{"id":35643928,"url":"https://github.com/78/esp-http3","last_synced_at":"2026-01-05T12:05:39.954Z","repository":{"id":326611304,"uuid":"1106322061","full_name":"78/esp-http3","owner":"78","description":"A QUIC HTTP/3 Client for ESP32, ported from Python implementation","archived":false,"fork":false,"pushed_at":"2025-12-19T17:01:05.000Z","size":458,"stargazers_count":10,"open_issues_count":0,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-22T07:06:08.865Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/78.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-29T02:49:13.000Z","updated_at":"2025-12-19T17:01:08.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/78/esp-http3","commit_stats":null,"previous_names":["78/esp-http3"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/78/esp-http3","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/78%2Fesp-http3","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/78%2Fesp-http3/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/78%2Fesp-http3/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/78%2Fesp-http3/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/78","download_url":"https://codeload.github.com/78/esp-http3/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/78%2Fesp-http3/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28216578,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2026-01-05T02:00:06.358Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-05T12:03:32.765Z","updated_at":"2026-01-05T12:05:39.938Z","avatar_url":"https://github.com/78.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ESP-HTTP3\n\nA QUIC/HTTP3 client library for ESP32 platform, implementing RFC 9000 (QUIC) and RFC 9114 (HTTP/3) protocols.\n\n## Features\n\n- ✅ QUIC v1 transport protocol\n- ✅ TLS 1.3 handshake (using mbedtls)\n- ✅ HTTP/3 request/response\n- ✅ Stream multiplexing\n- ✅ Flow control\n- ✅ Packet loss detection and recovery\n- ✅ Synchronous blocking API with background event loop\n\n## Quick Start\n\n### Simple GET Request\n\n```cpp\n#include \"client/http3_client.h\"\n\n// Configure connection\nHttp3ClientConfig config;\nconfig.hostname = \"api.example.com\";\nconfig.port = 443;\n\n// Create client (manages connection lifecycle)\nHttp3Client client(config);\n\n// Simple GET request\nHttp3Response response;\nif (client.Get(\"/api/health\", response)) {\n    ESP_LOGI(TAG, \"Status: %d\", response.status);\n    ESP_LOGI(TAG, \"Body: %s\", response.body.c_str());\n}\n```\n\n### Simple POST Request\n\n```cpp\nHttp3Client client(config);\n\nstd::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e headers = {\n    {\"content-type\", \"application/json\"}\n};\nconst char* body = R\"({\"key\": \"value\"})\";\n\nHttp3Response response;\nif (client.Post(\"/api/data\", headers, \n                (const uint8_t*)body, strlen(body), response)) {\n    ESP_LOGI(TAG, \"Status: %d\", response.status);\n}\n```\n\n### Streaming Download\n\n```cpp\nHttp3Client client(config);\n\n// Open stream\nauto stream = client.Open({.method = \"GET\", .path = \"/large-file\"});\nif (!stream) {\n    ESP_LOGE(TAG, \"Failed to open stream\");\n    return;\n}\n\n// Check status\nif (stream-\u003eGetStatus() != 200) {\n    ESP_LOGE(TAG, \"HTTP error: %d\", stream-\u003eGetStatus());\n    return;\n}\n\n// Read response body in chunks\nuint8_t buffer[4096];\nint bytes_read;\nwhile ((bytes_read = stream-\u003eRead(buffer, sizeof(buffer))) \u003e 0) {\n    // Process data...\n}\n\n// bytes_read == 0 means EOF, \u003c 0 means error\n```\n\n### Streaming Upload\n\n```cpp\nHttp3Client client(config);\n\nHttp3Request request;\nrequest.method = \"POST\";\nrequest.path = \"/upload\";\nrequest.streaming_upload = true;\nrequest.headers = {{\"content-type\", \"application/octet-stream\"}};\n\nauto stream = client.Open(request);\nif (!stream) {\n    ESP_LOGE(TAG, \"Failed to open stream\");\n    return;\n}\n\n// Write data in chunks\nfor (auto\u0026 chunk : data_chunks) {\n    if (stream-\u003eWrite(chunk.data(), chunk.size()) \u003c 0) {\n        ESP_LOGE(TAG, \"Write failed: %s\", stream-\u003eGetError().c_str());\n        return;\n    }\n}\n\n// Signal end of body\nstream-\u003eFinish();\n\n// Read response\nif (stream-\u003eGetStatus() == 200) {\n    ESP_LOGI(TAG, \"Upload successful\");\n}\n```\n\n## API Reference\n\n### Http3Client\n\nMain client class that manages QUIC connection and HTTP/3 streams.\n\n```cpp\nclass Http3Client {\n    // Constructor\n    explicit Http3Client(const Http3ClientConfig\u0026 config);\n    \n    // Connection state\n    bool IsConnected() const;\n    void Disconnect();\n    \n    // Simple request methods (blocking, accumulates body)\n    bool Get(const std::string\u0026 path, Http3Response\u0026 response,\n             uint32_t timeout_ms = 0);\n    bool Post(const std::string\u0026 path, \n              const std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e\u0026 headers,\n              const uint8_t* body, size_t body_size,\n              Http3Response\u0026 response,\n              uint32_t timeout_ms = 0);\n    \n    // Stream API (for streaming or large responses)\n    std::unique_ptr\u003cHttp3Stream\u003e Open(const Http3Request\u0026 request,\n                                       uint32_t timeout_ms = 0);\n    \n    // Statistics\n    Statistics GetStatistics() const;\n};\n```\n\n### Http3Stream\n\nRepresents an active HTTP/3 request stream with blocking read/write.\n\n```cpp\nclass Http3Stream {\n    // Stream info\n    int GetStreamId() const;\n    bool IsValid() const;\n    \n    // Response headers (blocking wait for headers)\n    int GetStatus(uint32_t timeout_ms = 0);\n    std::string GetHeader(const std::string\u0026 name) const;\n    \n    // Read response body (blocking)\n    // Returns: \u003e0 bytes read, 0 EOF, \u003c0 error\n    int Read(uint8_t* buffer, size_t size, uint32_t timeout_ms = 0);\n    \n    // Write request body (for streaming uploads)\n    int Write(const uint8_t* data, size_t size, uint32_t timeout_ms = 0);\n    int Write(std::vector\u003cuint8_t\u003e\u0026\u0026 data, uint32_t timeout_ms = 0);\n    \n    // Signal end of request body\n    bool Finish();\n    \n    // Close stream\n    void Close();\n    \n    // Error info\n    const std::string\u0026 GetError() const;\n};\n```\n\n### Configuration\n\n```cpp\nstruct Http3ClientConfig {\n    std::string hostname;\n    uint16_t port = 443;\n    \n    // Timeouts\n    uint32_t connect_timeout_ms = 10000;\n    uint32_t request_timeout_ms = 30000;\n    uint32_t idle_timeout_ms = 60000;\n    \n    // Buffer sizes\n    size_t receive_buffer_size = 64 * 1024;\n    \n    // Performance optimizations\n    bool cache_keypair = true;         // Cache X25519 keypair for faster reconnect\n    bool cache_session_ticket = false; // Session resumption (experimental)\n    \n    // Debug\n    bool enable_debug = false;\n};\n\nstruct Http3Request {\n    std::string method = \"GET\";\n    std::string path;\n    std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e headers;\n    \n    // For immediate body\n    const uint8_t* body = nullptr;\n    size_t body_size = 0;\n    \n    // For streaming upload\n    bool streaming_upload = false;\n};\n\nstruct Http3Response {\n    int status = 0;\n    std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e headers;\n    std::string body;\n    bool complete = false;\n    std::string error;\n};\n```\n\n## Threading Model\n\n- `Http3Client` manages background tasks for UDP receive and QUIC event processing\n- Public methods can be called from any task\n- Each `Http3Stream` should be used from a single task (except `Close()`)\n- Connection is established automatically on first request\n\n## Notes\n\n1. **Task Stack Size**: Requires at least 8KB stack size\n2. **Network Required**: Ensure WiFi or other network is connected before use\n3. **Resource Cleanup**: `Http3Stream` is automatically cleaned up when unique_ptr goes out of scope\n4. **Connection Reuse**: Multiple requests can share the same `Http3Client` connection\n\n## Dependencies\n\n- ESP-IDF v5.4+\n- mbedtls (for TLS 1.3)\n- lwip (for network stack)\n\n## License\n\nApache-2.0 License\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F78%2Fesp-http3","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F78%2Fesp-http3","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F78%2Fesp-http3/lists"}