From: William A. Rowe Jr Date: Mon, 29 Aug 2016 22:17:07 +0000 (+0000) Subject: New optional flag to enforce line delimiters in ap_[r]getline, X-Git-Tag: 2.5.0-alpha~1182 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=28163941ef93594a4e36b775aeaf007a67d92640;p=apache New optional flag to enforce line delimiters in ap_[r]getline, created by overloading 'int fold' (1 or 0) as 'int flags', with the same value 1 for AP_GETLINE_FOLD (which httpd doesn't use), and a new value 2 for AP_GETLINE_CRLF Enforce CRLF when HttpProtocolOptions Strict is in force. Correctly introduces a new t/TEST fail. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1758304 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/include/ap_mmn.h b/include/ap_mmn.h index e0b4a35939..aea8507f41 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -545,6 +545,7 @@ * 20160617.1 (2.5.0-dev) Added http_whitespace and http_methods to * core_server_config * 20160629.1 (2.5.0-dev) Dropped http_whitespace from core_server_config + * 20160629.2 (2.5.0-dev) Replaced fold w/multiple flags for ap_[r]getline() */ #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */ @@ -552,7 +553,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20160629 #endif -#define MODULE_MAGIC_NUMBER_MINOR 1 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 2 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/http_protocol.h b/include/http_protocol.h index 07fc6e9e47..77c9766b60 100644 --- a/include/http_protocol.h +++ b/include/http_protocol.h @@ -589,17 +589,22 @@ AP_DECLARE(int) ap_get_basic_auth_pw(request_rec *r, const char **pw); */ AP_CORE_DECLARE(void) ap_parse_uri(request_rec *r, const char *uri); +#define AP_GETLINE_FOLD 1 /* Whether to merge continuation lines */ +#define AP_GETLINE_CRLF 2 /*Whether line ends must be in the form CR LF */ + /** * Get the next line of input for the request * @param s The buffer into which to read the line * @param n The size of the buffer * @param r The request - * @param fold Whether to merge continuation lines + * @param flags Bit flag of multiple parsing options + * AP_GETLINE_FOLD Whether to merge continuation lines + * AP_GETLINE_CRLF Whether line ends must be in the form CR LF * @return The length of the line, if successful * n, if the line is too big to fit in the buffer * -1 for miscellaneous errors */ -AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int fold); +AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int flags); /** * Get the next line of input for the request @@ -617,7 +622,9 @@ AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int fold); * @param n The size of the buffer * @param read The length of the line. * @param r The request - * @param fold Whether to merge continuation lines + * @param flags Bit flag of multiple parsing options + * AP_GETLINE_FOLD Whether to merge continuation lines + * AP_GETLINE_CRLF Whether line ends must be in the form CR LF * @param bb Working brigade to use when reading buckets * @return APR_SUCCESS, if successful * APR_ENOSPC, if the line is too big to fit in the buffer @@ -626,7 +633,7 @@ AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int fold); #if APR_CHARSET_EBCDIC AP_DECLARE(apr_status_t) ap_rgetline(char **s, apr_size_t n, apr_size_t *read, - request_rec *r, int fold, + request_rec *r, int flags, apr_bucket_brigade *bb); #else /* ASCII box */ #define ap_rgetline(s, n, read, r, fold, bb) \ @@ -636,7 +643,7 @@ AP_DECLARE(apr_status_t) ap_rgetline(char **s, apr_size_t n, /** @see ap_rgetline */ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, apr_size_t *read, - request_rec *r, int fold, + request_rec *r, int flags, apr_bucket_brigade *bb); /** diff --git a/server/protocol.c b/server/protocol.c index 960d901ebd..875bcbba66 100644 --- a/server/protocol.c +++ b/server/protocol.c @@ -215,13 +215,15 @@ AP_DECLARE(apr_time_t) ap_rationalize_mtime(request_rec *r, apr_time_t mtime) */ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, apr_size_t *read, request_rec *r, - int fold, apr_bucket_brigade *bb) + int flags, apr_bucket_brigade *bb) { apr_status_t rv; apr_bucket *e; apr_size_t bytes_handled = 0, current_alloc = 0; char *pos, *last_char = *s; int do_alloc = (*s == NULL), saw_eos = 0; + int fold = flags & AP_GETLINE_FOLD; + int crlf = flags & AP_GETLINE_CRLF; /* * Initialize last_char as otherwise a random value will be compared @@ -327,6 +329,13 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, } } + if (last_char <= *s || last_char[-1] != APR_ASCII_CR) { + *last_char = '\0'; + bytes_handled = last_char - *s; + *read = bytes_handled; + return APR_EINVAL; + } + /* Now NUL-terminate the string at the end of the line; * if the last-but-one character is a CR, terminate there */ if (last_char > *s && last_char[-1] == APR_ASCII_CR) { @@ -471,7 +480,7 @@ AP_DECLARE(apr_status_t) ap_rgetline(char **s, apr_size_t n, } #endif -AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int fold) +AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int flags) { char *tmp_s = s; apr_status_t rv; @@ -479,7 +488,7 @@ AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int fold) apr_bucket_brigade *tmp_bb; tmp_bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); - rv = ap_rgetline(&tmp_s, n, &len, r, fold, tmp_bb); + rv = ap_rgetline(&tmp_s, n, &len, r, flags, tmp_bb); apr_brigade_destroy(tmp_bb); /* Map the out-of-space condition to the old API. */ @@ -607,7 +616,7 @@ static int read_request_line(request_rec *r, apr_bucket_brigade *bb) */ r->the_request = NULL; rv = ap_rgetline(&(r->the_request), (apr_size_t)(r->server->limit_req_line + 2), - &len, r, 0, bb); + &len, r, strict ? AP_GETLINE_CRLF : 0, bb); if (rv != APR_SUCCESS) { r->request_time = apr_time_now(); @@ -953,7 +962,7 @@ AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r, apr_bucket_brigade *bb field = NULL; rv = ap_rgetline(&field, r->server->limit_req_fieldsize + 2, - &len, r, 0, bb); + &len, r, strict ? AP_GETLINE_CRLF : 0, bb); if (rv != APR_SUCCESS) { if (APR_STATUS_IS_TIMEUP(rv)) {