⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mod_proxy_http.c

📁 Apache官方在今天放出产品系列2.2的最新版本2.2.11的源码包 最流行的HTTP服务器软件之一
💻 C
📖 第 1 页 / 共 5 页
字号:
     *     *   We have no request body (handled by RB_STREAM_CL)     *     *   We have a request body length <= MAX_MEM_SPOOL     *     *   The administrator has setenv force-proxy-request-1.0     *     *   The client sent a C-L body, and the administrator has     *   not setenv proxy-sendchunked or has set setenv proxy-sendcl     *     *   The client sent a T-E body, and the administrator has     *   setenv proxy-sendcl, and not setenv proxy-sendchunked     *     * If both proxy-sendcl and proxy-sendchunked are set, the     * behavior is the same as if neither were set, large bodies     * that can't be read will be forwarded in their original     * form of C-L, or T-E.     *     * To ensure maximum compatibility, setenv proxy-sendcl     * To reduce server resource use,   setenv proxy-sendchunked     *     * Then address specific servers with conditional setenv     * options to restore the default behavior where desireable.     *     * We have to compute content length by reading the entire request     * body; if request body is not small, we'll spool the remaining     * input to a temporary file.  Chunked is always preferable.     *     * We can only trust the client-provided C-L if the T-E header     * is absent, and the filters are unchanged (the body won't     * be resized by another content filter).     */    if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {        /* The whole thing fit, so our decision is trivial, use         * the filtered bytes read from the client for the request         * body Content-Length.         *         * If we expected no body, and read no body, do not set         * the Content-Length.         */        if (old_cl_val || old_te_val || bytes_read) {            old_cl_val = apr_off_t_toa(r->pool, bytes_read);        }        rb_method = RB_STREAM_CL;    }    else if (old_te_val) {        if (force10             || (apr_table_get(r->subprocess_env, "proxy-sendcl")                  && !apr_table_get(r->subprocess_env, "proxy-sendchunks")                  && !apr_table_get(r->subprocess_env, "proxy-sendchunked"))) {            rb_method = RB_SPOOL_CL;        }        else {            rb_method = RB_STREAM_CHUNKED;        }    }    else if (old_cl_val) {        if (r->input_filters == r->proto_input_filters) {            rb_method = RB_STREAM_CL;        }        else if (!force10                  && (apr_table_get(r->subprocess_env, "proxy-sendchunks")                      || apr_table_get(r->subprocess_env, "proxy-sendchunked"))                  && !apr_table_get(r->subprocess_env, "proxy-sendcl")) {            rb_method = RB_STREAM_CHUNKED;        }        else {            rb_method = RB_SPOOL_CL;        }    }    else {        /* This is an appropriate default; very efficient for no-body         * requests, and has the behavior that it will not add any C-L         * when the old_cl_val is NULL.         */        rb_method = RB_SPOOL_CL;    }/* Yes I hate gotos.  This is the subrequest shortcut */skip_body:    /*     * Handle Connection: header if we do HTTP/1.1 request:     * If we plan to close the backend connection sent Connection: close     * otherwise sent Connection: Keep-Alive.     */    if (!force10) {        if (p_conn->close || p_conn->close_on_recycle) {            buf = apr_pstrdup(p, "Connection: close" CRLF);        }        else {            buf = apr_pstrdup(p, "Connection: Keep-Alive" CRLF);        }        ap_xlate_proto_to_ascii(buf, strlen(buf));        e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);        APR_BRIGADE_INSERT_TAIL(header_brigade, e);    }    /* send the request body, if any. */    switch(rb_method) {    case RB_STREAM_CHUNKED:        rv = stream_reqbody_chunked(p, r, p_conn, origin, header_brigade,                                        input_brigade);        break;    case RB_STREAM_CL:        rv = stream_reqbody_cl(p, r, p_conn, origin, header_brigade,                                   input_brigade, old_cl_val);        break;    case RB_SPOOL_CL:        rv = spool_reqbody_cl(p, r, p_conn, origin, header_brigade,                                  input_brigade, (old_cl_val != NULL)                                              || (old_te_val != NULL)                                              || (bytes_read > 0));        break;    default:        /* shouldn't be possible */        rv = HTTP_INTERNAL_SERVER_ERROR ;        break;    }    if (rv != OK) {        /* apr_errno value has been logged in lower level method */        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,                     "proxy: pass request body failed to %pI (%s)"                     " from %s (%s)",                     p_conn->addr,                     p_conn->hostname ? p_conn->hostname: "",                     c->remote_ip,                     c->remote_host ? c->remote_host: "");        return rv;    }    return OK;}static void process_proxy_header(request_rec* r, proxy_dir_conf* c,                      const char* key, const char* value){    static const char* date_hdrs[]        = { "Date", "Expires", "Last-Modified", NULL } ;    static const struct {        const char* name;        ap_proxy_header_reverse_map_fn func;    } transform_hdrs[] = {        { "Location", ap_proxy_location_reverse_map } ,        { "Content-Location", ap_proxy_location_reverse_map } ,        { "URI", ap_proxy_location_reverse_map } ,        { "Destination", ap_proxy_location_reverse_map } ,        { "Set-Cookie", ap_proxy_cookie_reverse_map } ,        { NULL, NULL }    } ;    int i ;    for ( i = 0 ; date_hdrs[i] ; ++i ) {        if ( !strcasecmp(date_hdrs[i], key) ) {            apr_table_add(r->headers_out, key,                ap_proxy_date_canon(r->pool, value)) ;            return ;        }    }    for ( i = 0 ; transform_hdrs[i].name ; ++i ) {        if ( !strcasecmp(transform_hdrs[i].name, key) ) {            apr_table_add(r->headers_out, key,                (*transform_hdrs[i].func)(r, c, value)) ;            return ;       }    }    apr_table_add(r->headers_out, key, value) ;    return ;}/* * Note: pread_len is the length of the response that we've  mistakenly * read (assuming that we don't consider that an  error via * ProxyBadHeader StartBody). This depends on buffer actually being * local storage to the calling code in order for pread_len to make * any sense at all, since we depend on buffer still containing * what was read by ap_getline() upon return. */static void ap_proxy_read_headers(request_rec *r, request_rec *rr,                                  char *buffer, int size,                                  conn_rec *c, int *pread_len){    int len;    char *value, *end;    char field[MAX_STRING_LEN];    int saw_headers = 0;    void *sconf = r->server->module_config;    proxy_server_conf *psc;    proxy_dir_conf *dconf;    dconf = ap_get_module_config(r->per_dir_config, &proxy_module);    psc = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);    r->headers_out = apr_table_make(r->pool, 20);    *pread_len = 0;    /*     * Read header lines until we get the empty separator line, a read error,     * the connection closes (EOF), or we timeout.     */    while ((len = ap_getline(buffer, size, rr, 1)) > 0) {        if (!(value = strchr(buffer, ':'))) {     /* Find the colon separator */            /* We may encounter invalid headers, usually from buggy             * MS IIS servers, so we need to determine just how to handle             * them. We can either ignore them, assume that they mark the             * start-of-body (eg: a missing CRLF) or (the default) mark             * the headers as totally bogus and return a 500. The sole             * exception is an extra "HTTP/1.0 200, OK" line sprinkled             * in between the usual MIME headers, which is a favorite             * IIS bug.             */             /* XXX: The mask check is buggy if we ever see an HTTP/1.10 */            if (!apr_date_checkmask(buffer, "HTTP/#.# ###*")) {                if (psc->badopt == bad_error) {                    /* Nope, it wasn't even an extra HTTP header. Give up. */                    r->headers_out = NULL;                    return ;                }                else if (psc->badopt == bad_body) {                    /* if we've already started loading headers_out, then                     * return what we've accumulated so far, in the hopes                     * that they are useful; also note that we likely pre-read                     * the first line of the response.                     */                    if (saw_headers) {                        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,                         "proxy: Starting body due to bogus non-header in headers "                         "returned by %s (%s)", r->uri, r->method);                        *pread_len = len;                        return ;                    } else {                         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,                         "proxy: No HTTP headers "                         "returned by %s (%s)", r->uri, r->method);                        return ;                    }                }            }            /* this is the psc->badopt == bad_ignore case */            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,                         "proxy: Ignoring bogus HTTP header "                         "returned by %s (%s)", r->uri, r->method);            continue;        }        *value = '\0';        ++value;        /* XXX: RFC2068 defines only SP and HT as whitespace, this test is         * wrong... and so are many others probably.         */        while (apr_isspace(*value))            ++value;            /* Skip to start of value   */        /* should strip trailing whitespace as well */        for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); --end)            *end = '\0';        /* make sure we add so as not to destroy duplicated headers         * Modify headers requiring canonicalisation and/or affected         * by ProxyPassReverse and family with process_proxy_header         */        process_proxy_header(r, dconf, buffer, value) ;        saw_headers = 1;        /* the header was too long; at the least we should skip extra data */        if (len >= size - 1) {            while ((len = ap_getline(field, MAX_STRING_LEN, rr, 1))                    >= MAX_STRING_LEN - 1) {                /* soak up the extra data */            }            if (len == 0) /* time to exit the larger loop as well */                break;        }    }}static int addit_dammit(void *v, const char *key, const char *val){    apr_table_addn(v, key, val);    return 1;}staticapr_status_t ap_proxygetline(apr_bucket_brigade *bb, char *s, int n, request_rec *r,                             int fold, int *writen){    char *tmp_s = s;    apr_status_t rv;    apr_size_t len;    rv = ap_rgetline(&tmp_s, n, &len, r, fold, bb);    apr_brigade_cleanup(bb);    if (rv == APR_SUCCESS) {        *writen = (int) len;    } else if (rv == APR_ENOSPC) {        *writen = n;    } else {        *writen = -1;    }    return rv;}/* * Limit the number of interim respones we sent back to the client. Otherwise * we suffer from a memory build up. Besides there is NO sense in sending back * an unlimited number of interim responses to the client. Thus if we cross * this limit send back a 502 (Bad Gateway). */#ifndef AP_MAX_INTERIM_RESPONSES#define AP_MAX_INTERIM_RESPONSES 10#endifstaticapr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,                                            proxy_conn_rec *backend,                                            conn_rec *origin,                                            proxy_server_conf *conf,                                            char *server_portstr) {    conn_rec *c = r->connection;    char buffer[HUGE_STRING_LEN];    const char *buf;    char keepchar;    request_rec *rp;    apr_bucket *e;    apr_bucket_brigade *bb, *tmp_bb;    apr_bucket_brigade *pass_bb;    int len, backasswards;    int interim_response = 0; /* non-zero whilst interim 1xx responses                               * are being read. */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -