http-response-parser.c revision 7af70f7646264a2f52b361f9ca78f08681acc4e2
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "lib.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "istream.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "http-parser.h"
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch#include "http-date.h"
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen#include "http-message-parser.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "http-response-parser.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include <ctype.h>
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschenum http_response_parser_state {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch HTTP_RESPONSE_PARSE_STATE_INIT = 0,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch HTTP_RESPONSE_PARSE_STATE_VERSION,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch HTTP_RESPONSE_PARSE_STATE_SP1,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch HTTP_RESPONSE_PARSE_STATE_STATUS,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch HTTP_RESPONSE_PARSE_STATE_SP2,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch HTTP_RESPONSE_PARSE_STATE_REASON,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch HTTP_RESPONSE_PARSE_STATE_CR,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch HTTP_RESPONSE_PARSE_STATE_LF,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch HTTP_RESPONSE_PARSE_STATE_HEADER
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch};
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstruct http_response_parser {
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen struct http_message_parser parser;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch enum http_response_parser_state state;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch unsigned int response_status;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch const char *response_reason;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch};
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
feba5e502b2131c9a1c766b7ef9ff041dbf71d1dStephan Boschstruct http_response_parser *
feba5e502b2131c9a1c766b7ef9ff041dbf71d1dStephan Boschhttp_response_parser_init(struct istream *input,
feba5e502b2131c9a1c766b7ef9ff041dbf71d1dStephan Bosch const struct http_header_limits *hdr_limits)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_response_parser *parser;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
feba5e502b2131c9a1c766b7ef9ff041dbf71d1dStephan Bosch /* FIXME: implement status line limit */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch parser = i_new(struct http_response_parser, 1);
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch http_message_parser_init(&parser->parser, input, hdr_limits, 0);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return parser;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschvoid http_response_parser_deinit(struct http_response_parser **_parser)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_response_parser *parser = *_parser;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen http_message_parser_deinit(&parser->parser);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_free(parser);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic void
7384b4e78eaab44693c985192276e31322155e32Stephan Boschhttp_response_parser_restart(struct http_response_parser *parser)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
6dad0888fcec8372f230941c70d8940b8c203b32Stephan Bosch http_message_parser_restart(&parser->parser, NULL);
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch parser->response_status = 0;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch parser->response_reason = NULL;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic int http_response_parse_status(struct http_response_parser *parser)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen const unsigned char *p = parser->parser.cur;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen const size_t size = parser->parser.end - parser->parser.cur;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* status-code = 3DIGIT
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch */
1bc12a53ddc6696bb209fb79d7cc66262d2ea621Timo Sirainen if (size < 3)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return 0;
1bc12a53ddc6696bb209fb79d7cc66262d2ea621Timo Sirainen if (!i_isdigit(p[0]) || !i_isdigit(p[1]) || !i_isdigit(p[2]))
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return -1;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch parser->response_status =
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch (p[0] - '0')*100 + (p[1] - '0')*10 + (p[2] - '0');
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->parser.cur += 3;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return 1;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic int http_response_parse_reason(struct http_response_parser *parser)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen const unsigned char *p = parser->parser.cur;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* reason-phrase = *( HTAB / SP / VCHAR / obs-text )
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch */
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch // FIXME: limit length
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen while (p < parser->parser.end && http_char_is_text(*p))
1bc12a53ddc6696bb209fb79d7cc66262d2ea621Timo Sirainen p++;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (p == parser->parser.end)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return 0;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch parser->response_reason =
6dad0888fcec8372f230941c70d8940b8c203b32Stephan Bosch p_strdup_until(parser->parser.msg.pool, parser->parser.cur, p);
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->parser.cur = p;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return 1;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic inline const char *_chr_sanitize(unsigned char c)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (c >= 0x20 && c < 0x7F)
101e78ae4d5705f196fba22db3261db042bfb3c2Stephan Bosch return t_strdup_printf("`%c'", c);
101e78ae4d5705f196fba22db3261db042bfb3c2Stephan Bosch if (c == 0x0a)
101e78ae4d5705f196fba22db3261db042bfb3c2Stephan Bosch return "<LF>";
101e78ae4d5705f196fba22db3261db042bfb3c2Stephan Bosch if (c == 0x0d)
101e78ae4d5705f196fba22db3261db042bfb3c2Stephan Bosch return "<CR>";
101e78ae4d5705f196fba22db3261db042bfb3c2Stephan Bosch return t_strdup_printf("<0x%02x>", c);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Boschstatic int http_response_parse(struct http_response_parser *parser)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen struct http_message_parser *_parser = &parser->parser;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch int ret;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* status-line = HTTP-version SP status-code SP reason-phrase CRLF
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch status-code = 3DIGIT
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch reason-phrase = *( HTAB / SP / VCHAR / obs-text )
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch switch (parser->state) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch case HTTP_RESPONSE_PARSE_STATE_INIT:
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch http_response_parser_restart(parser);
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->state = HTTP_RESPONSE_PARSE_STATE_VERSION;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch /* fall through */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch case HTTP_RESPONSE_PARSE_STATE_VERSION:
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if ((ret=http_message_parse_version(_parser)) <= 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (ret < 0)
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _parser->error = "Invalid HTTP version in response";
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return ret;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->state = HTTP_RESPONSE_PARSE_STATE_SP1;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (_parser->cur == _parser->end)
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return 0;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch /* fall through */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch case HTTP_RESPONSE_PARSE_STATE_SP1:
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (*_parser->cur != ' ') {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _parser->error = t_strdup_printf
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch ("Expected ' ' after response version, but found %s",
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _chr_sanitize(*_parser->cur));
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return -1;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _parser->cur++;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->state = HTTP_RESPONSE_PARSE_STATE_STATUS;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (_parser->cur >= _parser->end)
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return 0;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch /* fall through */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch case HTTP_RESPONSE_PARSE_STATE_STATUS:
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if ((ret=http_response_parse_status(parser)) <= 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (ret < 0)
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _parser->error = "Invalid HTTP status code in response";
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return ret;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->state = HTTP_RESPONSE_PARSE_STATE_SP2;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (_parser->cur == _parser->end)
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return 0;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch /* fall through */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch case HTTP_RESPONSE_PARSE_STATE_SP2:
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (*_parser->cur != ' ') {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _parser->error = t_strdup_printf
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch ("Expected ' ' after response status code, but found %s",
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _chr_sanitize(*_parser->cur));
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return -1;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _parser->cur++;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->state = HTTP_RESPONSE_PARSE_STATE_REASON;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (_parser->cur >= _parser->end)
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return 0;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch /* fall through */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch case HTTP_RESPONSE_PARSE_STATE_REASON:
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if ((ret=http_response_parse_reason(parser)) <= 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch i_assert(ret == 0);
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return 0;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->state = HTTP_RESPONSE_PARSE_STATE_CR;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (_parser->cur == _parser->end)
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return 0;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch /* fall through */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch case HTTP_RESPONSE_PARSE_STATE_CR:
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (*_parser->cur == '\r')
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen _parser->cur++;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->state = HTTP_RESPONSE_PARSE_STATE_LF;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (_parser->cur == _parser->end)
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return 0;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch /* fall through */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch case HTTP_RESPONSE_PARSE_STATE_LF:
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (*_parser->cur != '\n') {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _parser->error = t_strdup_printf
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch ("Expected line end after response, but found %s",
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _chr_sanitize(*_parser->cur));
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return -1;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _parser->cur++;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->state = HTTP_RESPONSE_PARSE_STATE_HEADER;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return 1;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch case HTTP_RESPONSE_PARSE_STATE_HEADER:
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch default:
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch break;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_unreached();
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return -1;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Boschstatic int
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Boschhttp_response_parse_status_line(struct http_response_parser *parser)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen struct http_message_parser *_parser = &parser->parser;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen const unsigned char *begin;
1bc12a53ddc6696bb209fb79d7cc66262d2ea621Timo Sirainen size_t size, old_bytes = 0;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch int ret;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen while ((ret = i_stream_read_data(_parser->input, &begin, &size,
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen old_bytes)) > 0) {
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen _parser->cur = begin;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen _parser->end = _parser->cur + size;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if ((ret = http_response_parse(parser)) < 0)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return -1;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen i_stream_skip(_parser->input, _parser->cur - begin);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (ret > 0)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return 1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen old_bytes = i_stream_get_data_size(_parser->input);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (ret == -2) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _parser->error = "HTTP status line is too long";
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return -1;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (ret < 0) {
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (_parser->input->eof &&
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->state == HTTP_RESPONSE_PARSE_STATE_INIT)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return 0;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _parser->error = "Stream error";
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return -1;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return 0;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Boschstatic int
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Boschhttp_response_parse_retry_after(const char *hdrval, time_t resp_time,
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch time_t *retry_after_r)
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch{
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch time_t delta;
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch /* http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-23
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch Section 7.1.3:
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch The value of this field can be either an HTTP-date or an integer
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch number of seconds (in decimal) after the time of the response.
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch Time spans are non-negative decimal integers, representing time in
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch seconds.
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch Retry-After = HTTP-date / delta-seconds
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch delta-seconds = 1*DIGIT
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch */
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch if (str_to_time(hdrval, &delta) >= 0) {
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch if (resp_time == (time_t)-1) {
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch return -1;
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch }
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch *retry_after_r = resp_time + delta;
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch return 0;
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch }
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch return (http_date_parse
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch ((unsigned char *)hdrval, strlen(hdrval), retry_after_r) ? 0 : -1);
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch}
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschint http_response_parse_next(struct http_response_parser *parser,
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch enum http_response_payload_type payload_type,
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch struct http_response *response, const char **error_r)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch const char *hdrval;
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch time_t retry_after = (time_t)-1;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch int ret;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* make sure we finished streaming payload from previous response
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch before we continue. */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if ((ret = http_message_parse_finish_payload(&parser->parser)) <= 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch *error_r = parser->parser.error;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return ret;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* HTTP-message = start-line
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch *( header-field CRLF )
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch CRLF
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch [ message-body ]
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (parser->state != HTTP_RESPONSE_PARSE_STATE_HEADER) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if ((ret = http_response_parse_status_line(parser)) <= 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch *error_r = parser->parser.error;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return ret;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if ((ret = http_message_parse_headers(&parser->parser)) <= 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch *error_r = parser->parser.error;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return ret;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-21
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch Section 3.3.2:
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch A server MUST NOT send a Content-Length header field in any response
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch with a status code of 1xx (Informational) or 204 (No Content). [...]
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch */
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch if ((parser->response_status / 100 == 1 || parser->response_status == 204) &&
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->parser.msg.content_length > 0) {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch *error_r = t_strdup_printf(
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch "Unexpected Content-Length header field for %u response "
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch "(length=%"PRIuUOFF_T")", parser->response_status,
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->parser.msg.content_length);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return -1;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-21
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch Section 3.3.3:
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch Any response to a HEAD request and any response with a 1xx
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch (Informational), 204 (No Content), or 304 (Not Modified) status
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch code is always terminated by the first empty line after the
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch header fields, regardless of the header fields present in the
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch message, and thus cannot contain a message body.
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch */
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch if (parser->response_status / 100 == 1 || parser->response_status == 204
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch || parser->response_status == 304) { // HEAD is handled in caller
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch payload_type = HTTP_RESPONSE_PAYLOAD_TYPE_NOT_PRESENT;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch if ((payload_type == HTTP_RESPONSE_PAYLOAD_TYPE_ALLOWED) ||
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch (payload_type == HTTP_RESPONSE_PAYLOAD_TYPE_ONLY_UNSUCCESSFUL &&
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch parser->response_status / 100 != 2)) {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* [ message-body ] */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (http_message_parse_body(&parser->parser, FALSE) < 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch *error_r = parser->parser.error;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return -1;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch /* http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-23
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch Section 7.1.3:
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch Servers send the "Retry-After" header field to indicate how long the
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch user agent ought to wait before making a follow-up request. When
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch sent with a 503 (Service Unavailable) response, Retry-After indicates
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch how long the service is expected to be unavailable to the client.
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch When sent with any 3xx (Redirection) response, Retry-After indicates
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch the minimum time that the user agent is asked to wait before issuing
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch the redirected request.
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch */
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch if (parser->response_status == 503 || (parser->response_status / 100) == 3) {
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch hdrval = http_header_field_get(parser->parser.msg.header, "Retry-After");
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch if (hdrval != NULL) {
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch (void)http_response_parse_retry_after
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch (hdrval, parser->parser.msg.date, &retry_after);
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch /* broken Retry-After header is ignored */
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch }
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch }
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch parser->state = HTTP_RESPONSE_PARSE_STATE_INIT;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch memset(response, 0, sizeof(*response));
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch response->status = parser->response_status;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch response->reason = parser->response_reason;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch response->version_major = parser->parser.msg.version_major;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch response->version_minor = parser->parser.msg.version_minor;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch response->location = parser->parser.msg.location;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch response->date = parser->parser.msg.date;
7af70f7646264a2f52b361f9ca78f08681acc4e2Stephan Bosch response->retry_after = retry_after;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch response->payload = parser->parser.payload;
e8f1e510df3ab051a816715c2056f0d10aee929eStephan Bosch response->header = parser->parser.msg.header;
e8f1e510df3ab051a816715c2056f0d10aee929eStephan Bosch response->headers = *http_header_get_fields(response->header); /* FIXME: remove in v2.3 */
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch response->connection_options = parser->parser.msg.connection_options;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch response->connection_close = parser->parser.msg.connection_close;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return 1;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}