nodejs/llhttp

How to handle one requests in multiple packet with llhttp

wxd237 opened this issue · 4 comments

wxd237 commented

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?

wxd237 commented

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 ,
image

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:

  1. 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.
  2. 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?

  1. 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;
}
  1. 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