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

📄 proxy_http.c

📁 精通tomcat书籍原代码,希望大家共同学习
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Copyright 1999-2004 The Apache Software Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* HTTP routines for Apache proxy */

#include "mod_proxy.h"

module AP_MODULE_DECLARE_DATA proxy_http_module;

int ap_proxy_http_canon(request_rec *r, char *url);
int ap_proxy_http_handler(request_rec *r, proxy_worker *worker,
                          proxy_server_conf *conf,
                          char *url, const char *proxyname, 
                          apr_port_t proxyport);

static apr_status_t ap_proxy_http_cleanup(const char *scheme,
                                          request_rec *r,
                                          proxy_conn_rec *backend);

/*
 * Canonicalise http-like URLs.
 *  scheme is the scheme for the URL
 *  url    is the URL starting with the first '/'
 *  def_port is the default port for this scheme.
 */
int ap_proxy_http_canon(request_rec *r, char *url)
{
    char *host, *path, *search, sport[7];
    const char *err;
    const char *scheme;
    apr_port_t port, def_port;

    /* ap_port_of_scheme() */
    if (strncasecmp(url, "http:", 5) == 0) {
        url += 5;
        scheme = "http";
    }
    else if (strncasecmp(url, "https:", 6) == 0) {
        url += 6;
        scheme = "https";
    }
    else {
        return DECLINED;
    }
    def_port = apr_uri_port_of_scheme(scheme);

    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
             "proxy: HTTP: canonicalising URL %s", url);

    /* do syntatic check.
     * We break the URL into host, port, path, search
     */
    port = def_port;
    err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
    if (err) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                      "error parsing URL %s: %s",
                      url, err);
        return HTTP_BAD_REQUEST;
    }

    /* now parse path/search args, according to rfc1738 */
    /* N.B. if this isn't a true proxy request, then the URL _path_
     * has already been decoded.  True proxy requests have r->uri
     * == r->unparsed_uri, and no others have that property.
     */
    if (r->uri == r->unparsed_uri) {
        search = strchr(url, '?');
        if (search != NULL)
            *(search++) = '\0';
    }
    else
        search = r->args;

    /* process path */
    path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, r->proxyreq);
    if (path == NULL)
        return HTTP_BAD_REQUEST;

    if (port != def_port)
        apr_snprintf(sport, sizeof(sport), ":%d", port);
    else
        sport[0] = '\0';

    if (ap_strchr_c(host, ':')) { /* if literal IPv6 address */
        host = apr_pstrcat(r->pool, "[", host, "]", NULL);
    }
    r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "://", host, sport, 
            "/", path, (search) ? "?" : "", (search) ? search : "", NULL);
    return OK;
}
 
static const char *ap_proxy_location_reverse_map(request_rec *r, proxy_server_conf *conf, const char *url)
{
    struct proxy_alias *ent;
    int i, l1, l2;
    char *u;

    /* XXX FIXME: Make sure this handled the ambiguous case of the :80
     * after the hostname */

    l1 = strlen(url);
    ent = (struct proxy_alias *)conf->raliases->elts;
    for (i = 0; i < conf->raliases->nelts; i++) {
        l2 = strlen(ent[i].real);
        if (l1 >= l2 && strncasecmp(ent[i].real, url, l2) == 0) {
            u = apr_pstrcat(r->pool, ent[i].fake, &url[l2], NULL);
            return ap_construct_url(r->pool, u, r);
        }
    }
    return url;
}
/* cookies are a bit trickier to match: we've got two substrings to worry
 * about, and we can't just find them with strstr 'cos of case.  Regexp
 * matching would be an easy fix, but for better consistency with all the
 * other matches we'll refrain and use apr_strmatch to find path=/domain=
 * and stick to plain strings for the config values.
 */
static const char *proxy_cookie_reverse_map(request_rec *r,
                          proxy_server_conf *conf, const char *str)
{
    struct proxy_alias *ent;
    size_t len = strlen(str);
    const char* newpath = NULL ;
    const char* newdomain = NULL ;
    const char* pathp ;
    const char* domainp ;
    const char* pathe = NULL;
    const char* domaine = NULL;
    size_t l1, l2, poffs = 0, doffs = 0 ;
    int i;
    int ddiff = 0 ;
    int pdiff = 0 ;
    char* ret ;

/* find the match and replacement, but save replacing until we've done
   both path and domain so we know the new strlen
*/
    if ( pathp = apr_strmatch(conf->cookie_path_str, str, len) , pathp ) {
        pathp += 5 ;
        poffs = pathp - str ;
        pathe = ap_strchr_c(pathp, ';') ;
        l1 = pathe ? (pathe-pathp) : strlen(pathp) ;
        pathe = pathp + l1 ;
        ent = (struct proxy_alias *)conf->cookie_paths->elts;
        for (i = 0; i < conf->cookie_paths->nelts; i++) {
            l2 = strlen(ent[i].fake);
            if (l1 >= l2 && strncmp(ent[i].fake, pathp, l2) == 0) {
                newpath = ent[i].real ;
                pdiff = strlen(newpath) - l1 ;
                break ;
            }
        }
    }
    if ( domainp = apr_strmatch(conf->cookie_domain_str, str, len) , domainp ) {
        domainp += 7 ;
        doffs = domainp - str ;
        domaine = ap_strchr_c(domainp, ';') ;
        l1 = domaine ? (domaine-domainp) : strlen(domainp) ;
        domaine = domainp + l1 ;
        ent = (struct proxy_alias *)conf->cookie_domains->elts;
        for (i = 0; i < conf->cookie_domains->nelts; i++) {
            l2 = strlen(ent[i].fake);
            if (l1 >= l2 && strncasecmp(ent[i].fake, domainp, l2) == 0) {
                newdomain = ent[i].real ;
                ddiff = strlen(newdomain) - l1 ;
                break ;
            }
        }
    }
    if ( newpath ) {
        ret = apr_palloc(r->pool, len+pdiff+ddiff+1) ;
        l1 = strlen(newpath) ;
        if ( newdomain ) {
            l2 = strlen(newdomain) ;
            if ( doffs > poffs ) {
                memcpy(ret, str, poffs) ;
                memcpy(ret+poffs, newpath, l1) ;
                memcpy(ret+poffs+l1, pathe, domainp-pathe) ;
                memcpy(ret+doffs+pdiff, newdomain, l2) ;
                strcpy(ret+doffs+pdiff+l2, domaine) ;
            } else {
                memcpy(ret, str, doffs) ;
                memcpy(ret+doffs, newdomain, l2) ;
                memcpy(ret+doffs+l2, domaine, pathp-domaine) ;
                memcpy(ret+poffs+ddiff, newpath, l1) ;
                strcpy(ret+poffs+ddiff+l1, pathe) ;
            }
        } else {
            memcpy(ret, str, poffs) ;
            memcpy(ret+poffs, newpath, l1) ;
            strcpy(ret+poffs+l1, pathe) ;
        }
    } else {
        if ( newdomain ) {
            ret = apr_palloc(r->pool, len+pdiff+ddiff+1) ;
            l2 = strlen(newdomain) ;
            memcpy(ret, str, doffs) ;
            memcpy(ret+doffs, newdomain, l2) ;
            strcpy(ret+doffs+l2, domaine) ;
        } else {
            ret = (char*) str ;        /* no change */
        }
    }
    return ret ;
}

/* Clear all connection-based headers from the incoming headers table */
static void ap_proxy_clear_connection(apr_pool_t *p, apr_table_t *headers)
{
    const char *name;
    char *next = apr_pstrdup(p, apr_table_get(headers, "Connection"));

    apr_table_unset(headers, "Proxy-Connection");
    if (!next)
        return;

    while (*next) {
        name = next;
        while (*next && !apr_isspace(*next) && (*next != ',')) {
            ++next;
        }
        while (*next && (apr_isspace(*next) || (*next == ','))) {
            *next = '\0';
            ++next;
        }
        apr_table_unset(headers, name);
    }
    apr_table_unset(headers, "Connection");
}

static
apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r,
                                   proxy_conn_rec *conn, conn_rec *origin, 
                                   proxy_server_conf *conf,
                                   apr_uri_t *uri,
                                   char *url, char *server_portstr)
{
    conn_rec *c = r->connection;
    char *buf;
    apr_bucket *e, *last_header_bucket = NULL;
    const apr_array_header_t *headers_in_array;
    const apr_table_entry_t *headers_in;
    int counter, seen_eos, send_chunks;
    apr_status_t status;
    apr_bucket_brigade *header_brigade, *body_brigade, *input_brigade;

    header_brigade = apr_brigade_create(p, origin->bucket_alloc);
    body_brigade = apr_brigade_create(p, origin->bucket_alloc);
    input_brigade = apr_brigade_create(p, origin->bucket_alloc);

    /*
     * Send the HTTP/1.1 request to the remote server
     */

    /* strip connection listed hop-by-hop headers from the request */
    /* even though in theory a connection: close coming from the client
     * should not affect the connection to the server, it's unlikely
     * that subsequent client requests will hit this thread/process, so
     * we cancel server keepalive if the client does.
     */
    conn->close += ap_proxy_liststr(apr_table_get(r->headers_in,
                                                  "Connection"), "close");

    /* sub-requests never use keepalives */
    if (r->main) {
        conn->close++;
    }

    ap_proxy_clear_connection(p, r->headers_in);
    if (conn->close) {
        apr_table_setn(r->headers_in, "Connection", "close");
        origin->keepalive = AP_CONN_CLOSE;
    }

    /* By default, we can not send chunks. That means we must buffer
     * the entire request before sending it along to ensure we have
     * the correct Content-Length attached.
     */
    send_chunks = 0;

    if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) {
        buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.0" CRLF, NULL);
    } else {
        buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.1" CRLF, NULL);
        if (apr_table_get(r->subprocess_env, "proxy-sendchunks")) {
            send_chunks = 1;
        }
    }
    if (apr_table_get(r->subprocess_env, "proxy-nokeepalive")) {
        apr_table_unset(r->headers_in, "Connection");
        origin->keepalive = AP_CONN_CLOSE;
    }
    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);
    if (conf->preserve_host == 0) {
        if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
            buf = apr_pstrcat(p, "Host: ", uri->hostname, ":", uri->port_str,
                              CRLF, NULL);
        } else {
            buf = apr_pstrcat(p, "Host: ", uri->hostname, CRLF, NULL);
        }
    } 

⌨️ 快捷键说明

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