7
7
8
8
#include "common.h"
9
9
#include "git2.h"
10
- #include "http_parser.h"
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
+
11
36
#include "vector.h"
12
37
#include "trace.h"
13
38
#include "httpclient.h"
@@ -108,7 +133,7 @@ struct git_http_client {
108
133
git_http_server_t current_server ;
109
134
http_client_state state ;
110
135
111
- http_parser parser ;
136
+ http_parser_t parser ;
112
137
113
138
git_http_server server ;
114
139
git_http_server proxy ;
@@ -154,7 +179,7 @@ void git_http_response_dispose(git_http_response *response)
154
179
memset (response ,0 ,sizeof (git_http_response ));
155
180
}
156
181
157
- static int on_header_complete (http_parser * parser )
182
+ static int on_header_complete (http_parser_t * parser )
158
183
{
159
184
http_parser_context * ctx = (http_parser_context * )parser -> data ;
160
185
git_http_client * client = ctx -> client ;
@@ -219,7 +244,7 @@ static int on_header_complete(http_parser *parser)
219
244
return 0 ;
220
245
}
221
246
222
- static int on_header_field (http_parser * parser ,const char * str ,size_t len )
247
+ static int on_header_field (http_parser_t * parser ,const char * str ,size_t len )
223
248
{
224
249
http_parser_context * ctx = (http_parser_context * )parser -> data ;
225
250
@@ -254,7 +279,7 @@ static int on_header_field(http_parser *parser, const char *str, size_t len)
254
279
return 0 ;
255
280
}
256
281
257
- static int on_header_value (http_parser * parser ,const char * str ,size_t len )
282
+ static int on_header_value (http_parser_t * parser ,const char * str ,size_t len )
258
283
{
259
284
http_parser_context * ctx = (http_parser_context * )parser -> data ;
260
285
@@ -342,7 +367,7 @@ static int resend_needed(git_http_client *client, git_http_response *response)
342
367
return 0 ;
343
368
}
344
369
345
- static int on_headers_complete (http_parser * parser )
370
+ static int on_headers_complete (http_parser_t * parser )
346
371
{
347
372
http_parser_context * ctx = (http_parser_context * )parser -> data ;
348
373
@@ -365,7 +390,7 @@ static int on_headers_complete(http_parser *parser)
365
390
}
366
391
367
392
ctx -> response -> status = parser -> status_code ;
368
- ctx -> client -> keepalive = http_should_keep_alive (parser );
393
+ ctx -> client -> keepalive = git_http_should_keep_alive (parser );
369
394
370
395
/* Prepare for authentication */
371
396
collect_authinfo (& ctx -> response -> server_auth_schemetypes ,
@@ -378,18 +403,28 @@ static int on_headers_complete(http_parser *parser)
378
403
ctx -> response -> resend_credentials = resend_needed (ctx -> client ,
379
404
ctx -> response );
380
405
381
- /* Stop parsing. */
382
- http_parser_pause (parser ,1 );
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
383
414
384
415
if (ctx -> response -> content_type || ctx -> response -> chunked )
385
416
ctx -> client -> state = READING_BODY ;
386
417
else
387
418
ctx -> client -> state = DONE ;
388
419
420
+ #ifdef USE_LLHTTP
421
+ return HPE_PAUSED ;
422
+ #else
389
423
return 0 ;
424
+ #endif
390
425
}
391
426
392
- static int on_body (http_parser * parser ,const char * buf ,size_t len )
427
+ static int on_body (http_parser_t * parser ,const char * buf ,size_t len )
393
428
{
394
429
http_parser_context * ctx = (http_parser_context * )parser -> data ;
395
430
size_t max_len ;
@@ -411,7 +446,7 @@ static int on_body(http_parser *parser, const char *buf, size_t len)
411
446
return 0 ;
412
447
}
413
448
414
- static int on_message_complete (http_parser * parser )
449
+ static int on_message_complete (http_parser_t * parser )
415
450
{
416
451
http_parser_context * ctx = (http_parser_context * )parser -> data ;
417
452
@@ -878,7 +913,7 @@ GIT_INLINE(int) server_setup_from_url(
878
913
879
914
static void reset_parser (git_http_client * client )
880
915
{
881
- http_parser_init (& client -> parser , HTTP_RESPONSE );
916
+ git_http_parser_init (& client -> parser );
882
917
}
883
918
884
919
static int setup_hosts (
@@ -1122,9 +1157,46 @@ GIT_INLINE(int) client_read(git_http_client *client)
1122
1157
}
1123
1158
1124
1159
static bool parser_settings_initialized ;
1125
- static http_parser_settings parser_settings ;
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
+ }
1126
1198
1127
- GIT_INLINE (http_parser_settings * )http_client_parser_settings (void )
1199
+ GIT_INLINE (http_settings_t * )http_client_parser_settings (void )
1128
1200
{
1129
1201
if (!parser_settings_initialized ) {
1130
1202
parser_settings .on_header_field = on_header_field ;
@@ -1141,7 +1213,7 @@ GIT_INLINE(http_parser_settings *) http_client_parser_settings(void)
1141
1213
1142
1214
GIT_INLINE (int )client_read_and_parse (git_http_client * client )
1143
1215
{
1144
- http_parser * parser = & client -> parser ;
1216
+ http_parser_t * parser = & client -> parser ;
1145
1217
http_parser_context * ctx = (http_parser_context * )parser -> data ;
1146
1218
unsignedchar http_errno ;
1147
1219
int read_len ;
@@ -1155,11 +1227,10 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client)
1155
1227
if (!client -> read_buf .size && (read_len = client_read (client ))< 0 )
1156
1228
return read_len ;
1157
1229
1158
- parsed_len = http_parser_execute (parser ,
1159
- http_client_parser_settings (),
1230
+ parsed_len = git_http_parser_execute (parser ,
1160
1231
client -> read_buf .ptr ,
1161
1232
client -> read_buf .size );
1162
- http_errno = client -> parser . http_errno ;
1233
+ http_errno = git_http_parser_errno ( client -> parser ) ;
1163
1234
1164
1235
if (parsed_len > INT_MAX ) {
1165
1236
git_error_set (GIT_ERROR_HTTP ,"unexpectedly large parse" );
@@ -1179,33 +1250,36 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client)
1179
1250
* where the server gives you a 100 and 200 simultaneously.)
1180
1251
*/
1181
1252
if (http_errno == HPE_PAUSED ) {
1253
+ #ifndef USE_LLHTTP
1182
1254
/*
1183
1255
* http-parser has a "feature" where it will not deliver the
1184
1256
* final byte when paused in a callback. Consume that byte.
1185
1257
* https://github.com/nodejs/http-parser/issues/97
1186
1258
*/
1187
1259
GIT_ASSERT (client -> read_buf .size > parsed_len );
1188
1260
1189
- http_parser_pause (parser ,0 );
1261
+ #endif
1262
+ git_http_parser_resume (parser );
1190
1263
1191
- parsed_len += http_parser_execute ( parser ,
1192
- http_client_parser_settings () ,
1264
+ #ifndef USE_LLHTTP
1265
+ parsed_len += git_http_parser_execute ( parser ,
1193
1266
client -> read_buf .ptr + parsed_len ,
1194
1267
1 );
1268
+ #endif
1195
1269
}
1196
1270
1197
1271
/* Most failures will be reported in http_errno */
1198
- else if (parser -> http_errno != HPE_OK ) {
1272
+ else if (git_http_parser_errno ( client -> parser ) != HPE_OK ) {
1199
1273
git_error_set (GIT_ERROR_HTTP ,"http parser error: %s" ,
1200
- http_errno_description ( http_errno ));
1274
+ git_http_errno_description ( parser , http_errno ));
1201
1275
return -1 ;
1202
1276
}
1203
1277
1204
1278
/* Otherwise we should have consumed the entire buffer. */
1205
1279
else if (parsed_len != client -> read_buf .size ) {
1206
1280
git_error_set (GIT_ERROR_HTTP ,
1207
1281
"http parser did not consume entire buffer: %s" ,
1208
- http_errno_description ( http_errno ));
1282
+ git_http_errno_description ( parser , http_errno ));
1209
1283
return -1 ;
1210
1284
}
1211
1285