http-response-parser.c revision bfb3d8c8f2f156b0b2acec445375b8a08462ab1f
/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "str.h"
#include "strfuncs.h"
#include "istream.h"
#include "http-parser.h"
#include "http-date.h"
#include "http-header-parser.h"
#include "http-transfer.h"
#include "http-response-parser.h"
#include <ctype.h>
enum http_response_parser_state {
};
struct http_response_parser {
const char *error;
struct http_header_parser *header_parser;
const char *transfer_encoding;
struct http_response *response;
};
{
struct http_response_parser *parser;
return parser;
}
{
}
static void
{
parser->content_length = 0;
}
{
/* HTTP-version = HTTP-name "/" DIGIT "." DIGIT
HTTP-name = %x48.54.54.50 ; "HTTP", case-sensitive
*/
if (size < 8)
return 0;
return -1;
return 1;
}
{
/* status-code = 3DIGIT
*/
if (size < 3)
return 0;
return -1;
(p[0] - '0')*100 + (p[1] - '0')*10 + (p[2] - '0');
return 1;
}
{
/* reason-phrase = *( HTAB / SP / VCHAR / obs-text )
*/
p++;
return 0;
return 1;
}
static inline const char *_chr_sanitize(unsigned char c)
{
if (c >= 0x20 && c < 0x7F)
return t_strdup_printf("'%c'", c);
return t_strdup_printf("0x%02x", c);
}
{
int ret;
/* status-line = HTTP-version SP status-code SP reason-phrase CRLF
status-code = 3DIGIT
reason-phrase = *( HTAB / SP / VCHAR / obs-text )
*/
for (;;) {
/* fall through */
if (ret < 0)
return ret;
}
return 0;
/* fall through */
("Expected ' ' after response version, but found %s",
return -1;
}
return 0;
/* fall through */
if (ret < 0)
return ret;
}
return 0;
/* fall through */
("Expected ' ' after response status code, but found %s",
return -1;
}
return 0;
/* fall through */
return ret;
return 0;
/* fall through */
return 0;
/* fall through */
("Expected line end after response, but found %s",
return -1;
}
return 1;
default:
i_unreached();
}
}
i_unreached();
return -1;
}
{
int ret;
return -1;
if (ret > 0)
return 1;
}
if (ret < 0) {
return 0;
return -1;
}
return 0;
}
static int
{
struct http_response_header *hdr;
struct http_parser hparser;
void *value;
switch (name[0]) {
case 'C': case 'c':
const char *option;
/* Connection = 1#connection-option
connection-option = token
*/
for (;;) {
break;
break; // not interested in any other options
}
}
return 1;
}
/* Content-Length = 1*DIGIT */
return -1;
}
return 1;
}
break;
case 'D': case 'd':
/* Date = HTTP-date */
return 1;
}
break;
case 'L': case 'l':
/* Location = URI-reference (not parsed here) */
return 1;
}
break;
case 'T': case 't':
/* Transfer-Encoding = 1#transfer-coding */
return 1;
}
break;
default:
break;
}
return 1;
}
const char **error_r)
{
struct http_parser hparser;
const char *field_name, *error;
const unsigned char *field_data;
int ret;
/* make sure we finished streaming payload from previous response
before we continue. */
const unsigned char *data;
if (ret < 0)
*error_r = "Stream error while skipping payload";
return ret;
}
}
/* HTTP-message = start-line
*( header-field CRLF )
CRLF
[ message-body ]
*/
/* start-line */
return ret;
}
/* *( header-field CRLF ) CRLF */
else
}
while ((ret=http_header_parse_next_field
if (field_name == NULL) break;
return -1;
}
}
if (ret <= 0) {
if (ret < 0)
return ret;
}
Section 3.3.2:
A server MUST NOT send a Content-Length header field in any response
with a status code of 1xx (Informational) or 204 (No Content). [...]
*/
"Unexpected Content-Length header field for %u response "
return -1;
}
Section 3.3.3:
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.
*/
no_payload = TRUE;
}
if (!no_payload) {
/* [ message-body ] */
if (parser->content_length > 0) {
/* Got explicit message size from Content-Length: header */
const char *tenc;
/* Transfer-Encoding = 1#transfer-coding
transfer-coding = "chunked" / "compress" / "deflate" / "gzip"
/ transfer-extension ; [FIXME]
transfer-extension = token *( OWS ";" OWS transfer-parameter )
*/
(const unsigned char *)parser->transfer_encoding,
for (;;) {
break;
break; // FIXME
} else {
"Unkown Transfer-Encoding `%s' for %u response",
return -1;
}
}
}
}
return 1;
}