llhttp

repository·main·Indexed 23 days ago

https://github.com/nodejs/llhttp

A high-performance, maintainable C parser for HTTP requests and responses, ported from http_parser using a TypeScript-based generation process. It provides a set of callbacks via llhttp_settings_t to handle parsing milestones and character-level data, along with functions to retrieve HTTP metadata and manage lenient parsing modes for non-compliant clients.

Tokens
4.5K
Snippets
9
Records
23
Agent score
71%

What's inside llhttp

  1. Overview of llhttp

    main
    llhttp is a high-performance HTTP parser. It is a port of the original http_parser to TypeScript using llparse to generate optimized C source code. It is designed to be more maintainable and verifiable than the original http_parser while providing significantly better performance (approximately 156% faster in benchmarks).
  2. Verify the build and tests locally

    main

    Before attempting a release, ensure the codebase is healthy by running the linting, build, and test suites locally. This prevents releasing broken code.

    Run the following commands in order:

    npm run lint
    npm run build
    npm run test
  3. Release a new version of llhttp using GitHub CLI

    main

    To release a new version, follow these steps. This method assumes you have the GitHub CLI installed and configured.

    1. Increase the version: Use npm version to increment the version number. This will trigger the postversion script and create a new release branch on GitHub.
      npm version [major|minor|patch]
    
    2. **Create the GitHub release**: Run the following command to create a draft release on GitHub. It will open in your browser for review and final publishing.
       ```bash
    npm run github-release

    CRITICAL WARNING: The package on NPM is no longer updated. NEVER RUN npm publish.

    npm version [major|minor|patch]
    npm run github-release
  4. Initialize and execute the llhttp parser

    main

    To use the parser, you must first initialize the settings and the parser instance, then feed data using llhttp_execute().

    • llhttp_settings_init(llhttp_settings_t* settings): Initializes the settings object.
    • llhttp_init(llhttp_t* parser, llhttp_type_t type, const llhttp_settings_t* settings): Initializes the parser with a specific type (e.g., HTTP request or response) and your custom settings.
    • llhttp_execute(llhttp_t* parser, const char* data, size_t len): Parses the provided data. If it returns HPE_OK, all input was consumed. If it returns HPE_PAUSED, you can resume using llhttp_resume() after advancing the input pointer to the position returned by llhttp_get_error_pos().
    • llhttp_finish(llhttp_t* parser): Call this when the connection is closed (EOF) to ensure any remaining data (like a body without a Content-Length) is processed.
  5. Create a GitHub release without GitHub CLI

    main

    If you do not have the GitHub CLI, you can manually create a release on GitHub using these steps. In these instructions, $VERSION refers to the new version tag (e.g., v6.0.9).

    1. Start Release: On GitHub, start creating a new release targeting tag $VERSION. Use the Generate release notes button to populate the description.
    2. Verify Changelog: Ensure the changelog notes correctly compare the previous version to the current version. The last line should look like: **Full Changelog**: https://github.com/nodejs/llhttp/compare/v6.0.8...v6.0.9.
    3. Set Target: Change the release target to point to the tag release/$VERSION.
    4. Publish: Review the details and publish the release.
  6. Build llhttp on Windows

    main

    To build on Windows, follow these steps:

    1. Install Dependencies using Chocolatey:
      • git
      • node
      • llvm (or C++ Clang tools for Windows via Visual Studio installer)
      • make (or use MinGW)
    2. Verify Path: Ensure Clang and make are in your system PATH.
    3. Clone and Build:
      • Clone the repository using Git Bash.
      • Navigate to the directory.
      • Run npm ci.
      • Run make.
    4. Locate Outputs: The compiled libraries (libllhttp.a and libllhttp.so) will be in the build directory.

    When building your own executable, include the build directory in your include path to access llhttp.h.

  7. Use llhttp in a CMake project

    main

    You can integrate llhttp into a CMake project using FetchContent. Note that you should use a release tarball URL rather than a git repository URL to ensure CMakeLists.txt string replacements work correctly.

    As a Shared Library

    Link against the llhttp_shared target.

    As a Static Library

    Set LLHTTP_BUILD_SHARED_LIBS to OFF and LLHTTP_BUILD_STATIC_LIBS to ON before calling FetchContent_MakeAvailable. Link against the llhttp_static target.

    Note: For versions prior to 9.3.0, use BUILD_SHARED_LIBS and BUILD_STATIC_LIBS instead of the LLHTTP_ prefixed versions.

    ### Shared Library
    ```cmake
    FetchContent_Declare(llhttp
      URL "https://github.com/nodejs/llhttp/archive/refs/tags/release/v8.1.0.tar.gz")
    
    FetchContent_MakeAvailable(llhttp)
    
    # Link with the llhttp_shared target
    target_link_libraries(${EXAMPLE_PROJECT_NAME} ${PROJECT_LIBRARIES} llhttp_shared ${PROJECT_NAME})

    Static Library

    FetchContent_Declare(llhttp
      URL "https://github.com/nodejs/llhttp/archive/refs/tags/release/v8.1.0.tar.gz")
    
    set(LLHTTP_BUILD_SHARED_LIBS OFF CACHE INTERNAL "")
    set(LLHTTP_BUILD_STATIC_LIBS ON CACHE INTERNAL "")
    FetchContent_MakeAvailable(llhttp)
    
    # Link with the llhttp_static target
    target_link_libraries(${EXAMPLE_PROJECT_NAME} ${PROJECT_LIBRARIES} llhttp_static ${PROJECT_NAME})
  8. Understand the IURLResult structure

    main

    The .build() method of the URL class returns an IURLResult object. This object contains two main sections: entry and exit.

    entry

    Contains the starting points for the parser:

    • normal: The node for a standard URL entry.
    • connect: The node for a connecting URL entry.

    exit

    Contains the exit points used for transitioning to HTTP protocols:

    • toHTTP: The node for transitioning to standard HTTP.
    • toHTTP09: The node for transitioning to HTTP/0.9.

    Each property contains Node objects (from llparse) that define how to match specific parts of the URL string.

  9. Troubleshoot linker errors on Windows

    main
    If you encounter unresolved external symbol linker errors when building on Windows, ensure you are linking not just llhttp.c, but also the object files from api.c and http.c.
  10. How to use llhttp in C

    main

    To use llhttp, you must initialize a llhttp_settings_t object with your desired callbacks, then initialize the llhttp_t parser using llhttp_init. You can then process data by calling llhttp_execute.

    Common workflow:

    1. Initialize settings with llhttp_settings_init(&settings).
    2. Assign user callbacks (e.g., settings.on_message_complete) to the settings object.
    3. Initialize the parser with llhttp_init(&parser, type, &settings). Use HTTP_BOTH to automatically detect whether to parse a request or a response.
    4. Execute the parser using llhttp_execute(&parser, data, length).
    5. Check the returned llhttp_errno to verify if the parsing was successful (HPE_OK).
    #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.
    	*/
    	tlhttp_init(&parser, HTTP_BOTH, &settings);
    
    	/*Parse request! */
    	const char* request = "GET / HTTP/1.1\r\n\r\n";
    	int request_len = strlen(request);
    
    	enum llhttp_errno err = llhttp_execute(&parser, request, request_len);
    	if (err == HPE_OK) {
    		fprintf(stdout, "Successfully parsed!\n");
    	} else {
    		fprintf(stderr, "Parse error: %s %s\n", llhttp_errno_name(err), llhttp_get_error_reason(&parser));
    	}
    }
  11. Handle errors and pauses in llhttp

    main

    When llhttp_execute() returns an error or a pause state, use the following to manage the state:

    • llhttp_get_errno(const llhttp_t* parser): Gets the latest error code.
    • llhttp_get_error_reason(const llhttp_t* parser): Gets the verbal explanation of the error.
    • llhttp_get_error_pos(const llhttp_t* parser): Returns a pointer to the last successfully parsed byte. Use this to know where to resume after a pause.
    • llhttp_set_error_reason(llhttp_t* parser, const char* reason): Allows you to set a custom error message from within a user callback (useful when returning HPE_USER).
    • llhttp_resume(llhttp_t* parser): Resumes execution after llhttp_execute() returns HPE_PAUSED.
    • llhttp_resume_after_upgrade(llhttp_t* parser): Resumes execution after llhttp_execute() returns HPE_PAUSED_UPGRADE (used for CONNECT/Upgrade requests).