<commit_before>
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>


typedef struct {
	ngx_flag_t	enable;
	ngx_str_t	token_key;
	ngx_str_t	path_to_static;
	ngx_str_t   redis_url;
} ngx_http_tokenaccess_loc_conf_t;

static ngx_int_t ngx_http_tokenaccess_init(ngx_conf_t *cf);
static void *ngx_http_tokenaccess_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_tokenaccess_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child);

static ngx_command_t ngx_http_tokenaccess_commands[] = {

	{ ngx_string("tokenaccess"),
	  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
	  ngx_conf_set_flag_slot,
	  NGX_HTTP_LOC_CONF_OFFSET,
	  offsetof(ngx_http_tokenaccess_loc_conf_t, enable),
	  NULL },

	{ ngx_string("token_key"),
	  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
	  ngx_conf_set_str_slot,
	  NGX_HTTP_LOC_CONF_OFFSET,
	  offsetof(ngx_http_tokenaccess_loc_conf_t, token_key),
	  NULL },

	{ ngx_string("path_to_static"),
	  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
	  ngx_conf_set_str_slot,
	  NGX_HTTP_LOC_CONF_OFFSET,
	  offsetof(ngx_http_tokenaccess_loc_conf_t, path_to_static),
	  NULL },

	{ ngx_string("redis_url"),
	  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
	  ngx_conf_set_str_slot,
	  NGX_HTTP_LOC_CONF_OFFSET,
	  offsetof(ngx_http_tokenaccess_loc_conf_t, redis_url),
	  NULL },

	ngx_null_command
};

static ngx_http_module_t ngx_http_tokenaccess_module_ctx = {
    NULL,                                /* preconfiguration */
    ngx_http_tokenaccess_init,                /* postconfiguration */

    NULL,                                /* create main configuration */
    NULL,                                /* init main configuration */

    NULL,                                /* create server configuration */
    NULL,                                /* merge server configuration */

    ngx_http_tokenaccess_create_loc_conf,     /* create location configuration */
    ngx_http_tokenaccess_merge_loc_conf       /* merge location configuration */
};

ngx_module_t ngx_http_tokenaccess_module = {
    NGX_MODULE_V1,
    &ngx_http_tokenaccess_module_ctx,         /* module context */
    ngx_http_tokenaccess_commands,            /* module directives */
    NGX_HTTP_MODULE,                     /* module type */
    NULL,                                /* init master */
    NULL,                                /* init module */
    NULL,                                /* init process */
    NULL,                                /* init thread */
    NULL,                                /* exit thread */
    NULL,                                /* exit process */
    NULL,                                /* exit master */
    NGX_MODULE_V1_PADDING
};

static ngx_int_t ngx_http_tokenaccess_handler(ngx_http_request_t *r){
	ngx_int_t rc;
	//ngx_buf_t *b;
	//ngx_chain_t out;
	ngx_http_tokenaccess_loc_conf_t *my_cnf;
	//ngx_str_t type = ngx_string("text/html");
	ngx_str_t args = r->args;
	ngx_uint_t content_length = 0;
	ngx_log_t *log;
	u_char token_key[1024] = {0};

	if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))){
		return NGX_HTTP_NOT_ALLOWED;
	}

	if (r->uri.data[r->uri.len - 1] == '/') {
        return NGX_DECLINED;
    }

	my_cnf = ngx_http_get_module_loc_conf(r, ngx_http_tokenaccess_module);
	if (!my_cnf->enable){
		return NGX_DECLINED;
	}

	log = r->connection->log;

	rc = ngx_http_discard_request_body(r);
	if (rc != NGX_OK){
		return rc;
	}

	ngx_str_t look = my_cnf->token_key;
	if (look.len == 0){
		ngx_log_error(NGX_LOG_EMERG, log, 0, "token key is undefined!");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
	}

	/* parse the url arguments */
	ngx_uint_t i, j=0, k=0, l=0;
	for (i = 0; i <= args.len; i++) {
		if ( (i == args.len) || (args.data[i] == '&') ) {
			if (j > 1 ){
				k = j;
				l = i;
			}
			j = 0;
		} else if ( (j == 0) &&  (i<args.len-look.len) ){
			if ( (ngx_strncmp(args.data+i, look.data, look.len) == 0) 
					&& (args.data[i+look.len] == '=')) {
				j=i+look.len+1;
				i=j-1;
			}else j=1;
		}
	}

	if (k == l){
		ngx_log_error(NGX_LOG_EMERG, log, 0, "token value is undefined!");
        return NGX_HTTP_BAD_REQUEST;
	}

	ngx_memcpy(token_key, &args.data[k], l-k);
	content_length = ngx_strlen(token_key);

	ngx_log_error(NGX_LOG_EMERG, log, 0, "http root: \"%s\"", token_key);

	ngx_str_t path_to_static = my_cnf->path_to_static;
	if (&path_to_static != NULL) {

	}

	return NGX_DECLINED;
}

static void *ngx_http_tokenaccess_create_loc_conf(ngx_conf_t *cf){
	ngx_http_tokenaccess_loc_conf_t *conf = NULL;

	conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_tokenaccess_loc_conf_t));
	if (conf == NULL) {
		return NULL;
	}

    conf->enable = NGX_CONF_UNSET;
    ngx_str_null(&conf->token_key);
    ngx_str_null(&conf->path_to_static);
    ngx_str_null(&conf->redis_url);
    return conf;
}

static char *ngx_http_tokenaccess_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child){
    ngx_http_tokenaccess_loc_conf_t  *prev = parent; 
    ngx_http_tokenaccess_loc_conf_t  *conf = child;	

	ngx_conf_merge_value(conf->enable, prev->enable, 0);
	ngx_conf_merge_str_value(conf->token_key, prev->token_key, "token_key");
	ngx_conf_merge_str_value(conf->path_to_static, prev->path_to_static, "path_to_static");
	ngx_conf_merge_str_value(conf->redis_url, prev->redis_url, "redis_url");
	return NGX_CONF_OK;
}


static ngx_int_t ngx_http_tokenaccess_init(ngx_conf_t *cf){
	ngx_http_handler_pt *h;
	ngx_http_core_main_conf_t *cmcf;

	cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);<commit_msg>subrequest added<commit_after>
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>


typedef struct {
	ngx_flag_t  enable;
	ngx_str_t   token_key;
	ngx_str_t	path_to_static;
	ngx_str_t   redis_pass;
} ngx_http_tokenaccess_loc_conf_t;

typedef struct {
	ngx_str_t 	value;
} ngx_http_tokenaccess_ctx_t;

static ngx_int_t ngx_http_tokenaccess_subrequest_post_handler(ngx_http_request_t *r, void *data, ngx_int_t rc);
static void ngx_http_tokenaccess_post_handler(ngx_http_request_t *r);

static ngx_int_t ngx_http_tokenaccess_init(ngx_conf_t *cf);
static void *ngx_http_tokenaccess_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_tokenaccess_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child);

static ngx_command_t ngx_http_tokenaccess_commands[] = {

	{ ngx_string("tokenaccess"),
	  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
	  ngx_conf_set_flag_slot,
	  NGX_HTTP_LOC_CONF_OFFSET,
	  offsetof(ngx_http_tokenaccess_loc_conf_t, enable),
	  NULL },

	{ ngx_string("token_key"),
	  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
	  ngx_conf_set_str_slot,
	  NGX_HTTP_LOC_CONF_OFFSET,
	  offsetof(ngx_http_tokenaccess_loc_conf_t, token_key),
	  NULL },

	{ ngx_string("path_to_static"),
	  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
	  ngx_conf_set_str_slot,
	  NGX_HTTP_LOC_CONF_OFFSET,
	  offsetof(ngx_http_tokenaccess_loc_conf_t, path_to_static),
	  NULL },

	{ ngx_string("redis_pass"),
	  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
	  ngx_conf_set_str_slot,
	  NGX_HTTP_LOC_CONF_OFFSET,
	  offsetof(ngx_http_tokenaccess_loc_conf_t, redis_pass),
	  NULL },

	ngx_null_command
};

static ngx_http_module_t ngx_http_tokenaccess_module_ctx = {
    NULL,                                /* preconfiguration */
    ngx_http_tokenaccess_init,                /* postconfiguration */

    NULL,                                /* create main configuration */
    NULL,                                /* init main configuration */

    NULL,                                /* create server configuration */
    NULL,                                /* merge server configuration */

    ngx_http_tokenaccess_create_loc_conf,     /* create location configuration */
    ngx_http_tokenaccess_merge_loc_conf       /* merge location configuration */
};

ngx_module_t ngx_http_tokenaccess_module = {
    NGX_MODULE_V1,
    &ngx_http_tokenaccess_module_ctx,         /* module context */
    ngx_http_tokenaccess_commands,            /* module directives */
    NGX_HTTP_MODULE,                     /* module type */
    NULL,                                /* init master */
    NULL,                                /* init module */
    NULL,                                /* init process */
    NULL,                                /* init thread */
    NULL,                                /* exit thread */
    NULL,                                /* exit process */
    NULL,                                /* exit master */
    NGX_MODULE_V1_PADDING
};


static ngx_int_t ngx_http_tokenaccess_subrequest_post_handler(ngx_http_request_t *r, void *data, ngx_int_t rc) {
	ngx_http_request_t *pr = r->parent;

	ngx_http_tokenaccess_ctx_t *ctx = ngx_http_get_module_ctx(pr, ngx_http_tokenaccess_module);

	pr->headers_out.status = r->headers_out.status;
	if (r->headers_out.status == NGX_HTTP_OK) {
		ngx_buf_t *pRecvBuf = &r->upstream->buffer;
		ctx->value.len = pRecvBuf->last - pRecvBuf->pos;
		ctx->value.data = pRecvBuf->pos;
		if (ctx->value.len == 0){
			return NGX_HTTP_INTERNAL_SERVER_ERROR;
		}

		ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0, "SUB ctx->value.data: \"%s\", ctx->value.len: \"%d\"", ctx->value.data, ctx->value.len);
	}

	pr->write_event_handler = ngx_http_tokenaccess_post_handler;
	return NGX_OK;
}

static void ngx_http_tokenaccess_post_handler(ngx_http_request_t *r){
	if (r->headers_out.status != NGX_HTTP_OK) {
		ngx_http_finalize_request(r, r->headers_out.status);
		return;
	}
	
	ngx_http_tokenaccess_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_http_tokenaccess_module);

	ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0, "POST ctx->value.data: \"%s\", ctx->value.len: \"%d\"", ctx->value.data, ctx->value.len);

	ngx_buf_t *b = ngx_create_temp_buf(r->pool, sizeof(ngx_buf_t));

	u_char *filename = (u_char *)"/home/mgsys/dev/static/20120324.daily/1003_mail.htm";
    b->in_file = 1;
    b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
    if (b->file == NULL) {
        //return NGX_HTTP_INTERNAL_SERVER_ERROR;
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
    }
    b->file->fd = ngx_open_file(filename, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, NGX_FILE_OPEN, 0);
    b->file->log = r->connection->log;
    b->file->name.data = filename;
    b->file->name.len = sizeof(filename) - 1;

    if (b->file->fd <= 0){
    	//return NGX_HTTP_NOT_FOUND;
    	ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
    }

    if (ngx_file_info(filename, &b->file->info) == NGX_FILE_ERROR) {
    	//return NGX_HTTP_INTERNAL_SERVER_ERROR;
    	ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
    }

    b->file_pos = 0;
	b->file_last = b->file->info.st_size;

	b->last = b->pos + b->file->info.st_size;
	b->last_buf = 1;

	// ngx_str_t output_format = ngx_string(" %V ");
	// int bodylen = output_format.len + ctx->value.len;	

	// ngx_buf_t *b = ngx_create_temp_buf(r->pool, bodylen);
	// ngx_snprintf(b->pos, bodylen, (char *)output_format.data, &ctx->value);

	// b->last = b->pos + bodylen;
	// b->last_buf = 1;

	ngx_chain_t out;
	out.buf = b;
	out.next = NULL;
	ngx_str_t type = ngx_string("text/html");
	r->headers_out.content_type = type;
	r->headers_out.status = NGX_HTTP_OK;
	r->headers_out.content_length_n = b->file->info.st_size;
	r->connection->buffered |= NGX_HTTP_WRITE_BUFFERED;

	/* send the headers of your response */
	ngx_int_t ret = ngx_http_send_header(r);
	ret = ngx_http_output_filter(r, &out);

	ngx_pool_cleanup_t *cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t));
	if (cln == NULL) {
		ngx_http_finalize_request(r, NGX_ERROR);
	}
	cln->handler = ngx_pool_cleanup_file;
	ngx_pool_cleanup_file_t *clnf = cln->data;
	clnf-> fd = b->file->fd;
	clnf->name = b->file->name.data;
	clnf->log = r->pool->log;

	ngx_http_finalize_request(r, ret);
}

static ngx_int_t ngx_http_tokenaccess_handler(ngx_http_request_t *r){
	ngx_int_t rc;
	//ngx_buf_t *b;
	//ngx_chain_t out;
	ngx_http_tokenaccess_loc_conf_t *my_cnf;
	//ngx_str_t type = ngx_string("text/html");
	ngx_str_t args = r->args;
	ngx_uint_t content_length = 0;
	ngx_log_t *log;
	u_char token_key[1024] = {0};

	if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))){
		return NGX_HTTP_NOT_ALLOWED;
	}

	if (r->uri.data[r->uri.len - 1] == '/') {
        return NGX_DECLINED;
    }

	my_cnf = ngx_http_get_module_loc_conf(r, ngx_http_tokenaccess_module);
	if (!my_cnf->enable){
		return NGX_DECLINED;
	}

	log = r->connection->log;

	rc = ngx_http_discard_request_body(r);
	if (rc != NGX_OK){
		return rc;
	}

	ngx_str_t look = my_cnf->token_key;
	if (look.len == 0){
		ngx_log_error(NGX_LOG_EMERG, log, 0, "token key is undefined!");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
	}

	/* parse the url arguments */
	ngx_uint_t i, j=0, k=0, l=0;
	for (i = 0; i <= args.len; i++) {
		if ( (i == args.len) || (args.data[i] == '&') ) {
			if (j > 1 ){
				k = j;
				l = i;
			}
			j = 0;
		} else if ( (j == 0) &&  (i<args.len-look.len) ){
			if ( (ngx_strncmp(args.data+i, look.data, look.len) == 0) 
					&& (args.data[i+look.len] == '=')) {
				j=i+look.len+1;
				i=j-1;
			}else j=1;
		}
	}

	if (k == l){
		ngx_log_error(NGX_LOG_EMERG, log, 0, "token value is undefined!");
        return NGX_HTTP_BAD_REQUEST;
	}

	ngx_memcpy(token_key, &args.data[k], l-k);
	content_length = ngx_strlen(token_key);

	ngx_log_error(NGX_LOG_EMERG, log, 0, "http root: \"%s\"", token_key);

	ngx_http_tokenaccess_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_http_tokenaccess_module);
	if (ctx == NULL) {
		ctx = ngx_palloc(r->pool, sizeof(ngx_http_tokenaccess_ctx_t));
		if (ctx == NULL) {
			return NGX_ERROR;
		}
		ngx_http_set_ctx(r, ctx, ngx_http_tokenaccess_module);
	}

	ngx_http_post_subrequest_t *psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
	if (psr == NULL) {
		return NGX_HTTP_INTERNAL_SERVER_ERROR;
	}
	psr->handler = ngx_http_tokenaccess_subrequest_post_handler;
	psr->data = ctx;

	ngx_str_t sub_prefix = ngx_string("/list=s_sh000001");
	ngx_str_t sub_location;
	sub_location.len = sub_prefix.len;
	sub_location.data = ngx_palloc(r->pool, sub_location.len);
	ngx_snprintf(sub_location.data, sub_location.len, "%V", &sub_prefix);

	ngx_log_error(NGX_LOG_EMERG, log, 0, "sub_location.data: \"%s\"", sub_location.data);

	ngx_http_request_t *sr;
	rc = ngx_http_subrequest(r, &sub_location, NULL, &sr, psr, NGX_HTTP_SUBREQUEST_IN_MEMORY);
	if (rc != NGX_OK) {
		return NGX_ERROR;
	}
	return NGX_DONE;
}

static void *ngx_http_tokenaccess_create_loc_conf(ngx_conf_t *cf){
	ngx_http_tokenaccess_loc_conf_t *conf = NULL;

	conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_tokenaccess_loc_conf_t));
	if (conf == NULL) {
		return NULL;
	}

    conf->enable = NGX_CONF_UNSET;
    ngx_str_null(&conf->token_key);
    ngx_str_null(&conf->path_to_static);
    ngx_str_null(&conf->redis_pass);
    return conf;
}

static char *ngx_http_tokenaccess_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child){
    ngx_http_tokenaccess_loc_conf_t  *prev = parent; 
    ngx_http_tokenaccess_loc_conf_t  *conf = child;	

	ngx_conf_merge_value(conf->enable, prev->enable, 0);
	ngx_conf_merge_str_value(conf->token_key, prev->token_key, "token_key");
	ngx_conf_merge_str_value(conf->path_to_static, prev->path_to_static, "path_to_static");
	ngx_conf_merge_str_value(conf->redis_pass, prev->redis_pass, "redis_pass");
	return NGX_CONF_OK;
}


static ngx_int_t ngx_http_tokenaccess_init(ngx_conf_t *cf){
	ngx_http_handler_pt *h;
	ngx_http_core_main_conf_t *cmcf;

	cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
{'fraction_non_alphanumeric': 0.12129706313308275, 'fraction_numerical': 0.005415047461298337, 'mean_word_length': 3.5833576642335765, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 140, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 26, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5911716', 'n_tokens_mistral': 6707, 'n_tokens_neox': 6351, 'n_words': 945}