利用nginx subrequest实现与多个后端server的交互

/*

 * 利用nginx subrequest实现与多个后端server的交互
 * Nginx version: 1.2.2
 * Copyright (C) eling	
 * Email: [email protected]
 * 
 */


extern "C" {
#include 
#include 
#include 
}

// nginx header files should go before other, because they define 64-bit off_t

#define LAUTH_EXT_CMD_ARGS_NUM 2

typedef struct {
    ngx_uint_t                n;	// 2
    ngx_array_t              *uris;
} ngx_http_lauth_ext_conf_t;

typedef struct {
	ngx_uint_t                done;
    ngx_uint_t                status;
	ngx_str_t				 *content;
	
    ngx_http_request_t       *sr;
} ngx_http_lauth_ext_subrequest;

typedef struct {
	ngx_uint_t				i;
	ngx_array_t				*subrequests;	
} ngx_http_lauth_ext_ctx_t;

static ngx_int_t ngx_http_lauth_ext_handler(ngx_http_request_t *r);
static ngx_int_t ngx_http_lauth_ext_done(ngx_http_request_t *r,
    void *data, ngx_int_t rc);

static void *ngx_http_lauth_ext_create_conf(ngx_conf_t *cf);

static char *ngx_http_lauth_ext(ngx_conf_t *cf, ngx_command_t *cmd,
    void *conf);


static ngx_command_t  ngx_http_lauth_ext_commands[] = {

    { ngx_string("lauth_ext"),
      NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
      ngx_http_lauth_ext,
      NGX_HTTP_LOC_CONF_OFFSET,
      0,
      NULL },

      ngx_null_command
};


static ngx_http_module_t  ngx_http_lauth_ext_module_ctx = {
    NULL,                                  /* preconfiguration */
    NULL,            						/* postconfiguration */

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

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

    ngx_http_lauth_ext_create_conf,     /* create location configuration */
    NULL       							/* merge location configuration */
};


ngx_module_t  ngx_http_lauth_ext_module = {
    NGX_MODULE_V1,
    &ngx_http_lauth_ext_module_ctx,     /* module context */
    ngx_http_lauth_ext_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_lauth_ext_handler(ngx_http_request_t *r)
{
	ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0,
                   "lauth_ext request handler, uri:%V args:%V", &r->uri, &r->args);

	ngx_int_t 					rc;
    ngx_http_lauth_ext_conf_t  *lacf;
	ngx_str_t					*uri;
	ngx_str_t					*args;
	
	ngx_http_lauth_ext_ctx_t   		*ctx;	
	ngx_http_lauth_ext_subrequest  	*lasr;
	ngx_http_post_subrequest_t  	*ps;	
	
    lacf = (ngx_http_lauth_ext_conf_t *)ngx_http_get_module_loc_conf(r, ngx_http_lauth_ext_module); 	
	
    ctx = (ngx_http_lauth_ext_ctx_t *)ngx_http_get_module_ctx(r, ngx_http_lauth_ext_module);

//	args = &r->args;

    if (ctx != NULL) {
		ngx_http_lauth_ext_subrequest* lasr = (ngx_http_lauth_ext_subrequest*)ctx->subrequests->elts + (ctx->i - 1);
		
        if(ctx->i == LAUTH_EXT_CMD_ARGS_NUM){
			if(lasr->status == NGX_HTTP_INTERNAL_SERVER_ERROR){
				ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
				return NGX_OK;
			}
			else if(lasr->status != NGX_HTTP_OK){
				r->headers_out.status = lasr->status;
				r->header_only = 1;//???

				rc = ngx_http_send_header(r);
				ngx_http_finalize_request(r, rc);
				return NGX_OK;
			}

			r->headers_out.status = lasr->status;			
			r->headers_out.content_length_n = lasr->content->len;			
			
			rc = ngx_http_send_header(r);
    		if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
        		ngx_http_finalize_request(r, rc);
				return NGX_OK;
    		}			

			ngx_chain_t out;
			ngx_buf_t b;

			ngx_memzero(&b, sizeof(ngx_buf_t));
			b.temporary = 1;
			b.last_buf = 1;	//???
			
			b.pos = lasr->content->data;
			b.last = b.pos + lasr->content->len;
			b.start = b.pos;
			b.end = b.last;			
			
			out.buf = &b;
			out.next = NULL;

			rc = ngx_http_output_filter(r, &out);
    		ngx_http_finalize_request(r, rc);
			return NGX_OK;
		} 

		if(lasr->status == NGX_HTTP_INTERNAL_SERVER_ERROR){
			ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
			return NGX_OK;
		}
		else if(lasr->status != NGX_HTTP_OK){
			r->headers_out.status = lasr->status;
			r->header_only = 1;//???

			rc = ngx_http_send_header(r);
			ngx_http_finalize_request(r, rc);
			return NGX_OK;
		}

//		args = lasr->content;

		args = (ngx_str_t *)ngx_palloc(r->pool, sizeof(ngx_str_t));	
		if(args == NULL){
			ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
			return NGX_OK;
		}
		
		args->len = r->args.len + 1 + lasr->content->len;
		args->data = (u_char *)ngx_palloc(r->pool, args->len);
		if(args->data == NULL){
			ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
			return NGX_OK;
		}
		
		ngx_memcpy(args->data, r->args.data, r->args.len);
		args->data[r->args.len] = '&';
		ngx_memcpy(args->data + r->args.len + 1, lasr->content->data, lasr->content->len);
#if 0
		/*for test 
		*uri dont contain '\r', ...
		*/
		u_char *p = lasr->content->data + lasr->content->len;
		while(*--p == '\n'){
			args->len --;			
		}

		while(*--p == '\n'){
			ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
			return NGX_OK;
		}
#endif
		goto subrequest;
    }
	else{
		args = &r->args;
	}

    ctx = (ngx_http_lauth_ext_ctx_t *)ngx_pcalloc(r->pool, sizeof(ngx_http_lauth_ext_ctx_t));
    if (ctx == NULL) {
        return NGX_ERROR;
    }
	
	ctx->subrequests = ngx_array_create(r->pool, LAUTH_EXT_CMD_ARGS_NUM, sizeof(ngx_http_lauth_ext_subrequest));
	if (ctx->subrequests == NULL) {
        return NGX_ERROR;
    }

	ngx_http_set_ctx(r, ctx, ngx_http_lauth_ext_module);

subrequest:
	uri = (ngx_str_t *)lacf->uris->elts + ctx->i;
	ctx->i ++;
	
	lasr = (ngx_http_lauth_ext_subrequest *)ngx_array_push(ctx->subrequests);
	ngx_memzero(lasr, sizeof(ngx_http_lauth_ext_subrequest));

    ps = (ngx_http_post_subrequest_t *)ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
    if (ps == NULL) {
        return NGX_ERROR;
    }

    ps->handler = ngx_http_lauth_ext_done;
    ps->data = ctx;	 

    if(ngx_http_subrequest(r, uri, args, &lasr->sr, ps, NGX_HTTP_SUBREQUEST_IN_MEMORY/* | NGX_HTTP_SUBREQUEST_WAITED*/) != NGX_OK){
		return NGX_ERROR;
	}

	ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0,
                   "lauth_ext request handler, subrequest uri:%V args:%V", uri, args); 
	
	return NGX_AGAIN;
}


static ngx_int_t ngx_http_lauth_ext_done(ngx_http_request_t *r,
    void *data, ngx_int_t rc)
{
	ngx_http_lauth_ext_ctx_t *ctx = (ngx_http_lauth_ext_ctx_t *)data;  

	ngx_http_lauth_ext_subrequest* lasr = (ngx_http_lauth_ext_subrequest*)ctx->subrequests->elts + (ctx->i - 1);

	lasr->done = 1;
	lasr->status = r->headers_out.status;

	if(lasr->status == NGX_HTTP_OK){	
		if(r->upstream == NULL){
			ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                   "lauth_ext subrequest done, subrequest does not support upstream, uri:%V args:%V", 
                   &r->uri, &r->args);

			lasr->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
			goto end;
		}

		if(lasr->content == NULL){
			lasr->content = (ngx_str_t *)ngx_palloc(r->pool, sizeof(ngx_str_t));
			if(lasr->content == NULL){
				lasr->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
				goto end;
			}
		}
		
		lasr->content->len = r->headers_out.content_length_n;
		lasr->content->data = (u_char *)ngx_palloc(r->pool, lasr->content->len);
		if(lasr->content->data == NULL){
			lasr->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
			goto end;
		}
		
		ngx_memcpy(lasr->content->data, r->upstream->buffer.pos, lasr->content->len);

		goto end;
	}

end:
	if(lasr->content != NULL){
		ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0,
                   "lauth_ext subrequest done, uri:%V args:%V rc:%i status:%i content:%V", 
                   &r->uri, &r->args, rc, lasr->status, lasr->content);
	}
	else{
		ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0,
                   "lauth_ext subrequest done, uri:%V args:%V rc:%i status:%i", 
                   &r->uri, &r->args, rc, lasr->status);
	}
	
	r->parent->write_event_handler = (ngx_http_event_handler_pt)ngx_http_lauth_ext_handler;
	
    return rc;
}


static void *
ngx_http_lauth_ext_create_conf(ngx_conf_t *cf)
{
    ngx_http_lauth_ext_conf_t  *conf;

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

    conf->n = LAUTH_EXT_CMD_ARGS_NUM;
	conf->uris = ngx_array_create(cf->pool, LAUTH_EXT_CMD_ARGS_NUM, sizeof(ngx_str_t));
	if(conf->uris == NULL){
		return NGX_CONF_ERROR;
	}

    return conf;
}


static char *
ngx_http_lauth_ext(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_lauth_ext_conf_t *lacf = (ngx_http_lauth_ext_conf_t *)conf;
	ngx_http_core_loc_conf_t *clcf;

    ngx_str_t     *uri, *value;
    value = (ngx_str_t *)cf->args->elts;	

	for (ngx_uint_t i = 1; i <= lacf->n; i++) {
		uri = (ngx_str_t *)ngx_array_push(lacf->uris);
		*uri = value[i];
		
		ngx_log_error(NGX_LOG_DEBUG, cf->log, 0,
					"lauth_ext args: %V", uri);
	}

	clcf = (ngx_http_core_loc_conf_t *)ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
	clcf->handler = ngx_http_lauth_ext_handler;

    return NGX_CONF_OK;
}

你可能感兴趣的:(nginx)