-/* $OpenBSD: http.c,v 1.67 2022/09/08 13:52:36 claudio Exp $ */
+/* $OpenBSD: http.c,v 1.68 2022/09/09 08:11:06 claudio Exp $ */
/*
* Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com>
* Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
STATE_RESPONSE_HEADER,
STATE_RESPONSE_DATA,
STATE_RESPONSE_CHUNKED_HEADER,
+ STATE_RESPONSE_CHUNKED_CRLF,
STATE_RESPONSE_CHUNKED_TRAILER,
STATE_WRITE_DATA,
STATE_IDLE,
/*
* Parse the header between data chunks during chunked transfers.
* Returns 0 if a new chunk size could be correctly read.
- * Returns 1 for the empty trailer lines.
* If the chuck size could not be converted properly -1 is returned.
*/
static int
char *end;
unsigned long chunksize;
- /* empty lines are used as trailer */
- if (*header == '\0')
- return 1;
-
/* strip any optional chunk extension */
header[strcspn(header, "; \t")] = '\0';
errno = 0;
conn->bufpos = 0;
}
if (conn->chunked)
- conn->state = STATE_RESPONSE_CHUNKED_TRAILER;
+ conn->state = STATE_RESPONSE_CHUNKED_CRLF;
else
conn->state = STATE_RESPONSE_DATA;
goto read_more;
* check if transfer is done, in which case the last trailer
* still needs to be processed.
*/
- if (conn->iosz == 0) {
- conn->chunked = 0;
+ if (conn->iosz == 0)
conn->state = STATE_RESPONSE_CHUNKED_TRAILER;
- goto again;
- }
-
- conn->state = STATE_RESPONSE_DATA;
+ else
+ conn->state = STATE_RESPONSE_DATA;
goto again;
- case STATE_RESPONSE_CHUNKED_TRAILER:
+ case STATE_RESPONSE_CHUNKED_CRLF:
buf = http_get_line(conn);
if (buf == NULL)
goto read_more;
- if (http_parse_chunked(conn, buf) != 1) {
+ /* expect empty line to finish a chunk of data */
+ if (*buf != '\0') {
warnx("%s: bad chunk encoding", http_info(conn->host));
free(buf);
return http_failed(conn);
}
free(buf);
-
- /* if chunked got cleared then the transfer is over */
- if (conn->chunked == 0)
- return http_done(conn, HTTP_OK);
-
conn->state = STATE_RESPONSE_CHUNKED_HEADER;
goto again;
+ case STATE_RESPONSE_CHUNKED_TRAILER:
+ buf = http_get_line(conn);
+ if (buf == NULL)
+ goto read_more;
+ /* the trailer may include extra headers, just ignore them */
+ if (*buf != '\0') {
+ free(buf);
+ goto again;
+ }
+ free(buf);
+ conn->chunked = 0;
+ return http_done(conn, HTTP_OK);
default:
errx(1, "unexpected http state");
}
/* all data written, switch back to read */
if (conn->bufpos == 0 || conn->iosz == 0) {
if (conn->chunked && conn->iosz == 0)
- conn->state = STATE_RESPONSE_CHUNKED_TRAILER;
+ conn->state = STATE_RESPONSE_CHUNKED_CRLF;
else
conn->state = STATE_RESPONSE_DATA;
return http_read(conn);
case STATE_RESPONSE_HEADER:
case STATE_RESPONSE_DATA:
case STATE_RESPONSE_CHUNKED_HEADER:
+ case STATE_RESPONSE_CHUNKED_CRLF:
case STATE_RESPONSE_CHUNKED_TRAILER:
return http_read(conn);
case STATE_WRITE_DATA: