├── .github ├── dependabot.yml ├── labeler.yml ├── release-drafter.yml └── workflows │ ├── auto-labeler.yml │ ├── dependabot_automerge.yml │ ├── gotidy.yml │ ├── linter.yml │ ├── release-drafter.yml │ ├── security.yml │ └── test.yml ├── .gitignore ├── LICENSE ├── README.md ├── go.mod ├── go.sum ├── websocket.go └── websocket_test.go /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 2 | 3 | version: 2 4 | updates: 5 | - package-ecosystem: "gomod" 6 | directory: "/" # Location of package manifests 7 | labels: 8 | - "🤖 Dependencies" 9 | schedule: 10 | interval: daily 11 | - package-ecosystem: "github-actions" 12 | directory: "/" 13 | schedule: 14 | interval: daily 15 | labels: 16 | - "🤖 Dependencies" 17 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | version: v1 2 | labels: 3 | - label: '📒 Documentation' 4 | matcher: 5 | title: '\b(docs|doc:|\[doc\]|README|typos|comment|documentation)\b' 6 | - label: '☢️ Bug' 7 | matcher: 8 | title: '\b(fix|race|bug|missing|correct)\b' 9 | - label: '🧹 Updates' 10 | matcher: 11 | title: '\b(improve|update|refactor|deprecated|remove|unused|test)\b' 12 | - label: '🤖 Dependencies' 13 | matcher: 14 | title: '\b(bumb|bdependencies)\b' 15 | - label: '✏️ Feature' 16 | matcher: 17 | title: '\b(feature|feat|create|implement|add)\b' 18 | - label: '🤔 Question' 19 | matcher: 20 | title: '\b(question|how)\b' 21 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name-template: 'v$RESOLVED_VERSION' 2 | tag-template: 'v$RESOLVED_VERSION' 3 | categories: 4 | - title: '🚀 New' 5 | labels: 6 | - '✏️ Feature' 7 | - title: '🧹 Updates' 8 | labels: 9 | - '🧹 Updates' 10 | - '🤖 Dependencies' 11 | - title: '🐛 Fixes' 12 | labels: 13 | - '☢️ Bug' 14 | - title: '📚 Documentation' 15 | labels: 16 | - '📒 Documentation' 17 | change-template: '- $TITLE (#$NUMBER)' 18 | change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks. 19 | version-resolver: 20 | major: 21 | labels: 22 | - 'major' 23 | minor: 24 | labels: 25 | - 'minor' 26 | - '✏️ Feature' 27 | patch: 28 | labels: 29 | - 'patch' 30 | - '📒 Documentation' 31 | - '☢️ Bug' 32 | - '🤖 Dependencies' 33 | - '🧹 Updates' 34 | default: patch 35 | template: | 36 | $CHANGES 37 | 38 | **Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION 39 | 40 | Thank you $CONTRIBUTORS for making this update possible. 41 | -------------------------------------------------------------------------------- /.github/workflows/auto-labeler.yml: -------------------------------------------------------------------------------- 1 | name: Auto labeler 2 | on: 3 | issues: 4 | types: [ opened, edited, milestoned ] 5 | pull_request_target: 6 | types: [ opened ] 7 | permissions: 8 | contents: read 9 | issues: write 10 | pull-requests: write 11 | statuses: write 12 | checks: write 13 | jobs: 14 | labeler: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Check Labels 18 | id: labeler 19 | uses: fuxingloh/multi-labeler@v2 20 | with: 21 | github-token: ${{secrets.GITHUB_TOKEN}} 22 | -------------------------------------------------------------------------------- /.github/workflows/dependabot_automerge.yml: -------------------------------------------------------------------------------- 1 | name: Dependabot auto-merge 2 | on: 3 | pull_request 4 | 5 | permissions: 6 | contents: write 7 | pull-requests: write 8 | 9 | jobs: 10 | wait_for_checks: 11 | runs-on: ubuntu-latest 12 | if: ${{ github.actor == 'dependabot[bot]' }} 13 | steps: 14 | - name: Wait for check is finished 15 | uses: lewagon/wait-on-check-action@v1.3.1 16 | id: wait_for_checks 17 | with: 18 | ref: ${{ github.event.pull_request.head.sha || github.sha }} 19 | running-workflow-name: wait_for_checks 20 | check-regexp: Tests 21 | repo-token: ${{ secrets.PR_TOKEN }} 22 | wait-interval: 10 23 | dependabot: 24 | needs: [wait_for_checks] 25 | name: Dependabot auto-merge 26 | runs-on: ubuntu-latest 27 | if: ${{ github.actor == 'dependabot[bot]' }} 28 | steps: 29 | - name: Dependabot metadata 30 | id: metadata 31 | uses: dependabot/fetch-metadata@v1.5.0 32 | with: 33 | github-token: "${{ secrets.PR_TOKEN }}" 34 | - name: Enable auto-merge for Dependabot PRs 35 | if: ${{steps.metadata.outputs.update-type == 'version-update:semver-minor' || steps.metadata.outputs.update-type == 'version-update:semver-patch'}} 36 | run: | 37 | gh pr review --approve "$PR_URL" 38 | gh pr merge --auto --merge "$PR_URL" 39 | env: 40 | PR_URL: ${{github.event.pull_request.html_url}} 41 | GITHUB_TOKEN: ${{secrets.PR_TOKEN}} 42 | -------------------------------------------------------------------------------- /.github/workflows/gotidy.yml: -------------------------------------------------------------------------------- 1 | name: Tidy 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | paths: 8 | - '.github/workflows/gotidy.yml' 9 | - 'go.mod' 10 | - 'go.sum' 11 | 12 | jobs: 13 | fix: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - 17 | name: Checkout 18 | uses: actions/checkout@v3.5.2 19 | - 20 | name: Set up Go 21 | uses: actions/setup-go@v4 22 | with: 23 | go-version: 1.17 24 | - 25 | name: Tidy 26 | run: | 27 | rm -f go.sum 28 | go clean -modcache 29 | go mod tidy 30 | - 31 | name: Set up Git 32 | env: 33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 34 | run: | 35 | git config user.name GitHub 36 | git config user.email noreply@github.com 37 | git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git 38 | - 39 | name: Commit and push changes 40 | run: | 41 | git add . 42 | if output=$(git status --porcelain) && [ ! -z "$output" ]; then 43 | git commit --author "github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>" --message "Fix go modules" 44 | git push 45 | fi 46 | -------------------------------------------------------------------------------- /.github/workflows/linter.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | - main 6 | pull_request: 7 | name: Linter 8 | jobs: 9 | Golint: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Fetch Repository 13 | uses: actions/checkout@v3.5.2 14 | - name: Run Golint 15 | uses: reviewdog/action-golangci-lint@v2 16 | with: 17 | golangci_lint_flags: "--tests=false" 18 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | 3 | on: 4 | push: 5 | # branches to consider in the event; optional, defaults to all 6 | branches: 7 | - master 8 | - main 9 | 10 | jobs: 11 | update_release_draft: 12 | runs-on: ubuntu-latest 13 | steps: 14 | # (Optional) GitHub Enterprise requires GHE_HOST variable set 15 | #- name: Set GHE_HOST 16 | # run: | 17 | # echo "GHE_HOST=${GITHUB_SERVER_URL##https:\/\/}" >> $GITHUB_ENV 18 | 19 | # Drafts your next Release notes as Pull Requests are merged into "master" 20 | - uses: release-drafter/release-drafter@v5 21 | # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml 22 | # with: 23 | # config-name: my-config.yml 24 | # disable-autolabeler: true 25 | env: 26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 27 | -------------------------------------------------------------------------------- /.github/workflows/security.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | - main 6 | pull_request: 7 | name: Security 8 | jobs: 9 | Gosec: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Fetch Repository 13 | uses: actions/checkout@v3.5.2 14 | - name: Run Gosec 15 | uses: securego/gosec@master 16 | with: 17 | args: ./... 18 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | pull_request: 6 | name: Tests 7 | jobs: 8 | Tests: 9 | name: Tests 10 | strategy: 11 | matrix: 12 | go-version: 13 | - 1.17.x 14 | - 1.18.x 15 | - 1.19.x 16 | - 1.20.x 17 | platform: 18 | - ubuntu-latest 19 | - windows-latest 20 | - macos-latest 21 | runs-on: '${{ matrix.platform }}' 22 | steps: 23 | - name: Install Go 24 | uses: actions/setup-go@v4 25 | with: 26 | go-version: ${{ matrix.go-version }} 27 | - name: Setup Golang caches 28 | uses: actions/cache@v3 29 | with: 30 | # In order: 31 | # * Module download cache 32 | # * Build cache (Linux) 33 | # * Build cache (Mac) 34 | # * Build cache (Windows) 35 | path: | 36 | ~/go/pkg/mod 37 | ~/.cache/go-build 38 | ~/Library/Caches/go-build 39 | ~\AppData\Local\go-build 40 | key: ${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }} 41 | restore-keys: | 42 | ${{ runner.os }}-go-${{ matrix.go-version }}- 43 | - name: Fetch Repository 44 | uses: actions/checkout@v3.5.2 45 | - name: Run Test 46 | run: go test ./... -v -race 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | .idea 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Fiber 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ⚠️ Deprecated repository 2 | 3 | This middleware is no longer maintained, it is available within [Fiber Contrib](https://github.com/gofiber/contrib/tree/main/websocket). 4 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | // Deprecated: Now part of the fiber contrib repo: 2 | // github.com/gofiber/contrib/websocket 3 | module github.com/gofiber/websocket/v2 4 | 5 | go 1.17 6 | 7 | require ( 8 | github.com/fasthttp/websocket v1.5.3 9 | github.com/gofiber/fiber/v2 v2.46.0 10 | github.com/valyala/fasthttp v1.47.0 11 | ) 12 | 13 | require ( 14 | github.com/andybalholm/brotli v1.0.5 // indirect 15 | github.com/google/uuid v1.3.0 // indirect 16 | github.com/klauspost/compress v1.16.5 // indirect 17 | github.com/mattn/go-colorable v0.1.13 // indirect 18 | github.com/mattn/go-isatty v0.0.18 // indirect 19 | github.com/mattn/go-runewidth v0.0.14 // indirect 20 | github.com/philhofer/fwd v1.1.2 // indirect 21 | github.com/rivo/uniseg v0.2.0 // indirect 22 | github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect 23 | github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect 24 | github.com/tinylib/msgp v1.1.8 // indirect 25 | github.com/valyala/bytebufferpool v1.0.0 // indirect 26 | github.com/valyala/tcplisten v1.0.0 // indirect 27 | golang.org/x/sys v0.8.0 // indirect 28 | ) 29 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= 2 | github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= 3 | github.com/fasthttp/websocket v1.5.3 h1:TPpQuLwJYfd4LJPXvHDYPMFWbLjsT91n3GpWtCQtdek= 4 | github.com/fasthttp/websocket v1.5.3/go.mod h1:46gg/UBmTU1kUaTcwQXpUxtRwG2PvIZYeA8oL6vF3Fs= 5 | github.com/gofiber/fiber/v2 v2.46.0 h1:wkkWotblsGVlLjXj2dpgKQAYHtXumsK/HyFugQM68Ns= 6 | github.com/gofiber/fiber/v2 v2.46.0/go.mod h1:DNl0/c37WLe0g92U6lx1VMQuxGUQY5V7EIaVoEsUffc= 7 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 8 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 9 | github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= 10 | github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= 11 | github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= 12 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 13 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 14 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 15 | github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= 16 | github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 17 | github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= 18 | github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 19 | github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= 20 | github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= 21 | github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= 22 | github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= 23 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 24 | github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4= 25 | github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94/go.mod h1:90zrgN3D/WJsDd1iXHT96alCoN2KJo6/4x1DZC3wZs8= 26 | github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4= 27 | github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk= 28 | github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= 29 | github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw= 30 | github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= 31 | github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= 32 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= 33 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 34 | github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c= 35 | github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= 36 | github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= 37 | github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= 38 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 39 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 40 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 41 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 42 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 43 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 44 | golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= 45 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 46 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 47 | golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 48 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 49 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 50 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 51 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 52 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 53 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 54 | golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= 55 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 56 | golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= 57 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 58 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 59 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 60 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 61 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 62 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 63 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 64 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 65 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 66 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 67 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 68 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 69 | golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 70 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 71 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 72 | golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= 73 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 74 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 75 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 76 | golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= 77 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 78 | golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= 79 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 80 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 81 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 82 | golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 83 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 84 | golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 85 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 86 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 87 | golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 88 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 89 | golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= 90 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 91 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 92 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 93 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 94 | -------------------------------------------------------------------------------- /websocket.go: -------------------------------------------------------------------------------- 1 | // 🚀 Fiber is an Express inspired web framework written in Go with 💖 2 | // 📌 API Documentation: https://fiber.wiki 3 | // 📝 Github Repository: https://github.com/gofiber/fiber 4 | 5 | package websocket 6 | 7 | import ( 8 | "errors" 9 | "io" 10 | "sync" 11 | "time" 12 | 13 | "github.com/fasthttp/websocket" 14 | "github.com/gofiber/fiber/v2" 15 | "github.com/gofiber/fiber/v2/utils" 16 | "github.com/valyala/fasthttp" 17 | ) 18 | 19 | // Config ... 20 | type Config struct { 21 | // Filter defines a function to skip middleware. 22 | // Optional. Default: nil 23 | Filter func(*fiber.Ctx) bool 24 | 25 | // HandshakeTimeout specifies the duration for the handshake to complete. 26 | HandshakeTimeout time.Duration 27 | 28 | // Subprotocols specifies the client's requested subprotocols. 29 | Subprotocols []string 30 | 31 | // Allowed Origin's based on the Origin header, this validate the request origin to 32 | // prevent cross-site request forgery. Everything is allowed if left empty. 33 | Origins []string 34 | 35 | // ReadBufferSize and WriteBufferSize specify I/O buffer sizes in bytes. If a buffer 36 | // size is zero, then a useful default size is used. The I/O buffer sizes 37 | // do not limit the size of the messages that can be sent or received. 38 | ReadBufferSize, WriteBufferSize int 39 | 40 | // WriteBufferPool is a pool of buffers for write operations. If the value 41 | // is not set, then write buffers are allocated to the connection for the 42 | // lifetime of the connection. 43 | // 44 | // A pool is most useful when the application has a modest volume of writes 45 | // across a large number of connections. 46 | // 47 | // Applications should use a single pool for each unique value of 48 | // WriteBufferSize. 49 | WriteBufferPool websocket.BufferPool 50 | 51 | // EnableCompression specifies if the client should attempt to negotiate 52 | // per message compression (RFC 7692). Setting this value to true does not 53 | // guarantee that compression will be supported. Currently only "no context 54 | // takeover" modes are supported. 55 | EnableCompression bool 56 | } 57 | 58 | // New returns a new `handler func(*Conn)` that upgrades a client to the 59 | // websocket protocol, you can pass an optional config. 60 | func New(handler func(*Conn), config ...Config) fiber.Handler { 61 | // Init config 62 | var cfg Config 63 | if len(config) > 0 { 64 | cfg = config[0] 65 | } 66 | if len(cfg.Origins) == 0 { 67 | cfg.Origins = []string{"*"} 68 | } 69 | if cfg.ReadBufferSize == 0 { 70 | cfg.ReadBufferSize = 1024 71 | } 72 | if cfg.WriteBufferSize == 0 { 73 | cfg.WriteBufferSize = 1024 74 | } 75 | var upgrader = websocket.FastHTTPUpgrader{ 76 | HandshakeTimeout: cfg.HandshakeTimeout, 77 | Subprotocols: cfg.Subprotocols, 78 | ReadBufferSize: cfg.ReadBufferSize, 79 | WriteBufferSize: cfg.WriteBufferSize, 80 | EnableCompression: cfg.EnableCompression, 81 | WriteBufferPool: cfg.WriteBufferPool, 82 | CheckOrigin: func(fctx *fasthttp.RequestCtx) bool { 83 | if cfg.Origins[0] == "*" { 84 | return true 85 | } 86 | origin := utils.UnsafeString(fctx.Request.Header.Peek("Origin")) 87 | for i := range cfg.Origins { 88 | if cfg.Origins[i] == origin { 89 | return true 90 | } 91 | } 92 | return false 93 | }, 94 | } 95 | return func(c *fiber.Ctx) error { 96 | if cfg.Filter != nil && !cfg.Filter(c) { 97 | return c.Next() 98 | } 99 | 100 | conn := acquireConn() 101 | // locals 102 | c.Context().VisitUserValues(func(key []byte, value interface{}) { 103 | conn.locals[string(key)] = value 104 | }) 105 | 106 | // params 107 | params := c.Route().Params 108 | for i := 0; i < len(params); i++ { 109 | conn.params[utils.CopyString(params[i])] = utils.ImmutableString(c.Params(params[i])) 110 | } 111 | 112 | // queries 113 | c.Context().QueryArgs().VisitAll(func(key, value []byte) { 114 | conn.queries[string(key)] = string(value) 115 | }) 116 | 117 | // cookies 118 | c.Context().Request.Header.VisitAllCookie(func(key, value []byte) { 119 | conn.cookies[string(key)] = string(value) 120 | }) 121 | 122 | // headers 123 | c.Context().Request.Header.VisitAll(func(key, value []byte) { 124 | conn.headers[string(key)] = string(value) 125 | }) 126 | 127 | if err := upgrader.Upgrade(c.Context(), func(fconn *websocket.Conn) { 128 | conn.Conn = fconn 129 | defer releaseConn(conn) 130 | handler(conn) 131 | }); err != nil { // Upgrading required 132 | return fiber.ErrUpgradeRequired 133 | } 134 | 135 | return nil 136 | } 137 | } 138 | 139 | // Conn https://godoc.org/github.com/gorilla/websocket#pkg-index 140 | type Conn struct { 141 | *websocket.Conn 142 | locals map[string]interface{} 143 | params map[string]string 144 | cookies map[string]string 145 | headers map[string]string 146 | queries map[string]string 147 | } 148 | 149 | // Conn pool 150 | var poolConn = sync.Pool{ 151 | New: func() interface{} { 152 | return new(Conn) 153 | }, 154 | } 155 | 156 | // Acquire Conn from pool 157 | func acquireConn() *Conn { 158 | conn := poolConn.Get().(*Conn) 159 | conn.locals = make(map[string]interface{}) 160 | conn.params = make(map[string]string) 161 | conn.queries = make(map[string]string) 162 | conn.cookies = make(map[string]string) 163 | conn.headers = make(map[string]string) 164 | return conn 165 | } 166 | 167 | // Return Conn to pool 168 | func releaseConn(conn *Conn) { 169 | conn.Conn = nil 170 | poolConn.Put(conn) 171 | } 172 | 173 | // Locals makes it possible to pass interface{} values under string keys scoped to the request 174 | // and therefore available to all following routes that match the request. 175 | func (conn *Conn) Locals(key string) interface{} { 176 | return conn.locals[key] 177 | } 178 | 179 | // Params is used to get the route parameters. 180 | // Defaults to empty string "" if the param doesn't exist. 181 | // If a default value is given, it will return that value if the param doesn't exist. 182 | func (conn *Conn) Params(key string, defaultValue ...string) string { 183 | v, ok := conn.params[key] 184 | if !ok && len(defaultValue) > 0 { 185 | return defaultValue[0] 186 | } 187 | return v 188 | } 189 | 190 | // Query returns the query string parameter in the url. 191 | // Defaults to empty string "" if the query doesn't exist. 192 | // If a default value is given, it will return that value if the query doesn't exist. 193 | func (conn *Conn) Query(key string, defaultValue ...string) string { 194 | v, ok := conn.queries[key] 195 | if !ok && len(defaultValue) > 0 { 196 | return defaultValue[0] 197 | } 198 | return v 199 | } 200 | 201 | // Cookies is used for getting a cookie value by key 202 | // Defaults to empty string "" if the cookie doesn't exist. 203 | // If a default value is given, it will return that value if the cookie doesn't exist. 204 | func (conn *Conn) Cookies(key string, defaultValue ...string) string { 205 | v, ok := conn.cookies[key] 206 | if !ok && len(defaultValue) > 0 { 207 | return defaultValue[0] 208 | } 209 | return v 210 | } 211 | 212 | // Headers is used for getting a header value by key 213 | // Defaults to empty string "" if the header doesn't exist. 214 | // If a default value is given, it will return that value if the header doesn't exist. 215 | func (conn *Conn) Headers(key string, defaultValue ...string) string { 216 | v, ok := conn.headers[key] 217 | if !ok && len(defaultValue) > 0 { 218 | return defaultValue[0] 219 | } 220 | return v 221 | } 222 | 223 | // Constants are taken from https://github.com/fasthttp/websocket/blob/master/conn.go#L43 224 | 225 | // Close codes defined in RFC 6455, section 11.7. 226 | const ( 227 | CloseNormalClosure = 1000 228 | CloseGoingAway = 1001 229 | CloseProtocolError = 1002 230 | CloseUnsupportedData = 1003 231 | CloseNoStatusReceived = 1005 232 | CloseAbnormalClosure = 1006 233 | CloseInvalidFramePayloadData = 1007 234 | ClosePolicyViolation = 1008 235 | CloseMessageTooBig = 1009 236 | CloseMandatoryExtension = 1010 237 | CloseInternalServerErr = 1011 238 | CloseServiceRestart = 1012 239 | CloseTryAgainLater = 1013 240 | CloseTLSHandshake = 1015 241 | ) 242 | 243 | // The message types are defined in RFC 6455, section 11.8. 244 | const ( 245 | // TextMessage denotes a text data message. The text message payload is 246 | // interpreted as UTF-8 encoded text data. 247 | TextMessage = 1 248 | 249 | // BinaryMessage denotes a binary data message. 250 | BinaryMessage = 2 251 | 252 | // CloseMessage denotes a close control message. The optional message 253 | // payload contains a numeric code and text. Use the FormatCloseMessage 254 | // function to format a close message payload. 255 | CloseMessage = 8 256 | 257 | // PingMessage denotes a ping control message. The optional message payload 258 | // is UTF-8 encoded text. 259 | PingMessage = 9 260 | 261 | // PongMessage denotes a pong control message. The optional message payload 262 | // is UTF-8 encoded text. 263 | PongMessage = 10 264 | ) 265 | 266 | var ( 267 | // ErrBadHandshake is returned when the server response to opening handshake is 268 | // invalid. 269 | ErrBadHandshake = errors.New("websocket: bad handshake") 270 | // ErrCloseSent is returned when the application writes a message to the 271 | // connection after sending a close message. 272 | ErrCloseSent = errors.New("websocket: close sent") 273 | // ErrReadLimit is returned when reading a message that is larger than the 274 | // read limit set for the connection. 275 | ErrReadLimit = errors.New("websocket: read limit exceeded") 276 | ) 277 | 278 | // FormatCloseMessage formats closeCode and text as a WebSocket close message. 279 | // An empty message is returned for code CloseNoStatusReceived. 280 | func FormatCloseMessage(closeCode int, text string) []byte { 281 | return websocket.FormatCloseMessage(closeCode, text) 282 | } 283 | 284 | // IsCloseError returns boolean indicating whether the error is a *CloseError 285 | // with one of the specified codes. 286 | func IsCloseError(err error, codes ...int) bool { 287 | return websocket.IsCloseError(err, codes...) 288 | } 289 | 290 | // IsUnexpectedCloseError returns boolean indicating whether the error is a 291 | // *CloseError with a code not in the list of expected codes. 292 | func IsUnexpectedCloseError(err error, expectedCodes ...int) bool { 293 | return websocket.IsUnexpectedCloseError(err, expectedCodes...) 294 | } 295 | 296 | // IsWebSocketUpgrade returns true if the client requested upgrade to the 297 | // WebSocket protocol. 298 | func IsWebSocketUpgrade(c *fiber.Ctx) bool { 299 | return websocket.FastHTTPIsWebSocketUpgrade(c.Context()) 300 | } 301 | 302 | // JoinMessages concatenates received messages to create a single io.Reader. 303 | // The string term is appended to each message. The returned reader does not 304 | // support concurrent calls to the Read method. 305 | func JoinMessages(c *websocket.Conn, term string) io.Reader { 306 | return websocket.JoinMessages(c, term) 307 | } 308 | -------------------------------------------------------------------------------- /websocket_test.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | --------------------------------------------------------------------------------