예제 #1
0
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;
}
예제 #2
0
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
}
예제 #3
0
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;
}
예제 #4
0
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;
}
예제 #5
0
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;
}
예제 #7
0
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;
}
예제 #8
0
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;
}