{"id":32163570,"url":"https://github.com/haskell-grpc-native/http2-client","last_synced_at":"2025-12-11T23:30:06.646Z","repository":{"id":23927317,"uuid":"92448512","full_name":"haskell-grpc-native/http2-client","owner":"haskell-grpc-native","description":"A native HTTP2 client in Haskell","archived":false,"fork":false,"pushed_at":"2025-05-06T22:19:08.000Z","size":292,"stargazers_count":43,"open_issues_count":17,"forks_count":26,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-12-08T04:41:10.602Z","etag":null,"topics":["haskell-library","http2","protocol"],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/haskell-grpc-native.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog.md","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":"2017-05-25T22:09:53.000Z","updated_at":"2025-05-06T22:19:12.000Z","dependencies_parsed_at":"2024-04-10T22:45:11.239Z","dependency_job_id":"90e40d76-5a60-49cd-96e8-80d501507ada","html_url":"https://github.com/haskell-grpc-native/http2-client","commit_stats":{"total_commits":242,"total_committers":10,"mean_commits":24.2,"dds":0.06198347107438018,"last_synced_commit":"046b1f23ea547b75f1a3dc3d878603968bff4fb4"},"previous_names":["lucasdicioccio/http2-client"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/haskell-grpc-native/http2-client","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell-grpc-native%2Fhttp2-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell-grpc-native%2Fhttp2-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell-grpc-native%2Fhttp2-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell-grpc-native%2Fhttp2-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/haskell-grpc-native","download_url":"https://codeload.github.com/haskell-grpc-native/http2-client/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell-grpc-native%2Fhttp2-client/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27672073,"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":"2025-12-11T02:00:11.302Z","response_time":56,"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":["haskell-library","http2","protocol"],"created_at":"2025-10-21T14:35:15.004Z","updated_at":"2025-12-11T23:30:06.637Z","avatar_url":"https://github.com/haskell-grpc-native.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# http2-client\n\nAn native-Haskell HTTP2 client library based on `http2` and `tls` packages.\n\nHackage: https://hackage.haskell.org/package/http2-client .\n\n## General design\n\nHTTP2 is a heavy protocol. HTTP2 features pipelining, query and responses\ninterleaving, server-pushes, pings, stateful compression and flow-control,\npriorization etc. This library aims at exposing these features so that library\nusers can integrate `http2-client` in a variety of applications. In short, we'd\nlike to expose as many HTTP2 features as possible. Hence, the `http2-client`\nprogramming interface can feel low-level for users with expectations to get an\nAPI as simple as in HTTP1.x.\n\nExposing most HTTP2 primitives as a drawback: the library allows a client to\nbehave abnormally with-respect to the HTTP2 spec. That said, we try to prevent\nnotoriously-difficult errors such as concurrency bugs by coercing users with\nthe programming API following Haskell's philosophy to factor-out errors at\ncompile time. For instance, a client can send DATA frames on a stream after\nclosing it with a RST (easy to spot). However, a multi-threaded client will not\nbe able to interleave DATA frames with HEADERS and their CONTINUATIONs and the\nlocking required to achieve this invariant is hidden (hard to implement).\n\nFollowing this philosophy, we prefer to offer a somewhat low-level API in\n`Network.HTTP2.Client` and higher-level APIs (with a different performance\ntrade-off) in `Network.HTTP2.Client.Helpers`. For instance,\n`Network.HTTP2.Client.Helpers.waitStream` will consume a whole stream in memory\nbefore returning whereas `Network.HTTP2.Client` users will have to take chunks\none at a time. We look forward to the linear arrows extension for improving the\nlibrary design.\n\n### Versioning and GHC support\n\nWe try to follow https://pvp.haskell.org/ as `a.b.c.d` with the caveat that if\n`a=0` then we are still slightly unhappy with some APIs and we'll break things\narbitrarily.\n\nWe aim at supporting GHC-8.x, contributions to support GHC-7.x are welcome.\n\n### Installation\n\nThis package is a standard `Stack` project, please also refer to Stack's\ndocumentation if you have trouble installing or using this package.  Please\nalso have a look at the Hackage Matrix CI:\nhttps://matrix.hackage.haskell.org/package/http2-client .\n\n## Usage\n\nFirst, make sure you are somewhat familiar with HTTP and HTTP2 standards by\nreading RFCs or Wikipedia pages. If you use the library, feel free to shoot me\nan e-mail (cf. commits) or a tweet @lucasdicioccio .\n\n### Help and examples\n\nPlease see some literate Haskell documents in the `examples/` directory.  For\na more involved usage, we currently provide a command-line example client:\n`http2-client-exe` which I use as a test client and you could use to test\nvarious flow-control parameters. This binary lives in a separate package\nat https://github.com/lucasdicioccio/http2-client-exe .\n\nThe Haddocks, at https://hackage.haskell.org/package/http2-client, should have\nplenty implementation details, so please have a look.  Otherwise, you can ask\nhelp by creating an Issue on the bug-tracker.\n\n### Opening a stream\n\nFirst, you open a (TLS-protected) connection to a server and configure the\ninitial SETTINGS to advertise. Then you can open and consume streams. Opening\nstreams takes a stream-definition and expresses two sequential parts. First,\nsending the HTTP headers, which reserves an increasing stream-ID with the\nserver. Second, you consume a stream by sending DATA chunk or receiving DATA\nchunks. One thing that can prevent concurrency is if you have too many opened\nstreams for the server. The `http2-client` library tracks server's max\nconcurrency preference and will prevent you from opening too many streams.\n\n### Sending chunked data\n\nSent data must be chunked according to server's preferences. A function named\n`sendData` performs the chunking but this chunking could have some suboptimal\noverhead if you want to repeatedly call sendData with a buffer size that is not\na multiple of the server's preferred chunk size.\n\n### Flow control\n\nHTTP2 mandates a flow-control system that cannot be disabled. DATA chunks\nconsume credit from the flow-control system. The standard defines a\nflow-control context per stream plus one global per-connection. \n\n** Received DATA flow control ** In order to keep receiving data you need to\nperiodically transfer credit to the server. One transfers credit to server by\ncalling `_updateWindow`, which transfers locally-accumulated credit (you\naccumulate credit with `addCredit`). The current implementation already follows\na \"zero-sum\" credit where received DATA is immediately consumed and\nre-credited.  That is, if you only keep calling `_updateWindow` at some\nfrequency the stream will progress. You can also `_addCredit` to permit\nreceiving more DATA on a stream/connection (e.g., if you want to implement\nsomething like TCP slow-start).\n\n** Sent DATA flow control ** A server following the HTTP2 specification\nstrictly will kick you for sending too much data. The `http2-client` library\nallows you to be more aggressive than the server allows and you have to care\nfor your streams. We provide an incoming flow-control context that will allow\nyou to call `_withdrawCredit` to wait until some credit is available. At the\ntime of this writing, the `sendData` function does not call `_withdrawCredit`\nand we provide no equivalent. Note that the chunking and flow-control\nmechanisms have interesting interactions in HTTP2 in a multi-threaded context.\nPay attention to always take credit in the per-stream flow-control context\nbefore taking it from the global per-connection flow-control context.\nOtherwise, you risk starving the global per-connection flow-control with no\nguarantee that you'll be allowed to send a DATA frame.\n\n## Settings changes\n\nThe HTTP2 RFC acknowledges the inherent race conditions that may occur when\nchanging SETTINGS. The `http2-client` library should be rather permissive and\naccept rather than reject frames caught violating inconsistent settings once\nclient settings are made stricter. Conversely, the `http2-client` library tries\nto enforce server-SETTINGS strictly before ACKnowledging the setting changes.\nThis configuration can lead to problems if the server send more-permissive\nSETTINGS (e.g., allowing a large default window size -\u003e which recredits all\nstreams) but if the server applies this change locally only after receiving the\nclient ACK. One way to be double-sure the `http2-client` library is always\nstrict would be to apply settings changes in two steps: settings that move in\nthe \"stricter direction\" (e.g., fewer concurrency, smaller initial window)\nshould be applied _before_ ACK-ing the SETTING frame. Meanwhile settings that\nmove in the \"looser direction\" (e.g., more concurrency) should be applied\n_after_ ACK-ing the SETTINGS frame.\n\nThe current design apply SETTINGS:\n- (client prefs) after receiving a ACK for sent SETTINGS, you get the choice to\n  wait for an ACK or wait in a thread, but you must wait for an ACK to apply\n  changed settings (the `_settings` function will return an IO to wait for the\n  ACK and apply settings). Note that the initial SETTINGS change frame is\n  waited for in a thread without library's user intervention (if you feel\n  strongly against this choice, please open a bug).\n- (server prefs) immediately after receiving and hence before sending ACK-SETTINGS\n\nFortunately, changing settings mid-stream is probably a rare behavior and the\ndefault SETTINGS are large enough to avoid creating fatal errors before\nsending/receiving the initial SETTINGS frames.\n\n## Things that are hardcoded\n\nA number of HTTP2 features are currently hardcoded:\n- PINGs are replied-to immediately (i.e., a server could hog a connection with PINGs)\n- the initial SETTINGS frame sent to the server is waited-for in a separate\n  thread, settings are applied to the connection when the server ACKs the frame\n- flow-control from DATA frames is decremented immediately when received (in a\n  separate thread) rather than when consumed from the client\n- similarly, flow-control re-increment every DATA received as soon as it is\n  received\n\n## Contributing\n\nContributions are welcome. As I start integrating external contribution I plan\nto follow the following procedure:\n- stop pushing directly into master\n- develop any patch in a new branch, branched from master\n- merge requests target master\n\nPlease pay attention to the following:\n- avoid introducing external dependencies, especially if dependencies are not in stackage\n- avoid reformatting-only merge requests\n- please verify that you can `stack clean` and `stack build --pedantic`\n\nGeneral mindset to have during code-reviews:\n- be kind\n- be patient\n- surpass egos and bring data if there is a disagreement\n\n## Bugtracker\n\nMost of the following points have their own issues on the issue tracker at\nGitHub: https://github.com/lucasdicioccio/http2-client/issues .\n\n### Things that will likely change the API\n\nI think the fundamentals are right but the following needs tweaking:\n\n- function to reset a stream will likely be blocking until a RST/EndStream is\n  received so that all DATA frames are accounted for in the flow-control system\n- need a way to hook custom flow-control algorithms\n\n### Support of the HTTP2 standard\n\nThe current implementation follows the HTTP2 standard except for the following:\n- does not handle `PRIORITY`\n- does not expose padding\n- does not handle `SETTINGS_MAX_HEADER_LIST_SIZE`\n  * it's unclear to me whether this limitation is applied per frame or in total\n  * the accounting is done before compression with 32 extra bytes per header\n- does not implement most of the checks that should trigger protocol errors\n  * unwanted frames on idle/closed streams\n  * increasing IDs only\n  * invalid settings\n  * invalid window in flow-control\n  * invalid frame sizes\n  * data-consumed out of flow-control limits\n  * authority of push promise https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-10.1\n  * ...\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaskell-grpc-native%2Fhttp2-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhaskell-grpc-native%2Fhttp2-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaskell-grpc-native%2Fhttp2-client/lists"}