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

📄 http_filters.c

📁 Apache官方在今天放出产品系列2.2的最新版本2.2.11的源码包 最流行的HTTP服务器软件之一
💻 C
📖 第 1 页 / 共 4 页
字号:
            ctx->eos_sent = 1;            return APR_SUCCESS;        case BODY_CHUNK:        case BODY_CHUNK_PART:            {                apr_brigade_cleanup(bb);                /* We need to read the CRLF after the chunk.  */                if (ctx->state == BODY_CHUNK) {                    rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE,                                        block, 0);                    if (block == APR_NONBLOCK_READ &&                        ( (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb)) ||                          (APR_STATUS_IS_EAGAIN(rv)) )) {                        return APR_EAGAIN;                    }                    /* If we get an error, then leave */                    if (rv != APR_SUCCESS) {                        return rv;                    }                    /*                     * We really don't care whats on this line. If it is RFC                     * compliant it should be only \r\n. If there is more                     * before we just ignore it as long as we do not get over                     * the limit for request lines.                     */                    rv = get_remaining_chunk_line(ctx, bb,                                                  f->r->server->limit_req_line);                    apr_brigade_cleanup(bb);                    if (APR_STATUS_IS_EAGAIN(rv)) {                        return rv;                    }                } else {                    rv = APR_SUCCESS;                }                if (rv == APR_SUCCESS) {                    /* Read the real chunk line. */                    rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE,                                        block, 0);                    /* Test timeout */                    if (block == APR_NONBLOCK_READ &&                        ( (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb)) ||                          (APR_STATUS_IS_EAGAIN(rv)) )) {                        ctx->state = BODY_CHUNK_PART;                        return APR_EAGAIN;                    }                    ctx->state = BODY_CHUNK;                    if (rv == APR_SUCCESS) {                        rv = get_chunk_line(ctx, bb, f->r->server->limit_req_line);                        if (APR_STATUS_IS_EAGAIN(rv)) {                            ctx->state = BODY_CHUNK_PART;                            apr_brigade_cleanup(bb);                            return rv;                        }                        if (rv == APR_SUCCESS) {                            ctx->remaining = get_chunk_size(ctx->chunk_ln);                            if (ctx->remaining == INVALID_CHAR) {                                rv = APR_EGENERAL;                                http_error = HTTP_SERVICE_UNAVAILABLE;                            }                        }                    }                    apr_brigade_cleanup(bb);                }                /* Detect chunksize error (such as overflow) */                if (rv != APR_SUCCESS || ctx->remaining < 0) {                    ctx->remaining = 0; /* Reset it in case we have to                                         * come back here later */                    bail_out_on_error(ctx, f, http_error);                    return rv;                }                if (!ctx->remaining) {                    /* Handle trailers by calling ap_get_mime_headers again! */                    ctx->state = BODY_NONE;                    ap_get_mime_headers(f->r);                    e = apr_bucket_eos_create(f->c->bucket_alloc);                    APR_BRIGADE_INSERT_TAIL(b, e);                    ctx->eos_sent = 1;                    return APR_SUCCESS;                }            }            break;        }    }    /* Ensure that the caller can not go over our boundary point. */    if (ctx->state == BODY_LENGTH || ctx->state == BODY_CHUNK) {        if (ctx->remaining < readbytes) {            readbytes = ctx->remaining;        }        AP_DEBUG_ASSERT(readbytes > 0);    }    rv = ap_get_brigade(f->next, b, mode, block, readbytes);    if (rv != APR_SUCCESS) {        return rv;    }    /* How many bytes did we just read? */    apr_brigade_length(b, 0, &totalread);    /* If this happens, we have a bucket of unknown length.  Die because     * it means our assumptions have changed. */    AP_DEBUG_ASSERT(totalread >= 0);    if (ctx->state != BODY_NONE) {        ctx->remaining -= totalread;    }    /* If we have no more bytes remaining on a C-L request,     * save the callter a roundtrip to discover EOS.     */    if (ctx->state == BODY_LENGTH && ctx->remaining == 0) {        e = apr_bucket_eos_create(f->c->bucket_alloc);        APR_BRIGADE_INSERT_TAIL(b, e);    }    /* We have a limit in effect. */    if (ctx->limit) {        /* FIXME: Note that we might get slightly confused on chunked inputs         * as we'd need to compensate for the chunk lengths which may not         * really count.  This seems to be up for interpretation.  */        ctx->limit_used += totalread;        if (ctx->limit < ctx->limit_used) {            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,                          "Read content-length of %" APR_OFF_T_FMT                          " is larger than the configured limit"                          " of %" APR_OFF_T_FMT, ctx->limit_used, ctx->limit);            apr_brigade_cleanup(bb);            e = ap_bucket_error_create(HTTP_REQUEST_ENTITY_TOO_LARGE, NULL,                                       f->r->pool,                                       f->c->bucket_alloc);            APR_BRIGADE_INSERT_TAIL(bb, e);            e = apr_bucket_eos_create(f->c->bucket_alloc);            APR_BRIGADE_INSERT_TAIL(bb, e);            ctx->eos_sent = 1;            return ap_pass_brigade(f->r->output_filters, bb);        }    }    return APR_SUCCESS;}/** * Parse a chunk extension, detect overflow. * There are two error cases: *  1) If the conversion would require too many bits, a -1 is returned. *  2) If the conversion used the correct number of bits, but an overflow *     caused only the sign bit to flip, then that negative number is *     returned. * In general, any negative number can be considered an overflow error. */static long get_chunk_size(char *b){    long chunksize = 0;    size_t chunkbits = sizeof(long) * 8;    ap_xlate_proto_from_ascii(b, strlen(b));    if (!apr_isxdigit(*b)) {        /*         * Detect invalid character at beginning. This also works for empty         * chunk size lines.         */        return INVALID_CHAR;    }    /* Skip leading zeros */    while (*b == '0') {        ++b;    }    while (apr_isxdigit(*b) && (chunkbits > 0)) {        int xvalue = 0;        if (*b >= '0' && *b <= '9') {            xvalue = *b - '0';        }        else if (*b >= 'A' && *b <= 'F') {            xvalue = *b - 'A' + 0xa;        }        else if (*b >= 'a' && *b <= 'f') {            xvalue = *b - 'a' + 0xa;        }        chunksize = (chunksize << 4) | xvalue;        chunkbits -= 4;        ++b;    }    if (apr_isxdigit(*b) && (chunkbits <= 0)) {        /* overflow */        return -1;    }    return chunksize;}typedef struct header_struct {    apr_pool_t *pool;    apr_bucket_brigade *bb;} header_struct;/* Send a single HTTP header field to the client.  Note that this function * is used in calls to table_do(), so their interfaces are co-dependent. * In other words, don't change this one without checking table_do in alloc.c. * It returns true unless there was a write error of some kind. */static int form_header_field(header_struct *h,                             const char *fieldname, const char *fieldval){#if APR_CHARSET_EBCDIC    char *headfield;    apr_size_t len;    apr_size_t name_len;    apr_size_t val_len;    char *next;    name_len = strlen(fieldname);    val_len = strlen(fieldval);    len = name_len + val_len + 4; /* 4 for ": " plus CRLF */    headfield = (char *)apr_palloc(h->pool, len + 1);    memcpy(headfield, fieldname, name_len);    next = headfield + name_len;    *next++ = ':';    *next++ = ' ';    memcpy(next, fieldval, val_len);    next += val_len;    *next++ = CR;    *next++ = LF;    *next = 0;    ap_xlate_proto_to_ascii(headfield, len);    apr_brigade_write(h->bb, NULL, NULL, headfield, len);#else    struct iovec vec[4];    struct iovec *v = vec;    v->iov_base = (void *)fieldname;    v->iov_len = strlen(fieldname);    v++;    v->iov_base = ": ";    v->iov_len = sizeof(": ") - 1;    v++;    v->iov_base = (void *)fieldval;    v->iov_len = strlen(fieldval);    v++;    v->iov_base = CRLF;    v->iov_len = sizeof(CRLF) - 1;    apr_brigade_writev(h->bb, NULL, NULL, vec, 4);#endif /* !APR_CHARSET_EBCDIC */    return 1;}/* 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, ','));    }}/* Send a request's HTTP response headers to the client. */static apr_status_t send_all_header_fields(header_struct *h,                                           const request_rec *r){    const apr_array_header_t *elts;    const apr_table_entry_t *t_elt;    const apr_table_entry_t *t_end;    struct iovec *vec;    struct iovec *vec_next;    elts = apr_table_elts(r->headers_out);    if (elts->nelts == 0) {        return APR_SUCCESS;    }    t_elt = (const apr_table_entry_t *)(elts->elts);    t_end = t_elt + elts->nelts;    vec = (struct iovec *)apr_palloc(h->pool, 4 * elts->nelts *                                     sizeof(struct iovec));    vec_next = vec;    /* For each field, generate     *    name ": " value CRLF     */    do {        vec_next->iov_base = (void*)(t_elt->key);        vec_next->iov_len = strlen(t_elt->key);        vec_next++;        vec_next->iov_base = ": ";        vec_next->iov_len = sizeof(": ") - 1;        vec_next++;        vec_next->iov_base = (void*)(t_elt->val);        vec_next->iov_len = strlen(t_elt->val);        vec_next++;        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}/* Confirm that the status line is well-formed and matches r->status. * If they don't match, a filter may have negated the status line set by a * handler. * Zap r->status_line if bad. */static void validate_status_line(request_rec *r){    char *end;    if (r->status_line        && (strlen(r->status_line) <= 4            || apr_strtoi64(r->status_line, &end, 10) != r->status            || *end != ' '            || (end - 3) != r->status_line)) {        r->status_line = NULL;    }}/* * 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) {

⌨️ 快捷键说明

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