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

📄 http_protocol.c

📁 Apache HTTP Server 是一个功能强大的灵活的与HTTP/1.1相兼容的web服务器.这里给出的是Apache HTTP服务器的源码。
💻 C
📖 第 1 页 / 共 5 页
字号:
        vec_next->iov_base = CRLF;        vec_next->iov_len = sizeof(CRLF) - 1;        vec_next++;        t_elt++;    } while (t_elt < t_end);#if APR_CHARSET_EBCDIC    {        apr_size_t len;        char *tmp = apr_pstrcatv(r->pool, vec, vec_next - vec, &len);        ap_xlate_proto_to_ascii(tmp, len);        return apr_brigade_write(h->bb, NULL, NULL, tmp, len);    }#else    return apr_brigade_writev(h->bb, NULL, NULL, vec, vec_next - vec);#endif}/* * Determine the protocol to use for the response. Potentially downgrade * to HTTP/1.0 in some situations and/or turn off keepalives. * * also prepare r->status_line. */static void basic_http_header_check(request_rec *r,                                    const char **protocol){    if (r->assbackwards) {        /* no such thing as a response protocol */        return;    }    if (!r->status_line) {        r->status_line = status_lines[ap_index_of_response(r->status)];    }    /* Note that we must downgrade before checking for force responses. */    if (r->proto_num > HTTP_VERSION(1,0)        && apr_table_get(r->subprocess_env, "downgrade-1.0")) {        r->proto_num = HTTP_VERSION(1,0);    }    /* kludge around broken browsers when indicated by force-response-1.0     */    if (r->proto_num == HTTP_VERSION(1,0)        && apr_table_get(r->subprocess_env, "force-response-1.0")) {        *protocol = "HTTP/1.0";        r->connection->keepalive = AP_CONN_CLOSE;    }    else {        *protocol = AP_SERVER_PROTOCOL;    }}/* fill "bb" with a barebones/initial HTTP response header */static void basic_http_header(request_rec *r, apr_bucket_brigade *bb,                              const char *protocol){    char *date;    const char *server;    header_struct h;    struct iovec vec[4];    if (r->assbackwards) {        /* there are no headers to send */        return;    }    /* Output the HTTP/1.x Status-Line and the Date and Server fields */    vec[0].iov_base = (void *)protocol;    vec[0].iov_len  = strlen(protocol);    vec[1].iov_base = (void *)" ";    vec[1].iov_len  = sizeof(" ") - 1;    vec[2].iov_base = (void *)(r->status_line);    vec[2].iov_len  = strlen(r->status_line);    vec[3].iov_base = (void *)CRLF;    vec[3].iov_len  = sizeof(CRLF) - 1;#if APR_CHARSET_EBCDIC    {        char *tmp;        apr_size_t len;        tmp = apr_pstrcatv(r->pool, vec, 4, &len);        ap_xlate_proto_to_ascii(tmp, len);        apr_brigade_write(bb, NULL, NULL, tmp, len);    }#else    apr_brigade_writev(bb, NULL, NULL, vec, 4);#endif    date = apr_palloc(r->pool, APR_RFC822_DATE_LEN);    ap_recent_rfc822_date(date, r->request_time);    h.pool = r->pool;    h.bb = bb;    form_header_field(&h, "Date", date);    /* keep the set-by-proxy server header, otherwise     * generate a new server header */    if (r->proxyreq != PROXYREQ_NONE) {        server = apr_table_get(r->headers_out, "Server");        if (server) {            form_header_field(&h, "Server", server);        }    }    else {        form_header_field(&h, "Server", ap_get_server_version());    }    /* unset so we don't send them again */    apr_table_unset(r->headers_out, "Date");        /* Avoid bogosity */    apr_table_unset(r->headers_out, "Server");}AP_DECLARE(void) ap_basic_http_header(request_rec *r, apr_bucket_brigade *bb){    const char *protocol;    basic_http_header_check(r, &protocol);    basic_http_header(r, bb, protocol);}/* Navigator versions 2.x, 3.x and 4.0 betas up to and including 4.0b2 * have a header parsing bug.  If the terminating \r\n occur starting * at offset 256, 257 or 258 of output then it will not properly parse * the headers.  Curiously it doesn't exhibit this problem at 512, 513. * We are guessing that this is because their initial read of a new request * uses a 256 byte buffer, and subsequent reads use a larger buffer. * So the problem might exist at different offsets as well. * * This should also work on keepalive connections assuming they use the * same small buffer for the first read of each new request. * * At any rate, we check the bytes written so far and, if we are about to * tickle the bug, we instead insert a bogus padding header.  Since the bug * manifests as a broken image in Navigator, users blame the server.  :( * It is more expensive to check the User-Agent than it is to just add the * bytes, so we haven't used the BrowserMatch feature here. */static void terminate_header(apr_bucket_brigade *bb){    char tmp[] = "X-Pad: avoid browser bug" CRLF;    char crlf[] = CRLF;    apr_off_t len;    apr_size_t buflen;    (void) apr_brigade_length(bb, 1, &len);    if (len >= 255 && len <= 257) {        buflen = strlen(tmp);        ap_xlate_proto_to_ascii(tmp, buflen);        apr_brigade_write(bb, NULL, NULL, tmp, buflen);    }    buflen = strlen(crlf);    ap_xlate_proto_to_ascii(crlf, buflen);    apr_brigade_write(bb, NULL, NULL, crlf, buflen);}/* Build the Allow field-value from the request handler method mask. * Note that we always allow TRACE, since it is handled below. */static char *make_allow(request_rec *r){    char *list;    apr_int64_t mask;    apr_array_header_t *allow = apr_array_make(r->pool, 10, sizeof(char *));    apr_hash_index_t *hi = apr_hash_first(r->pool, methods_registry);    mask = r->allowed_methods->method_mask;    for (; hi; hi = apr_hash_next(hi)) {        const void *key;        void *val;        apr_hash_this(hi, &key, NULL, &val);        if ((mask & (AP_METHOD_BIT << *(int *)val)) != 0) {            *(const char **)apr_array_push(allow) = key;            /* the M_GET method actually refers to two methods */            if (*(int *)val == M_GET)                *(const char **)apr_array_push(allow) = "HEAD";        }    }    /* TRACE is always allowed */    *(const char **)apr_array_push(allow) = "TRACE";    list = apr_array_pstrcat(r->pool, allow, ',');    /* ### this is rather annoying. we should enforce registration of       ### these methods */    if ((mask & (AP_METHOD_BIT << M_INVALID))        && (r->allowed_methods->method_list != NULL)        && (r->allowed_methods->method_list->nelts != 0)) {        int i;        char **xmethod = (char **) r->allowed_methods->method_list->elts;        /*         * Append all of the elements of r->allowed_methods->method_list         */        for (i = 0; i < r->allowed_methods->method_list->nelts; ++i) {            list = apr_pstrcat(r->pool, list, ",", xmethod[i], NULL);        }    }    return list;}AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r){    int rv;    apr_bucket_brigade *b;    header_struct h;    if (r->method_number != M_TRACE) {        return DECLINED;    }    /* Get the original request */    while (r->prev) {        r = r->prev;    }    if ((rv = ap_setup_client_block(r, REQUEST_NO_BODY))) {        return rv;    }    ap_set_content_type(r, "message/http");    /* Now we recreate the request, and echo it back */    b = apr_brigade_create(r->pool, r->connection->bucket_alloc);    apr_brigade_putstrs(b, NULL, NULL, r->the_request, CRLF, NULL);    h.pool = r->pool;    h.bb = b;    apr_table_do((int (*) (void *, const char *, const char *))                 form_header_field, (void *) &h, r->headers_in, NULL);    apr_brigade_puts(b, NULL, NULL, CRLF);    ap_pass_brigade(r->output_filters, b);    return DONE;}AP_DECLARE(int) ap_send_http_options(request_rec *r){    if (r->assbackwards) {        return DECLINED;    }    apr_table_setn(r->headers_out, "Allow", make_allow(r));    /* the request finalization will send an EOS, which will flush all     * the headers out (including the Allow header)     */    return OK;}/* This routine is called by apr_table_do and merges all instances of * the passed field values into a single array that will be further * processed by some later routine.  Originally intended to help split * and recombine multiple Vary fields, though it is generic to any field * consisting of comma/space-separated tokens. */static int uniq_field_values(void *d, const char *key, const char *val){    apr_array_header_t *values;    char *start;    char *e;    char **strpp;    int  i;    values = (apr_array_header_t *)d;    e = apr_pstrdup(values->pool, val);    do {        /* Find a non-empty fieldname */        while (*e == ',' || apr_isspace(*e)) {            ++e;        }        if (*e == '\0') {            break;        }        start = e;        while (*e != '\0' && *e != ',' && !apr_isspace(*e)) {            ++e;        }        if (*e != '\0') {            *e++ = '\0';        }        /* Now add it to values if it isn't already represented.         * Could be replaced by a ap_array_strcasecmp() if we had one.         */        for (i = 0, strpp = (char **) values->elts; i < values->nelts;             ++i, ++strpp) {            if (*strpp && strcasecmp(*strpp, start) == 0) {                break;            }        }        if (i == values->nelts) {  /* if not found */            *(char **)apr_array_push(values) = start;        }    } while (*e != '\0');    return 1;}/* * Since some clients choke violently on multiple Vary fields, or * Vary fields with duplicate tokens, combine any multiples and remove * any duplicates. */static void fixup_vary(request_rec *r){    apr_array_header_t *varies;    varies = apr_array_make(r->pool, 5, sizeof(char *));    /* Extract all Vary fields from the headers_out, separate each into     * its comma-separated fieldname values, and then add them to varies     * if not already present in the array.     */    apr_table_do((int (*)(void *, const char *, const char *))uniq_field_values,                 (void *) varies, r->headers_out, "Vary", NULL);    /* If we found any, replace old Vary fields with unique-ified value */    if (varies->nelts > 0) {        apr_table_setn(r->headers_out, "Vary",                       apr_array_pstrcat(r->pool, varies, ','));    }}AP_DECLARE(void) ap_set_content_type(request_rec *r, const char *ct){    if (!ct) {        r->content_type = NULL;    }    else if (!r->content_type || strcmp(r->content_type, ct)) {        r->content_type = ct;        /* Insert filters requested by the AddOutputFiltersByType          * configuration directive. Content-type filters must be          * inserted after the content handlers have run because          * only then, do we reliably know the content-type.         */        ap_add_output_filters_by_type(r);    }}typedef struct header_filter_ctx {    int headers_sent;} header_filter_ctx;AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,                                                           apr_bucket_brigade *b){    request_rec *r = f->r;    conn_rec *c = r->connection;    const char *clheader;    const char *protocol;    apr_bucket *e;    apr_bucket_brigade *b2;    header_struct h;    header_filter_ctx *ctx = f->ctx;    AP_DEBUG_ASSERT(!r->main);    if (r->header_only) {        if (!ctx) {            ctx = f->ctx = apr_pcalloc(r->pool, sizeof(header_filter_ctx));        }        else if (ctx->headers_sent) {            apr_brigade_destroy(b);            return OK;        }    }    APR_BRIGADE_FOREACH(e, b) {        if (e->type == &ap_bucket_type_error) {            ap_bucket_error *eb = e->data;

⌨️ 快捷键说明

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