http-response-parser.c revision c177bc7c153dd4d00dfa719f8a93c81129c4235e
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainenhttp_response_parser_init(struct istream *input,
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainen /* FIXME: implement status line limit */
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen parser = i_new(struct http_response_parser, 1);
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainen http_message_parser_init(&parser->parser, input, hdr_limits, 0, TRUE);
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainenvoid http_response_parser_deinit(struct http_response_parser **_parser)
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainen struct http_response_parser *parser = *_parser;
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainenhttp_response_parser_restart(struct http_response_parser *parser)
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen http_message_parser_restart(&parser->parser, NULL);
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainenstatic int http_response_parse_status(struct http_response_parser *parser)
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen const size_t size = parser->parser.end - parser->parser.cur;
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen /* status-code = 3DIGIT
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (!i_isdigit(p[0]) || !i_isdigit(p[1]) || !i_isdigit(p[2]))
ac383c437b1ccb9420cae6b4c4b03af3c8019e02Timo Sirainen (p[0] - '0')*100 + (p[1] - '0')*10 + (p[2] - '0');
45114a7f9600d04c294f8f1051c0289c092febceTimo Sirainenstatic int http_response_parse_reason(struct http_response_parser *parser)
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainen /* reason-phrase = *( HTAB / SP / VCHAR / obs-text )
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen // FIXME: limit length
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen while (p < parser->parser.end && http_char_is_text(*p))
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen pool = http_message_parser_get_pool(&parser->parser);
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainenstatic const char *_reply_sanitize(struct http_message_parser *parser)
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen const unsigned char *p;
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen unsigned int i;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen for (p = parser->cur, i = 0; p < parser->end && i < 20; p++, i++) {
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen if (*p == 0x0a)
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen else if (*p == 0x0d)
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainenstatic int http_response_parse(struct http_response_parser *parser)
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen struct http_message_parser *_parser = &parser->parser;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen /* RFC 7230, Section 3.1.2: Status Line
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen status-line = HTTP-version SP status-code SP reason-phrase CRLF
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen status-code = 3DIGIT
1caf757864e7734345660e7d190f84e42668a6f8Timo Sirainen reason-phrase = *( HTAB / SP / VCHAR / obs-text )
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen parser->state = HTTP_RESPONSE_PARSE_STATE_VERSION;
1caf757864e7734345660e7d190f84e42668a6f8Timo Sirainen /* fall through */
1caf757864e7734345660e7d190f84e42668a6f8Timo Sirainen if ((ret=http_message_parse_version(_parser)) <= 0) {
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen "Invalid HTTP version in response: %s",
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen parser->state = HTTP_RESPONSE_PARSE_STATE_SP1;
fcde781c3ceb470c8dff34a68df19c69f93bcec9Timo Sirainen /* fall through */
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainen ("Expected ' ' after response version, but found %s",
1caf757864e7734345660e7d190f84e42668a6f8Timo Sirainen parser->state = HTTP_RESPONSE_PARSE_STATE_STATUS;
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen /* fall through */
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen if ((ret=http_response_parse_status(parser)) <= 0) {
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen _parser->error = "Invalid HTTP status code in response";
1caf757864e7734345660e7d190f84e42668a6f8Timo Sirainen parser->state = HTTP_RESPONSE_PARSE_STATE_SP2;
fcde781c3ceb470c8dff34a68df19c69f93bcec9Timo Sirainen /* fall through */
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen ("Expected ' ' after response status code, but found %s",
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen parser->state = HTTP_RESPONSE_PARSE_STATE_REASON;
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen /* fall through */
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen if ((ret=http_response_parse_reason(parser)) <= 0) {
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen /* fall through */
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen /* fall through */
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen ("Expected line end after response, but found %s",
916221f976af0ed8b397f06f4f381c0ac0be3b86Timo Sirainen parser->state = HTTP_RESPONSE_PARSE_STATE_HEADER;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainenhttp_response_parse_status_line(struct http_response_parser *parser)
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen struct http_message_parser *_parser = &parser->parser;
916221f976af0ed8b397f06f4f381c0ac0be3b86Timo Sirainen const unsigned char *begin;
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen while ((ret = i_stream_read_bytes(_parser->input, &begin, &size,
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen i_stream_skip(_parser->input, _parser->cur - begin);
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen old_bytes = i_stream_get_data_size(_parser->input);
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen _parser->error = "HTTP status line is too long";
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen parser->state == HTTP_RESPONSE_PARSE_STATE_INIT)
return (http_date_parse
const char *hdrval;
int ret;
return ret;
return ret;
return ret;