Mercurial > dovecot > core-2.2
changeset 17549:9511372c7c18
lib-http: Updated comments to RFC7230/RFC7231.
author | Stephan Bosch <stephan@rename-it.nl> |
---|---|
date | Wed, 02 Jul 2014 00:10:16 +0300 |
parents | 3e0e4dd7fb65 |
children | 1278fed4f2c9 |
files | src/lib-http/http-client-connection.c src/lib-http/http-client-request.c src/lib-http/http-client.c src/lib-http/http-date.c src/lib-http/http-header-parser.c src/lib-http/http-message-parser.c src/lib-http/http-parser.c src/lib-http/http-parser.h src/lib-http/http-request-parser.c src/lib-http/http-response-parser.c src/lib-http/http-transfer-chunked.c src/lib-http/http-url.c |
diffstat | 12 files changed, 236 insertions(+), 234 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-http/http-client-connection.c Tue Jul 01 23:24:08 2014 +0300 +++ b/src/lib-http/http-client-connection.c Wed Jul 02 00:10:16 2014 +0300 @@ -308,16 +308,14 @@ if (req->connect_tunnel) conn->tunneling = TRUE; - /* https://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-21; - Section 6.1.2.1: + /* RFC 7231, Section 5.1.1: Expect - Because of the presence of older implementations, the protocol allows - ambiguous situations in which a client might send "Expect: 100-continue" - without receiving either a 417 (Expectation Failed) or a 100 (Continue) - status code. Therefore, when a client sends this header field to an - origin server (possibly via a proxy) from which it has never seen a 100 - (Continue) status code, the client SHOULD NOT wait for an indefinite - period before sending the payload body. + o A client that sends a 100-continue expectation is not required to + wait for any specific length of time; such a client MAY proceed to + send the message body even if it has not yet received a response. + Furthermore, since 100 (Continue) responses cannot be sent through + an HTTP/1.0 intermediary, such a client SHOULD NOT wait for an + indefinite period before sending the message body. */ if (req->payload_sync && !conn->peer->seen_100_response) { i_assert(req->payload_chunked || req->payload_size > 0); @@ -551,13 +549,11 @@ if (conn->to_response != NULL) timeout_remove(&conn->to_response); - /* https://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-21 - Section 7.2: + /* RFC 7231, Section 6.2: - A client MUST be prepared to accept one or more 1xx status responses - prior to a regular response, even if the client does not expect a 100 - (Continue) status message. Unexpected 1xx status responses MAY be - ignored by a user agent. + A client MUST be able to parse one or more 1xx responses received + prior to a final response, even if the client does not expect one. A + user agent MAY ignore unexpected 1xx responses. */ if (req->payload_sync && response.status == 100) { if (conn->payload_continue) {
--- a/src/lib-http/http-client-request.c Tue Jul 01 23:24:08 2014 +0300 +++ b/src/lib-http/http-client-request.c Wed Jul 02 00:10:16 2014 +0300 @@ -350,16 +350,18 @@ enum http_response_payload_type http_client_request_get_payload_type(struct http_client_request *req) { - /* https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23 - Section 3.3: + /* RFC 7230, Section 3.3: - The presence of a message body in a response depends on both the - request method to which it is responding and the response status code. - Responses to the HEAD request method never include a message body - because the associated response header fields, if present, indicate only - what their values would have been if the request method had been GET - 2xx (Successful) responses to CONNECT switch to tunnel mode instead of - having a message body (Section 4.3.6 of [Part2]). + The presence of a message body in a response depends on both the + request method to which it is responding and the response status code + (Section 3.1.2 of [RFC7230]). Responses to the HEAD request method + (Section 4.3.2 of [RFC7231]) never include a message body because the + associated response header fields (e.g., Transfer-Encoding, + Content-Length, etc.), if present, indicate only what their values + would have been if the request method had been GET (Section 4.3.1 of + [RFC7231]). 2xx (Successful) responses to a CONNECT request method + (Section 4.3.6 of [RFC7231]) switch to tunnel mode instead of having a + message body. */ if (strcmp(req->method, "HEAD") == 0) return HTTP_RESPONSE_PAYLOAD_TYPE_NOT_PRESENT; @@ -933,8 +935,7 @@ req->label = p_strdup_printf(req->pool, "[%s %s%s]", req->method, origin_url, req->target); - /* https://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-21 - Section-7.4.4 + /* RFC 7231, Section 6.4.4: -> A 303 `See Other' redirect status response is handled a bit differently. Basically, the response content is located elsewhere, but the original
--- a/src/lib-http/http-client.c Tue Jul 01 23:24:08 2014 +0300 +++ b/src/lib-http/http-client.c Wed Jul 02 00:10:16 2014 +0300 @@ -54,7 +54,7 @@ http-client-connection: This is an actual connection to a server. Once a connection is ready to - handle requests, it claims a request from a host object. One connection can + handle requests, it claims a request from a queue object. One connection can service multiple hosts and one host can have multiple associated connections, possibly to different ips and ports.
--- a/src/lib-http/http-date.c Tue Jul 01 23:24:08 2014 +0300 +++ b/src/lib-http/http-date.c Wed Jul 02 00:10:16 2014 +0300 @@ -7,75 +7,65 @@ #include <ctype.h> -/* - Official specification is still RFC261, Section 3.3, but we anticipate - HTTPbis and use the draft Part 2, Section 5.1 as reference for our - parser: - - http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-20#section-5.1 +/* RFC 7231, Section 7.1.1.1: Date/Time Formats The defined syntax is as follows: - HTTP-date = rfc1123-date / obs-date + HTTP-date = IMF-fixdate / obs-date Preferred format: - rfc1123-date = day-name "," SP date1 SP time-of-day SP GMT - ; fixed length subset of the format defined in - ; Section 5.2.14 of [RFC1123] - day-name = %x4D.6F.6E ; "Mon", case-sensitive - / %x54.75.65 ; "Tue", case-sensitive - / %x57.65.64 ; "Wed", case-sensitive - / %x54.68.75 ; "Thu", case-sensitive - / %x46.72.69 ; "Fri", case-sensitive - / %x53.61.74 ; "Sat", case-sensitive - / %x53.75.6E ; "Sun", case-sensitive - date1 = day SP month SP year - ; e.g., 02 Jun 1982 - day = 2DIGIT - month = %x4A.61.6E ; "Jan", case-sensitive + IMF-fixdate = day-name "," SP date1 SP time-of-day SP GMT + ; fixed length/zone/capitalization subset of the format + ; see Section 3.3 of [RFC5322] + day-name = %x4D.6F.6E ; "Mon", case-sensitive + / %x54.75.65 ; "Tue", case-sensitive + / %x57.65.64 ; "Wed", case-sensitive + / %x54.68.75 ; "Thu", case-sensitive + / %x46.72.69 ; "Fri", case-sensitive + / %x53.61.74 ; "Sat", case-sensitive + / %x53.75.6E ; "Sun", case-sensitive + date1 = day SP month SP year + ; e.g., 02 Jun 1982 + day = 2DIGIT + month = %x4A.61.6E ; "Jan", case-sensitive / %x46.65.62 ; "Feb", case-sensitive - / %x4D.61.72 ; "Mar", case-sensitive - / %x41.70.72 ; "Apr", case-sensitive - / %x4D.61.79 ; "May", case-sensitive - / %x4A.75.6E ; "Jun", case-sensitive - / %x4A.75.6C ; "Jul", case-sensitive - / %x41.75.67 ; "Aug", case-sensitive - / %x53.65.70 ; "Sep", case-sensitive - / %x4F.63.74 ; "Oct", case-sensitive - / %x4E.6F.76 ; "Nov", case-sensitive - / %x44.65.63 ; "Dec", case-sensitive - year = 4DIGIT - GMT = %x47.4D.54 ; "GMT", case-sensitive - time-of-day = hour ":" minute ":" second - ; 00:00:00 - 23:59:59 - hour = 2DIGIT - minute = 2DIGIT - second = 2DIGIT - - The semantics of day-name, day, month, year, and time-of-day are the - same as those defined for the RFC 5322 constructs with the - corresponding name ([RFC5322], Section 3.3). + / %x4D.61.72 ; "Mar", case-sensitive + / %x41.70.72 ; "Apr", case-sensitive + / %x4D.61.79 ; "May", case-sensitive + / %x4A.75.6E ; "Jun", case-sensitive + / %x4A.75.6C ; "Jul", case-sensitive + / %x41.75.67 ; "Aug", case-sensitive + / %x53.65.70 ; "Sep", case-sensitive + / %x4F.63.74 ; "Oct", case-sensitive + / %x4E.6F.76 ; "Nov", case-sensitive + / %x44.65.63 ; "Dec", case-sensitive + year = 4DIGIT + GMT = %x47.4D.54 ; "GMT", case-sensitive + time-of-day = hour ":" minute ":" second + ; 00:00:00 - 23:59:60 (leap second) + hour = 2DIGIT + minute = 2DIGIT + second = 2DIGIT Obsolete formats: - obs-date = rfc850-date / asctime-date + obs-date = rfc850-date / asctime-date - rfc850-date = day-name-l "," SP date2 SP time-of-day SP GMT - date2 = day "-" month "-" 2DIGIT - ; day-month-year (e.g., 02-Jun-82) - day-name-l = %x4D.6F.6E.64.61.79 ; "Monday", case-sensitive - / %x54.75.65.73.64.61.79 ; "Tuesday", case-sensitive - / %x57.65.64.6E.65.73.64.61.79 ; "Wednesday", case-sensitive - / %x54.68.75.72.73.64.61.79 ; "Thursday", case-sensitive - / %x46.72.69.64.61.79 ; "Friday", case-sensitive - / %x53.61.74.75.72.64.61.79 ; "Saturday", case-sensitive - / %x53.75.6E.64.61.79 ; "Sunday", case-sensitive + rfc850-date = day-name-l "," SP date2 SP time-of-day SP GMT + date2 = day "-" month "-" 2DIGIT + ; e.g., 02-Jun-82 + day-name-l = %x4D.6F.6E.64.61.79 ; "Monday", case-sensitive + / %x54.75.65.73.64.61.79 ; "Tuesday", case-sensitive + / %x57.65.64.6E.65.73.64.61.79 ; "Wednesday", case-sensitive + / %x54.68.75.72.73.64.61.79 ; "Thursday", case-sensitive + / %x46.72.69.64.61.79 ; "Friday", case-sensitive + / %x53.61.74.75.72.64.61.79 ; "Saturday", case-sensitive + / %x53.75.6E.64.61.79 ; "Sunday", case-sensitive - asctime-date = day-name SP date3 SP time-of-day SP year - date3 = month SP ( 2DIGIT / ( SP 1DIGIT )) - ; month day (e.g., Jun 2) - + asctime-date = day-name SP date3 SP time-of-day SP year + date3 = month SP ( 2DIGIT / ( SP 1DIGIT )) + ; e.g., Jun 2 */ static const char *month_names[] = { @@ -257,14 +247,14 @@ } static int -http_date_parse_format_rfc1123(struct http_date_parser *parser) +http_date_parse_format_imf_fixdate(struct http_date_parser *parser) { /* - rfc1123-date = day-name "," SP date1 SP time-of-day SP GMT - ; fixed length subset of the format defined in - ; Section 5.2.14 of [RFC1123] + IMF-fixdate = day-name "," SP date1 SP time-of-day SP GMT + ; fixed length/zone/capitalization subset of the format + ; see Section 3.3 of [RFC5322] date1 = day SP month SP year - ; e.g., 02 Jun 1982 + ; e.g., 02 Jun 1982 Remaining: {...} SP day SP month SP year SP time-of-day SP GMT @@ -390,10 +380,10 @@ int i; /* - HTTP-date = rfc1123-date / obs-date - rfc1123-date = day-name "," SP date1 SP time-of-day SP GMT - ; fixed length subset of the format defined in - ; Section 5.2.14 of [RFC1123] + HTTP-date = IMF-fixdate / obs-date + IMF-fixdate = day-name "," SP date1 SP time-of-day SP GMT + ; fixed length/zone/capitalization subset of the format + ; see Section 3.3 of [RFC5322] obs-date = rfc850-date / asctime-date rfc850-date = day-name-l "," SP date2 SP time-of-day SP GMT asctime-date = day-name SP date3 SP time-of-day SP year @@ -414,7 +404,7 @@ return http_date_parse_format_rfc850(parser); } - /* rfc1123-date / asctime-date */ + /* IMF-fixdate / asctime-date */ for (i = 0; i < 7; i++) { if (strcmp(weekday_names[i], str_c(dayname)) == 0) { break; @@ -433,9 +423,9 @@ if (parser->cur[0] != ',') return -1; - /* rfc1123-date */ + /* IMF-fixdate */ parser->cur++; - return http_date_parse_format_rfc1123(parser); + return http_date_parse_format_imf_fixdate(parser); } bool http_date_parse(const unsigned char *data, size_t size,
--- a/src/lib-http/http-header-parser.c Tue Jul 01 23:24:08 2014 +0300 +++ b/src/lib-http/http-header-parser.c Wed Jul 02 00:10:16 2014 +0300 @@ -120,7 +120,8 @@ { const unsigned char *first; - /* field-content = *( HTAB / SP / VCHAR / obs-text ) + /* field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] + field-vchar = VCHAR / obs-text */ do { first = parser->cur; @@ -156,14 +157,19 @@ { int ret; - /* 'header' = *( header-field CRLF ) CRLF + /* RFC 7230, Section 3.2: Header Fields + + 'header' = *( header-field CRLF ) CRLF + ; Actually part of HTTP-message syntax + header-field = field-name ":" OWS field-value OWS field-name = token field-value = *( field-content / obs-fold ) - field-content = *( HTAB / SP / VCHAR / obs-text ) - obs-fold = CRLF ( SP / HTAB ) + field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] + field-vchar = VCHAR / obs-text + obs-fold = CRLF 1*( SP / HTAB ) ; obsolete line folding - ; see Section 3.2.2 + ; see Section 3.2.4 */ for (;;) {
--- a/src/lib-http/http-message-parser.c Tue Jul 01 23:24:08 2014 +0300 +++ b/src/lib-http/http-message-parser.c Wed Jul 02 00:10:16 2014 +0300 @@ -68,7 +68,9 @@ parser->error_code = HTTP_MESSAGE_PARSE_ERROR_NONE; parser->error = NULL; - /* HTTP-version = HTTP-name "/" DIGIT "." DIGIT + /* RFC 7230, Section 2.6: Protocol Versioning + + HTTP-version = HTTP-name "/" DIGIT "." DIGIT HTTP-name = %x48.54.54.50 ; "HTTP", case-sensitive */ if (size < 8) @@ -127,8 +129,7 @@ hdr = http_header_field_add(parser->msg.header, name, data, size); - /* https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23 - Section 3.2.2: + /* RFC 7230, Section 3.2.2: Field Order A sender MUST NOT generate multiple header fields with the same field name in a message unless either the entire field value for that @@ -144,11 +145,13 @@ const char *option; unsigned int num_tokens = 0; - /* Multiple Connection headers are allowed and combined into one */ + /* RFC 7230, Section 6.1: Connection - /* Connection = 1#connection-option - connection-option = token + Connection = 1#connection-option + connection-option = token */ + + /* Multiple Connection headers are allowed and combined into one */ http_parser_init(&hparser, data, size); for (;;) { if (http_parse_token_list_next(&hparser, &option) <= 0) @@ -175,7 +178,11 @@ parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE; return -1; } - /* Content-Length = 1*DIGIT */ + + /* RFC 7230, Section 3.3.2: Content-Length + + Content-Length = 1*DIGIT + */ if (str_to_uoff(hdr->value, &parser->msg.content_length) < 0) { parser->error= "Invalid Content-Length header"; parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE; @@ -186,6 +193,7 @@ } break; case 'D': case 'd': + /* Date: */ if (strcasecmp(name, "Date") == 0) { if (parser->msg.date != (time_t)-1) { parser->error = "Duplicate Date header"; @@ -193,15 +201,24 @@ return -1; } - /* Date = HTTP-date */ + /* RFC 7231, Section 7.1.1.2: Date + + Date = HTTP-date + */ (void)http_date_parse(data, size, &parser->msg.date); return 0; } break; case 'L': case 'l': + /* Location: */ if (strcasecmp(name, "Location") == 0) { + /* RFC 7231, Section 7.1.2: Location + + Location = URI-reference + + -> not parsed here + */ /* FIXME: move this to response parser */ - /* Location = URI-reference (not parsed here) */ parser->msg.location = hdr->value; return 0; } @@ -215,14 +232,20 @@ if (!array_is_created(&parser->msg.transfer_encoding)) p_array_init(&parser->msg.transfer_encoding, parser->msg.pool, 4); - /* Transfer-Encoding = 1#transfer-coding - transfer-coding = "chunked" / "compress" / "deflate" / "gzip" - / transfer-extension - transfer-extension = token *( OWS ";" OWS transfer-parameter ) - transfer-parameter = attribute BWS "=" BWS value - attribute = token - value = word - */ + /* RFC 7230, Section 3.3.1: Transfer-Encoding + + Transfer-Encoding = 1#transfer-coding + + RFC 7230, Section 4: Transfer Codings + + transfer-coding = "chunked" ; RFC 7230, Section 4.1 + / "compress" ; RFC 7230, Section 4.2.1 + / "deflate" ; RFC 7230, Section 4.2.2 + / "gzip" ; RFC 7230, Section 4.2.3 + / transfer-extension + transfer-extension = token *( OWS ";" OWS transfer-parameter ) + transfer-parameter = token BWS "=" BWS ( token / quoted-string ) + */ http_parser_init(&hparser, data, size); for (;;) { /* transfer-coding */ @@ -261,8 +284,8 @@ hparser.cur++; http_parse_ows(&hparser); - /* value */ - if (http_parse_word(&hparser, &value) <= 0) { + /* token / quoted-string */ + if (http_parse_token_or_qstring(&hparser, &value) <= 0) { parse_error = TRUE; break; } @@ -277,12 +300,15 @@ break; } else { - /* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23 - Appendix B: + /* RFC 7230, Section 7: ABNF List Extension: #rule - For compatibility with legacy list rules, recipients SHOULD accept - empty list elements. + For compatibility with legacy list rules, a recipient MUST parse + and ignore a reasonable number of empty list elements: enough to + handle common mistakes by senders that merge values, but not so + much that they could be used as a denial-of-service mechanism. */ + // FIXME: limit allowed number of empty list elements + // FIXME: handle invalid transfer encoding } http_parse_ows(&hparser); if (hparser.cur >= hparser.end || *hparser.cur != ',') @@ -399,42 +425,41 @@ parser->payload = http_transfer_chunked_istream_create (parser->input, parser->max_payload_size); } else if (!request) { - /* https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23 - Section 3.3.3.: + /* RFC 7230, Section 3.3.3: Message Body Length - If a Transfer-Encoding header field is present in a response and - the chunked transfer coding is not the final encoding, the - message body length is determined by reading the connection until - it is closed by the server. + If a Transfer-Encoding header field is present in a response and + the chunked transfer coding is not the final encoding, the + message body length is determined by reading the connection until + it is closed by the server. */ /* FIXME: enforce max payload size (relevant to http-client only) */ parser->payload = i_stream_create_limit(parser->input, (size_t)-1); } else { - /* https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23 - Section 3.3.3.: + /* RFC 7230, Section 3.3.3: Message Body Length - If a Transfer-Encoding header field is present in a request and the - chunked transfer coding is not the final encoding, the message body - length cannot be determined reliably; the server MUST respond with - the 400 (Bad Request) status code and then close the connection. + If a Transfer-Encoding header field is present in a request and + the chunked transfer coding is not the final encoding, the + message body length cannot be determined reliably; the server + MUST respond with the 400 (Bad Request) status code and then + close the connection. */ parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE; parser->error = "Final Transfer-Encoding in request is not chunked"; return -1; } - /* https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23 - Section 3.3.3.: + /* RFC 7230, Section 3.3.3: Message Body Length - If a message is received with both a Transfer-Encoding and a - Content-Length header field, the Transfer-Encoding overrides the - Content-Length. Such a message might indicate an attempt to - perform request or response smuggling (bypass of security-related - checks on message routing or content) and thus ought to be - handled as an error. A sender MUST remove the received Content- - Length field prior to forwarding such a message downstream. + If a message is received with both a Transfer-Encoding and a + Content-Length header field, the Transfer-Encoding overrides the + Content-Length. Such a message might indicate an attempt to + perform request smuggling (Section 9.5 of [RFC7230]) or response + splitting (Section 9.4 of [RFC7230]) and ought to be handled as + an error. A sender MUST remove the received Content-Length field + prior to forwarding such a message downstream. */ + // FIXME: make this an error? if (parser->msg.have_content_length) http_header_field_delete(parser->msg.header, "Content-Length"); @@ -451,17 +476,18 @@ i_stream_create_limit(parser->input, parser->msg.content_length); } else if (!parser->msg.have_content_length && !request) { - /* https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23 - Section 3.3.3.: + /* RFC 7230, Section 3.3.3: Message Body Length - If this is a request message and none of the above are true, then - the message body length is zero (no message body is present). + 6. If this is a request message and none of the above are true, then + the message body length is zero (no message body is present). - Otherwise, this is a response message without a declared message - body length, so the message body length is determined by the - number of octets received prior to the server closing the connection. + 7. Otherwise, this is a response message without a declared message + body length, so the message body length is determined by the + number of octets received prior to the server closing the + connection */ - /* FIXME: enforce max payload size (relevant to http-client only) */ + // FIXME: enforce max payload size (relevant to http-client only) + // FIXME: handle request case correctly. parser->payload = i_stream_create_limit(parser->input, (size_t)-1); }
--- a/src/lib-http/http-parser.c Tue Jul 01 23:24:08 2014 +0300 +++ b/src/lib-http/http-parser.c Wed Jul 02 00:10:16 2014 +0300 @@ -186,7 +186,8 @@ return 1; } -int http_parse_word(struct http_parser *parser, const char **word_r) +int http_parse_token_or_qstring(struct http_parser *parser, + const char **word_r) { if (parser->cur >= parser->end) return 0;
--- a/src/lib-http/http-parser.h Tue Jul 01 23:24:08 2014 +0300 +++ b/src/lib-http/http-parser.h Wed Jul 02 00:10:16 2014 +0300 @@ -51,6 +51,7 @@ const char **token_r); int http_parse_quoted_string(struct http_parser *parser, const char **str_r); -int http_parse_word(struct http_parser *parser, const char **word_r); +int http_parse_token_or_qstring(struct http_parser *parser, + const char **word_r); #endif
--- a/src/lib-http/http-request-parser.c Tue Jul 01 23:24:08 2014 +0300 +++ b/src/lib-http/http-request-parser.c Wed Jul 02 00:10:16 2014 +0300 @@ -158,9 +158,11 @@ struct http_message_parser *_parser = &parser->parser; int ret; - /* request-line = method SP request-target SP HTTP-version CRLF + /* RFC 7230, Section 3.1.1: Request Line + + request-line = method SP request-target SP HTTP-version CRLF + method = token */ - for (;;) { switch (parser->state) { case HTTP_REQUEST_PARSE_STATE_INIT: @@ -345,13 +347,11 @@ bool parse_error = FALSE; unsigned int num_expectations = 0; - /* Expect = 1#expectation - expectation = expect-name [ BWS "=" BWS expect-value ] - *( OWS ";" [ OWS expect-param ] ) - expect-param = expect-name [ BWS "=" BWS expect-value ] - expect-name = token - expect-value = token / quoted-string + /* RFC 7231, Section 5.1.1: + + Expect = "100-continue" */ + // FIXME: simplify; RFC 7231 discarded Expect extension mechanism http_parser_init(&hparser, (const unsigned char *)hdr->value, hdr->size); while (!parse_error) { const char *expect_name, *expect_value; @@ -362,18 +362,6 @@ if (strcasecmp(expect_name, "100-continue") == 0) { request->expect_100_continue = TRUE; } else { - /* http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-23 - Section 5.1.1: - - If all received Expect header field(s) are syntactically valid but - contain an expectation that the recipient does not understand or - cannot comply with, the recipient MUST respond with a 417 - (Expectation Failed) status code. A recipient of a syntactically - invalid Expectation header field MUST respond with a 4xx status code - other than 417. - - --> Must check rest of expect header syntax before returning error. - */ if (parser->error_code == HTTP_REQUEST_PARSE_ERROR_NONE) { parser->error_code = HTTP_REQUEST_PARSE_ERROR_EXPECTATION_FAILED; _parser->error = t_strdup_printf @@ -391,7 +379,7 @@ http_parse_ows(&hparser); /* value */ - if (http_parse_word(&hparser, &expect_value) <= 0) { + if (http_parse_token_or_qstring(&hparser, &expect_value) <= 0) { parse_error = TRUE; break; } @@ -430,7 +418,7 @@ http_parse_ows(&hparser); /* value */ - if (http_parse_word(&hparser, &value) <= 0) { + if (http_parse_token_or_qstring(&hparser, &value) <= 0) { parse_error = TRUE; break; } @@ -480,6 +468,7 @@ array_foreach(hdrs, hdr) { int ret = 0; + /* Expect: */ if (http_header_field_is(hdr, "Expect")) ret = http_request_parse_expect_header(parser, request, hdr); @@ -510,7 +499,9 @@ return ret; } - /* HTTP-message = start-line + /* RFC 7230, Section 3: + + HTTP-message = start-line *( header-field CRLF ) CRLF [ message-body ] @@ -548,8 +539,7 @@ } parser->state = HTTP_REQUEST_PARSE_STATE_INIT; - /* https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23 - Section 5.4: + /* RFC 7230, Section 5.4: Host A server MUST respond with a 400 (Bad Request) status code to any HTTP/1.1 request message that lacks a Host header field and to any
--- a/src/lib-http/http-response-parser.c Tue Jul 01 23:24:08 2014 +0300 +++ b/src/lib-http/http-response-parser.c Wed Jul 02 00:10:16 2014 +0300 @@ -108,11 +108,12 @@ struct http_message_parser *_parser = &parser->parser; int ret; - /* status-line = HTTP-version SP status-code SP reason-phrase CRLF + /* RFC 7230, Section 3.1.2: Status Line + + status-line = HTTP-version SP status-code SP reason-phrase CRLF status-code = 3DIGIT reason-phrase = *( HTAB / SP / VCHAR / obs-text ) */ - switch (parser->state) { case HTTP_RESPONSE_PARSE_STATE_INIT: http_response_parser_restart(parser); @@ -239,16 +240,17 @@ { time_t delta; - /* http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-23 - Section 7.1.3: + /* RFC 7231, Section 7.1.3: Retry-After + + The value of this field can be either an HTTP-date or a number of + seconds to delay after the response is received. - The value of this field can be either an HTTP-date or an integer - number of seconds (in decimal) after the time of the response. - Time spans are non-negative decimal integers, representing time in - seconds. + Retry-After = HTTP-date / delta-seconds - Retry-After = HTTP-date / delta-seconds - delta-seconds = 1*DIGIT + A delay-seconds value is a non-negative decimal integer, representing + time in seconds. + + delta-seconds = 1*DIGIT */ if (str_to_time(hdrval, &delta) >= 0) { if (resp_time == (time_t)-1) { @@ -277,7 +279,9 @@ return ret; } - /* HTTP-message = start-line + /* RFC 7230, Section 3: + + HTTP-message = start-line *( header-field CRLF ) CRLF [ message-body ] @@ -293,11 +297,10 @@ return ret; } - /* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-21 - Section 3.3.2: + /* RFC 7230, Section 3.3.2: Content-Length A server MUST NOT send a Content-Length header field in any response - with a status code of 1xx (Informational) or 204 (No Content). [...] + with a status code of 1xx (Informational) or 204 (No Content). */ if ((parser->response_status / 100 == 1 || parser->response_status == 204) && parser->parser.msg.content_length > 0) { @@ -308,14 +311,13 @@ return -1; } - /* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-21 - Section 3.3.3: + /* RFC 7230, Section 3.3.3: Message Body Length - Any response to a HEAD request and any response with a 1xx - (Informational), 204 (No Content), or 304 (Not Modified) status - code is always terminated by the first empty line after the - header fields, regardless of the header fields present in the - message, and thus cannot contain a message body. + 1. Any response to a HEAD request and any response with a 1xx + (Informational), 204 (No Content), or 304 (Not Modified) status + code is always terminated by the first empty line after the + header fields, regardless of the header fields present in the + message, and thus cannot contain a message body. */ if (parser->response_status / 100 == 1 || parser->response_status == 204 || parser->response_status == 304) { // HEAD is handled in caller @@ -332,8 +334,7 @@ } } - /* http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-23 - Section 7.1.3: + /* RFC 7231, Section 7.1.3: Retry-After Servers send the "Retry-After" header field to indicate how long the user agent ought to wait before making a follow-up request. When
--- a/src/lib-http/http-transfer-chunked.c Tue Jul 01 23:24:08 2014 +0300 +++ b/src/lib-http/http-transfer-chunked.c Wed Jul 02 00:10:16 2014 +0300 @@ -119,7 +119,7 @@ static int http_transfer_chunked_skip_qdtext (struct http_transfer_chunked_istream *tcstream) { - /* qdtext-nf = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text */ + /* qdtext = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text */ while (tcstream->cur < tcstream->end && http_char_is_qdtext(*tcstream->cur)) tcstream->cur++; if (tcstream->cur == tcstream->end) @@ -132,13 +132,12 @@ { int ret; - /* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-21; - Section 4.1: + /* RFC 7230, Section 4.1: Chunked Transfer Encoding chunked-body = *chunk - last-chunk - trailer-part - CRLF + last-chunk + trailer-part + CRLF chunk = chunk-size [ chunk-ext ] CRLF chunk-data CRLF @@ -147,14 +146,9 @@ chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) chunk-ext-name = token - chunk-ext-val = token / quoted-str-nf + chunk-ext-val = token / quoted-string chunk-data = 1*OCTET ; a sequence of chunk-size octets trailer-part = *( header-field CRLF ) - - quoted-str-nf = DQUOTE *( qdtext-nf / quoted-pair ) DQUOTE - ; like quoted-string, but disallowing line folding - qdtext-nf = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text - quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) */ for (;;) { @@ -201,7 +195,7 @@ return 0; /* fall through */ case HTTP_CHUNKED_PARSE_STATE_EXT_VALUE: - /* chunk-ext-val = token / quoted-str-nf */ + /* chunk-ext-val = token / quoted-string */ if (*tcstream->cur != '"') { tcstream->state = HTTP_CHUNKED_PARSE_STATE_EXT_VALUE_TOKEN; break; @@ -555,7 +549,7 @@ /* Make sure we have room for both chunk data and overhead - chunk = chunk-size CRLF + chunk = chunk-size [ chunk-ext ] CRLF chunk-data CRLF chunk-size = 1*HEXDIG */
--- a/src/lib-http/http-url.c Tue Jul 01 23:24:08 2014 +0300 +++ b/src/lib-http/http-url.c Wed Jul 02 00:10:16 2014 +0300 @@ -42,16 +42,15 @@ const char *p; if ((url_parser->flags & HTTP_URL_ALLOW_USERINFO_PART) == 0) { - /* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-20 - - Section 2.8.1: + /* RFC 7230, Section 2.7.1: http URI Scheme - {...} Senders MUST NOT include a userinfo subcomponent (and its "@" - delimiter) when transmitting an "http" URI in a message. Recipients - of HTTP messages that contain a URI reference SHOULD parse for the - existence of userinfo and treat its presence as an error, likely - indicating that the deprecated subcomponent is being used to - obscure the authority for the sake of phishing attacks. + A sender MUST NOT generate the userinfo subcomponent (and its "@" + delimiter) when an "http" URI reference is generated within a + message as a request target or header field value. Before making + use of an "http" URI reference received from an untrusted source, + a recipient SHOULD parse for userinfo and treat its presence as + an error; it is likely being used to obscure the authority for + the sake of phishing attacks. */ parser->error = "HTTP URL does not allow `userinfo@' part"; return FALSE; @@ -104,14 +103,12 @@ const char *part; int ret; - /* - http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23 - Appendix C: + /* RFC 7230, Appendix B: http-URI = "http://" authority path-abempty [ "?" query ] - [ "#" fragment ] + [ "#" fragment ] https-URI = "https://" authority path-abempty [ "?" query ] - [ "#" fragment ] + [ "#" fragment ] partial-URI = relative-part [ "?" query ] request-target = origin-form / absolute-form / authority-form / @@ -121,12 +118,11 @@ absolute-form = absolute-URI authority-form = authority asterisk-form = "*" - ; Not parsed here + ; Not parsed here absolute-path = 1*( "/" segment ) - http://tools.ietf.org/html/rfc3986 - Appendix A: (implemented in uri-util.h) + RFC 3986, Appendix A: (implemented in uri-util.h) absolute-URI = scheme ":" hier-part [ "?" query ]