8
8
#include "common.h"
9
9
#include "git2.h"
10
10
11
- #ifdef USE_LLHTTP
12
- #include <llhttp.h>
13
- typedef llhttp_settings_t http_settings_t ;
14
- typedef llhttp_t http_parser_t ;
15
- GIT_INLINE (http_settings_t * ) http_client_parser_settings (void );
16
- #define git_http_parser_init (parser ) llhttp_init(parser, HTTP_RESPONSE, http_client_parser_settings())
17
- #define git_http_parser_pause (parser ) llhttp_pause(parser)
18
- #define git_http_parser_resume (parser ) llhttp_resume(parser)
19
- #define git_http_parser_errno (parser ) parser.error
20
- #define git_http_should_keep_alive (parser ) llhttp_should_keep_alive(parser)
21
- #define git_http_errno_description (parser , errno ) llhttp_get_error_reason(parser)
22
- #else
23
- #include <http_parser.h>
24
- /* Legacy http-parser. */
25
- typedef http_parser_settings http_settings_t ;
26
- typedef struct http_parser http_parser_t ;
27
- GIT_INLINE (http_settings_t * ) http_client_parser_settings (void );
28
- #define git_http_parser_init (parser ) http_parser_init(parser, HTTP_RESPONSE)
29
- #define git_http_parser_pause (parser ) http_parser_pause(parser, 1)
30
- #define git_http_parser_resume (parser ) http_parser_pause(parser, 0)
31
- #define git_http_parser_errno (parser ) parser.http_errno
32
- #define git_http_should_keep_alive (parser ) http_should_keep_alive(parser)
33
- #define git_http_errno_description (parser , errno ) http_errno_description(errno)
34
- #endif /* USE_LLHTTP */
35
-
36
11
#include "vector.h"
37
12
#include "trace.h"
38
13
#include "httpclient.h"
@@ -46,6 +21,7 @@ GIT_INLINE(http_settings_t *) http_client_parser_settings(void);
46
21
#include "streams/socket.h"
47
22
#include "streams/tls.h"
48
23
#include "auth.h"
24
+ #include "httpparser.h"
49
25
50
26
static git_http_auth_scheme auth_schemes [] = {
51
27
{ GIT_HTTP_AUTH_NEGOTIATE , "Negotiate" , GIT_CREDENTIAL_DEFAULT , git_http_auth_negotiate },
@@ -133,7 +109,7 @@ struct git_http_client {
133
109
git_http_server_t current_server ;
134
110
http_client_state state ;
135
111
136
- http_parser_t parser ;
112
+ git_http_parser parser ;
137
113
138
114
git_http_server server ;
139
115
git_http_server proxy ;
@@ -179,7 +155,7 @@ void git_http_response_dispose(git_http_response *response)
179
155
memset (response , 0 , sizeof (git_http_response ));
180
156
}
181
157
182
- static int on_header_complete (http_parser_t * parser )
158
+ static int on_header_complete (git_http_parser * parser )
183
159
{
184
160
http_parser_context * ctx = (http_parser_context * ) parser -> data ;
185
161
git_http_client * client = ctx -> client ;
@@ -244,7 +220,7 @@ static int on_header_complete(http_parser_t *parser)
244
220
return 0 ;
245
221
}
246
222
247
- static int on_header_field (http_parser_t * parser , const char * str , size_t len )
223
+ static int on_header_field (git_http_parser * parser , const char * str , size_t len )
248
224
{
249
225
http_parser_context * ctx = (http_parser_context * ) parser -> data ;
250
226
@@ -279,7 +255,7 @@ static int on_header_field(http_parser_t *parser, const char *str, size_t len)
279
255
return 0 ;
280
256
}
281
257
282
- static int on_header_value (http_parser_t * parser , const char * str , size_t len )
258
+ static int on_header_value (git_http_parser * parser , const char * str , size_t len )
283
259
{
284
260
http_parser_context * ctx = (http_parser_context * ) parser -> data ;
285
261
@@ -367,7 +343,7 @@ static int resend_needed(git_http_client *client, git_http_response *response)
367
343
return 0 ;
368
344
}
369
345
370
- static int on_headers_complete (http_parser_t * parser )
346
+ static int on_headers_complete (git_http_parser * parser )
371
347
{
372
348
http_parser_context * ctx = (http_parser_context * ) parser -> data ;
373
349
@@ -389,8 +365,8 @@ static int on_headers_complete(http_parser_t *parser)
389
365
return ctx -> parse_status = PARSE_STATUS_ERROR ;
390
366
}
391
367
392
- ctx -> response -> status = parser -> status_code ;
393
- ctx -> client -> keepalive = git_http_should_keep_alive (parser );
368
+ ctx -> response -> status = git_http_parser_status_code ( parser ) ;
369
+ ctx -> client -> keepalive = git_http_parser_keep_alive (parser );
394
370
395
371
/* Prepare for authentication */
396
372
collect_authinfo (& ctx -> response -> server_auth_schemetypes ,
@@ -403,28 +379,15 @@ static int on_headers_complete(http_parser_t *parser)
403
379
ctx -> response -> resend_credentials = resend_needed (ctx -> client ,
404
380
ctx -> response );
405
381
406
- #ifndef USE_LLHTTP
407
- /* Stop parsing. llhttp documentation says about llhttp_pause():
408
- * "Do not call this from user callbacks! User callbacks must
409
- * return HPE_PAUSED if pausing is required", so that's what
410
- * we will do, and call git_http_parser_pause() only for
411
- * http-parser. */
412
- git_http_parser_pause (parser );
413
- #endif
414
-
415
382
if (ctx -> response -> content_type || ctx -> response -> chunked )
416
383
ctx -> client -> state = READING_BODY ;
417
384
else
418
385
ctx -> client -> state = DONE ;
419
386
420
- #ifdef USE_LLHTTP
421
- return HPE_PAUSED ;
422
- #else
423
- return 0 ;
424
- #endif
387
+ return git_http_parser_pause (parser );
425
388
}
426
389
427
- static int on_body (http_parser_t * parser , const char * buf , size_t len )
390
+ static int on_body (git_http_parser * parser , const char * buf , size_t len )
428
391
{
429
392
http_parser_context * ctx = (http_parser_context * ) parser -> data ;
430
393
size_t max_len ;
@@ -446,7 +409,7 @@ static int on_body(http_parser_t *parser, const char *buf, size_t len)
446
409
return 0 ;
447
410
}
448
411
449
- static int on_message_complete (http_parser_t * parser )
412
+ static int on_message_complete (git_http_parser * parser )
450
413
{
451
414
http_parser_context * ctx = (http_parser_context * ) parser -> data ;
452
415
@@ -911,9 +874,29 @@ GIT_INLINE(int) server_setup_from_url(
911
874
return 0 ;
912
875
}
913
876
877
+ static bool parser_settings_initialized ;
878
+ static git_http_parser_settings parser_settings ;
879
+
880
+ GIT_INLINE (git_http_parser_settings * ) http_client_parser_settings (void )
881
+ {
882
+ if (!parser_settings_initialized ) {
883
+ parser_settings .on_header_field = on_header_field ;
884
+ parser_settings .on_header_value = on_header_value ;
885
+ parser_settings .on_headers_complete = on_headers_complete ;
886
+ parser_settings .on_body = on_body ;
887
+ parser_settings .on_message_complete = on_message_complete ;
888
+
889
+ parser_settings_initialized = true;
890
+ }
891
+
892
+ return & parser_settings ;
893
+ }
894
+
914
895
static void reset_parser (git_http_client * client )
915
896
{
916
- git_http_parser_init (& client -> parser );
897
+ git_http_parser_init (& client -> parser ,
898
+ GIT_HTTP_PARSER_RESPONSE ,
899
+ http_client_parser_settings ());
917
900
}
918
901
919
902
static int setup_hosts (
@@ -1156,64 +1139,9 @@ GIT_INLINE(int) client_read(git_http_client *client)
1156
1139
return (int )read_len ;
1157
1140
}
1158
1141
1159
- static bool parser_settings_initialized ;
1160
- static http_settings_t parser_settings ;
1161
-
1162
- static size_t git_http_parser_execute (http_parser_t * parser , const char * data , size_t len )
1163
- {
1164
- #ifdef USE_LLHTTP
1165
- llhttp_errno_t error ;
1166
- size_t parsed_len ;
1167
-
1168
- /*
1169
- * Unlike http_parser, which returns the number of parsed
1170
- * bytes in the _execute() call, llhttp returns an error
1171
- * code.
1172
- */
1173
-
1174
- if (data == NULL || len == 0 ) {
1175
- error = llhttp_finish (parser );
1176
- } else {
1177
- error = llhttp_execute (parser , data , len );
1178
- }
1179
-
1180
- parsed_len = len ;
1181
- /*
1182
- * Adjust number of parsed bytes in case of error.
1183
- */
1184
- if (error != HPE_OK ) {
1185
- parsed_len = llhttp_get_error_pos (parser ) - data ;
1186
-
1187
- /* This isn't a real pause, just a way to stop parsing early. */
1188
- if (error == HPE_PAUSED_UPGRADE ) {
1189
- llhttp_resume_after_upgrade (parser );
1190
- }
1191
- }
1192
-
1193
- return parsed_len ;
1194
- #else
1195
- return http_parser_execute (parser , http_client_parser_settings (), data , len );
1196
- #endif
1197
- }
1198
-
1199
- GIT_INLINE (http_settings_t * ) http_client_parser_settings (void )
1200
- {
1201
- if (!parser_settings_initialized ) {
1202
- parser_settings .on_header_field = on_header_field ;
1203
- parser_settings .on_header_value = on_header_value ;
1204
- parser_settings .on_headers_complete = on_headers_complete ;
1205
- parser_settings .on_body = on_body ;
1206
- parser_settings .on_message_complete = on_message_complete ;
1207
-
1208
- parser_settings_initialized = true;
1209
- }
1210
-
1211
- return & parser_settings ;
1212
- }
1213
-
1214
1142
GIT_INLINE (int ) client_read_and_parse (git_http_client * client )
1215
1143
{
1216
- http_parser_t * parser = & client -> parser ;
1144
+ git_http_parser * parser = & client -> parser ;
1217
1145
http_parser_context * ctx = (http_parser_context * ) parser -> data ;
1218
1146
unsigned char http_errno ;
1219
1147
int read_len ;
@@ -1230,7 +1158,7 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client)
1230
1158
parsed_len = git_http_parser_execute (parser ,
1231
1159
client -> read_buf .ptr ,
1232
1160
client -> read_buf .size );
1233
- http_errno = git_http_parser_errno (client -> parser );
1161
+ http_errno = git_http_parser_errno (parser );
1234
1162
1235
1163
if (parsed_len > INT_MAX ) {
1236
1164
git_error_set (GIT_ERROR_HTTP , "unexpectedly large parse" );
@@ -1249,37 +1177,37 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client)
1249
1177
* (This can happen in response to an expect/continue request,
1250
1178
* where the server gives you a 100 and 200 simultaneously.)
1251
1179
*/
1252
- if (http_errno == HPE_PAUSED ) {
1253
- #ifndef USE_LLHTTP
1254
- /*
1255
- * http-parser has a "feature" where it will not deliver the
1256
- * final byte when paused in a callback. Consume that byte.
1257
- * https://github.com/nodejs/http-parser/issues/97
1258
- */
1259
- GIT_ASSERT (client -> read_buf .size > parsed_len );
1180
+ if (http_errno == GIT_HTTP_PARSER_PAUSED ) {
1181
+ size_t additional_size ;
1260
1182
1261
- #endif
1262
1183
git_http_parser_resume (parser );
1263
1184
1264
- #ifndef USE_LLHTTP
1265
- parsed_len += git_http_parser_execute (parser ,
1266
- client -> read_buf .ptr + parsed_len ,
1267
- 1 );
1268
- #endif
1185
+ /*
1186
+ * http-parser has a "feature" where it will not deliver
1187
+ * the final byte when paused in a callback. Consume
1188
+ * that byte.
1189
+ */
1190
+ if ((additional_size = git_http_parser_remain_after_pause (parser )) > 0 ) {
1191
+ GIT_ASSERT ((client -> read_buf .size - parsed_len ) >= additional_size );
1192
+
1193
+ parsed_len += git_http_parser_execute (parser ,
1194
+ client -> read_buf .ptr + parsed_len ,
1195
+ additional_size );
1196
+ }
1269
1197
}
1270
1198
1271
1199
/* Most failures will be reported in http_errno */
1272
- else if (git_http_parser_errno (client -> parser ) != HPE_OK ) {
1200
+ else if (git_http_parser_errno (parser ) != GIT_HTTP_PARSER_OK ) {
1273
1201
git_error_set (GIT_ERROR_HTTP , "http parser error: %s" ,
1274
- git_http_errno_description (parser , http_errno ));
1202
+ git_http_parser_errmsg (parser , http_errno ));
1275
1203
return -1 ;
1276
1204
}
1277
1205
1278
1206
/* Otherwise we should have consumed the entire buffer. */
1279
1207
else if (parsed_len != client -> read_buf .size ) {
1280
1208
git_error_set (GIT_ERROR_HTTP ,
1281
1209
"http parser did not consume entire buffer: %s" ,
1282
- git_http_errno_description (parser , http_errno ));
1210
+ git_http_parser_errmsg (parser , http_errno ));
1283
1211
return -1 ;
1284
1212
}
1285
1213
@@ -1318,7 +1246,7 @@ static void complete_response_body(git_http_client *client)
1318
1246
1319
1247
/* If there was an error, just close the connection. */
1320
1248
if (client_read_and_parse (client ) < 0 ||
1321
- parser_context .error != HPE_OK ||
1249
+ parser_context .error != GIT_HTTP_PARSER_OK ||
1322
1250
(parser_context .parse_status != PARSE_STATUS_OK &&
1323
1251
parser_context .parse_status != PARSE_STATUS_NO_OUTPUT )) {
1324
1252
git_error_clear ();
@@ -1596,7 +1524,7 @@ int git_http_client_skip_body(git_http_client *client)
1596
1524
do {
1597
1525
error = client_read_and_parse (client );
1598
1526
1599
- if (parser_context .error != HPE_OK ||
1527
+ if (parser_context .error != GIT_HTTP_PARSER_OK ||
1600
1528
(parser_context .parse_status != PARSE_STATUS_OK &&
1601
1529
parser_context .parse_status != PARSE_STATUS_NO_OUTPUT )) {
1602
1530
git_error_set (GIT_ERROR_HTTP ,
0 commit comments