{"id":13424610,"url":"https://github.com/h2o/picohttpparser","last_synced_at":"2025-05-15T08:09:23.622Z","repository":{"id":686421,"uuid":"330414","full_name":"h2o/picohttpparser","owner":"h2o","description":"tiny HTTP parser written in C (used in HTTP::Parser::XS et al.)","archived":false,"fork":false,"pushed_at":"2024-06-17T09:44:12.000Z","size":169,"stargazers_count":1911,"open_issues_count":20,"forks_count":258,"subscribers_count":78,"default_branch":"master","last_synced_at":"2025-03-27T16:11:18.564Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/h2o.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2009-10-08T00:08:05.000Z","updated_at":"2025-03-24T17:30:24.000Z","dependencies_parsed_at":"2024-01-29T03:23:14.823Z","dependency_job_id":"a2c71f53-c43d-445a-a6d0-4d45bef2cde1","html_url":"https://github.com/h2o/picohttpparser","commit_stats":{"total_commits":129,"total_committers":18,"mean_commits":7.166666666666667,"dds":0.2713178294573644,"last_synced_commit":"066d2b1e9ab820703db0837a7255d92d30f0c9f5"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/h2o%2Fpicohttpparser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/h2o%2Fpicohttpparser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/h2o%2Fpicohttpparser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/h2o%2Fpicohttpparser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/h2o","download_url":"https://codeload.github.com/h2o/picohttpparser/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247043342,"owners_count":20874086,"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","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":"2024-07-31T00:00:56.980Z","updated_at":"2025-04-03T17:09:14.537Z","avatar_url":"https://github.com/h2o.png","language":"C","readme":"PicoHTTPParser\n=============\n\nCopyright (c) 2009-2014 [Kazuho Oku](https://github.com/kazuho), [Tokuhiro Matsuno](https://github.com/tokuhirom), [Daisuke Murase](https://github.com/typester), [Shigeo Mitsunari](https://github.com/herumi)\n\nPicoHTTPParser is a tiny, primitive, fast HTTP request/response parser.\n\nUnlike most parsers, it is stateless and does not allocate memory by itself.\nAll it does is accept pointer to buffer and the output structure, and setups the pointers in the latter to point at the necessary portions of the buffer.\n\nThe code is widely deployed within Perl applications through popular modules that use it, including [Plack](https://metacpan.org/pod/Plack), [Starman](https://metacpan.org/pod/Starman), [Starlet](https://metacpan.org/pod/Starlet), [Furl](https://metacpan.org/pod/Furl).  It is also the HTTP/1 parser of [H2O](https://github.com/h2o/h2o).\n\nCheck out [test.c] to find out how to use the parser.\n\nThe software is dual-licensed under the Perl License or the MIT License.\n\nUsage\n-----\n\nThe library exposes four functions: `phr_parse_request`, `phr_parse_response`, `phr_parse_headers`, `phr_decode_chunked`.\n\n### phr_parse_request\n\nThe example below reads an HTTP request from socket `sock` using `read(2)`, parses it using `phr_parse_request`, and prints the details.\n\n```c\nchar buf[4096], *method, *path;\nint pret, minor_version;\nstruct phr_header headers[100];\nsize_t buflen = 0, prevbuflen = 0, method_len, path_len, num_headers;\nssize_t rret;\n\nwhile (1) {\n    /* read the request */\n    while ((rret = read(sock, buf + buflen, sizeof(buf) - buflen)) == -1 \u0026\u0026 errno == EINTR)\n        ;\n    if (rret \u003c= 0)\n        return IOError;\n    prevbuflen = buflen;\n    buflen += rret;\n    /* parse the request */\n    num_headers = sizeof(headers) / sizeof(headers[0]);\n    pret = phr_parse_request(buf, buflen, \u0026method, \u0026method_len, \u0026path, \u0026path_len,\n                             \u0026minor_version, headers, \u0026num_headers, prevbuflen);\n    if (pret \u003e 0)\n        break; /* successfully parsed the request */\n    else if (pret == -1)\n        return ParseError;\n    /* request is incomplete, continue the loop */\n    assert(pret == -2);\n    if (buflen == sizeof(buf))\n        return RequestIsTooLongError;\n}\n\nprintf(\"request is %d bytes long\\n\", pret);\nprintf(\"method is %.*s\\n\", (int)method_len, method);\nprintf(\"path is %.*s\\n\", (int)path_len, path);\nprintf(\"HTTP version is 1.%d\\n\", minor_version);\nprintf(\"headers:\\n\");\nfor (i = 0; i != num_headers; ++i) {\n    printf(\"%.*s: %.*s\\n\", (int)headers[i].name_len, headers[i].name,\n           (int)headers[i].value_len, headers[i].value);\n}\n```\n\n### phr_parse_response, phr_parse_headers\n\n`phr_parse_response` and `phr_parse_headers` provide similar interfaces as `phr_parse_request`.  `phr_parse_response` parses an HTTP response, and `phr_parse_headers` parses the headers only.\n\n### phr_decode_chunked\n\nThe example below decodes incoming data in chunked-encoding.  The data is decoded in-place.\n\n```c\nstruct phr_chunked_decoder decoder = {}; /* zero-clear */\nchar *buf = malloc(4096);\nsize_t size = 0, capacity = 4096, rsize;\nssize_t rret, pret;\n\n/* set consume_trailer to 1 to discard the trailing header, or the application\n * should call phr_parse_headers to parse the trailing header */\ndecoder.consume_trailer = 1;\n\ndo {\n    /* expand the buffer if necessary */\n    if (size == capacity) {\n        capacity *= 2;\n        buf = realloc(buf, capacity);\n        assert(buf != NULL);\n    }\n    /* read */\n    while ((rret = read(sock, buf + size, capacity - size)) == -1 \u0026\u0026 errno == EINTR)\n        ;\n    if (rret \u003c= 0)\n        return IOError;\n    /* decode */\n    rsize = rret;\n    pret = phr_decode_chunked(\u0026decoder, buf + size, \u0026rsize);\n    if (pret == -1)\n        return ParseError;\n    size += rsize;\n} while (pret == -2);\n\n/* successfully decoded the chunked data */\nassert(pret \u003e= 0);\nprintf(\"decoded data is at %p (%zu bytes)\\n\", buf, size);\n```\n\nBenchmark\n---------\n\n![benchmark results](http://i.gyazo.com/a85c18d3162dfb46b485bb41e0ad443a.png)\n\nThe benchmark code is from [fukamachi/fast-http@6b91103](https://github.com/fukamachi/fast-http/tree/6b9110347c7a3407310c08979aefd65078518478).\n\nThe internals of picohttpparser has been described to some extent in [my blog entry]( http://blog.kazuhooku.com/2014/11/the-internals-h2o-or-how-to-write-fast.html).\n","funding_links":[],"categories":["Networking","C","Rest protocol","内存分配"],"sub_categories":["网络"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fh2o%2Fpicohttpparser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fh2o%2Fpicohttpparser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fh2o%2Fpicohttpparser/lists"}