How to handle one requests in multiple packet with llhttp
wxd237 opened this issue · 4 comments
For example: multiple packet one requests
std::vector buf;
first recv:
buf="GET /index.html HTTP/1.1\r\nContent-Length:4\r\n";
second recv:
buf="GET /index.html HTTP/1.1\r\nContent-Length:4\r\nABCD";
how can I know the pos the parse ;
that I can continue the parse.
You can't really do from the the outside.
But you can do within a callback (such on_message_complete
) where the first argument will be the current data position of the parser (as a const char*
) and thus you can use pointer arithmetics.
This is the technique used in tests, see:
https://github.com/nodejs/llparse-test-fixture/blob/main/src/native/fixture.c#L61
Does it answer your question?
for the code
#include "stdio.h"
#include "llhttp.h"
#include "string.h"
int handle_on_message_complete(llhttp_t* parser) {
fprintf(stdout, "Message completed!\n");
return 0;
}
int main() {
llhttp_t parser;
llhttp_settings_t settings;
/*Initialize user callbacks and settings */
llhttp_settings_init(&settings);
/*Set user callback */
settings.on_message_complete = handle_on_message_complete;
/*Initialize the parser in HTTP_BOTH mode, meaning that it will select between
*HTTP_REQUEST and HTTP_RESPONSE parsing automatically while reading the first
*input.
*/
llhttp_init(&parser, HTTP_BOTH, &settings);
/*Parse request! */
const char* request = "GET / HTTP/1.1\r\n\r\n";
int request_len = strlen(request);
printf("first execute------------\n");
enum llhttp_errno err = llhttp_execute(&parser, request, request_len-1);
if (err == HPE_OK) {
fprintf(stdout, "Successfully parsed!\n");
} else {
fprintf(stderr, "Parse error: %s %s\n", llhttp_errno_name(err), parser.reason);
}
const char *p=request+request_len-1;
printf("second execute--------\n");
err = llhttp_execute(&parser, p, 1);
if (err == HPE_OK) {
fprintf(stdout, "Successfully parsed!\n");
} else {
fprintf(stderr, "Parse error: %s %s\n", llhttp_errno_name(err), parser.reason);
}
}
after the first execute,how can i get the p.
I already see https://github.com/nodejs/llhttp/issues/176
,
the is not have cursor in my version of llhttp ,i use llhttp 8.1.1
I tried. Apparently is not possible as of today.
llhttp tries to do a zero-copy parsing so it does not track the position on the input, especially since the input can be fed to the parser in a "streaming way":
const char* request_part1 = "GET / HTTP";
const char* request_part2 = "/1.1\r\n\r\n";
int request_part1_len = strlen(request_part1);
int request_part2_len = strlen(request_part2);
enum llhttp_errno err1 = llhttp_execute(&parser, request_part1, request_part1_len-1);
if (err1 == HPE_OK) {
fprintf(stdout, "Successfully parsed!\n");
} else {
fprintf(stderr, "Parse error: %s %s\n", llhttp_errno_name(err1), parser.reason);
}
enum llhttp_errno err2 = llhttp_execute(&parser, request_part2, request_part2_len-1);
if (err2 == HPE_OK) {
fprintf(stdout, "Successfully parsed!\n");
} else {
fprintf(stderr, "Parse error: %s %s\n", llhttp_errno_name(err2), parser.reason);
}
I think there are two possible use case for your question here, so I'm giving you hint on both:
- If you feed multiple strings to the parser and all of them represent a complete HTTP message: you don't need to track position at all, the parser will reset itself automatically.
- If you feed one or more strings to the parser and any of them might represent a partial HTTP message (or a message plus a partial message), then you can use llhttp parser callbacks (like on_body) to track the position of the parser.
Does it answer your question?
- you can return HPE_PAUSED from message complete callback
int handle_on_message_complete(llhttp_t* parser) {
fprintf(stdout, "Message completed!\n");
return HPE_PAUSED;
}
- llhttp_execute(&parser, request,...) should stop at the end of first http message. you can get the last parsed byte by llhttp_get_error_pos().
const char *last_parsed_pos = llhttp_get_error_pos(&parser);
3.the next message should start at: last_parsed_pos-request+1