{"id":13776834,"url":"https://github.com/tokers/lua-resty-http2","last_synced_at":"2025-04-06T02:47:02.041Z","repository":{"id":96328651,"uuid":"145936296","full_name":"tokers/lua-resty-http2","owner":"tokers","description":"The HTTP/2 Protocol (Client Side) Implementation for OpenResty.","archived":false,"fork":false,"pushed_at":"2020-02-04T13:30:38.000Z","size":171,"stargazers_count":76,"open_issues_count":3,"forks_count":12,"subscribers_count":8,"default_branch":"master","last_synced_at":"2024-02-14T18:34:21.023Z","etag":null,"topics":["http2","lua-resty","openresty"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tokers.png","metadata":{"files":{"readme":"README.markdown","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}},"created_at":"2018-08-24T03:12:54.000Z","updated_at":"2023-12-29T09:14:38.000Z","dependencies_parsed_at":null,"dependency_job_id":"87e6245b-e83f-471f-adf4-005013536cd6","html_url":"https://github.com/tokers/lua-resty-http2","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tokers%2Flua-resty-http2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tokers%2Flua-resty-http2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tokers%2Flua-resty-http2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tokers%2Flua-resty-http2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tokers","download_url":"https://codeload.github.com/tokers/lua-resty-http2/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247426985,"owners_count":20937197,"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":["http2","lua-resty","openresty"],"created_at":"2024-08-03T18:00:33.746Z","updated_at":"2025-04-06T02:47:02.009Z","avatar_url":"https://github.com/tokers.png","language":"Lua","funding_links":[],"categories":["Libraries"],"sub_categories":[],"readme":"Name\n====\n\nlua-resty-http2 - The HTTP/2 Protocol (Client Side) Implementation for OpenResty. Still Pending.\n\n![Build Status](https://travis-ci.org/tokers/lua-resty-http2.svg?branch=master)\n\nTable of Contents\n=================\n\n* [Name](#name)\n* [Status](#status)\n* [Synopsis](#synopsis)\n* [Description](#description)\n* [API Implemented](#api-implemented)\n  * [resty.http2](#restyhttp2)\n    * [http2.new](#http2new)\n    * [client:acknowledge_settings](#clientacknowledge_settings)\n    * [client:request](#clientrequest)\n    * [client:send_request](#clientsend_request)\n    * [client:read_headers](#clientread_headers)\n    * [client:read_body](#clientread_body)\n    * [client:close](#clientclose)\n    * [client:keepalive](#clientkeepalive)\n  * [resty.http2.protocol](#restyhttp2protocol)\n    * [protocol.session](#protocolsession)\n    * [session:adjust_window](#sessionadjust_window)\n    * [session:frame_queue](#sessionframe_queue)\n    * [session:flush_queue](#sessionflush_queue)\n    * [session:submit_request](#sessionsubmit_request)\n    * [session:submit_window_update](#sessionsubmit_window_update)\n    * [session:recv_frame](#sessionrecv_frame)\n    * [session:close](#sessionclose)\n    * [session:detach](#sessiondetach)\n    * [session:attach](#sessionattach)\n  * [resty.http2.stream](#restyhttp2stream)\n    * [h2_stream.new](#h2_streamnew)\n    * [h2_stream.new_root](#h2_streamnew_root)\n    * [stream:submit_headers](#streamsubmit_headers)\n    * [stream:submit_data](#streamsubmit_data)\n    * [stream:submit_window_update](#streamsubmit_window_update)\n    * [stream:set_dependency](#streamset_dependency)\n  * [resty.http2.frame](#restyhttp2frame)\n    * [h2_frame.header.new](#h2_frameheadernew)\n    * [h2_frame.header.pack](#h2_frameheaderpack)\n    * [h2_frame.header.unpack](#h2_frameheaderunpack)\n    * [h2_frame.priority.pack](#h2_frameprioritypack)\n    * [h2_frame.priority.unpack](#h2_framepriorityunpack)\n    * [h2_frame.rst_stream.pack](#h2_framerst_streampack)\n    * [h2_frame.rst_stream.unpack](#h2_framerst_streamunpack)\n    * [h2_frame.rst_stream.new](#h2_framerst_streamunnew)\n    * [h2_frame.settings.pack](#h2_framesettingspack)\n    * [h2_frame.settings.unpack](#h2_framesettingsunpack)\n    * [h2_frame.settings.new](#h2_framesettingsnew)\n    * [h2_frame.ping.pack](#h2_framepingpack)\n    * [h2_frame.ping.unpack](#h2_framepingunpack)\n    * [h2_frame.goaway.pack](#h2_framegoawaypack)\n    * [h2_frame.goaway.unpack](#h2_framegoawayunpack)\n    * [h2_frame.goaway.new](#h2_framegoawaynew)\n    * [h2_frame.window_update.pack](#h2_framewindow_updatepack)\n    * [h2_frame.window_update.unpack](#h2_framewindow_updateunpack)\n    * [h2_frame.window_update.new](#h2_framewindow_updatenew)\n    * [h2_frame.headers.pack](#h2_frameheaderspack)\n    * [h2_frame.headers.unpack](#h2_frameheadersunpack)\n    * [h2_frame.headers.new](#h2_frameheadersnew)\n    * [h2_frame.continuation.pack](#h2_framecontinuationpack)\n    * [h2_frame.continuation.unpack](#h2_framecontinuationunpack)\n    * [h2_frame.continuation.new](#h2_framecontinuationnew)\n    * [h2_frame.data.pack](#h2_framedatapack)\n    * [h2_frame.data.unpack](#h2_framedataunpack)\n    * [h2_frame.data.new](#h2_framedatannew)\n    * [h2_frame.push_promise.unpack](#h2_framepush_promiseunpack)\n  * [resty.http2.hpack](#restyhttp2hpack)\n    * [hpack.encode](#hpackencode)\n    * [hpack.indexed](#hpackindexed)\n    * [hpack.incr_indexed](#hpackincr_indexed)\n    * [hpack.new](#hpacknew)\n    * [h:insert_entry](#hinsert_entry)\n    * [h:resize](#hresize)\n    * [h:decode](#hdecode)\n    * [h:get_indexed_header](#hget_indexed_header)\n  * [resty.http2.error](#restyhttp2error)\n    * [h2_error.strerror](#h2_errorstrerror)\n    * [h2_error.is_stream_error](#h2_erroris_stream_error)\n* [Author](#author)\n* [Copyright and License](#copyright-and-license)\n* [See Also](#see-also)\n\nStatus\n======\n\nThis Lua module is currently considered experimental.\n\nSynopsis\n========\n\n```lua\nlocal http2 = require \"resty.http2\"\n\nlocal host = \"127.0.0.1\"\nlocal port = 8080\nlocal sock = ngx.socket.tcp()\nlocal ok, err = sock:connect(host, port)\nif not ok then\n    ngx.log(ngx.ERR, \"failed to connect \", host, \":\", port, \": \", err)\n    return\nend\n\nlocal headers = {\n    { name = \":authority\", value = \"test.com\" },\n    { name = \":method\", value = \"GET\" },\n    { name = \":path\", value = \"/index.html\" },\n    { name = \":scheme\", value = \"http\" },\n    { name = \"accept-encoding\", value = \"gzip\" },\n    { name = \"user-agent\", value = \"example/client\" },\n}\n\nlocal on_headers_reach = function(ctx, headers)\n    -- Process the response headers\nend\n\nlocal on_data_reach = function(ctx, data)\n    -- Process the response body\nend\n\nlocal opts = {\n    ctx = sock,\n    recv = sock.receive,\n    send = sock.send,\n}\n\nlocal client, err = http2.new(opts)\nif not client then\n    ngx.log(ngx.ERR, \"failed to create HTTP/2 client: \", err)\n    return\nend\n\nlocal ok, err = client:request(headers, nil, on_headers_reach, on_data_reach)\nif not ok then\n    ngx.log(ngx.ERR, \"client:process() failed: \", err)\n    return\nend\n\nsock:close()\n```\n\nAs a more formal exemplify, please read the [util/example.lua](util/example.lua).\n\nDescription\n===========\n\nThis pure Lua library implements the client side HTTP/2 protocol, but not all\ndetails are covered, for example, the stream dependencies is maintained but\nnever used.\n\nThere are some inherent limitations which are not solved, however.\n\n**Cannot be used over the SSL/TLS handshaked connections**. The `tcpsock:sslhandshake` doesn't support the ALPN or NPN extensions,\nso currently only the plain connections can be used, the library will start\nHTTP/2 session with sending the connection preface, i.e. the string:\n\n```\nPRI * HTTP/2.0\\r\\n\\r\\nSM\\r\\n\\r\\n\n```\n\nThis library provides a patch for the Application-Layer Protocol Negotiation. just uses [this](util/lua-nginx-module-0.10.13-ssl-alpn.patch) if you need.\n\n**Only a HTTP request can be submitted**. Currently the implemented APIs support for submitting just one HTTP request. PRs are welcome to solve this.\n\n**HTTP/2 session reuse**. The HTTP/2 protocol is designed as persistent, while the Cosocket object is binded to a specific HTTP request. One has to close the Cosocket object or set it alive before the request is over, this model is conflict with the reuse of HTTP/2 session, just a work-around way can solve this, see [client:keepalive](#client:keepalive) for the details.\n\n[Back to TOC](#table-of-contents)\n\n\nAPI Implemented\n===============\n\n[Back to TOC](#table-of-contents)\n\n\nresty.http2\n-----------\n\nTo load this module, just do this:\n\n```lua\nlocal http2 = require \"resty.http2\"\n```\n\n[Back to TOC](#table-of-contents)\n\n### http2.new\n\n**syntax**: *local client, err = http2.new(opts)*\n\nCreates a HTTP/2 client by specifying the options. In case of failure, `nil`\nand a error message string will be returned.\n\nThe sole parameter `opts`, which is a Lua table, contains some fields:\n\n* `recv`, a Lua function which is used to read bytes;\n\n* `send`, a Lua function which is used to send bytes;\n\n* `ctx`, an opaque data, acts as the callers' context;\n\nThe `recv` and `send` function will be called like:\n\n```lua\nlocal data, err = recv(ctx, size)\nlocal ok, err = send(ctx, data)\n```\n\n* `preread_size`, a Lua number which influences the peer's initial send window size (advertise through the SETTINGS frame), default is `65535`;\n\n* `max_concurrent_stream`, a Lua number which limits the max concurrent streams in a HTTP/2 session, default is `128`;\n\n* `max_frame_size`, a Lua number which limits the max frame size that peer can send, default is `16777215`.\n\n* `key`, a Lua string which represents which cached HTTP/2 session the callers want to resue, if not found, new HTTP/2 session will be created. See [client:keepalive](client:keepalive) for more details.\n\n[Back to TOC](#table-of-contents)\n\n\n### client:acknowledge_settings\n\n\n**syntax**: *local ok, err = client:acknowledge_settings()*\n\nAcknowledges peer's SETTINGS frame, settings will be applied automatically.\n\nIn case of failure, `nil` and a Lua string will describes the error reason will be given.\n\n[Back to TOC](#table-of-contents)\n\n\n### client:request\n\n**syntax**: *local ok, err = client:request(headers, body?, on_headers_reach, on_data_reach, on_trailers_reach)*\n\nSends a HTTP request to peer,\n\nIn case of failure, `nil` and a Lua string will describes the error reason will be given.\n\nthe `headers`, should be a array-like Lua table represent the HTTP request headers, each entry is like `{ name = \"header1\", value = \"value1\" }`.\n\nIt is worth noting that this library doesn't take care of the HTTP headers' semantics, so it's callers' responsibility to supply this, and callers should implement any necessary conversions, for example, `Host` should be converted to `:authority`. Also, the following headers will be ignored as they are CONNECTION specific.\n\n  * `Connection`\n  * `Keep-Alive`\n  * `Proxy-Connection`\n  * `Upgrade`\n  * `Transfer-Encoding`\n\nThe `body`, can be a Lua string represents the HTTP request body. It also can be a Lua function to implement the stream-way uploading. When `body` is a Lua function, it will be called like:\n\n```lua\nlocal part_data, last, err = body(size)\n```\n\nIn case of failure, `body` should provide the 3rd return value `err` to tell this library that some fatal errors happen, then this method will be aborted immediately, and a GOAWAY frame will be sent to peer with error code INTERNAL_ERROR.\n\nWhen all data has been generated, the 2nd return value `last` should be provided, and it's value must be `true`.\n\n`on_headers_reach`, should be a Lua function, as a callback which will be called when complete HTTP response headers are received, it will be called like:\n\n```lua\nlocal abort = on_headers_reach(ctx, headers)\n```\n\nThe 2nd parameter `headers` is a hash-like Lua table which represents the HTTP response headers received from peer.\n\n`on_headers_reach` can decide whether aborts the HTTP/2 session by returning a boolean value `abort` to the library, the HTTP/2 session will be aborted if `on_headers_reach` returns a true value.\n\nThe parameter `on_data_reach`, is a Lua function, acts as the callback which will be called when response body are received every time, it will be called like:\n\n```lua\nlocal abort = on_data_reach(ctx, data)\n```\n\nThe 2nd parameter `data` is a Lua string represents the HTTP respose body received this time.\n\nThe meaning of return value is same as the `on_headers_reach`.\n\nAfter this method returns, the HTTP/2 session is still alive, one can decide to close this session by calling [client:close](#clientcloe) or going ahead to do something.\n\nThe last parameter `on_trailers_reach` is not necessary but is required if\ntrailer headers exist in in some scenarios (like gRPC).\n\n```lua\nlocal abort = on_trailers_reach(ctx, trailers)\n```\n\nThe 2nd parameter is the a hash-like Lua table which holds all the trailer HTTP headers.\n\nLikewise, `on_trailers_reach` can decide whether aborts the HTTP/2 session by passing the return value `abort`, session will be aborted if `abort` is true.\n\n[Back to TOC](#table-of-contents)\n\n\n### client:send_request\n\n**syntax**: *local stream, err = client:send_request(headers, body?)*\n\nSends the headers and body (if any) to peer.\n\nmeanings of `headers` and `body` are same as the one in [client:request](#clientrequest).\n\nThe corresponding created stream object will be given when this method returns.\n\nIn case of failure, `nil` and a Lua string which describes the error reason will be given.\n\n[Back to TOC](#table-of-contents)\n\n\n### client:read_headers\n\n**syntax**: *local headers, err = client:read_headers(stream)*\n\nReads the response headers from peer, the parameter `stream` is the one created by [client:send_request](#clientsend_request).\n\nThe return headers is a hash-like Lua table which contains the whole HTTP response headers, which may contains some pesudo-headers like `\":status\"`, callers should do some transforms if necessary.\n\nIn case of failure, `nil` and a Lua string which describes the error reason will be given.\n\n[Back to TOC](#table-of-contents)\n\n### client:read_body\n\n**syntax**: *local body, err = client:read_body(stream)*\n\nReads a DATA frame from peer, the parameter `stream` is the one created by [client:send_request](#clientsend_request).\n\nThe return data is a Lua string which represents a piece of response body. Empty string will be given if the whole body were read done.\n\nIn case of failure, `nil` and a Lua string which describes the error reason will be given.\n\n[Back to TOC](#table-of-contents)\n\n### client:close\n\n**syntax**: *local ok, err = client:close(code)*\n\nCloses the current HTTP/2 session with the error code `code`.\n\nSee [resty.http2.error](#restyhttp2error) to learn the error codes.\n\nIn case of failure, `nil` and a Lua string which describes the error reason will be given.\n\n[Back to TOC](#table-of-contents)\n\n### client:keepalive\n\n**syntax**: *client:keepalive(key)*\n\nCaches current HTTP/2 session for the reuse, note malformed HTTP/2 session will never be cached. The HTTP/2 session will detached from the connection, precisely, the current Cosocket object.\n\nThe detached HTTP/2 session will be saved in an internal hash-like Lua table, the unique parameter `key` will be used to index this session when callers want to reuse it.\n\nAfter set this session as alive, callers should also set the Cosocket object as keepalive.\n\nThere is an inherent limitation between the mapping of HTTP/2 session and the underlying connection. A HTTP/2 session can only be used in a TCP connection becasue it is stateful, if callers store the connection to a pool which caches multiple connections, the binding relations is lost, since which connection is picked to the Cosocket object is not sure, thereby which HTTP/2 session shall be matched is also unknown.\n\nThis is no elegant way to solve this, unless the Cosocket model can assign an identifier to the underlying connection. Now what callers can do is use the single size connection pool to bypass this limitation, for example:\n\n```lua\n...\n\nsock:connect(host, port, { pool = \"h2\" })\n\n...\n\nsock:setkeepalive(75, 1)\nclient:keepalive(\"test\")\n```\n\n[Back to TOC](#table-of-contents)\n\nresty.http2.protocol\n-------------------\n\nThis module implements some low-level protocool-relevant APIs.\n\nTo load this module, just do this:\n\n```lua\nlocal protocol = require \"resty.http2.protocol\"\n```\n\n[Back to TOC](#table-of-contents)\n\n### protocol.session\n\n**syntax**: *local session, err = protocol.session(recv, send, ctx, preread_size?, max_concurrent_stream?, max_frame_size?)*\n\nCreates a new HTTP/2 session, in case of failure, `nil` and a Lua string which\ndescribes the error reason will be given.\n\nThe meaning of every parameter is same as these described in [http2.new](#http2new).\n\nThe initial SETTINGS frame and WINDOW_UPDATE frame will be sent before this\nfunction returns.\n\n[Back to TOC](#table-of-contents)\n\n### session:adjust_window\n\n**syntax**: *local ok = session:adjust_window(delta)*\n\nAdjusts each streams send window size, stream will be reset if the altered send window size exceeds MAX_WINDOW_SIZE, in this case, `ok` will be `nil`.\n\n[Back to TOC](#table-of-contents)\n\n### session:frame_queue\n\n**syntax**: *session:frame_queue(frame)*\n\nAppends `frame` to current session's output queue.\n\n[Back to TOC](#table-of-contents)\n\n### session:flush_queue\n\n**syntax**: *local ok, err = session:flush_queue()*\n\nPacks and flushes the queueing frames, in case of failure, `nil` and a Lua\nstring which described the error reason will be given.\n\n[Back to TOC](#table-of-contents)\n\n### session:submit_request\n\n**syntax**: *local ok, err = session:submit_request(headers, no_body, priority?, pad?)*\n\nSubmits a HTTP request to the current HTTP/2 session, in case of failure, `nil`\nand a Lua string which described the error reason wil be given.\n\nMeaning of each parameter:\n\n* `headers`, should be a hash-like Lua table represent the HTTP request headers, it is worth noting that this library doesn't take care of the HTTP headers' semantics, so it's callers' responsibility to supply this, and callers should transform any necessary pesudo headers. For example, `:authority` should be passed rather `Host`;\n\n* `no_body`, a boolean value, indicates whether this request has body. When it\nis true, the generated HEADERS frame will contains the END_HEADERS flag;\n\n* `priority`, a hash-like Lua table, which is used to define a custom stream dependencies:\n  * `priority.sid` represents the dependent stream identifier;\n  * `priority.excl`, whether the new stream becomes the sole dependency of the\n  stream indicated by `priority.sid`;\n  * `priority.weight` defines weight of new stream;\n\n* `pad`, the padding data.\n\n[Back to TOC](#table-of-contents)\n\n### session:submit_window_update\n\n**syntax**: *local ok, err = session:submit_window_update(incr)*\n\nSubmits a WINDOW_UPDATE frame for the whole HTTP/2 session with an increment `incr`, in case of failure, `nil` and a Lua string which describes the error reason will be given.\n\n[Back to TOC](#table-of-contents)\n\n### session:recv_frame\n\n**syntax**: *local frame, err = session:recv_frame()*\n\nReceives a HTTP/2 frame, in case of failure, `nil` and a Lua string which describes the error reason will be given.\n\nThe corresponding action will be taken automatically, for example, GOAWAY frame will be sent if peer violates the HTTP/2 protocol conventions; WINDOW_UPDATE frame will be sent if peer's send window becomes too small.\n\n[Back to TOC](#table-of-contents)\n\n### session:close\n\n**syntax**: *session:close(code?, debug_data?)*\n\nGenerates a GOAWAY frame with the error code `code` and debug data `debug_data`, the default error code is NO_ERROR and the debug_data is `nil`.\n\nNote this function just queues the GOAWAY frame to the output queue, callers\nshould call `session:flush_queue` to really send the frames.\n\n[Back to TOC](#table-of-contents)\n\n### session:detach\n\n**syntax**: *session:detach()*\n\nDetachs the current HTTP/2 session with the Cosocket object.\n\n[Back to TOC](#table-of-contents)\n\n### session:attach\n\n**syntax**: *local ok, err = session:attach(recv, send, ctx)*\n\nAttachs the current HTTP/2 session with a Cosocket object, in case of failure, `nil` and a Lua string which describes the error reason will be given.\n\nThe meanings of `recv`, `send` and `ctx` are same as these described in [http.new](#http2new).\n\n[Back to TOC](#table-of-contents)\n\nresty.http2.stream\n------------------\n\nThis module implements some low-level stream-relevant APIs.\n\nTo load this module, just do this:\n\n```lua\nlocal h2_stream = require \"resty.http2.stream\"\n```\n\n[Back to TOC](#table-of-contents)\n\n### h2_stream.new\n\n**syntax**: *local stream = h2_stream.new(sid, weight, session)*\n\nCreates a new stream with the identifier `sid`, weight `weight` and the HTTP/2 session which it belongs.\n\n[Back to TOC](#table-of-contents)\n\n### h2_stream.new_root\n\n**syntax**: *local root_stream = h2_stream.new_root(session)*\n\nCreates the root stream with it's session.\n\nThe root stream's identifier is `0x0` and is really a virtual stream which is used to manipulate the whole HTTP/2 session.\n\n[Back to TOC](#table-of-contents)\n\n### stream:submit_headers\n\n**syntax**: *local ok, err = stream:submit_headers(headers, end_stream, priority?, pad?)*\n\nSubmits some HTTP headers to the stream.\n\nThe first parameter `headers`, should be a hash-like Lua table represent the HTTP request headers, it is worth noting that this library doesn't take care of the HTTP headers' semantics, so it's callers' responsibility to supply this, and callers should transform any necessary pesudo headers. For example, `:authority` should be passed rather `Host`;\n\nThe `end_stream` parameter should be a boolean value and is used to control whether the HEADERS frame should take the END_STREAM flag, basically callers can set it true if there is no request body need to send.\n\n`priority` should be a hash-like Lua table (if any), which is used to define a custom stream dependencies:\n  * `priority.sid` represents the dependent stream identifier;\n  * `priority.excl`, whether the new stream becomes the sole dependency of the\n  stream indicated by `priority.sid`;\n  * `priority.weight` defines weight of new stream;\n\nThe last parameter `pad`, represents the padding data.\n\nIn case of failure, `nil` and a Lua string which describes the corresponding error will be given.\n\n[Back to TOC](#table-of-contents)\n\n### stream:submit_data\n\n**syntax**: *local ok, err = stream:submit_data(data, pad, last)*\n\nSubmits some request body to the stream, `data` should be a Lua string, with optional padding data.\n\nThe last parameter `last` is indicated whether this is the last submittion, the current DATA frame will attach the END_STREAM flag if `last` is true.\n\nIn case of failure, `nil` and a Lua string which describes the corresponding error will be given.\n\n[Back to TOC](#table-of-contents)\n\n### stream:submit_window_update\n\n**syntax**: *local ok, err = session:submit_window_update(incr)*\n\nSubmits a WINDOW_UPDATE frame for the stream with an increment `incr`, in case of failure, `nil` and a Lua string which describes the error reason will be given.\n\n[Back to TOC](#table-of-contents)\n\n### stream:set_dependency\n\n**syntax**: *stream:set_dependency(depend, excl)*\n\nSets current stream's dependencies to a stream with the identifier `depend`.\n\nThe second parameter `excl`, indicates whether current stream will be the sole child of `depend`.\n\nWhen `depend` is absent, the target stream will be the root and `excl` will be treat as `false`.\n\n[Back to TOC](#table-of-contents)\n\n### stream:rst\n\n**syntax**: *stream:rst(code)*\n\nGenerates a RST_STREAM frame with the error code `code`. In the case of `code` is absent, the NO_ERROR code will be selected.\n\nNote this method just **generates** a RST_STREAM frame rather than send it, caller should send this frame by calling [session:flush_queue](#sessionflush_queue).\n\n[Back to TOC](#table-of-contents)\n\nresty.http2.frame\n-----------------\n\nThis module implements some low-level frame-relevant APIs.\n\nTo load this module, just do this:\n\n```lua\nlocal h2_frame = require \"resty.http2.frame\"\n```\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.header.new\n\n**syntax**: *local hd = h2_frame.header.new(length, typ, flags, id)*\n\nCreates a frame header, with the payload length `length`, frame type `type` and\ntakes `flags` as the frame flags, which belongs to the stream `id`.\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.header.pack\n\n**syntax**: *h2_frame.header.pack(hd, dst)*\n\nSerializes the frame header `hd` to the destination `dst`. The `dst` must be a\narray-like Lua table.\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.header.unpack\n\n**syntax**: *h2_frame.header.unpack(src)*\n\nDeserializes a frame header from a Lua string `src`, the length of `src` must be at least 9 octets.\n[Back to TOC](#table-of-contents)\n\n### h2_frame.priority.pack\n\n**syntax**: *h2_frame.priority.pack(pf, dst)*\n\nSerializes a PRIORITY frame to the destination `dst`. The `dst` must be a array-like Lua table.\n\nThe `pf` must be a hash-like Lua table which contians:\n\n* `header`, the frame header;\n* `depend`, the dependent stream identifier\n* `excl`, specifies whether the current stream where this PRIORITY frame stays becomes the sole child of the stream identified by `depend`;\n* `weight`, assigns a new weight `weight` to current stream;\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.priority.unpack\n\n**syntax**: *local ok, err = h2_frame.priority.unpack(pf, src, stream)*\n\nDeserializes a PRIORITY frame from a Lua string `src`, the length of `src` must\nbe at least the size specified in the `pf.header.length`.\n\nThe `pf` should be a hash-like Lua table which already contains the current\nPRIORITY frame's header, i.e. `pf.header`.\n\nThe last parameter `stream` specifies the stream that current PRIORITY frame\nbelongs.\n\nCorresponding actions will be taken automatically inside this method like\nbuilding the new dependencies.\n\nIn case of failure, `nil` and an error code will be given.\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.rst_stream.pack\n\n**syntax**: *h2_frame.rst_stream.pack(rf, dst)*\n\nSerializes a RST_STREAM frame to the destination `dst`. The `dst` must be a array-like Lua table.\n\nThe `rf` must be a hash-like Lua table which contains:\n\n* `header`, the frame header;\n* `error_code`, the error code;\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.rst_stream.unpack\n\n**syntax**: *h2_frame.rst_stream.unpack(rf, src, stream)*\n\nDeserializes a RST_STREAM frame from a Lua string `src`. The length of `src`\nmust be at least the size specified in the `rf.header.length`.\n\nThe `rf` should be a hash-like Lua table which already contains the current\nRST_STREAM frame's header, i.e. `rf.header`.\n\nThe last parameter `stream` specifies the stream that current RST_STREAM frame\nbelongs.\n\nCorresponding actions will be taken automatically inside this method like\nchanging the stream's state.\n\nIn case of failure, `nil` and an error code will be given.\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.rst_stream.new\n\n**syntax**: *local rf = h2_frame.rst_stream.new(error_code, sid)*\n\nCreates a RST_STREAM frame with the error code `error_code`, which belongs to\nthe stream `sid`.\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.settings.pack\n\n**syntax**: *h2_frame.settings.pack(sf, dst)*\n\nSerializes a SETTINGS frame to the destination `dst`. The `dst` must be a array-like Lua table.\n\nThe `sf` must be a hash-like Lua table which contains:\n\n* `header`, the frame header;\n* `item`, the specific settings, which should be a array-like Lua table, each element should be a hash-like Lua table:\n  * `id`, the setting identifier, can be:\n    * SETTINGS_ENABLE_PUSH (0x2)\n    * SETTINGS_MAX_CONCURRENT_STREAMS (0x3)\n    * SETTINGS_INITIAL_WINDOW_SIZE (0x4)\n    * SETTINGS_MAX_FRAME_SIZE (0x5)\n  * `value`, the corresponding setting value;\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.settings.unpack\n\n**syntax**: *local ok, err = h2_frame.settings.unpack(sf, src, stream)*\n\nDeserializes a SETTINGS frame from a Lua string `src`. The length of `src` must be at least the size specified in the `sf.header.length`.\n\nThe `sf` should be a hash-like Lua table which already contains the current SETTINGS frame's header, i.e. `sf.header`.\n\nThe last parameter `stream` specifies the stream that current SETTINGS frame belongs (must be the root stream).\n\nCorresponding actions will be taken automatically inside this method like updating the HTTP/2 session settings value.\n\nIn case of failure, `nil` and an error code will be given.\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.settings.new\n\n**syntax**: *local sf = h2_frame.settings.new(flags, payload)*\n\nCreates a SETTINGS frame with the flags `flags` and payload item `payload`.\n\nThe `payload` should be a array-like Lua table, each element should be a hash-like Lua table:\n  * `id`, the setting identifier, can be:\n    * SETTINGS_ENABLE_PUSH (0x2)\n    * SETTINGS_MAX_CONCURRENT_STREAMS (0x3)\n    * SETTINGS_INITIAL_WINDOW_SIZE (0x4)\n    * SETTINGS_MAX_FRAME_SIZE (0x5)\n  * `value`, the corresponding setting value;\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.ping.pack\n\n**syntax**: *h2_frame.ping.pack(pf, dst)*\n\nSerializes a PING frame to the destination `dst`. The `dst` must be a array-like Lua table.\n\nThe `pf` must be a hash-like Lua table which contains:\n\n* `header`, the frame header;\n* `opaque_data_hi`, highest 32 bits value of the corresponding ping data;\n* `opaque_data_lo`, lowest 32 bits value of the corresponding ping data;\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.ping.unpack\n\n**syntax**: *local ok, err = h2_frame.ping.unpack(pf, src, stream)*\n\nDeserializes a PING frame from a Lua string `src`. The length of `src` must be at least the size specified in the `sf.header.length`.\n\nThe `pf` should be a hash-like Lua table which already contains the current PING frame's header, i.e. `pf.header`.\n\nThe last parameter `stream` specifies the stream that current PING frame belongs (must be the root stream).\n\nIn case of failure, `nil` and an error code will be given.\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.goaway.pack\n\n**syntax**: *h2_frame.goaway.pack(gf, dst)*\n\nSerializes a GOAWAY frame to the destination `dst`. The `dst` must be a array-like Lua table.\n\nThe `gf` must be hash-like Lua table which contains:\n\n* `header`, the frame header;\n* `last_stream_id`, the last peer-initialized stream identifier;\n* `error_code`, the error code;\n* `debug_data`, the debug data;\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.goaway.unpack\n\n**syntax**: *local ok, err = h2_frame.goaway.unpack(gf, src, stream)*\n\nDeserializes a GOAWAY frame from a Lua string `src`. The length of `src` must be at least the size specified in the `gf.header.length`.\n\nThe `gf` should be a hash-like Lua table which already contains the current GOAWAY frame's heaer, i.e. `gf.header`.\n\nThe last parameter `stream` specifies the stream that current GOAWAY frame belongs (must be the root stream).\n\nIn case of failure, `nil` and a Lua string which describes the error reason will be given.\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.goaway.new\n\n**syntax**: *local gf = h2_frame.goaway.new(last_sid, error_code, debug_data)*\n\nCreates a GOAWAY frame with the last peer-initialized stream identifier `last_sid`, and error code `error_code`. Optionally, with the debug data `debug_data`.\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.window_update.pack\n\n**syntax**: *h2_frame.window_update.pack(wf, dst)*\n\nSerializes a WINDOW_UPDATE frame to the destination `dst`. The `dst` must be a array-like Lua table.\n\nThe `wf` must be hash-like Lua table which contains:\n\n* `header`, the frame header;\n* `window_size_increment`, the window size increment;\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.window_update.unpack\n\n**syntax**: *local ok, err = h2_frame.window_update.unpack(wf, src, stream)*\n\nDeserializes a WINDOW_UPDATE frame from a Lua string `src`. The length of `src` must be at least the size specified in the `wf.header.length`.\n\nThe `wf` should be a hash-like Lua table which already contains the current WINDOW_UPDATE frame's heaer, i.e. `wf.header`.\n\nThe last parameter `stream` specifies the stream that current WINDOW_UPDATE frame belongs.\n\nIn case of failure, `nil` and an error code will be given.\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.window_update.new\n\n**syntax**: *local wf = h2_frame.window_update.new(sid, window)*\n\nCreates a WINDOW_UPDATE frame with the stream identifier `sid`, and enlarges the window size specified by `window`.\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.headers.pack\n\n**syntax**: *h2_frame.headers.pack(hf, dst)*\n\nSerializes a HEADERS frame to the destination `dst`. The `dst` must be a array-like Lua table.\n\nThe `hf` must be hash-like Lua table which contains:\n\n* `header`, the frame header;\n* `pad`, the padding data;\n* `depend`, the dependent stream identifier;\n* `excl`, specifies whether the stream that current HEADERS frame belongs will become the sole child of the stream `depend`;\n* `weight`, specifies the weight of the stream that current HEADERS frame belongs.\n* `block_frags`, the plain HTTP headers (after the hpack compressing);\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.headers.unpack\n\n**syntax**: *local ok,err = h2_frame.headers.unpack(hf, src, stream)*\n\nDeserializes a HEADERS frame from the Lua string `src`, the length of `src` must be at least the size specified in the `hf.header.length`\n\nThe `hf` should be a hash-like Lua table which already contains the current HEADERS frame's heaer, i.e. `hf.header`.\n\nThe last parameter `stream` specifies the stream that current HEADER frame belongs.\n\nThe corresponding action will be taken, for example, stream state transition will happens.\n\nIn case of failure, `nil` and an error code will be given.\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.headers.new\n\n**syntax**: *local hf = h2_frame.headers.new(frags, pri?, pad?, end_stream, end_headers, sid)*\n\nCreates a HEADERS frame which takes the block fragments `frags`.\n\nThe parameter `pri` can be taken to specify the stream dependencies, `pri` should be a hash-like Lua table, which contains:\n\n* `sid`, the dependent stream identifier;\n* `excl`, whether the stream `sid` will be the sole child of dependent stream;\n* `weight`, defines the current stream's (specified by `sid`) weight\n;\n\nThe `pad` specifies the padding data, which is optional.\n\nWhen `end_stream` is true, current HEADERS frame will takes the END_STREAM flag, likewise, when `end_headers` is true, current HEADERS frame will takes the END_HEADERS flag.\n\nOne should take care that if current HEADERS frame doesn't contain the whole headers, then one or more CONTINUATION frames must be followed according to the HTTP/2 procotol.\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.continuation.pack\n\n**syntax**: *h2_frame.continuation.pack(cf, dst)*\n\nSerializes a CONTINUATION frame to the destination `dst`. The `dst` must be a array-like Lua table.\n\nThe `cf` must be hash-like Lua table which contains:\n\n* `header`, the frame header;\n* `block_frags`, the plain HTTP headers (after the hpack compressing);\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.continuation.unpack\n\n**syntax**: *local ok, err = h2_frame.continuation.unpack(cf, src, stream)*\n\nDeserializes a CONTINUATION frame from the Lua string `src`, the length of `src` must be at least the size specified in the `cf.header.length`\n\nThe `cf` should be a hash-like Lua table which already contains the current CONTINUATION frame's heaer, i.e. `cf.header`.\n\nThe last parameter `stream` specifies the stream that current CONTINUATION frame belongs.\n\nThe corresponding action will be taken, for example, stream state transition will happens.\n\nIn case of failure, `nil` and an error code will be given.\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.continuation.new\n\n**syntax**: *local cf = h2_frame.continuation.new(frags, end_headers, sid)*\n\nCreates a CONTINUATION frame which takes the block fragments `frags`.\n\nWhen `end_headers` is true, current CONTINUATION frame will takes the END_HEADERS flag.\n\nOne should take care that if current CONTINUATION frame doesn't contain the whole headers, then one or more CONTINUATION frames must be followed according to the HTTP/2 procotol.\n\nThe `sid` specifies the stream that current CONTINUATION frame belongs.\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.data.pack\n\n**syntax**: *h2_frame.data.pack(df, dst)*\n\nSerializes a DATA frame to the destination `dst`. The `dst` must be a array-like Lua table.\n\nThe `df` must be hash-like Lua table which contains:\n\n* `header`, the frame header;\n* `payload`, the HTTP request/response body;\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.data.unpack\n\n**syntax**: *local ok, err = h2_frame.data.unpack(df, src, stream)*\n\nDeserializes a DATA frame from the Lua string `src`, the length of `src` must be at least the size specified in the `df.header.length`\n\nThe `df` should be a hash-like Lua table which already contains the current DATA frame's heaer, i.e. `df.header`.\n\nThe last parameter `stream` specifies the stream that current DATA frame belongs.\n\nThe corresponding action will be taken, for example, stream state transition will happens.\n\nIn case of failure, `nil` and an error code will be given.\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.data.new\n\n**syntax**: *local df = h2_frame.data.new(payload, pad, last, sid)*\n\nCreates a DATA frame which takes the payload `payload`.\n\nThe `pad` specifies the padding data, which is optional.\n\nWhen `last` is true, current DATA frame will takes the END_STREAM flag.\n\nThe `sid` specifies the stream that current DATA frame belongs.\n\n[Back to TOC](#table-of-contents)\n\n### h2_frame.push_promise.unpack\n\n**syntax**: *local df = h2_frame.data.new(payload, pad, last, sid)*\n\nCurrently any incoming PUSH_PROMISE frame will be rejected.\n\nThis method always returns `nil` and the error PROTOCOL_ERROR.\n\n[Back to TOC](#table-of-contents)\n\nresty.http2.hpack\n------------------\n\nThis module implements some low-level HPACK APIs.\n\nTo load this module, just do this:\n\n```lua\nlocal hpack = require \"resty.http2.hpack\"\n```\n\n[Back to TOC](#table-of-contents)\n\n### hpack.encode\n\n**syntax**: *hpack.encode(src, dst, lower)*\n\nEncodes the Lua string `src` to destination `dst`, the `dst` must be a array-like Lua table. Huffman codes will be tried firstly.\n\nThe `lower` specifies whether current encoding operation is case-insensitive, default is `false`.\n\n[Back to TOC](#table-of-contents)\n\n### hpack.indexed\n\n**syntax**: *local v = hpack.indexed(index)*\n\nReturns the index after using Indexed Header Field Representation.\n\n[Back to TOC](#table-of-contents)\n\n### hpack.incr_indexed\n\n**syntax**: *local v = hpack.indexed(index)*\n\nReturns the index after using Literal Header Field With Incremental Indexing.\n\n[Back to TOC](#table-of-contents)\n\n### hpack.new\n\n**syntax**: *local h = hpack.new(size)*\n\nCreates a hpack instance, since the HPACK decoding is stateful.\n\nThe `size` represents the maximum hpack table size, default is 4096 bytes.\n\nThe return value `h`, represents the HPACK instance. One of h's member is important, i.e. `h.cached`, which saves the whole header block fragments, and [h:decode](#hdecode) will analysis the data inside the `h.cached`.\n\nCurrently the [h2_frame.headers.unpack](#h2_frameheadersunpack) and\n[h2_frame.continuation.unpack](#h2_framecontinuationunpack) will push header block fragments to `h.cached`, once the block is complete, the decoding will be executed.\n\n[Back to TOC](#table-of-contents)\n\n### h:insert_entry\n\n**syntax**: *local ok = h:insert_entry(header_name, header_value)*\n\nTries to insert a header entry with name `header_name` and value `header_value` to the HPACK dynamic table.\n\nThe insertion maybe failed if this entry is too large. Necessary entry eviction will happen if the space is not enough.\n\nThis method will return `true` if the insertion is successful or `false` if not.\n\n[Back to TOC](#table-of-contents)\n\n### h:resize\n\n**syntax**: *local ok = h:resize(new_size)*\n\nAdjusts the dynamic table size to `new_size`, currently the `new_size` cannot exceed `4096`, other the resize operation will be failed.\n\nWhen the dynamic table size is shrink, some entries will be evicted according the HPACK's rule.\n\nThis method will return `true` if the resize operation is successful or `false` if not.\n\n[Back to TOC](#table-of-contents)\n\n### h:decode\n\n**syntax**: *local ok, err = h:decode(dst)*\n\nDecodes the header block fragments inside `h.cached`, decoded headers will be saved in `dst`, a hash-like Lua table.\n\nIn case of failure, `nil` and an error code will be given.\n\n[Back to TOC](#table-of-contents)\n\n### h:get_indexed_header\n\n**syntax**: *local entry = h:get_indexed_header(index)*\n\nReturns the header entry according the index `index`.\n\nThe return value will be `nil` if the index is invalid, otherwise, the `entry` will be hash-like Lua table with two items:\n\n* `entry.name`, the header name;\n* `entry.value`, the header value;\n\n[Back to TOC](#table-of-contents)\n\nresty.http2.error\n-----------------\n\nThis module implements some low-level error-relevant APIs.\n\nThere many defined error codes, basically they are consistent with HTTP/2 protocol:\n\n* `h2_error.NO_ERROR`\n* `h2_error.PROTOCOL`\n* `h2_error.INTERNAL_ERROR`\n* `h2_error.FLOW_CONTROL_ERROR`\n* `h2_error.SETTINGS_TIMEOUT`\n* `h2_error.STREAM_CLOSED`\n* `h2_error.FRAME_SIZE_ERROR`\n* `h2_error.REFUSED_STREAM`\n* `h2_error.CANCEL`\n* `h2_error.COMPRESSION_ERROR`\n* `h2_error.CONNECT_ERROR`\n* `h2_error.ENHANCE_YOUR_CALM`\n* `h2_error.INADEQUATE_SECURITY`\n* `h2_error.HTTP_1_1_REQUIRED`\n\nAnd three custom error codes:\n\n* `h2_error.STREAM_PROTOCOL_ERROR`, stream level protocol error;\n* `h2_error.STREAM_FLOW_CONTROL_ERROR`, stream level flow control error;\n* `h2_error.STREAM_FRAME_SIZE_ERROR`, stream level frame size error;\n\nStream level errors will not influence the whole connection but reset the current stream.\n\nTo load this module, just do this:\n\n[Back to TOC](#table-of-contents)\n\n### h2_error.strerror\n\n**syntax**: *local msg = h2_error.strerror(code)*\n\nReturns a Lua string which describe the error code `code`, `\"unknown error\"` will be given if the error code is unknown.\n\n[Back to TOC](#table-of-contents)\n\n### h2_error.is_stream_error\n\n**syntax**: *local ok = h2_error.is_stream_error(code)*\n\nJudges whether the error code `code` is a stream-level error.\n\n[Back to TOC](#table-of-contents)\n\n\nAuthor\n======\n\nAlex Zhang (张超) zchao1995@gmail.com, UPYUN Inc.\n\n[Back to TOC](#table-of-contents)\n\n\nCopyright and License\n=====================\n\nPlease see the [LICENSE](LICENSE) file.\n\n[Back to TOC](#table-of-contents)\n\nSee Also\n========\n\n* upyun-resty: https://github.com/upyun/upyun-resty\n* lua-resty-httpipe: https://github.com/timebug/lua-resty-httpipe\n* lua-resty-requests: https://github.com/tokers/lua-resty-requests\n\n[Back to TOC](#table-of-contents)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftokers%2Flua-resty-http2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftokers%2Flua-resty-http2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftokers%2Flua-resty-http2/lists"}