### Parse Complete HTTP Request in Memory Source: https://context7.com/h2o/picohttpparser/llms.txt This example shows how to parse a complete HTTP request string directly from memory. It initializes the necessary structures and calls `phr_parse_request` with a zero `last_len` for a single-pass parse. Ensure the input string is null-terminated if using `strlen`. ```c /* Example: Parse a complete HTTP request in memory */ void example_parse_request(void) { const char *request = "GET /index.html HTTP/1.1\r\n" "Host: example.com\r\n" "User-Agent: MyClient/1.0\r\n" "Accept: text/html\r\n" "\r\n"; const char *method, *path; int minor_version; struct phr_header headers[16]; size_t method_len, path_len, num_headers = 16; int result = phr_parse_request(request, strlen(request), &method, &method_len, &path, &path_len, &minor_version, headers, &num_headers, 0); if (result > 0) { printf("Parsed %d bytes\n", result); printf("Method: %.*s, Path: %.*s, HTTP/1.%d\n", (int)method_len, method, (int)path_len, path, minor_version); /* Output: Parsed 82 bytes Method: GET, Path: /index.html, HTTP/1.1 */ } } ``` -------------------------------- ### Handle Parsed HTTP Headers Source: https://context7.com/h2o/picohttpparser/llms.txt Iterate through parsed headers using the `phr_header` structure. This example demonstrates how to access header names and values, including handling multiline headers where the name is NULL. ```c #include #include #include "picohttpparser.h" /* Work with parsed headers */ void example_header_handling(void) { const char *request = "GET / HTTP/1.0\r\n" "Host: example.com\r\n" "Accept: text/html\r\n" "X-Multi: first line\r\n" " continuation\r\n" /* Multiline header */ "\r\n"; const char *method, *path; int minor_version; struct phr_header headers[16]; size_t method_len, path_len, num_headers = 16; size_t i; phr_parse_request(request, strlen(request), &method, &method_len, &path, &path_len, &minor_version, headers, &num_headers, 0); /* Iterate through headers */ for (i = 0; i < num_headers; ++i) { if (headers[i].name != NULL) { /* Normal header */ printf("Header: %.*s = %.*s\n", (int)headers[i].name_len, headers[i].name, (int)headers[i].value_len, headers[i].value); } else { /* Continuation line (multiline header) */ printf(" Continuation: %.*s\n", (int)headers[i].value_len, headers[i].value); } } /* Find a specific header */ for (i = 0; i < num_headers; ++i) { if (headers[i].name_len == 4 && strncasecmp(headers[i].name, "Host", 4) == 0) { printf("Found Host: %.*s\n", (int)headers[i].value_len, headers[i].value); break; } } } ``` -------------------------------- ### Decode Chunked Data in Memory Source: https://context7.com/h2o/picohttpparser/llms.txt This example demonstrates decoding chunked encoded data directly from a memory buffer. The `phr_decode_chunked` function processes the buffer in-place. Ensure `consume_trailer` is set appropriately if trailing headers are expected. ```c /* Example: Decode chunked data in memory */ void example_decode_chunked(void) { /* Chunked encoded data: "hello " (6 bytes) + "world" (5 bytes) */ char buf[] = "6\r\nhello \r\n5\r\nworld\r\n0\r\n\r\n"; size_t bufsz = strlen(buf); struct phr_chunked_decoder decoder = {0}; decoder.consume_trailer = 1; ssize_t ret = phr_decode_chunked(&decoder, buf, &bufsz); if (ret >= 0) { printf("Decoded %zu bytes: %.*s\n", bufsz, (int)bufsz, buf); printf("Leftover bytes: %zd\n", ret); /* Output: Decoded 11 bytes: hello world Leftover bytes: 0 */ } } ``` -------------------------------- ### Handle Trailing Headers Manually Source: https://context7.com/h2o/picohttpparser/llms.txt This example demonstrates how to manually parse trailing headers after decoding chunked data. Set `decoder.consume_trailer` to 0 to prevent automatic consumption. The function returns the offset and length of the trailing headers, which can then be parsed using `phr_parse_headers`. ```c /* Example: Handle trailing headers manually */ void example_chunked_with_trailers(void) { char buf[] = "b\r\nhello world\r\n0\r\nX-Checksum: abc123\r\n\r\n"; size_t bufsz = strlen(buf); struct phr_chunked_decoder decoder = {0}; decoder.consume_trailer = 0; /* Don't consume trailers */ ssize_t ret = phr_decode_chunked(&decoder, buf, &bufsz); if (ret > 0) { printf("Decoded body: %.*s\n", (int)bufsz, buf); printf("Trailing headers at offset %zu, length %zd\n", bufsz, ret); /* Parse trailing headers */ struct phr_header headers[4]; size_t num_headers = 4; phr_parse_headers(buf + bufsz, ret, headers, &num_headers, 0); printf("Trailer: %.*s: %.*s\n", (int)headers[0].name_len, headers[0].name, (int)headers[0].value_len, headers[0].value); } } ``` -------------------------------- ### Decode Chunked Data with Chunk Extensions Source: https://context7.com/h2o/picohttpparser/llms.txt This example shows how `phr_decode_chunked` handles chunk extensions, such as `comment=hi`, by ignoring them during decoding. The function focuses on the data payload. Trailing headers are automatically consumed if `consume_trailer` is set to 1. ```c /* Example: Decode chunked data with chunk extensions (ignored) */ void example_chunked_with_extensions(void) { char buf[] = "6;comment=hi\r\nhello \r\n5\r\nworld\r\n0\r\n\r\n"; size_t bufsz = strlen(buf); struct phr_chunked_decoder decoder = {0}; decoder.consume_trailer = 1; ssize_t ret = phr_decode_chunked(&decoder, buf, &bufsz); if (ret >= 0) { printf("Decoded: %.*s\n", (int)bufsz, buf); /* Output: Decoded: hello world */ } } ``` -------------------------------- ### Initialize and Configure Chunked Decoder Source: https://context7.com/h2o/picohttpparser/llms.txt Demonstrates two methods for zero-initializing the `phr_chunked_decoder` structure: using a compound literal or `memset`. It also shows how to configure the `consume_trailer` option. ```c #include #include #include "picohttpparser.h" /* Initialize and configure chunked decoder */ void example_decoder_setup(void) { /* Method 1: Zero initialization with compound literal */ struct phr_chunked_decoder dec1 = {0}; /* Method 2: memset */ struct phr_chunked_decoder dec2; memset(&dec2, 0, sizeof(dec2)); /* Configure options */ dec1.consume_trailer = 1; /* Auto-consume trailing headers */ /* The decoder tracks internal state: * - bytes_left_in_chunk: remaining bytes in current chunk * - _state: internal parsing state * - _hex_count: hex digits parsed in chunk size * - _total_read: total bytes processed (for overhead detection) * - _total_overhead: overhead bytes (for DoS protection) */ } ``` -------------------------------- ### Parse HTTP Request from Socket Incrementally Source: https://context7.com/h2o/picohttpparser/llms.txt This function demonstrates how to parse an HTTP request from a socket using incremental buffering. It handles partial requests and protects against slowloris attacks by using the `prevbuflen` parameter. Ensure the buffer size is sufficient or implement dynamic resizing for very large requests. ```c #include #include #include #include #include #include "picohttpparser.h" /* Parse HTTP request from socket with incremental buffering */ int parse_http_request(int sock) { char buf[4096]; const char *method, *path; int pret, minor_version; struct phr_header headers[100]; size_t buflen = 0, prevbuflen = 0, method_len, path_len, num_headers; ssize_t rret; size_t i; while (1) { /* Read data from socket */ while ((rret = read(sock, buf + buflen, sizeof(buf) - buflen)) == -1 && errno == EINTR) ; if (rret <= 0) return -1; /* IO error */ prevbuflen = buflen; buflen += rret; /* Parse the request */ num_headers = sizeof(headers) / sizeof(headers[0]); pret = phr_parse_request(buf, buflen, &method, &method_len, &path, &path_len, &minor_version, headers, &num_headers, prevbuflen); if (pret > 0) break; /* Successfully parsed */ else if (pret == -1) return -1; /* Parse error */ /* pret == -2: request is incomplete, continue reading */ assert(pret == -2); if (buflen == sizeof(buf)) return -1; /* Request too long */ } /* Print parsed request details */ printf("Request length: %d bytes\n", pret); printf("Method: %.*s\n", (int)method_len, method); printf("Path: %.*s\n", (int)path_len, path); printf("HTTP version: 1.%d\n", minor_version); printf("Headers (%zu):\n", num_headers); for (i = 0; i < num_headers; ++i) { printf(" %.*s: %.*s\n", (int)headers[i].name_len, headers[i].name, (int)headers[i].value_len, headers[i].value); } return pret; } ``` -------------------------------- ### Parse HTTP Response from Memory Source: https://context7.com/h2o/picohttpparser/llms.txt Parses a complete HTTP response string directly from memory. Initializes header array and other variables. Ensure the input string is a valid HTTP response. ```c /* Example: Parse a complete HTTP response in memory */ void example_parse_response(void) { const char *response = "HTTP/1.1 200 OK\r\n" "Content-Type: text/html\r\n" "Content-Length: 1234\r\n" "Connection: keep-alive\r\n" "\r\n"; const char *msg; int minor_version, status; struct phr_header headers[16]; size_t msg_len, num_headers = 16; int result = phr_parse_response(response, strlen(response), &minor_version, &status, &msg, &msg_len, headers, &num_headers, 0); if (result > 0) { printf("Parsed %d bytes\n", result); printf("HTTP/1.%d %d %.*s\n", minor_version, status, (int)msg_len, msg); /* Output: Parsed 82 bytes HTTP/1.1 200 OK */ } } ``` -------------------------------- ### Reuse Chunked Decoder for Multiple Requests Source: https://context7.com/h2o/picohttpparser/llms.txt Illustrates how to reuse a `phr_chunked_decoder` instance for multiple chunked bodies on the same connection. Crucially, the decoder must be re-zero-initialized before processing each new request. ```c #include #include #include "picohttpparser.h" /* Reuse decoder for multiple requests on same connection */ void example_decoder_reuse(void) { struct phr_chunked_decoder decoder = {0}; decoder.consume_trailer = 1; /* First chunked body */ char buf1[] = "5\r\nhello\r\n0\r\n\r\n"; size_t bufsz1 = strlen(buf1); phr_decode_chunked(&decoder, buf1, &bufsz1); printf("First body: %.*s\n", (int)bufsz1, buf1); /* Reset for next request - must zero-initialize again */ memset(&decoder, 0, sizeof(decoder)); decoder.consume_trailer = 1; /* Second chunked body */ char buf2[] = "5\r\nworld\r\n0\r\n\r\n"; size_t bufsz2 = strlen(buf2); phr_decode_chunked(&decoder, buf2, &bufsz2); printf("Second body: %.*s\n", (int)bufsz2, buf2); } ``` -------------------------------- ### phr_parse_request API Source: https://github.com/h2o/picohttpparser/blob/master/README.md Demonstrates how to parse an HTTP request from a buffer using phr_parse_request. It reads data, parses the request line and headers, and extracts details like method, path, version, and headers. ```APIDOC ## phr_parse_request ### Description Parses an HTTP request from a given buffer. It extracts the request method, path, HTTP version, and headers. ### Method C Function ### Endpoint N/A (Library Function) ### Parameters - **buf** (char*) - Pointer to the buffer containing the HTTP request. - **buflen** (size_t) - The length of the data in the buffer. - **method** (char**) - Output pointer to the start of the HTTP method string. - **method_len** (size_t*) - Output pointer to the length of the HTTP method string. - **path** (char**) - Output pointer to the start of the request path string. - **path_len** (size_t*) - Output pointer to the length of the request path string. - **minor_version** (int*) - Output pointer to the HTTP minor version (e.g., 0 for HTTP/1.0, 1 for HTTP/1.1). - **headers** (struct phr_header*) - Array to store parsed headers. - **num_headers** (size_t*) - Input: maximum number of headers to parse. Output: number of headers parsed. - **prevbuflen** (size_t) - The length of the buffer processed in the previous call (for incremental parsing). ### Return Value - **Positive integer**: The total number of bytes consumed from the buffer upon successful parsing. - **0**: The request is incomplete and more data is needed. - **-1**: An error occurred during parsing. - **-2**: The request is incomplete, and the buffer is full. ### Request Example ```c char buf[4096], *method, *path; int pret, minor_version; struct phr_header headers[100]; size_t buflen = 0, prevbuflen = 0, method_len, path_len, num_headers; ssize_t rret; while (1) { /* read the request */ while ((rret = read(sock, buf + buflen, sizeof(buf) - buflen)) == -1 && errno == EINTR) ; if (rret <= 0) return IOError; prevbuflen = buflen; buflen += rret; /* parse the request */ num_headers = sizeof(headers) / sizeof(headers[0]); pret = phr_parse_request(buf, buflen, &method, &method_len, &path, &path_len, &minor_version, headers, &num_headers, prevbuflen); if (pret > 0) break; /* successfully parsed the request */ else if (pret == -1) return ParseError; /* request is incomplete, continue the loop */ assert(pret == -2); if (buflen == sizeof(buf)) return RequestIsTooLongError; } printf("request is %d bytes long\n", pret); printf("method is %.*s\n", (int)method_len, method); printf("path is %.*s\n", (int)path_len, path); printf("HTTP version is 1.%d\n", minor_version); printf("headers:\n"); for (i = 0; i != num_headers; ++i) { printf("%.*s: %.*s\n", (int)headers[i].name_len, headers[i].name, (int)headers[i].value_len, headers[i].value); } ``` ### Response N/A (This is a parsing function, not an API endpoint) ### Error Handling - **IOError**: Error during read operation. - **ParseError**: Error during parsing. - **RequestIsTooLongError**: Request exceeds buffer size. ``` -------------------------------- ### Parse Trailing Headers After Chunked Body with picohttpparser Source: https://context7.com/h2o/picohttpparser/llms.txt This function demonstrates parsing trailing headers that appear after a chunked HTTP body. It uses `phr_parse_headers` to process the header data. Ensure the `trailing_headers` buffer and its length are correctly provided. ```c /* Parse trailing headers after chunked body */ void parse_trailing_headers(const char *trailing_headers, size_t len) { struct phr_header headers[16]; size_t num_headers = 16; size_t i; int result = phr_parse_headers(trailing_headers, len, headers, &num_headers, 0); if (result > 0) { printf("Trailing headers:\n"); for (i = 0; i < num_headers; ++i) { printf(" %.*s: %.*s\n", (int)headers[i].name_len, headers[i].name, (int)headers[i].value_len, headers[i].value); } } } ``` -------------------------------- ### Parse HTTP Response Incrementally Source: https://context7.com/h2o/picohttpparser/llms.txt Reads and parses an HTTP response from a socket incrementally. Handles partial responses and IO errors. Ensure the buffer size is sufficient or implement dynamic resizing. ```c #include #include #include #include #include #include "picohttpparser.h" /* Parse HTTP response from socket with incremental buffering */ int parse_http_response(int sock) { char buf[4096]; const char *msg; int pret, minor_version, status; struct phr_header headers[100]; size_t buflen = 0, prevbuflen = 0, msg_len, num_headers; ssize_t rret; size_t i; while (1) { /* Read data from socket */ while ((rret = read(sock, buf + buflen, sizeof(buf) - buflen)) == -1 && errno == EINTR) ; if (rret <= 0) return -1; /* IO error */ prevbuflen = buflen; buflen += rret; /* Parse the response */ num_headers = sizeof(headers) / sizeof(headers[0]); pret = phr_parse_response(buf, buflen, &minor_version, &status, &msg, &msg_len, headers, &num_headers, prevbuflen); if (pret > 0) break; /* Successfully parsed */ else if (pret == -1) return -1; /* Parse error */ /* pret == -2: response is incomplete, continue reading */ assert(pret == -2); if (buflen == sizeof(buf)) return -1; /* Response too long */ } /* Print parsed response details */ printf("Response length: %d bytes\n", pret); printf("HTTP version: 1.%d\n", minor_version); printf("Status: %d %.*s\n", status, (int)msg_len, msg); printf("Headers (%zu):\n", num_headers); for (i = 0; i < num_headers; ++i) { printf(" %.*s: %.*s\n", (int)headers[i].name_len, headers[i].name, (int)headers[i].value_len, headers[i].value); } return pret; } ``` -------------------------------- ### Parse Standalone HTTP Headers with picohttpparser Source: https://context7.com/h2o/picohttpparser/llms.txt Use `phr_parse_headers` to parse HTTP headers when the request or status line is not present. Ensure sufficient space in the `headers` array. The function returns the number of bytes consumed on success. ```c #include #include #include "picohttpparser.h" /* Parse standalone HTTP headers */ void example_parse_headers(void) { const char *headers_str = "Host: example.com\r\n" "Content-Type: application/json\r\n" "X-Custom-Header: custom-value\r\n" "\r\n"; struct phr_header headers[16]; size_t num_headers = 16; size_t i; int result = phr_parse_headers(headers_str, strlen(headers_str), headers, &num_headers, 0); if (result > 0) { printf("Parsed %d bytes, found %zu headers:\n", result, num_headers); for (i = 0; i < num_headers; ++i) { printf(" %.*s: %.*s\n", (int)headers[i].name_len, headers[i].name, (int)headers[i].value_len, headers[i].value); } /* Output: Parsed 75 bytes, found 3 headers: Host: example.com Content-Type: application/json X-Custom-Header: custom-value */ } } ``` -------------------------------- ### Decode Chunked Encoding Source: https://github.com/h2o/picohttpparser/blob/master/README.md Decodes incoming data in chunked-encoding format in-place. Set `consume_trailer` to 1 to discard trailing headers, otherwise, they must be parsed separately using `phr_parse_headers`. ```c struct phr_chunked_decoder decoder = {}; /* zero-clear */ char *buf = malloc(4096); size_t size = 0, capacity = 4096, rsize; ssize_t rret, pret; /* set consume_trailer to 1 to discard the trailing header, or the application * should call phr_parse_headers to parse the trailing header */ decoder.consume_trailer = 1; do { /* expand the buffer if necessary */ if (size == capacity) { capacity *= 2; buf = realloc(buf, capacity); assert(buf != NULL); } /* read */ while ((rret = read(sock, buf + size, capacity - size)) == -1 && errno == EINTR) ; if (rret <= 0) return IOError; /* decode */ rsize = rret; pret = phr_decode_chunked(&decoder, buf + size, &rsize); if (pret == -1) return ParseError; size += rsize; } while (pret == -2); /* successfully decoded the chunked data */ assert(pret >= 0); printf("decoded data is at %p (%zu bytes)\n", buf, size); ``` -------------------------------- ### phr_parse_request - HTTP Request Parsing Source: https://context7.com/h2o/picohttpparser/llms.txt Parses an HTTP request from a buffer, extracting method, path, version, and headers. Supports incremental parsing. ```APIDOC ## phr_parse_request - HTTP Request Parsing ### Description Parses an HTTP request from a buffer. The function extracts the HTTP method, path, HTTP version, and all headers from the request. It returns the number of bytes consumed if successful, -2 if the request is partial (incomplete), or -1 if parsing failed. The `last_len` parameter enables incremental parsing by indicating how many bytes were already examined in previous calls, which also provides protection against slowloris attacks. ### Method `int phr_parse_request(const char *buf, size_t len, const char **method, size_t *method_len, const char **path, size_t *path_len, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len);` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters (for `phr_parse_request` function) - **buf** (const char *) - Pointer to the buffer containing the HTTP request. - **len** (size_t) - The length of the buffer. - **method** (const char **) - Output parameter: Pointer to the start of the HTTP method string. - **method_len** (size_t *) - Output parameter: Pointer to the length of the HTTP method string. - **path** (const char **) - Output parameter: Pointer to the start of the request path string. - **path_len** (size_t *) - Output parameter: Pointer to the length of the request path string. - **minor_version** (int *) - Output parameter: Pointer to the HTTP minor version (e.g., 1 for HTTP/1.1). - **headers** (struct phr_header *) - Output parameter: Array to store parsed headers. Each element is a `phr_header` struct containing `name`, `name_len`, `value`, and `value_len`. - **num_headers** (size_t *) - Input/Output parameter: On input, the maximum number of headers to parse. On output, the number of headers actually parsed. - **last_len** (size_t) - The number of bytes already examined in previous calls (for incremental parsing). ### Return Value - **Success**: The number of bytes consumed from the buffer. - **Partial Request**: -2 (if the request is incomplete). - **Parse Error**: -1 (if parsing failed). ### Request Example (Conceptual C code) ```c char buf[4096]; size_t buflen = 0; // ... read data into buf ... const char *method, *path; int minor_version; struct phr_header headers[100]; size_t num_headers = 100; int pret = phr_parse_request(buf, buflen, &method, &method_len, &path, &path_len, &minor_version, headers, &num_headers, 0); if (pret > 0) { // Successfully parsed } else if (pret == -2) { // Incomplete request, read more data } else { // Parse error } ``` ### Response #### Success Response (200) This function does not return a standard HTTP response. Instead, it returns an integer indicating the parsing status and populates output parameters with request details. #### Response Example (Parsed Data) If `phr_parse_request` returns a positive value `pret`: - **Method**: A string representing the HTTP method (e.g., "GET"). - **Path**: A string representing the request path (e.g., "/index.html"). - **HTTP Version**: An integer representing the minor version (e.g., 1 for HTTP/1.1). - **Headers**: An array of `phr_header` structs, each containing header name and value. ```c // Example of accessing parsed data: printf("Method: %.*s\n", (int)method_len, method); printf("Path: %.*s\n", (int)path_len, path); printf("HTTP version: 1.%d\n", minor_version); for (size_t i = 0; i < num_headers; ++i) { printf(" %.*s: %.*s\n", (int)headers[i].name_len, headers[i].name, (int)headers[i].value_len, headers[i].value); } ``` ``` -------------------------------- ### phr_parse_response and phr_parse_headers API Source: https://github.com/h2o/picohttpparser/blob/master/README.md Details the functions phr_parse_response and phr_parse_headers, which are similar to phr_parse_request but are used for parsing HTTP responses and headers respectively. ```APIDOC ## phr_parse_response, phr_parse_headers ### Description `phr_parse_response` and `phr_parse_headers` provide similar interfaces to `phr_parse_request`. `phr_parse_response` is used to parse an HTTP response, while `phr_parse_headers` parses only the headers section of an HTTP message. ### Method C Function ### Endpoint N/A (Library Functions) ### Parameters (Similar to `phr_parse_request`, with parameters adjusted for response or header parsing) ### Return Value (Similar to `phr_parse_request`, indicating success, incompleteness, or error) ### Request Example N/A (Usage examples are similar to `phr_parse_request` but adapted for responses or headers) ### Response N/A (These are parsing functions, not API endpoints) ### Error Handling (Similar error conditions as `phr_parse_request` may apply, depending on the specific function used.) ``` -------------------------------- ### phr_decode_chunked API Source: https://github.com/h2o/picohttpparser/blob/master/README.md Explains how to use phr_decode_chunked to decode data encoded using HTTP chunked transfer encoding. It handles buffer management and in-place decoding. ```APIDOC ## phr_decode_chunked ### Description Decodes incoming data that is encoded using HTTP chunked transfer encoding. The decoding is performed in-place within the provided buffer. ### Method C Function ### Endpoint N/A (Library Function) ### Parameters - **decoder** (struct phr_chunked_decoder*) - A pointer to a `phr_chunked_decoder` structure, which should be zero-initialized before the first call. This structure maintains the state of the decoding process. - **buf** (char*) - A pointer to the buffer containing the chunked-encoded data to be decoded. - **size** (size_t*) - On input, the number of bytes available in `buf`. On output, the number of bytes successfully decoded and available in `buf` (after in-place modification). ### Request Body N/A (This function operates on raw data buffers) ### Return Value - **Positive integer**: Indicates the total number of bytes consumed from the input buffer and successfully decoded. The decoded data is available in `buf` up to the new `size`. - **0**: Decoding is complete, and any trailing headers have been processed (if `consume_trailer` was set to 1). - **-1**: An error occurred during decoding. - **-2**: The chunked data is incomplete, and more data needs to be read and processed. ### Request Example ```c struct phr_chunked_decoder decoder = {}; /* zero-clear */ char *buf = malloc(4096); size_t size = 0, capacity = 4096, rsize; ssize_t rret, pret; /* set consume_trailer to 1 to discard the trailing header, or the application * should call phr_parse_headers to parse the trailing header */ decoder.consume_trailer = 1; do { /* expand the buffer if necessary */ if (size == capacity) { capacity *= 2; buf = realloc(buf, capacity); assert(buf != NULL); } /* read */ while ((rret = read(sock, buf + size, capacity - size)) == -1 && errno == EINTR) ; if (rret <= 0) return IOError; /* decode */ rsize = rret; pret = phr_decode_chunked(&decoder, buf + size, &rsize); if (pret == -1) return ParseError; size += rsize; } while (pret == -2); /* successfully decoded the chunked data */ assert(pret >= 0); printf("decoded data is at %p (%zu bytes)\n", buf, size); ``` ### Response N/A (This is a decoding function, not an API endpoint) ### Error Handling - **IOError**: Error during read operation. - **ParseError**: Error during decoding. - **Memory Allocation Error**: If `malloc` or `realloc` fails. ``` -------------------------------- ### Parse HTTP Request Source: https://github.com/h2o/picohttpparser/blob/master/README.md Reads an HTTP request from a socket, parses it using phr_parse_request, and prints request details. Ensure the buffer is large enough to hold the entire request or handle partial reads. ```c char buf[4096], *method, *path; int pret, minor_version; struct phr_header headers[100]; size_t buflen = 0, prevbuflen = 0, method_len, path_len, num_headers; ssize_t rret; while (1) { /* read the request */ while ((rret = read(sock, buf + buflen, sizeof(buf) - buflen)) == -1 && errno == EINTR) ; if (rret <= 0) return IOError; prevbuflen = buflen; buflen += rret; /* parse the request */ num_headers = sizeof(headers) / sizeof(headers[0]); pret = phr_parse_request(buf, buflen, &method, &method_len, &path, &path_len, &minor_version, headers, &num_headers, prevbuflen); if (pret > 0) break; /* successfully parsed the request */ else if (pret == -1) return ParseError; /* request is incomplete, continue the loop */ assert(pret == -2); if (buflen == sizeof(buf)) return RequestIsTooLongError; } printf("request is %d bytes long\n", pret); printf("method is %.*s\n", (int)method_len, method); printf("path is %.*s\n", (int)path_len, path); printf("HTTP version is 1.%d\n", minor_version); printf("headers:\n"); for (i = 0; i != num_headers; ++i) { printf(".*s: %.*s\n", (int)headers[i].name_len, headers[i].name, (int)headers[i].value_len, headers[i].value); } ``` -------------------------------- ### Decode Chunked Transfer Encoding from Socket Source: https://context7.com/h2o/picohttpparser/llms.txt This function reads data from a socket, decodes chunked transfer encoding in-place, and expands the buffer as needed. It returns 0 on success, -1 on error, or -2 if more data is required. Ensure the `phr_chunked_decoder` struct is zero-initialized before use. ```c #include #include #include #include #include #include #include "picohttpparser.h" /* Decode chunked transfer encoding from socket */ int decode_chunked_body(int sock, char **decoded_buf, size_t *decoded_size) { struct phr_chunked_decoder decoder = {0}; /* Must be zero-initialized */ char *buf; size_t size = 0, capacity = 4096, rsize; ssize_t rret, pret; /* Set consume_trailer to 1 to discard trailing headers automatically, * or 0 if you want to parse them using phr_parse_headers */ decoder.consume_trailer = 1; buf = malloc(capacity); if (!buf) return -1; do { /* Expand buffer if necessary */ if (size == capacity) { capacity *= 2; buf = realloc(buf, capacity); if (!buf) return -1; } /* Read data from socket */ while ((rret = read(sock, buf + size, capacity - size)) == -1 && errno == EINTR) ; if (rret <= 0) { free(buf); return -1; } /* Decode chunked data in-place */ rsize = rret; pret = phr_decode_chunked(&decoder, buf + size, &rsize); if (pret == -1) { free(buf); return -1; /* Parse error */ } size += rsize; } while (pret == -2); /* -2 means incomplete, continue reading */ /* Successfully decoded */ assert(pret >= 0); *decoded_buf = buf; *decoded_size = size; printf("Decoded %zu bytes of chunked data\n", size); return 0; } ``` -------------------------------- ### phr_decode_chunked Function Source: https://context7.com/h2o/picohttpparser/llms.txt Decodes chunked transfer encoding in-place. It rewrites the buffer by removing chunked encoding headers and returns the decoded data. The function maintains state in a `phr_chunked_decoder` struct which must be zero-initialized before first use. It returns a non-negative number indicating bytes left undecoded on success, -2 if incomplete, or -1 on error. The `consume_trailer` parameter controls whether trailing headers are automatically discarded or parsed separately. ```APIDOC ## phr_decode_chunked ### Description Decodes chunked transfer encoding in-place. The function rewrites the buffer by removing chunked encoding headers and returns the decoded data. It maintains state in a `phr_chunked_decoder` struct which must be zero-initialized before first use. Returns a non-negative number indicating bytes left undecoded on success, -2 if incomplete, or -1 on error. Set `consume_trailer` to 1 to automatically discard trailing headers, or 0 to parse them separately using `phr_parse_headers`. ### Parameters #### Request Body - **decoder** (`struct phr_chunked_decoder*`) - Pointer to a `phr_chunked_decoder` struct. Must be zero-initialized before first use. - **buf** (`char*`) - Pointer to the buffer containing chunked encoded data. This buffer will be modified in-place. - **bufsz** (`size_t*`) - Pointer to the size of the buffer. This will be updated to reflect the size of the decoded data. - **consume_trailer** (`int`) - If 1, automatically discard trailing headers. If 0, parse them separately using `phr_parse_headers`. ### Return Value - Non-negative number: Bytes left undecoded on success. - -2: Incomplete data, more data is needed. - -1: Error during decoding. ### Example Usage (C) ```c #include "picohttpparser.h" #include #include #include void example_decode_chunked(void) { char buf[] = "6\r\nhello \r\n5\r\nworld\r\n0\r\n\r\n"; size_t bufsz = strlen(buf); struct phr_chunked_decoder decoder = {0}; decoder.consume_trailer = 1; ssize_t ret = phr_decode_chunked(&decoder, buf, &bufsz); if (ret >= 0) { printf("Decoded %zu bytes: %.*s\n", bufsz, (int)bufsz, buf); printf("Leftover bytes: %zd\n", ret); } } ``` ### Example with Trailing Headers (C) ```c #include "picohttpparser.h" #include #include #include void example_chunked_with_trailers(void) { char buf[] = "b\r\nhello world\r\n0\r\nX-Checksum: abc123\r\n\r\n"; size_t bufsz = strlen(buf); struct phr_chunked_decoder decoder = {0}; decoder.consume_trailer = 0; /* Don't consume trailers */ ssize_t ret = phr_decode_chunked(&decoder, buf, &bufsz); if (ret > 0) { printf("Decoded body: %.*s\n", (int)bufsz, buf); printf("Trailing headers at offset %zu, length %zd\n", bufsz, ret); /* Parse trailing headers */ struct phr_header headers[4]; size_t num_headers = 4; phr_parse_headers(buf + bufsz, ret, headers, &num_headers, 0); printf("Trailer: %.*s: %.*s\n", (int)headers[0].name_len, headers[0].name, (int)headers[0].value_len, headers[0].value); } } ``` ``` -------------------------------- ### Check Chunked Decoder State Source: https://context7.com/h2o/picohttpparser/llms.txt Use `phr_decode_chunked_is_in_data` to determine if the chunked decoder is currently processing chunk data or headers. This is useful for understanding the parser's state during incremental processing. ```c #include #include #include "picohttpparser.h" /* Check decoder state during incremental parsing */ void example_check_decoder_state(void) { struct phr_chunked_decoder decoder = {0}; decoder.consume_trailer = 1; /* First chunk: just the header */ char buf1[] = "b\r\n"; size_t bufsz1 = strlen(buf1); phr_decode_chunked(&decoder, buf1, &bufsz1); printf("After chunk header: in_data=%d\n", phr_decode_chunked_is_in_data(&decoder)); /* Output: After chunk header: in_data=1 */ /* Feed chunk data */ char buf2[] = "hello world\r\n0\r\n\r\n"; size_t bufsz2 = strlen(buf2); phr_decode_chunked(&decoder, buf2, &bufsz2); printf("After complete decode: in_data=%d\n", phr_decode_chunked_is_in_data(&decoder)); /* Output: After complete decode: in_data=0 */ } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.