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

📄 mod_proxy_ajp.c

📁 Apache官方在今天放出产品系列2.2的最新版本2.2.11的源码包 最流行的HTTP服务器软件之一
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements.  See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. *//* AJP routines for Apache proxy */#include "mod_proxy.h"#include "ajp.h"module AP_MODULE_DECLARE_DATA proxy_ajp_module;/* * 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. */static int proxy_ajp_canon(request_rec *r, char *url){    char *host, *path, sport[7];    char *search = NULL;    const char *err;    apr_port_t port = AJP13_DEF_PORT;    /* ap_port_of_scheme() */    if (strncasecmp(url, "ajp:", 4) == 0) {        url += 4;    }    else {        return DECLINED;    }    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,             "proxy: AJP: canonicalising URL %s", url);    /*     * do syntactic check.     * We break the URL into host, port, path, search     */    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:     * process the path. With proxy-noncanon set (by     * mod_proxy) we use the raw, unparsed uri     */    if (apr_table_get(r->notes, "proxy-nocanon")) {        path = url;   /* this is the raw path */    }    else {        path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,                                 r->proxyreq);        search = r->args;    }    if (path == NULL)        return HTTP_BAD_REQUEST;    apr_snprintf(sport, sizeof(sport), ":%d", port);    if (ap_strchr_c(host, ':')) {        /* if literal IPv6 address */        host = apr_pstrcat(r->pool, "[", host, "]", NULL);    }    r->filename = apr_pstrcat(r->pool, "proxy:ajp://", host, sport,                              "/", path, (search) ? "?" : "",                              (search) ? search : "", NULL);    return OK;}#define METHOD_NON_IDEMPOTENT       0#define METHOD_IDEMPOTENT           1#define METHOD_IDEMPOTENT_WITH_ARGS 2static int is_idempotent(request_rec *r){    /*     * RFC2616 (9.1.2): GET, HEAD, PUT, DELETE, OPTIONS, TRACE are considered     * idempotent. Hint: HEAD requests use M_GET as method number as well.     */    switch (r->method_number) {        case M_GET:        case M_DELETE:        case M_PUT:        case M_OPTIONS:        case M_TRACE:            /*             * If the request has arguments it might have side-effects and thus             * it might be undesirable to resent it to a backend again             * automatically.             */            if (r->args) {                return METHOD_IDEMPOTENT_WITH_ARGS;            }            return METHOD_IDEMPOTENT;        /* Everything else is not considered idempotent. */        default:            return METHOD_NON_IDEMPOTENT;    }}static apr_off_t get_content_length(request_rec * r){    apr_off_t len = 0;    if (r->clength > 0) {        return r->clength;    }    else if (r->main == NULL) {        const char *clp = apr_table_get(r->headers_in, "Content-Length");        if (clp) {            char *errp;            if (apr_strtoff(&len, clp, &errp, 10) || *errp || len < 0) {                len = 0; /* parse error */            }        }    }    return len;}/* * XXX: AJP Auto Flushing * * When processing CMD_AJP13_SEND_BODY_CHUNK AJP messages we will do a poll * with FLUSH_WAIT miliseconds timeout to determine if more data is currently * available at the backend. If there is no more data available, we flush * the data to the client by adding a flush bucket to the brigade we pass * up the filter chain. * This is only a bandaid to fix the AJP/1.3 protocol shortcoming of not * sending (actually not having defined) a flush message, when the data * should be flushed to the client. As soon as this protocol shortcoming is * fixed this code should be removed. * * For further discussion see PR37100. * http://issues.apache.org/bugzilla/show_bug.cgi?id=37100 *//* * process the request and write the response. */static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,                                proxy_conn_rec *conn,                                conn_rec *origin,                                proxy_dir_conf *conf,                                apr_uri_t *uri,                                char *url, char *server_portstr){    apr_status_t status;    int result;    apr_bucket *e;    apr_bucket_brigade *input_brigade;    apr_bucket_brigade *output_brigade;    ajp_msg_t *msg;    apr_size_t bufsiz = 0;    char *buff;    char *send_body_chunk_buff;    apr_uint16_t size;    const char *tenc;    int havebody = 1;    int output_failed = 0;    int backend_failed = 0;    apr_off_t bb_len;    int data_sent = 0;    int headers_sent = 0;    int rv = 0;    apr_int32_t conn_poll_fd;    apr_pollfd_t *conn_poll;    proxy_server_conf *psf =    ap_get_module_config(r->server->module_config, &proxy_module);    apr_size_t maxsize = AJP_MSG_BUFFER_SZ;    int send_body = 0;    apr_off_t content_length = 0;    if (psf->io_buffer_size_set)       maxsize = psf->io_buffer_size;    if (maxsize > AJP_MAX_BUFFER_SZ)       maxsize = AJP_MAX_BUFFER_SZ;    else if (maxsize < AJP_MSG_BUFFER_SZ)       maxsize = AJP_MSG_BUFFER_SZ;    maxsize = APR_ALIGN(maxsize, 1024);           /*     * Send the AJP request to the remote server     */    /* send request headers */    status = ajp_send_header(conn->sock, r, maxsize, uri);    if (status != APR_SUCCESS) {        conn->close++;        ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,                     "proxy: AJP: request failed to %pI (%s)",                     conn->worker->cp->addr,                     conn->worker->hostname);        if (status == AJP_EOVERFLOW)            return HTTP_BAD_REQUEST;        else {            /*             * This is only non fatal when the method is idempotent. In this             * case we can dare to retry it with a different worker if we are             * a balancer member.             */            if (is_idempotent(r) == METHOD_IDEMPOTENT) {                return HTTP_SERVICE_UNAVAILABLE;            }            return HTTP_INTERNAL_SERVER_ERROR;        }    }    /* allocate an AJP message to store the data of the buckets */    bufsiz = maxsize;    status = ajp_alloc_data_msg(r->pool, &buff, &bufsiz, &msg);    if (status != APR_SUCCESS) {        /* We had a failure: Close connection to backend */        conn->close++;        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,                     "proxy: ajp_alloc_data_msg failed");        return HTTP_INTERNAL_SERVER_ERROR;    }    /* read the first bloc of data */    input_brigade = apr_brigade_create(p, r->connection->bucket_alloc);    tenc = apr_table_get(r->headers_in, "Transfer-Encoding");    if (tenc && (strcasecmp(tenc, "chunked") == 0)) {        /* The AJP protocol does not want body data yet */        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,                     "proxy: request is chunked");    } else {        /* Get client provided Content-Length header */        content_length = get_content_length(r);        status = ap_get_brigade(r->input_filters, input_brigade,                                AP_MODE_READBYTES, APR_BLOCK_READ,                                maxsize - AJP_HEADER_SZ);        if (status != APR_SUCCESS) {            /* We had a failure: Close connection to backend */            conn->close++;            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,                         "proxy: ap_get_brigade failed");            apr_brigade_destroy(input_brigade);            return HTTP_INTERNAL_SERVER_ERROR;        }        /* have something */        if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,                         "proxy: APR_BUCKET_IS_EOS");        }        /* Try to send something */        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,                     "proxy: data to read (max %" APR_SIZE_T_FMT                     " at %" APR_SIZE_T_FMT ")", bufsiz, msg->pos);        status = apr_brigade_flatten(input_brigade, buff, &bufsiz);        if (status != APR_SUCCESS) {            /* We had a failure: Close connection to backend */            conn->close++;            apr_brigade_destroy(input_brigade);            ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,                         "proxy: apr_brigade_flatten");            return HTTP_INTERNAL_SERVER_ERROR;        }        apr_brigade_cleanup(input_brigade);        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,                     "proxy: got %" APR_SIZE_T_FMT " bytes of data", bufsiz);        if (bufsiz > 0) {            status = ajp_send_data_msg(conn->sock, msg, bufsiz);            if (status != APR_SUCCESS) {                /* We had a failure: Close connection to backend */                conn->close++;                apr_brigade_destroy(input_brigade);                ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,                             "proxy: send failed to %pI (%s)",                             conn->worker->cp->addr,                             conn->worker->hostname);                /*                 * It is fatal when we failed to send a (part) of the request                 * body.                 */                return HTTP_INTERNAL_SERVER_ERROR;            }            conn->worker->s->transferred += bufsiz;            send_body = 1;        }        else if (content_length > 0) {            ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,                         "proxy: read zero bytes, expecting"                         " %" APR_OFF_T_FMT " bytes",                         content_length);            status = ajp_send_data_msg(conn->sock, msg, 0);            if (status != APR_SUCCESS) {                /* We had a failure: Close connection to backend */                conn->close++;                ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,                            "proxy: send failed to %pI (%s)",                            conn->worker->cp->addr,                            conn->worker->hostname);                return HTTP_INTERNAL_SERVER_ERROR;            }            else {                /* Client send zero bytes with C-L > 0                 */                return HTTP_BAD_REQUEST;            }        }    }    /* read the response */    conn->data = NULL;    status = ajp_read_header(conn->sock, r, maxsize,                             (ajp_msg_t **)&(conn->data));    if (status != APR_SUCCESS) {        /* We had a failure: Close connection to backend */        conn->close++;        apr_brigade_destroy(input_brigade);        ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,                     "proxy: read response failed from %pI (%s)",                     conn->worker->cp->addr,                     conn->worker->hostname);        /*         * This is only non fatal when we have not sent (parts) of a possible         * request body so far (we do not store it and thus cannot sent it         * again) and the method is idempotent. In this case we can dare to         * retry it with a different worker if we are a balancer member.         */        if (!send_body && (is_idempotent(r) == METHOD_IDEMPOTENT)) {            return HTTP_SERVICE_UNAVAILABLE;        }        return HTTP_INTERNAL_SERVER_ERROR;    }    /* parse the reponse */    result = ajp_parse_type(r, conn->data);    output_brigade = apr_brigade_create(p, r->connection->bucket_alloc);    /*     * Prepare apr_pollfd_t struct for possible later check if there is currently     * data available from the backend (do not flush response to client)

⌨️ 快捷键说明

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