{"id":26866416,"url":"https://github.com/jauntsdn/netty-websocket-http1","last_synced_at":"2025-05-07T01:23:30.445Z","repository":{"id":65507827,"uuid":"583907787","full_name":"jauntsdn/netty-websocket-http1","owner":"jauntsdn","description":"Very fast java/netty websocket-http1 codec with no per-frame heap allocations","archived":false,"fork":false,"pushed_at":"2025-03-29T08:37:17.000Z","size":241,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"develop","last_synced_at":"2025-03-29T09:28:20.398Z","etag":null,"topics":["java","netty","websocket"],"latest_commit_sha":null,"homepage":"","language":"Java","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/jauntsdn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"license.md","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":"2022-12-31T12:09:53.000Z","updated_at":"2025-03-29T08:37:21.000Z","dependencies_parsed_at":"2024-04-30T05:35:32.383Z","dependency_job_id":"f56e594b-94a1-4537-89d0-2a2aedcad541","html_url":"https://github.com/jauntsdn/netty-websocket-http1","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jauntsdn%2Fnetty-websocket-http1","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jauntsdn%2Fnetty-websocket-http1/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jauntsdn%2Fnetty-websocket-http1/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jauntsdn%2Fnetty-websocket-http1/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jauntsdn","download_url":"https://codeload.github.com/jauntsdn/netty-websocket-http1/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246418652,"owners_count":20773935,"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":["java","netty","websocket"],"created_at":"2025-03-31T04:54:35.264Z","updated_at":"2025-03-31T04:54:35.781Z","avatar_url":"https://github.com/jauntsdn.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Maven Central](https://img.shields.io/maven-central/v/com.jauntsdn.netty/netty-websocket-http1)\n[![Build](https://github.com/jauntsdn/netty-websocket-http1/actions/workflows/ci-build.yml/badge.svg)](https://github.com/jauntsdn/netty-websocket-http1/actions/workflows/ci-build.yml)\n\n# netty-websocket-http1\n\nAlternative Netty implementation of [RFC6455](https://tools.ietf.org/html/rfc6455) - the WebSocket protocol. \n\nIts advantages are significant per-core throughput improvement (1.8 - 2x) for small frames compared to netty's out-of-the-box \nwebsocket codecs, minimal heap allocations on frame path, and compatibility with \n[netty-websocket-http2](https://github.com/jauntsdn/netty-websocket-http2).\n\n### use case \u0026 scope\n\n* Intended for dense binary data \u0026 text messages: no extensions (compression) support.\n\n* No per-frame heap allocations in websocket frameFactory / decoder.\n\n* Library assumes small frames - many have payload \u003c= 125 bytes, most are \u003c 1500, maximum supported is 65k (65535 bytes).\n\n* On encoder side 3 use cases are supported: frame factory [[1]](https://github.com/jauntsdn/netty-websocket-http1/blob/fb7bbb12d4fc0e62a72845dee89fe8f1d86f9a0a/netty-websocket-http1-test/src/test/java/com/jauntsdn/netty/handler/codec/http/websocketx/WebSocketCodecTest.java#L1475) (create bytebuffer and encode frame prefix), \nframe encoder [[2]](https://github.com/jauntsdn/netty-websocket-http1/blob/fb7bbb12d4fc0e62a72845dee89fe8f1d86f9a0a/netty-websocket-http1-test/src/test/java/com/jauntsdn/netty/handler/codec/http/websocketx/WebSocketCodecTest.java#L1019) (encode frame prefix into provided bytebuffer), \nframe bulk-encoder [[3]](https://github.com/jauntsdn/netty-websocket-http1/blob/fb7bbb12d4fc0e62a72845dee89fe8f1d86f9a0a/netty-websocket-http1-test/src/test/java/com/jauntsdn/netty/handler/codec/http/websocketx/WebSocketCodecTest.java#L707) (much more performant - encode multiple frames into provided bytebuffer).\n\n* Just codec - fragments, pings, close frames are decoded \u0026 protocol validated only. It is responsibility of user code \nto handle frames according to protocol (reassemble frame fragments, perform graceful close, \nrespond to pings) and do utf8 validation of inbound text frames ([utility](https://github.com/jauntsdn/netty-websocket-http1/blob/fb7bbb12d4fc0e62a72845dee89fe8f1d86f9a0a/netty-websocket-http1/src/main/java/com/jauntsdn/netty/handler/codec/http/websocketx/WebSocketFrameListener.java#L81) is provided).\n\n### build \u0026 binaries\n\n```\n./gradlew\n```\n\nReleases are published on MavenCentral\n```groovy\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    implementation \"com.jauntsdn.netty:netty-websocket-http1:1.3.0\"\n}\n```\n\n### performance\n\nPer-core throughput [this codec perf-test](https://github.com/jauntsdn/netty-websocket-http1/tree/develop/netty-websocket-http1-perftest/src/main/java/com/jauntsdn/netty/handler/codec/http/websocketx/perftest), \n[netty built-in codec perf-test](https://github.com/jauntsdn/netty-websocket-http1/tree/netty-codec/netty-builtin-websocket-perftest/src/main/java/io/netty/handler/codec/http/websocketx/perftest) \ncomparison with netty's out-of-the-box websocket handlers: \nnon-masked frames with 8, 64, 125, 1000 bytes of payload over encrypted/non-encrypted connection.\n\njava 9+\n```\n./gradlew clean build installDist\n./perf_server_run.sh\n./perf_client_run.sh\n```\n\n* encrypted\n\n| payload size | this codec, million messages | netty's codec, million messages |\n| :---         |     :---:     |        :---: |\n| 8            | 2.8 | 1.45 |\n| 64           | 2.3 |  1.2 |\n| 125          | 1.9 | 1.1  |\n| 1000         | 0.52| 0.35 |\n\n### websocket-http2\n\nLibrary may be combined with [jauntsdn/websocket-http2](https://github.com/jauntsdn/netty-websocket-http2) using [http1 codec](https://github.com/jauntsdn/netty-websocket-http2/blob/develop/netty-websocket-http2-callbacks-codec/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/WebSocketCallbacksCodec.java) \n\nfor significantly improved per-core throughput [this codec perf-test](https://github.com/jauntsdn/netty-websocket-http2/tree/develop/netty-websocket-http2-perftest/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/perftest/callbackscodec), \n[netty built-in codec perf-test](https://github.com/jauntsdn/netty-websocket-http2/tree/develop/netty-websocket-http2-perftest/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/perftest/messagecodec):  \n\n* encrypted\n\n| payload size | this codec, million msgs  | netty's codec, million msgs |\n| :---:        |     :---:     |        :---: |\n| 8      | 0.93 | 0.56   |\n| 125    | 0.74 | 0.464  |\n| 1000   | 0.275 | 0.211 |\n\n### frameFactory / callbacks API\n\n[WebSocketFrameFactory](https://github.com/jauntsdn/netty-websocket-http1/blob/develop/netty-websocket-http1/src/main/java/com/jauntsdn/netty/handler/codec/http/websocketx/WebSocketFrameFactory.java) \nto create outbound frames. It is library user responsibility to mask outbound frame once payload is written \n`ByteBuf WebSocketFrameFactory.mask(ByteBuf)`\n\n```java\npublic interface WebSocketFrameFactory {\n\n  ByteBuf createBinaryFrame(ByteBufAllocator allocator, int binaryDataSize);\n  \n  // ByteBuf createTextFrame(ByteBufAllocator allocator, int binaryDataSize);\n  \n  // ByteBuf create*Fragment*(ByteBufAllocator allocator, int textDataSize);\n\n  // create*Frame are omitted for control frames, created in similar fashion\n\n  ByteBuf mask(ByteBuf frame);\n}\n```\n\n[WebSocketFrameListener](https://github.com/jauntsdn/netty-websocket-http1/blob/develop/netty-websocket-http1/src/main/java/com/jauntsdn/netty/handler/codec/http/websocketx/WebSocketFrameListener.java) \nto receive inbound frames\n\n```java\npublic interface WebSocketFrameListener {\n\n  void onChannelRead(\n      ChannelHandlerContext ctx, boolean finalFragment, int rsv, int opcode, ByteBuf payload);\n   \n  // netty handler callbacks are omitted for brevity\n\n  // lifecycle\n  default void onOpen(ChannelHandlerContext ctx) {}\n\n  default void onClose(ChannelHandlerContext ctx) {}\n}\n```\n\n[WebSocketCallbacksHandler](https://github.com/jauntsdn/netty-websocket-http1/blob/develop/netty-websocket-http1/src/main/java/com/jauntsdn/netty/handler/codec/http/websocketx/WebSocketCallbacksHandler.java) \nto exchange `WebSocketFrameListener` for `WebSocketFrameFactory` on successful websocket handshake\n\n```java\npublic interface WebSocketCallbacksHandler {\n\n  WebSocketFrameListener exchange(\n      ChannelHandlerContext ctx, WebSocketFrameFactory webSocketFrameFactory);\n}\n```\n\n### testing\n\n* WebSocket frames [integration tests](https://github.com/jauntsdn/netty-websocket-http1/blob/develop/netty-websocket-http1-test/src/test/java/com/jauntsdn/netty/handler/codec/http/websocketx/WebSocketCodecTest.java): \ncontrol \u0026 data frames of all allowed sizes, jauntsdn/netty-websocket-http1 client, netty websocket server. \n\n* WebSocket frames long-running [soak test](https://github.com/jauntsdn/netty-websocket-http1/tree/develop/netty-websocket-http1-soaktest/src/main/java/com/jauntsdn/netty/handler/codec/http/websocketx/soaktest): \nexercising all logic paths of codec with 100m of randomized frames over multiple connections: netty websocket client, jauntsdn/netty-websocket-http1 server.\n\n* [Perf tests](https://github.com/jauntsdn/netty-websocket-http1/tree/develop/netty-websocket-http1-perftest/src/main/java/com/jauntsdn/netty/handler/codec/http/websocketx/perftest): \nestimation of per-core throughput of jauntsdn/netty-websocket-http1 client \u0026 server.\n\n### examples\n\n`netty-websocket-http1-perftest` may serve as API showcase for both [client](https://github.com/jauntsdn/netty-websocket-http1/blob/develop/netty-websocket-http1-perftest/src/main/java/com/jauntsdn/netty/handler/codec/http/websocketx/perftest/client/Main.java) \nand [server](https://github.com/jauntsdn/netty-websocket-http1/blob/develop/netty-websocket-http1-perftest/src/main/java/com/jauntsdn/netty/handler/codec/http/websocketx/perftest/server/Main.java):\n\n## LICENSE\n\nCopyright 2022-Present Maksym Ostroverkhov.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjauntsdn%2Fnetty-websocket-http1","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjauntsdn%2Fnetty-websocket-http1","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjauntsdn%2Fnetty-websocket-http1/lists"}