Skip to content
This repository was archived by the owner on Nov 6, 2022. It is now read-only.

Commit d767545

Browse files
KjellSchubertindutny
authored andcommitted
src: callbacks chunk boundaries: header/complete
(Proxygen fork merge D508755 D521404, orig author [email protected]) Fix: #231 PR-URL: #233 Reviewed-By: Fedor Indutny <[email protected]>
1 parent 2872cb7 commit d767545

File tree

3 files changed

+118
-6
lines changed

3 files changed

+118
-6
lines changed

http_parser.c

+9-5
Original file line numberDiff line numberDiff line change
@@ -1782,9 +1782,9 @@ size_t http_parser_execute (http_parser *parser,
17821782

17831783
if (parser->flags & F_TRAILING) {
17841784
/* End of a chunked request */
1785-
UPDATE_STATE(NEW_MESSAGE());
1786-
CALLBACK_NOTIFY(message_complete);
1787-
break;
1785+
UPDATE_STATE(s_message_done);
1786+
CALLBACK_NOTIFY_NOADVANCE(chunk_complete);
1787+
REEXECUTE();
17881788
}
17891789

17901790
UPDATE_STATE(s_headers_done);
@@ -1994,6 +1994,7 @@ size_t http_parser_execute (http_parser *parser,
19941994
} else {
19951995
UPDATE_STATE(s_chunk_data);
19961996
}
1997+
CALLBACK_NOTIFY(chunk_header);
19971998
break;
19981999
}
19992000

@@ -2033,6 +2034,7 @@ size_t http_parser_execute (http_parser *parser,
20332034
STRICT_CHECK(ch != LF);
20342035
parser->nread = 0;
20352036
UPDATE_STATE(s_chunk_size_start);
2037+
CALLBACK_NOTIFY(chunk_complete);
20362038
break;
20372039

20382040
default:
@@ -2144,13 +2146,15 @@ http_parser_settings_init(http_parser_settings *settings)
21442146

21452147
const char *
21462148
http_errno_name(enum http_errno err) {
2147-
assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
2149+
assert(((size_t) err) <
2150+
(sizeof(http_strerror_tab) / sizeof(http_strerror_tab[0])));
21482151
return http_strerror_tab[err].name;
21492152
}
21502153

21512154
const char *
21522155
http_errno_description(enum http_errno err) {
2153-
assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
2156+
assert(((size_t) err) <
2157+
(sizeof(http_strerror_tab) / sizeof(http_strerror_tab[0])));
21542158
return http_strerror_tab[err].description;
21552159
}
21562160

http_parser.h

+7
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ enum flags
160160
XX(CB_body, "the on_body callback failed") \
161161
XX(CB_message_complete, "the on_message_complete callback failed") \
162162
XX(CB_status, "the on_status callback failed") \
163+
XX(CB_chunk_header, "the on_chunk_header callback failed") \
164+
XX(CB_chunk_complete, "the on_chunk_complete callback failed") \
163165
\
164166
/* Parsing-related errors */ \
165167
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
@@ -240,6 +242,11 @@ struct http_parser_settings {
240242
http_cb on_headers_complete;
241243
http_data_cb on_body;
242244
http_cb on_message_complete;
245+
/* When on_chunk_header is called, the current chunk length is stored
246+
* in parser->content_length.
247+
*/
248+
http_cb on_chunk_header;
249+
http_cb on_chunk_complete;
243250
};
244251

245252

test.c

+102-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
#define MAX_HEADERS 13
4141
#define MAX_ELEMENT_SIZE 2048
42+
#define MAX_CHUNKS 16
4243

4344
#define MIN(a,b) ((a) < (b) ? (a) : (b))
4445

@@ -65,6 +66,10 @@ struct message {
6566
char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE];
6667
int should_keep_alive;
6768

69+
int num_chunks;
70+
int num_chunks_complete;
71+
int chunk_lengths[MAX_CHUNKS];
72+
6873
const char *upgrade; // upgraded body
6974

7075
unsigned short http_major;
@@ -301,6 +306,8 @@ const struct message requests[] =
301306
{ { "Transfer-Encoding" , "chunked" }
302307
}
303308
,.body= "all your base are belong to us"
309+
,.num_chunks_complete= 2
310+
,.chunk_lengths= { 0x1e }
304311
}
305312

306313
#define TWO_CHUNKS_MULT_ZERO_END 9
@@ -327,6 +334,8 @@ const struct message requests[] =
327334
{ { "Transfer-Encoding", "chunked" }
328335
}
329336
,.body= "hello world"
337+
,.num_chunks_complete= 3
338+
,.chunk_lengths= { 5, 6 }
330339
}
331340

332341
#define CHUNKED_W_TRAILING_HEADERS 10
@@ -357,6 +366,8 @@ const struct message requests[] =
357366
, { "Content-Type", "text/plain" }
358367
}
359368
,.body= "hello world"
369+
,.num_chunks_complete= 3
370+
,.chunk_lengths= { 5, 6 }
360371
}
361372

362373
#define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11
@@ -383,6 +394,8 @@ const struct message requests[] =
383394
{ { "Transfer-Encoding", "chunked" }
384395
}
385396
,.body= "hello world"
397+
,.num_chunks_complete= 3
398+
,.chunk_lengths= { 5, 6 }
386399
}
387400

388401
#define WITH_QUOTES 12
@@ -1195,7 +1208,8 @@ const struct message responses[] =
11951208
,.body =
11961209
"This is the data in the first chunk\r\n"
11971210
"and this is the second one\r\n"
1198-
1211+
,.num_chunks_complete= 3
1212+
,.chunk_lengths= { 0x25, 0x1c }
11991213
}
12001214

12011215
#define NO_CARRIAGE_RET 5
@@ -1349,6 +1363,8 @@ const struct message responses[] =
13491363
, { "Connection", "close" }
13501364
}
13511365
,.body= ""
1366+
,.num_chunks_complete= 1
1367+
,.chunk_lengths= {}
13521368
}
13531369

13541370
#define NON_ASCII_IN_STATUS_LINE 10
@@ -1531,6 +1547,7 @@ const struct message responses[] =
15311547
}
15321548
,.body_size= 0
15331549
,.body= ""
1550+
,.num_chunks_complete= 1
15341551
}
15351552

15361553
#if !HTTP_PARSER_STRICT
@@ -1604,6 +1621,8 @@ const struct message responses[] =
16041621
, { "Transfer-Encoding", "chunked" }
16051622
}
16061623
,.body= "\n"
1624+
,.num_chunks_complete= 2
1625+
,.chunk_lengths= { 1 }
16071626
}
16081627

16091628
#define EMPTY_REASON_PHRASE_AFTER_SPACE 20
@@ -1839,6 +1858,35 @@ response_status_cb (http_parser *p, const char *buf, size_t len)
18391858
return 0;
18401859
}
18411860

1861+
int
1862+
chunk_header_cb (http_parser *p)
1863+
{
1864+
assert(p == parser);
1865+
int chunk_idx = messages[num_messages].num_chunks;
1866+
messages[num_messages].num_chunks++;
1867+
if (chunk_idx < MAX_CHUNKS) {
1868+
messages[num_messages].chunk_lengths[chunk_idx] = p->content_length;
1869+
}
1870+
1871+
return 0;
1872+
}
1873+
1874+
int
1875+
chunk_complete_cb (http_parser *p)
1876+
{
1877+
assert(p == parser);
1878+
1879+
/* Here we want to verify that each chunk_header_cb is matched by a
1880+
* chunk_complete_cb, so not only should the total number of calls to
1881+
* both callbacks be the same, but they also should be interleaved
1882+
* properly */
1883+
assert(messages[num_messages].num_chunks ==
1884+
messages[num_messages].num_chunks_complete + 1);
1885+
1886+
messages[num_messages].num_chunks_complete++;
1887+
return 0;
1888+
}
1889+
18421890
/* These dontcall_* callbacks exist so that we can verify that when we're
18431891
* paused, no additional callbacks are invoked */
18441892
int
@@ -1907,6 +1955,23 @@ dontcall_response_status_cb (http_parser *p, const char *buf, size_t len)
19071955
abort();
19081956
}
19091957

1958+
int
1959+
dontcall_chunk_header_cb (http_parser *p)
1960+
{
1961+
if (p) { } // gcc
1962+
fprintf(stderr, "\n\n*** on_chunk_header() called on paused parser ***\n\n");
1963+
exit(1);
1964+
}
1965+
1966+
int
1967+
dontcall_chunk_complete_cb (http_parser *p)
1968+
{
1969+
if (p) { } // gcc
1970+
fprintf(stderr, "\n\n*** on_chunk_complete() "
1971+
"called on paused parser ***\n\n");
1972+
exit(1);
1973+
}
1974+
19101975
static http_parser_settings settings_dontcall =
19111976
{.on_message_begin = dontcall_message_begin_cb
19121977
,.on_header_field = dontcall_header_field_cb
@@ -1916,6 +1981,8 @@ static http_parser_settings settings_dontcall =
19161981
,.on_body = dontcall_body_cb
19171982
,.on_headers_complete = dontcall_headers_complete_cb
19181983
,.on_message_complete = dontcall_message_complete_cb
1984+
,.on_chunk_header = dontcall_chunk_header_cb
1985+
,.on_chunk_complete = dontcall_chunk_complete_cb
19191986
};
19201987

19211988
/* These pause_* callbacks always pause the parser and just invoke the regular
@@ -1986,6 +2053,22 @@ pause_response_status_cb (http_parser *p, const char *buf, size_t len)
19862053
return response_status_cb(p, buf, len);
19872054
}
19882055

2056+
int
2057+
pause_chunk_header_cb (http_parser *p)
2058+
{
2059+
http_parser_pause(p, 1);
2060+
*current_pause_parser = settings_dontcall;
2061+
return chunk_header_cb(p);
2062+
}
2063+
2064+
int
2065+
pause_chunk_complete_cb (http_parser *p)
2066+
{
2067+
http_parser_pause(p, 1);
2068+
*current_pause_parser = settings_dontcall;
2069+
return chunk_complete_cb(p);
2070+
}
2071+
19892072
static http_parser_settings settings_pause =
19902073
{.on_message_begin = pause_message_begin_cb
19912074
,.on_header_field = pause_header_field_cb
@@ -1995,6 +2078,8 @@ static http_parser_settings settings_pause =
19952078
,.on_body = pause_body_cb
19962079
,.on_headers_complete = pause_headers_complete_cb
19972080
,.on_message_complete = pause_message_complete_cb
2081+
,.on_chunk_header = pause_chunk_header_cb
2082+
,.on_chunk_complete = pause_chunk_complete_cb
19982083
};
19992084

20002085
static http_parser_settings settings =
@@ -2006,6 +2091,8 @@ static http_parser_settings settings =
20062091
,.on_body = body_cb
20072092
,.on_headers_complete = headers_complete_cb
20082093
,.on_message_complete = message_complete_cb
2094+
,.on_chunk_header = chunk_header_cb
2095+
,.on_chunk_complete = chunk_complete_cb
20092096
};
20102097

20112098
static http_parser_settings settings_count_body =
@@ -2017,6 +2104,8 @@ static http_parser_settings settings_count_body =
20172104
,.on_body = count_body_cb
20182105
,.on_headers_complete = headers_complete_cb
20192106
,.on_message_complete = message_complete_cb
2107+
,.on_chunk_header = chunk_header_cb
2108+
,.on_chunk_complete = chunk_complete_cb
20202109
};
20212110

20222111
static http_parser_settings settings_null =
@@ -2028,6 +2117,8 @@ static http_parser_settings settings_null =
20282117
,.on_body = 0
20292118
,.on_headers_complete = 0
20302119
,.on_message_complete = 0
2120+
,.on_chunk_header = 0
2121+
,.on_chunk_complete = 0
20312122
};
20322123

20332124
void
@@ -2196,6 +2287,12 @@ message_eq (int index, const struct message *expected)
21962287
MESSAGE_CHECK_STR_EQ(expected, m, body);
21972288
}
21982289

2290+
assert(m->num_chunks == m->num_chunks_complete);
2291+
MESSAGE_CHECK_NUM_EQ(expected, m, num_chunks_complete);
2292+
for (i = 0; i < m->num_chunks && i < MAX_CHUNKS; i++) {
2293+
MESSAGE_CHECK_NUM_EQ(expected, m, chunk_lengths[i]);
2294+
}
2295+
21992296
MESSAGE_CHECK_NUM_EQ(expected, m, num_headers);
22002297

22012298
int r;
@@ -3488,7 +3585,11 @@ main (void)
34883585
, { "Content-Type", "text/plain" }
34893586
}
34903587
,.body_size= 31337*1024
3588+
,.num_chunks_complete= 31338
34913589
};
3590+
for (i = 0; i < MAX_CHUNKS; i++) {
3591+
large_chunked.chunk_lengths[i] = 1024;
3592+
}
34923593
test_message_count_body(&large_chunked);
34933594
free(msg);
34943595
}

0 commit comments

Comments
 (0)