Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12:Update
apache2.6987
httpd-2.4.10-chunk_header_parsing_defect.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File httpd-2.4.10-chunk_header_parsing_defect.patch of Package apache2.6987
diff -urN httpd-2.4.10/modules/http/http_filters.c ../apache2/httpd-2.4.10/modules/http/http_filters.c --- httpd-2.4.10/modules/http/http_filters.c 2015-08-06 16:23:17.654915151 +0200 +++ ../apache2/httpd-2.4.10/modules/http/http_filters.c 2015-08-06 16:25:51.454481331 +0200 @@ -57,24 +57,29 @@ APLOG_USE_MODULE(http); -#define INVALID_CHAR -2 - -static long get_chunk_size(char *); - -typedef struct http_filter_ctx { +typedef struct http_filter_ctx +{ apr_off_t remaining; apr_off_t limit; apr_off_t limit_used; - enum { - BODY_NONE, - BODY_LENGTH, - BODY_CHUNK, - BODY_CHUNK_PART + apr_int32_t chunk_used; + apr_int32_t chunk_bws; + apr_int32_t chunkbits; + enum + { + BODY_NONE, /* streamed data */ + BODY_LENGTH, /* data constrained by content length */ + BODY_CHUNK, /* chunk expected */ + BODY_CHUNK_PART, /* chunk digits */ + BODY_CHUNK_EXT, /* chunk extension */ + BODY_CHUNK_CR, /* got space(s) after digits, expect [CR]LF or ext */ + BODY_CHUNK_LF, /* got CR after digits or ext, expect LF */ + BODY_CHUNK_DATA, /* data constrained by chunked encoding */ + BODY_CHUNK_END, /* chunked data terminating CRLF */ + BODY_CHUNK_END_LF, /* got CR after data, expect LF */ + BODY_CHUNK_TRAILER /* trailers */ } state; - int eos_sent; - char chunk_ln[32]; - char *pos; - apr_off_t linesize; + unsigned int eos_sent :1; apr_bucket_brigade *bb; } http_ctx_t; @@ -119,117 +124,154 @@ return ap_pass_brigade(f->r->output_filters, bb); } -static apr_status_t get_remaining_chunk_line(http_ctx_t *ctx, - apr_bucket_brigade *b, - int linelimit) +/** + * Parse a chunk line with optional extension, detect overflow. + * There are two error cases: + * 1) If the conversion would require too many bits, APR_EGENERAL is returned. + * 2) If the conversion used the correct number of bits, but an overflow + * caused only the sign bit to flip, then APR_ENOSPC is returned. + * In general, any negative number can be considered an overflow error. + */ +static apr_status_t parse_chunk_size(http_ctx_t *ctx, const char *buffer, + apr_size_t len, int linelimit) { - apr_status_t rv; - apr_off_t brigade_length; - apr_bucket *e; - const char *lineend; - apr_size_t len = 0; + apr_size_t i = 0; - /* - * As the brigade b should have been requested in mode AP_MODE_GETLINE - * all buckets in this brigade are already some type of memory - * buckets (due to the needed scanning for LF in mode AP_MODE_GETLINE) - * or META buckets. - */ - rv = apr_brigade_length(b, 0, &brigade_length); - if (rv != APR_SUCCESS) { - return rv; - } - /* Sanity check. Should never happen. See above. */ - if (brigade_length == -1) { - return APR_EGENERAL; - } - if (!brigade_length) { - return APR_EAGAIN; - } - ctx->linesize += brigade_length; - if (ctx->linesize > linelimit) { - return APR_ENOSPC; - } - /* - * As all buckets are already some type of memory buckets or META buckets - * (see above), we only need to check the last byte in the last data bucket. - */ - for (e = APR_BRIGADE_LAST(b); - e != APR_BRIGADE_SENTINEL(b); - e = APR_BUCKET_PREV(e)) { + while (i < len) { + char c = buffer[i]; - if (APR_BUCKET_IS_METADATA(e)) { + ap_xlate_proto_from_ascii(&c, 1); + + /* handle CRLF after the chunk */ + if (ctx->state == BODY_CHUNK_END + || ctx->state == BODY_CHUNK_END_LF) { + if (c == LF) { + ctx->state = BODY_CHUNK; + } + else if (c == CR && ctx->state == BODY_CHUNK_END) { + ctx->state = BODY_CHUNK_END_LF; + } + else { + /* + * LF expected. + */ + return APR_EINVAL; + } + i++; continue; } - rv = apr_bucket_read(e, &lineend, &len, APR_BLOCK_READ); - if (rv != APR_SUCCESS) { - return rv; + + /* handle start of the chunk */ + if (ctx->state == BODY_CHUNK) { + if (!apr_isxdigit(c)) { + /* + * Detect invalid character at beginning. This also works for + * empty chunk size lines. + */ + return APR_EINVAL; + } + else { + ctx->state = BODY_CHUNK_PART; + } + ctx->remaining = 0; + ctx->chunkbits = sizeof(apr_off_t) * 8; + ctx->chunk_used = 0; + ctx->chunk_bws = 0; } - if (len > 0) { - break; /* we got the data we want */ + + if (c == LF) { + if (ctx->remaining) { + ctx->state = BODY_CHUNK_DATA; + } + else { + ctx->state = BODY_CHUNK_TRAILER; + } } - /* If we got a zero-length data bucket, we try the next one */ - } - /* We had no data in this brigade */ - if (!len || e == APR_BRIGADE_SENTINEL(b)) { - return APR_EAGAIN; - } - if (lineend[len - 1] != APR_ASCII_LF) { - return APR_EAGAIN; - } - /* Line is complete. So reset ctx for next round. */ - ctx->linesize = 0; - ctx->pos = ctx->chunk_ln; - return APR_SUCCESS; -} + else if (ctx->state == BODY_CHUNK_LF) { + /* + * LF expected. + */ + return APR_EINVAL; + } + else if (c == CR) { + ctx->state = BODY_CHUNK_LF; + } + else if (c == ';') { + ctx->state = BODY_CHUNK_EXT; + } + else if (ctx->state == BODY_CHUNK_EXT) { + /* + * Control chars (but tabs) are invalid. + */ + if (c != '\t' && apr_iscntrl(c)) { + return APR_EINVAL; + } + } + else if (c == ' ' || c == '\t') { + /* Be lenient up to 10 BWS (term from rfc7230 - 3.2.3). + */ + ctx->state = BODY_CHUNK_CR; + if (++ctx->chunk_bws > 10) { + return APR_EINVAL; + } + } + else if (ctx->state == BODY_CHUNK_CR) { + /* + * ';', CR or LF expected. + */ + return APR_EINVAL; + } + else if (ctx->state == BODY_CHUNK_PART) { + int xvalue; -static apr_status_t get_chunk_line(http_ctx_t *ctx, apr_bucket_brigade *b, - int linelimit) -{ - apr_size_t len; - int tmp_len; - apr_status_t rv; + /* ignore leading zeros */ + if (!ctx->remaining && c == '0') { + i++; + continue; + } - tmp_len = sizeof(ctx->chunk_ln) - (ctx->pos - ctx->chunk_ln) - 1; - /* Saveguard ourselves against underflows */ - if (tmp_len < 0) { - len = 0; - } - else { - len = (apr_size_t) tmp_len; - } - /* - * Check if there is space left in ctx->chunk_ln. If not, then either - * the chunk size is insane or we have chunk-extensions. Ignore both - * by discarding the remaining part of the line via - * get_remaining_chunk_line. Only bail out if the line is too long. - */ - if (len > 0) { - rv = apr_brigade_flatten(b, ctx->pos, &len); - if (rv != APR_SUCCESS) { - return rv; - } - ctx->pos += len; - ctx->linesize += len; - *(ctx->pos) = '\0'; - /* - * Check if we really got a full line. If yes the - * last char in the just read buffer must be LF. - * If not advance the buffer and return APR_EAGAIN. - * We do not start processing until we have the - * full line. - */ - if (ctx->pos[-1] != APR_ASCII_LF) { - /* Check if the remaining data in the brigade has the LF */ - return get_remaining_chunk_line(ctx, b, linelimit); + ctx->chunkbits -= 4; + if (ctx->chunkbits < 0) { + /* overflow */ + return APR_ENOSPC; + } + + if (c >= '0' && c <= '9') { + xvalue = c - '0'; + } + else if (c >= 'A' && c <= 'F') { + xvalue = c - 'A' + 0xa; + } + else if (c >= 'a' && c <= 'f') { + xvalue = c - 'a' + 0xa; + } + else { + /* bogus character */ + return APR_EINVAL; + } + + ctx->remaining = (ctx->remaining << 4) | xvalue; + if (ctx->remaining < 0) { + /* overflow */ + return APR_ENOSPC; + } } - /* Line is complete. So reset ctx->pos for next round. */ - ctx->pos = ctx->chunk_ln; - return APR_SUCCESS; + else { + /* Should not happen */ + return APR_EGENERAL; + } + + i++; } - return get_remaining_chunk_line(ctx, b, linelimit); -} + /* sanity check */ + ctx->chunk_used += len; + if (ctx->chunk_used < 0 || ctx->chunk_used > linelimit) { + return APR_ENOSPC; + } + + return APR_SUCCESS; +} static apr_status_t read_chunked_trailers(http_ctx_t *ctx, ap_filter_t *f, apr_bucket_brigade *b, int merge) @@ -243,7 +285,6 @@ r->status = HTTP_OK; r->headers_in = r->trailers_in; apr_table_clear(r->headers_in); - ctx->state = BODY_NONE; ap_get_mime_headers(r); if(r->status == HTTP_OK) { @@ -287,9 +328,9 @@ apr_bucket *e; http_ctx_t *ctx = f->ctx; apr_status_t rv; - apr_off_t totalread; int http_error = HTTP_REQUEST_ENTITY_TOO_LARGE; apr_bucket_brigade *bb; + int again; conf = (core_server_config *) ap_get_module_config(f->r->server->module_config, &core_module); @@ -303,7 +344,6 @@ const char *tenc, *lenp; f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx)); ctx->state = BODY_NONE; - ctx->pos = ctx->chunk_ln; ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc); bb = ctx->bb; @@ -335,14 +375,17 @@ * reading the connection until it is closed by the server." */ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(02555) - "Unknown Transfer-Encoding: %s;" - " using read-until-close", tenc); + "Unknown Transfer-Encoding: %s; " + "using read-until-close", tenc); tenc = NULL; } else { + /* Something that isn't a HTTP request, unless some future + * edition defines new transfer encodings, is unsupported. + */ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(01585) "Unknown Transfer-Encoding: %s", tenc); - return bail_out_on_error(ctx, f, HTTP_NOT_IMPLEMENTED); + return bail_out_on_error(ctx, f, HTTP_BAD_REQUEST); } lenp = NULL; } @@ -361,7 +404,7 @@ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(01587) "Invalid Content-Length"); - return bail_out_on_error(ctx, f, HTTP_REQUEST_ENTITY_TOO_LARGE); + return bail_out_on_error(ctx, f, HTTP_BAD_REQUEST); } /* If we have a limit in effect and we know the C-L ahead of @@ -403,7 +446,8 @@ if (!ap_is_HTTP_SUCCESS(f->r->status)) { ctx->state = BODY_NONE; ctx->eos_sent = 1; - } else { + } + else { char *tmp; int len; @@ -426,285 +470,199 @@ 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) { - apr_brigade_cleanup(bb); + /* sanity check in case we're read twice */ + if (ctx->eos_sent) { + e = apr_bucket_eos_create(f->c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(b, e); + return APR_SUCCESS; + } + + do { + apr_brigade_cleanup(b); + again = 0; /* until further notice */ + + /* read and handle the brigade */ + switch (ctx->state) { + case BODY_CHUNK: + case BODY_CHUNK_PART: + case BODY_CHUNK_EXT: + case BODY_CHUNK_CR: + case BODY_CHUNK_LF: + case BODY_CHUNK_END: + case BODY_CHUNK_END_LF: { - rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE, - block, 0); + rv = ap_get_brigade(f->next, b, AP_MODE_GETLINE, block, 0); /* for timeout */ - if (block == APR_NONBLOCK_READ && - ( (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb)) || - (APR_STATUS_IS_EAGAIN(rv)) )) { - ctx->state = BODY_CHUNK_PART; + if (block == APR_NONBLOCK_READ + && ((rv == APR_SUCCESS && APR_BRIGADE_EMPTY(b)) + || (APR_STATUS_IS_EAGAIN(rv)))) { return APR_EAGAIN; } - if (rv == APR_SUCCESS) { - rv = get_chunk_line(ctx, bb, f->r->server->limit_req_line); - if (APR_STATUS_IS_EAGAIN(rv)) { - apr_brigade_cleanup(bb); - ctx->state = BODY_CHUNK_PART; - 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_BAD_REQUEST; - } - } + if (rv == APR_EOF) { + return APR_INCOMPLETE; } - apr_brigade_cleanup(bb); - /* Detect chunksize error (such as overflow) */ - if (rv != APR_SUCCESS || ctx->remaining < 0) { - ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, f->r, APLOGNO(01589) "Error reading first chunk %s ", - (ctx->remaining < 0) ? "(overflow)" : ""); - if (APR_STATUS_IS_TIMEUP(rv) || ctx->remaining > 0) { - http_error = HTTP_REQUEST_TIME_OUT; - } - ctx->remaining = 0; /* Reset it in case we have to - * come back here later */ - return bail_out_on_error(ctx, f, http_error); + if (rv != APR_SUCCESS) { + return rv; } - if (!ctx->remaining) { - return read_chunked_trailers(ctx, f, b, - conf->merge_trailers == AP_MERGE_TRAILERS_ENABLE); - } - } - } - else { - bb = ctx->bb; - } + e = APR_BRIGADE_FIRST(b); + while (e != APR_BRIGADE_SENTINEL(b)) { + const char *buffer; + apr_size_t len; - if (ctx->eos_sent) { - e = apr_bucket_eos_create(f->c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(b, e); - return APR_SUCCESS; - } + if (!APR_BUCKET_IS_METADATA(e)) { + int parsing = 0; - 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: - case BODY_CHUNK_PART: - { - apr_brigade_cleanup(bb); + rv = apr_bucket_read(e, &buffer, &len, APR_BLOCK_READ); - /* 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_EOF) { - return APR_INCOMPLETE; + if (rv == APR_SUCCESS) { + parsing = 1; + rv = parse_chunk_size(ctx, buffer, len, + f->r->server->limit_req_fieldsize); } 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; + ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, f->r, APLOGNO(01590) + "Error reading/parsing chunk %s ", + (APR_ENOSPC == rv) ? "(overflow)" : ""); + if (parsing) { + if (rv != APR_ENOSPC) { http_error = HTTP_BAD_REQUEST; } + return bail_out_on_error(ctx, f, http_error); } + return rv; } - apr_brigade_cleanup(bb); } - /* Detect chunksize error (such as overflow) */ - if (rv != APR_SUCCESS || ctx->remaining < 0) { - ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, f->r, APLOGNO(01590) "Error reading chunk %s ", - (ctx->remaining < 0) ? "(overflow)" : ""); - if (APR_STATUS_IS_TIMEUP(rv) || ctx->remaining > 0) { - http_error = HTTP_REQUEST_TIME_OUT; - } - ctx->remaining = 0; /* Reset it in case we have to - * come back here later */ - return bail_out_on_error(ctx, f, http_error); - } + apr_bucket_delete(e); + e = APR_BRIGADE_FIRST(b); + } + again = 1; /* come around again */ - if (!ctx->remaining) { - return read_chunked_trailers(ctx, f, b, + if (ctx->state == BODY_CHUNK_TRAILER) { + /* Treat UNSET as DISABLE - trailers aren't merged by default */ + return read_chunked_trailers(ctx, f, b, conf->merge_trailers == AP_MERGE_TRAILERS_ENABLE); - } } + break; } - } + case BODY_NONE: + case BODY_LENGTH: + case BODY_CHUNK_DATA: { - /* 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); - } + /* Ensure that the caller can not go over our boundary point. */ + if (ctx->state != BODY_NONE && ctx->remaining < readbytes) { + readbytes = ctx->remaining; + } + if (readbytes > 0) { + apr_off_t totalread; + + rv = ap_get_brigade(f->next, b, mode, block, readbytes); + + /* for timeout */ + if (block == APR_NONBLOCK_READ + && ((rv == APR_SUCCESS && APR_BRIGADE_EMPTY(b)) + || (APR_STATUS_IS_EAGAIN(rv)))) { + return APR_EAGAIN; + } - rv = ap_get_brigade(f->next, b, mode, block, readbytes); + if (rv == APR_EOF && ctx->state != BODY_NONE + && ctx->remaining > 0) { + return APR_INCOMPLETE; + } - if (rv == APR_EOF && ctx->state != BODY_NONE && - ctx->remaining > 0) { - return APR_INCOMPLETE; - } - if (rv != APR_SUCCESS) { - return rv; - } + if (rv != APR_SUCCESS) { + return rv; + } - /* How many bytes did we just read? */ - apr_brigade_length(b, 0, &totalread); + /* 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 (ctx->remaining > 0) { - e = APR_BRIGADE_LAST(b); - if (APR_BUCKET_IS_EOS(e)) { - apr_bucket_delete(e); - return APR_INCOMPLETE; + /* 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 (ctx->remaining > 0) { + e = APR_BRIGADE_LAST(b); + if (APR_BUCKET_IS_EOS(e)) { + apr_bucket_delete(e); + return APR_INCOMPLETE; + } + } + else if (ctx->state == BODY_CHUNK_DATA) { + /* next chunk please */ + ctx->state = BODY_CHUNK_END; + ctx->chunk_used = 0; + } + } + + /* 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_INFO, 0, f->r, + APLOGNO(01591) "Read content length of " + "%" APR_OFF_T_FMT " is larger than the " + "configured limit of %" APR_OFF_T_FMT, + ctx->limit_used, ctx->limit); + return bail_out_on_error(ctx, f, + HTTP_REQUEST_ENTITY_TOO_LARGE); + } + } } - } - } - /* 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); - } + /* If we have no more bytes remaining on a C-L request, + * save the caller a round trip 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); + ctx->eos_sent = 1; + } - /* 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_INFO, 0, f->r, APLOGNO(01591) - "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); + break; } - } - - 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; + case BODY_CHUNK_TRAILER: { - ap_xlate_proto_from_ascii(b, strlen(b)); + rv = ap_get_brigade(f->next, b, mode, block, readbytes); - 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; - } + /* for timeout */ + if (block == APR_NONBLOCK_READ + && ((rv == APR_SUCCESS && APR_BRIGADE_EMPTY(b)) + || (APR_STATUS_IS_EAGAIN(rv)))) { + return APR_EAGAIN; + } - while (apr_isxdigit(*b) && (chunkbits > 0)) { - int xvalue = 0; + if (rv != APR_SUCCESS) { + return rv; + } - if (*b >= '0' && *b <= '9') { - xvalue = *b - '0'; + break; } - else if (*b >= 'A' && *b <= 'F') { - xvalue = *b - 'A' + 0xa; + default: { + /* Should not happen */ + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(02901) + "Unexpected body state (%i)", (int)ctx->state); + return APR_EGENERAL; } - else if (*b >= 'a' && *b <= 'f') { - xvalue = *b - 'a' + 0xa; } - chunksize = (chunksize << 4) | xvalue; - chunkbits -= 4; - ++b; - } - if (apr_isxdigit(*b)) { - /* overflow */ - return -1; - } + } while (again); - return chunksize; + return APR_SUCCESS; } typedef struct header_struct {
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor