📄 http_protocol.c
字号:
ctx->state = BODY_LENGTH; errno = 0; ctx->remaining = strtol(lenp, &endstr, 10); /* we depend on ANSI */ /* This protects us from over/underflow (the errno check), * non-digit chars in the string (excluding leading space) * (the endstr checks) and a negative number. Depending * on the strtol implementation, the errno check may also * trigger on an all whitespace string */ if (errno || (endstr && *endstr) || (ctx->remaining < 0)) { conversion_error = 1; } if (conversion_error) { apr_bucket_brigade *bb; ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, "Invalid Content-Length"); bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc); 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); } /* If we have a limit in effect and we know the C-L ahead of * time, stop it here if it is invalid. */ if (ctx->limit && ctx->limit < ctx->remaining) { apr_bucket_brigade *bb; ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, "Requested content-length of %" APR_OFF_T_FMT " is larger than the configured limit" " of %" APR_OFF_T_FMT, ctx->remaining, ctx->limit); bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc); 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); } } /* If we don't have a request entity indicated by the headers, EOS. * (BODY_NONE is a valid intermediate state due to trailers, * but it isn't a valid starting state.) * * RFC 2616 Section 4.4 note 5 states that connection-close * is invalid for a request entity - request bodies must be * denoted by C-L or T-E: chunked. * * Note that since the proxy uses this filter to handle the * proxied *response*, proxy responses MUST be exempt. */ if (ctx->state == BODY_NONE && f->r->proxyreq != PROXYREQ_RESPONSE) { e = apr_bucket_eos_create(f->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(b, e); ctx->eos_sent = 1; return APR_SUCCESS; } /* Since we're about to read data, send 100-Continue if needed. * Only valid on chunked and C-L bodies where the C-L is > 0. */ if ((ctx->state == BODY_CHUNK || (ctx->state == BODY_LENGTH && ctx->remaining > 0)) && f->r->expecting_100 && f->r->proto_num >= HTTP_VERSION(1,1)) { char *tmp; apr_bucket_brigade *bb; tmp = apr_pstrcat(f->r->pool, AP_SERVER_PROTOCOL, " ", status_lines[0], CRLF CRLF, NULL); bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc); e = apr_bucket_pool_create(tmp, strlen(tmp), f->r->pool, f->c->bucket_alloc); APR_BRIGADE_INSERT_HEAD(bb, e); e = apr_bucket_flush_create(f->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, e); ap_pass_brigade(f->c->output_filters, bb); } /* We can't read the chunk until after sending 100 if required. */ if (ctx->state == BODY_CHUNK) { char line[30]; apr_bucket_brigade *bb; apr_size_t len = 30; bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc); rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE, APR_BLOCK_READ, 0); if (rv == APR_SUCCESS) { rv = apr_brigade_flatten(bb, line, &len); if (rv == APR_SUCCESS) { ctx->remaining = get_chunk_size(line); } } 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 */ 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); } 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; } } } if (ctx->eos_sent) { e = apr_bucket_eos_create(f->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(b, e); return APR_SUCCESS; } if (!ctx->remaining) { switch (ctx->state) { case BODY_NONE: break; case BODY_LENGTH: e = apr_bucket_eos_create(f->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(b, e); ctx->eos_sent = 1; return APR_SUCCESS; case BODY_CHUNK: { char line[30]; apr_bucket_brigade *bb; apr_size_t len = 30; bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc); /* We need to read the CRLF after the chunk. */ rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE, APR_BLOCK_READ, 0); apr_brigade_cleanup(bb); if (rv == APR_SUCCESS) { /* Read the real chunk line. */ rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE, APR_BLOCK_READ, 0); if (rv == APR_SUCCESS) { rv = apr_brigade_flatten(bb, line, &len); if (rv == APR_SUCCESS) { ctx->remaining = get_chunk_size(line); } } 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 */ 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); } 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) { apr_bucket_brigade *bb; 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); bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc); 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;}/* The index is found by its offset from the x00 code of each level. * Although this is fast, it will need to be replaced if some nutcase * decides to define a high-numbered code before the lower numbers. * If that sad event occurs, replace the code below with a linear search * from status_lines[shortcut[i]] to status_lines[shortcut[i+1]-1]; */AP_DECLARE(int) ap_index_of_response(int status){ static int shortcut[6] = {0, LEVEL_200, LEVEL_300, LEVEL_400, LEVEL_500, RESPONSE_CODES}; int i, pos; if (status < 100) { /* Below 100 is illegal for HTTP status */ return LEVEL_500; } for (i = 0; i < 5; i++) { status -= 100; if (status < 100) { pos = (status + shortcut[i]); if (pos < shortcut[i + 1]) { return pos; } else { return LEVEL_500; /* status unknown (falls in gap) */ } } } return LEVEL_500; /* 600 or above is also illegal */}AP_DECLARE(const char *) ap_get_status_line(int status){ return status_lines[ap_index_of_response(status)];}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;}/* 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++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -