ngx_int_t ngx_http_log_handler(ngx_http_request_t *r) { u_char *line, *p; size_t len; ngx_uint_t i, l; ngx_http_log_t *log; ngx_open_file_t *file; ngx_http_log_op_t *op; ngx_http_log_loc_conf_t *lcf; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http log handler"); lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module); if (lcf->off) { return NGX_OK; } log = lcf->logs->elts; for (l = 0; l < lcf->logs->nelts; l++) { if (ngx_time() == log[l].disk_full_time) { /* * on FreeBSD writing to a full filesystem with enabled softupdates * may block process for much longer time than writing to non-full * filesystem, so we skip writing to a log for one second */ continue; } ngx_http_script_flush_no_cacheable_variables(r, log[l].format->flushes); len = 0; op = log[l].format->ops->elts; for (i = 0; i < log[l].format->ops->nelts; i++) { if (op[i].len == 0) { len += op[i].getlen(r, op[i].data); } else { len += op[i].len; } } len += NGX_LINEFEED_SIZE; file = log[l].file; if (file && file->buffer) { if (len > (size_t) (file->last - file->pos)) { ngx_http_log_write(r, &log[l], file->buffer, file->pos - file->buffer); file->pos = file->buffer; } if (len <= (size_t) (file->last - file->pos)) { p = file->pos; for (i = 0; i < log[l].format->ops->nelts; i++) { p = op[i].run(r, p, &op[i]); } ngx_linefeed(p); file->pos = p; continue; } } line = ngx_pnalloc(r->pool, len); if (line == NULL) { return NGX_ERROR; } p = line; for (i = 0; i < log[l].format->ops->nelts; i++) { p = op[i].run(r, p, &op[i]); } ngx_linefeed(p); ngx_http_log_write(r, &log[l], line, p - line); } return NGX_OK; }
static ngx_uint_t construct_request_buffer(ngx_http_request_t *r, passenger_loc_conf_t *slcf, passenger_context_t *context, buffer_construction_state *state, ngx_buf_t *b) { #define PUSH_STATIC_STR(str) \ do { \ if (b != NULL) { \ b->last = ngx_copy(b->last, (const u_char *) str, \ sizeof(str) - 1); \ } \ total_size += sizeof(str) - 1; \ } while (0) ngx_uint_t total_size = 0; ngx_str_t *union_station_filters; ngx_uint_t i; ngx_list_part_t *part; ngx_table_elt_t *header; size_t len; ngx_http_script_len_code_pt lcode; ngx_http_script_code_pt code; ngx_http_script_engine_t e, le; if (b != NULL) { b->last = ngx_copy(b->last, state->method.data, state->method.len); } total_size += state->method.len; if (b != NULL) { b->last = ngx_copy(b->last, state->escaped_uri.data, state->escaped_uri.len); } total_size += state->escaped_uri.len; if (r->args.len > 0) { if (b != NULL) { b->last = ngx_copy(b->last, "?", 1); b->last = ngx_copy(b->last, r->args.data, r->args.len); } total_size += r->args.len + 1; } PUSH_STATIC_STR(" HTTP/1.1\r\nConnection: close\r\n"); 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 (ngx_hash_find(&slcf->headers_set_hash, header[i].hash, header[i].lowcase_key, header[i].key.len) || header_is_transfer_encoding(&header[i].key)) { continue; } if (b != NULL) { b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len); b->last = ngx_copy(b->last, ": ", 2); b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len); b->last = ngx_copy(b->last, "\r\n", 2); } total_size += header[i].key.len + header[i].value.len + 4; } if (r->headers_in.chunked) { PUSH_STATIC_STR("Content-Length: "); if (b != NULL) { b->last = ngx_copy(b->last, state->content_length.data, state->content_length.len); } total_size += state->content_length.len; PUSH_STATIC_STR("\r\n"); } if (slcf->headers_set_len) { ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); ngx_http_script_flush_no_cacheable_variables(r, slcf->flushes); le.ip = slcf->headers_set_len->elts; le.request = r; le.flushed = 1; while (*(uintptr_t *) le.ip) { while (*(uintptr_t *) le.ip) { lcode = *(ngx_http_script_len_code_pt *) le.ip; total_size += lcode(&le); } le.ip += sizeof(uintptr_t); } if (b != NULL) { ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); e.ip = slcf->headers_set->elts; e.pos = b->last; e.request = r; e.flushed = 1; le.ip = slcf->headers_set_len->elts; while (*(uintptr_t *) le.ip) { lcode = *(ngx_http_script_len_code_pt *) le.ip; /* skip the header line name length */ (void) lcode(&le); if (*(ngx_http_script_len_code_pt *) le.ip) { for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) { lcode = *(ngx_http_script_len_code_pt *) le.ip; } e.skip = (len == sizeof("\r\n") - 1) ? 1 : 0; } else { e.skip = 0; } 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 (b != NULL) { b->last = ngx_copy(b->last, "!~: ", sizeof("!~: ") - 1); b->last = ngx_copy(b->last, state->core_password.data, state->core_password.len); b->last = ngx_copy(b->last, "\r\n", sizeof("\r\n") - 1); } total_size += (sizeof("!~: \r\n") - 1) + state->core_password.len; PUSH_STATIC_STR("!~DOCUMENT_ROOT: "); if (b != NULL) { b->last = ngx_copy(b->last, context->public_dir.data, context->public_dir.len); } total_size += context->public_dir.len; PUSH_STATIC_STR("\r\n"); if (context->base_uri.len > 0) { PUSH_STATIC_STR("!~SCRIPT_NAME: "); if (b != NULL) { b->last = ngx_copy(b->last, context->base_uri.data, context->base_uri.len); } total_size += context->base_uri.len; PUSH_STATIC_STR("\r\n"); } PUSH_STATIC_STR("!~REMOTE_ADDR: "); if (b != NULL) { b->last = ngx_copy(b->last, r->connection->addr_text.data, r->connection->addr_text.len); } total_size += r->connection->addr_text.len; PUSH_STATIC_STR("\r\n"); PUSH_STATIC_STR("!~REMOTE_PORT: "); if (b != NULL) { b->last = ngx_copy(b->last, state->remote_port.data, state->remote_port.len); } total_size += state->remote_port.len; PUSH_STATIC_STR("\r\n"); if (r->headers_in.user.len > 0) { PUSH_STATIC_STR("!~REMOTE_USER: "******"\r\n"); } if (slcf->app_group_name.data == NULL) { PUSH_STATIC_STR("!~PASSENGER_APP_GROUP_NAME: "); if (b != NULL) { b->last = ngx_copy(b->last, context->public_dir.data, context->public_dir.len); } total_size += context->public_dir.len; if (slcf->environment.data != NULL) { if (b != NULL) { b->last = ngx_copy(b->last, " (", 2); b->last = ngx_copy(b->last, slcf->environment.data, slcf->environment.len); b->last = ngx_copy(b->last, ")", 1); } total_size += (sizeof(" (") - 1) + slcf->environment.len + (sizeof(")") - 1); } PUSH_STATIC_STR("\r\n"); } PUSH_STATIC_STR("!~PASSENGER_APP_TYPE: "); if (b != NULL) { b->last = ngx_copy(b->last, state->app_type.data, state->app_type.len); } total_size += state->app_type.len; PUSH_STATIC_STR("\r\n"); if (slcf->union_station_filters != NGX_CONF_UNSET_PTR && slcf->union_station_filters->nelts > 0) { union_station_filters = (ngx_str_t *) slcf->union_station_filters->elts; for (i = 0; i < slcf->union_station_filters->nelts; i++) { PUSH_STATIC_STR("!~UNION_STATION_FILTERS: "); if (b != NULL) { b->last = ngx_copy(b->last, union_station_filters[i].data, union_station_filters[i].len); } total_size += union_station_filters[i].len; PUSH_STATIC_STR("\r\n"); } } if (b != NULL) { b->last = ngx_copy(b->last, slcf->options_cache.data, slcf->options_cache.len); } total_size += slcf->options_cache.len; if (slcf->env_vars_cache.data != NULL) { PUSH_STATIC_STR("!~PASSENGER_ENV_VARS: "); if (b != NULL) { b->last = ngx_copy(b->last, slcf->env_vars_cache.data, slcf->env_vars_cache.len); } total_size += slcf->env_vars_cache.len; PUSH_STATIC_STR("\r\n"); } /* D = Dechunk response * Prevent Nginx from rechunking the response. * C = Strip 100 Continue header * S = SSL */ PUSH_STATIC_STR("!~FLAGS: DC"); #if (NGX_HTTP_SSL) if (r->http_connection->ssl) { PUSH_STATIC_STR("S"); } #endif PUSH_STATIC_STR("\r\n\r\n"); return total_size; #undef PUSH_STATIC_STR }
static ngx_int_t ngx_http_log_handler(ngx_http_request_t *r) { u_char *line, *p; size_t len; ngx_uint_t i, l, bypass, threshold; ngx_http_log_t *log; ngx_open_file_t *file; ngx_http_log_op_t *op; ngx_http_log_loc_conf_t *lcf; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http log handler"); lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module); if (lcf->off) { return NGX_OK; } if (r->headers_out.status == NGX_HTTP_BAD_REQUEST && !lcf->log_empty_request && (r->header_in && r->header_in->last == r->header_in->start)) { return NGX_OK; } log = lcf->logs->elts; for (l = 0; l < lcf->logs->nelts; l++) { if (log[l].scope != 0) { bypass = 1; if (log[l].sample_count < log[l].sample) { if (log[l].scatter_count++ == 0) { bypass = 0; ++log[l].sample_count; } threshold = log[l].scatter; if (log[l].sample_count >= log[l].inflexion) { --threshold; } if (log[l].scatter_count == threshold) { log[l].scatter_count = 0; } } if (++log[l].scope_count == log[l].scope) { log[l].scope_count = 0; log[l].sample_count = 0; log[l].scatter_count = 0; } if (bypass == 1) { continue; } } if (ngx_time() == log[l].disk_full_time) { /* * on FreeBSD writing to a full filesystem with enabled softupdates * may block process for much longer time than writing to non-full * filesystem, so we skip writing to a log for one second */ continue; } ngx_http_script_flush_no_cacheable_variables(r, log[l].format->flushes); len = 0; op = log[l].format->ops->elts; for (i = 0; i < log[l].format->ops->nelts; i++) { if (op[i].len == 0) { len += op[i].getlen(r, op[i].data); } else { len += op[i].len; } } len += NGX_LINEFEED_SIZE; file = log[l].file; if (file && file->buffer) { if (len > (size_t) (file->last - file->pos)) { ngx_http_log_write(r, &log[l], file->buffer, file->pos - file->buffer); file->pos = file->buffer; } if (len <= (size_t) (file->last - file->pos)) { p = file->pos; for (i = 0; i < log[l].format->ops->nelts; i++) { p = op[i].run(r, p, &op[i]); } ngx_linefeed(p); file->pos = p; continue; } } line = ngx_pnalloc(r->pool, len); if (line == NULL) { return NGX_ERROR; } p = line; for (i = 0; i < log[l].format->ops->nelts; i++) { p = op[i].run(r, p, &op[i]); } ngx_linefeed(p); #if (NGX_SYSLOG) if (log[l].syslog != NULL) { if (!(log[l].syslog->fd == NGX_INVALID_FILE && ngx_cached_time->sec < log[l].syslog->next_try)) { (void) ngx_write_syslog(log[l].syslog, line, p - line); } continue; } #endif ngx_http_log_write(r, &log[l], line, p - line); } 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") + 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; }
ngx_int_t ngx_http_fluentd_handler(ngx_http_request_t *r) { u_char *line, *p; size_t len; ngx_uint_t i, l; ngx_str_t tag; ngx_http_fluentd_t *log; ngx_http_log_op_t *op; ngx_http_fluentd_conf_t *ulcf; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fluentd handler"); ulcf = ngx_http_get_module_loc_conf(r, ngx_http_fluentd_module); if(ulcf->off) { return NGX_OK; } if(ulcf->tag != NULL) { if(ulcf->tag->lengths == NULL) { tag = ulcf->tag->value; } else { if (ngx_http_script_run(r, &tag, ulcf->tag->lengths->elts, 0, ulcf->tag->values->elts) == NULL) { return NGX_ERROR; } } } else { tag.data = (u_char*)"nginx"; tag.len = sizeof("nginx") - 1; } log = ulcf->logs->elts; for (l = 0; l < ulcf->logs->nelts; l++) { #if defined nginx_version && nginx_version >= 7018 ngx_http_script_flush_no_cacheable_variables(r, log[l].format->flushes); #endif len = 1; op = log[l].format->ops->elts; for (i = 0; i < log[l].format->ops->nelts; i++) { if (op[i].len == 0) { len += op[i].getlen(r, op[i].data); } else { len += op[i].len; } } len += 1 + sizeof("\"tag\":") + 1 + 1 + tag.len + 1 + 1 + 1; /* '{tag: "value", ' */ #if defined nginx_version && nginx_version >= 7003 line = ngx_pnalloc(r->pool, len); #else line = ngx_palloc(r->pool, len); #endif if (line == NULL) { return NGX_ERROR; } /* * JSON Style message */ p = ngx_sprintf(line, "{\"tag\":\"%V\", ", &tag); for (i = 0; i < log[l].format->ops->nelts; i++) { p = op[i].run(r, p, &op[i]); } *p++ = '}'; ngx_http_fluentd_send(log[l].endpoint, line, p - line); } return NGX_OK; }