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_int_t ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) { ngx_buf_t *b; ngx_chain_t *cl; if (buf->pos == buf->last) { return NGX_OK; } if (p->free) { cl = p->free; b = cl->buf; p->free = cl->next; ngx_free_chain(p->pool, cl); } else { b = ngx_alloc_buf(p->pool); if (b == NULL) { return NGX_ERROR; } } ngx_memcpy(b, buf, sizeof(ngx_buf_t)); b->shadow = buf; b->tag = p->tag; b->last_shadow = 1; b->recycled = 1; buf->shadow = b; cl = ngx_alloc_chain_link(p->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; cl->next = NULL; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num); if (p->in) { *p->last_in = cl; } else { p->in = cl; } p->last_in = &cl->next; if (p->length == -1) { return NGX_OK; } p->length -= b->last - b->pos; return NGX_OK; }
ngx_int_t ngx_http_echo_exec_echo_request_body(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx) { ngx_buf_t *b; ngx_chain_t *out, *cl, **ll; if (r->request_body == NULL || r->request_body->bufs == NULL) { return NGX_OK; } out = NULL; ll = &out; for (cl = r->request_body->bufs; cl; cl = cl->next) { if (ngx_buf_special(cl->buf)) { /* we do not want to create zero-size bufs */ continue; } *ll = ngx_alloc_chain_link(r->pool); if (*ll == NULL) { return NGX_ERROR; } b = ngx_alloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } (*ll)->buf = b; (*ll)->next = NULL; ngx_memcpy(b, cl->buf, sizeof(ngx_buf_t)); b->tag = (ngx_buf_tag_t) &ngx_http_echo_exec_echo_request_body; b->last_buf = 0; b->last_in_chain = 0; ll = &(*ll)->next; } if (out == NULL) { return NGX_OK; } return ngx_http_echo_send_chain_link(r, ctx, out); }
static ngx_int_t ngx_http_ajp_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) { ngx_int_t rc; ngx_buf_t *b, **prev; ngx_chain_t *cl; ngx_http_request_t *r; ngx_http_ajp_ctx_t *a; ngx_http_ajp_loc_conf_t *alcf; if (buf->pos == buf->last) { return NGX_OK; } r = p->input_ctx; a = ngx_http_get_module_ctx(r, ngx_http_ajp_module); alcf = ngx_http_get_module_loc_conf(r, ngx_http_ajp_module); ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "ngx_http_ajp_input_filter: state(%d)", a->state); b = NULL; prev = &buf->shadow; while(buf->pos < buf->last) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->log, 0, "input filter packet, begin length: %z, buffer_size: %z", a->length, ngx_buf_size(buf)); /* This a new data packet */ if (a->length == 0) { if (a->extra_zero_byte) { if (*(buf->pos) == 0x00){ buf->pos++; } a->extra_zero_byte = 0; } rc = ngx_http_ajp_process_packet_header(r, a, buf); if (buf->pos == buf->last) { break; } if (rc == NGX_AGAIN) { break; } if (rc == NGX_DONE) { break; } if (rc == NGX_ERROR) { return NGX_ERROR; } } /* Get a zero length packet */ if (a->length == 0) { if (a->extra_zero_byte && (buf->pos < buf->last) && (*(buf->pos) == 0x00)) { buf->pos++; a->extra_zero_byte = 0; } continue; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->log, 0, "input filter packet, length:%z, buffer_size:%z", a->length, ngx_buf_size(buf)); if (p->free) { b = p->free->buf; p->free = p->free->next; } else { b = ngx_alloc_buf(p->pool); if (b == NULL) { return NGX_ERROR; } } ngx_memzero(b, sizeof(ngx_buf_t)); b->pos = buf->pos; b->start = buf->start; b->end = buf->end; b->tag = p->tag; b->temporary = 1; b->recycled = 1; *prev = b; prev = &b->shadow; cl = ngx_alloc_chain_link(p->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; cl->next = NULL; if (p->in) { *p->last_in = cl; } else { p->in = cl; } p->last_in = &cl->next; /* STUB */ b->num = buf->num; if (buf->pos + a->length < buf->last) { buf->pos += a->length; b->last = buf->pos; a->length = 0; } else { a->length -= buf->last - buf->pos; buf->pos = buf->last; b->last = buf->last; } if (b->pos == b->last) { b->sync = 1; } if ((a->length == 0) && a->extra_zero_byte && (buf->pos < buf->last) && (*(buf->pos) == 0x00)) { /* The last byte of this message always seems to be * 0x00 and is not part of the chunk. */ buf->pos++; a->extra_zero_byte = 0; } ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d %p size: %z", b->num, b->pos, b->last - b->pos); } ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0, "free buf %p %z", buf->pos, ngx_buf_size(buf)); if (alcf->keep_conn) { /* set p->length, minimal amount of data we want to see */ if (!a->length) { p->length = 1; } else { p->length = a->length; } if (p->upstream_done) { p->length = 0; } } if (b) { b->shadow = buf; b->last_shadow = 1; ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf %p %z", b->pos, ngx_buf_size(buf)); return NGX_OK; } /* there is no data record in the buf, add it to free chain */ if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) { return NGX_ERROR; } return NGX_OK; }
ngx_chain_t * ajp_data_msg_send_body(ngx_http_request_t *r, size_t max_size, ngx_chain_t **body) { size_t size; ngx_buf_t *b_in, *b_out; ajp_msg_t *msg; ngx_chain_t *out, *cl, *in; ngx_http_ajp_ctx_t *a; a = ngx_http_get_module_ctx(r, ngx_http_ajp_module); if (*body == NULL || a == NULL) { return NULL; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ajp_data_msg_send_body"); msg = ajp_msg_reuse(&a->msg); if (ajp_alloc_data_msg(r->pool, msg) != NGX_OK) { return NULL; } out = cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NULL; } cl->buf = msg->buf; max_size -= AJP_HEADER_SZ; size = 0; in = *body; b_out = NULL; while (in) { b_in = in->buf; b_out = ngx_alloc_buf(r->pool); if (b_out == NULL) { return NULL; } ngx_memcpy(b_out, b_in, sizeof(ngx_buf_t)); if (b_in->in_file) { if ((size_t)(b_in->file_last - b_in->file_pos) <= (max_size - size)) { b_out->file_pos = b_in->file_pos; b_out->file_last = b_in->file_pos = b_in->file_last; size += (size_t) b_out->file_last - (size_t) b_out->file_pos; } else if ((size_t)(b_in->file_last - b_in->file_pos) > (max_size - size)) { b_out->file_pos = b_in->file_pos; b_in->file_pos += max_size - size; b_out->file_last = b_in->file_pos; size += (size_t) b_out->file_last - (size_t) b_out->file_pos; } } else { if ((size_t)(b_in->last - b_in->pos) <= (max_size - size)) { b_out->pos = b_in->pos; b_out->last = b_in->pos = b_in->last; size += b_out->last - b_out->pos; } else if ((size_t)(b_in->last - b_in->pos) > (max_size - size)) { b_out->pos = b_in->pos; b_in->pos += max_size - size; b_out->last = b_in->pos; size += b_out->last - b_out->pos; } } cl->next = ngx_alloc_chain_link(r->pool); if (cl->next == NULL) { return NULL; } cl = cl->next; cl->buf = b_out; if (size >= max_size) { break; } else { in = in->next; } } *body = in; cl->next = NULL; ajp_data_msg_end(msg, size); return out; }
static ngx_int_t create_request(ngx_http_request_t *r) { passenger_loc_conf_t *slcf; passenger_context_t *context; buffer_construction_state state; ngx_uint_t request_size; ngx_buf_t *b; ngx_chain_t *cl, *body; slcf = ngx_http_get_module_loc_conf(r, ngx_http_passenger_module); context = ngx_http_get_module_ctx(r, ngx_http_passenger_module); if (context == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* Construct and pass request headers */ if (prepare_request_buffer_construction(r, context, &state) != NGX_OK) { return NGX_ERROR; } request_size = construct_request_buffer(r, slcf, context, &state, NULL); b = ngx_create_temp_buf(r->pool, request_size); if (b == NULL) { return NGX_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; construct_request_buffer(r, slcf, context, &state, b); /* Pass request body */ body = r->upstream->request_bufs; r->upstream->request_bufs = cl; while (body) { b = ngx_alloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } ngx_memcpy(b, body->buf, sizeof(ngx_buf_t)); cl->next = ngx_alloc_chain_link(r->pool); if (cl->next == NULL) { return NGX_ERROR; } cl = cl->next; cl->buf = b; body = body->next; } b->flush = 1; cl->next = NULL; return NGX_OK; }
static ngx_int_t ngx_http_sub_body_filter(void *context, ngx_chain_t *in) { ngx_int_t rc; ngx_buf_t *b; ngx_chain_t *cl; ngx_http_sub_ctx_t *ctx; ngx_http_sub_loc_conf_t *slcf; ngx_http_request_t *r = (ngx_http_request_t*)context; ctx = ngx_http_get_module_ctx(r, ngx_http_sub_filter_module); if (ctx == NULL) { return ngx_http_next_body_filter(r, in); } if ((in == NULL && ctx->buf == NULL && ctx->in == NULL && ctx->busy == NULL)) { return ngx_http_next_body_filter(r, in); } if (ctx->once && (ctx->buf == NULL || ctx->in == NULL)) { if (ctx->busy) { if (ngx_http_sub_output(r, ctx) == NGX_ERROR) { return NGX_ERROR; } } return ngx_http_next_body_filter(r, in); } /* add the incoming chain to the chain ctx->in */ if (in) { if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { return NGX_ERROR; } } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http sub filter \"%V\"", &r->uri); while (ctx->in || ctx->buf) { if (ctx->buf == NULL) { ctx->buf = ctx->in->buf; ctx->in = ctx->in->next; ctx->pos = ctx->buf->pos; } if (ctx->state == sub_start_state) { ctx->copy_start = ctx->pos; ctx->copy_end = ctx->pos; } b = NULL; while (ctx->pos < ctx->buf->last) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "saved: \"%V\" state: %d", &ctx->saved, ctx->state); rc = ngx_http_sub_parse(r, ctx); ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "parse: %d, looked: \"%V\" %p-%p", rc, &ctx->looked, ctx->copy_start, ctx->copy_end); if (rc == NGX_ERROR) { return rc; } if (ctx->copy_start != ctx->copy_end) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "saved: \"%V\"", &ctx->saved); if (ctx->saved.len) { if (ctx->free) { cl = ctx->free; ctx->free = ctx->free->next; b = cl->buf; ngx_memzero(b, sizeof(ngx_buf_t)); } else { b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; } b->pos = ngx_pnalloc(r->pool, ctx->saved.len); if (b->pos == NULL) { return NGX_ERROR; } ngx_memcpy(b->pos, ctx->saved.data, ctx->saved.len); b->last = b->pos + ctx->saved.len; b->memory = 1; *ctx->last_out = cl; ctx->last_out = &cl->next; ctx->saved.len = 0; } if (ctx->free) { cl = ctx->free; ctx->free = ctx->free->next; b = cl->buf; } else { b = ngx_alloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; } ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t)); b->pos = ctx->copy_start; b->last = ctx->copy_end; b->shadow = NULL; b->last_buf = 0; b->recycled = 0; if (b->in_file) { b->file_last = b->file_pos + (b->last - ctx->buf->pos); b->file_pos += b->pos - ctx->buf->pos; } cl->next = NULL; *ctx->last_out = cl; ctx->last_out = &cl->next; } if (ctx->state == sub_start_state) { ctx->copy_start = ctx->pos; ctx->copy_end = ctx->pos; } else { ctx->copy_start = NULL; ctx->copy_end = NULL; } if (rc == NGX_AGAIN) { continue; } /* rc == NGX_OK */ b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module); if (ctx->sub.data == NULL) { if (ngx_http_complex_value(r, &slcf->value, &ctx->sub) != NGX_OK) { return NGX_ERROR; } } if (ctx->sub.len) { b->memory = 1; b->pos = ctx->sub.data; b->last = ctx->sub.data + ctx->sub.len; } else { b->sync = 1; } cl->buf = b; cl->next = NULL; *ctx->last_out = cl; ctx->last_out = &cl->next; ctx->once = slcf->once; continue; } if (ctx->buf->last_buf || ngx_buf_in_memory(ctx->buf)) { if (b == NULL) { if (ctx->free) { cl = ctx->free; ctx->free = ctx->free->next; b = cl->buf; ngx_memzero(b, sizeof(ngx_buf_t)); } else { b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; } b->sync = 1; cl->next = NULL; *ctx->last_out = cl; ctx->last_out = &cl->next; } b->last_buf = ctx->buf->last_buf; b->shadow = ctx->buf; b->recycled = ctx->buf->recycled; } ctx->buf = NULL; ctx->saved.len = ctx->looked.len; ngx_memcpy(ctx->saved.data, ctx->looked.data, ctx->looked.len); } if (ctx->out == NULL && ctx->busy == NULL) { return NGX_OK; } return ngx_http_sub_output(r, ctx); }
static ngx_int_t create_request(ngx_http_request_t *r) { u_char ch; const char * helper_agent_request_socket_password_data; unsigned int helper_agent_request_socket_password_len; u_char buf[sizeof("4294967296") + 1]; size_t len, size, key_len, val_len; const u_char *app_type_string; size_t app_type_string_len; int server_name_len; ngx_str_t escaped_uri; ngx_str_t *union_station_filters = NULL; void *tmp; ngx_uint_t i, n; ngx_buf_t *b; ngx_chain_t *cl, *body; ngx_list_part_t *part; ngx_table_elt_t *header; ngx_http_script_code_pt code; ngx_http_script_engine_t e, le; ngx_http_core_srv_conf_t *cscf; passenger_loc_conf_t *slcf; passenger_context_t *context; ngx_http_script_len_code_pt lcode; cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); slcf = ngx_http_get_module_loc_conf(r, ngx_http_passenger_module); context = ngx_http_get_module_ctx(r, ngx_http_passenger_module); if (context == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } app_type_string = (const u_char *) pp_get_app_type_name(context->app_type); app_type_string_len = strlen((const char *) app_type_string) + 1; /* include null terminator */ /* * Nginx unescapes URI's before passing them to Phusion Passenger, * but backend processes expect the escaped version. * http://code.google.com/p/phusion-passenger/issues/detail?id=404 */ escaped_uri.len = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, NGX_ESCAPE_URI) + r->uri.len; escaped_uri.data = ngx_pnalloc(r->pool, escaped_uri.len + 1); escaped_uri.data[escaped_uri.len] = '\0'; ngx_escape_uri(escaped_uri.data, r->uri.data, r->uri.len, NGX_ESCAPE_URI); /************************************************** * Determine the request header length. **************************************************/ len = 0; /* Length of the Content-Length header. A value of -1 means that the content * length is unspecified, which is the case for e.g. WebSocket requests. */ if (r->headers_in.content_length_n >= 0) { len += sizeof("CONTENT_LENGTH") + uint_to_str(r->headers_in.content_length_n, buf, sizeof(buf)) + 1; /* +1 for trailing null */ } /* DOCUMENT_ROOT, SCRIPT_NAME, RAILS_RELATIVE_URL_ROOT, PATH_INFO and REQUEST_URI. */ len += sizeof("DOCUMENT_ROOT") + context->public_dir.len + 1; if (context->base_uri.len > 0) { len += sizeof("SCRIPT_NAME") + context->base_uri.len + 1; len += sizeof("RAILS_RELATIVE_URL_ROOT") + context->base_uri.len + 1; len += sizeof("PATH_INFO") + escaped_uri.len - context->base_uri.len + 1; } else { len += sizeof("SCRIPT_NAME") + sizeof(""); len += sizeof("PATH_INFO") + escaped_uri.len + 1; } len += sizeof("REQUEST_URI") + escaped_uri.len + 1; if (r->args.len > 0) { len += 1 + r->args.len; } /* SERVER_NAME; must be equal to HTTP_HOST without the port part */ if (r->headers_in.host != NULL) { tmp = memchr(r->headers_in.host->value.data, ':', r->headers_in.host->value.len); if (tmp == NULL) { server_name_len = r->headers_in.host->value.len; } else { server_name_len = (int) ((const u_char *) tmp - r->headers_in.host->value.data); } } else { server_name_len = cscf->server_name.len; } len += sizeof("SERVER_NAME") + server_name_len + 1; /* Various other HTTP headers. */ if (r->headers_in.content_type != NULL && r->headers_in.content_type->value.len > 0) { len += sizeof("CONTENT_TYPE") + r->headers_in.content_type->value.len + 1; } #if (NGX_HTTP_SSL) if (r->http_connection->ssl) { len += sizeof("HTTPS") + sizeof("on"); } #endif /* Lengths of Passenger application pool options. */ len += slcf->options_cache.len; len += sizeof("PASSENGER_APP_TYPE") + app_type_string_len; if (slcf->union_station_filters != NGX_CONF_UNSET_PTR && slcf->union_station_filters->nelts > 0) { len += sizeof("UNION_STATION_FILTERS"); union_station_filters = (ngx_str_t *) slcf->union_station_filters->elts; for (i = 0; i < slcf->union_station_filters->nelts; i++) { if (i != 0) { len++; } len += union_station_filters[i].len; } len++; } /***********************/ /***********************/ /* Lengths of various CGI variables. */ if (slcf->vars_len) { ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); ngx_http_script_flush_no_cacheable_variables(r, slcf->flushes); le.flushed = 1; le.ip = slcf->vars_len->elts; le.request = r; while (*(uintptr_t *) le.ip) { lcode = *(ngx_http_script_len_code_pt *) le.ip; key_len = lcode(&le); for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) { lcode = *(ngx_http_script_len_code_pt *) le.ip; } le.ip += sizeof(uintptr_t); len += key_len + val_len; } } /* Lengths of HTTP headers. */ if (slcf->upstream_config.pass_request_headers) { part = &r->headers_in.headers.part; header = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; header = part->elts; i = 0; } if (!header_is_transfer_encoding(&header[i].key)) { len += sizeof("HTTP_") - 1 + header[i].key.len + 1 + header[i].value.len + 1; } } } /************************************************** * Build the request header data. **************************************************/ helper_agent_request_socket_password_data = pp_agents_starter_get_request_socket_password(pp_agents_starter, &helper_agent_request_socket_password_len); size = helper_agent_request_socket_password_len + /* netstring length + ":" + trailing "," */ /* note: 10 == sizeof("4294967296") - 1 */ len + 10 + 1 + 1; b = ngx_create_temp_buf(r->pool, size); if (b == NULL) { return NGX_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; /* Build SCGI header netstring length part. */ b->last = ngx_copy(b->last, helper_agent_request_socket_password_data, helper_agent_request_socket_password_len); b->last = ngx_snprintf(b->last, 10, "%ui", len); *b->last++ = (u_char) ':'; if (r->headers_in.content_length_n >= 0) { b->last = ngx_copy(b->last, "CONTENT_LENGTH", sizeof("CONTENT_LENGTH")); b->last = ngx_snprintf(b->last, 10, "%ui", r->headers_in.content_length_n); *b->last++ = (u_char) 0; } /* Build DOCUMENT_ROOT, SCRIPT_NAME, RAILS_RELATIVE_URL_ROOT, PATH_INFO and REQUEST_URI. */ b->last = ngx_copy(b->last, "DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT")); b->last = ngx_copy(b->last, context->public_dir.data, context->public_dir.len + 1); if (context->base_uri.len > 0) { b->last = ngx_copy(b->last, "SCRIPT_NAME", sizeof("SCRIPT_NAME")); b->last = ngx_copy(b->last, context->base_uri.data, context->base_uri.len + 1); b->last = ngx_copy(b->last, "RAILS_RELATIVE_URL_ROOT", sizeof("RAILS_RELATIVE_URL_ROOT")); b->last = ngx_copy(b->last, context->base_uri.data, context->base_uri.len + 1); b->last = ngx_copy(b->last, "PATH_INFO", sizeof("PATH_INFO")); b->last = ngx_copy(b->last, escaped_uri.data + context->base_uri.len, escaped_uri.len - context->base_uri.len); b->last = ngx_copy(b->last, "", 1); } else { b->last = ngx_copy(b->last, "SCRIPT_NAME", sizeof("SCRIPT_NAME")); b->last = ngx_copy(b->last, "", sizeof("")); b->last = ngx_copy(b->last, "PATH_INFO", sizeof("PATH_INFO")); b->last = ngx_copy(b->last, escaped_uri.data, escaped_uri.len); b->last = ngx_copy(b->last, "", 1); } b->last = ngx_copy(b->last, "REQUEST_URI", sizeof("REQUEST_URI")); b->last = ngx_copy(b->last, escaped_uri.data, escaped_uri.len); if (r->args.len > 0) { b->last = ngx_copy(b->last, "?", 1); b->last = ngx_copy(b->last, r->args.data, r->args.len); } b->last = ngx_copy(b->last, "", 1); /* SERVER_NAME */ b->last = ngx_copy(b->last, "SERVER_NAME", sizeof("SERVER_NAME")); if (r->headers_in.host != NULL) { b->last = ngx_copy(b->last, r->headers_in.host->value.data, server_name_len); } else { b->last = ngx_copy(b->last, cscf->server_name.data, server_name_len); } b->last = ngx_copy(b->last, "", 1); /* Various other HTTP headers. */ if (r->headers_in.content_type != NULL && r->headers_in.content_type->value.len > 0) { b->last = ngx_copy(b->last, "CONTENT_TYPE", sizeof("CONTENT_TYPE")); b->last = ngx_copy(b->last, r->headers_in.content_type->value.data, r->headers_in.content_type->value.len); b->last = ngx_copy(b->last, "", 1); } #if (NGX_HTTP_SSL) if (r->http_connection->ssl) { b->last = ngx_copy(b->last, "HTTPS", sizeof("HTTPS")); b->last = ngx_copy(b->last, "on", sizeof("on")); } #endif /* Build Passenger application pool option headers. */ b->last = ngx_copy(b->last, slcf->options_cache.data, slcf->options_cache.len); b->last = ngx_copy(b->last, "PASSENGER_APP_TYPE", sizeof("PASSENGER_APP_TYPE")); b->last = ngx_copy(b->last, app_type_string, app_type_string_len); if (slcf->union_station_filters != NGX_CONF_UNSET_PTR && slcf->union_station_filters->nelts > 0) { b->last = ngx_copy(b->last, "UNION_STATION_FILTERS", sizeof("UNION_STATION_FILTERS")); for (i = 0; i < slcf->union_station_filters->nelts; i++) { if (i != 0) { b->last = ngx_copy(b->last, "\1", 1); } b->last = ngx_copy(b->last, union_station_filters[i].data, union_station_filters[i].len); } b->last = ngx_copy(b->last, "\0", 1); } /***********************/ /***********************/ if (slcf->vars_len) { ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); e.ip = slcf->vars->elts; e.pos = b->last; e.request = r; e.flushed = 1; le.ip = slcf->vars_len->elts; while (*(uintptr_t *) le.ip) { lcode = *(ngx_http_script_len_code_pt *) le.ip; (void) lcode(&le); for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) { lcode = *(ngx_http_script_len_code_pt *) le.ip; } le.ip += sizeof(uintptr_t); while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) &e); } e.ip += sizeof(uintptr_t); } b->last = e.pos; } if (slcf->upstream_config.pass_request_headers) { part = &r->headers_in.headers.part; header = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; header = part->elts; i = 0; } if (header_is_transfer_encoding(&header[i].key)) { continue; } b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1); for (n = 0; n < header[i].key.len; n++) { ch = header[i].key.data[n]; if (ch >= 'a' && ch <= 'z') { ch &= ~0x20; } else if (ch == '-') { ch = '_'; } *b->last++ = ch; } *b->last++ = (u_char) 0; b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len); *b->last++ = (u_char) 0; } } *b->last++ = (u_char) ','; if (slcf->upstream_config.pass_request_body) { body = r->upstream->request_bufs; r->upstream->request_bufs = cl; while (body) { b = ngx_alloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } ngx_memcpy(b, body->buf, sizeof(ngx_buf_t)); cl->next = ngx_alloc_chain_link(r->pool); if (cl->next == NULL) { return NGX_ERROR; } cl = cl->next; cl->buf = b; body = body->next; } b->flush = 1; } else { r->upstream->request_bufs = cl; } cl->next = NULL; return NGX_OK; }
static ngx_int_t create_request(ngx_http_request_t *r) { u_char ch; u_char buf[sizeof("4294967296")]; size_t len, size, key_len, val_len, content_length; const u_char *app_type_string; size_t app_type_string_len; u_char framework_spawner_idle_time_string[12]; u_char app_spawner_idle_time_string[12]; u_char *end; ngx_uint_t i, n; ngx_buf_t *b; ngx_chain_t *cl, *body; ngx_list_part_t *part; ngx_table_elt_t *header; ngx_http_script_code_pt code; ngx_http_script_engine_t e, le; passenger_loc_conf_t *slcf; passenger_main_conf_t *main_conf; passenger_context_t *context; ngx_http_script_len_code_pt lcode; #if (NGX_HTTP_SSL) ngx_http_ssl_srv_conf_t *ssl_conf; #endif slcf = ngx_http_get_module_loc_conf(r, ngx_http_passenger_module); main_conf = &passenger_main_conf; context = ngx_http_get_module_ctx(r, ngx_http_passenger_module); if (context == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } switch (context->app_type) { case AP_RAILS: app_type_string = (const u_char *) "rails"; app_type_string_len = sizeof("rails"); break; case AP_RACK: app_type_string = (const u_char *) "rack"; app_type_string_len = sizeof("rack"); break; case AP_WSGI: app_type_string = (const u_char *) "wsgi"; app_type_string_len = sizeof("wsgi"); break; default: app_type_string = (const u_char *) "rails"; app_type_string_len = sizeof("rails"); break; } /************************************************** * Determine the request header length. **************************************************/ /* Length of the Content-Length header. */ if (r->headers_in.content_length_n < 0) { content_length = 0; } else { content_length = r->headers_in.content_length_n; } uint_to_str(content_length, buf, sizeof(buf)); /* +1 for trailing null */ len = sizeof("CONTENT_LENGTH") + ngx_strlen(buf) + 1; /* DOCUMENT_ROOT, SCRIPT_NAME and base URI */ len += sizeof("DOCUMENT_ROOT") + context->public_dir.len + 1; if (context->base_uri.len > 0) { len += sizeof("SCRIPT_NAME") + context->base_uri.len + 1; len += sizeof("RAILS_RELATIVE_URL_ROOT") + context->base_uri.len + 1; } else { len += sizeof("SCRIPT_NAME") + sizeof(""); } /* Various other HTTP headers. */ if (r->headers_in.content_type != NULL && r->headers_in.content_type->value.len > 0) { len += sizeof("CONTENT_TYPE") + r->headers_in.content_type->value.len + 1; } #if (NGX_HTTP_SSL) ssl_conf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); if (ssl_conf->enable) { len += sizeof("HTTPS") + sizeof("on"); } #endif /* Lengths of Passenger application pool options. */ if (slcf->use_global_queue) { len += sizeof("PASSENGER_USE_GLOBAL_QUEUE") + sizeof("true"); } else { len += sizeof("PASSENGER_USE_GLOBAL_QUEUE") + sizeof("false"); } len += sizeof("PASSENGER_ENVIRONMENT") + slcf->environment.len + 1; len += sizeof("PASSENGER_SPAWN_METHOD") + slcf->spawn_method.len + 1; len += sizeof("PASSENGER_APP_TYPE") + app_type_string_len; end = ngx_snprintf(framework_spawner_idle_time_string, sizeof(framework_spawner_idle_time_string) - 1, "%d", slcf->framework_spawner_idle_time); *end = '\0'; len += sizeof("PASSENGER_FRAMEWORK_SPAWNER_IDLE_TIME") + ngx_strlen(framework_spawner_idle_time_string) + 1; end = ngx_snprintf(app_spawner_idle_time_string, sizeof(app_spawner_idle_time_string) - 1, "%d", slcf->app_spawner_idle_time); *end = '\0'; len += sizeof("PASSENGER_APP_SPAWNER_IDLE_TIME") + ngx_strlen(app_spawner_idle_time_string) + 1; /* Lengths of various CGI variables. */ if (slcf->vars_len) { ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); ngx_http_script_flush_no_cacheable_variables(r, slcf->flushes); le.flushed = 1; le.ip = slcf->vars_len->elts; le.request = r; while (*(uintptr_t *) le.ip) { lcode = *(ngx_http_script_len_code_pt *) le.ip; key_len = lcode(&le); for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) { lcode = *(ngx_http_script_len_code_pt *) le.ip; } le.ip += sizeof(uintptr_t); len += key_len + val_len; } } /* Lengths of HTTP headers. */ if (slcf->upstream.pass_request_headers) { part = &r->headers_in.headers.part; header = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; header = part->elts; i = 0; } len += sizeof("HTTP_") - 1 + header[i].key.len + 1 + header[i].value.len + 1; } } /* Trailing dummy header. * * If the last header value is an empty string, then the buffer * will end with "\0\0". For example, if 'SSL_CLIENT_CERT' * is the last header and it has an empty value, then the SCGI header * will end with: * * "SSL_CLIENT_CERT\0\0" * * The data in the buffer will be processed by the AbstractRequestHandler class, * which is implemented in Ruby. But it uses Hash[*data.split("\0")] to * unserialize the data. Unfortunately String#split will not transform * the trailing "\0\0" into an empty string: * * "SSL_CLIENT_CERT\0\0".split("\0") * # => desired result: ["SSL_CLIENT_CERT", ""] * # => actual result: ["SSL_CLIENT_CERT"] * * When that happens, Hash[..] will raise an ArgumentError because * data.split("\0") does not return an array with a length that is a * multiple of 2. * * So here, we add a dummy header to prevent situations like that from * happening. */ len += sizeof("_") + sizeof("_"); /************************************************** * Build the request header data. **************************************************/ size = passenger_helper_server_password.len + /* netstring length + ":" + trailing "," */ /* note: 10 == sizeof("4294967296") - 1 */ len + 10 + 1 + 1; b = ngx_create_temp_buf(r->pool, size); if (b == NULL) { return NGX_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; /* Build SCGI header netstring length part. */ b->last = ngx_copy(b->last, passenger_helper_server_password.data, passenger_helper_server_password.len); b->last = ngx_snprintf(b->last, 10, "%ui", len); *b->last++ = (u_char) ':'; /* Build CONTENT_LENGTH header. This must always be sent, even if 0. */ b->last = ngx_copy(b->last, "CONTENT_LENGTH", sizeof("CONTENT_LENGTH")); b->last = ngx_snprintf(b->last, 10, "%ui", content_length); *b->last++ = (u_char) 0; /* Build DOCUMENT_ROOT, SCRIPT_NAME and base URI. */ b->last = ngx_copy(b->last, "DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT")); b->last = ngx_copy(b->last, context->public_dir.data, context->public_dir.len + 1); if (context->base_uri.len > 0) { b->last = ngx_copy(b->last, "SCRIPT_NAME", sizeof("SCRIPT_NAME")); b->last = ngx_copy(b->last, context->base_uri.data, context->base_uri.len + 1); b->last = ngx_copy(b->last, "RAILS_RELATIVE_URL_ROOT", sizeof("RAILS_RELATIVE_URL_ROOT")); b->last = ngx_copy(b->last, context->base_uri.data, context->base_uri.len + 1); } else { b->last = ngx_copy(b->last, "SCRIPT_NAME", sizeof("SCRIPT_NAME")); b->last = ngx_copy(b->last, "", sizeof("")); } /* Various other HTTP headers. */ if (r->headers_in.content_type != NULL && r->headers_in.content_type->value.len > 0) { b->last = ngx_copy(b->last, "CONTENT_TYPE", sizeof("CONTENT_TYPE")); b->last = ngx_copy(b->last, r->headers_in.content_type->value.data, r->headers_in.content_type->value.len + 1); } #if (NGX_HTTP_SSL) ssl_conf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); if (ssl_conf->enable) { b->last = ngx_copy(b->last, "HTTPS", sizeof("HTTPS")); b->last = ngx_copy(b->last, "on", sizeof("on")); } #endif /* Build Passenger application pool option headers. */ b->last = ngx_copy(b->last, "PASSENGER_USE_GLOBAL_QUEUE", sizeof("PASSENGER_USE_GLOBAL_QUEUE")); if (slcf->use_global_queue) { b->last = ngx_copy(b->last, "true", sizeof("true")); } else { b->last = ngx_copy(b->last, "false", sizeof("false")); } b->last = ngx_copy(b->last, "PASSENGER_ENVIRONMENT", sizeof("PASSENGER_ENVIRONMENT")); b->last = ngx_copy(b->last, slcf->environment.data, slcf->environment.len + 1); b->last = ngx_copy(b->last, "PASSENGER_SPAWN_METHOD", sizeof("PASSENGER_SPAWN_METHOD")); b->last = ngx_copy(b->last, slcf->spawn_method.data, slcf->spawn_method.len + 1); b->last = ngx_copy(b->last, "PASSENGER_APP_TYPE", sizeof("PASSENGER_APP_TYPE")); b->last = ngx_copy(b->last, app_type_string, app_type_string_len); b->last = ngx_copy(b->last, "PASSENGER_FRAMEWORK_SPAWNER_IDLE_TIME", sizeof("PASSENGER_FRAMEWORK_SPAWNER_IDLE_TIME")); b->last = ngx_copy(b->last, framework_spawner_idle_time_string, ngx_strlen(framework_spawner_idle_time_string) + 1); b->last = ngx_copy(b->last, "PASSENGER_APP_SPAWNER_IDLE_TIME", sizeof("PASSENGER_APP_SPAWNER_IDLE_TIME")); b->last = ngx_copy(b->last, app_spawner_idle_time_string, ngx_strlen(app_spawner_idle_time_string) + 1); if (slcf->vars_len) { ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); e.ip = slcf->vars->elts; e.pos = b->last; e.request = r; e.flushed = 1; le.ip = slcf->vars_len->elts; while (*(uintptr_t *) le.ip) { lcode = *(ngx_http_script_len_code_pt *) le.ip; (void) lcode(&le); for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) { lcode = *(ngx_http_script_len_code_pt *) le.ip; } le.ip += sizeof(uintptr_t); while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) &e); } e.ip += sizeof(uintptr_t); } b->last = e.pos; } if (slcf->upstream.pass_request_headers) { part = &r->headers_in.headers.part; header = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; header = part->elts; i = 0; } b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1); for (n = 0; n < header[i].key.len; n++) { ch = header[i].key.data[n]; if (ch >= 'a' && ch <= 'z') { ch &= ~0x20; } else if (ch == '-') { ch = '_'; } *b->last++ = ch; } *b->last++ = (u_char) 0; b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len); *b->last++ = (u_char) 0; } } /* Trailing dummy header. See earlier comment for explanation. */ b->last = ngx_copy(b->last, "_\0_", sizeof("_\0_")); *b->last++ = (u_char) ','; if (slcf->upstream.pass_request_body) { body = r->upstream->request_bufs; r->upstream->request_bufs = cl; while (body) { b = ngx_alloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } ngx_memcpy(b, body->buf, sizeof(ngx_buf_t)); cl->next = ngx_alloc_chain_link(r->pool); if (cl->next == NULL) { return NGX_ERROR; } cl = cl->next; cl->buf = b; body = body->next; } b->flush = 1; } else { r->upstream->request_bufs = cl; } cl->next = NULL; return NGX_OK; }
static ngx_int_t ngx_http_scgi_create_request(ngx_http_request_t *r) { u_char ch, *key, *val, *lowcase_key; size_t len, allocated; ngx_buf_t *b; ngx_str_t *content_length; ngx_uint_t i, n, hash, header_params; ngx_chain_t *cl, *body; ngx_list_part_t *part; ngx_table_elt_t *header, **ignored; ngx_http_script_code_pt code; ngx_http_script_engine_t e, le; ngx_http_scgi_loc_conf_t *scf; ngx_http_script_len_code_pt lcode; static ngx_str_t zero = ngx_string("0"); content_length = r->headers_in.content_length ? &r->headers_in.content_length->value : &zero; len = sizeof("CONTENT_LENGTH") + content_length->len + 1; header_params = 0; ignored = NULL; scf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module); if (scf->params_len) { ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); ngx_http_script_flush_no_cacheable_variables(r, scf->flushes); le.flushed = 1; le.ip = scf->params_len->elts; le.request = r; while (*(uintptr_t *) le.ip) { lcode = *(ngx_http_script_len_code_pt *) le.ip; len += lcode(&le); while (*(uintptr_t *) le.ip) { lcode = *(ngx_http_script_len_code_pt *) le.ip; len += lcode(&le) + 1; } le.ip += sizeof(uintptr_t); } } if (scf->upstream.pass_request_headers) { allocated = 0; lowcase_key = NULL; if (scf->header_params) { ignored = ngx_palloc(r->pool, scf->header_params * sizeof(void *)); if (ignored == NULL) { return NGX_ERROR; } } part = &r->headers_in.headers.part; header = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; header = part->elts; i = 0; } if (scf->header_params) { if (allocated < header[i].key.len) { allocated = header[i].key.len + 16; lowcase_key = ngx_pnalloc(r->pool, allocated); if (lowcase_key == NULL) { return NGX_ERROR; } } hash = 0; for (n = 0; n < header[i].key.len; n++) { ch = header[i].key.data[n]; if (ch >= 'A' && ch <= 'Z') { ch |= 0x20; } else if (ch == '-') { ch = '_'; } hash = ngx_hash(hash, ch); lowcase_key[n] = ch; } if (ngx_hash_find(&scf->headers_hash, hash, lowcase_key, n)) { ignored[header_params++] = &header[i]; continue; } } len += sizeof("HTTP_") - 1 + header[i].key.len + 1 + header[i].value.len + 1; } } /* netstring: "length:" + packet + "," */ b = ngx_create_temp_buf(r->pool, NGX_SIZE_T_LEN + 1 + len + 1); if (b == NULL) { return NGX_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; b->last = ngx_snprintf(b->last, NGX_SIZE_T_LEN + 1 + sizeof("CONTENT_LENGTH") + NGX_OFF_T_LEN + 1, "%ui:CONTENT_LENGTH%Z%V%Z", len, content_length); if (scf->params_len) { ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); e.ip = scf->params->elts; e.pos = b->last; e.request = r; e.flushed = 1; while (*(uintptr_t *) e.ip) { #if (NGX_DEBUG) key = e.pos; #endif code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) & e); #if (NGX_DEBUG) val = e.pos; #endif while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) &e); } *e.pos++ = '\0'; e.ip += sizeof(uintptr_t); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "scgi param: \"%s: %s\"", key, val); } b->last = e.pos; } if (scf->upstream.pass_request_headers) { part = &r->headers_in.headers.part; header = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; header = part->elts; i = 0; } for (n = 0; n < header_params; n++) { if (&header[i] == ignored[n]) { goto next; } } key = b->last; b->last = ngx_cpymem(key, "HTTP_", sizeof("HTTP_") - 1); for (n = 0; n < header[i].key.len; n++) { ch = header[i].key.data[n]; if (ch >= 'a' && ch <= 'z') { ch &= ~0x20; } else if (ch == '-') { ch = '_'; } *b->last++ = ch; } *b->last++ = (u_char) 0; val = b->last; b->last = ngx_copy(val, header[i].value.data, header[i].value.len); *b->last++ = (u_char) 0; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "scgi param: \"%s: %s\"", key, val); next: continue; } } *b->last++ = (u_char) ','; if (scf->upstream.pass_request_body) { body = r->upstream->request_bufs; r->upstream->request_bufs = cl; while (body) { b = ngx_alloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } ngx_memcpy(b, body->buf, sizeof(ngx_buf_t)); cl->next = ngx_alloc_chain_link(r->pool); if (cl->next == NULL) { return NGX_ERROR; } cl = cl->next; cl->buf = b; body = body->next; } } else { r->upstream->request_bufs = cl; } cl->next = NULL; return NGX_OK; }
static ngx_int_t create_request(ngx_http_request_t *r) { u_char ch; const char * helper_agent_request_socket_password_data; unsigned int helper_agent_request_socket_password_len; u_char buf[sizeof("4294967296")]; size_t len, size, key_len, val_len, content_length; const u_char *app_type_string; size_t app_type_string_len; int server_name_len; ngx_str_t escaped_uri; ngx_str_t *union_station_filters = NULL; u_char min_instances_string[12]; u_char max_requests_string[12]; u_char max_preloader_idle_time_string[12]; u_char *end; void *tmp; ngx_uint_t i, n; ngx_buf_t *b; ngx_chain_t *cl, *body; ngx_list_part_t *part; ngx_table_elt_t *header; ngx_http_script_code_pt code; ngx_http_script_engine_t e, le; ngx_http_core_srv_conf_t *cscf; passenger_loc_conf_t *slcf; passenger_context_t *context; ngx_http_script_len_code_pt lcode; #if (NGX_HTTP_SSL) ngx_http_ssl_srv_conf_t *ssl_conf; #endif cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); slcf = ngx_http_get_module_loc_conf(r, ngx_http_passenger_module); context = ngx_http_get_module_ctx(r, ngx_http_passenger_module); if (context == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } switch (context->app_type) { case AP_CLASSIC_RAILS: app_type_string = (const u_char *) "classic-rails"; app_type_string_len = sizeof("classic-rails"); break; case AP_RACK: app_type_string = (const u_char *) "rack"; app_type_string_len = sizeof("rack"); break; case AP_WSGI: app_type_string = (const u_char *) "wsgi"; app_type_string_len = sizeof("wsgi"); break; default: app_type_string = (const u_char *) "rack"; app_type_string_len = sizeof("rack"); break; } /* * Nginx unescapes URI's before passing them to Phusion Passenger, * but backend processes expect the escaped version. * http://code.google.com/p/phusion-passenger/issues/detail?id=404 */ escaped_uri.len = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, NGX_ESCAPE_URI) + r->uri.len; escaped_uri.data = ngx_pnalloc(r->pool, escaped_uri.len + 1); escaped_uri.data[escaped_uri.len] = '\0'; ngx_escape_uri(escaped_uri.data, r->uri.data, r->uri.len, NGX_ESCAPE_URI); /************************************************** * Determine the request header length. **************************************************/ /* Length of the Content-Length header. */ if (r->headers_in.content_length_n < 0) { content_length = 0; } else { content_length = r->headers_in.content_length_n; } uint_to_str(content_length, buf, sizeof(buf)); /* +1 for trailing null */ len = sizeof("CONTENT_LENGTH") + ngx_strlen(buf) + 1; /* DOCUMENT_ROOT, SCRIPT_NAME, RAILS_RELATIVE_URL_ROOT, PATH_INFO and REQUEST_URI. */ len += sizeof("DOCUMENT_ROOT") + context->public_dir.len + 1; if (context->base_uri.len > 0) { len += sizeof("SCRIPT_NAME") + context->base_uri.len + 1; len += sizeof("RAILS_RELATIVE_URL_ROOT") + context->base_uri.len + 1; len += sizeof("PATH_INFO") + escaped_uri.len - context->base_uri.len + 1; } else { len += sizeof("SCRIPT_NAME") + sizeof(""); len += sizeof("PATH_INFO") + escaped_uri.len + 1; } len += sizeof("REQUEST_URI") + escaped_uri.len + 1; if (r->args.len > 0) { len += 1 + r->args.len; } /* SERVER_NAME; must be equal to HTTP_HOST without the port part */ if (r->headers_in.host != NULL) { tmp = memchr(r->headers_in.host->value.data, ':', r->headers_in.host->value.len); if (tmp == NULL) { server_name_len = r->headers_in.host->value.len; } else { server_name_len = (int) ((const u_char *) tmp - r->headers_in.host->value.data); } } else { server_name_len = cscf->server_name.len; } len += sizeof("SERVER_NAME") + server_name_len + 1; /* Various other HTTP headers. */ if (r->headers_in.content_type != NULL && r->headers_in.content_type->value.len > 0) { len += sizeof("CONTENT_TYPE") + r->headers_in.content_type->value.len + 1; } #if (NGX_HTTP_SSL) ssl_conf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); if (ssl_conf->enable) { len += sizeof("HTTPS") + sizeof("on"); } #endif /* Lengths of Passenger application pool options. */ ANALYZE_BOOLEAN_CONFIG_LENGTH("PASSENGER_FRIENDLY_ERROR_PAGES", slcf, friendly_error_pages); ANALYZE_BOOLEAN_CONFIG_LENGTH("UNION_STATION_SUPPORT", slcf, union_station_support); ANALYZE_BOOLEAN_CONFIG_LENGTH("PASSENGER_DEBUGGER", slcf, debugger); ANALYZE_BOOLEAN_CONFIG_LENGTH("PASSENGER_SHOW_VERSION_IN_HEADER", slcf, show_version_in_header); ANALYZE_STR_CONFIG_LENGTH("PASSENGER_RUBY", slcf, ruby); len += sizeof("PASSENGER_ENV") + slcf->environment.len + 1; len += sizeof("PASSENGER_SPAWN_METHOD") + slcf->spawn_method.len + 1; len += sizeof("PASSENGER_APP_TYPE") + app_type_string_len; ANALYZE_STR_CONFIG_LENGTH("PASSENGER_APP_GROUP_NAME", slcf, app_group_name); ANALYZE_STR_CONFIG_LENGTH("PASSENGER_APP_RIGHTS", slcf, app_rights); ANALYZE_STR_CONFIG_LENGTH("PASSENGER_USER", slcf, user); ANALYZE_STR_CONFIG_LENGTH("PASSENGER_GROUP", slcf, group); ANALYZE_STR_CONFIG_LENGTH("UNION_STATION_KEY", slcf, union_station_key); end = ngx_snprintf(min_instances_string, sizeof(min_instances_string) - 1, "%d", (slcf->min_instances == (ngx_int_t) -1) ? 1 : slcf->min_instances); *end = '\0'; len += sizeof("PASSENGER_MIN_INSTANCES") + ngx_strlen(min_instances_string) + 1; end = ngx_snprintf(max_requests_string, sizeof(max_requests_string) - 1, "%d", (slcf->max_requests == (ngx_int_t) -1) ? 0 : slcf->max_requests); *end = '\0'; len += sizeof("PASSENGER_MAX_REQUESTS") + ngx_strlen(max_requests_string) + 1; end = ngx_snprintf(max_preloader_idle_time_string, sizeof(max_preloader_idle_time_string) - 1, "%d", (slcf->max_preloader_idle_time == (ngx_int_t) -1) ? -1 : slcf->max_preloader_idle_time); *end = '\0'; len += sizeof("PASSENGER_MAX_PRELOADER_IDLE_TIME") + ngx_strlen(max_preloader_idle_time_string) + 1; if (slcf->union_station_filters != NGX_CONF_UNSET_PTR && slcf->union_station_filters->nelts > 0) { len += sizeof("UNION_STATION_FILTERS"); union_station_filters = (ngx_str_t *) slcf->union_station_filters->elts; for (i = 0; i < slcf->union_station_filters->nelts; i++) { if (i != 0) { len++; } len += union_station_filters[i].len; } len++; } /***********************/ /***********************/ /* Lengths of various CGI variables. */ if (slcf->vars_len) { ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); ngx_http_script_flush_no_cacheable_variables(r, slcf->flushes); le.flushed = 1; le.ip = slcf->vars_len->elts; le.request = r; while (*(uintptr_t *) le.ip) { lcode = *(ngx_http_script_len_code_pt *) le.ip; key_len = lcode(&le); for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) { lcode = *(ngx_http_script_len_code_pt *) le.ip; } le.ip += sizeof(uintptr_t); len += key_len + val_len; } } /* Lengths of HTTP headers. */ if (slcf->upstream_config.pass_request_headers) { part = &r->headers_in.headers.part; header = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; header = part->elts; i = 0; } len += sizeof("HTTP_") - 1 + header[i].key.len + 1 + header[i].value.len + 1; } } /************************************************** * Build the request header data. **************************************************/ helper_agent_request_socket_password_data = agents_starter_get_request_socket_password(passenger_agents_starter, &helper_agent_request_socket_password_len); size = helper_agent_request_socket_password_len + /* netstring length + ":" + trailing "," */ /* note: 10 == sizeof("4294967296") - 1 */ len + 10 + 1 + 1; b = ngx_create_temp_buf(r->pool, size); if (b == NULL) { return NGX_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; /* Build SCGI header netstring length part. */ b->last = ngx_copy(b->last, helper_agent_request_socket_password_data, helper_agent_request_socket_password_len); b->last = ngx_snprintf(b->last, 10, "%ui", len); *b->last++ = (u_char) ':'; /* Build CONTENT_LENGTH header. This must always be sent, even if 0. */ b->last = ngx_copy(b->last, "CONTENT_LENGTH", sizeof("CONTENT_LENGTH")); b->last = ngx_snprintf(b->last, 10, "%ui", content_length); *b->last++ = (u_char) 0; /* Build DOCUMENT_ROOT, SCRIPT_NAME, RAILS_RELATIVE_URL_ROOT, PATH_INFO and REQUEST_URI. */ b->last = ngx_copy(b->last, "DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT")); b->last = ngx_copy(b->last, context->public_dir.data, context->public_dir.len + 1); if (context->base_uri.len > 0) { b->last = ngx_copy(b->last, "SCRIPT_NAME", sizeof("SCRIPT_NAME")); b->last = ngx_copy(b->last, context->base_uri.data, context->base_uri.len + 1); b->last = ngx_copy(b->last, "RAILS_RELATIVE_URL_ROOT", sizeof("RAILS_RELATIVE_URL_ROOT")); b->last = ngx_copy(b->last, context->base_uri.data, context->base_uri.len + 1); b->last = ngx_copy(b->last, "PATH_INFO", sizeof("PATH_INFO")); b->last = ngx_copy(b->last, escaped_uri.data + context->base_uri.len, escaped_uri.len - context->base_uri.len); b->last = ngx_copy(b->last, "", 1); } else { b->last = ngx_copy(b->last, "SCRIPT_NAME", sizeof("SCRIPT_NAME")); b->last = ngx_copy(b->last, "", sizeof("")); b->last = ngx_copy(b->last, "PATH_INFO", sizeof("PATH_INFO")); b->last = ngx_copy(b->last, escaped_uri.data, escaped_uri.len); b->last = ngx_copy(b->last, "", 1); } b->last = ngx_copy(b->last, "REQUEST_URI", sizeof("REQUEST_URI")); b->last = ngx_copy(b->last, escaped_uri.data, escaped_uri.len); if (r->args.len > 0) { b->last = ngx_copy(b->last, "?", 1); b->last = ngx_copy(b->last, r->args.data, r->args.len); } b->last = ngx_copy(b->last, "", 1); /* SERVER_NAME */ b->last = ngx_copy(b->last, "SERVER_NAME", sizeof("SERVER_NAME")); if (r->headers_in.host != NULL) { b->last = ngx_copy(b->last, r->headers_in.host->value.data, server_name_len); } else { b->last = ngx_copy(b->last, cscf->server_name.data, server_name_len); } b->last = ngx_copy(b->last, "", 1); /* Various other HTTP headers. */ if (r->headers_in.content_type != NULL && r->headers_in.content_type->value.len > 0) { b->last = ngx_copy(b->last, "CONTENT_TYPE", sizeof("CONTENT_TYPE")); b->last = ngx_copy(b->last, r->headers_in.content_type->value.data, r->headers_in.content_type->value.len); b->last = ngx_copy(b->last, "", 1); } #if (NGX_HTTP_SSL) ssl_conf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); if (ssl_conf->enable) { b->last = ngx_copy(b->last, "HTTPS", sizeof("HTTPS")); b->last = ngx_copy(b->last, "on", sizeof("on")); } #endif /* Build Passenger application pool option headers. */ SERIALIZE_BOOLEAN_CONFIG_DATA("PASSENGER_FRIENDLY_ERROR_PAGES", slcf, friendly_error_pages); SERIALIZE_BOOLEAN_CONFIG_DATA("UNION_STATION_SUPPORT", slcf, union_station_support); SERIALIZE_BOOLEAN_CONFIG_DATA("PASSENGER_DEBUGGER", slcf, debugger); SERIALIZE_BOOLEAN_CONFIG_DATA("PASSENGER_SHOW_VERSION_IN_HEADER", slcf, show_version_in_header); SERIALIZE_STR_CONFIG_DATA("PASSENGER_RUBY", slcf, ruby); b->last = ngx_copy(b->last, "PASSENGER_ENV", sizeof("PASSENGER_ENV")); b->last = ngx_copy(b->last, slcf->environment.data, slcf->environment.len + 1); b->last = ngx_copy(b->last, "PASSENGER_SPAWN_METHOD", sizeof("PASSENGER_SPAWN_METHOD")); b->last = ngx_copy(b->last, slcf->spawn_method.data, slcf->spawn_method.len + 1); SERIALIZE_STR_CONFIG_DATA("PASSENGER_APP_GROUP_NAME", slcf, app_group_name); SERIALIZE_STR_CONFIG_DATA("PASSENGER_APP_RIGHTS", slcf, app_rights); SERIALIZE_STR_CONFIG_DATA("PASSENGER_USER", slcf, user); SERIALIZE_STR_CONFIG_DATA("PASSENGER_GROUP", slcf, group); SERIALIZE_STR_CONFIG_DATA("UNION_STATION_KEY", slcf, union_station_key); b->last = ngx_copy(b->last, "PASSENGER_APP_TYPE", sizeof("PASSENGER_APP_TYPE")); b->last = ngx_copy(b->last, app_type_string, app_type_string_len); b->last = ngx_copy(b->last, "PASSENGER_MIN_INSTANCES", sizeof("PASSENGER_MIN_INSTANCES")); b->last = ngx_copy(b->last, min_instances_string, ngx_strlen(min_instances_string) + 1); b->last = ngx_copy(b->last, "PASSENGER_MAX_REQUESTS", sizeof("PASSENGER_MAX_REQUESTS")); b->last = ngx_copy(b->last, max_requests_string, ngx_strlen(max_requests_string) + 1); b->last = ngx_copy(b->last, "PASSENGER_MAX_PRELOADER_IDLE_TIME", sizeof("PASSENGER_MAX_PRELOADER_IDLE_TIME")); b->last = ngx_copy(b->last, max_preloader_idle_time_string, ngx_strlen(max_preloader_idle_time_string) + 1); if (slcf->union_station_filters != NGX_CONF_UNSET_PTR && slcf->union_station_filters->nelts > 0) { b->last = ngx_copy(b->last, "UNION_STATION_FILTERS", sizeof("UNION_STATION_FILTERS")); for (i = 0; i < slcf->union_station_filters->nelts; i++) { if (i != 0) { b->last = ngx_copy(b->last, "\1", 1); } b->last = ngx_copy(b->last, union_station_filters[i].data, union_station_filters[i].len); } b->last = ngx_copy(b->last, "\0", 1); } /***********************/ /***********************/ if (slcf->vars_len) { ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); e.ip = slcf->vars->elts; e.pos = b->last; e.request = r; e.flushed = 1; le.ip = slcf->vars_len->elts; while (*(uintptr_t *) le.ip) { lcode = *(ngx_http_script_len_code_pt *) le.ip; (void) lcode(&le); for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) { lcode = *(ngx_http_script_len_code_pt *) le.ip; } le.ip += sizeof(uintptr_t); while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) &e); } e.ip += sizeof(uintptr_t); } b->last = e.pos; } if (slcf->upstream_config.pass_request_headers) { part = &r->headers_in.headers.part; header = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; header = part->elts; i = 0; } b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1); for (n = 0; n < header[i].key.len; n++) { ch = header[i].key.data[n]; if (ch >= 'a' && ch <= 'z') { ch &= ~0x20; } else if (ch == '-') { ch = '_'; } *b->last++ = ch; } *b->last++ = (u_char) 0; b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len); *b->last++ = (u_char) 0; } } *b->last++ = (u_char) ','; if (slcf->upstream_config.pass_request_body) { body = r->upstream->request_bufs; r->upstream->request_bufs = cl; while (body) { b = ngx_alloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } ngx_memcpy(b, body->buf, sizeof(ngx_buf_t)); cl->next = ngx_alloc_chain_link(r->pool); if (cl->next == NULL) { return NGX_ERROR; } cl = cl->next; cl->buf = b; body = body->next; } b->flush = 1; } else { r->upstream->request_bufs = cl; } cl->next = NULL; return NGX_OK; }
static ngx_int_t ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_int_t rc; ngx_buf_t *b; ngx_chain_t *cl; ngx_http_sub_ctx_t *ctx; ctx = ngx_http_get_module_ctx(r, ngx_http_sub_filter_module); if (ctx == NULL) { return ngx_http_next_body_filter(r, in); } if ((in == NULL && ctx->buf == NULL && ctx->in == NULL && ctx->busy == NULL)) { return ngx_http_next_body_filter(r, in); } if (ctx->once && (ctx->buf == NULL || ctx->in == NULL)) { if (ctx->busy) { if (ngx_http_sub_output(r, ctx) == NGX_ERROR) { return NGX_ERROR; } } return ngx_http_next_body_filter(r, in); } /* add the incoming chain to the chain ctx->in */ if (in) { if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { return NGX_ERROR; } } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http sub filter \"%V\"", &r->uri); while (ctx->in || (ctx->buf && ctx->buf->last_buf)) { if (ctx->buf == NULL) { ctx->buf = ctx->in->buf; ctx->in = ctx->in->next; ctx->pos = ctx->buf->pos; } else { if(ctx->buf->last_buf) { ngx_memzero(ctx->buf->last, ctx->tmp.len/2); ctx->buf->last += ctx->tmp.len/2; } else { ngx_uint_t next_buf_size = ctx->in->buf->last - ctx->in->buf->pos; ngx_uint_t tmp_buf_size = ctx->buf->last - ctx->buf->pos; ngx_uint_t rem_part_size = ctx->tmp.len/2 - (tmp_buf_size - ctx->first_part_size); ngx_uint_t next_part_size = next_buf_size < rem_part_size ? next_buf_size : rem_part_size; ngx_memcpy(ctx->buf->last, ctx->in->buf->pos, next_part_size); ctx->buf->last += next_part_size; if(ctx->in->buf->last_buf) { rem_part_size -= next_part_size; ngx_memzero(ctx->buf->last, rem_part_size); ctx->buf->last += rem_part_size; } else if(next_part_size != rem_part_size) { ctx->in = ctx->in->next; continue; } } ctx->pos = ctx->buf->pos; } ctx->pos += ctx->next_buf_offset; ctx->copy_start = ctx->pos; ctx->copy_end = ctx->pos; b = NULL; while (ctx->pos < ctx->buf->last) { /* ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "saved: \"%V\" state: %d", &ctx->saved, ctx->state); */ rc = ngx_http_sub_parse(r, ctx); ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "parse: %d, tmp: \"%V\" %p-%p", rc, &ctx->tmp, ctx->copy_start, ctx->copy_end); if (rc == NGX_ERROR) { return rc; } if (ctx->copy_start != ctx->copy_end) { /* ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "saved: \"%V\"", &ctx->saved); */ if (ctx->free) { cl = ctx->free; ctx->free = ctx->free->next; b = cl->buf; } else { b = ngx_alloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; } if(ctx->state == sub_main_state) { ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t)); b->pos = ctx->copy_start; b->last = ctx->copy_end; b->shadow = NULL; b->last_buf = 0; b->recycled = 0; if (b->in_file) { b->file_last = b->file_pos + (b->last - ctx->buf->pos); b->file_pos += b->pos - ctx->buf->pos; } } else { ngx_uint_t buf_size = ctx->copy_end - ctx->copy_start; ngx_memzero(b, sizeof(ngx_buf_t)); b->pos = ngx_pnalloc(r->pool, buf_size); if (b->pos == NULL) { return NGX_ERROR; } ngx_memcpy(b->pos, ctx->copy_start, buf_size); b->last = b->pos + buf_size; b->memory = 1; } cl->next = NULL; *ctx->last_out = cl; ctx->last_out = &cl->next; } if (rc == NGX_AGAIN) { continue; } /* rc == NGX_OK */ b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } if(!ctx->repl[ctx->index].data) { if (ngx_http_complex_value(r, &ctx->values[ctx->index], &ctx->repl[ctx->index]) != NGX_OK) { return NGX_ERROR; } } if (ctx->repl[ctx->index].len) { b->memory = 1; b->pos = ctx->repl[ctx->index].data; b->last = ctx->repl[ctx->index].data + ctx->repl[ctx->index].len; } else { b->sync = 1; } cl->buf = b; cl->next = NULL; *ctx->last_out = cl; ctx->last_out = &cl->next; // ctx->once = slcf->once; continue; } if (ctx->buf->last_buf || ngx_buf_in_memory(ctx->buf)) { if (b == NULL) { if (ctx->free) { cl = ctx->free; ctx->free = ctx->free->next; b = cl->buf; ngx_memzero(b, sizeof(ngx_buf_t)); } else { b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; } b->sync = 1; cl->next = NULL; *ctx->last_out = cl; ctx->last_out = &cl->next; } b->last_buf = ctx->buf->last_buf; b->shadow = ctx->buf; b->recycled = ctx->buf->recycled; } if(ctx->state == sub_main_state && ctx->first_part_size) { b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } b->last_buf = ctx->buf->last_buf; b->pos = ctx->tmp.data; b->last = b->pos + ctx->first_part_size; b->memory = 1; ctx->buf = b; ctx->state = sub_tmp_state; } else { ctx->buf = NULL; ctx->state = sub_main_state; } } if (ctx->out == NULL && ctx->busy == NULL) { return NGX_OK; } return ngx_http_sub_output(r, ctx); }