X7ROOT File Manager
Current Path:
/opt/cpanel/ea-ruby27/src/passenger-release-6.1.2/src/nginx_module
opt
/
cpanel
/
ea-ruby27
/
src
/
passenger-release-6.1.2
/
src
/
nginx_module
/
??
..
??
.clangd
(81 B)
??
ConfigGeneral
??
Configuration.c
(43.68 KB)
??
Configuration.h
(3.42 KB)
??
ContentHandler.c
(59.62 KB)
??
ContentHandler.h
(2.24 KB)
??
LocationConfig
??
MainConfig
??
README.md
(369 B)
??
StaticContentHandler.c
(6.91 KB)
??
StaticContentHandler.h
(1.74 KB)
??
config
(5.8 KB)
??
ngx_http_passenger_module.c
(22.79 KB)
??
ngx_http_passenger_module.h
(2.66 KB)
Editing: ContentHandler.c
/* * Copyright (C) Igor Sysoev * Copyright (C) 2007 Manlio Perillo (manlio.perillo@gmail.com) * Copyright (c) 2010-2025 Asynchronous B.V. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include <nginx.h> #include <ngx_http.h> #include "ngx_http_passenger_module.h" #include "ContentHandler.h" #include "StaticContentHandler.h" #include "Configuration.h" #include "cxx_supportlib/Constants.h" #include "cxx_supportlib/FileTools/PathManipCBindings.h" #define NGX_HTTP_SCGI_PARSE_NO_HEADER 20 typedef enum { FT_ERROR, FT_FILE, FT_DIRECTORY, FT_OTHER } FileType; static ngx_int_t reinit_request(ngx_http_request_t *r); static ngx_int_t process_status_line(ngx_http_request_t *r); static ngx_int_t parse_status_line(ngx_http_request_t *r, passenger_context_t *context); static ngx_int_t process_header(ngx_http_request_t *r); static void abort_request(ngx_http_request_t *r); static void finalize_request(ngx_http_request_t *r, ngx_int_t rc); static FileType get_file_type(const u_char *filename, unsigned int throttle_rate) { struct stat buf; int ret; ret = pp_cached_file_stat_perform(pp_stat_cache, (const char *) filename, &buf, throttle_rate); if (ret == 0) { if (S_ISREG(buf.st_mode)) { return FT_FILE; } else if (S_ISDIR(buf.st_mode)) { return FT_DIRECTORY; } else { return FT_OTHER; } } else { return FT_ERROR; } } static int file_exists(const u_char *filename, unsigned int throttle_rate) { return get_file_type(filename, throttle_rate) == FT_FILE; } static int mapped_filename_equals(const u_char *filename, size_t filename_len, ngx_str_t *str) { return (str->len == filename_len && memcmp(str->data, filename, filename_len) == 0) || (str->len == filename_len - 1 && filename[filename_len - 1] == '/' && memcmp(str->data, filename, filename_len - 1) == 0); } /** * Maps the URI for the given request to a page cache file, if possible. * * @return Whether the URI has been successfully mapped to a page cache file. * @param r The corresponding request. * @param public_dir The web application's 'public' directory. * @param filename The filename that the URI normally maps to. * @param filename_len The length of the <tt>filename</tt> string. * @param root The size of the root path in <tt>filename</tt>. * @param page_cache_file If mapping was successful, then the page cache * file's filename will be stored in here. * <tt>page_cache_file.data</tt> must already point to * a buffer, and <tt>page_cache_file.len</tt> must be set * to the size of this buffer, including terminating NUL. */ static int map_uri_to_page_cache_file(ngx_http_request_t *r, ngx_str_t *public_dir, const u_char *filename, size_t filename_len, ngx_str_t *page_cache_file) { u_char *end; if ((r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) || filename_len == 0) { return 0; } /* From this point on we know that filename is not an empty string. */ /* Check whether `filename` is equal to public_dir. * `filename` may also be equal to public_dir + "/" so check for that as well. */ if (mapped_filename_equals(filename, filename_len, public_dir)) { /* If the URI maps to the 'public' or the alias directory (i.e. the request is the * base URI) then index.html is the page cache file. */ if (filename_len + sizeof("/index.html") > page_cache_file->len) { /* Page cache filename doesn't fit in the buffer. */ return 0; } end = ngx_copy(page_cache_file->data, filename, filename_len); if (filename[filename_len - 1] != '/') { end = ngx_copy(end, "/", 1); } end = ngx_copy(end, "index.html", sizeof("index.html")); } else if (filename[filename_len - 1] == '/') { /* if the filename ends with '/' check for filename + "index.html". */ if (filename_len + sizeof("index.html") > page_cache_file->len) { /* Page cache filename doesn't fit in the buffer. */ return 0; } end = ngx_copy(page_cache_file->data, filename, filename_len); end = ngx_copy(end, "index.html", sizeof("index.html")); } else { /* Otherwise, the page cache file is just filename + ".html". */ if (filename_len + sizeof(".html") > page_cache_file->len) { /* Page cache filename doesn't fit in the buffer. */ return 0; } end = ngx_copy(page_cache_file->data, filename, filename_len); end = ngx_copy(end, ".html", sizeof(".html")); } if (file_exists(page_cache_file->data, 0)) { page_cache_file->len = end - page_cache_file->data - 1; return 1; } else { return 0; } } static void cleanup_detector_result(void *data) { psg_app_type_detector_result_deinit((PsgAppTypeDetectorResult *) data); } static int find_base_uri(ngx_http_request_t *r, const passenger_loc_conf_t *loc, ngx_str_t *found_base_uri) { ngx_uint_t i; ngx_str_t *base_uris, *base_uri, *uri; if (loc->autogenerated.base_uris == NGX_CONF_UNSET_PTR) { return 0; } else { base_uris = (ngx_str_t *) loc->autogenerated.base_uris->elts; uri = &r->uri; for (i = 0; i < loc->autogenerated.base_uris->nelts; i++) { base_uri = &base_uris[i]; if (base_uri->len == 1 && base_uri->data[0] == '/') { /* Ignore 'passenger_base_uri /' options. Users usually * specify this out of ignorance. */ continue; } if (( uri->len == base_uri->len && ngx_strncmp(uri->data, base_uri->data, uri->len) == 0 ) || ( uri->len > base_uri->len && ngx_strncmp(uri->data, base_uri->data, base_uri->len) == 0 && uri->data[base_uri->len] == (u_char) '/' )) { *found_base_uri = *base_uri; return 1; } } return 0; } } static void set_upstream_server_address(ngx_http_upstream_t *upstream, ngx_http_upstream_conf_t *upstream_config) { ngx_http_upstream_server_t *servers = upstream_config->upstream->servers->elts; ngx_addr_t *address = &servers[0].addrs[0]; const char *core_address; unsigned int core_address_len; struct sockaddr_un *sockaddr; /* The Nginx API makes it extremely difficult to register an upstream server * address outside of the configuration loading phase. However we don't know * the Passenger core's request socket filename until we're done with loading * the configuration. So during configuration loading we register a placeholder * address for the upstream configuration, and while processing requests * we substitute the placeholder filename with the real Passenger core request * socket filename. */ if (address->name.data == pp_placeholder_upstream_address.data) { sockaddr = (struct sockaddr_un *) address->sockaddr; core_address = psg_watchdog_launcher_get_core_address(psg_watchdog_launcher, &core_address_len); core_address += sizeof("unix:") - 1; core_address_len -= sizeof("unix:") - 1; address->name.data = (u_char *) core_address; address->name.len = core_address_len; strncpy(sockaddr->sun_path, core_address, sizeof(sockaddr->sun_path)); sockaddr->sun_path[sizeof(sockaddr->sun_path) - 1] = '\0'; } } /** * If the Passenger core socket cannot be connected to then we want Nginx to print * the proper socket filename in the error message. The socket filename is stored * in one of the upstream peer data structures. This name is initialized during * the first ngx_http_read_client_request_body() call so there's no way to fix the * name before the first request, which is why we do it after the fact. */ static void fix_peer_address(ngx_http_request_t *r) { ngx_http_upstream_rr_peer_data_t *rrp; ngx_http_upstream_rr_peers_t *peers; ngx_http_upstream_rr_peer_t *peer; unsigned int peer_index; const char *core_address; unsigned int core_address_len; if (r->upstream->peer.get != ngx_http_upstream_get_round_robin_peer) { /* This function only supports the round-robin upstream method. */ return; } rrp = r->upstream->peer.data; peers = rrp->peers; core_address = psg_watchdog_launcher_get_core_address(psg_watchdog_launcher, &core_address_len); while (peers != NULL) { if (peers->name) { if (peers->name->data == (u_char *) core_address) { /* Peer names already fixed. */ return; } peers->name->data = (u_char *) core_address; peers->name->len = core_address_len; } peer_index = 0; while (1) { peer = &peers->peer[peer_index]; peer->name.data = (u_char *) core_address; peer->name.len = core_address_len; if (peer->down) { peer_index++; } else { break; } } peers = peers->next; } } #if (NGX_HTTP_CACHE) static ngx_int_t create_key(ngx_http_request_t *r) { ngx_str_t *key; passenger_loc_conf_t *slcf; key = ngx_array_push(&r->cache->keys); if (key == NULL) { return NGX_ERROR; } slcf = ngx_http_get_module_loc_conf(r, ngx_http_passenger_module); if (ngx_http_complex_value(r, &slcf->cache_key, key) != NGX_OK) { return NGX_ERROR; } return NGX_OK; } #endif /** * Checks whether the given header is "Transfer-Encoding". * We do not pass Transfer-Encoding headers to the Passenger core because * Nginx always buffers the request body and always sets Content-Length * in the request headers. */ static int header_is_transfer_encoding(ngx_str_t *key) { return key->len == sizeof("transfer-encoding") - 1 && ngx_tolower(key->data[0]) == (u_char) 't' && ngx_tolower(key->data[sizeof("transfer-encoding") - 2]) == (u_char) 'g' && ngx_strncasecmp(key->data + 1, (u_char *) "ransfer-encodin", sizeof("ransfer-encodin") - 1) == 0; } /* Given an ngx_chain_t head and tail position, appends a new chain element at the end, * updates the head (if necessary) and returns the new element. * * - The element is allocated from a freelist. * - Ensures that the element contains a buffer of at least `size` bytes. * - Sets the given tag on the buffer in the chain element. * * On error, returns NULL without modifying the given chain. */ static ngx_chain_t * append_ngx_chain_element(ngx_pool_t *p, ngx_chain_t **head, ngx_chain_t *tail, ngx_chain_t **freelist, ngx_buf_tag_t tag, size_t size) { ngx_chain_t *elem; ngx_buf_t *buf; elem = ngx_chain_get_free_buf(p, freelist); if (elem == NULL) { return NULL; } buf = elem->buf; buf->tag = tag; if (size > 0 && (buf->pos == NULL || buf->last == NULL || (size_t) ngx_buf_size(buf) < size)) { ngx_memzero(buf, sizeof(ngx_buf_t)); buf->start = ngx_palloc(p, size); if (buf->start == NULL) { return NULL; } /* * set by ngx_memzero(): * * b->file_pos = 0; * b->file_last = 0; * b->file = NULL; * b->shadow = NULL; * b->tag = 0; * and flags */ buf->pos = buf->start; buf->last = buf->start; buf->end = buf->last + size; buf->temporary = 1; } if (*head == NULL) { *head = elem; } else { tail->next = elem; } return elem; } /* Given a chain of buffers containing client body data, * this filter wraps all that data into chunked encoding * headers and footers. */ static ngx_int_t body_rechunk_output_filter(void *data, ngx_chain_t *input) { ngx_http_request_t *r = data; ngx_chain_t *output_head = NULL, *output_tail = NULL; ngx_int_t body_eof_reached = 0; ngx_int_t rc; passenger_context_t *ctx; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, PROGRAM_NAME " rechunk output filter"); ctx = ngx_http_get_module_ctx(r, ngx_http_passenger_module); if (input == NULL) { goto out; } if (!ctx->header_sent) { /* The first buffer contains the request header, so pass it unmodified. */ ctx->header_sent = 1; while (input != NULL) { output_tail = append_ngx_chain_element(r->pool, &output_head, output_tail, &ctx->free, (ngx_buf_tag_t) &body_rechunk_output_filter, 0); if (output_tail == NULL) { return NGX_ERROR; } ngx_memcpy(output_tail->buf, input->buf, sizeof(ngx_buf_t)); body_eof_reached = input->buf->last_buf; input = input->next; } } else { while (input != NULL) { /* Append chunked encoding size header */ output_tail = append_ngx_chain_element(r->pool, &output_head, output_tail, &ctx->free, (ngx_buf_tag_t) &body_rechunk_output_filter, 32); if (output_tail == NULL) { return NGX_ERROR; } output_tail->buf->last = ngx_sprintf(output_tail->buf->last, "%xO\r\n", ngx_buf_size(input->buf)); /* Append chunked encoding payload */ output_tail = append_ngx_chain_element(r->pool, &output_head, output_tail, &ctx->free, (ngx_buf_tag_t) &body_rechunk_output_filter, 0); if (output_tail == NULL) { return NGX_ERROR; } ngx_memcpy(output_tail->buf, input->buf, sizeof(ngx_buf_t)); /* Append chunked encoding footer */ output_tail = append_ngx_chain_element(r->pool, &output_head, output_tail, &ctx->free, (ngx_buf_tag_t) &body_rechunk_output_filter, 2); if (output_tail == NULL) { return NGX_ERROR; } output_tail->buf->last = ngx_copy(output_tail->buf->last, "\r\n", 2); body_eof_reached = input->buf->last_buf; input = input->next; } } if (body_eof_reached) { /* Append final termination chunk. */ output_tail = append_ngx_chain_element(r->pool, &output_head, output_tail, &ctx->free, (ngx_buf_tag_t) &body_rechunk_output_filter, 5); if (output_tail == NULL) { return NGX_ERROR; } output_tail->buf->last = ngx_copy(output_tail->buf->last, "0\r\n\r\n", 5); } out: rc = ngx_chain_writer(&r->upstream->writer, output_head); /* * The previous ngx_chain_writer() call consumed some buffers. * Find such consumped (empty) buffers in the output buffer list, * and either free them or add them to the freelist depending on * whether the buffer's tag matches ours. */ ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &output_head, (ngx_buf_tag_t) &body_rechunk_output_filter); return rc; } #define SET_NGX_STR(str, the_data) \ do { \ (str)->data = (u_char *) the_data; \ (str)->len = sizeof(the_data) - 1; \ } while (0) #define SET_NGX_STR_WITH_NULL(str, the_data) \ do { \ (str)->data = (u_char *) the_data; \ (str)->len = sizeof(the_data); \ } while (0) typedef struct { ngx_str_t method; /* Includes trailing space */ ngx_str_t app_type; ngx_str_t app_start_command; ngx_str_t escaped_uri; ngx_str_t content_length; /* Only used if !r->request_body_no_buffering */ ngx_str_t core_password; ngx_str_t remote_port; } buffer_construction_state; /* prepare_request_buffer_construction() and construct_request_buffer() are * used to create an HTTP request header buffer to be sent to the Core Controller. * * construct_request_buffer() is actually called twice: the first time in "no-op" mode to * calculate how many bytes it must allocate, and the second time to actually create the * buffer. For efficiency reasons, as much preparation work as possible is split into * the prepare_request_buffer_construction() function so that the two construct_request_buffer() * calls don't have to perform that work twice. */ static ngx_int_t prepare_request_buffer_construction(ngx_http_request_t *r, passenger_loc_conf_t *slcf, passenger_context_t *context, buffer_construction_state *state) { unsigned int len; ngx_uint_t port; struct sockaddr_in *sin; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; #endif const PsgWrapperRegistryEntry *wrapper_registry_entry; /* Construct HTTP method string, including trailing space. */ switch (r->method) { case NGX_HTTP_GET: SET_NGX_STR(&state->method, "GET "); break; case NGX_HTTP_HEAD: SET_NGX_STR(&state->method, "HEAD "); break; case NGX_HTTP_POST: SET_NGX_STR(&state->method, "POST "); break; case NGX_HTTP_PUT: SET_NGX_STR(&state->method, "PUT "); break; case NGX_HTTP_DELETE: SET_NGX_STR(&state->method, "DELETE "); break; case NGX_HTTP_MKCOL: SET_NGX_STR(&state->method, "MKCOL "); break; case NGX_HTTP_COPY: SET_NGX_STR(&state->method, "COPY "); break; case NGX_HTTP_MOVE: SET_NGX_STR(&state->method, "MOVE "); break; case NGX_HTTP_OPTIONS: SET_NGX_STR(&state->method, "OPTIONS "); break; case NGX_HTTP_PROPFIND: SET_NGX_STR(&state->method, "PROPFIND "); break; case NGX_HTTP_PROPPATCH: SET_NGX_STR(&state->method, "PROPPATCH "); break; case NGX_HTTP_LOCK: SET_NGX_STR(&state->method, "LOCK "); break; case NGX_HTTP_UNLOCK: SET_NGX_STR(&state->method, "UNLOCK "); break; case NGX_HTTP_PATCH: SET_NGX_STR(&state->method, "PATCH "); break; case NGX_HTTP_TRACE: SET_NGX_STR(&state->method, "TRACE "); break; default: SET_NGX_STR(&state->method, "UNKNOWN "); break; } if (slcf->autogenerated.app_start_command.data != NULL) { /* The config specified that this is either a generic app or a Kuria app. */ state->app_type.data = NULL; state->app_type.len = 0; state->app_start_command = slcf->autogenerated.app_start_command; } else { wrapper_registry_entry = psg_app_type_detector_result_get_wrapper_registry_entry( context->detector_result); if (wrapper_registry_entry != NULL) { /* This is an auto-supported app. */ state->app_type.data = (u_char *) psg_wrapper_registry_entry_get_language(wrapper_registry_entry, &state->app_type.len); state->app_start_command.data = NULL; state->app_start_command.len = 0; } else { /* This has been autodetected to be a generic app or a Kuria app. */ state->app_type.data = NULL; state->app_type.len = 0; state->app_start_command.data = (u_char *) psg_app_type_detector_result_get_app_start_command( context->detector_result, &state->app_start_command.len); } } /* * 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 * * Here we check whether Nginx has rewritten the URI or not. If not, * we can use the raw, unparsed URI as sent by the client. */ if (r->valid_unparsed_uri && r->main) { state->escaped_uri = r->unparsed_uri; const char *pos = memchr((const char *) r->unparsed_uri.data, '?', r->unparsed_uri.len); if (pos != NULL) { state->escaped_uri.len = pos - (const char *) r->unparsed_uri.data; } } else { state->escaped_uri.len = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, NGX_ESCAPE_URI) + r->uri.len; state->escaped_uri.data = ngx_pnalloc(r->pool, state->escaped_uri.len); if (state->escaped_uri.data == NULL) { return NGX_ERROR; } ngx_escape_uri(state->escaped_uri.data, r->uri.data, r->uri.len, NGX_ESCAPE_URI); } if (r->headers_in.chunked && !r->request_body_no_buffering) { /* If the request body is chunked, then Nginx sets r->headers_in.content_length_n * but does not set r->headers_in.headers, so we add this header ourselves. */ state->content_length.data = ngx_pnalloc(r->pool, sizeof("4294967295") - 1); state->content_length.len = ngx_snprintf(state->content_length.data, sizeof("4294967295") - 1, "%O", r->headers_in.content_length_n) - state->content_length.data; } // else: content_length not used state->core_password.data = (u_char *) psg_watchdog_launcher_get_core_password( psg_watchdog_launcher, &len); state->core_password.len = len; switch (r->connection->sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *) r->connection->sockaddr; port = ntohs(sin6->sin6_port); break; #endif #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: port = 0; break; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) r->connection->sockaddr; port = ntohs(sin->sin_port); break; } state->remote_port.data = ngx_pnalloc(r->pool, sizeof("65535") - 1); if (state->remote_port.data == NULL) { return NGX_ERROR; } if (port > 0 && port < 65536) { state->remote_port.len = ngx_snprintf(state->remote_port.data, sizeof("65535") - 1, "%ui", port) - state->remote_port.data; } else { state->remote_port.len = 0; } return NGX_OK; } /* See comment for prepare_request_buffer_construction() */ 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_uint_t i; ngx_list_part_t *part; ngx_table_elt_t *header; size_t len; ngx_str_t public_dir_parent; ngx_str_t public_dir_resolved; const char *temp_path; 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) || (!r->request_body_no_buffering && 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 && !r->request_body_no_buffering) { 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: "); if (b != NULL) { b->last = ngx_copy(b->last, r->headers_in.user.data, r->headers_in.user.len); } total_size += r->headers_in.user.len; PUSH_STATIC_STR("\r\n"); } if (slcf->autogenerated.app_group_name.data == NULL) { PUSH_STATIC_STR("!~PASSENGER_APP_GROUP_NAME: "); if (slcf->autogenerated.app_root.data == NULL) { if (context->base_uri.data == NULL) { /* If no passenger_base_uri applies, then the app * group name is based on the parent directory of * the document root. */ public_dir_parent.data = (u_char *) psg_extract_dir_name_static( (const char *) context->public_dir.data, context->public_dir.len, &public_dir_parent.len); } else { /* If a passenger_base_uri applies, then the document * root may be a symlink. We base the app group name * on `extractDirName(resolveSymlink(public_dir))`. */ public_dir_resolved.data = (u_char *) psg_resolve_symlink((const char *) context->public_dir.data, context->public_dir.len, &public_dir_resolved.len); if (public_dir_resolved.data == NULL) { /* Resolve or memory allocation error. Fallback to * assuming that no passenger_base_uri applies. */ ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno, "error resolving symlink %V", &context->public_dir); public_dir_parent.data = (u_char *) psg_extract_dir_name_static( (const char *) context->public_dir.data, context->public_dir.len, &public_dir_parent.len); } else { temp_path = psg_extract_dir_name_static( (const char *) public_dir_resolved.data, public_dir_resolved.len, &public_dir_parent.len); public_dir_parent.data = ngx_pnalloc(r->pool, public_dir_parent.len); memcpy(public_dir_parent.data, temp_path, public_dir_parent.len); free(public_dir_resolved.data); } } if (b != NULL) { b->last = ngx_copy(b->last, public_dir_parent.data, public_dir_parent.len); } total_size += public_dir_parent.len; } else { if (b != NULL) { b->last = ngx_copy(b->last, slcf->autogenerated.app_root.data, slcf->autogenerated.app_root.len); } total_size += slcf->autogenerated.app_root.len; } if (slcf->autogenerated.environment.data != NULL) { if (b != NULL) { b->last = ngx_copy(b->last, " (", 2); b->last = ngx_copy(b->last, slcf->autogenerated.environment.data, slcf->autogenerated.environment.len); b->last = ngx_copy(b->last, ")", 1); } total_size += (sizeof(" (") - 1) + slcf->autogenerated.environment.len + (sizeof(")") - 1); } PUSH_STATIC_STR("\r\n"); } if (state->app_type.len > 0) { 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"); } else { PUSH_STATIC_STR("!~PASSENGER_APP_START_COMMAND: "); if (b != NULL) { b->last = ngx_copy(b->last, state->app_start_command.data, state->app_start_command.len); } total_size += state->app_start_command.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. * B = Buffer request body * C = Strip 100 Continue header * S = SSL */ PUSH_STATIC_STR("!~FLAGS: CD"); if (slcf->autogenerated.buffer_upload) { PUSH_STATIC_STR("B"); } #if (NGX_HTTP_SSL) if (r->http_connection != NULL /* happens in sub-requests */ && 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 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, slcf, 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; } construct_request_buffer(r, slcf, context, &state, b); cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; /* Pass already received request body buffers. Make sure they come * after the request header buffer we just constructed. */ body = r->upstream->request_bufs; r->upstream->request_bufs = cl; if (!r->request_body_no_buffering) { while (body) { if (r->headers_in.chunked && r->request_body_no_buffering) { /* If Transfer-Encoding is chunked, then Nginx dechunks the body. * If at the same time request body buffering is disabled, then * we pass the Transfer-Encoding header to the Passenger Core, * and thus we also need to ensure we rechunk the body. */ b = ngx_create_temp_buf(r->pool, 32); if (b == NULL) { return NGX_ERROR; } b->last = ngx_sprintf(b->last, "%xO\r\n", ngx_buf_size(body->buf)); cl->next = ngx_alloc_chain_link(r->pool); if (cl->next == NULL) { return NGX_ERROR; } cl = cl->next; cl->buf = b; } 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; if (r->headers_in.chunked && r->request_body_no_buffering) { b = ngx_create_temp_buf(r->pool, 2); if (b == NULL) { return NGX_ERROR; } b->last = ngx_copy(b->last, "\r\n", 2); cl->next = ngx_alloc_chain_link(r->pool); if (cl->next == NULL) { return NGX_ERROR; } cl = cl->next; cl->buf = b; } } } b->flush = 1; cl->next = NULL; /* Again, if Transfer-Encoding is chunked, then Nginx dechunks the body. * Here we install an output filter to make sure that the request body parts * that will be received in the future, will also be rechunked when passed * to the Passenger Core. */ if (r->headers_in.chunked && r->request_body_no_buffering) { r->upstream->output.output_filter = body_rechunk_output_filter; r->upstream->output.filter_ctx = r; } return NGX_OK; } static ngx_int_t reinit_request(ngx_http_request_t *r) { passenger_context_t *context; context = ngx_http_get_module_ctx(r, ngx_http_passenger_module); if (context == NULL) { return NGX_OK; } context->status = 0; context->status_count = 0; context->status_start = NULL; context->status_end = NULL; r->upstream->process_header = process_status_line; r->state = 0; return NGX_OK; } static ngx_int_t process_status_line(ngx_http_request_t *r) { ngx_int_t rc; ngx_http_upstream_t *u; passenger_context_t *context; context = ngx_http_get_module_ctx(r, ngx_http_passenger_module); if (context == NULL) { return NGX_ERROR; } rc = parse_status_line(r, context); if (rc == NGX_AGAIN) { return rc; } u = r->upstream; if (rc == NGX_HTTP_SCGI_PARSE_NO_HEADER) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "upstream sent no valid HTTP/1.0 header"); #if 0 if (u->accel) { return NGX_HTTP_UPSTREAM_INVALID_HEADER; } #endif u->headers_in.status_n = NGX_HTTP_OK; u->state->status = NGX_HTTP_OK; return NGX_OK; } u->headers_in.status_n = context->status; u->state->status = context->status; u->headers_in.status_line.len = context->status_end - context->status_start; u->headers_in.status_line.data = ngx_palloc(r->pool, u->headers_in.status_line.len); if (u->headers_in.status_line.data == NULL) { return NGX_ERROR; } ngx_memcpy(u->headers_in.status_line.data, context->status_start, u->headers_in.status_line.len); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http scgi status %ui \"%V\"", u->headers_in.status_n, &u->headers_in.status_line); u->process_header = process_header; return process_header(r); } static ngx_int_t parse_status_line(ngx_http_request_t *r, passenger_context_t *context) { u_char ch; u_char *pos; ngx_http_upstream_t *u; enum { sw_start = 0, sw_H, sw_HT, sw_HTT, sw_HTTP, sw_first_major_digit, sw_major_digit, sw_first_minor_digit, sw_minor_digit, sw_status, sw_space_after_status, sw_status_text, sw_almost_done } state; u = r->upstream; state = r->state; for (pos = u->buffer.pos; pos < u->buffer.last; pos++) { ch = *pos; switch (state) { /* "HTTP/" */ case sw_start: switch (ch) { case 'H': state = sw_H; break; default: return NGX_HTTP_SCGI_PARSE_NO_HEADER; } break; case sw_H: switch (ch) { case 'T': state = sw_HT; break; default: return NGX_HTTP_SCGI_PARSE_NO_HEADER; } break; case sw_HT: switch (ch) { case 'T': state = sw_HTT; break; default: return NGX_HTTP_SCGI_PARSE_NO_HEADER; } break; case sw_HTT: switch (ch) { case 'P': state = sw_HTTP; break; default: return NGX_HTTP_SCGI_PARSE_NO_HEADER; } break; case sw_HTTP: switch (ch) { case '/': state = sw_first_major_digit; break; default: return NGX_HTTP_SCGI_PARSE_NO_HEADER; } break; /* the first digit of major HTTP version */ case sw_first_major_digit: if (ch < '1' || ch > '9') { return NGX_HTTP_SCGI_PARSE_NO_HEADER; } state = sw_major_digit; break; /* the major HTTP version or dot */ case sw_major_digit: if (ch == '.') { state = sw_first_minor_digit; break; } if (ch < '0' || ch > '9') { return NGX_HTTP_SCGI_PARSE_NO_HEADER; } break; /* the first digit of minor HTTP version */ case sw_first_minor_digit: if (ch < '0' || ch > '9') { return NGX_HTTP_SCGI_PARSE_NO_HEADER; } state = sw_minor_digit; break; /* the minor HTTP version or the end of the request line */ case sw_minor_digit: if (ch == ' ') { state = sw_status; break; } if (ch < '0' || ch > '9') { return NGX_HTTP_SCGI_PARSE_NO_HEADER; } break; /* HTTP status code */ case sw_status: if (ch == ' ') { break; } if (ch < '0' || ch > '9') { return NGX_HTTP_SCGI_PARSE_NO_HEADER; } context->status = context->status * 10 + ch - '0'; if (++context->status_count == 3) { state = sw_space_after_status; context->status_start = pos - 2; } break; /* space or end of line */ case sw_space_after_status: switch (ch) { case ' ': state = sw_status_text; break; case '.': /* IIS may send 403.1, 403.2, etc */ state = sw_status_text; break; case CR: state = sw_almost_done; break; case LF: goto done; default: return NGX_HTTP_SCGI_PARSE_NO_HEADER; } break; /* any text until end of line */ case sw_status_text: switch (ch) { case CR: state = sw_almost_done; break; case LF: goto done; } break; /* end of status line */ case sw_almost_done: context->status_end = pos - 1; switch (ch) { case LF: goto done; default: return NGX_HTTP_SCGI_PARSE_NO_HEADER; } } } u->buffer.pos = pos; r->state = state; return NGX_AGAIN; done: u->buffer.pos = pos + 1; if (context->status_end == NULL) { context->status_end = pos; } r->state = sw_start; return NGX_OK; } static ngx_int_t process_header(ngx_http_request_t *r) { ngx_str_t *status_line; ngx_int_t rc, status; ngx_table_elt_t *h; ngx_http_upstream_t *u; ngx_http_upstream_header_t *hh; ngx_http_upstream_main_conf_t *umcf; ngx_http_core_loc_conf_t *clcf; umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); for ( ;; ) { rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1); if (rc == NGX_OK) { /* a header line has been parsed successfully */ h = ngx_list_push(&r->upstream->headers_in.headers); if (h == NULL) { return NGX_ERROR; } h->hash = r->header_hash; h->key.len = r->header_name_end - r->header_name_start; h->value.len = r->header_end - r->header_start; h->key.data = ngx_pnalloc(r->pool, h->key.len + 1 + h->value.len + 1 + h->key.len); if (h->key.data == NULL) { return NGX_ERROR; } h->value.data = h->key.data + h->key.len + 1; h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1; ngx_memcpy(h->key.data, r->header_name_start, h->key.len); h->key.data[h->key.len] = '\0'; ngx_memcpy(h->value.data, r->header_start, h->value.len); h->value.data[h->value.len] = '\0'; if (h->key.len == r->lowcase_index) { ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len); } else { ngx_strlow(h->lowcase_key, h->key.data, h->key.len); } hh = ngx_hash_find(&umcf->headers_in_hash, h->hash, h->lowcase_key, h->key.len); if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { return NGX_ERROR; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http scgi header: \"%V: %V\"", &h->key, &h->value); continue; } if (rc == NGX_HTTP_PARSE_HEADER_DONE) { /* a whole header has been parsed successfully */ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http scgi header done"); /* * if no "Server" and "Date" in header line, * then add the default headers */ if (r->upstream->headers_in.server == NULL) { h = ngx_list_push(&r->upstream->headers_in.headers); if (h == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash( ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r'); h->key.len = sizeof("Server") - 1; h->key.data = (u_char *) "Server"; if (!passenger_main_conf.autogenerated.show_version_in_header) { if (clcf->server_tokens) { h->value.data = (u_char *) (NGINX_VER " + " PROGRAM_NAME); } else { h->value.data = (u_char *) ("nginx + " PROGRAM_NAME); } } else { if (clcf->server_tokens) { h->value.data = (u_char *) (NGINX_VER " + " PROGRAM_NAME " " PASSENGER_VERSION); } else { h->value.data = (u_char *) ("nginx + " PROGRAM_NAME " " PASSENGER_VERSION); } } h->value.len = ngx_strlen(h->value.data); h->lowcase_key = (u_char *) "server"; } if (r->upstream->headers_in.date == NULL) { h = ngx_list_push(&r->upstream->headers_in.headers); if (h == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e'); h->key.len = sizeof("Date") - 1; h->key.data = (u_char *) "Date"; h->value.len = 0; h->value.data = NULL; h->lowcase_key = (u_char *) "date"; } /* Process "Status" header. */ u = r->upstream; if (u->headers_in.status_n) { goto done; } if (u->headers_in.status) { status_line = &u->headers_in.status->value; status = ngx_atoi(status_line->data, 3); if (status == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "upstream sent invalid status \"%V\"", status_line); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } u->headers_in.status_n = status; u->headers_in.status_line = *status_line; } else if (u->headers_in.location) { u->headers_in.status_n = 302; ngx_str_set(&u->headers_in.status_line, "302 Moved Temporarily"); } else { u->headers_in.status_n = 200; ngx_str_set(&u->headers_in.status_line, "200 OK"); } if (u->state && u->state->status == 0) { u->state->status = u->headers_in.status_n; } done: /* Supported since Nginx 1.3.15. */ #ifdef NGX_HTTP_SWITCHING_PROTOCOLS if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS && r->headers_in.upgrade) { u->upgrade = 1; } #endif return NGX_OK; } if (rc == NGX_AGAIN) { return NGX_AGAIN; } /* there was error while a header line parsing */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "upstream sent invalid header"); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } } static void abort_request(ngx_http_request_t *r) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "abort Passenger request"); } static void finalize_request(ngx_http_request_t *r, ngx_int_t rc) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "finalize Passenger request"); } ngx_int_t passenger_content_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_http_upstream_t *u; passenger_loc_conf_t *slcf; ngx_str_t path, base_uri; u_char *path_last, *end; u_char root_path_str[NGX_MAX_PATH + 1]; ngx_str_t root_path; size_t root_len, len; u_char page_cache_file_str[NGX_MAX_PATH + 1]; ngx_str_t page_cache_file; passenger_context_t *context; void *detector_result_mem; ngx_pool_cleanup_t *detector_result_cleanup; PP_Error error; const PsgWrapperRegistryEntry *wrapper_registry_entry; if (passenger_main_conf.autogenerated.root_dir.len == 0) { return NGX_DECLINED; } slcf = ngx_http_get_module_loc_conf(r, ngx_http_passenger_module); /* Let the next content handler take care of this request if Phusion * Passenger is disabled for this URL. */ if (!slcf->autogenerated.enabled) { return NGX_DECLINED; } /* Let the next content handler take care of this request if this URL * maps to an existing file. */ path_last = ngx_http_map_uri_to_path(r, &path, &root_len, 0); if (path_last != NULL && file_exists(path.data, 0)) { return NGX_DECLINED; } /* Create a string containing the root path. This path already * contains a trailing slash. */ end = ngx_copy(root_path_str, path.data, root_len); *end = '\0'; root_path.data = root_path_str; root_path.len = root_len; context = ngx_pcalloc(r->pool, sizeof(passenger_context_t)); if (context == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_http_set_ctx(r, context, ngx_http_passenger_module); /* Find the base URI for this web application, if any. */ if (find_base_uri(r, slcf, &base_uri)) { /* Store the found base URI into context->public_dir. We infer that * the 'public' directory of the web app equals document root + base URI. */ if (slcf->autogenerated.document_root.data != NULL) { len = slcf->autogenerated.document_root.len + 1; context->public_dir.data = ngx_palloc(r->pool, sizeof(u_char) * len); end = ngx_copy(context->public_dir.data, slcf->autogenerated.document_root.data, slcf->autogenerated.document_root.len); } else { len = root_path.len + base_uri.len + 1; context->public_dir.data = ngx_palloc(r->pool, sizeof(u_char) * len); end = ngx_copy(context->public_dir.data, root_path.data, root_path.len); end = ngx_copy(end, base_uri.data, base_uri.len); } *end = '\0'; context->public_dir.len = len - 1; context->base_uri = base_uri; } else { /* No base URI directives are applicable for this request. So assume that * the web application's public directory is the document root. * context->base_uri is now a NULL string. */ len = sizeof(u_char *) * (root_path.len + 1); context->public_dir.data = ngx_palloc(r->pool, len); end = ngx_copy(context->public_dir.data, root_path.data, root_path.len); *end = '\0'; context->public_dir.len = root_path.len; } if (context->public_dir.len == 0) { /* If the `root` directive is set to `/` then `public_dir` * becomes the empty string. We fix this into `/`. */ context->public_dir.data = (u_char *) "/"; context->public_dir.len = 1; } /* If there's a corresponding page cache file for this URL, then serve that * file instead. */ page_cache_file.data = page_cache_file_str; page_cache_file.len = sizeof(page_cache_file_str); if (map_uri_to_page_cache_file(r, &context->public_dir, path.data, path_last - path.data, &page_cache_file)) { return passenger_static_content_handler(r, &page_cache_file); } detector_result_mem = ngx_palloc(r->pool, psg_app_type_detector_result_get_object_size()); context->detector_result = psg_app_type_detector_result_init(detector_result_mem); detector_result_cleanup = ngx_pool_cleanup_add(r->pool, 0); detector_result_cleanup->handler = cleanup_detector_result; detector_result_cleanup->data = context->detector_result; /* If `app_start_command` is set, then it means the config specified that it is * either a generic app or a Kuria app. */ if (slcf->autogenerated.app_start_command.data == NULL && slcf->autogenerated.app_type.data == NULL) { /* If neither `app_start_command` nor `app_type` are set, then * autodetect what kind of app this is. */ pp_error_init(&error); if (slcf->autogenerated.app_root.data == NULL) { psg_app_type_detector_check_document_root( psg_app_type_detector, context->detector_result, (const char *) context->public_dir.data, context->public_dir.len, context->base_uri.len != 0, &error); } else { psg_app_type_detector_check_app_root( psg_app_type_detector, context->detector_result, (const char *) slcf->autogenerated.app_root.data, slcf->autogenerated.app_root.len, &error); } if (psg_app_type_detector_result_is_null(context->detector_result)) { if (error.message == NULL) { return NGX_DECLINED; } else if (error.errnoCode == EACCES) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "%s; This error means that the Nginx worker process (PID %d, " "running as UID %d) does not have permission to access this file. " "Please read this page to learn how to fix this problem: " "https://www.phusionpassenger.com/library/admin/nginx/troubleshooting/?a=upon-accessing-the-web-app-nginx-reports-a-permission-denied-error; Extra info", error.message, (int) getpid(), (int) getuid()); } else { ngx_log_error(NGX_LOG_ALERT, r->connection->log, (error.errnoCode == PP_NO_ERRNO) ? 0 : error.errnoCode, "%s", error.message); } pp_error_destroy(&error); return NGX_HTTP_INTERNAL_SERVER_ERROR; } } else if (slcf->autogenerated.app_start_command.data == NULL) { /* If `app_start_command` is not set but `app_type` is, then * verify whether the given `app_type` value is supported * and resolve aliases. */ wrapper_registry_entry = psg_wrapper_registry_lookup(psg_wrapper_registry, (const char *) slcf->autogenerated.app_type.data, slcf->autogenerated.app_type.len); if (psg_wrapper_registry_entry_is_null(wrapper_registry_entry)) { return NGX_DECLINED; } else { psg_app_type_detector_result_set_wrapper_registry_entry( context->detector_result, wrapper_registry_entry); } } /* Setup upstream stuff and prepare sending the request to the Passenger core. */ if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } u = r->upstream; u->schema = pp_schema_string; u->output.tag = (ngx_buf_tag_t) &ngx_http_passenger_module; set_upstream_server_address(u, &slcf->upstream_config); u->conf = &slcf->upstream_config; #if (NGX_HTTP_CACHE) u->create_key = create_key; #endif u->create_request = create_request; u->reinit_request = reinit_request; u->process_header = process_status_line; u->abort_request = abort_request; u->finalize_request = finalize_request; r->state = 0; u->buffering = slcf->upstream_config.buffering; u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t)); if (u->pipe == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } u->pipe->input_filter = ngx_event_pipe_copy_input_filter; u->pipe->input_ctx = r; r->request_body_no_buffering = !slcf->upstream_config.request_buffering; rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); fix_peer_address(r); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } return NGX_DONE; }
Upload File
Create Folder