static ngx_int_t ngx_http_addition_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_int_t rc; ngx_uint_t last; ngx_chain_t *cl; ngx_http_request_t *sr; ngx_http_addition_ctx_t *ctx; ngx_http_addition_conf_t *conf; if (in == NULL || r->header_only) { return ngx_http_next_body_filter(r, in); } ctx = ngx_http_get_module_ctx(r, ngx_http_addition_filter_module); if (ctx == NULL) { return ngx_http_next_body_filter(r, in); } conf = ngx_http_get_module_loc_conf(r, ngx_http_addition_filter_module); if (!ctx->before_body_sent) { ctx->before_body_sent = 1; if (conf->before_body.len) { if (ngx_http_subrequest(r, &conf->before_body, NULL, &sr, NULL, 0) != NGX_OK) { return NGX_ERROR; } } } if (conf->after_body.len == 0) { ngx_http_set_ctx(r, NULL, ngx_http_addition_filter_module); return ngx_http_next_body_filter(r, in); } last = 0; for (cl = in; cl; cl = cl->next) { if (cl->buf->last_buf) { cl->buf->last_buf = 0; cl->buf->sync = 1; last = 1; } } rc = ngx_http_next_body_filter(r, in); if (rc == NGX_ERROR || !last || conf->after_body.len == 0) { return rc; } if (ngx_http_subrequest(r, &conf->after_body, NULL, &sr, NULL, 0) != NGX_OK) { return NGX_ERROR; } ngx_http_set_ctx(r, NULL, ngx_http_addition_filter_module); return ngx_http_send_special(r, NGX_HTTP_LAST); }
static void nchan_publisher_body_handler(ngx_http_request_t *r) { ngx_str_t *channel_id; nchan_loc_conf_t *cf = ngx_http_get_module_loc_conf(r, ngx_nchan_module); ngx_table_elt_t *content_length_elt; ngx_http_complex_value_t *authorize_request_url_ccv = cf->authorize_request_url; if((channel_id = nchan_get_channel_id(r, PUB, 1))==NULL) { nchan_http_finalize_request(r, r->headers_out.status ? NGX_OK : NGX_HTTP_INTERNAL_SERVER_ERROR); return; } if(!authorize_request_url_ccv) { nchan_publisher_body_handler_continued(r, channel_id, cf); } else { nchan_pub_subrequest_stuff_t *psr_stuff; if((psr_stuff = ngx_palloc(r->pool, sizeof(*psr_stuff))) == NULL) { nchan_log_request_error(r, "can't allocate memory for publisher auth subrequest"); nchan_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } ngx_http_post_subrequest_t *psr = &psr_stuff->psr; nchan_pub_subrequest_data_t *psrd = &psr_stuff->psr_data; ngx_http_request_t *sr; ngx_str_t auth_request_url; ngx_http_complex_value(r, authorize_request_url_ccv, &auth_request_url); psr->handler = nchan_publisher_body_authorize_handler; psr->data = psrd; psrd->ch_id = channel_id; ngx_http_subrequest(r, &auth_request_url, NULL, &sr, psr, 0); if((sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t))) == NULL) { nchan_log_request_error(r, "can't allocate memory for publisher auth subrequest body"); nchan_http_finalize_request(r, r->headers_out.status ? NGX_OK : NGX_HTTP_INTERNAL_SERVER_ERROR); return; } if((content_length_elt = ngx_palloc(r->pool, sizeof(*content_length_elt))) == NULL) { nchan_log_request_error(r, "can't allocate memory for publisher auth subrequest content-length header"); nchan_http_finalize_request(r, r->headers_out.status ? NGX_OK : NGX_HTTP_INTERNAL_SERVER_ERROR); return; } if(sr->headers_in.content_length) { *content_length_elt = *sr->headers_in.content_length; content_length_elt->value.len=1; content_length_elt->value.data=(u_char *)"0"; sr->headers_in.content_length = content_length_elt; } sr->headers_in.content_length_n = 0; sr->args = r->args; sr->header_only = 1; } }
ngx_int_t ngx_http_echo_exec_echo_location_async(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) { ngx_int_t rc; ngx_http_request_t *sr; /* subrequest object */ ngx_str_t *computed_arg_elts; ngx_str_t location; ngx_str_t *url_args; ngx_str_t args; ngx_uint_t flags = 0; dd_enter(); computed_arg_elts = computed_args->elts; location = computed_arg_elts[0]; if (location.len == 0) { return NGX_ERROR; } if (computed_args->nelts > 1) { url_args = &computed_arg_elts[1]; } else { url_args = NULL; } args.data = NULL; args.len = 0; if (ngx_http_parse_unsafe_uri(r, &location, &args, &flags) != NGX_OK) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "echo_location_async sees unsafe uri: \"%V\"", &location); return NGX_ERROR; } if (args.len > 0 && url_args == NULL) { url_args = &args; } rc = ngx_http_echo_send_header_if_needed(r, ctx); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } rc = ngx_http_subrequest(r, &location, url_args, &sr, NULL, 0); if (rc != NGX_OK) { return NGX_ERROR; } rc = ngx_http_echo_adjust_subrequest(sr); if (rc != NGX_OK) { return NGX_ERROR; } return NGX_OK; }
static ngx_int_t ngx_http_rj_cdn_com_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_str_t uri; ngx_http_request_t *sr; /*subrequest object*/ uri.data = ngx_pcalloc(r->pool, r->args.len); uri.len = r->args.len; memcpy(uri.data, r->args.data, r->args.len); rc = ngx_http_echo_send_header_if_needed(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } rc = ngx_http_subrequest(r, &uri, NULL, &sr, NULL, 0); if (rc != NGX_OK) return NGX_ERROR; rc = ngx_http_rj_cdn_com_adjust_subrequest(sr); if (rc != NGX_OK) return NGX_ERROR; rc = ngx_http_send_special(r, NGX_HTTP_LAST); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE){ return rc; } return rc; }
ngx_int_t ngx_http_echo_exec_echo_location_async(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) { ngx_int_t rc; ngx_http_request_t *sr; /* subrequest object */ ngx_str_t *computed_arg_elts; ngx_str_t location; ngx_str_t *url_args; ngx_str_t args; ngx_uint_t flags; computed_arg_elts = computed_args->elts; location = computed_arg_elts[0]; if (location.len == 0) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (computed_args->nelts > 1) { url_args = &computed_arg_elts[1]; } else { url_args = NULL; } dd("location: %s", location.data); dd("location args: %s", (char*) (url_args ? url_args->data : (u_char*)"NULL")); args.data = NULL; args.len = 0; if (ngx_http_parse_unsafe_uri(r, &location, &args, &flags) != NGX_OK) { ctx->headers_sent = 1; return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (args.len > 0 && url_args == NULL) { url_args = &args; } rc = ngx_http_echo_send_header_if_needed(r, ctx); if (r->header_only || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } rc = ngx_http_subrequest(r, &location, url_args, &sr, NULL, 0); if (rc != NGX_OK) { return NGX_ERROR; } rc = ngx_http_echo_adjust_subrequest(sr); if (rc != NGX_OK) { return rc; } return NGX_OK; }
static ngx_int_t ngx_http_slice_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_int_t rc; ngx_chain_t *cl; ngx_http_request_t *sr; ngx_http_slice_ctx_t *ctx; ngx_http_slice_loc_conf_t *slcf; ctx = ngx_http_get_module_ctx(r, ngx_http_slice_filter_module); if (ctx == NULL || r != r->main) { return ngx_http_next_body_filter(r, in); } for (cl = in; cl; cl = cl->next) { if (cl->buf->last_buf) { cl->buf->last_buf = 0; cl->buf->last_in_chain = 1; cl->buf->sync = 1; ctx->last = 1; } } rc = ngx_http_next_body_filter(r, in); if (rc == NGX_ERROR || !ctx->last) { return rc; } if (ctx->start >= ctx->end) { ngx_http_set_ctx(r, NULL, ngx_http_slice_filter_module); ngx_http_send_special(r, NGX_HTTP_LAST); return rc; } if (r->buffered) { return rc; } if (ngx_http_subrequest(r, &r->uri, &r->args, &sr, NULL, 0) != NGX_OK) { return NGX_ERROR; } ngx_http_set_ctx(sr, ctx, ngx_http_slice_filter_module); slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_filter_module); ctx->range.len = ngx_sprintf(ctx->range.data, "bytes=%O-%O", ctx->start, ctx->start + (off_t) slcf->size - 1) - ctx->range.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http slice subrequest: \"%V\"", &ctx->range); return rc; }
static void esi_tag_start_include(ESITag *tag, ESIAttribute *attributes) { ngx_int_t rc; ngx_str_t uri, args; ngx_http_request_t *sr; ESIAttribute *attr = attributes; ngx_http_request_t *request = tag->ctx->request; ngx_pool_t *pool = request->pool; ngx_uint_t flags = 0; ngx_http_post_subrequest_t *psr; ngx_chain_t *link; ngx_buf_t *buf; flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY; args.len = 0; args.data = NULL; // printf( "esi:include\n" ); while( attr ) { // printf( "\t%s => %s\n", attr->name, attr->value ); if( !ngx_strcmp( attr->name, "src" ) ) { uri.len = strlen(attr->value)+1; uri.data = ngx_palloc(pool, uri.len ); ngx_memcpy( uri.data, attr->value, uri.len ); printf( "uri: %s\n", uri.data ); } attr = attr->next; } if( uri.len > 0 ) { psr = ngx_palloc(pool, sizeof(ngx_http_post_subrequest_t)); if( psr == NULL ) { return; //return NGX_ERROR; } /* attach the handler */ psr->handler = ngx_http_esi_stub_output; /* allocate a buffer */ buf = ngx_alloc_buf(pool); if( buf == NULL ) { return; //return NGX_ERROR; } link = ngx_alloc_chain_link(pool); if( link == NULL ) { return; //return NGX_ERROR; } link->buf = buf; link->next = NULL; psr->data = link; rc = ngx_http_subrequest(request, &uri, &args, &sr, psr, flags); } ngx_pfree( pool, uri.data ); }
ngx_http_request_t *subscriber_subrequest(subscriber_t *sub, ngx_str_t *url, ngx_buf_t *body, subrequest_callback_pt cb, void *cb_data) { ngx_http_request_t *r = sub->request; ngx_http_post_subrequest_t *psr = ngx_pcalloc(r->pool, sizeof(*psr)); nchan_subrequest_data_cb_t *psrd = ngx_pcalloc(r->pool, sizeof(*psrd)); ngx_http_request_t *sr; sub->fn->reserve(sub); psr->handler = subscriber_subrequest_handler; psr->data = psrd; psrd->sub = sub; psrd->cb_data = cb_data; psrd->cb = cb; ngx_http_subrequest(r, url, NULL, &sr, psr, NGX_HTTP_SUBREQUEST_IN_MEMORY); if((sr->request_body = ngx_pcalloc(r->pool, sizeof(*sr->request_body))) == NULL) { //dummy request body return NULL; } if(body && ngx_buf_size(body) > 0) { static ngx_str_t POST_REQUEST_STRING = {4, (u_char *)"POST "}; size_t sz; ngx_http_request_body_t *sr_body = sr->request_body; ngx_chain_t *fakebody_chain; ngx_buf_t *fakebody_buf; fakebody_chain = ngx_palloc(r->pool, sizeof(*fakebody_chain)); fakebody_buf = ngx_palloc(r->pool, sizeof(*fakebody_buf)); sr_body->bufs = fakebody_chain; fakebody_chain->next = NULL; fakebody_chain->buf = fakebody_buf; ngx_memzero(fakebody_buf, sizeof(*fakebody_buf)); fakebody_buf->last_buf = 1; fakebody_buf->last_in_chain = 1; fakebody_buf->flush = 1; fakebody_buf->memory = 1; //just copy the buffer contents. it's inefficient but I don't care at the moment. //this can and should be optimized later sz = ngx_buf_size(body); fakebody_buf->start = ngx_palloc(r->pool, sz); //huuh? ngx_memcpy(fakebody_buf->start, body->start, sz); fakebody_buf->end = fakebody_buf->start + sz; fakebody_buf->pos = fakebody_buf->start; fakebody_buf->last = fakebody_buf->end; nchan_adjust_subrequest(sr, NGX_HTTP_POST, &POST_REQUEST_STRING, sr_body, sz, NULL); } else { sr->header_only = 1; } sr->args = sub->request->args; return sr; }
ngx_int_t ngx_http_echo_exec_echo_subrequest(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) { ngx_int_t rc; ngx_http_request_t *sr; /* subrequest object */ ngx_http_post_subrequest_t *psr; ngx_http_echo_subrequest_t *parsed_sr; ngx_str_t args; ngx_uint_t flags; rc = ngx_http_echo_parse_subrequest_spec(r, computed_args, &parsed_sr); if (rc != NGX_OK) { return rc; } args.data = NULL; args.len = 0; if (ngx_http_parse_unsafe_uri(r, parsed_sr->location, &args, &flags) != NGX_OK) { ctx->headers_sent = 1; return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (args.len > 0 && parsed_sr->query_string == NULL) { parsed_sr->query_string = &args; } rc = ngx_http_echo_send_header_if_needed(r, ctx); if (r->header_only || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } psr->handler = ngx_http_echo_post_subrequest; psr->data = ctx; rc = ngx_http_subrequest(r, parsed_sr->location, parsed_sr->query_string, &sr, psr, 0); if (rc != NGX_OK) { return NGX_ERROR; } rc = ngx_http_echo_adjust_subrequest(sr, parsed_sr); if (rc != NGX_OK) { return rc; } return NGX_OK; }
static void nchan_publisher_body_handler_continued(ngx_http_request_t *r, ngx_str_t *channel_id, nchan_loc_conf_t *cf) { ngx_http_complex_value_t *publisher_upstream_request_url_ccv; static ngx_str_t POST_REQUEST_STRING = {4, (u_char *)"POST "}; switch(r->method) { case NGX_HTTP_GET: cf->storage_engine->find_channel(channel_id, (callback_pt) &channel_info_callback, (void *)r); break; case NGX_HTTP_PUT: case NGX_HTTP_POST: publisher_upstream_request_url_ccv = cf->publisher_upstream_request_url; if(publisher_upstream_request_url_ccv == NULL) { ngx_str_t *content_type = (r->headers_in.content_type ? &r->headers_in.content_type->value : NULL); ngx_int_t content_length = r->headers_in.content_length_n > 0 ? r->headers_in.content_length_n : 0; nchan_publisher_post_request(r, content_type, content_length, r->request_body->bufs, channel_id, cf); } else { nchan_pub_upstream_stuff_t *psr_stuff; if((psr_stuff = ngx_palloc(r->pool, sizeof(*psr_stuff))) == NULL) { ERR("can't allocate memory for publisher auth subrequest"); ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } ngx_http_post_subrequest_t *psr = &psr_stuff->psr; nchan_pub_upstream_data_t *psrd = &psr_stuff->psr_data; ngx_http_request_t *sr; ngx_str_t publisher_upstream_request_url; ngx_http_complex_value(r, publisher_upstream_request_url_ccv, &publisher_upstream_request_url); psr->handler = nchan_publisher_upstream_handler; psr->data = psrd; psrd->ch_id = channel_id; ngx_http_subrequest(r, &publisher_upstream_request_url, NULL, &sr, psr, NGX_HTTP_SUBREQUEST_IN_MEMORY); nchan_adjust_subrequest(sr, NGX_HTTP_POST, &POST_REQUEST_STRING, r->request_body, r->headers_in.content_length_n, NULL); } break; case NGX_HTTP_DELETE: cf->storage_engine->delete_channel(channel_id, (callback_pt) &channel_info_callback, (void *)r); nchan_maybe_send_channel_event_message(r, CHAN_DELETE); break; default: nchan_respond_status(r, NGX_HTTP_FORBIDDEN, NULL, 0); } }
static ngx_int_t ngx_http_subrequest_mytest_handler(ngx_http_request_t * r) { //创建http上下文 ngx_http_subrequest_mytest_ctx_t* myctx = ngx_http_get_module_ctx(r, ngx_http_subrequest_mytest_module); if (myctx == NULL) { myctx = ngx_palloc(r->pool, sizeof(ngx_http_subrequest_mytest_ctx_t)); if (myctx == NULL) { return NGX_ERROR; } //将上下文设置到原始请求r中 ngx_http_set_ctx(r, myctx, ngx_http_subrequest_mytest_module); } // ngx_http_post_subrequest_t结构体会决定子请求的回调方法 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; } //设置子请求回调方法为mytest_subrequest_post_handler psr->handler = mytest_subrequest_post_handler; //data设为myctx上下文,这样回调mytest_subrequest_post_handler时传入的data参数就是myctx psr->data = myctx; //子请求的URI前缀是/list,这是因为访问新浪服务器的请求必须是类 //似/list=s_sh000001这样的URI, ngx_str_t sub_prefix = ngx_string("/list="); ngx_str_t sub_location; sub_location.len = sub_prefix.len + r->args.len; sub_location.data = ngx_palloc(r->pool, sub_location.len); ngx_snprintf(sub_location.data, sub_location.len, "%V%V", &sub_prefix, &r->args); //sr就是子请求 ngx_http_request_t *sr; //调用ngx_http_subrequest创建子请求,它只会返回NGX_OK //或者NGX_ERROR。返回NGX_OK时,sr就已经是合法的子请求。注意,这里 //的NGX_HTTP_SUBREQUEST_IN_MEMORY参数将告诉upstream模块把上 //游服务器的响应全部保存在子请求的sr->upstream->buffer内存缓冲区中 ngx_int_t rc = ngx_http_subrequest(r, &sub_location, NULL, &sr, psr, NGX_HTTP_SUBREQUEST_IN_MEMORY); if (rc != NGX_OK) { return NGX_ERROR; } //必须返回NGX_DONE,理由同upstream return NGX_DONE; }
ngx_int_t ngx_http_echo_exec_echo_subrequest_async(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) { ngx_int_t rc; ngx_http_echo_subrequest_t *parsed_sr; ngx_http_request_t *sr; /* subrequest object */ ngx_str_t args; ngx_uint_t flags; rc = ngx_http_echo_parse_subrequest_spec(r, computed_args, &parsed_sr); if (rc != NGX_OK) { return rc; } dd("location: %s", parsed_sr->location->data); dd("location args: %s", (char*) (parsed_sr->query_string ? parsed_sr->query_string->data : (u_char*)"NULL")); args.data = NULL; args.len = 0; if (ngx_http_parse_unsafe_uri(r, parsed_sr->location, &args, &flags) != NGX_OK) { ctx->headers_sent = 1; return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (args.len > 0 && parsed_sr->query_string == NULL) { parsed_sr->query_string = &args; } rc = ngx_http_echo_send_header_if_needed(r, ctx); if (r->header_only || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } rc = ngx_http_subrequest(r, parsed_sr->location, parsed_sr->query_string, &sr, NULL, 0); if (rc != NGX_OK) { return NGX_ERROR; } rc = ngx_http_echo_adjust_subrequest(sr, parsed_sr); if (rc != NGX_OK) { return rc; } return NGX_OK; }
static ngx_int_t ngx_http_data_dome_subrequest(ngx_http_request_t *r) { ngx_http_request_t *sr; ngx_http_post_subrequest_t *ps; ngx_http_data_dome_auth_ctx_t *ctx; ctx = ngx_http_get_module_ctx(r->main, ngx_http_data_dome_auth_module); ps = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (ps == NULL) { return NGX_ERROR; } ps->handler = ngx_http_data_dome_auth_done; ps->data = ctx; if (ngx_http_subrequest(r, &ctx->uri, NULL, &sr, ps, NGX_HTTP_SUBREQUEST_WAITED | NGX_HTTP_SUBREQUEST_IN_MEMORY) != NGX_OK) { return NGX_ERROR; } /* * allocate fake request body to avoid attempts to read it and to make * sure real body file (if already read) won't be closed by upstream */ sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (sr->request_body == NULL) { return NGX_ERROR; } /* * cleanup headers_in to avoid attempts to send it to the API server */ ngx_memzero(&sr->headers_in, sizeof(ngx_http_upstream_headers_in_t)); if (ngx_list_init(&sr->headers_in.headers, r->pool, 2, sizeof(ngx_table_elt_t)) != NGX_OK) { return NGX_ERROR; } ctx->subrequest = sr; return NGX_AGAIN; }
ngx_int_t nchan_subscriber_authorize_subscribe(subscriber_t *sub, ngx_str_t *ch_id) { ngx_http_complex_value_t *authorize_request_url_ccv = sub->cf->authorize_request_url; ngx_str_t auth_request_url; if(!authorize_request_url_ccv) { return nchan_subscriber_subscribe(sub, ch_id); } else { nchan_auth_subrequest_stuff_t *psr_stuff = ngx_palloc(sub->request->pool, sizeof(*psr_stuff)); assert(psr_stuff != NULL); //ngx_http_request_t *fake_parent_req = fake_cloned_parent_request(sub->request); ngx_http_post_subrequest_t *psr = &psr_stuff->psr; nchan_auth_subrequest_data_t *psrd = &psr_stuff->psr_data; ngx_http_request_t *sr; ngx_http_complex_value(sub->request, authorize_request_url_ccv, &auth_request_url); sub->fn->reserve(sub); psr->handler = subscriber_authorize_callback; psr->data = psrd; psrd->sub = sub; psrd->ch_id = ch_id; ngx_http_subrequest(sub->request, &auth_request_url, NULL, &sr, psr, 0); sr->request_body = ngx_pcalloc(sub->request->pool, sizeof(ngx_http_request_body_t)); //dummy request body if (sr->request_body == NULL) { return NGX_ERROR; } sr->header_only = 1; sr->args = sub->request->args; return NGX_OK; } }
static ngx_int_t ngx_http_auth_radius_init_subrequest( ngx_http_request_t *r, ngx_str_t* url, ngx_str_t* args, ngx_http_post_subrequest_pt handler ) { ngx_http_request_t* sr; ngx_http_post_subrequest_t* ps; ps = ngx_palloc( r->pool, sizeof( ngx_http_post_subrequest_t ) ); if ( ps == NULL ) { return NGX_ERROR; } ps->handler = handler; if ( ngx_http_subrequest( r, url, args, &sr, ps, NGX_HTTP_SUBREQUEST_IN_MEMORY | NGX_HTTP_SUBREQUEST_WAITED ) != NGX_OK ) { return NGX_ERROR; } return NGX_OK; }
static ngx_int_t generic_subscriber_subrequest_old(subscriber_t *sub, ngx_http_complex_value_t *url_ccv, ngx_int_t (*handler)(ngx_http_request_t *, void *, ngx_int_t), ngx_http_request_t **subrequest, ngx_str_t *chid) { ngx_str_t request_url; nchan_subrequest_stuff_t *psr_stuff = ngx_palloc(sub->request->pool, sizeof(*psr_stuff)); assert(psr_stuff != NULL); //ngx_http_request_t *fake_parent_req = fake_cloned_parent_request(sub->request); ngx_http_post_subrequest_t *psr = &psr_stuff->psr; nchan_subrequest_data_t *psrd = &psr_stuff->psr_data; ngx_http_request_t *sr; ngx_http_complex_value(sub->request, url_ccv, &request_url); sub->fn->reserve(sub); psr->handler = handler; psr->data = psrd; psrd->sub = sub; if(chid) { psrd->ch_id = chid; } ngx_http_subrequest(sub->request, &request_url, NULL, &sr, psr, NGX_HTTP_SUBREQUEST_IN_MEMORY); sr->request_body = ngx_pcalloc(sub->request->pool, sizeof(ngx_http_request_body_t)); //dummy request body if (sr->request_body == NULL) { return NGX_ERROR; } sr->header_only = 1; sr->args = sub->request->args; if(subrequest) { *subrequest = sr; } return NGX_OK; }
static ngx_int_t ngx_http_eval_handler(ngx_http_request_t *r) { size_t loc_len; ngx_str_t args; ngx_str_t subrequest_uri; ngx_uint_t flags; ngx_http_core_loc_conf_t *clcf; ngx_http_eval_loc_conf_t *ecf; ngx_http_eval_ctx_t *ctx; ngx_http_request_t *sr; ngx_int_t rc; ngx_http_post_subrequest_t *psr; u_char *p; if(r != r->main && ngx_memn2cmp(r->uri.data, "/eval_", r->uri.len, 6 - 1) == 0) { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); loc_len = r->valid_location ? clcf->name.len : 0; if(r->uri.len != loc_len) { r->uri.data += loc_len; r->uri.len -= loc_len; } else { r->uri.len = 1; } } ecf = ngx_http_get_module_loc_conf(r, ngx_http_eval_module); if(ecf->variables == NULL || !ecf->variables->nelts) { return NGX_DECLINED; } ctx = ngx_http_get_module_ctx(r, ngx_http_eval_module); if(ctx == NULL) { ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_eval_ctx_t)); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ctx->base_conf = ecf; ngx_http_set_ctx(r, ctx, ngx_http_eval_module); } if(ctx->done) { if(!ecf->escalate || ctx->status == NGX_OK || ctx->status == NGX_HTTP_OK) { return NGX_DECLINED; } return ctx->status; } if(ctx->in_progress) { return NGX_AGAIN; } psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return NGX_ERROR; } if(ngx_http_eval_init_variables(r, ctx, ecf) != NGX_OK) { return NGX_ERROR; } args.len = 0; args.data = NULL; flags = 0; subrequest_uri.len = ecf->eval_location.len + r->uri.len; p = subrequest_uri.data = ngx_palloc(r->pool, subrequest_uri.len); if(p == NULL) { return NGX_ERROR; } p = ngx_copy(p, ecf->eval_location.data, ecf->eval_location.len); p = ngx_copy(p, r->uri.data, r->uri.len); if (ngx_http_parse_unsafe_uri(r, &subrequest_uri, &args, &flags) != NGX_OK) { return NGX_ERROR; } psr->handler = ngx_http_eval_post_subrequest_handler; psr->data = ctx; flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY|NGX_HTTP_SUBREQUEST_WAITED; rc = ngx_http_subrequest(r, &subrequest_uri, &args, &sr, psr, flags); if (rc == NGX_ERROR || rc == NGX_DONE) { return rc; } sr->discard_body = 1; ctx->in_progress = 1; /* * Wait for subrequest to complete */ return NGX_AGAIN; }
static ngx_int_t ngx_http_auth_request_handler(ngx_http_request_t *r) { ngx_table_elt_t *h, *ho; ngx_http_request_t *sr; ngx_http_post_subrequest_t *ps; ngx_http_auth_request_ctx_t *ctx; ngx_http_auth_request_conf_t *arcf; arcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_request_module); if (arcf->uri.len == 0) { return NGX_DECLINED; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "auth request handler"); ctx = ngx_http_get_module_ctx(r, ngx_http_auth_request_module); if (ctx != NULL) { if (!ctx->done) { return NGX_AGAIN; } /* * as soon as we are done - explicitly set variables to make * sure they will be available after internal redirects */ if (ngx_http_auth_request_set_variables(r, arcf, ctx) != NGX_OK) { return NGX_ERROR; } /* return appropriate status */ if (ctx->status == NGX_HTTP_FORBIDDEN) { return ctx->status; } if (ctx->status == NGX_HTTP_UNAUTHORIZED) { sr = ctx->subrequest; h = sr->headers_out.www_authenticate; if (!h && sr->upstream) { h = sr->upstream->headers_in.www_authenticate; } if (h) { ho = ngx_list_push(&r->headers_out.headers); if (ho == NULL) { return NGX_ERROR; } *ho = *h; r->headers_out.www_authenticate = ho; } return ctx->status; } if (ctx->status >= NGX_HTTP_OK && ctx->status < NGX_HTTP_SPECIAL_RESPONSE) { return NGX_OK; } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "auth request unexpected status: %d", ctx->status); return NGX_HTTP_INTERNAL_SERVER_ERROR; } ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_auth_request_ctx_t)); if (ctx == NULL) { return NGX_ERROR; } ps = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (ps == NULL) { return NGX_ERROR; } ps->handler = ngx_http_auth_request_done; ps->data = ctx; if (ngx_http_subrequest(r, &arcf->uri, NULL, &sr, ps, NGX_HTTP_SUBREQUEST_WAITED) != NGX_OK) { return NGX_ERROR; } /* * allocate fake request body to avoid attempts to read it and to make * sure real body file (if already read) won't be closed by upstream */ sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (sr->request_body == NULL) { return NGX_ERROR; } sr->header_only = 1; ctx->subrequest = sr; ngx_http_set_ctx(r, ctx, ngx_http_auth_request_module); return NGX_AGAIN; }
static ngx_int_t ngx_http_jstore_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_http_core_main_conf_t *cmcf; ngx_http_jstore_loc_conf_t *jlcf; ngx_http_jstore_ctx_t *ctx; ngx_http_request_t *sr = NULL; ngx_http_upstream_t *u; ngx_chain_t *cl, *jchain; ngx_buf_t *buf, *jbuf; ngx_int_t rc, rc_next; ssize_t n; off_t clen; off_t content_length = r->headers_out.content_length_n; if(in == NULL) { goto pipe; } /* skip jstore's subrequest's response body */ if(ngx_http_jstore_is_subrequest(r)) { for(cl = in; cl; cl = cl->next) { buf = cl->buf; buf->file_pos = buf->file_last; buf->pos = buf->last; buf->sync = 1; buf->memory = 0; buf->in_file = 0; } return NGX_OK; } ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "jstore body filter"); ctx = ngx_http_get_module_ctx(r, ngx_http_jstore_filter_module); if(ctx == NULL || !ctx->store_enable || ctx->subr_sent) { goto pipe; } for(cl = in; cl; cl = cl->next) { buf = cl->buf; if(ngx_buf_special(buf)) { continue; } clen = ngx_buf_size(buf); if(content_length >= 0 && clen + ctx->copied_length > content_length) { ngx_log_error(NGX_LOG_ERR,r->connection->log, 0, "body(%d) is larger than Content-Length(%d)", clen + ctx->copied_length, content_length); goto fail; } /* alloc new buffer, and link it */ jbuf = ngx_create_temp_buf(r->pool, clen); if(jbuf == NULL) { goto fail; } jchain = ngx_alloc_chain_link(r->pool); if(jchain == NULL) { goto pipe; } if(ctx->buf_chain_head == NULL) { ctx->buf_chain_head = jchain; } else { ctx->buf_chain_tail->next = jchain; } ctx->buf_chain_tail = jchain; jchain->buf = jbuf; jchain->next = NULL; /* copy content */ if(buf->in_file && buf->file){ n = ngx_read_file(buf->file, jbuf->start, clen, buf->file_pos); if(n < 0){ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_read_file failed! ret: %d", n); goto fail; } buf->file->offset -= n; } else { ngx_memcpy(jbuf->start, buf->pos, clen); } jbuf->last += clen; ctx->copied_length += clen; } /* upstream done? buffering and non-buffering */ u = r->upstream; if(!(u->pipe && u->pipe->upstream_done) && u->length != 0) { goto pipe; } /* should not happen */ if(content_length >= 0 && ctx->copied_length != content_length) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "JSTORE bug!!"); goto fail; } /* now we have collect all response, so send a subrequest to store it */ /* send the main request first */ rc_next = ngx_http_next_body_filter(r, in); ctx->subr_sent = 1; /* create subrequest */ rc = ngx_http_subrequest(r, &(r->uri), &(r->args), &sr, NULL, 0); if(rc == NGX_ERROR) { goto fail; } /* method */ sr->method = NGX_HTTP_POST; sr->method_name.data = JSUBR_METHOD_STR; sr->method_name.len = JSUBR_METHOD_LEN; /* request headers */ sr->headers_in.headers = u->headers_in.headers; sr->headers_in.content_length_n = ctx->copied_length; /* $proxy_internal_body_length is cacheable, and the subrequest * has different content-lenght with main request, so we have * to clear the variables. */ cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); sr->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts * sizeof(ngx_http_variable_value_t)); /* request body */ sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if(sr->request_body == NULL) { goto fail; } sr->request_body->bufs = ctx->buf_chain_head; /* ngx_http_subrequest() and ngx_http_named_location() both * increase @r->count, but we want it to be incresed once * actually. */ r->count--; /* jump to the named location */ ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "jstore: named-location"); jlcf = ngx_http_get_module_loc_conf(r, ngx_http_jstore_filter_module); ngx_http_named_location(sr, &jlcf->target); return rc_next; fail: ngx_http_set_ctx(r, NULL, ngx_http_jstore_filter_module); pipe: return ngx_http_next_body_filter(r, in); }
static ngx_int_t ngx_http_srcache_fetch_subrequest(ngx_http_request_t *r, ngx_http_srcache_loc_conf_t *conf, ngx_http_srcache_ctx_t *ctx) { ngx_http_srcache_ctx_t *sr_ctx; ngx_http_post_subrequest_t *psr; ngx_str_t args; ngx_uint_t flags = 0; ngx_http_request_t *sr; ngx_int_t rc; ngx_http_srcache_parsed_request_t *parsed_sr; dd_enter(); parsed_sr = ngx_palloc(r->pool, sizeof(ngx_http_srcache_parsed_request_t)); if (parsed_sr == NULL) { return NGX_ERROR; } if (conf->fetch == NULL) { return NGX_ERROR; } parsed_sr->method = conf->fetch->method; parsed_sr->method_name = conf->fetch->method_name; parsed_sr->request_body = NULL; parsed_sr->content_length_n = -1; if (ngx_http_complex_value(r, &conf->fetch->location, &parsed_sr->location) != NGX_OK) { return NGX_ERROR; } if (parsed_sr->location.len == 0) { return NGX_ERROR; } if (ngx_http_complex_value(r, &conf->fetch->args, &parsed_sr->args) != NGX_OK) { return NGX_ERROR; } args.data = NULL; args.len = 0; if (ngx_http_parse_unsafe_uri(r, &parsed_sr->location, &args, &flags) != NGX_OK) { return NGX_ERROR; } if (args.len > 0 && parsed_sr->args.len == 0) { parsed_sr->args = args; } sr_ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_srcache_ctx_t)); if (sr_ctx == NULL) { return NGX_ERROR; } sr_ctx->in_fetch_subrequest = 1; psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return NGX_ERROR; } psr->handler = ngx_http_srcache_fetch_post_subrequest; psr->data = sr_ctx; dd("firing the fetch subrequest"); dd("fetch location: %.*s", (int) parsed_sr->location.len, parsed_sr->location.data); dd("fetch args: %.*s", (int) parsed_sr->args.len, parsed_sr->args.data); rc = ngx_http_subrequest(r, &parsed_sr->location, &parsed_sr->args, &sr, psr, flags); if (rc != NGX_OK) { return NGX_ERROR; } rc = ngx_http_srcache_adjust_subrequest(sr, parsed_sr); if (rc != NGX_OK) { return NGX_ERROR; } ngx_http_set_ctx(sr, sr_ctx, ngx_http_srcache_filter_module); ctx->issued_fetch_subrequest = 1; return NGX_OK; }
static ngx_int_t websocket_publish(full_subscriber_t *fsub, ngx_buf_t *buf) { static ngx_str_t nopublishing = ngx_string("Publishing not allowed."); static ngx_str_t POST_REQUEST_STRING = {4, (u_char *)"POST "}; if(!fsub->sub.cf->pub.websocket) { return websocket_send_close_frame(fsub, CLOSE_POLICY_VIOLATION, &nopublishing); } #if (NGX_DEBUG_POOL) ERR("ws request pool size: %V", ngx_http_debug_pool_str(fsub->sub.request->pool)); #endif ngx_http_complex_value_t *publisher_upstream_request_url_ccv; publisher_upstream_request_url_ccv = fsub->sub.cf->publisher_upstream_request_url; if(publisher_upstream_request_url_ccv == NULL) { websocket_publish_continue(fsub, buf); } else { nchan_pub_upstream_stuff_t *psr_stuff; ngx_http_post_subrequest_t *psr; nchan_pub_upstream_data_t *psrd; ngx_http_request_t *r = fsub->sub.request; ngx_http_request_t *sr; ngx_http_request_body_t *fakebody; ngx_chain_t *fakebody_chain; ngx_buf_t *fakebody_buf; size_t sz; if(!fsub->upstream_stuff) { if((psr_stuff = ngx_palloc(r->pool, sizeof(*psr_stuff))) == NULL) { ERR("can't allocate memory for publisher auth subrequest"); websocket_respond_status(&fsub->sub, NGX_HTTP_INTERNAL_SERVER_ERROR, NULL); return NGX_ERROR; } fsub->upstream_stuff = psr_stuff; psr = &psr_stuff->psr; psr->data = &psr_stuff->psr_data; psr->handler = websocket_publisher_upstream_handler; psr_stuff->psr_data.fsub = fsub; psr_stuff->psr_data.tmp_pool = NULL; ngx_http_complex_value(r, publisher_upstream_request_url_ccv, &psr_stuff->psr_data.upstream_request_url); } psrd = &fsub->upstream_stuff->psr_data; psr = &fsub->upstream_stuff->psr; if(psrd->tmp_pool) { //previous upstream request's pool ngx_destroy_pool(psrd->tmp_pool); psrd->tmp_pool = NULL; } psrd->buf = *buf; psrd->original_pool = r->pool; psrd->original_cleanup = r->cleanup; r->cleanup = NULL; psrd->tmp_pool = ngx_create_pool(NCHAN_WS_UPSTREAM_TMP_POOL_SIZE, r->connection->log); r->pool = psrd->tmp_pool; //ERR("request %p tmp pool %p", r, r->pool); fakebody = ngx_pcalloc(r->pool, sizeof(*fakebody)); if(ngx_buf_size(buf) > 0) { fakebody_chain = ngx_palloc(r->pool, sizeof(*fakebody_chain)); fakebody_buf = ngx_palloc(r->pool, sizeof(*fakebody_buf)); fakebody->bufs = fakebody_chain; fakebody_chain->next = NULL; fakebody_chain->buf = fakebody_buf; init_msg_buf(fakebody_buf); //just copy the buffer contents. it's inefficient but I don't care at the moment. //this can and should be optimized later sz = ngx_buf_size(buf); fakebody_buf->start = ngx_palloc(r->pool, sz); //huuh? ngx_memcpy(fakebody_buf->start, buf->start, sz); fakebody_buf->end = fakebody_buf->start + sz; fakebody_buf->pos = fakebody_buf->start; fakebody_buf->last = fakebody_buf->end; } else { sz = 0; } ngx_http_subrequest(r, &psrd->upstream_request_url, NULL, &sr, psr, NGX_HTTP_SUBREQUEST_IN_MEMORY); nchan_adjust_subrequest(sr, NGX_HTTP_POST, &POST_REQUEST_STRING, fakebody, sz, NULL); /* //http request sudden close cleanup if((psrd->cln = ngx_http_cleanup_add(sr, 0)) == NULL) { ERR("Unable to add request cleanup for websocket upstream request"); return NGX_ERROR; } psrd->cln->data = fsub; psrd->cln->handler = (ngx_http_cleanup_pt )sudden_upstream_request_abort_handler; */ } return NGX_OK; }
static ngx_int_t ngx_http_eval_handler(ngx_http_request_t *r) { size_t loc_len; ngx_str_t args; ngx_str_t subrequest_uri; ngx_uint_t flags; ngx_http_core_loc_conf_t *clcf; ngx_http_eval_loc_conf_t *ecf; ngx_http_eval_ctx_t *ctx; ngx_http_request_t *sr; ngx_int_t rc; ngx_http_post_subrequest_t *psr; ngx_http_eval_block_t *block; u_char *p; if(r != r->main && r->uri.len > 6 && r->uri.data[0] == '/' && r->uri.data[1] == 'e' && r->uri.data[2] == 'v' && r->uri.data[3] == 'a' && r->uri.data[4] == 'l' && r->uri.data[5] == '_') { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); loc_len = r->valid_location ? clcf->name.len : 0; if(r->uri.len != loc_len) { r->uri.data += loc_len; r->uri.len -= loc_len; } else { r->uri.len = 1; } } ecf = ngx_http_get_module_loc_conf(r, ngx_http_eval_module); if(ecf->blocks == NULL || !ecf->blocks->nelts) { return NGX_DECLINED; } ctx = ngx_http_get_module_ctx(r, ngx_http_eval_module); if(ctx == NULL) { ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_eval_ctx_t)); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ctx->base_conf = ecf; ctx->current_block = ecf->blocks->elts; ctx->last_block = ctx->current_block + ecf->blocks->nelts - 1; ngx_http_set_ctx(r, ctx, ngx_http_eval_module); } if(ctx->done) { ctx->in_progress = 0; if(ctx->current_block == ctx->last_block) { if(!ecf->escalate || ctx->status == NGX_OK || ctx->status == NGX_HTTP_OK) { return NGX_DECLINED; } return ctx->status; } ctx->current_block++; } if(ctx->in_progress) { #if defined nginx_version && nginx_version >= 8042 return NGX_DONE; #else return NGX_AGAIN; #endif } /* * Advance to block which has at least one variable */ while(ctx->current_block->variables == NULL || ctx->current_block->variables->nelts == 0) { if(ctx->current_block == ctx->last_block) { return NGX_DECLINED; } ctx->current_block++; } block = ctx->current_block; psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return NGX_ERROR; } if(ngx_http_eval_init_variables(r, ctx, block) != NGX_OK) { return NGX_ERROR; } args.len = r->args.len; args.data = r->args.data; flags = 0; subrequest_uri.len = block->eval_location.len + r->uri.len; p = subrequest_uri.data = ngx_palloc(r->pool, subrequest_uri.len); if(p == NULL) { return NGX_ERROR; } p = ngx_copy(p, block->eval_location.data, block->eval_location.len); p = ngx_copy(p, r->uri.data, r->uri.len); if (ngx_http_parse_unsafe_uri(r, &subrequest_uri, &args, &flags) != NGX_OK) { return NGX_ERROR; } psr->handler = ngx_http_eval_post_subrequest_handler; psr->data = ctx; flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY|NGX_HTTP_SUBREQUEST_WAITED; rc = ngx_http_subrequest(r, &subrequest_uri, &args, &sr, psr, flags); if (rc == NGX_ERROR || rc == NGX_DONE) { return rc; } /* * create a fake request body instead of discarding the real one * in order to avoid attempts to read it */ sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (sr->request_body == NULL) { return NGX_ERROR; } ctx->in_progress = 1; ctx->done = 0; /* * Wait for subrequest to complete */ #if defined nginx_version && nginx_version >= 8042 return NGX_DONE; #else return NGX_AGAIN; #endif }
ngx_int_t ngx_http_echo_exec_echo_location(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) { ngx_int_t rc; ngx_http_request_t *sr; /* subrequest object */ ngx_str_t *computed_arg_elts; ngx_str_t location; ngx_str_t *url_args; ngx_http_post_subrequest_t *psr; ngx_str_t args; ngx_uint_t flags; computed_arg_elts = computed_args->elts; location = computed_arg_elts[0]; if (location.len == 0) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (computed_args->nelts > 1) { url_args = &computed_arg_elts[1]; } else { url_args = NULL; } args.data = NULL; args.len = 0; if (ngx_http_parse_unsafe_uri(r, &location, &args, &flags) != NGX_OK) { ctx->headers_sent = 1; return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (args.len > 0 && url_args == NULL) { url_args = &args; } rc = ngx_http_echo_send_header_if_needed(r, ctx); if (r->header_only || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } psr->handler = ngx_http_echo_post_subrequest; psr->data = ctx; rc = ngx_http_subrequest(r, &location, url_args, &sr, psr, 0); if (rc != NGX_OK) { return NGX_ERROR; } rc = ngx_http_echo_adjust_subrequest(sr); if (rc != NGX_OK) { return rc; } return NGX_OK; }
static ngx_int_t ngx_http_auth_request_handler(ngx_http_request_t *r) { ngx_uint_t i; ngx_int_t rc; ngx_list_part_t *part; ngx_table_elt_t *h, *hi; ngx_http_request_t *sr; ngx_http_post_subrequest_t *ps; ngx_http_auth_request_ctx_t *ctx; ngx_http_auth_request_conf_t *arcf; arcf = ngx_http_get_module_loc_conf(r, ngx_http_shibboleth_module); if (arcf->uri.len == 0) { return NGX_DECLINED; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "shib request handler"); ctx = ngx_http_get_module_ctx(r, ngx_http_shibboleth_module); if (ctx != NULL) { if (!ctx->done) { return NGX_AGAIN; } /* * as soon as we are done - explicitly set variables to make * sure they will be available after internal redirects */ if (ngx_http_auth_request_set_variables(r, arcf, ctx) != NGX_OK) { return NGX_ERROR; } /* * Handle the subrequest * as per the FastCGI authorizer specification. */ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "shib request authorizer handler"); sr = ctx->subrequest; if (ctx->status == NGX_HTTP_OK) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "shib request authorizer allows access"); if (arcf->use_headers) { /* * 200 response may include headers prefixed with `Variable-`, * copy these into main request headers */ part = &sr->headers_out.headers.part; h = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; h = part->elts; i = 0; } if (h[i].hash == 0) { continue; } if (h[i].key.len >= 9 && ngx_strncasecmp(h[i].key.data, (u_char *) "Variable-", 9) == 0) { /* copy header into original request */ hi = ngx_list_push(&r->headers_in.headers); if (hi == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* Strip the Variable- prefix */ hi->key.len = h[i].key.len - 9; hi->key.data = h[i].key.data + 9; hi->hash = ngx_hash_key(hi->key.data, hi->key.len); hi->value = h[i].value; hi->lowcase_key = ngx_pnalloc(r->pool, hi->key.len); if (hi->lowcase_key == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_strlow(hi->lowcase_key, hi->key.data, hi->key.len); ngx_log_debug2( NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "shib request authorizer copied header: \"%V: %V\"", &hi->key, &hi->value); } } } else { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "shib request authorizer not using headers"); } return NGX_OK; } /* * Unconditionally return subrequest response status, headers * and content as per FastCGI spec (section 6.3). * * The subrequest response body cannot be returned as Nginx does not * currently support NGX_HTTP_SUBREQUEST_IN_MEMORY. */ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "shib request authorizer returning sub-response"); /* copy status */ r->headers_out.status = sr->headers_out.status; /* copy headers */ part = &sr->headers_out.headers.part; h = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; h = part->elts; i = 0; } rc = ngx_http_set_output_header(r, h[i].key, h[i].value); if (rc == NGX_ERROR) { return NGX_ERROR; } ngx_log_debug2( NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "shib request authorizer returning header: \"%V: %V\"", &h[i].key, &h[i].value); } return ctx->status; } ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_auth_request_ctx_t)); if (ctx == NULL) { return NGX_ERROR; } ps = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (ps == NULL) { return NGX_ERROR; } ps->handler = ngx_http_auth_request_done; ps->data = ctx; if (ngx_http_subrequest(r, &arcf->uri, NULL, &sr, ps, NGX_HTTP_SUBREQUEST_WAITED) != NGX_OK) { return NGX_ERROR; } /* * allocate fake request body to avoid attempts to read it and to make * sure real body file (if already read) won't be closed by upstream */ sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (sr->request_body == NULL) { return NGX_ERROR; } /* * true FastCGI authorizers should always return the subrequest * response body but the Nginx FastCGI handler does not support * NGX_HTTP_SUBREQUEST_IN_MEMORY at present. */ sr->header_only = 1; ctx->subrequest = sr; ngx_http_set_ctx(r, ctx, ngx_http_shibboleth_module); return NGX_AGAIN; }
ngx_int_t ngx_http_echo_exec_echo_location(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) { ngx_int_t rc; ngx_http_request_t *sr; /* subrequest object */ ngx_str_t *computed_arg_elts; ngx_str_t location; ngx_str_t *url_args; ngx_http_post_subrequest_t *psr; ngx_str_t args; ngx_uint_t flags = 0; ngx_http_echo_ctx_t *sr_ctx; computed_arg_elts = computed_args->elts; location = computed_arg_elts[0]; if (location.len == 0) { return NGX_ERROR; } if (computed_args->nelts > 1) { url_args = &computed_arg_elts[1]; } else { url_args = NULL; } args.data = NULL; args.len = 0; if (ngx_http_parse_unsafe_uri(r, &location, &args, &flags) != NGX_OK) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "echo_location sees unsafe uri: \"%V\"", &location); return NGX_ERROR; } if (args.len > 0 && url_args == NULL) { url_args = &args; } rc = ngx_http_echo_send_header_if_needed(r, ctx); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } sr_ctx = ngx_http_echo_create_ctx(r); psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return NGX_ERROR; } psr->handler = ngx_http_echo_post_subrequest; psr->data = sr_ctx; rc = ngx_http_subrequest(r, &location, url_args, &sr, psr, 0); if (rc != NGX_OK) { return NGX_ERROR; } rc = ngx_http_echo_adjust_subrequest(sr); if (rc != NGX_OK) { return NGX_ERROR; } return NGX_AGAIN; }
ngx_int_t ngx_child_request_start( ngx_http_request_t *r, ngx_child_request_callback_t callback, void* callback_context, ngx_str_t* internal_location, ngx_child_request_params_t* params, ngx_buf_t* response_buffer) { ngx_child_request_context_t* child_ctx; ngx_http_post_subrequest_t *psr; ngx_http_request_t *sr; ngx_uint_t flags; ngx_str_t uri; ngx_int_t rc; u_char* p; // create the child context child_ctx = ngx_pcalloc(r->pool, sizeof(*child_ctx)); if (child_ctx == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_child_request_start: ngx_pcalloc failed"); return NGX_ERROR; } child_ctx->callback = callback; child_ctx->callback_context = callback_context; child_ctx->response_buffer = response_buffer; // build the subrequest uri uri.data = ngx_pnalloc(r->pool, internal_location->len + params->base_uri.len + 1); if (uri.data == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_child_request_start: ngx_palloc failed (2)"); return NGX_ERROR; } p = ngx_copy(uri.data, internal_location->data, internal_location->len); p = ngx_copy(p, params->base_uri.data, params->base_uri.len); *p = '\0'; uri.len = p - uri.data; // create the subrequest psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_child_request_start: ngx_palloc failed (3)"); return NGX_ERROR; } psr->handler = ngx_child_request_finished_handler; psr->data = r; if (is_in_memory(child_ctx)) { if (ngx_list_init(&child_ctx->upstream_headers, r->pool, 8, sizeof(ngx_table_elt_t)) != NGX_OK) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_child_request_start: ngx_list_init failed"); return NGX_ERROR; } flags = NGX_HTTP_SUBREQUEST_WAITED | NGX_HTTP_SUBREQUEST_IN_MEMORY; } else { flags = NGX_HTTP_SUBREQUEST_WAITED; } rc = ngx_http_subrequest(r, &uri, ¶ms->extra_args, &sr, psr, flags); if (rc == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_child_request_start: ngx_http_subrequest failed %i", rc); return rc; } // set the context of the subrequest ngx_http_set_ctx(sr, child_ctx, ngx_http_vod_module); // change the write_event_handler in order to inject the response buffer into the upstream // (this can be done only after the proxy module allocates the upstream) if (is_in_memory(child_ctx)) { sr->write_event_handler = ngx_child_request_initial_wev_handler; } // Note: ngx_http_subrequest always sets the subrequest method to GET if (params->method == NGX_HTTP_HEAD) { sr->method = NGX_HTTP_HEAD; sr->method_name = ngx_http_vod_head_method; } // build the request headers rc = ngx_child_request_copy_headers(r, params, &sr->headers_in, &r->headers_in); if (rc != NGX_OK) { return rc; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_child_request_start: completed successfully sr=%p", sr); return NGX_AGAIN; }
static int ngx_http_lua_ngx_location_capture_multi(lua_State *L) { ngx_http_request_t *r; ngx_http_request_t *sr; /* subrequest object */ ngx_http_post_subrequest_t *psr; ngx_http_lua_ctx_t *sr_ctx; ngx_http_lua_ctx_t *ctx; ngx_array_t *extra_vars; ngx_str_t uri; ngx_str_t args; ngx_str_t extra_args; ngx_uint_t flags; u_char *p; u_char *q; size_t len; size_t nargs; int rc; int n; ngx_uint_t method; ngx_http_request_body_t *body; int type; ngx_buf_t *b; unsigned vars_action; ngx_uint_t nsubreqs; ngx_uint_t index; size_t sr_statuses_len; size_t sr_headers_len; size_t sr_bodies_len; unsigned custom_ctx; n = lua_gettop(L); if (n != 1) { return luaL_error(L, "only one argument is expected, but got %d", n); } luaL_checktype(L, 1, LUA_TTABLE); nsubreqs = lua_objlen(L, 1); if (nsubreqs == 0) { return luaL_error(L, "at least one subrequest should be specified"); } lua_getglobal(L, GLOBALS_SYMBOL_REQUEST); r = lua_touserdata(L, -1); lua_pop(L, 1); if (r == NULL) { return luaL_error(L, "no request object found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx found"); } sr_statuses_len = nsubreqs * sizeof(ngx_int_t); sr_headers_len = nsubreqs * sizeof(ngx_http_headers_out_t *); sr_bodies_len = nsubreqs * sizeof(ngx_str_t); p = ngx_pcalloc(r->pool, sr_statuses_len + sr_headers_len + sr_bodies_len); if (p == NULL) { return luaL_error(L, "out of memory"); } ctx->sr_statuses = (void *) p; p += sr_statuses_len; ctx->sr_headers = (void *) p; p += sr_headers_len; ctx->sr_bodies = (void *) p; ctx->nsubreqs = nsubreqs; n = lua_gettop(L); dd("top before loop: %d", n); ctx->done = 0; ctx->waiting = 0; extra_vars = NULL; for (index = 0; index < nsubreqs; index++) { ctx->waiting++; lua_rawgeti(L, 1, index + 1); if (lua_isnil(L, -1)) { return luaL_error(L, "only array-like tables are allowed"); } dd("queries query: top %d", lua_gettop(L)); if (lua_type(L, -1) != LUA_TTABLE) { return luaL_error(L, "the query argument %d is not a table, " "but a %s", index, lua_typename(L, lua_type(L, -1))); } nargs = lua_objlen(L, -1); if (nargs != 1 && nargs != 2) { return luaL_error(L, "query argument %d expecting one or " "two arguments", index); } lua_rawgeti(L, 2, 1); /* queries query uri */ dd("queries query uri: %d", lua_gettop(L)); dd("first arg in first query: %s", lua_typename(L, lua_type(L, -1))); body = NULL; extra_args.data = NULL; extra_args.len = 0; if (extra_vars != NULL) { /* flush out existing elements in the array */ extra_vars->nelts = 0; } vars_action = 0; custom_ctx = 0; if (nargs == 2) { /* check out the options table */ lua_rawgeti(L, 2, 2); /* queries query uri opts */ dd("queries query uri opts: %d", lua_gettop(L)); if (lua_type(L, 4) != LUA_TTABLE) { return luaL_error(L, "expecting table as the 2nd argument for " "subrequest %d, but got %s", index, luaL_typename(L, 4)); } dd("queries query uri opts: %d", lua_gettop(L)); /* check the args option */ lua_getfield(L, 4, "args"); type = lua_type(L, -1); switch (type) { case LUA_TTABLE: ngx_http_lua_process_args_option(r, L, -1, &extra_args); break; case LUA_TNIL: /* do nothing */ break; case LUA_TNUMBER: case LUA_TSTRING: extra_args.data = (u_char *) lua_tolstring(L, -1, &len); extra_args.len = len; break; default: return luaL_error(L, "Bad args option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the vars option */ lua_getfield(L, 4, "vars"); switch (lua_type(L, -1)) { case LUA_TTABLE: ngx_http_lua_process_vars_option(r, L, -1, &extra_vars); dd("post process vars top: %d", lua_gettop(L)); break; case LUA_TNIL: /* do nothing */ break; default: return luaL_error(L, "Bad vars option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the share_all_vars option */ lua_getfield(L, 4, "share_all_vars"); switch (lua_type(L, -1)) { case LUA_TNIL: /* do nothing */ break; case LUA_TBOOLEAN: if (lua_toboolean(L, -1)) { vars_action |= NGX_HTTP_LUA_SHARE_ALL_VARS; } break; default: return luaL_error(L, "Bad share_all_vars option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the copy_all_vars option */ lua_getfield(L, 4, "copy_all_vars"); switch (lua_type(L, -1)) { case LUA_TNIL: /* do nothing */ break; case LUA_TBOOLEAN: if (lua_toboolean(L, -1)) { vars_action |= NGX_HTTP_LUA_COPY_ALL_VARS; } break; default: return luaL_error(L, "Bad copy_all_vars option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the "method" option */ lua_getfield(L, 4, "method"); type = lua_type(L, -1); if (type == LUA_TNIL) { method = NGX_HTTP_GET; } else { if (type != LUA_TNUMBER) { return luaL_error(L, "Bad http request method"); } method = (ngx_uint_t) lua_tonumber(L, -1); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the "ctx" option */ lua_getfield(L, 4, "ctx"); type = lua_type(L, -1); if (type != LUA_TNIL) { if (type != LUA_TTABLE) { return luaL_error(L, "Bad ctx option value type %s, " "expected a Lua table", lua_typename(L, type)); } custom_ctx = 1; } else { lua_pop(L, 1); } dd("queries query uri opts ctx?: %d", lua_gettop(L)); /* check the "body" option */ lua_getfield(L, 4, "body"); type = lua_type(L, -1); if (type != LUA_TNIL) { if (type != LUA_TSTRING && type != LUA_TNUMBER) { return luaL_error(L, "Bad http request body"); } body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (body == NULL) { return luaL_error(L, "out of memory"); } q = (u_char *) lua_tolstring(L, -1, &len); dd("request body: [%.*s]", (int) len, q); if (len) { b = ngx_create_temp_buf(r->pool, len); if (b == NULL) { return luaL_error(L, "out of memory"); } b->last = ngx_copy(b->last, q, len); body->bufs = ngx_alloc_chain_link(r->pool); if (body->bufs == NULL) { return luaL_error(L, "out of memory"); } body->bufs->buf = b; body->bufs->next = NULL; body->buf = b; } } lua_pop(L, 1); /* pop the body */ /* stack: queries query uri opts ctx? */ lua_remove(L, 4); /* stack: queries query uri ctx? */ dd("queries query uri ctx?: %d", lua_gettop(L)); } else { method = NGX_HTTP_GET; } /* stack: queries query uri ctx? */ n = lua_gettop(L); dd("top size so far: %d", n); p = (u_char *) luaL_checklstring(L, 3, &len); uri.data = ngx_palloc(r->pool, len); if (uri.data == NULL) { return luaL_error(L, "memory allocation error"); } ngx_memcpy(uri.data, p, len); uri.len = len; args.data = NULL; args.len = 0; flags = 0; rc = ngx_http_parse_unsafe_uri(r, &uri, &args, &flags); if (rc != NGX_OK) { dd("rc = %d", (int) rc); return luaL_error(L, "unsafe uri in argument #1: %s", p); } if (args.len == 0) { args = extra_args; } else if (extra_args.len) { /* concatenate the two parts of args together */ len = args.len + (sizeof("&") - 1) + extra_args.len; p = ngx_palloc(r->pool, len); if (p == NULL) { return luaL_error(L, "out of memory"); } q = ngx_copy(p, args.data, args.len); *q++ = '&'; ngx_memcpy(q, extra_args.data, extra_args.len); args.data = p; args.len = len; } psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return luaL_error(L, "memory allocation error"); } sr_ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t)); if (sr_ctx == NULL) { return luaL_error(L, "out of memory"); } /* set by ngx_pcalloc: * sr_ctx->run_post_subrequest = 0 * sr_ctx->free = NULL */ sr_ctx->cc_ref = LUA_NOREF; sr_ctx->ctx_ref = LUA_NOREF; sr_ctx->capture = 1; sr_ctx->index = index; psr->handler = ngx_http_lua_post_subrequest; psr->data = sr_ctx; rc = ngx_http_subrequest(r, &uri, &args, &sr, psr, 0); if (rc != NGX_OK) { return luaL_error(L, "failed to issue subrequest: %d", (int) rc); } ngx_http_set_ctx(sr, sr_ctx, ngx_http_lua_module); rc = ngx_http_lua_adjust_subrequest(sr, method, body, vars_action, extra_vars); if (rc != NGX_OK) { return luaL_error(L, "failed to adjust the subrequest: %d", (int) rc); } dd("queries query uri opts ctx? %d", lua_gettop(L)); /* stack: queries query uri ctx? */ if (custom_ctx) { ngx_http_lua_ngx_set_ctx_helper(L, sr, sr_ctx, -1); lua_pop(L, 3); } else { lua_pop(L, 2); } /* stack: queries */ } if (extra_vars) { ngx_array_destroy(extra_vars); } return lua_yield(L, 0); }
static ngx_int_t ngx_http_fancyindex_handler(ngx_http_request_t *r) { ngx_http_request_t *sr; ngx_str_t *sr_uri; ngx_str_t rel_uri; ngx_int_t rc; ngx_http_fancyindex_loc_conf_t *alcf; ngx_chain_t out[3] = { { NULL, NULL }, { NULL, NULL}, { NULL, NULL }}; if (r->uri.data[r->uri.len - 1] != '/') { return NGX_DECLINED; } /* TODO: Win32 */ #if defined(nginx_version) \ && ((nginx_version < 7066) \ || ((nginx_version > 8000) && (nginx_version < 8038))) if (r->zero_in_uri) { return NGX_DECLINED; } #endif if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_DECLINED; } alcf = ngx_http_get_module_loc_conf(r, ngx_http_fancyindex_module); if (!alcf->enable) { return NGX_DECLINED; } if ((rc = make_content_buf(r, &out[0].buf, alcf) != NGX_OK)) return rc; out[0].buf->last_in_chain = 1; r->headers_out.status = NGX_OK; r->headers_out.content_type_len = ngx_sizeof_ssz("text/html"); r->headers_out.content_type.len = ngx_sizeof_ssz("text/html"); r->headers_out.content_type.data = (u_char *) "text/html"; rc = ngx_http_send_header(r); if (rc != NGX_OK || r->header_only) return rc; if (alcf->header.len > 0) { /* URI is configured, make Nginx take care of with a subrequest. */ sr_uri = &alcf->header; if (*sr_uri->data != '/') { /* Relative path */ rel_uri.len = r->uri.len + alcf->header.len; rel_uri.data = ngx_palloc(r->pool, rel_uri.len); if (rel_uri.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_memcpy(ngx_cpymem(rel_uri.data, r->uri.data, r->uri.len), alcf->header.data, alcf->header.len); sr_uri = &rel_uri; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex: header subrequest \"%V\"", sr_uri); rc = ngx_http_subrequest(r, sr_uri, NULL, &sr, NULL, 0); if (rc == NGX_ERROR || rc == NGX_DONE) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex: header subrequest for \"%V\" failed", sr_uri); return rc; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex: header subrequest status = %i", sr->headers_out.status); /* ngx_http_subrequest returns NGX_OK(0), not NGX_HTTP_OK(200) */ if (sr->headers_out.status != NGX_OK) { /* * XXX: Should we write a message to the error log just in case * we get something different from a 404? */ goto add_builtin_header; } } else { add_builtin_header: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex: adding built-in header"); /* Make space before */ out[1].next = out[0].next; out[1].buf = out[0].buf; /* Chain header buffer */ out[0].next = &out[1]; out[0].buf = make_header_buf(r, alcf->css_href); } /* If footer is disabled, chain up footer buffer. */ if (alcf->footer.len == 0) { ngx_uint_t last = (alcf->header.len == 0) ? 2 : 1; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex: adding built-in footer at %i", last); out[last-1].next = &out[last]; out[last].buf = make_footer_buf(r); out[last-1].buf->last_in_chain = 0; out[last].buf->last_in_chain = 1; out[last].buf->last_buf = 1; /* Send everything with a single call :D */ return ngx_http_output_filter(r, &out[0]); } /* * If we reach here, we were asked to send a custom footer. We need to: * partially send whatever is referenced from out[0] and then send the * footer as a subrequest. If the subrequest fails, we should send the * standard footer as well. */ rc = ngx_http_output_filter(r, &out[0]); if (rc != NGX_OK && rc != NGX_AGAIN) return NGX_HTTP_INTERNAL_SERVER_ERROR; /* URI is configured, make Nginx take care of with a subrequest. */ sr_uri = &alcf->footer; if (*sr_uri->data != '/') { /* Relative path */ rel_uri.len = r->uri.len + alcf->footer.len; rel_uri.data = ngx_palloc(r->pool, rel_uri.len); if (rel_uri.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_memcpy(ngx_cpymem(rel_uri.data, r->uri.data, r->uri.len), alcf->footer.data, alcf->footer.len); sr_uri = &rel_uri; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex: footer subrequest \"%V\"", sr_uri); rc = ngx_http_subrequest(r, sr_uri, NULL, &sr, NULL, 0); if (rc == NGX_ERROR || rc == NGX_DONE) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex: footer subrequest for \"%V\" failed", sr_uri); return rc; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex: header subrequest status = %i", sr->headers_out.status); /* see above: ngx_http_subrequest resturns NGX_OK (0) not NGX_HTTP_OK (200) */ if (sr->headers_out.status != NGX_OK) { /* * XXX: Should we write a message to the error log just in case * we get something different from a 404? */ out[0].next = NULL; out[0].buf = make_footer_buf(r); out[0].buf->last_in_chain = 1; out[0].buf->last_buf = 1; /* Directly send out the builtin footer */ return ngx_http_output_filter(r, &out[0]); } return (r != r->main) ? rc : ngx_http_send_special(r, NGX_HTTP_LAST); }
static ngx_int_t ngx_http_srcache_store_subrequest(ngx_http_request_t *r, ngx_http_srcache_ctx_t *ctx) { ngx_http_srcache_ctx_t *sr_ctx; ngx_str_t args; ngx_uint_t flags = 0; ngx_http_request_t *sr; ngx_int_t rc; ngx_http_request_body_t *rb = NULL; ngx_http_srcache_loc_conf_t *conf; ngx_http_post_subrequest_t *psr; ngx_http_srcache_parsed_request_t *parsed_sr; dd("store subrequest"); conf = ngx_http_get_module_loc_conf(r, ngx_http_srcache_filter_module); if (conf->store == NULL) { dd("conf store is NULL"); return NGX_ERROR; } parsed_sr = ngx_palloc(r->pool, sizeof(ngx_http_srcache_parsed_request_t)); if (parsed_sr == NULL) { return NGX_ERROR; } parsed_sr->method = conf->store->method; parsed_sr->method_name = conf->store->method_name; if (ctx->body_to_cache) { dd("found body to cache (len %d)", (int) ctx->response_length); rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { return NGX_ERROR; } rb->bufs = ctx->body_to_cache; rb->buf = ctx->body_to_cache->buf; parsed_sr->request_body = rb; } else { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "srcache_store: no request body for the subrequest"); return NGX_ERROR; } parsed_sr->content_length_n = ctx->response_length; if (ngx_http_complex_value(r, &conf->store->location, &parsed_sr->location) != NGX_OK) { return NGX_ERROR; } if (parsed_sr->location.len == 0) { return NGX_ERROR; } if (ngx_http_complex_value(r, &conf->store->args, &parsed_sr->args) != NGX_OK) { return NGX_ERROR; } args.data = NULL; args.len = 0; if (ngx_http_parse_unsafe_uri(r, &parsed_sr->location, &args, &flags) != NGX_OK) { return NGX_ERROR; } if (args.len > 0 && parsed_sr->args.len == 0) { parsed_sr->args = args; } dd("firing the store subrequest"); dd("store location: %.*s", (int) parsed_sr->location.len, parsed_sr->location.data); dd("store args: %.*s", (int) parsed_sr->args.len, parsed_sr->args.data); sr_ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_srcache_ctx_t)); if (sr_ctx == NULL) { return NGX_ERROR; } sr_ctx->in_store_subrequest = 1; psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return NGX_ERROR; } psr->handler = ngx_http_srcache_store_post_subrequest; psr->data = sr_ctx; rc = ngx_http_subrequest(r, &parsed_sr->location, &parsed_sr->args, &sr, psr, flags); if (rc != NGX_OK) { return NGX_ERROR; } rc = ngx_http_srcache_adjust_subrequest(sr, parsed_sr); if (rc != NGX_OK) { return NGX_ERROR; } ngx_http_set_ctx(sr, sr_ctx, ngx_http_srcache_filter_module); return NGX_OK; }
static ngx_int_t ngx_http_mogilefs_put_handler(ngx_http_request_t *r) { ngx_http_mogilefs_put_ctx_t *ctx; ngx_str_t args; ngx_uint_t flags; ngx_http_request_t *sr; ngx_str_t spare_location = ngx_null_string, uri, value; ngx_int_t rc; u_char *p; ngx_http_core_loc_conf_t *clcf; ngx_http_mogilefs_loc_conf_t *mgcf; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "mogilefs put handler"); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); mgcf = ngx_http_get_module_loc_conf(r, ngx_http_mogilefs_module); if (clcf->handler != ngx_http_mogilefs_handler || (mgcf->location_type == NGX_MOGILEFS_MAIN && !(r->method & mgcf->methods))) { return NGX_DECLINED; } ctx = ngx_http_get_module_ctx(r, ngx_http_mogilefs_module); if(ctx == NULL) { ctx = ngx_palloc(r->pool, sizeof(ngx_http_mogilefs_put_ctx_t)); if (ctx == NULL) { return NGX_ERROR; } ctx->psr = NULL; ctx->state = START; ctx->status = 0; ctx->create_open_ctx = NULL; if(ngx_http_mogilefs_eval_key(r, &ctx->key) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_http_set_ctx(r, ctx, ngx_http_mogilefs_module); } if(ctx->psr == NULL) { ctx->psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (ctx->psr == NULL) { return NGX_ERROR; } } if(r->request_body == NULL) { rc = ngx_http_read_client_request_body(r, ngx_http_mogilefs_body_handler); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } return NGX_DONE; } // Still receiving body? if(r->request_body->rest) { return NGX_DONE; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "mogilefs put handler state: %ui, status: %i", ctx->state, ctx->status); if(ctx->state == CREATE_OPEN || ctx->state == FETCH || ctx->state == CREATE_CLOSE) { if(ctx->status != NGX_OK && ctx->status != NGX_HTTP_CREATED && ctx->status != NGX_HTTP_NO_CONTENT) { return (ctx->status >= NGX_HTTP_SPECIAL_RESPONSE) ? ctx->status : NGX_HTTP_INTERNAL_SERVER_ERROR; } } switch(ctx->state) { case START: spare_location = mgcf->create_open_spare_location; ctx->state = CREATE_OPEN; break; case CREATE_OPEN: spare_location = mgcf->fetch_location; ctx->state = FETCH; break; case FETCH: spare_location = mgcf->create_close_spare_location; ctx->state = CREATE_CLOSE; break; case CREATE_CLOSE: r->headers_out.content_length_n = 0; r->headers_out.status = NGX_HTTP_CREATED; r->header_only = 1; return ngx_http_send_header(r); } uri.len = spare_location.len + ctx->key.len; uri.data = ngx_palloc(r->pool, uri.len); p = ngx_cpymem(uri.data, spare_location.data, spare_location.len); p = ngx_cpymem(p, ctx->key.data, ctx->key.len); args.len = 0; args.data = NULL; flags = 0; if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) { return NGX_ERROR; } ctx->psr->handler = ngx_http_mogilefs_finish_phase_handler; ctx->psr->data = ctx; flags |= NGX_HTTP_SUBREQUEST_WAITED; if(ctx->state == FETCH) { flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY; } rc = ngx_http_subrequest(r, &uri, &args, &sr, ctx->psr, flags); if (rc == NGX_ERROR) { return rc; } if(ctx->state == CREATE_CLOSE) { ngx_http_set_ctx(sr, ctx->create_open_ctx, ngx_http_mogilefs_module); value.data = ngx_palloc(r->pool, NGX_OFF_T_LEN); if(value.data == NULL) { return NGX_ERROR; } value.len = ngx_sprintf(value.data, "%O", r->headers_in.content_length_n) - value.data; if(ngx_http_mogilefs_add_aux_param(sr, &ngx_http_mogilefs_size, &value) != NGX_OK) { return NGX_ERROR; } } /* * Nginx closes temporary file with buffered body * whenever it starts sending reponse from upstream * and it is not doing subrequest in memory. * * Since the request body in create_open subrequest is * inherited from main request, it is necessary to prevent * nginx from closing the temporary file with request body, * before it could be passed to the storage node on fetch/store * stage. * * We do it by "hiding" the request body from nginx internals. */ if(ctx->state == CREATE_OPEN) { sr->request_body = NULL; } sr->method = NGX_HTTP_PUT; sr->method_name = ngx_http_mogilefs_put_method; /* * Wait for subrequest to complete */ return NGX_DONE; }