├── .editorconfig ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── 0-new-issue.yml │ ├── 1-new-feature.yml │ └── config.yml └── workflows │ └── build.yml ├── .gitignore ├── .pr-preview.json ├── LICENSE ├── Makefile ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── index.bs └── review-drafts ├── 2022-03.bs ├── 2022-09.bs └── 2023-09.bs /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | charset = utf-8 7 | indent_size = 2 8 | indent_style = space 9 | trim_trailing_whitespace = true 10 | max_line_length = 100 11 | 12 | [Makefile] 13 | indent_style = tab 14 | 15 | [*.md] 16 | max_line_length = off 17 | 18 | [*.bs] 19 | indent_size = 1 20 | 21 | [*.py] 22 | indent_size = 4 23 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.bs diff=html linguist-language=HTML 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/0-new-issue.yml: -------------------------------------------------------------------------------- 1 | name: New issue 2 | description: File a new issue against the WebSockets Standard. 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: | 7 | Before filling out this form, please familiarize yourself with the [Code of Conduct](https://whatwg.org/code-of-conduct). You might also find the [FAQ](https://whatwg.org/faq) and [Working Mode](https://whatwg.org/working-mode) useful. 8 | 9 | If at any point you have questions, please reach out to us on [Chat](https://whatwg.org/chat). 10 | - type: textarea 11 | attributes: 12 | label: "What is the issue with the WebSockets Standard?" 13 | validations: 14 | required: true 15 | - type: markdown 16 | attributes: 17 | value: "Thank you for taking the time to improve the WebSockets Standard!" 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1-new-feature.yml: -------------------------------------------------------------------------------- 1 | name: New feature 2 | description: Request a new feature in the WebSockets Standard. 3 | labels: ["addition/proposal", "needs implementer interest"] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Before filling out this form, please familiarize yourself with the [Code of Conduct](https://whatwg.org/code-of-conduct), [FAQ](https://whatwg.org/faq), and [Working Mode](https://whatwg.org/working-mode). They help with setting expectations and making sure you know what is required. The FAQ ["How should I go about proposing new features to WHATWG standards?"](https://whatwg.org/faq#adding-new-features) is especially relevant. 9 | 10 | If at any point you have questions, please reach out to us on [Chat](https://whatwg.org/chat). 11 | - type: textarea 12 | attributes: 13 | label: "What problem are you trying to solve?" 14 | validations: 15 | required: true 16 | - type: textarea 17 | attributes: 18 | label: "What solutions exist today?" 19 | - type: textarea 20 | attributes: 21 | label: "How would you solve it?" 22 | - type: textarea 23 | attributes: 24 | label: "Anything else?" 25 | - type: markdown 26 | attributes: 27 | value: "Thank you for taking the time to improve the WebSockets Standard!" 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Chat 4 | url: https://whatwg.org/chat 5 | about: Please do reach out with questions and feedback! 6 | - name: Stack Overflow 7 | url: https://stackoverflow.com/ 8 | about: If you're having trouble building a web page, this is not the right repository. Consider asking your question on Stack Overflow instead. 9 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | push: 8 | branches: 9 | - main 10 | workflow_dispatch: 11 | 12 | jobs: 13 | build: 14 | name: Build 15 | runs-on: ubuntu-22.04 16 | steps: 17 | - uses: actions/checkout@v3 18 | with: 19 | fetch-depth: 2 20 | - uses: actions/setup-python@v4 21 | with: 22 | python-version: "3.11" 23 | - run: pip install bikeshed && bikeshed update 24 | # Note: `make deploy` will do a deploy dry run on PRs. 25 | - run: make deploy 26 | env: 27 | SERVER: ${{ secrets.MARQUEE_SERVER }} 28 | SERVER_PUBLIC_KEY: ${{ secrets.MARQUEE_PUBLIC_KEY }} 29 | SERVER_DEPLOY_KEY: ${{ secrets.MARQUEE_DEPLOY_KEY }} 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /websockets.spec.whatwg.org/ 2 | /deploy.sh 3 | /index.html 4 | -------------------------------------------------------------------------------- /.pr-preview.json: -------------------------------------------------------------------------------- 1 | { 2 | "src_file": "index.bs", 3 | "type": "bikeshed", 4 | "params": { 5 | "force": 1, 6 | "md-status": "LS-PR", 7 | "md-Text-Macro": "PR-NUMBER {{ pull_request.number }}" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright © WHATWG (Apple, Google, Mozilla, Microsoft). 2 | 3 | This work is licensed under a Creative Commons Attribution 4.0 International 4 | License. To the extent portions of it are incorporated into source code, 5 | such portions in the source code are licensed under the BSD 3-Clause License instead. 6 | 7 | - - - - 8 | 9 | Creative Commons Attribution 4.0 International Public License 10 | 11 | By exercising the Licensed Rights (defined below), You accept and agree 12 | to be bound by the terms and conditions of this Creative Commons 13 | Attribution 4.0 International Public License ("Public License"). To the 14 | extent this Public License may be interpreted as a contract, You are 15 | granted the Licensed Rights in consideration of Your acceptance of 16 | these terms and conditions, and the Licensor grants You such rights in 17 | consideration of benefits the Licensor receives from making the 18 | Licensed Material available under these terms and conditions. 19 | 20 | 21 | Section 1 -- Definitions. 22 | 23 | a. Adapted Material means material subject to Copyright and Similar 24 | Rights that is derived from or based upon the Licensed Material 25 | and in which the Licensed Material is translated, altered, 26 | arranged, transformed, or otherwise modified in a manner requiring 27 | permission under the Copyright and Similar Rights held by the 28 | Licensor. For purposes of this Public License, where the Licensed 29 | Material is a musical work, performance, or sound recording, 30 | Adapted Material is always produced where the Licensed Material is 31 | synched in timed relation with a moving image. 32 | 33 | b. Adapter's License means the license You apply to Your Copyright 34 | and Similar Rights in Your contributions to Adapted Material in 35 | accordance with the terms and conditions of this Public License. 36 | 37 | c. Copyright and Similar Rights means copyright and/or similar rights 38 | closely related to copyright including, without limitation, 39 | performance, broadcast, sound recording, and Sui Generis Database 40 | Rights, without regard to how the rights are labeled or 41 | categorized. For purposes of this Public License, the rights 42 | specified in Section 2(b)(1)-(2) are not Copyright and Similar 43 | Rights. 44 | 45 | d. Effective Technological Measures means those measures that, in the 46 | absence of proper authority, may not be circumvented under laws 47 | fulfilling obligations under Article 11 of the WIPO Copyright 48 | Treaty adopted on December 20, 1996, and/or similar international 49 | agreements. 50 | 51 | e. Exceptions and Limitations means fair use, fair dealing, and/or 52 | any other exception or limitation to Copyright and Similar Rights 53 | that applies to Your use of the Licensed Material. 54 | 55 | f. Licensed Material means the artistic or literary work, database, 56 | or other material to which the Licensor applied this Public 57 | License. 58 | 59 | g. Licensed Rights means the rights granted to You subject to the 60 | terms and conditions of this Public License, which are limited to 61 | all Copyright and Similar Rights that apply to Your use of the 62 | Licensed Material and that the Licensor has authority to license. 63 | 64 | h. Licensor means the individual(s) or entity(ies) granting rights 65 | under this Public License. 66 | 67 | i. Share means to provide material to the public by any means or 68 | process that requires permission under the Licensed Rights, such 69 | as reproduction, public display, public performance, distribution, 70 | dissemination, communication, or importation, and to make material 71 | available to the public including in ways that members of the 72 | public may access the material from a place and at a time 73 | individually chosen by them. 74 | 75 | j. Sui Generis Database Rights means rights other than copyright 76 | resulting from Directive 96/9/EC of the European Parliament and of 77 | the Council of 11 March 1996 on the legal protection of databases, 78 | as amended and/or succeeded, as well as other essentially 79 | equivalent rights anywhere in the world. 80 | 81 | k. You means the individual or entity exercising the Licensed Rights 82 | under this Public License. Your has a corresponding meaning. 83 | 84 | 85 | Section 2 -- Scope. 86 | 87 | a. License grant. 88 | 89 | 1. Subject to the terms and conditions of this Public License, 90 | the Licensor hereby grants You a worldwide, royalty-free, 91 | non-sublicensable, non-exclusive, irrevocable license to 92 | exercise the Licensed Rights in the Licensed Material to: 93 | 94 | a. reproduce and Share the Licensed Material, in whole or 95 | in part; and 96 | 97 | b. produce, reproduce, and Share Adapted Material. 98 | 99 | 2. Exceptions and Limitations. For the avoidance of doubt, where 100 | Exceptions and Limitations apply to Your use, this Public 101 | License does not apply, and You do not need to comply with 102 | its terms and conditions. 103 | 104 | 3. Term. The term of this Public License is specified in Section 105 | 6(a). 106 | 107 | 4. Media and formats; technical modifications allowed. The 108 | Licensor authorizes You to exercise the Licensed Rights in 109 | all media and formats whether now known or hereafter created, 110 | and to make technical modifications necessary to do so. The 111 | Licensor waives and/or agrees not to assert any right or 112 | authority to forbid You from making technical modifications 113 | necessary to exercise the Licensed Rights, including 114 | technical modifications necessary to circumvent Effective 115 | Technological Measures. For purposes of this Public License, 116 | simply making modifications authorized by this Section 2(a) 117 | (4) never produces Adapted Material. 118 | 119 | 5. Downstream recipients. 120 | 121 | a. Offer from the Licensor -- Licensed Material. Every 122 | recipient of the Licensed Material automatically 123 | receives an offer from the Licensor to exercise the 124 | Licensed Rights under the terms and conditions of this 125 | Public License. 126 | 127 | b. No downstream restrictions. You may not offer or impose 128 | any additional or different terms or conditions on, or 129 | apply any Effective Technological Measures to, the 130 | Licensed Material if doing so restricts exercise of the 131 | Licensed Rights by any recipient of the Licensed 132 | Material. 133 | 134 | 6. No endorsement. Nothing in this Public License constitutes or 135 | may be construed as permission to assert or imply that You 136 | are, or that Your use of the Licensed Material is, connected 137 | with, or sponsored, endorsed, or granted official status by, 138 | the Licensor or others designated to receive attribution as 139 | provided in Section 3(a)(1)(A)(i). 140 | 141 | b. Other rights. 142 | 143 | 1. Moral rights, such as the right of integrity, are not 144 | licensed under this Public License, nor are publicity, 145 | privacy, and/or other similar personality rights; however, to 146 | the extent possible, the Licensor waives and/or agrees not to 147 | assert any such rights held by the Licensor to the limited 148 | extent necessary to allow You to exercise the Licensed 149 | Rights, but not otherwise. 150 | 151 | 2. Patent and trademark rights are not licensed under this 152 | Public License. 153 | 154 | 3. To the extent possible, the Licensor waives any right to 155 | collect royalties from You for the exercise of the Licensed 156 | Rights, whether directly or through a collecting society 157 | under any voluntary or waivable statutory or compulsory 158 | licensing scheme. In all other cases the Licensor expressly 159 | reserves any right to collect such royalties. 160 | 161 | 162 | Section 3 -- License Conditions. 163 | 164 | Your exercise of the Licensed Rights is expressly made subject to the 165 | following conditions. 166 | 167 | a. Attribution. 168 | 169 | 1. If You Share the Licensed Material (including in modified 170 | form), You must: 171 | 172 | a. retain the following if it is supplied by the Licensor 173 | with the Licensed Material: 174 | 175 | i. identification of the creator(s) of the Licensed 176 | Material and any others designated to receive 177 | attribution, in any reasonable manner requested by 178 | the Licensor (including by pseudonym if 179 | designated); 180 | 181 | ii. a copyright notice; 182 | 183 | iii. a notice that refers to this Public License; 184 | 185 | iv. a notice that refers to the disclaimer of 186 | warranties; 187 | 188 | v. a URI or hyperlink to the Licensed Material to the 189 | extent reasonably practicable; 190 | 191 | b. indicate if You modified the Licensed Material and 192 | retain an indication of any previous modifications; and 193 | 194 | c. indicate the Licensed Material is licensed under this 195 | Public License, and include the text of, or the URI or 196 | hyperlink to, this Public License. 197 | 198 | 2. You may satisfy the conditions in Section 3(a)(1) in any 199 | reasonable manner based on the medium, means, and context in 200 | which You Share the Licensed Material. For example, it may be 201 | reasonable to satisfy the conditions by providing a URI or 202 | hyperlink to a resource that includes the required 203 | information. 204 | 205 | 3. If requested by the Licensor, You must remove any of the 206 | information required by Section 3(a)(1)(A) to the extent 207 | reasonably practicable. 208 | 209 | 4. If You Share Adapted Material You produce, the Adapter's 210 | License You apply must not prevent recipients of the Adapted 211 | Material from complying with this Public License. 212 | 213 | 214 | Section 4 -- Sui Generis Database Rights. 215 | 216 | Where the Licensed Rights include Sui Generis Database Rights that 217 | apply to Your use of the Licensed Material: 218 | 219 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right 220 | to extract, reuse, reproduce, and Share all or a substantial 221 | portion of the contents of the database; 222 | 223 | b. if You include all or a substantial portion of the database 224 | contents in a database in which You have Sui Generis Database 225 | Rights, then the database in which You have Sui Generis Database 226 | Rights (but not its individual contents) is Adapted Material; and 227 | 228 | c. You must comply with the conditions in Section 3(a) if You Share 229 | all or a substantial portion of the contents of the database. 230 | 231 | For the avoidance of doubt, this Section 4 supplements and does not 232 | replace Your obligations under this Public License where the Licensed 233 | Rights include other Copyright and Similar Rights. 234 | 235 | 236 | Section 5 -- Disclaimer of Warranties and Limitation of Liability. 237 | 238 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE 239 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS 240 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF 241 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, 242 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, 243 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR 244 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, 245 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT 246 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT 247 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. 248 | 249 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE 250 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, 251 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, 252 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, 253 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR 254 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN 255 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR 256 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR 257 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. 258 | 259 | c. The disclaimer of warranties and limitation of liability provided 260 | above shall be interpreted in a manner that, to the extent 261 | possible, most closely approximates an absolute disclaimer and 262 | waiver of all liability. 263 | 264 | 265 | Section 6 -- Term and Termination. 266 | 267 | a. This Public License applies for the term of the Copyright and 268 | Similar Rights licensed here. However, if You fail to comply with 269 | this Public License, then Your rights under this Public License 270 | terminate automatically. 271 | 272 | b. Where Your right to use the Licensed Material has terminated under 273 | Section 6(a), it reinstates: 274 | 275 | 1. automatically as of the date the violation is cured, provided 276 | it is cured within 30 days of Your discovery of the 277 | violation; or 278 | 279 | 2. upon express reinstatement by the Licensor. 280 | 281 | For the avoidance of doubt, this Section 6(b) does not affect any 282 | right the Licensor may have to seek remedies for Your violations 283 | of this Public License. 284 | 285 | c. For the avoidance of doubt, the Licensor may also offer the 286 | Licensed Material under separate terms or conditions or stop 287 | distributing the Licensed Material at any time; however, doing so 288 | will not terminate this Public License. 289 | 290 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public 291 | License. 292 | 293 | 294 | Section 7 -- Other Terms and Conditions. 295 | 296 | a. The Licensor shall not be bound by any additional or different 297 | terms or conditions communicated by You unless expressly agreed. 298 | 299 | b. Any arrangements, understandings, or agreements regarding the 300 | Licensed Material not stated herein are separate from and 301 | independent of the terms and conditions of this Public License. 302 | 303 | 304 | Section 8 -- Interpretation. 305 | 306 | a. For the avoidance of doubt, this Public License does not, and 307 | shall not be interpreted to, reduce, limit, restrict, or impose 308 | conditions on any use of the Licensed Material that could lawfully 309 | be made without permission under this Public License. 310 | 311 | b. To the extent possible, if any provision of this Public License is 312 | deemed unenforceable, it shall be automatically reformed to the 313 | minimum extent necessary to make it enforceable. If the provision 314 | cannot be reformed, it shall be severed from this Public License 315 | without affecting the enforceability of the remaining terms and 316 | conditions. 317 | 318 | c. No term or condition of this Public License will be waived and no 319 | failure to comply consented to unless expressly agreed to by the 320 | Licensor. 321 | 322 | d. Nothing in this Public License constitutes or may be interpreted 323 | as a limitation upon, or waiver of, any privileges and immunities 324 | that apply to the Licensor or You, including from the legal 325 | processes of any jurisdiction or authority. 326 | 327 | - - - - 328 | 329 | BSD 3-Clause License 330 | 331 | Redistribution and use in source and binary forms, with or without 332 | modification, are permitted provided that the following conditions are met: 333 | 334 | 1. Redistributions of source code must retain the above copyright notice, this 335 | list of conditions and the following disclaimer. 336 | 337 | 2. Redistributions in binary form must reproduce the above copyright notice, 338 | this list of conditions and the following disclaimer in the documentation 339 | and/or other materials provided with the distribution. 340 | 341 | 3. Neither the name of the copyright holder nor the names of its 342 | contributors may be used to endorse or promote products derived from 343 | this software without specific prior written permission. 344 | 345 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 346 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 347 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 348 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 349 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 350 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 351 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 352 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 353 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 354 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 355 | 356 | - - - - 357 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL=/bin/bash -o pipefail 2 | .PHONY: local remote deploy 3 | 4 | remote: index.bs 5 | @ (HTTP_STATUS=$$(curl https://api.csswg.org/bikeshed/ \ 6 | --output index.html \ 7 | --write-out "%{http_code}" \ 8 | --header "Accept: text/plain, text/html" \ 9 | -F die-on=warning \ 10 | -F md-Text-Macro="COMMIT-SHA LOCAL COPY" \ 11 | -F file=@index.bs) && \ 12 | [[ "$$HTTP_STATUS" -eq "200" ]]) || ( \ 13 | echo ""; cat index.html; echo ""; \ 14 | rm -f index.html; \ 15 | exit 22 \ 16 | ); 17 | 18 | local: index.bs 19 | bikeshed spec index.bs index.html --md-Text-Macro="COMMIT-SHA LOCAL-COPY" 20 | 21 | deploy: index.bs 22 | curl --remote-name --fail https://resources.whatwg.org/build/deploy.sh 23 | bash ./deploy.sh 24 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | - [ ] At least two implementers are interested (and none opposed): 8 | * … 9 | * … 10 | - [ ] [Tests](https://github.com/web-platform-tests/wpt) are written and can be reviewed and commented upon at: 11 | * … 12 | - [ ] [Implementation bugs](https://github.com/whatwg/meta/blob/main/MAINTAINERS.md#handling-pull-requests) are filed: 13 | * Chromium: … 14 | * Gecko: … 15 | * WebKit: … 16 | * Deno: … 17 | - [ ] [MDN issue](https://github.com/whatwg/meta/blob/main/MAINTAINERS.md#handling-pull-requests) is filed: … 18 | - [ ] The top of this comment includes a [clear commit message](https://github.com/whatwg/meta/blob/main/COMMITTING.md) to use. 19 | 20 | (See [WHATWG Working Mode: Changes](https://whatwg.org/working-mode#changes) for more details.) 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repository hosts the [WebSockets Standard](https://websockets.spec.whatwg.org/). 2 | 3 | ## Code of conduct 4 | 5 | We are committed to providing a friendly, safe, and welcoming environment for all. Please read and respect the [Code of Conduct](https://whatwg.org/code-of-conduct). 6 | 7 | ## Contribution opportunities 8 | 9 | Folks notice minor and larger issues with the WebSockets Standard all the time and we'd love your help fixing those. Pull requests for typographical and grammar errors are also most welcome. 10 | 11 | Issues labeled ["good first issue"](https://github.com/whatwg/websockets/labels/good%20first%20issue) are a good place to get a taste for editing the WebSockets Standard. Note that we don't assign issues and there's no reason to ask for availability either, just provide a pull request. 12 | 13 | If you are thinking of suggesting a new feature, read through the [FAQ](https://whatwg.org/faq) and [Working Mode](https://whatwg.org/working-mode) documents to get yourself familiarized with the process. 14 | 15 | We'd be happy to help you with all of this [on Chat](https://whatwg.org/chat). 16 | 17 | ## Pull requests 18 | 19 | In short, change `index.bs` and submit your patch, with a [good commit message](https://github.com/whatwg/meta/blob/main/COMMITTING.md). 20 | 21 | Please add your name to the Acknowledgments section in your first pull request, even for trivial fixes. The names are sorted lexicographically. 22 | 23 | To ensure your patch meets all the necessary requirements, please also see the [Contributor Guidelines](https://github.com/whatwg/meta/blob/main/CONTRIBUTING.md). Editors of the WebSockets Standard are expected to follow the [Maintainer Guidelines](https://github.com/whatwg/meta/blob/main/MAINTAINERS.md). 24 | 25 | ## Tests 26 | 27 | Tests are an essential part of the standardization process and will need to be created or adjusted as changes to the standard are made. Tests for the WebSockets Standard can be found in the `websockets/` directory of [`web-platform-tests/wpt`](https://github.com/web-platform-tests/wpt). 28 | 29 | A dashboard showing the tests running against browser engines can be seen at [wpt.fyi/results/websockets](https://wpt.fyi/results/websockets). 30 | 31 | ## Building "locally" 32 | 33 | For quick local iteration, run `make`; this will use a web service to build the standard, so that you don't have to install anything. See more in the [Contributor Guidelines](https://github.com/whatwg/meta/blob/main/CONTRIBUTING.md#building). 34 | -------------------------------------------------------------------------------- /index.bs: -------------------------------------------------------------------------------- 1 |
  2 | Group: WHATWG
  3 | H1: WebSockets
  4 | Shortname: websockets
  5 | Text Macro: TWITTER whatsockets
  6 | Text Macro: LATESTRD 2023-09
  7 | Abstract: This specification provides APIs to enable web applications to maintain bidirectional
  8 | Abstract: communications with server-side processes.
  9 | Translation: ja https://triple-underscore.github.io/WebSocket-ja.html
 10 | Indent: 1
 11 | Markup Shorthands: markdown yes
 12 | 
13 | 14 |
 15 | {
 16 |  "WSP": {
 17 |   "aliasOf": "RFC6455"
 18 |  },
 19 |  "HSTS": {
 20 |   "aliasOf": "RFC6797"
 21 |  }
 22 | }
 23 | 
24 | 25 | 38 | 39 |
 40 | spec:RFC6455; urlPrefix: https://datatracker.ietf.org/doc/html/rfc6455
 41 |  type: dfn
 42 |   text:the WebSocket connection is established; url:page-19:~:text=_The%20WebSocket%20Connection%20is%20Established_,-and
 43 |   text:extensions in use; url:page-19:~:text=_The%20WebSocket%20Connection%20is%20Established_,-and
 44 |   text:subprotocol in use; url:page-19:~:text=_Subprotocol%20In,Use_
 45 |   text:a WebSocket message has been received; url:page-66:~:text=_A%20WebSocket%20Message%20Has%20Been%20Received_
 46 |   text:send a WebSocket Message; url:page-66:~:text=needs%20to-,_Send%20a%20WebSocket%20Message_
 47 |   text:fail the WebSocket connection; url:section-7.1.7
 48 |   text:close the WebSocket connection; url:section-7.1.1
 49 |   text:start the WebSocket closing handshake; url:section-7.1.2
 50 |   text:the WebSocket closing handshake is started; url:section-7.1.3
 51 |   text:the WebSocket connection is closed; url:section-7.1.4
 52 |   text:the WebSocket connection close code; url:section-7.1.5
 53 |   text:the WebSocket connection close reason; url:section-7.1.6
 54 |   text:established; url:page-19:~:text=_The%20WebSocket%20Connection%20is%20Established_,-and
 55 |   text:ws; url:section-11.1.1
 56 |   text:wss; url:section-11.1.2
 57 |   text:cleanly; url:page-41:~:text=closed-,_cleanly_.
 58 |  type: http-header; text:Sec-WebSocket-Protocol; url:section-11.3.4
 59 | spec:html; type:dfn; urlPrefix: https://html.spec.whatwg.org/multipage/webappapis.html
 60 |  for:event loop; text:step 1; url:step1
 61 | 
62 | 63 | 64 | # Introduction # {#network-intro} 65 | 66 |
67 | 68 | This section is non-normative. 69 | 70 | To enable web applications to maintain bidirectional communications with server-side processes, 71 | this specification introduces the {{WebSocket}} interface. 72 | 73 |

This interface does not allow for raw access to the underlying network. For 74 | example, this interface could not be used to implement an IRC client without proxying messages 75 | through a custom server.

76 |
77 | 78 | 79 | # WebSocket protocol alterations # {#websocket-protocol} 80 | 81 |
82 | This section replaces part of the WebSocket protocol opening handshake client requirement to 83 | integrate it with algorithms defined in Fetch. This way CSP, cookies, HSTS, and other 84 | Fetch-related protocols are handled in a single location. Ideally the RFC would be 85 | updated with this language, but it is never that easy. The {{WebSocket}} API, defined below, uses 86 | this language. [[!WSP]] [[!FETCH]] 87 | 88 | The way this works is by replacing The WebSocket Protocol's "establish a WebSocket connection" 89 | algorithm with a new one that integrates with Fetch. "Establish a WebSocket 90 | connection" consists of three algorithms: setting up a connection, creating and transmiting a 91 | handshake request, and validating the handshake response. That layering is different from 92 | Fetch, which first creates a handshake, then sets up a connection and transmits the 93 | handshake, and finally validates the response. Keep that in mind while reading these alterations. 94 |
95 | 96 | 97 | ## Connections ## {#websocket-connections} 98 | 99 |
100 | 101 | To obtain a WebSocket connection, given a 102 | |url|, run these steps: 103 | 104 | 1. Let |host| be |url|'s host. 105 | 1. Let |port| be |url|'s port. 106 | 1. Let |resource name| be U+002F (/), followed by the strings in |url|'s path 107 | (including empty strings), if any, separated from each other by U+002F (/). 108 | 1. If |url|'s query is non-empty, append U+003F (?), followed by |url|'s 109 | query, to |resource name|. 110 | 1. Let |secure| be false, if |url|'s [=url/scheme=] is "`http`"; otherwise true. 111 | 1. Follow the requirements stated in step 2 to 5, inclusive, of the first set of steps in section 4.1 of The WebSocket 113 | Protocol to establish a WebSocket connection, passing 114 | |host|, |port|, |resource name| and |secure|. [[!WSP]] 115 | 1. If that established a connection, return it, and return failure otherwise. 116 | 117 |

Although structured a little differently, carrying different properties, and 118 | therefore not shareable, a WebSocket connection is very close to identical to an "ordinary" 119 | [=connection=]. 120 | 121 |

122 | 123 | 124 | ## Opening handshake ## {#websocket-opening-handshake} 125 | 126 |
127 | 128 | To establish a WebSocket connection, given a 129 | |url|, |protocols|, and |client|, run these steps: 130 | 131 | 1. Let |requestURL| be a copy of |url|, with its [=url/scheme=] set to "`http`", if |url|'s 132 | [=url/scheme=] is "`ws`"; otherwise to "`https`". 133 | 134 |

This change of scheme is essential to integrate well with 135 | fetching. E.g., HSTS would not work without it. There is no real 136 | reason for WebSocket to have distinct schemes, it's a legacy artefact. 137 | [[!HSTS]] 138 | 139 | 1. Let |request| be a new request, whose URL is |requestURL|, 140 | client is |client|, [=service-workers mode=] is "`none`", 141 | referrer is "`no-referrer`", mode is "`websocket`", 142 | credentials mode is "`include`", cache mode is "`no-store`" 143 | , and redirect mode is "`error`". 144 | 145 | 1. Append (\``Upgrade`\`, \``websocket`\`) to |request|'s 146 | header list. 147 | 1. Append (\``Connection`\`, \``Upgrade`\`) to |request|'s 148 | header list. 149 | 1. Let |keyValue| be a nonce consisting of a randomly selected 16-byte value that has been 150 | forgiving-base64-encoded and [=isomorphic encoded=]. 151 | 152 |

If the randomly selected value was the byte sequence 0x01 153 | 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10, |keyValue| would be 154 | forgiving-base64-encoded to "`AQIDBAUGBwgJCgsMDQ4PEC==`" and isomorphic encoded to 155 | \``AQIDBAUGBwgJCgsMDQ4PEC==`\`. 156 | 157 | 1. Append (\``Sec-WebSocket-Key`\`, |keyValue|) to |request|'s 158 | header list. 159 | 1. Append (\``Sec-WebSocket-Version`\`, \``13`\`) to |request|'s 160 | header list. 161 | 1. For each |protocol| in |protocols|, combine 162 | (\``Sec-WebSocket-Protocol`\`, |protocol|) in |request|'s header list. 163 | 164 | 1. Let |permessageDeflate| be a user-agent defined "`permessage-deflate`" extension 165 | header value. [[!WSP]] 166 | 167 |

\``permessage-deflate; client_max_window_bits`\` 168 | 169 | 1. Append (\``Sec-WebSocket-Extensions`\`, |permessageDeflate|) to 170 | |request|'s header list. 171 | 1. Fetch |request| with useParallelQueue set to true, 172 | and processResponse given |response| being these steps: 173 | 1. If |response| is a [=network error=] or its status is not 101, [=fail the 174 | WebSocket connection=]. 175 | 1. If |protocols| is not the empty list and [=extracting header list values=] given 176 | \``Sec-WebSocket-Protocol`\` and |response|'s header list 177 | results in null, failure, or the empty byte sequence, then [=fail the WebSocket connection=]. 178 | 179 |

This is different from the check on this header defined by The WebSocket Protocol. 180 | That only covers a subprotocol not requested by the client. This covers a subprotocol requested 181 | by the client, but not acknowledged by the server. 182 | 183 | 1. Follow the requirements stated step 2 to step 6, inclusive, of the last set of steps in 184 | section 4.1 of The WebSocket 185 | Protocol to validate |response|. This either results in [=fail the WebSocket connection=] 186 | or [=the WebSocket connection is established=]. 187 | 188 |

189 | 190 | [=Fail the WebSocket connection=] and [=the WebSocket connection is established=] are defined by The 191 | WebSocket Protocol. [[!WSP]] 192 | 193 |

The reason redirects are not followed and this handshake is generally restricted is 194 | because it could introduce serious security problems in a web browser context. For example, consider 195 | a host with a WebSocket server at one path and an open HTTP redirector at another. Suddenly, any 196 | script that can be given a particular WebSocket URL can be tricked into communicating to (and 197 | potentially sharing secrets with) any host on the internet, even if the script checks that the URL 198 | has the right hostname. 199 | 200 | 201 | 202 | # The {{WebSocket}} interface # {#the-websocket-interface} 203 | ## Interface definition ## {#interface-definition} 204 | 205 | The Web IDL definition for the {{WebSocket}} class is given as follows: 206 | 207 |

208 | enum BinaryType { "blob", "arraybuffer" }; 209 | 210 | [Exposed=(Window,Worker)] 211 | interface WebSocket : EventTarget { 212 | constructor(USVString url, optional (DOMString or sequence<DOMString>) protocols = []); 213 | readonly attribute USVString url; 214 | 215 | // ready state 216 | const unsigned short CONNECTING = 0; 217 | const unsigned short OPEN = 1; 218 | const unsigned short CLOSING = 2; 219 | const unsigned short CLOSED = 3; 220 | readonly attribute unsigned short readyState; 221 | readonly attribute unsigned long long bufferedAmount; 222 | 223 | // networking 224 | attribute EventHandler onopen; 225 | attribute EventHandler onerror; 226 | attribute EventHandler onclose; 227 | readonly attribute DOMString extensions; 228 | readonly attribute DOMString protocol; 229 | undefined close(optional [Clamp] unsigned short code, optional USVString reason); 230 | 231 | // messaging 232 | attribute EventHandler onmessage; 233 | attribute BinaryType binaryType; 234 | undefined send((BufferSource or Blob or USVString) data); 235 | }; 236 | 237 | 238 | Each {{WebSocket}} object has an associated url, which 239 | is a [=URL record=]. 240 | 241 | Each {{WebSocket}} object has an associated binary type, which is a 242 | {{BinaryType}}. Initially it must be "{{BinaryType/blob}}". 243 | 244 | Each {{WebSocket}} object has an associated ready state, which is a 245 | number representing the state of the connection. Initially it must be {{WebSocket/CONNECTING}} (0). 246 | It can have the following values: 247 | 248 | : CONNECTING (numeric value 0) 249 | :: The connection has not yet been established. 250 | : OPEN (numeric value 1) 251 | :: [=The WebSocket connection is established=] and communication is possible. 252 | : CLOSING (numeric value 2) 253 | :: The connection is going through the 254 | closing handshake, or the {{WebSocket/close()}} method has been invoked. 255 | : CLOSED (numeric value 3) 256 | :: The connection has been closed or could not be opened. 257 | 258 |
259 | : |socket| = new {{WebSocket/constructor(url, protocols)|WebSocket}}(|url| [, |protocols| ]) 260 | :: Creates a new {{WebSocket}} object, immediately establishing the associated WebSocket 261 | connection. 262 | 263 | |url| is a string giving the URL over which the connection is established. 264 | Only "`ws`", "`wss`", "`http`", and "`https`" schemes are allowed; others will cause a 265 | "{{SyntaxError}}" {{DOMException}}. URLs with [=fragments=] will always cause such an exception. 266 | 267 | |protocols| is either a string or an array of strings. If it is a string, it is equivalent to 268 | an array consisting of just that string; if it is omitted, it is equivalent to the empty array. 269 | Each string in the array is a subprotocol name. The connection will only be established if the 270 | server reports that it has selected one of these subprotocols. The subprotocol names have to 271 | match the requirements for elements that comprise the value of \``Sec-WebSocket-Protocol`\` fields as defined by The WebSocket protocol. 273 | [[!WSP]] 274 | 275 | : |socket|.send(|data|) 276 | :: Transmits |data| using the WebSocket connection. |data| can be a string, a {{Blob}}, an 277 | {{ArrayBuffer}}, or an {{ArrayBufferView}}. 278 | 279 | : |socket|.close([ |code| ] [, |reason| ]) 280 | :: Closes the WebSocket connection, optionally using |code| as [=the WebSocket connection 281 | close code=] and |reason| as [=the WebSocket connection close reason=]. 282 | 283 | : |socket|.url 284 | :: Returns the URL that was used to establish the WebSocket connection. 285 | 286 | : |socket|.readyState 287 | :: Returns the state of the WebSocket connection. It can have the values described above. 288 | 289 | : |socket|.bufferedAmount 290 | :: Returns the number of bytes of application data (UTF-8 text and binary data) that have been 291 | queued using {{WebSocket/send()}} but not yet been transmitted to the network. 292 | 293 | If the WebSocket connection is closed, this attribute's value will only increase with each call 294 | to the {{WebSocket/send()}} method. (The number does not reset to zero once the connection 295 | closes.) 296 | 297 | : |socket|.extensions 298 | :: Returns the extensions selected by the server, if any. 299 | 300 | : |socket|.protocol 301 | :: Returns the subprotocol selected by the server, if any. It can be used in conjunction with the 302 | array form of the constructor's second argument to perform subprotocol negotiation. 303 | 304 | : |socket|.binaryType 305 | :: Returns a string that indicates how binary data from |socket| is exposed to scripts: 306 | 307 | : "{{BinaryType/blob}}" 308 | :: Binary data is returned in {{Blob}} form. 309 | : "{{BinaryType/arraybuffer}}" 310 | :: Binary data is returned in {{ArrayBuffer}} form. 311 | 312 | The default is "{{BinaryType/blob}}". 313 | 314 | : |socket|.binaryType = value 315 | :: Changes how binary data is returned. 316 |
317 | 318 |
319 | The new 320 | WebSocket(|url|, |protocols|) 321 | constructor steps are: 322 | 323 | 1. Let |baseURL| be [=this=]'s [=relevant settings object=]'s [=API base URL=]. 324 | 1. Let |urlRecord| be the result of applying the [=URL parser=] to |url| with |baseURL|. 325 | 1. If |urlRecord| is failure, then throw a "{{SyntaxError}}" {{DOMException}}. 326 | 1. If |urlRecord|'s [=url/scheme=] is "`http`", then set |urlRecord|'s [=url/scheme=] to "`ws`". 327 | 1. Otherwise, if |urlRecord|'s [=url/scheme=] is "`https`", set |urlRecord|'s [=url/scheme=] to 328 | "`wss`". 329 | 1. If |urlRecord|'s [=scheme=] is not "[=ws=]" or "[=wss=]", then throw a 330 | "{{SyntaxError}}" {{DOMException}}. 331 | 1. If |urlRecord|'s [=fragment=] is non-null, then throw a "{{SyntaxError}}" {{DOMException}}. 332 | 1. If |protocols| is a string, set |protocols| to a sequence consisting of just that string. 333 | 1. If any of the values in |protocols| occur more than once or otherwise fail to match the 334 | requirements for elements that comprise the value of 335 | \``Sec-WebSocket-Protocol`\` fields as defined by The WebSocket protocol, 336 | then throw a "{{SyntaxError}}" {{DOMException}}. [[!WSP]] 337 | 1. Set [=this=]'s [=WebSocket/internal-url|url=] to |urlRecord|. 338 | 1. Let |client| be [=this=]'s [=relevant settings object=]. 339 | 1. Run this step [=in parallel=]: 340 | 1. [=Establish a WebSocket connection=] given |urlRecord|, |protocols|, and |client|. [[!FETCH]] 341 | 342 |

If the [=establish a WebSocket connection=] algorithm 343 | fails, it triggers the [=fail the WebSocket connection=] algorithm, which 344 | then invokes the [=close the WebSocket connection=] algorithm, which then 345 | establishes that [=the WebSocket connection is closed=], which fires the 346 | {{WebSocket/close}} event as described below. 347 |

348 | 349 |
350 | 351 | The url getter steps are to return [=this=]'s 352 | [=WebSocket/internal-url|url=], [=URL serializer|serialized=]. 353 | 354 | The readyState getter steps are to return [=this=]'s 355 | [=WebSocket/ready state=]. 356 | 357 | The extensions attribute must initially return the empty 358 | string. After [=the WebSocket connection is established=], its value might change, as defined 359 | below.

360 | 361 | The protocol attribute must initially return the empty 362 | string. After [=the WebSocket connection is established=], its value might change, as defined below. 363 | 364 |
365 | The close(|code|, |reason|) method steps are: 366 | 367 | 1. If |code| is present, but is neither an integer equal to 1000 nor an integer in the range 3000 368 | to 4999, inclusive, throw an "{{InvalidAccessError}}" {{DOMException}}. 369 | 1. If |reason| is present, then run these substeps: 370 | 1. Let |reasonBytes| be the result of encoding |reason|. 371 | 1. If |reasonBytes| is longer than 123 bytes, then throw a "{{SyntaxError}}" {{DOMException}}. 372 | 1. Run the first matching steps from the following list: 373 |
374 | : If [=this=]'s [=WebSocket/ready state=] is {{WebSocket/CLOSING}} (2) or {{WebSocket/CLOSED}} (3) 375 | :: Do nothing. 376 | 377 |

The connection is already closing or is already closed. If it has not already, a 378 | {{WebSocket/close}} event will eventually fire as described below. 379 | 380 | : If the WebSocket connection is not yet [=established=] [[!WSP]] 381 | :: [=Fail the WebSocket connection=] and set [=this=]'s [=WebSocket/ready state=] to 382 | {{WebSocket/CLOSING}} (2). [[!WSP]] 383 | 384 |

The [=fail the WebSocket connection=] algorithm invokes the [=close the 385 | WebSocket connection=] algorithm, which then establishes that [=the WebSocket connection is 386 | closed=], which fires the {{WebSocket/close}} event as described 387 | below. 388 | 389 | : If the WebSocket closing handshake has not yet been started [[!WSP]] 391 | :: [=Start the WebSocket closing handshake=] and set [=this=]'s [=WebSocket/ready state=] to 392 | {{WebSocket/CLOSING}} (2). [[!WSP]] 393 | 394 | If neither |code| nor |reason| is present, the WebSocket Close message must not have a body. 395 | 396 |

The WebSocket Protocol erroneously states that the status code is required for the [=start the WebSocket closing handshake=] algorithm. 398 | 399 | 400 | If |code| is present, then the status code to use in the WebSocket Close 401 | message must be the integer given by |code|. [[!WSP]] 402 | 403 | If |reason| is also present, then |reasonBytes| must be provided in the Close message after the 404 | status code. [[!WSP]] 405 | 406 |

The [=start the WebSocket closing handshake=] algorithm eventually invokes the 407 | [=close the WebSocket connection=] algorithm, which then establishes that [=the WebSocket 408 | connection is closed=], which fires the {{WebSocket/close}} event as 409 | described below. 410 | 411 | : Otherwise 412 | :: Set [=this=]'s [=WebSocket/ready state=] to {{WebSocket/CLOSING}} (2). 413 | 414 |

[=The WebSocket closing handshake is started=], and will eventually invoke the 415 | [=close the WebSocket connection=] algorithm, which will establish that [=the WebSocket 416 | connection is closed=], and thus the {{WebSocket/close}} event will fire, as described below. 418 |

419 |
420 | 421 |

The {{WebSocket/close()}} method does not discard previously sent messages before 422 | starting the WebSocket closing handshake — even if, in practice, the user agent is still busy 423 | sending those messages, the handshake will only start after the messages are sent. 426 | 427 |


428 | 429 | The bufferedAmount getter steps are to return the number of bytes 430 | of application data (UTF-8 text and binary data) that have been queued using {{WebSocket/send()}} 431 | but that, as of the last time the [=event loop=] reached step 1, had not yet 432 | been transmitted to the network. (This thus includes any text sent during the execution of the 433 | current task, regardless of whether the user agent is able to transmit text in the background [=in 434 | parallel=] with script execution.) This does not include framing overhead incurred by the protocol, 435 | or buffering done by the operating system or network hardware. 436 | 437 |
438 | 439 | In this simple example, the {{WebSocket/bufferedAmount}} attribute is used to ensure that updates 440 | are sent either at the rate of one update every 50ms, if the network can handle that rate, or at 441 | whatever rate the network can handle, if that is too fast. 442 | 443 | 444 | var socket = new WebSocket('ws://game.example.com:12010/updates'); 445 | socket.onopen = function () { 446 | setInterval(function() { 447 | if (socket.bufferedAmount == 0) 448 | socket.send(getUpdateData()); 449 | }, 50); 450 | }; 451 | 452 | 453 | The {{WebSocket/bufferedAmount}} attribute can also be used to saturate the network without sending 454 | the data at a higher rate than the network can handle, though this requires more careful monitoring 455 | of the value of the attribute over time. 456 | 457 |
458 | 459 |
460 | 461 | The binaryType getter steps are to return [=this=]'s 462 | [=WebSocket/binary type=]. 463 | 464 | The {{WebSocket/binaryType}} setter steps are to set [=this=]'s [=WebSocket/binary type=] to 465 | [=the given value=]. 466 | 467 |

User agents can use the [=WebSocket/binary type=] as a hint for how to handle 468 | incoming binary data: if it is "{{BinaryType/blob}}", it is safe to spool it to disk, and if it is 469 | "{{BinaryType/arraybuffer}}", it is likely more efficient to keep the data in memory. Naturally, 470 | user agents are encouraged to use more subtle heuristics to decide whether to keep incoming data in 471 | memory or not, e.g. based on how big the data is or how common it is for a script to change the 472 | attribute at the last minute. This latter aspect is important in particular because it is quite 473 | possible for the attribute to be changed after the user agent has received the data but before the 474 | user agent has fired the event for it. 475 | 476 |

477 | The send(|data|) method steps are: 478 | 479 | 1. If [=this=]'s [=WebSocket/ready state=] is {{WebSocket/CONNECTING}}, then throw an 480 | "{{InvalidStateError}}" {{DOMException}}. 481 | 482 | 2. Run the appropriate set of steps from the following list: 483 | 484 | : If |data| is a string 485 | :: If [=the WebSocket connection is established=] and the WebSocket closing handshake has not yet started, then the user agent must 487 | [=send a WebSocket Message=] comprised of the |data| argument using a text frame opcode; if 488 | the data cannot be sent, e.g. because it would need to be buffered but the buffer is full, 489 | the user agent must flag the WebSocket as full and then [=close 490 | the WebSocket connection=]. Any invocation of this method with a string argument that does 491 | not throw an exception must increase the {{WebSocket/bufferedAmount}} attribute by the 492 | number of bytes needed to express the argument as UTF-8. [[!UNICODE]] [[!ENCODING]] [[!WSP]] 493 | 494 | 495 | : If |data| is a {{Blob}} object 496 | :: If [=the WebSocket connection is established=], and the WebSocket closing handshake has not yet started, then the user agent 498 | must [=send a WebSocket Message=] comprised of |data| using a binary frame opcode; if the 499 | data cannot be sent, e.g. because it would need to be buffered but the buffer is full, the 500 | user agent must flag the WebSocket as full and then [=close the 501 | WebSocket connection=]. The data to be sent is the raw data represented by the {{Blob}} 502 | object. 503 | 504 | Any invocation of this method with a {{Blob}} argument that does not throw an exception must 505 | increase the {{WebSocket/bufferedAmount}} attribute by the size of the {{Blob}} object's raw 506 | data, in bytes. 507 | 508 | [[!WSP]] [[!FILEAPI]] 509 | 510 | : If |data| is an {{ArrayBuffer}} 511 | :: If [=the WebSocket connection is established=], and the WebSocket closing handshake has not yet started, then the user agent 513 | must [=send a WebSocket Message=] comprised of |data| using a binary frame opcode; if the 514 | data cannot be sent, e.g. because it would need to be buffered but the buffer is full, the 515 | user agent must flag the WebSocket as full and then [=close the 516 | WebSocket connection=]. The data to be sent is the data stored in the buffer described by 517 | the {{ArrayBuffer}} object. Any invocation of this method with an {{ArrayBuffer}} argument 518 | that does not throw an exception must increase the {{WebSocket/bufferedAmount}} attribute by 519 | the length of the {{ArrayBuffer}} in bytes. [[!WSP]] 520 | 521 | : If |data| is an {{ArrayBufferView}} 522 | :: If [=the WebSocket connection is established=], and the WebSocket closing handshake has not yet started, then the user agent 524 | must [=send a WebSocket Message=] comprised of |data| using a binary frame opcode; if the 525 | data cannot be sent, e.g. because it would need to be buffered but the buffer is full, the 526 | user agent must flag the WebSocket as full and then [=close the 527 | WebSocket connection=]. The data to be sent is the data stored in the section of the buffer 528 | described by the {{ArrayBuffer}} object that |data| references. Any invocation of this 529 | method with this kind of argument that does not throw an exception must increase the 530 | {{WebSocket/bufferedAmount}} attribute by the length of |data|'s buffer in bytes. [[!WSP]] 531 |
532 | 533 |
534 | 535 | The following are the [=event handlers=] (and their corresponding [=event handler event types=]) 536 | that must be supported, as [=event handler IDL attributes=], by all objects implementing the 537 | {{WebSocket}} interface: 538 | 539 | 540 | 541 | 543 |
[=Event handler=] [=Event handler event type=] 542 |
onopen {{WebSocket/open}} 544 |
onmessage {{WebSocket/message}} 545 |
onerror {{WebSocket/error}} 546 |
onclose {{WebSocket/close}} 547 |
548 | 549 | 550 | # Feedback from the protocol # {#feedback-from-the-protocol} 551 | 552 | When [=the WebSocket connection is established=], the user agent must [=queue a task=] to run these 553 | steps: 554 | 555 |
556 | 557 | 1. Change the [=WebSocket/ready state=] to {{WebSocket/OPEN}} (1). 558 | 1. Change the {{WebSocket/extensions}} attribute's value to the [=extensions in 559 | use=], if it is not the null value. [[!WSP]] 560 | 1. Change the {{WebSocket/protocol}} attribute's value to the [=subprotocol in 561 | use=], if it is not the null value. [[!WSP]] 562 | 1. [=Fire an event=] named open at the {{WebSocket}} object. 563 | 564 |

Since the algorithm above is queued as a task, there is no 565 | race condition between the WebSocket connection 566 | being established and the script setting up an event listener for the {{WebSocket/open}} 567 | event. 568 | 569 |

570 | 571 |
572 | 573 |
574 | 575 | When [=a WebSocket message has been received=] with type |type| and data |data|, the user agent must 576 | [=queue a task=] to follow these steps: [[!WSP]] 577 | 578 | 1. If [=WebSocket/ready state=] is not {{WebSocket/OPEN}} (1), then return. 579 | 1. Let |dataForEvent| be determined by switching on |type| and [=WebSocket/binary type=]: 580 | 581 |
582 | : |type| indicates that the data is Text 583 | :: a new {{DOMString}} containing |data| 584 | 585 | : |type| indicates that the data is Binary and [=WebSocket/binary type=] is 586 | "blob" 587 | :: a new {{Blob}} object, created in the [=relevant Realm=] of the {{WebSocket}} object, that 588 | represents |data| as its raw data [[!FILEAPI]] 589 | 590 | : |type| indicates that the data is Binary and [=WebSocket/binary type=] is 591 | "arraybuffer" 592 | :: a new {{ArrayBuffer}} object, created in the [=relevant Realm=] of the {{WebSocket}} object, 593 | whose contents are |data| 594 |
595 | 596 | 1. [=Fire an event=] named message at the {{WebSocket}} object, 597 | using {{MessageEvent}}, with the {{MessageEvent/origin}} attribute initialized to the serialization of the {{WebSocket}} object's [=url=]'s [=origin=], and the 599 | {{MessageEvent/data}} attribute initialized to |dataForEvent|. 600 | 601 |

User agents are encouraged to check if they can perform the above steps efficiently 602 | before they run the task, picking tasks from other [=task queues=] while they prepare the buffers 603 | if not. For example, if the [=WebSocket/binary type=] is "{{BinaryType/blob}}" when the data 604 | arrived, and the user agent spooled all the data to disk, but just before running the above 605 | [=task=] for this particular message the script switched [=WebSocket/binary type=] to 606 | "{{BinaryType/arraybuffer}}", the user agent would want to page the data back to RAM before running 607 | this [=task=] so as to avoid stalling the main thread while it created the {{ArrayBuffer}} object. 608 | 609 |

610 | 611 |
612 | 613 | Here is an example of how to define a handler for the {{WebSocket/message}} event in the case of 614 | text frames: 615 | 616 | 617 | mysocket.onmessage = function (event) { 618 | if (event.data == 'on') { 619 | turnLampOn(); 620 | } else if (event.data == 'off') { 621 | turnLampOff(); 622 | } 623 | }; 624 | 625 | 626 | The protocol here is a trivial one, with the server just sending "on" or "off" messages. 627 | 628 |
629 | 630 |
631 | 632 | When [=the WebSocket closing handshake is started=], the user agent must [=queue a task=] to change 633 | the [=WebSocket/ready state=] to {{WebSocket/CLOSING}} (2). (If the {{WebSocket/close()}} method 634 | was called, the [=WebSocket/ready state=] will already be set to {{WebSocket/CLOSING}} (2) when 635 | this task runs.) [[!WSP]] 636 | 637 |
638 | 639 |

When [=the WebSocket connection is closed=], possibly [=cleanly=], the user 640 | agent must [=queue a task=] to run the following substeps: 641 | 642 |

643 | 1. Change the [=WebSocket/ready state=] to {{WebSocket/CLOSED}} (3). 644 | 1. If the user agent was required to [=fail the WebSocket connection=], or if the WebSocket connection was closed after being flagged 646 | as full, [=fire an event=] named error at the 647 | {{WebSocket}} object. [[!WSP]] 648 | 1. [=Fire an event=] named close at the {{WebSocket}} object, 649 | using {{CloseEvent}}, with the {{CloseEvent/wasClean}} attribute initialized to true if the 650 | connection closed [=cleanly=] and false otherwise, the {{CloseEvent/code}} attribute initialized 651 | to [=the WebSocket connection close code=], and the {{CloseEvent/reason}} attribute initialized 652 | to the result of applying [=UTF-8 decode without BOM=] to [=the WebSocket connection close 653 | reason=]. [[!WSP]] 654 |
655 | 656 |
657 | 658 | User agents must not convey any failure information to scripts in a way that would allow a 659 | script to distinguish the following situations: 660 | 661 | * A server whose host name could not be resolved. 662 | * A server to which packets could not successfully be routed. 663 | * A server that refused the connection on the specified port. 664 | * A server that failed to correctly perform a TLS handshake (e.g., the server certificate can't be 665 | verified). 666 | * A server that did not complete the opening handshake (e.g. because it was not a WebSocket 667 | server). 668 | * A WebSocket server that sent a correct opening handshake, but that specified options that caused 669 | the client to drop the connection (e.g. the server specified a subprotocol that the client did 670 | not offer). 671 | * A WebSocket server that abruptly closed the connection after successfully completing the 672 | opening handshake. 673 | 674 | In all of these cases, [=the WebSocket connection close code=] would be 1006, as required by 675 | WebSocket Protocol. [[!WSP]] 676 | 677 | Allowing a script to distinguish these cases would allow a script to probe the user's local network 678 | in preparation for an attack. 679 | 680 |

In particular, this means the code 1015 is not used by the user agent (unless the 681 | server erroneously uses it in its close frame, of course). 682 | 683 |

684 | 685 |
686 | 687 | The [=task source=] for all [=tasks=] queued in this section is the 688 | WebSocket task source. 689 | 690 | 691 | # Ping and Pong frames # {#ping-and-pong-frames} 692 | 693 | The WebSocket protocol defines Ping and Pong frames that can be used for keep-alive, 694 | heart-beats, network status probing, latency instrumentation, and so forth. These are not currently 695 | exposed in the API. 696 | 697 | User agents may send ping and unsolicited pong frames as desired, for example in an attempt to 698 | maintain local network NAT mappings, to detect failed connections, or to display latency metrics to 699 | the user. User agents must not use pings or unsolicited pongs to aid the server; it is assumed that 700 | servers will solicit pongs whenever appropriate for the server's needs. 701 | 702 | 705 | 706 | 707 | # The {{CloseEvent}} interface # {#the-closeevent-interface} 708 | 709 | {{WebSocket}} objects use the {{CloseEvent}} interface for their {{WebSocket/close}} events: 710 | 711 | 712 | [Exposed=(Window,Worker)] 713 | interface CloseEvent : Event { 714 | constructor(DOMString type, optional CloseEventInit eventInitDict = {}); 715 | 716 | readonly attribute boolean wasClean; 717 | readonly attribute unsigned short code; 718 | readonly attribute USVString reason; 719 | }; 720 | 721 | dictionary CloseEventInit : EventInit { 722 | boolean wasClean = false; 723 | unsigned short code = 0; 724 | USVString reason = ""; 725 | }; 726 | 727 | 728 |
729 | 730 | : |event| . {{CloseEvent/wasClean}} 731 | :: Returns true if the connection closed cleanly; false otherwise. 732 | : |event| . {{CloseEvent/code}} 733 | :: Returns the WebSocket connection close code provided by the server. 734 | : |event| . {{CloseEvent/reason}} 735 | :: Returns the WebSocket connection close reason provided by the server. 736 | 737 |
738 | 739 | The wasClean attribute must return the value it was initialized 740 | to. It represents whether the connection closed cleanly or not. 741 | 742 | The code attribute must return the value it was initialized 743 | to. It represents the WebSocket connection close code provided by the server. 744 | 745 | The reason attribute must return the value it was initialized 746 | to. It represents the WebSocket connection close reason provided by the server. 747 | 748 | 749 | 750 | # Garbage collection # {#garbage-collection} 751 | 752 | A {{WebSocket}} object whose [=WebSocket/ready state=] was set to {{WebSocket/CONNECTING}} (0) as 753 | of the last time the [=event loop=] reached step 1 must not be garbage 754 | collected if there are any event listeners registered for {{WebSocket/open}} events, 755 | {{WebSocket/message}} events, {{WebSocket/error}} events, or {{WebSocket/close}} events. 756 | 757 | A {{WebSocket}} object whose [=WebSocket/ready state=] was set to {{WebSocket/OPEN}} (1) as of the 758 | last time the [=event loop=] reached step 1 must not be garbage collected 759 | if there are any event listeners registered for {{WebSocket/message}} events, {{WebSocket/error}}, 760 | or {{WebSocket/close}} events. 761 | 762 | A {{WebSocket}} object whose [=WebSocket/ready state=] was set to {{WebSocket/CLOSING}} (2) as of 763 | the last time the [=event loop=] reached step 1 must not be garbage 764 | collected if there are any event listeners registered for {{WebSocket/error}} or {{WebSocket/close}} 765 | events. 766 | 767 | A {{WebSocket}} object with an established 768 | connection that has data queued to be transmitted to the network must not be garbage collected. 769 | [[!WSP]] 770 | 771 | If a {{WebSocket}} object is garbage collected while its connection is still open, the user agent 772 | must [=start the WebSocket closing handshake=], with no status code for the Close 773 | message. [[!WSP]] 774 | 775 |
776 | 777 | If a user agent is to make disappear a {{WebSocket}} object (this happens when a 778 | {{Document}} object goes away), the user agent must follow the first appropriate set of steps from 779 | the following list: 780 | 781 |
782 | 783 |
784 | 785 | : If the WebSocket connection is not yet [=established=] [[!WSP]] 786 | :: [=Fail the WebSocket connection=]. [[!WSP]] 787 | : If the WebSocket closing handshake has not yet been 788 | started [[!WSP]] 789 | :: [=Start the WebSocket closing handshake=], with the status code to use in the 790 | WebSocket Close message being 1001. [[!WSP]] 791 | : Otherwise 792 | :: Do nothing. 793 | 794 |
795 | 796 |
797 | 798 |

Acknowledgments

799 | 800 | Until the creation of this standard in 2021, the text here was maintained in the HTML Standard and Fetch Standard. Thanks to all of the contributors to those 803 | repositories who helped develop the specification, especially Ian Hickson and Anne van Kesteren as 804 | the respective original authors. 805 | 806 | Thanks to 807 | devsnek and 808 | 平野裕 (Yutaka Hirano) 809 | for their contributions after the creation of the WebSockets Standard. 810 | 811 | This standard is written by Adam Rice (Google, ricea@chromium.org). 813 | -------------------------------------------------------------------------------- /review-drafts/2022-03.bs: -------------------------------------------------------------------------------- 1 |
  2 | Group: WHATWG
  3 | Date: 2022-03-21
  4 | H1: WebSockets
  5 | Shortname: websockets
  6 | Text Macro: TWITTER whatsockets
  7 | Text Macro: LATESTRD 2022-03
  8 | Abstract: This specification provides APIs to enable web applications to maintain bidirectional
  9 | Abstract: communications with server-side processes.
 10 | Translation: ja https://triple-underscore.github.io/WebSocket-ja.html
 11 | Indent: 1
 12 | Markup Shorthands: markdown yes
 13 | 
14 | 15 |
 16 | {
 17 |  "WSP": {
 18 |   "aliasOf": "RFC6455"
 19 |  },
 20 |  "HSTS": {
 21 |   "aliasOf": "RFC6797"
 22 |  }
 23 | }
 24 | 
25 | 26 | 39 | 40 |
 41 | spec:RFC6455; urlPrefix: https://tools.ietf.org/html/rfc6455
 42 |  type: dfn
 43 |   text:the WebSocket connection is established; url:page-19:~:text=_The%20WebSocket%20Connection%20is%20Established_,-and
 44 |   text:extensions in use; url:page-19:~:text=_The%20WebSocket%20Connection%20is%20Established_,-and
 45 |   text:subprotocol in use; url:page-19:~:text=_Subprotocol%20In,Use_
 46 |   text:a WebSocket message has been received; url:page-66:~:text=_A%20WebSocket%20Message%20Has%20Been%20Received_
 47 |   text:send a WebSocket Message; url:page-66:~:text=needs%20to-,_Send%20a%20WebSocket%20Message_
 48 |   text:fail the WebSocket connection; url:section-7.1.7
 49 |   text:close the WebSocket connection; url:section-7.1.1
 50 |   text:start the WebSocket closing handshake; url:section-7.1.2
 51 |   text:the WebSocket closing handshake is started; url:section-7.1.3
 52 |   text:the WebSocket connection is closed; url:section-7.1.4
 53 |   text:the WebSocket connection close code; url:section-7.1.5
 54 |   text:the WebSocket connection close reason; url:section-7.1.6
 55 |   text:established; url:page-19:~:text=_The%20WebSocket%20Connection%20is%20Established_,-and
 56 |   text:ws; url:section-11.1.1
 57 |   text:wss; url:section-11.1.2
 58 |   text:cleanly; url:page-41:~:text=closed-,_cleanly_.
 59 |  type: http-header; text:Sec-WebSocket-Protocol; url:section-11.3.4
 60 | spec:html; type:dfn; urlPrefix: https://html.spec.whatwg.org/multipage/webappapis.html
 61 |  for:event loop; text:step 1; url:step1
 62 | 
63 | 64 | 65 | # Introduction # {#network-intro} 66 | 67 |
68 | 69 | This section is non-normative. 70 | 71 | To enable web applications to maintain bidirectional communications with server-side processes, 72 | this specification introduces the {{WebSocket}} interface. 73 | 74 |

This interface does not allow for raw access to the underlying network. For 75 | example, this interface could not be used to implement an IRC client without proxying messages 76 | through a custom server.

77 |
78 | 79 | 80 | # WebSocket protocol alterations # {#websocket-protocol} 81 | 82 |
83 | This section replaces part of the WebSocket protocol opening handshake client requirement to 84 | integrate it with algorithms defined in Fetch. This way CSP, cookies, HSTS, and other 85 | Fetch-related protocols are handled in a single location. Ideally the RFC would be 86 | updated with this language, but it is never that easy. The {{WebSocket}} API, defined below, uses 87 | this language. [[!WSP]] [[!FETCH]] 88 | 89 | The way this works is by replacing The WebSocket Protocol's "establish a WebSocket connection" 90 | algorithm with a new one that integrates with Fetch. "Establish a WebSocket 91 | connection" consists of three algorithms: setting up a connection, creating and transmiting a 92 | handshake request, and validating the handshake response. That layering is different from 93 | Fetch, which first creates a handshake, then sets up a connection and transmits the 94 | handshake, and finally validates the response. Keep that in mind while reading these alterations. 95 |
96 | 97 | 98 | ## Connections ## {#websocket-connections} 99 | 100 |
101 | 102 | To obtain a WebSocket connection, given a 103 | |url|, run these steps: 104 | 105 | 1. Let |host| be |url|'s host. 106 | 1. Let |port| be |url|'s port. 107 | 1. Let |resource name| be U+002F (/), followed by the strings in |url|'s path 108 | (including empty strings), if any, separated from each other by U+002F (/). 109 | 1. If |url|'s query is non-empty, append U+003F (?), followed by |url|'s 110 | query, to |resource name|. 111 | 1. Let |secure| be false, if |url|'s scheme is "`http`", and true otherwise. 112 | 1. Follow the requirements stated in step 2 to 5, inclusive, of the first set of steps in section 4.1 of The WebSocket Protocol to 114 | establish a WebSocket connection, passing |host|, |port|, 115 | |resource name| and |secure|. [[!WSP]] 116 | 1. If that established a connection, return it, and return failure otherwise. 117 | 118 |

Although structured a little differently, carrying different properties, and 119 | therefore not shareable, a WebSocket connection is very close to identical to an "ordinary" 120 | [=connection=]. 121 | 122 |

123 | 124 | 125 | ## Opening handshake ## {#websocket-opening-handshake} 126 | 127 |
128 | 129 | To establish a WebSocket connection, given a 130 | |url|, |protocols|, and |client|, run these steps: 131 | 132 | 1. Let |requestURL| be a copy of |url|, with its scheme set to "`http`", if |url|'s 133 | scheme is "`ws`", and to "`https`" otherwise. 134 | 135 |

This change of scheme is essential to integrate well with 136 | fetching. E.g., HSTS would not work without it. There is no real 137 | reason for WebSocket to have distinct schemes, it's a legacy artefact. 138 | [[!HSTS]] 139 | 140 | 1. Let |request| be a new request, whose URL is |requestURL|, 141 | client is |client|, [=service-workers mode=] is "`none`", 142 | referrer is "`no-referrer`", mode is "`websocket`", 143 | credentials mode is "`include`", cache mode is "`no-store`" 144 | , and redirect mode is "`error`". 145 | 146 | 1. Append (\``Upgrade`\`, \``websocket`\`) to |request|'s 147 | header list. 148 | 1. Append (\``Connection`\`, \``Upgrade`\`) to |request|'s 149 | header list. 150 | 1. Let |keyValue| be a nonce consisting of a randomly selected 16-byte value that has been 151 | forgiving-base64-encoded and [=isomorphic encoded=]. 152 | 153 |

If the randomly selected value was the byte sequence 0x01 154 | 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10, |keyValue| would be 155 | forgiving-base64-encoded to "`AQIDBAUGBwgJCgsMDQ4PEC==`" and isomorphic encoded to 156 | \``AQIDBAUGBwgJCgsMDQ4PEC==`\`. 157 | 158 | 1. Append (\``Sec-WebSocket-Key`\`, |keyValue|) to |request|'s 159 | header list. 160 | 1. Append (\``Sec-WebSocket-Version`\`, \``13`\`) to |request|'s 161 | header list. 162 | 1. For each |protocol| in |protocols|, combine 163 | (\``Sec-WebSocket-Protocol`\`, |protocol|) in |request|'s header list. 164 | 165 | 1. Let |permessageDeflate| be a user-agent defined "`permessage-deflate`" extension 166 | header value. [[!WSP]] 167 | 168 |

\``permessage-deflate; client_max_window_bits`\` 169 | 170 | 1. Append (\``Sec-WebSocket-Extensions`\`, |permessageDeflate|) to 171 | |request|'s header list. 172 | 1. Fetch |request| with useParallelQueue set to true, 173 | and processResponse given |response| being these steps: 174 | 1. If |response| is a [=network error=] or its status is not 101, [=fail the 175 | WebSocket connection=]. 176 | 1. If |protocols| is not the empty list and [=extracting header list values=] given 177 | \``Sec-WebSocket-Protocol`\` and |response|'s header list 178 | results in null, failure, or the empty byte sequence, then [=fail the WebSocket connection=]. 179 | 180 |

This is different from the check on this header defined by The WebSocket Protocol. 181 | That only covers a subprotocol not requested by the client. This covers a subprotocol requested 182 | by the client, but not acknowledged by the server. 183 | 184 | 1. Follow the requirements stated step 2 to step 6, inclusive, of the last set of steps in 185 | section 4.1 of The WebSocket Protocol 186 | to validate |response|. This either results in [=fail the WebSocket connection=] 187 | or [=the WebSocket connection is established=]. 188 | 189 |

190 | 191 | [=Fail the WebSocket connection=] and [=the WebSocket connection is established=] are defined by The 192 | WebSocket Protocol. [[!WSP]] 193 | 194 |

The reason redirects are not followed and this handshake is generally restricted is 195 | because it could introduce serious security problems in a web browser context. For example, consider 196 | a host with a WebSocket server at one path and an open HTTP redirector at another. Suddenly, any 197 | script that can be given a particular WebSocket URL can be tricked into communicating to (and 198 | potentially sharing secrets with) any host on the internet, even if the script checks that the URL 199 | has the right hostname. 200 | 201 | 202 | 203 | # The {{WebSocket}} interface # {#the-websocket-interface} 204 | ## Interface definition ## {#interface-definition} 205 | 206 | The Web IDL definition for the {{WebSocket}} class is given as follows: 207 | 208 |

209 | enum BinaryType { "blob", "arraybuffer" }; 210 | 211 | [Exposed=(Window,Worker)] 212 | interface WebSocket : EventTarget { 213 | constructor(USVString url, optional (DOMString or sequence<DOMString>) protocols = []); 214 | readonly attribute USVString url; 215 | 216 | // ready state 217 | const unsigned short CONNECTING = 0; 218 | const unsigned short OPEN = 1; 219 | const unsigned short CLOSING = 2; 220 | const unsigned short CLOSED = 3; 221 | readonly attribute unsigned short readyState; 222 | readonly attribute unsigned long long bufferedAmount; 223 | 224 | // networking 225 | attribute EventHandler onopen; 226 | attribute EventHandler onerror; 227 | attribute EventHandler onclose; 228 | readonly attribute DOMString extensions; 229 | readonly attribute DOMString protocol; 230 | undefined close(optional [Clamp] unsigned short code, optional USVString reason); 231 | 232 | // messaging 233 | attribute EventHandler onmessage; 234 | attribute BinaryType binaryType; 235 | undefined send((BufferSource or Blob or USVString) data); 236 | }; 237 | 238 | 239 | Each {{WebSocket}} object has an associated url, which 240 | is a [=URL record=]. 241 | 242 | Each {{WebSocket}} object has an associated binary type, which is a 243 | {{BinaryType}}. Initially it must be "{{BinaryType/blob}}". 244 | 245 | Each {{WebSocket}} object has an associated ready state, which is a 246 | number representing the state of the connection. Initially it must be {{WebSocket/CONNECTING}} (0). 247 | It can have the following values: 248 | 249 | : CONNECTING (numeric value 0) 250 | :: The connection has not yet been established. 251 | : OPEN (numeric value 1) 252 | :: [=The WebSocket connection is established=] and communication is possible. 253 | : CLOSING (numeric value 2) 254 | :: The connection is going through the 255 | closing handshake, or the {{WebSocket/close()}} method has been invoked. 256 | : CLOSED (numeric value 3) 257 | :: The connection has been closed or could not be opened. 258 | 259 |
260 | : |socket| = new {{WebSocket/constructor(url, protocols)|WebSocket}}(|url| [, |protocols| ]) 261 | :: Creates a new {{WebSocket}} object, immediately establishing the associated WebSocket 262 | connection. 263 | 264 | |url| is a string giving the URL over which the connection is established. 265 | Only "`ws`" or "`wss`" schemes are allowed; others will cause a "{{SyntaxError}}" 266 | {{DOMException}}. URLs with [=fragments=] will also cause such an exception. 267 | 268 | |protocols| is either a string or an array of strings. If it is a string, it is equivalent to 269 | an array consisting of just that string; if it is omitted, it is equivalent to the empty array. 270 | Each string in the array is a subprotocol name. The connection will only be established if the 271 | server reports that it has selected one of these subprotocols. The subprotocol names have to 272 | match the requirements for elements that comprise the value of \``Sec-WebSocket-Protocol`\` fields as defined by The WebSocket protocol. 274 | [[!WSP]] 275 | 276 | : |socket|.send(|data|) 277 | :: Transmits |data| using the WebSocket connection. |data| can be a string, a {{Blob}}, an 278 | {{ArrayBuffer}}, or an {{ArrayBufferView}}. 279 | 280 | : |socket|.close([ |code| ] [, |reason| ]) 281 | :: Closes the WebSocket connection, optionally using |code| as [=the WebSocket connection 282 | close code=] and |reason| as the [=the WebSocket connection close reason=]. 283 | 284 | : |socket|.url 285 | :: Returns the URL that was used to establish the WebSocket connection. 286 | 287 | : |socket|.readyState 288 | :: Returns the state of the WebSocket connection. It can have the values described above. 289 | 290 | : |socket|.bufferedAmount 291 | :: Returns the number of bytes of application data (UTF-8 text and binary data) that have been 292 | queued using {{WebSocket/send()}} but not yet been transmitted to the network. 293 | 294 | If the WebSocket connection is closed, this attribute's value will only increase with each call 295 | to the {{WebSocket/send()}} method. (The number does not reset to zero once the connection 296 | closes.) 297 | 298 | : |socket|.extensions 299 | :: Returns the extensions selected by the server, if any. 300 | 301 | : |socket|.protocol 302 | :: Returns the subprotocol selected by the server, if any. It can be used in conjunction with the 303 | array form of the constructor's second argument to perform subprotocol negotiation. 304 | 305 | : |socket|.binaryType 306 | :: Returns a string that indicates how binary data from |socket| is exposed to scripts: 307 | 308 | : "{{BinaryType/blob}}" 309 | :: Binary data is returned in {{Blob}} form. 310 | : "{{BinaryType/arraybuffer}}" 311 | :: Binary data is returned in {{ArrayBuffer}} form. 312 | 313 | The default is "{{BinaryType/blob}}". 314 | 315 | : |socket|.binaryType = value 316 | :: Changes how binary data is returned. 317 |
318 | 319 |
320 | The new 321 | WebSocket(|url|, |protocols|) 322 | constructor steps are: 323 | 324 | 1. Let |urlRecord| be the result of applying the [=URL parser=] to |url|. 325 | 1. If |urlRecord| is failure, then throw a "{{SyntaxError}}" {{DOMException}}. 326 | 1. If |urlRecord|'s [=scheme=] is not "[=ws=]" or "[=wss=]", then throw a 327 | "{{SyntaxError}}" {{DOMException}}. 328 | 1. If |urlRecord|'s [=fragment=] is non-null, then throw a "{{SyntaxError}}" {{DOMException}}. 329 | 1. If |protocols| is a string, set |protocols| to a sequence consisting of just that string. 330 | 1. If any of the values in |protocols| occur more than once or otherwise fail to match the 331 | requirements for elements that comprise the value of 332 | \``Sec-WebSocket-Protocol`\` fields as defined by The WebSocket protocol, 333 | then throw a "{{SyntaxError}}" {{DOMException}}. [[!WSP]] 334 | 1. Set [=this=]'s [=WebSocket/internal-url|url=] to |urlRecord|. 335 | 1. Let |client| be [=this=]'s [=relevant settings object=]. 336 | 1. Run this step [=in parallel=]: 337 | 1. [=Establish a WebSocket connection=] given |urlRecord|, |protocols|, and |client|. [[!FETCH]] 338 | 339 |

If the [=establish a WebSocket connection=] algorithm 340 | fails, it triggers the [=fail the WebSocket connection=] algorithm, which 341 | then invokes the [=close the WebSocket connection=] algorithm, which then 342 | establishes that [=the WebSocket connection is closed=], which fires the 343 | {{WebSocket/close}} event as described below. 344 |

345 | 346 |
347 | 348 | The url getter steps are to return [=this=]'s 349 | [=WebSocket/internal-url|url=], [=URL serializer|serialized=]. 350 | 351 | The readyState getter steps are to return [=this=]'s 352 | [=WebSocket/ready state=]. 353 | 354 | The extensions attribute must initially return the empty 355 | string. After [=the WebSocket connection is established=], its value might change, as defined 356 | below.

357 | 358 | The protocol attribute must initially return the empty 359 | string. After [=the WebSocket connection is established=], its value might change, as defined below. 360 | 361 |
362 | The close(|code|, |reason|) method steps are: 363 | 364 | 1. If |code| is present, but is neither an integer equal to 1000 nor an integer in the range 3000 365 | to 4999, inclusive, throw an "{{InvalidAccessError}}" {{DOMException}}. 366 | 1. If |reason| is present, then run these substeps: 367 | 1. Let |reasonBytes| be the result of encoding |reason|. 368 | 1. If |reasonBytes| is longer than 123 bytes, then throw a "{{SyntaxError}}" {{DOMException}}. 369 | 1. Run the first matching steps from the following list: 370 |
371 | : If [=this=]'s [=WebSocket/ready state=] is {{WebSocket/CLOSING}} (2) or {{WebSocket/CLOSED}} (3) 372 | :: Do nothing. 373 | 374 |

The connection is already closing or is already closed. If it has not already, a 375 | {{WebSocket/close}} event will eventually fire as described below. 376 | 377 | : If the WebSocket connection is not yet [=established=] [[!WSP]] 378 | :: [=Fail the WebSocket connection=] and set [=this=]'s [=WebSocket/ready state=] to 379 | {{WebSocket/CLOSING}} (2). [[!WSP]] 380 | 381 |

The [=fail the WebSocket connection=] algorithm invokes the [=close the 382 | WebSocket connection=] algorithm, which then establishes that [=the WebSocket connection is 383 | closed=], which fires the {{WebSocket/close}} event as described 384 | below. 385 | 386 | : If the WebSocket closing handshake has not yet been started [[!WSP]] 388 | :: [=Start the WebSocket closing handshake=] and set [=this=]'s [=WebSocket/ready state=] to 389 | {{WebSocket/CLOSING}} (2). [[!WSP]] 390 | 391 | If neither |code| nor |reason| is present, the WebSocket Close message must not have a body. 392 | 393 |

The WebSocket Protocol erroneously states that the status code is required for the [=start the WebSocket closing handshake=] algorithm. 395 | 396 | 397 | If |code| is present, then the status code to use in the WebSocket Close 398 | message must be the integer given by |code|. [[!WSP]] 399 | 400 | If |reason| is also present, then |reasonBytes| must be provided in the Close message after the 401 | status code. [[!WSP]] 402 | 403 |

The [=start the WebSocket closing handshake=] algorithm eventually invokes the 404 | [=close the WebSocket connection=] algorithm, which then establishes that [=the WebSocket 405 | connection is closed=], which fires the {{WebSocket/close}} event as 406 | described below. 407 | 408 | : Otherwise 409 | :: Set [=this=]'s [=WebSocket/ready state=] to {{WebSocket/CLOSING}} (2). 410 | 411 |

[=The WebSocket closing handshake is started=], and will eventually invoke the 412 | [=close the WebSocket connection=] algorithm, which will establish that [=the WebSocket 413 | connection is closed=], and thus the {{WebSocket/close}} event will fire, as described below. 415 |

416 |
417 | 418 |

The {{WebSocket/close()}} method does not discard previously sent messages before 419 | starting the WebSocket closing handshake — even if, in practice, the user agent is still busy 420 | sending those messages, the handshake will only start after the messages are sent. 423 | 424 |


425 | 426 | The bufferedAmount getter steps are to return the number of bytes 427 | of application data (UTF-8 text and binary data) that have been queued using {{WebSocket/send()}} 428 | but that, as of the last time the [=event loop=] reached step 1, had not yet 429 | been transmitted to the network. (This thus includes any text sent during the execution of the 430 | current task, regardless of whether the user agent is able to transmit text in the background [=in 431 | parallel=] with script execution.) This does not include framing overhead incurred by the protocol, 432 | or buffering done by the operating system or network hardware. 433 | 434 |
435 | 436 | In this simple example, the {{WebSocket/bufferedAmount}} attribute is used to ensure that updates 437 | are sent either at the rate of one update every 50ms, if the network can handle that rate, or at 438 | whatever rate the network can handle, if that is too fast. 439 | 440 | 441 | var socket = new WebSocket('ws://game.example.com:12010/updates'); 442 | socket.onopen = function () { 443 | setInterval(function() { 444 | if (socket.bufferedAmount == 0) 445 | socket.send(getUpdateData()); 446 | }, 50); 447 | }; 448 | 449 | 450 | The {{WebSocket/bufferedAmount}} attribute can also be used to saturate the network without sending 451 | the data at a higher rate than the network can handle, though this requires more careful monitoring 452 | of the value of the attribute over time. 453 | 454 |
455 | 456 |
457 | 458 | The binaryType getter steps are to return [=this=]'s 459 | [=WebSocket/binary type=]. 460 | 461 | The {{WebSocket/binaryType}} setter steps are to set [=this=]'s [=WebSocket/binary type=] to 462 | [=the given value=]. 463 | 464 |

User agents can use the [=WebSocket/binary type=] as a hint for how to handle 465 | incoming binary data: if it is "{{BinaryType/blob}}", it is safe to spool it to disk, and if it is 466 | "{{BinaryType/arraybuffer}}", it is likely more efficient to keep the data in memory. Naturally, 467 | user agents are encouraged to use more subtle heuristics to decide whether to keep incoming data in 468 | memory or not, e.g. based on how big the data is or how common it is for a script to change the 469 | attribute at the last minute. This latter aspect is important in particular because it is quite 470 | possible for the attribute to be changed after the user agent has received the data but before the 471 | user agent has fired the event for it. 472 | 473 |

474 | The send(|data|) method steps are: 475 | 476 | 1. If [=this=]'s [=WebSocket/ready state=] is {{WebSocket/CONNECTING}}, then throw an 477 | "{{InvalidStateError}}" {{DOMException}}. 478 | 479 | 2. Run the appropriate set of steps from the following list: 480 | 481 | : If |data| is a string 482 | :: If [=the WebSocket connection is established=] and the WebSocket closing handshake has not yet started, then the user agent must 484 | [=send a WebSocket Message=] comprised of the |data| argument using a text frame opcode; if 485 | the data cannot be sent, e.g. because it would need to be buffered but the buffer is full, 486 | the user agent must flag the WebSocket as full and then [=close 487 | the WebSocket connection=]. Any invocation of this method with a string argument that does 488 | not throw an exception must increase the {{WebSocket/bufferedAmount}} attribute by the 489 | number of bytes needed to express the argument as UTF-8. [[!UNICODE]] [[!ENCODING]] [[!WSP]] 490 | 491 | 492 | : If |data| is a {{Blob}} object 493 | :: If [=the WebSocket connection is established=], and the WebSocket closing handshake has not yet started, then the user agent 495 | must [=send a WebSocket Message=] comprised of |data| using a binary frame opcode; if the 496 | data cannot be sent, e.g. because it would need to be buffered but the buffer is full, the 497 | user agent must flag the WebSocket as full and then [=close the 498 | WebSocket connection=]. The data to be sent is the raw data represented by the {{Blob}} 499 | object. 500 | 501 | Any invocation of this method with a {{Blob}} argument that does not throw an exception must 502 | increase the {{WebSocket/bufferedAmount}} attribute by the size of the {{Blob}} object's raw 503 | data, in bytes. 504 | 505 | [[!WSP]] [[!FILEAPI]] 506 | 507 | : If |data| is an {{ArrayBuffer}} 508 | :: If [=the WebSocket connection is established=], and the WebSocket closing handshake has not yet started, then the user agent 510 | must [=send a WebSocket Message=] comprised of |data| using a binary frame opcode; if the 511 | data cannot be sent, e.g. because it would need to be buffered but the buffer is full, the 512 | user agent must flag the WebSocket as full and then [=close the 513 | WebSocket connection=]. The data to be sent is the data stored in the buffer described by 514 | the {{ArrayBuffer}} object. Any invocation of this method with an {{ArrayBuffer}} argument 515 | that does not throw an exception must increase the {{WebSocket/bufferedAmount}} attribute by 516 | the length of the {{ArrayBuffer}} in bytes. [[!WSP]] 517 | 518 | : If |data| is an {{ArrayBufferView}} 519 | :: If [=the WebSocket connection is established=], and the WebSocket closing handshake has not yet started, then the user agent 521 | must [=send a WebSocket Message=] comprised of |data| using a binary frame opcode; if the 522 | data cannot be sent, e.g. because it would need to be buffered but the buffer is full, the 523 | user agent must flag the WebSocket as full and then [=close the 524 | WebSocket connection=]. The data to be sent is the data stored in the section of the buffer 525 | described by the {{ArrayBuffer}} object that |data| references. Any invocation of this 526 | method with this kind of argument that does not throw an exception must increase the 527 | {{WebSocket/bufferedAmount}} attribute by the length of |data|'s buffer in bytes. [[!WSP]] 528 |
529 | 530 |
531 | 532 | The following are the [=event handlers=] (and their corresponding [=event handler event types=]) 533 | that must be supported, as [=event handler IDL attributes=], by all objects implementing the 534 | {{WebSocket}} interface: 535 | 536 | 537 | 538 | 540 |
[=Event handler=] [=Event handler event type=] 539 |
onopen {{WebSocket/open}} 541 |
onmessage {{WebSocket/message}} 542 |
onerror {{WebSocket/error}} 543 |
onclose {{WebSocket/close}} 544 |
545 | 546 | 547 | # Feedback from the protocol # {#feedback-from-the-protocol} 548 | 549 | When [=the WebSocket connection is established=], the user agent must [=queue a task=] to run these 550 | steps: 551 | 552 |
553 | 554 | 1. Change the [=WebSocket/ready state=] to {{WebSocket/OPEN}} (1). 555 | 1. Change the {{WebSocket/extensions}} attribute's value to the [=extensions in 556 | use=], if it is not the null value. [[!WSP]] 557 | 1. Change the {{WebSocket/protocol}} attribute's value to the [=subprotocol in 558 | use=], if it is not the null value. [[!WSP]] 559 | 1. [=Fire an event=] named open at the {{WebSocket}} object. 560 | 561 |

Since the algorithm above is queued as a task, there is no 562 | race condition between the WebSocket connection 563 | being established and the script setting up an event listener for the {{WebSocket/open}} 564 | event. 565 | 566 |

567 | 568 |
569 | 570 |
571 | 572 | When [=a WebSocket message has been received=] with type |type| and data |data|, the user agent must 573 | [=queue a task=] to follow these steps: [[!WSP]] 574 | 575 | 1. If [=WebSocket/ready state=] ]is not {{WebSocket/OPEN}} (1), then return. 576 | 1. Let |dataForEvent| be determined by switching on |type| and [=WebSocket/binary type=]: 577 | 578 |
579 | : |type| indicates that the data is Text 580 | :: a new {{DOMString}} containing |data| 581 | 582 | : |type| indicates that the data is Binary and [=WebSocket/binary type=] is 583 | "blob" 584 | :: a new {{Blob}} object, created in the [=relevant Realm=] of the {{WebSocket}} object, that 585 | represents |data| as its raw data [[!FILEAPI]] 586 | 587 | : |type| indicates that the data is Binary and [=WebSocket/binary type=] is 588 | "arraybuffer" 589 | :: a new {{ArrayBuffer}} object, created in the [=relevant Realm=] of the {{WebSocket}} object, 590 | whose contents are |data| 591 |
592 | 593 | 1. [=Fire an event=] named message at the {{WebSocket}} object, 594 | using {{MessageEvent}}, with the {{MessageEvent/origin}} attribute initialized to the serialization of the {{WebSocket}} object's [=url=]'s [=origin=], and the 596 | {{MessageEvent/data}} attribute initialized to |dataForEvent|. 597 | 598 |

User agents are encouraged to check if they can perform the above steps efficiently 599 | before they run the task, picking tasks from other [=task queues=] while they prepare the buffers 600 | if not. For example, if the [=WebSocket/binary type=] is "{{BinaryType/blob}}" when the data 601 | arrived, and the user agent spooled all the data to disk, but just before running the above 602 | [=task=] for this particular message the script switched [=WebSocket/binary type=] to 603 | "{{BinaryType/arraybuffer}}", the user agent would want to page the data back to RAM before running 604 | this [=task=] so as to avoid stalling the main thread while it created the {{ArrayBuffer}} object. 605 | 606 |

607 | 608 |
609 | 610 | Here is an example of how to define a handler for the {{WebSocket/message}} event in the case of 611 | text frames: 612 | 613 | 614 | mysocket.onmessage = function (event) { 615 | if (event.data == 'on') { 616 | turnLampOn(); 617 | } else if (event.data == 'off') { 618 | turnLampOff(); 619 | } 620 | }; 621 | 622 | 623 | The protocol here is a trivial one, with the server just sending "on" or "off" messages. 624 | 625 |
626 | 627 |
628 | 629 | When [=the WebSocket closing handshake is started=], the user agent must [=queue a task=] to change 630 | the [=WebSocket/ready state=] to {{WebSocket/CLOSING}} (2). (If the {{WebSocket/close()}} method 631 | was called, the [=WebSocket/ready state=] will already be set to {{WebSocket/CLOSING}} (2) when 632 | this task runs.) [[!WSP]] 633 | 634 |
635 | 636 |

When [=the WebSocket connection is closed=], possibly [=cleanly=], the user 637 | agent must [=queue a task=] to run the following substeps: 638 | 639 |

640 | 1. Change the [=WebSocket/ready state=] to {{WebSocket/CLOSED}} (3). 641 | 1. If the user agent was required to [=fail the WebSocket connection=], or if the WebSocket connection was closed after being flagged 643 | as full, [=fire an event=] named error at the 644 | {{WebSocket}} object. [[!WSP]] 645 | 1. [=Fire an event=] named close at the {{WebSocket}} object, 646 | using {{CloseEvent}}, with the {{CloseEvent/wasClean}} attribute initialized to true if the 647 | connection closed [=cleanly=] and false otherwise, the {{CloseEvent/code}} attribute initialized 648 | to [=the WebSocket connection close code=], and the {{CloseEvent/reason}} attribute initialized 649 | to the result of applying [=UTF-8 decode without BOM=] to [=the WebSocket connection close 650 | reason=]. [[!WSP]] 651 |
652 | 653 |
654 | 655 | User agents must not convey any failure information to scripts in a way that would allow a 656 | script to distinguish the following situations: 657 | 658 | * A server whose host name could not be resolved. 659 | * A server to which packets could not successfully be routed. 660 | * A server that refused the connection on the specified port. 661 | * A server that failed to correctly perform a TLS handshake (e.g., the server certificate can't be 662 | verified). 663 | * A server that did not complete the opening handshake (e.g. because it was not a WebSocket 664 | server). 665 | * A WebSocket server that sent a correct opening handshake, but that specified options that caused 666 | the client to drop the connection (e.g. the server specified a subprotocol that the client did 667 | not offer). 668 | * A WebSocket server that abruptly closed the connection after successfully completing the 669 | opening handshake. 670 | 671 | In all of these cases, [=the WebSocket connection close code=] would be 1006, as required by 672 | WebSocket Protocol. [[!WSP]] 673 | 674 | Allowing a script to distinguish these cases would allow a script to probe the user's local network 675 | in preparation for an attack. 676 | 677 |

In particular, this means the code 1015 is not used by the user agent (unless the 678 | server erroneously uses it in its close frame, of course). 679 | 680 |

681 | 682 |
683 | 684 | The [=task source=] for all [=tasks=] queued in this section is the 685 | WebSocket task source. 686 | 687 | 688 | # Ping and Pong frames # {#ping-and-pong-frames} 689 | 690 | The WebSocket protocol defines Ping and Pong frames that can be used for keep-alive, 691 | heart-beats, network status probing, latency instrumentation, and so forth. These are not currently 692 | exposed in the API. 693 | 694 | User agents may send ping and unsolicited pong frames as desired, for example in an attempt to 695 | maintain local network NAT mappings, to detect failed connections, or to display latency metrics to 696 | the user. User agents must not use pings or unsolicited pongs to aid the server; it is assumed that 697 | servers will solicit pongs whenever appropriate for the server's needs. 698 | 699 | 702 | 703 | 704 | # The {{CloseEvent}} interface # {#the-closeevent-interface} 705 | 706 | {{WebSocket}} objects use the {{CloseEvent}} interface for their {{WebSocket/close}} events: 707 | 708 | 709 | [Exposed=(Window,Worker)] 710 | interface CloseEvent : Event { 711 | constructor(DOMString type, optional CloseEventInit eventInitDict = {}); 712 | 713 | readonly attribute boolean wasClean; 714 | readonly attribute unsigned short code; 715 | readonly attribute USVString reason; 716 | }; 717 | 718 | dictionary CloseEventInit : EventInit { 719 | boolean wasClean = false; 720 | unsigned short code = 0; 721 | USVString reason = ""; 722 | }; 723 | 724 | 725 |
726 | 727 | : |event| . {{CloseEvent/wasClean}} 728 | :: Returns true if the connection closed cleanly; false otherwise. 729 | : |event| . {{CloseEvent/code}} 730 | :: Returns the WebSocket connection close code provided by the server. 731 | : |event| . {{CloseEvent/reason}} 732 | :: Returns the WebSocket connection close reason provided by the server. 733 | 734 |
735 | 736 | The wasClean attribute must return the value it was initialized 737 | to. It represents whether the connection closed cleanly or not. 738 | 739 | The code attribute must return the value it was initialized 740 | to. It represents the WebSocket connection close code provided by the server. 741 | 742 | The reason attribute must return the value it was initialized 743 | to. It represents the WebSocket connection close reason provided by the server. 744 | 745 | 746 | 747 | # Garbage collection # {#garbage-collection} 748 | 749 | A {{WebSocket}} object whose [=WebSocket/ready state=] was set to {{WebSocket/CONNECTING}} (0) as 750 | of the last time the [=event loop=] reached step 1 must not be garbage 751 | collected if there are any event listeners registered for {{WebSocket/open}} events, 752 | {{WebSocket/message}} events, {{WebSocket/error}} events, or {{WebSocket/close}} events. 753 | 754 | A {{WebSocket}} object whose [=WebSocket/ready state=] was set to {{WebSocket/OPEN}} (1) as of the 755 | last time the [=event loop=] reached step 1 must not be garbage collected 756 | if there are any event listeners registered for {{WebSocket/message}} events, {{WebSocket/error}}, 757 | or {{WebSocket/close}} events. 758 | 759 | A {{WebSocket}} object whose [=WebSocket/ready state=] was set to {{WebSocket/CLOSING}} (2) as of 760 | the last time the [=event loop=] reached step 1 must not be garbage 761 | collected if there are any event listeners registered for {{WebSocket/error}} or {{WebSocket/close}} 762 | events. 763 | 764 | A {{WebSocket}} object with an established 765 | connection that has data queued to be transmitted to the network must not be garbage collected. 766 | [[!WSP]] 767 | 768 | If a {{WebSocket}} object is garbage collected while its connection is still open, the user agent 769 | must [=start the WebSocket closing handshake=], with no status code for the Close 770 | message. [[!WSP]] 771 | 772 |
773 | 774 | If a user agent is to make disappear a {{WebSocket}} object (this happens when a 775 | {{Document}} object goes away), the user agent must follow the first appropriate set of steps from 776 | the following list: 777 | 778 |
779 | 780 |
781 | 782 | : If the WebSocket connection is not yet [=established=] [[!WSP]] 783 | :: [=Fail the WebSocket connection=]. [[!WSP]] 784 | : If the WebSocket closing handshake has not yet been 785 | started [[!WSP]] 786 | :: [=Start the WebSocket closing handshake=], with the status code to use in the 787 | WebSocket Close message being 1001. [[!WSP]] 788 | : Otherwise 789 | :: Do nothing. 790 | 791 |
792 | 793 |
794 | 795 |

Acknowledgments

796 | 797 | Until the creation of this standard in 2021, the text here was maintained in the HTML Standard and Fetch Standard. Thanks to all of the contributors to those 800 | repositories who helped develop the specification, especially Ian Hickson and Anne van Kesteren as 801 | the respective original authors. 802 | 803 | Thanks to 804 | 平野裕 (Yutaka Hirano) 805 | for their contributions after the creation of the WebSockets Standard. 806 | 807 | This standard is written by Adam Rice (Google, ricea@chromium.org). 809 | -------------------------------------------------------------------------------- /review-drafts/2022-09.bs: -------------------------------------------------------------------------------- 1 |
  2 | Group: WHATWG
  3 | Status: RD
  4 | Date: 2022-09-19
  5 | H1: WebSockets
  6 | Shortname: websockets
  7 | Text Macro: TWITTER whatsockets
  8 | Text Macro: LATESTRD 2022-09
  9 | Abstract: This specification provides APIs to enable web applications to maintain bidirectional
 10 | Abstract: communications with server-side processes.
 11 | Translation: ja https://triple-underscore.github.io/WebSocket-ja.html
 12 | Indent: 1
 13 | Markup Shorthands: markdown yes
 14 | 
15 | 16 |
 17 | {
 18 |  "WSP": {
 19 |   "aliasOf": "RFC6455"
 20 |  },
 21 |  "HSTS": {
 22 |   "aliasOf": "RFC6797"
 23 |  }
 24 | }
 25 | 
26 | 27 | 40 | 41 |
 42 | spec:RFC6455; urlPrefix: https://datatracker.ietf.org/doc/html/rfc6455
 43 |  type: dfn
 44 |   text:the WebSocket connection is established; url:page-19:~:text=_The%20WebSocket%20Connection%20is%20Established_,-and
 45 |   text:extensions in use; url:page-19:~:text=_The%20WebSocket%20Connection%20is%20Established_,-and
 46 |   text:subprotocol in use; url:page-19:~:text=_Subprotocol%20In,Use_
 47 |   text:a WebSocket message has been received; url:page-66:~:text=_A%20WebSocket%20Message%20Has%20Been%20Received_
 48 |   text:send a WebSocket Message; url:page-66:~:text=needs%20to-,_Send%20a%20WebSocket%20Message_
 49 |   text:fail the WebSocket connection; url:section-7.1.7
 50 |   text:close the WebSocket connection; url:section-7.1.1
 51 |   text:start the WebSocket closing handshake; url:section-7.1.2
 52 |   text:the WebSocket closing handshake is started; url:section-7.1.3
 53 |   text:the WebSocket connection is closed; url:section-7.1.4
 54 |   text:the WebSocket connection close code; url:section-7.1.5
 55 |   text:the WebSocket connection close reason; url:section-7.1.6
 56 |   text:established; url:page-19:~:text=_The%20WebSocket%20Connection%20is%20Established_,-and
 57 |   text:ws; url:section-11.1.1
 58 |   text:wss; url:section-11.1.2
 59 |   text:cleanly; url:page-41:~:text=closed-,_cleanly_.
 60 |  type: http-header; text:Sec-WebSocket-Protocol; url:section-11.3.4
 61 | spec:html; type:dfn; urlPrefix: https://html.spec.whatwg.org/multipage/webappapis.html
 62 |  for:event loop; text:step 1; url:step1
 63 | 
64 | 65 | 66 | # Introduction # {#network-intro} 67 | 68 |
69 | 70 | This section is non-normative. 71 | 72 | To enable web applications to maintain bidirectional communications with server-side processes, 73 | this specification introduces the {{WebSocket}} interface. 74 | 75 |

This interface does not allow for raw access to the underlying network. For 76 | example, this interface could not be used to implement an IRC client without proxying messages 77 | through a custom server.

78 |
79 | 80 | 81 | # WebSocket protocol alterations # {#websocket-protocol} 82 | 83 |
84 | This section replaces part of the WebSocket protocol opening handshake client requirement to 85 | integrate it with algorithms defined in Fetch. This way CSP, cookies, HSTS, and other 86 | Fetch-related protocols are handled in a single location. Ideally the RFC would be 87 | updated with this language, but it is never that easy. The {{WebSocket}} API, defined below, uses 88 | this language. [[!WSP]] [[!FETCH]] 89 | 90 | The way this works is by replacing The WebSocket Protocol's "establish a WebSocket connection" 91 | algorithm with a new one that integrates with Fetch. "Establish a WebSocket 92 | connection" consists of three algorithms: setting up a connection, creating and transmiting a 93 | handshake request, and validating the handshake response. That layering is different from 94 | Fetch, which first creates a handshake, then sets up a connection and transmits the 95 | handshake, and finally validates the response. Keep that in mind while reading these alterations. 96 |
97 | 98 | 99 | ## Connections ## {#websocket-connections} 100 | 101 |
102 | 103 | To obtain a WebSocket connection, given a 104 | |url|, run these steps: 105 | 106 | 1. Let |host| be |url|'s host. 107 | 1. Let |port| be |url|'s port. 108 | 1. Let |resource name| be U+002F (/), followed by the strings in |url|'s path 109 | (including empty strings), if any, separated from each other by U+002F (/). 110 | 1. If |url|'s query is non-empty, append U+003F (?), followed by |url|'s 111 | query, to |resource name|. 112 | 1. Let |secure| be false, if |url|'s scheme is "`http`", and true otherwise. 113 | 1. Follow the requirements stated in step 2 to 5, inclusive, of the first set of steps in section 4.1 of The WebSocket 115 | Protocol to establish a WebSocket connection, passing 116 | |host|, |port|, |resource name| and |secure|. [[!WSP]] 117 | 1. If that established a connection, return it, and return failure otherwise. 118 | 119 |

Although structured a little differently, carrying different properties, and 120 | therefore not shareable, a WebSocket connection is very close to identical to an "ordinary" 121 | [=connection=]. 122 | 123 |

124 | 125 | 126 | ## Opening handshake ## {#websocket-opening-handshake} 127 | 128 |
129 | 130 | To establish a WebSocket connection, given a 131 | |url|, |protocols|, and |client|, run these steps: 132 | 133 | 1. Let |requestURL| be a copy of |url|, with its scheme set to "`http`", if |url|'s 134 | scheme is "`ws`", and to "`https`" otherwise. 135 | 136 |

This change of scheme is essential to integrate well with 137 | fetching. E.g., HSTS would not work without it. There is no real 138 | reason for WebSocket to have distinct schemes, it's a legacy artefact. 139 | [[!HSTS]] 140 | 141 | 1. Let |request| be a new request, whose URL is |requestURL|, 142 | client is |client|, [=service-workers mode=] is "`none`", 143 | referrer is "`no-referrer`", mode is "`websocket`", 144 | credentials mode is "`include`", cache mode is "`no-store`" 145 | , and redirect mode is "`error`". 146 | 147 | 1. Append (\``Upgrade`\`, \``websocket`\`) to |request|'s 148 | header list. 149 | 1. Append (\``Connection`\`, \``Upgrade`\`) to |request|'s 150 | header list. 151 | 1. Let |keyValue| be a nonce consisting of a randomly selected 16-byte value that has been 152 | forgiving-base64-encoded and [=isomorphic encoded=]. 153 | 154 |

If the randomly selected value was the byte sequence 0x01 155 | 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10, |keyValue| would be 156 | forgiving-base64-encoded to "`AQIDBAUGBwgJCgsMDQ4PEC==`" and isomorphic encoded to 157 | \``AQIDBAUGBwgJCgsMDQ4PEC==`\`. 158 | 159 | 1. Append (\``Sec-WebSocket-Key`\`, |keyValue|) to |request|'s 160 | header list. 161 | 1. Append (\``Sec-WebSocket-Version`\`, \``13`\`) to |request|'s 162 | header list. 163 | 1. For each |protocol| in |protocols|, combine 164 | (\``Sec-WebSocket-Protocol`\`, |protocol|) in |request|'s header list. 165 | 166 | 1. Let |permessageDeflate| be a user-agent defined "`permessage-deflate`" extension 167 | header value. [[!WSP]] 168 | 169 |

\``permessage-deflate; client_max_window_bits`\` 170 | 171 | 1. Append (\``Sec-WebSocket-Extensions`\`, |permessageDeflate|) to 172 | |request|'s header list. 173 | 1. Fetch |request| with useParallelQueue set to true, 174 | and processResponse given |response| being these steps: 175 | 1. If |response| is a [=network error=] or its status is not 101, [=fail the 176 | WebSocket connection=]. 177 | 1. If |protocols| is not the empty list and [=extracting header list values=] given 178 | \``Sec-WebSocket-Protocol`\` and |response|'s header list 179 | results in null, failure, or the empty byte sequence, then [=fail the WebSocket connection=]. 180 | 181 |

This is different from the check on this header defined by The WebSocket Protocol. 182 | That only covers a subprotocol not requested by the client. This covers a subprotocol requested 183 | by the client, but not acknowledged by the server. 184 | 185 | 1. Follow the requirements stated step 2 to step 6, inclusive, of the last set of steps in 186 | section 4.1 of The WebSocket 187 | Protocol to validate |response|. This either results in [=fail the WebSocket connection=] 188 | or [=the WebSocket connection is established=]. 189 | 190 |

191 | 192 | [=Fail the WebSocket connection=] and [=the WebSocket connection is established=] are defined by The 193 | WebSocket Protocol. [[!WSP]] 194 | 195 |

The reason redirects are not followed and this handshake is generally restricted is 196 | because it could introduce serious security problems in a web browser context. For example, consider 197 | a host with a WebSocket server at one path and an open HTTP redirector at another. Suddenly, any 198 | script that can be given a particular WebSocket URL can be tricked into communicating to (and 199 | potentially sharing secrets with) any host on the internet, even if the script checks that the URL 200 | has the right hostname. 201 | 202 | 203 | 204 | # The {{WebSocket}} interface # {#the-websocket-interface} 205 | ## Interface definition ## {#interface-definition} 206 | 207 | The Web IDL definition for the {{WebSocket}} class is given as follows: 208 | 209 |

210 | enum BinaryType { "blob", "arraybuffer" }; 211 | 212 | [Exposed=(Window,Worker)] 213 | interface WebSocket : EventTarget { 214 | constructor(USVString url, optional (DOMString or sequence<DOMString>) protocols = []); 215 | readonly attribute USVString url; 216 | 217 | // ready state 218 | const unsigned short CONNECTING = 0; 219 | const unsigned short OPEN = 1; 220 | const unsigned short CLOSING = 2; 221 | const unsigned short CLOSED = 3; 222 | readonly attribute unsigned short readyState; 223 | readonly attribute unsigned long long bufferedAmount; 224 | 225 | // networking 226 | attribute EventHandler onopen; 227 | attribute EventHandler onerror; 228 | attribute EventHandler onclose; 229 | readonly attribute DOMString extensions; 230 | readonly attribute DOMString protocol; 231 | undefined close(optional [Clamp] unsigned short code, optional USVString reason); 232 | 233 | // messaging 234 | attribute EventHandler onmessage; 235 | attribute BinaryType binaryType; 236 | undefined send((BufferSource or Blob or USVString) data); 237 | }; 238 | 239 | 240 | Each {{WebSocket}} object has an associated url, which 241 | is a [=URL record=]. 242 | 243 | Each {{WebSocket}} object has an associated binary type, which is a 244 | {{BinaryType}}. Initially it must be "{{BinaryType/blob}}". 245 | 246 | Each {{WebSocket}} object has an associated ready state, which is a 247 | number representing the state of the connection. Initially it must be {{WebSocket/CONNECTING}} (0). 248 | It can have the following values: 249 | 250 | : CONNECTING (numeric value 0) 251 | :: The connection has not yet been established. 252 | : OPEN (numeric value 1) 253 | :: [=The WebSocket connection is established=] and communication is possible. 254 | : CLOSING (numeric value 2) 255 | :: The connection is going through the 256 | closing handshake, or the {{WebSocket/close()}} method has been invoked. 257 | : CLOSED (numeric value 3) 258 | :: The connection has been closed or could not be opened. 259 | 260 |
261 | : |socket| = new {{WebSocket/constructor(url, protocols)|WebSocket}}(|url| [, |protocols| ]) 262 | :: Creates a new {{WebSocket}} object, immediately establishing the associated WebSocket 263 | connection. 264 | 265 | |url| is a string giving the URL over which the connection is established. 266 | Only "`ws`" or "`wss`" schemes are allowed; others will cause a "{{SyntaxError}}" 267 | {{DOMException}}. URLs with [=fragments=] will also cause such an exception. 268 | 269 | |protocols| is either a string or an array of strings. If it is a string, it is equivalent to 270 | an array consisting of just that string; if it is omitted, it is equivalent to the empty array. 271 | Each string in the array is a subprotocol name. The connection will only be established if the 272 | server reports that it has selected one of these subprotocols. The subprotocol names have to 273 | match the requirements for elements that comprise the value of \``Sec-WebSocket-Protocol`\` fields as defined by The WebSocket protocol. 275 | [[!WSP]] 276 | 277 | : |socket|.send(|data|) 278 | :: Transmits |data| using the WebSocket connection. |data| can be a string, a {{Blob}}, an 279 | {{ArrayBuffer}}, or an {{ArrayBufferView}}. 280 | 281 | : |socket|.close([ |code| ] [, |reason| ]) 282 | :: Closes the WebSocket connection, optionally using |code| as [=the WebSocket connection 283 | close code=] and |reason| as [=the WebSocket connection close reason=]. 284 | 285 | : |socket|.url 286 | :: Returns the URL that was used to establish the WebSocket connection. 287 | 288 | : |socket|.readyState 289 | :: Returns the state of the WebSocket connection. It can have the values described above. 290 | 291 | : |socket|.bufferedAmount 292 | :: Returns the number of bytes of application data (UTF-8 text and binary data) that have been 293 | queued using {{WebSocket/send()}} but not yet been transmitted to the network. 294 | 295 | If the WebSocket connection is closed, this attribute's value will only increase with each call 296 | to the {{WebSocket/send()}} method. (The number does not reset to zero once the connection 297 | closes.) 298 | 299 | : |socket|.extensions 300 | :: Returns the extensions selected by the server, if any. 301 | 302 | : |socket|.protocol 303 | :: Returns the subprotocol selected by the server, if any. It can be used in conjunction with the 304 | array form of the constructor's second argument to perform subprotocol negotiation. 305 | 306 | : |socket|.binaryType 307 | :: Returns a string that indicates how binary data from |socket| is exposed to scripts: 308 | 309 | : "{{BinaryType/blob}}" 310 | :: Binary data is returned in {{Blob}} form. 311 | : "{{BinaryType/arraybuffer}}" 312 | :: Binary data is returned in {{ArrayBuffer}} form. 313 | 314 | The default is "{{BinaryType/blob}}". 315 | 316 | : |socket|.binaryType = value 317 | :: Changes how binary data is returned. 318 |
319 | 320 |
321 | The new 322 | WebSocket(|url|, |protocols|) 323 | constructor steps are: 324 | 325 | 1. Let |urlRecord| be the result of applying the [=URL parser=] to |url|. 326 | 1. If |urlRecord| is failure, then throw a "{{SyntaxError}}" {{DOMException}}. 327 | 1. If |urlRecord|'s [=scheme=] is not "[=ws=]" or "[=wss=]", then throw a 328 | "{{SyntaxError}}" {{DOMException}}. 329 | 1. If |urlRecord|'s [=fragment=] is non-null, then throw a "{{SyntaxError}}" {{DOMException}}. 330 | 1. If |protocols| is a string, set |protocols| to a sequence consisting of just that string. 331 | 1. If any of the values in |protocols| occur more than once or otherwise fail to match the 332 | requirements for elements that comprise the value of 333 | \``Sec-WebSocket-Protocol`\` fields as defined by The WebSocket protocol, 334 | then throw a "{{SyntaxError}}" {{DOMException}}. [[!WSP]] 335 | 1. Set [=this=]'s [=WebSocket/internal-url|url=] to |urlRecord|. 336 | 1. Let |client| be [=this=]'s [=relevant settings object=]. 337 | 1. Run this step [=in parallel=]: 338 | 1. [=Establish a WebSocket connection=] given |urlRecord|, |protocols|, and |client|. [[!FETCH]] 339 | 340 |

If the [=establish a WebSocket connection=] algorithm 341 | fails, it triggers the [=fail the WebSocket connection=] algorithm, which 342 | then invokes the [=close the WebSocket connection=] algorithm, which then 343 | establishes that [=the WebSocket connection is closed=], which fires the 344 | {{WebSocket/close}} event as described below. 345 |

346 | 347 |
348 | 349 | The url getter steps are to return [=this=]'s 350 | [=WebSocket/internal-url|url=], [=URL serializer|serialized=]. 351 | 352 | The readyState getter steps are to return [=this=]'s 353 | [=WebSocket/ready state=]. 354 | 355 | The extensions attribute must initially return the empty 356 | string. After [=the WebSocket connection is established=], its value might change, as defined 357 | below.

358 | 359 | The protocol attribute must initially return the empty 360 | string. After [=the WebSocket connection is established=], its value might change, as defined below. 361 | 362 |
363 | The close(|code|, |reason|) method steps are: 364 | 365 | 1. If |code| is present, but is neither an integer equal to 1000 nor an integer in the range 3000 366 | to 4999, inclusive, throw an "{{InvalidAccessError}}" {{DOMException}}. 367 | 1. If |reason| is present, then run these substeps: 368 | 1. Let |reasonBytes| be the result of encoding |reason|. 369 | 1. If |reasonBytes| is longer than 123 bytes, then throw a "{{SyntaxError}}" {{DOMException}}. 370 | 1. Run the first matching steps from the following list: 371 |
372 | : If [=this=]'s [=WebSocket/ready state=] is {{WebSocket/CLOSING}} (2) or {{WebSocket/CLOSED}} (3) 373 | :: Do nothing. 374 | 375 |

The connection is already closing or is already closed. If it has not already, a 376 | {{WebSocket/close}} event will eventually fire as described below. 377 | 378 | : If the WebSocket connection is not yet [=established=] [[!WSP]] 379 | :: [=Fail the WebSocket connection=] and set [=this=]'s [=WebSocket/ready state=] to 380 | {{WebSocket/CLOSING}} (2). [[!WSP]] 381 | 382 |

The [=fail the WebSocket connection=] algorithm invokes the [=close the 383 | WebSocket connection=] algorithm, which then establishes that [=the WebSocket connection is 384 | closed=], which fires the {{WebSocket/close}} event as described 385 | below. 386 | 387 | : If the WebSocket closing handshake has not yet been started [[!WSP]] 389 | :: [=Start the WebSocket closing handshake=] and set [=this=]'s [=WebSocket/ready state=] to 390 | {{WebSocket/CLOSING}} (2). [[!WSP]] 391 | 392 | If neither |code| nor |reason| is present, the WebSocket Close message must not have a body. 393 | 394 |

The WebSocket Protocol erroneously states that the status code is required for the [=start the WebSocket closing handshake=] algorithm. 396 | 397 | 398 | If |code| is present, then the status code to use in the WebSocket Close 399 | message must be the integer given by |code|. [[!WSP]] 400 | 401 | If |reason| is also present, then |reasonBytes| must be provided in the Close message after the 402 | status code. [[!WSP]] 403 | 404 |

The [=start the WebSocket closing handshake=] algorithm eventually invokes the 405 | [=close the WebSocket connection=] algorithm, which then establishes that [=the WebSocket 406 | connection is closed=], which fires the {{WebSocket/close}} event as 407 | described below. 408 | 409 | : Otherwise 410 | :: Set [=this=]'s [=WebSocket/ready state=] to {{WebSocket/CLOSING}} (2). 411 | 412 |

[=The WebSocket closing handshake is started=], and will eventually invoke the 413 | [=close the WebSocket connection=] algorithm, which will establish that [=the WebSocket 414 | connection is closed=], and thus the {{WebSocket/close}} event will fire, as described below. 416 |

417 |
418 | 419 |

The {{WebSocket/close()}} method does not discard previously sent messages before 420 | starting the WebSocket closing handshake — even if, in practice, the user agent is still busy 421 | sending those messages, the handshake will only start after the messages are sent. 424 | 425 |


426 | 427 | The bufferedAmount getter steps are to return the number of bytes 428 | of application data (UTF-8 text and binary data) that have been queued using {{WebSocket/send()}} 429 | but that, as of the last time the [=event loop=] reached step 1, had not yet 430 | been transmitted to the network. (This thus includes any text sent during the execution of the 431 | current task, regardless of whether the user agent is able to transmit text in the background [=in 432 | parallel=] with script execution.) This does not include framing overhead incurred by the protocol, 433 | or buffering done by the operating system or network hardware. 434 | 435 |
436 | 437 | In this simple example, the {{WebSocket/bufferedAmount}} attribute is used to ensure that updates 438 | are sent either at the rate of one update every 50ms, if the network can handle that rate, or at 439 | whatever rate the network can handle, if that is too fast. 440 | 441 | 442 | var socket = new WebSocket('ws://game.example.com:12010/updates'); 443 | socket.onopen = function () { 444 | setInterval(function() { 445 | if (socket.bufferedAmount == 0) 446 | socket.send(getUpdateData()); 447 | }, 50); 448 | }; 449 | 450 | 451 | The {{WebSocket/bufferedAmount}} attribute can also be used to saturate the network without sending 452 | the data at a higher rate than the network can handle, though this requires more careful monitoring 453 | of the value of the attribute over time. 454 | 455 |
456 | 457 |
458 | 459 | The binaryType getter steps are to return [=this=]'s 460 | [=WebSocket/binary type=]. 461 | 462 | The {{WebSocket/binaryType}} setter steps are to set [=this=]'s [=WebSocket/binary type=] to 463 | [=the given value=]. 464 | 465 |

User agents can use the [=WebSocket/binary type=] as a hint for how to handle 466 | incoming binary data: if it is "{{BinaryType/blob}}", it is safe to spool it to disk, and if it is 467 | "{{BinaryType/arraybuffer}}", it is likely more efficient to keep the data in memory. Naturally, 468 | user agents are encouraged to use more subtle heuristics to decide whether to keep incoming data in 469 | memory or not, e.g. based on how big the data is or how common it is for a script to change the 470 | attribute at the last minute. This latter aspect is important in particular because it is quite 471 | possible for the attribute to be changed after the user agent has received the data but before the 472 | user agent has fired the event for it. 473 | 474 |

475 | The send(|data|) method steps are: 476 | 477 | 1. If [=this=]'s [=WebSocket/ready state=] is {{WebSocket/CONNECTING}}, then throw an 478 | "{{InvalidStateError}}" {{DOMException}}. 479 | 480 | 2. Run the appropriate set of steps from the following list: 481 | 482 | : If |data| is a string 483 | :: If [=the WebSocket connection is established=] and the WebSocket closing handshake has not yet started, then the user agent must 485 | [=send a WebSocket Message=] comprised of the |data| argument using a text frame opcode; if 486 | the data cannot be sent, e.g. because it would need to be buffered but the buffer is full, 487 | the user agent must flag the WebSocket as full and then [=close 488 | the WebSocket connection=]. Any invocation of this method with a string argument that does 489 | not throw an exception must increase the {{WebSocket/bufferedAmount}} attribute by the 490 | number of bytes needed to express the argument as UTF-8. [[!UNICODE]] [[!ENCODING]] [[!WSP]] 491 | 492 | 493 | : If |data| is a {{Blob}} object 494 | :: If [=the WebSocket connection is established=], and the WebSocket closing handshake has not yet started, then the user agent 496 | must [=send a WebSocket Message=] comprised of |data| using a binary frame opcode; if the 497 | data cannot be sent, e.g. because it would need to be buffered but the buffer is full, the 498 | user agent must flag the WebSocket as full and then [=close the 499 | WebSocket connection=]. The data to be sent is the raw data represented by the {{Blob}} 500 | object. 501 | 502 | Any invocation of this method with a {{Blob}} argument that does not throw an exception must 503 | increase the {{WebSocket/bufferedAmount}} attribute by the size of the {{Blob}} object's raw 504 | data, in bytes. 505 | 506 | [[!WSP]] [[!FILEAPI]] 507 | 508 | : If |data| is an {{ArrayBuffer}} 509 | :: If [=the WebSocket connection is established=], and the WebSocket closing handshake has not yet started, then the user agent 511 | must [=send a WebSocket Message=] comprised of |data| using a binary frame opcode; if the 512 | data cannot be sent, e.g. because it would need to be buffered but the buffer is full, the 513 | user agent must flag the WebSocket as full and then [=close the 514 | WebSocket connection=]. The data to be sent is the data stored in the buffer described by 515 | the {{ArrayBuffer}} object. Any invocation of this method with an {{ArrayBuffer}} argument 516 | that does not throw an exception must increase the {{WebSocket/bufferedAmount}} attribute by 517 | the length of the {{ArrayBuffer}} in bytes. [[!WSP]] 518 | 519 | : If |data| is an {{ArrayBufferView}} 520 | :: If [=the WebSocket connection is established=], and the WebSocket closing handshake has not yet started, then the user agent 522 | must [=send a WebSocket Message=] comprised of |data| using a binary frame opcode; if the 523 | data cannot be sent, e.g. because it would need to be buffered but the buffer is full, the 524 | user agent must flag the WebSocket as full and then [=close the 525 | WebSocket connection=]. The data to be sent is the data stored in the section of the buffer 526 | described by the {{ArrayBuffer}} object that |data| references. Any invocation of this 527 | method with this kind of argument that does not throw an exception must increase the 528 | {{WebSocket/bufferedAmount}} attribute by the length of |data|'s buffer in bytes. [[!WSP]] 529 |
530 | 531 |
532 | 533 | The following are the [=event handlers=] (and their corresponding [=event handler event types=]) 534 | that must be supported, as [=event handler IDL attributes=], by all objects implementing the 535 | {{WebSocket}} interface: 536 | 537 | 538 | 539 | 541 |
[=Event handler=] [=Event handler event type=] 540 |
onopen {{WebSocket/open}} 542 |
onmessage {{WebSocket/message}} 543 |
onerror {{WebSocket/error}} 544 |
onclose {{WebSocket/close}} 545 |
546 | 547 | 548 | # Feedback from the protocol # {#feedback-from-the-protocol} 549 | 550 | When [=the WebSocket connection is established=], the user agent must [=queue a task=] to run these 551 | steps: 552 | 553 |
554 | 555 | 1. Change the [=WebSocket/ready state=] to {{WebSocket/OPEN}} (1). 556 | 1. Change the {{WebSocket/extensions}} attribute's value to the [=extensions in 557 | use=], if it is not the null value. [[!WSP]] 558 | 1. Change the {{WebSocket/protocol}} attribute's value to the [=subprotocol in 559 | use=], if it is not the null value. [[!WSP]] 560 | 1. [=Fire an event=] named open at the {{WebSocket}} object. 561 | 562 |

Since the algorithm above is queued as a task, there is no 563 | race condition between the WebSocket connection 564 | being established and the script setting up an event listener for the {{WebSocket/open}} 565 | event. 566 | 567 |

568 | 569 |
570 | 571 |
572 | 573 | When [=a WebSocket message has been received=] with type |type| and data |data|, the user agent must 574 | [=queue a task=] to follow these steps: [[!WSP]] 575 | 576 | 1. If [=WebSocket/ready state=] is not {{WebSocket/OPEN}} (1), then return. 577 | 1. Let |dataForEvent| be determined by switching on |type| and [=WebSocket/binary type=]: 578 | 579 |
580 | : |type| indicates that the data is Text 581 | :: a new {{DOMString}} containing |data| 582 | 583 | : |type| indicates that the data is Binary and [=WebSocket/binary type=] is 584 | "blob" 585 | :: a new {{Blob}} object, created in the [=relevant Realm=] of the {{WebSocket}} object, that 586 | represents |data| as its raw data [[!FILEAPI]] 587 | 588 | : |type| indicates that the data is Binary and [=WebSocket/binary type=] is 589 | "arraybuffer" 590 | :: a new {{ArrayBuffer}} object, created in the [=relevant Realm=] of the {{WebSocket}} object, 591 | whose contents are |data| 592 |
593 | 594 | 1. [=Fire an event=] named message at the {{WebSocket}} object, 595 | using {{MessageEvent}}, with the {{MessageEvent/origin}} attribute initialized to the serialization of the {{WebSocket}} object's [=url=]'s [=origin=], and the 597 | {{MessageEvent/data}} attribute initialized to |dataForEvent|. 598 | 599 |

User agents are encouraged to check if they can perform the above steps efficiently 600 | before they run the task, picking tasks from other [=task queues=] while they prepare the buffers 601 | if not. For example, if the [=WebSocket/binary type=] is "{{BinaryType/blob}}" when the data 602 | arrived, and the user agent spooled all the data to disk, but just before running the above 603 | [=task=] for this particular message the script switched [=WebSocket/binary type=] to 604 | "{{BinaryType/arraybuffer}}", the user agent would want to page the data back to RAM before running 605 | this [=task=] so as to avoid stalling the main thread while it created the {{ArrayBuffer}} object. 606 | 607 |

608 | 609 |
610 | 611 | Here is an example of how to define a handler for the {{WebSocket/message}} event in the case of 612 | text frames: 613 | 614 | 615 | mysocket.onmessage = function (event) { 616 | if (event.data == 'on') { 617 | turnLampOn(); 618 | } else if (event.data == 'off') { 619 | turnLampOff(); 620 | } 621 | }; 622 | 623 | 624 | The protocol here is a trivial one, with the server just sending "on" or "off" messages. 625 | 626 |
627 | 628 |
629 | 630 | When [=the WebSocket closing handshake is started=], the user agent must [=queue a task=] to change 631 | the [=WebSocket/ready state=] to {{WebSocket/CLOSING}} (2). (If the {{WebSocket/close()}} method 632 | was called, the [=WebSocket/ready state=] will already be set to {{WebSocket/CLOSING}} (2) when 633 | this task runs.) [[!WSP]] 634 | 635 |
636 | 637 |

When [=the WebSocket connection is closed=], possibly [=cleanly=], the user 638 | agent must [=queue a task=] to run the following substeps: 639 | 640 |

641 | 1. Change the [=WebSocket/ready state=] to {{WebSocket/CLOSED}} (3). 642 | 1. If the user agent was required to [=fail the WebSocket connection=], or if the WebSocket connection was closed after being flagged 644 | as full, [=fire an event=] named error at the 645 | {{WebSocket}} object. [[!WSP]] 646 | 1. [=Fire an event=] named close at the {{WebSocket}} object, 647 | using {{CloseEvent}}, with the {{CloseEvent/wasClean}} attribute initialized to true if the 648 | connection closed [=cleanly=] and false otherwise, the {{CloseEvent/code}} attribute initialized 649 | to [=the WebSocket connection close code=], and the {{CloseEvent/reason}} attribute initialized 650 | to the result of applying [=UTF-8 decode without BOM=] to [=the WebSocket connection close 651 | reason=]. [[!WSP]] 652 |
653 | 654 |
655 | 656 | User agents must not convey any failure information to scripts in a way that would allow a 657 | script to distinguish the following situations: 658 | 659 | * A server whose host name could not be resolved. 660 | * A server to which packets could not successfully be routed. 661 | * A server that refused the connection on the specified port. 662 | * A server that failed to correctly perform a TLS handshake (e.g., the server certificate can't be 663 | verified). 664 | * A server that did not complete the opening handshake (e.g. because it was not a WebSocket 665 | server). 666 | * A WebSocket server that sent a correct opening handshake, but that specified options that caused 667 | the client to drop the connection (e.g. the server specified a subprotocol that the client did 668 | not offer). 669 | * A WebSocket server that abruptly closed the connection after successfully completing the 670 | opening handshake. 671 | 672 | In all of these cases, [=the WebSocket connection close code=] would be 1006, as required by 673 | WebSocket Protocol. [[!WSP]] 674 | 675 | Allowing a script to distinguish these cases would allow a script to probe the user's local network 676 | in preparation for an attack. 677 | 678 |

In particular, this means the code 1015 is not used by the user agent (unless the 679 | server erroneously uses it in its close frame, of course). 680 | 681 |

682 | 683 |
684 | 685 | The [=task source=] for all [=tasks=] queued in this section is the 686 | WebSocket task source. 687 | 688 | 689 | # Ping and Pong frames # {#ping-and-pong-frames} 690 | 691 | The WebSocket protocol defines Ping and Pong frames that can be used for keep-alive, 692 | heart-beats, network status probing, latency instrumentation, and so forth. These are not currently 693 | exposed in the API. 694 | 695 | User agents may send ping and unsolicited pong frames as desired, for example in an attempt to 696 | maintain local network NAT mappings, to detect failed connections, or to display latency metrics to 697 | the user. User agents must not use pings or unsolicited pongs to aid the server; it is assumed that 698 | servers will solicit pongs whenever appropriate for the server's needs. 699 | 700 | 703 | 704 | 705 | # The {{CloseEvent}} interface # {#the-closeevent-interface} 706 | 707 | {{WebSocket}} objects use the {{CloseEvent}} interface for their {{WebSocket/close}} events: 708 | 709 | 710 | [Exposed=(Window,Worker)] 711 | interface CloseEvent : Event { 712 | constructor(DOMString type, optional CloseEventInit eventInitDict = {}); 713 | 714 | readonly attribute boolean wasClean; 715 | readonly attribute unsigned short code; 716 | readonly attribute USVString reason; 717 | }; 718 | 719 | dictionary CloseEventInit : EventInit { 720 | boolean wasClean = false; 721 | unsigned short code = 0; 722 | USVString reason = ""; 723 | }; 724 | 725 | 726 |
727 | 728 | : |event| . {{CloseEvent/wasClean}} 729 | :: Returns true if the connection closed cleanly; false otherwise. 730 | : |event| . {{CloseEvent/code}} 731 | :: Returns the WebSocket connection close code provided by the server. 732 | : |event| . {{CloseEvent/reason}} 733 | :: Returns the WebSocket connection close reason provided by the server. 734 | 735 |
736 | 737 | The wasClean attribute must return the value it was initialized 738 | to. It represents whether the connection closed cleanly or not. 739 | 740 | The code attribute must return the value it was initialized 741 | to. It represents the WebSocket connection close code provided by the server. 742 | 743 | The reason attribute must return the value it was initialized 744 | to. It represents the WebSocket connection close reason provided by the server. 745 | 746 | 747 | 748 | # Garbage collection # {#garbage-collection} 749 | 750 | A {{WebSocket}} object whose [=WebSocket/ready state=] was set to {{WebSocket/CONNECTING}} (0) as 751 | of the last time the [=event loop=] reached step 1 must not be garbage 752 | collected if there are any event listeners registered for {{WebSocket/open}} events, 753 | {{WebSocket/message}} events, {{WebSocket/error}} events, or {{WebSocket/close}} events. 754 | 755 | A {{WebSocket}} object whose [=WebSocket/ready state=] was set to {{WebSocket/OPEN}} (1) as of the 756 | last time the [=event loop=] reached step 1 must not be garbage collected 757 | if there are any event listeners registered for {{WebSocket/message}} events, {{WebSocket/error}}, 758 | or {{WebSocket/close}} events. 759 | 760 | A {{WebSocket}} object whose [=WebSocket/ready state=] was set to {{WebSocket/CLOSING}} (2) as of 761 | the last time the [=event loop=] reached step 1 must not be garbage 762 | collected if there are any event listeners registered for {{WebSocket/error}} or {{WebSocket/close}} 763 | events. 764 | 765 | A {{WebSocket}} object with an established 766 | connection that has data queued to be transmitted to the network must not be garbage collected. 767 | [[!WSP]] 768 | 769 | If a {{WebSocket}} object is garbage collected while its connection is still open, the user agent 770 | must [=start the WebSocket closing handshake=], with no status code for the Close 771 | message. [[!WSP]] 772 | 773 |
774 | 775 | If a user agent is to make disappear a {{WebSocket}} object (this happens when a 776 | {{Document}} object goes away), the user agent must follow the first appropriate set of steps from 777 | the following list: 778 | 779 |
780 | 781 |
782 | 783 | : If the WebSocket connection is not yet [=established=] [[!WSP]] 784 | :: [=Fail the WebSocket connection=]. [[!WSP]] 785 | : If the WebSocket closing handshake has not yet been 786 | started [[!WSP]] 787 | :: [=Start the WebSocket closing handshake=], with the status code to use in the 788 | WebSocket Close message being 1001. [[!WSP]] 789 | : Otherwise 790 | :: Do nothing. 791 | 792 |
793 | 794 |
795 | 796 |

Acknowledgments

797 | 798 | Until the creation of this standard in 2021, the text here was maintained in the HTML Standard and Fetch Standard. Thanks to all of the contributors to those 801 | repositories who helped develop the specification, especially Ian Hickson and Anne van Kesteren as 802 | the respective original authors. 803 | 804 | Thanks to 805 | 平野裕 (Yutaka Hirano) 806 | for their contributions after the creation of the WebSockets Standard. 807 | 808 | This standard is written by Adam Rice (Google, ricea@chromium.org). 810 | -------------------------------------------------------------------------------- /review-drafts/2023-09.bs: -------------------------------------------------------------------------------- 1 |
  2 | Group: WHATWG
  3 | Status: RD
  4 | Date: 2023-09-18
  5 | H1: WebSockets
  6 | Shortname: websockets
  7 | Text Macro: TWITTER whatsockets
  8 | Text Macro: LATESTRD 2023-09
  9 | Abstract: This specification provides APIs to enable web applications to maintain bidirectional
 10 | Abstract: communications with server-side processes.
 11 | Translation: ja https://triple-underscore.github.io/WebSocket-ja.html
 12 | Indent: 1
 13 | Markup Shorthands: markdown yes
 14 | 
15 | 16 |
 17 | {
 18 |  "WSP": {
 19 |   "aliasOf": "RFC6455"
 20 |  },
 21 |  "HSTS": {
 22 |   "aliasOf": "RFC6797"
 23 |  }
 24 | }
 25 | 
26 | 27 | 40 | 41 |
 42 | spec:RFC6455; urlPrefix: https://datatracker.ietf.org/doc/html/rfc6455
 43 |  type: dfn
 44 |   text:the WebSocket connection is established; url:page-19:~:text=_The%20WebSocket%20Connection%20is%20Established_,-and
 45 |   text:extensions in use; url:page-19:~:text=_The%20WebSocket%20Connection%20is%20Established_,-and
 46 |   text:subprotocol in use; url:page-19:~:text=_Subprotocol%20In,Use_
 47 |   text:a WebSocket message has been received; url:page-66:~:text=_A%20WebSocket%20Message%20Has%20Been%20Received_
 48 |   text:send a WebSocket Message; url:page-66:~:text=needs%20to-,_Send%20a%20WebSocket%20Message_
 49 |   text:fail the WebSocket connection; url:section-7.1.7
 50 |   text:close the WebSocket connection; url:section-7.1.1
 51 |   text:start the WebSocket closing handshake; url:section-7.1.2
 52 |   text:the WebSocket closing handshake is started; url:section-7.1.3
 53 |   text:the WebSocket connection is closed; url:section-7.1.4
 54 |   text:the WebSocket connection close code; url:section-7.1.5
 55 |   text:the WebSocket connection close reason; url:section-7.1.6
 56 |   text:established; url:page-19:~:text=_The%20WebSocket%20Connection%20is%20Established_,-and
 57 |   text:ws; url:section-11.1.1
 58 |   text:wss; url:section-11.1.2
 59 |   text:cleanly; url:page-41:~:text=closed-,_cleanly_.
 60 |  type: http-header; text:Sec-WebSocket-Protocol; url:section-11.3.4
 61 | spec:html; type:dfn; urlPrefix: https://html.spec.whatwg.org/multipage/webappapis.html
 62 |  for:event loop; text:step 1; url:step1
 63 | 
64 | 65 | 66 | # Introduction # {#network-intro} 67 | 68 |
69 | 70 | This section is non-normative. 71 | 72 | To enable web applications to maintain bidirectional communications with server-side processes, 73 | this specification introduces the {{WebSocket}} interface. 74 | 75 |

This interface does not allow for raw access to the underlying network. For 76 | example, this interface could not be used to implement an IRC client without proxying messages 77 | through a custom server.

78 |
79 | 80 | 81 | # WebSocket protocol alterations # {#websocket-protocol} 82 | 83 |
84 | This section replaces part of the WebSocket protocol opening handshake client requirement to 85 | integrate it with algorithms defined in Fetch. This way CSP, cookies, HSTS, and other 86 | Fetch-related protocols are handled in a single location. Ideally the RFC would be 87 | updated with this language, but it is never that easy. The {{WebSocket}} API, defined below, uses 88 | this language. [[!WSP]] [[!FETCH]] 89 | 90 | The way this works is by replacing The WebSocket Protocol's "establish a WebSocket connection" 91 | algorithm with a new one that integrates with Fetch. "Establish a WebSocket 92 | connection" consists of three algorithms: setting up a connection, creating and transmiting a 93 | handshake request, and validating the handshake response. That layering is different from 94 | Fetch, which first creates a handshake, then sets up a connection and transmits the 95 | handshake, and finally validates the response. Keep that in mind while reading these alterations. 96 |
97 | 98 | 99 | ## Connections ## {#websocket-connections} 100 | 101 |
102 | 103 | To obtain a WebSocket connection, given a 104 | |url|, run these steps: 105 | 106 | 1. Let |host| be |url|'s host. 107 | 1. Let |port| be |url|'s port. 108 | 1. Let |resource name| be U+002F (/), followed by the strings in |url|'s path 109 | (including empty strings), if any, separated from each other by U+002F (/). 110 | 1. If |url|'s query is non-empty, append U+003F (?), followed by |url|'s 111 | query, to |resource name|. 112 | 1. Let |secure| be false, if |url|'s [=url/scheme=] is "`http`"; otherwise true. 113 | 1. Follow the requirements stated in step 2 to 5, inclusive, of the first set of steps in section 4.1 of The WebSocket 115 | Protocol to establish a WebSocket connection, passing 116 | |host|, |port|, |resource name| and |secure|. [[!WSP]] 117 | 1. If that established a connection, return it, and return failure otherwise. 118 | 119 |

Although structured a little differently, carrying different properties, and 120 | therefore not shareable, a WebSocket connection is very close to identical to an "ordinary" 121 | [=connection=]. 122 | 123 |

124 | 125 | 126 | ## Opening handshake ## {#websocket-opening-handshake} 127 | 128 |
129 | 130 | To establish a WebSocket connection, given a 131 | |url|, |protocols|, and |client|, run these steps: 132 | 133 | 1. Let |requestURL| be a copy of |url|, with its [=url/scheme=] set to "`http`", if |url|'s 134 | [=url/scheme=] is "`ws`"; otherwise to "`https`". 135 | 136 |

This change of scheme is essential to integrate well with 137 | fetching. E.g., HSTS would not work without it. There is no real 138 | reason for WebSocket to have distinct schemes, it's a legacy artefact. 139 | [[!HSTS]] 140 | 141 | 1. Let |request| be a new request, whose URL is |requestURL|, 142 | client is |client|, [=service-workers mode=] is "`none`", 143 | referrer is "`no-referrer`", mode is "`websocket`", 144 | credentials mode is "`include`", cache mode is "`no-store`" 145 | , and redirect mode is "`error`". 146 | 147 | 1. Append (\``Upgrade`\`, \``websocket`\`) to |request|'s 148 | header list. 149 | 1. Append (\``Connection`\`, \``Upgrade`\`) to |request|'s 150 | header list. 151 | 1. Let |keyValue| be a nonce consisting of a randomly selected 16-byte value that has been 152 | forgiving-base64-encoded and [=isomorphic encoded=]. 153 | 154 |

If the randomly selected value was the byte sequence 0x01 155 | 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10, |keyValue| would be 156 | forgiving-base64-encoded to "`AQIDBAUGBwgJCgsMDQ4PEC==`" and isomorphic encoded to 157 | \``AQIDBAUGBwgJCgsMDQ4PEC==`\`. 158 | 159 | 1. Append (\``Sec-WebSocket-Key`\`, |keyValue|) to |request|'s 160 | header list. 161 | 1. Append (\``Sec-WebSocket-Version`\`, \``13`\`) to |request|'s 162 | header list. 163 | 1. For each |protocol| in |protocols|, combine 164 | (\``Sec-WebSocket-Protocol`\`, |protocol|) in |request|'s header list. 165 | 166 | 1. Let |permessageDeflate| be a user-agent defined "`permessage-deflate`" extension 167 | header value. [[!WSP]] 168 | 169 |

\``permessage-deflate; client_max_window_bits`\` 170 | 171 | 1. Append (\``Sec-WebSocket-Extensions`\`, |permessageDeflate|) to 172 | |request|'s header list. 173 | 1. Fetch |request| with useParallelQueue set to true, 174 | and processResponse given |response| being these steps: 175 | 1. If |response| is a [=network error=] or its status is not 101, [=fail the 176 | WebSocket connection=]. 177 | 1. If |protocols| is not the empty list and [=extracting header list values=] given 178 | \``Sec-WebSocket-Protocol`\` and |response|'s header list 179 | results in null, failure, or the empty byte sequence, then [=fail the WebSocket connection=]. 180 | 181 |

This is different from the check on this header defined by The WebSocket Protocol. 182 | That only covers a subprotocol not requested by the client. This covers a subprotocol requested 183 | by the client, but not acknowledged by the server. 184 | 185 | 1. Follow the requirements stated step 2 to step 6, inclusive, of the last set of steps in 186 | section 4.1 of The WebSocket 187 | Protocol to validate |response|. This either results in [=fail the WebSocket connection=] 188 | or [=the WebSocket connection is established=]. 189 | 190 |

191 | 192 | [=Fail the WebSocket connection=] and [=the WebSocket connection is established=] are defined by The 193 | WebSocket Protocol. [[!WSP]] 194 | 195 |

The reason redirects are not followed and this handshake is generally restricted is 196 | because it could introduce serious security problems in a web browser context. For example, consider 197 | a host with a WebSocket server at one path and an open HTTP redirector at another. Suddenly, any 198 | script that can be given a particular WebSocket URL can be tricked into communicating to (and 199 | potentially sharing secrets with) any host on the internet, even if the script checks that the URL 200 | has the right hostname. 201 | 202 | 203 | 204 | # The {{WebSocket}} interface # {#the-websocket-interface} 205 | ## Interface definition ## {#interface-definition} 206 | 207 | The Web IDL definition for the {{WebSocket}} class is given as follows: 208 | 209 |

210 | enum BinaryType { "blob", "arraybuffer" }; 211 | 212 | [Exposed=(Window,Worker)] 213 | interface WebSocket : EventTarget { 214 | constructor(USVString url, optional (DOMString or sequence<DOMString>) protocols = []); 215 | readonly attribute USVString url; 216 | 217 | // ready state 218 | const unsigned short CONNECTING = 0; 219 | const unsigned short OPEN = 1; 220 | const unsigned short CLOSING = 2; 221 | const unsigned short CLOSED = 3; 222 | readonly attribute unsigned short readyState; 223 | readonly attribute unsigned long long bufferedAmount; 224 | 225 | // networking 226 | attribute EventHandler onopen; 227 | attribute EventHandler onerror; 228 | attribute EventHandler onclose; 229 | readonly attribute DOMString extensions; 230 | readonly attribute DOMString protocol; 231 | undefined close(optional [Clamp] unsigned short code, optional USVString reason); 232 | 233 | // messaging 234 | attribute EventHandler onmessage; 235 | attribute BinaryType binaryType; 236 | undefined send((BufferSource or Blob or USVString) data); 237 | }; 238 | 239 | 240 | Each {{WebSocket}} object has an associated url, which 241 | is a [=URL record=]. 242 | 243 | Each {{WebSocket}} object has an associated binary type, which is a 244 | {{BinaryType}}. Initially it must be "{{BinaryType/blob}}". 245 | 246 | Each {{WebSocket}} object has an associated ready state, which is a 247 | number representing the state of the connection. Initially it must be {{WebSocket/CONNECTING}} (0). 248 | It can have the following values: 249 | 250 | : CONNECTING (numeric value 0) 251 | :: The connection has not yet been established. 252 | : OPEN (numeric value 1) 253 | :: [=The WebSocket connection is established=] and communication is possible. 254 | : CLOSING (numeric value 2) 255 | :: The connection is going through the 256 | closing handshake, or the {{WebSocket/close()}} method has been invoked. 257 | : CLOSED (numeric value 3) 258 | :: The connection has been closed or could not be opened. 259 | 260 |
261 | : |socket| = new {{WebSocket/constructor(url, protocols)|WebSocket}}(|url| [, |protocols| ]) 262 | :: Creates a new {{WebSocket}} object, immediately establishing the associated WebSocket 263 | connection. 264 | 265 | |url| is a string giving the URL over which the connection is established. 266 | Only "`ws`", "`wss`", "`http`", and "`https`" schemes are allowed; others will cause a 267 | "{{SyntaxError}}" {{DOMException}}. URLs with [=fragments=] will always cause such an exception. 268 | 269 | |protocols| is either a string or an array of strings. If it is a string, it is equivalent to 270 | an array consisting of just that string; if it is omitted, it is equivalent to the empty array. 271 | Each string in the array is a subprotocol name. The connection will only be established if the 272 | server reports that it has selected one of these subprotocols. The subprotocol names have to 273 | match the requirements for elements that comprise the value of \``Sec-WebSocket-Protocol`\` fields as defined by The WebSocket protocol. 275 | [[!WSP]] 276 | 277 | : |socket|.send(|data|) 278 | :: Transmits |data| using the WebSocket connection. |data| can be a string, a {{Blob}}, an 279 | {{ArrayBuffer}}, or an {{ArrayBufferView}}. 280 | 281 | : |socket|.close([ |code| ] [, |reason| ]) 282 | :: Closes the WebSocket connection, optionally using |code| as [=the WebSocket connection 283 | close code=] and |reason| as [=the WebSocket connection close reason=]. 284 | 285 | : |socket|.url 286 | :: Returns the URL that was used to establish the WebSocket connection. 287 | 288 | : |socket|.readyState 289 | :: Returns the state of the WebSocket connection. It can have the values described above. 290 | 291 | : |socket|.bufferedAmount 292 | :: Returns the number of bytes of application data (UTF-8 text and binary data) that have been 293 | queued using {{WebSocket/send()}} but not yet been transmitted to the network. 294 | 295 | If the WebSocket connection is closed, this attribute's value will only increase with each call 296 | to the {{WebSocket/send()}} method. (The number does not reset to zero once the connection 297 | closes.) 298 | 299 | : |socket|.extensions 300 | :: Returns the extensions selected by the server, if any. 301 | 302 | : |socket|.protocol 303 | :: Returns the subprotocol selected by the server, if any. It can be used in conjunction with the 304 | array form of the constructor's second argument to perform subprotocol negotiation. 305 | 306 | : |socket|.binaryType 307 | :: Returns a string that indicates how binary data from |socket| is exposed to scripts: 308 | 309 | : "{{BinaryType/blob}}" 310 | :: Binary data is returned in {{Blob}} form. 311 | : "{{BinaryType/arraybuffer}}" 312 | :: Binary data is returned in {{ArrayBuffer}} form. 313 | 314 | The default is "{{BinaryType/blob}}". 315 | 316 | : |socket|.binaryType = value 317 | :: Changes how binary data is returned. 318 |
319 | 320 |
321 | The new 322 | WebSocket(|url|, |protocols|) 323 | constructor steps are: 324 | 325 | 1. Let |baseURL| be [=this=]'s [=relevant settings object=]'s [=API base URL=]. 326 | 1. Let |urlRecord| be the result of applying the [=URL parser=] to |url| with |baseURL|. 327 | 1. If |urlRecord| is failure, then throw a "{{SyntaxError}}" {{DOMException}}. 328 | 1. If |urlRecord|'s [=url/scheme=] is "`http`", then set |urlRecord|'s [=url/scheme=] to "`ws`". 329 | 1. Otherwise, if |urlRecord|'s [=url/scheme=] is "`https`", set |urlRecord|'s [=url/scheme=] to 330 | "`wss`". 331 | 1. If |urlRecord|'s [=scheme=] is not "[=ws=]" or "[=wss=]", then throw a 332 | "{{SyntaxError}}" {{DOMException}}. 333 | 1. If |urlRecord|'s [=fragment=] is non-null, then throw a "{{SyntaxError}}" {{DOMException}}. 334 | 1. If |protocols| is a string, set |protocols| to a sequence consisting of just that string. 335 | 1. If any of the values in |protocols| occur more than once or otherwise fail to match the 336 | requirements for elements that comprise the value of 337 | \``Sec-WebSocket-Protocol`\` fields as defined by The WebSocket protocol, 338 | then throw a "{{SyntaxError}}" {{DOMException}}. [[!WSP]] 339 | 1. Set [=this=]'s [=WebSocket/internal-url|url=] to |urlRecord|. 340 | 1. Let |client| be [=this=]'s [=relevant settings object=]. 341 | 1. Run this step [=in parallel=]: 342 | 1. [=Establish a WebSocket connection=] given |urlRecord|, |protocols|, and |client|. [[!FETCH]] 343 | 344 |

If the [=establish a WebSocket connection=] algorithm 345 | fails, it triggers the [=fail the WebSocket connection=] algorithm, which 346 | then invokes the [=close the WebSocket connection=] algorithm, which then 347 | establishes that [=the WebSocket connection is closed=], which fires the 348 | {{WebSocket/close}} event as described below. 349 |

350 | 351 |
352 | 353 | The url getter steps are to return [=this=]'s 354 | [=WebSocket/internal-url|url=], [=URL serializer|serialized=]. 355 | 356 | The readyState getter steps are to return [=this=]'s 357 | [=WebSocket/ready state=]. 358 | 359 | The extensions attribute must initially return the empty 360 | string. After [=the WebSocket connection is established=], its value might change, as defined 361 | below.

362 | 363 | The protocol attribute must initially return the empty 364 | string. After [=the WebSocket connection is established=], its value might change, as defined below. 365 | 366 |
367 | The close(|code|, |reason|) method steps are: 368 | 369 | 1. If |code| is present, but is neither an integer equal to 1000 nor an integer in the range 3000 370 | to 4999, inclusive, throw an "{{InvalidAccessError}}" {{DOMException}}. 371 | 1. If |reason| is present, then run these substeps: 372 | 1. Let |reasonBytes| be the result of encoding |reason|. 373 | 1. If |reasonBytes| is longer than 123 bytes, then throw a "{{SyntaxError}}" {{DOMException}}. 374 | 1. Run the first matching steps from the following list: 375 |
376 | : If [=this=]'s [=WebSocket/ready state=] is {{WebSocket/CLOSING}} (2) or {{WebSocket/CLOSED}} (3) 377 | :: Do nothing. 378 | 379 |

The connection is already closing or is already closed. If it has not already, a 380 | {{WebSocket/close}} event will eventually fire as described below. 381 | 382 | : If the WebSocket connection is not yet [=established=] [[!WSP]] 383 | :: [=Fail the WebSocket connection=] and set [=this=]'s [=WebSocket/ready state=] to 384 | {{WebSocket/CLOSING}} (2). [[!WSP]] 385 | 386 |

The [=fail the WebSocket connection=] algorithm invokes the [=close the 387 | WebSocket connection=] algorithm, which then establishes that [=the WebSocket connection is 388 | closed=], which fires the {{WebSocket/close}} event as described 389 | below. 390 | 391 | : If the WebSocket closing handshake has not yet been started [[!WSP]] 393 | :: [=Start the WebSocket closing handshake=] and set [=this=]'s [=WebSocket/ready state=] to 394 | {{WebSocket/CLOSING}} (2). [[!WSP]] 395 | 396 | If neither |code| nor |reason| is present, the WebSocket Close message must not have a body. 397 | 398 |

The WebSocket Protocol erroneously states that the status code is required for the [=start the WebSocket closing handshake=] algorithm. 400 | 401 | 402 | If |code| is present, then the status code to use in the WebSocket Close 403 | message must be the integer given by |code|. [[!WSP]] 404 | 405 | If |reason| is also present, then |reasonBytes| must be provided in the Close message after the 406 | status code. [[!WSP]] 407 | 408 |

The [=start the WebSocket closing handshake=] algorithm eventually invokes the 409 | [=close the WebSocket connection=] algorithm, which then establishes that [=the WebSocket 410 | connection is closed=], which fires the {{WebSocket/close}} event as 411 | described below. 412 | 413 | : Otherwise 414 | :: Set [=this=]'s [=WebSocket/ready state=] to {{WebSocket/CLOSING}} (2). 415 | 416 |

[=The WebSocket closing handshake is started=], and will eventually invoke the 417 | [=close the WebSocket connection=] algorithm, which will establish that [=the WebSocket 418 | connection is closed=], and thus the {{WebSocket/close}} event will fire, as described below. 420 |

421 |
422 | 423 |

The {{WebSocket/close()}} method does not discard previously sent messages before 424 | starting the WebSocket closing handshake — even if, in practice, the user agent is still busy 425 | sending those messages, the handshake will only start after the messages are sent. 428 | 429 |


430 | 431 | The bufferedAmount getter steps are to return the number of bytes 432 | of application data (UTF-8 text and binary data) that have been queued using {{WebSocket/send()}} 433 | but that, as of the last time the [=event loop=] reached step 1, had not yet 434 | been transmitted to the network. (This thus includes any text sent during the execution of the 435 | current task, regardless of whether the user agent is able to transmit text in the background [=in 436 | parallel=] with script execution.) This does not include framing overhead incurred by the protocol, 437 | or buffering done by the operating system or network hardware. 438 | 439 |
440 | 441 | In this simple example, the {{WebSocket/bufferedAmount}} attribute is used to ensure that updates 442 | are sent either at the rate of one update every 50ms, if the network can handle that rate, or at 443 | whatever rate the network can handle, if that is too fast. 444 | 445 | 446 | var socket = new WebSocket('ws://game.example.com:12010/updates'); 447 | socket.onopen = function () { 448 | setInterval(function() { 449 | if (socket.bufferedAmount == 0) 450 | socket.send(getUpdateData()); 451 | }, 50); 452 | }; 453 | 454 | 455 | The {{WebSocket/bufferedAmount}} attribute can also be used to saturate the network without sending 456 | the data at a higher rate than the network can handle, though this requires more careful monitoring 457 | of the value of the attribute over time. 458 | 459 |
460 | 461 |
462 | 463 | The binaryType getter steps are to return [=this=]'s 464 | [=WebSocket/binary type=]. 465 | 466 | The {{WebSocket/binaryType}} setter steps are to set [=this=]'s [=WebSocket/binary type=] to 467 | [=the given value=]. 468 | 469 |

User agents can use the [=WebSocket/binary type=] as a hint for how to handle 470 | incoming binary data: if it is "{{BinaryType/blob}}", it is safe to spool it to disk, and if it is 471 | "{{BinaryType/arraybuffer}}", it is likely more efficient to keep the data in memory. Naturally, 472 | user agents are encouraged to use more subtle heuristics to decide whether to keep incoming data in 473 | memory or not, e.g. based on how big the data is or how common it is for a script to change the 474 | attribute at the last minute. This latter aspect is important in particular because it is quite 475 | possible for the attribute to be changed after the user agent has received the data but before the 476 | user agent has fired the event for it. 477 | 478 |

479 | The send(|data|) method steps are: 480 | 481 | 1. If [=this=]'s [=WebSocket/ready state=] is {{WebSocket/CONNECTING}}, then throw an 482 | "{{InvalidStateError}}" {{DOMException}}. 483 | 484 | 2. Run the appropriate set of steps from the following list: 485 | 486 | : If |data| is a string 487 | :: If [=the WebSocket connection is established=] and the WebSocket closing handshake has not yet started, then the user agent must 489 | [=send a WebSocket Message=] comprised of the |data| argument using a text frame opcode; if 490 | the data cannot be sent, e.g. because it would need to be buffered but the buffer is full, 491 | the user agent must flag the WebSocket as full and then [=close 492 | the WebSocket connection=]. Any invocation of this method with a string argument that does 493 | not throw an exception must increase the {{WebSocket/bufferedAmount}} attribute by the 494 | number of bytes needed to express the argument as UTF-8. [[!UNICODE]] [[!ENCODING]] [[!WSP]] 495 | 496 | 497 | : If |data| is a {{Blob}} object 498 | :: If [=the WebSocket connection is established=], and the WebSocket closing handshake has not yet started, then the user agent 500 | must [=send a WebSocket Message=] comprised of |data| using a binary frame opcode; if the 501 | data cannot be sent, e.g. because it would need to be buffered but the buffer is full, the 502 | user agent must flag the WebSocket as full and then [=close the 503 | WebSocket connection=]. The data to be sent is the raw data represented by the {{Blob}} 504 | object. 505 | 506 | Any invocation of this method with a {{Blob}} argument that does not throw an exception must 507 | increase the {{WebSocket/bufferedAmount}} attribute by the size of the {{Blob}} object's raw 508 | data, in bytes. 509 | 510 | [[!WSP]] [[!FILEAPI]] 511 | 512 | : If |data| is an {{ArrayBuffer}} 513 | :: If [=the WebSocket connection is established=], and the WebSocket closing handshake has not yet started, then the user agent 515 | must [=send a WebSocket Message=] comprised of |data| using a binary frame opcode; if the 516 | data cannot be sent, e.g. because it would need to be buffered but the buffer is full, the 517 | user agent must flag the WebSocket as full and then [=close the 518 | WebSocket connection=]. The data to be sent is the data stored in the buffer described by 519 | the {{ArrayBuffer}} object. Any invocation of this method with an {{ArrayBuffer}} argument 520 | that does not throw an exception must increase the {{WebSocket/bufferedAmount}} attribute by 521 | the length of the {{ArrayBuffer}} in bytes. [[!WSP]] 522 | 523 | : If |data| is an {{ArrayBufferView}} 524 | :: If [=the WebSocket connection is established=], and the WebSocket closing handshake has not yet started, then the user agent 526 | must [=send a WebSocket Message=] comprised of |data| using a binary frame opcode; if the 527 | data cannot be sent, e.g. because it would need to be buffered but the buffer is full, the 528 | user agent must flag the WebSocket as full and then [=close the 529 | WebSocket connection=]. The data to be sent is the data stored in the section of the buffer 530 | described by the {{ArrayBuffer}} object that |data| references. Any invocation of this 531 | method with this kind of argument that does not throw an exception must increase the 532 | {{WebSocket/bufferedAmount}} attribute by the length of |data|'s buffer in bytes. [[!WSP]] 533 |
534 | 535 |
536 | 537 | The following are the [=event handlers=] (and their corresponding [=event handler event types=]) 538 | that must be supported, as [=event handler IDL attributes=], by all objects implementing the 539 | {{WebSocket}} interface: 540 | 541 | 542 | 543 | 545 |
[=Event handler=] [=Event handler event type=] 544 |
onopen {{WebSocket/open}} 546 |
onmessage {{WebSocket/message}} 547 |
onerror {{WebSocket/error}} 548 |
onclose {{WebSocket/close}} 549 |
550 | 551 | 552 | # Feedback from the protocol # {#feedback-from-the-protocol} 553 | 554 | When [=the WebSocket connection is established=], the user agent must [=queue a task=] to run these 555 | steps: 556 | 557 |
558 | 559 | 1. Change the [=WebSocket/ready state=] to {{WebSocket/OPEN}} (1). 560 | 1. Change the {{WebSocket/extensions}} attribute's value to the [=extensions in 561 | use=], if it is not the null value. [[!WSP]] 562 | 1. Change the {{WebSocket/protocol}} attribute's value to the [=subprotocol in 563 | use=], if it is not the null value. [[!WSP]] 564 | 1. [=Fire an event=] named open at the {{WebSocket}} object. 565 | 566 |

Since the algorithm above is queued as a task, there is no 567 | race condition between the WebSocket connection 568 | being established and the script setting up an event listener for the {{WebSocket/open}} 569 | event. 570 | 571 |

572 | 573 |
574 | 575 |
576 | 577 | When [=a WebSocket message has been received=] with type |type| and data |data|, the user agent must 578 | [=queue a task=] to follow these steps: [[!WSP]] 579 | 580 | 1. If [=WebSocket/ready state=] is not {{WebSocket/OPEN}} (1), then return. 581 | 1. Let |dataForEvent| be determined by switching on |type| and [=WebSocket/binary type=]: 582 | 583 |
584 | : |type| indicates that the data is Text 585 | :: a new {{DOMString}} containing |data| 586 | 587 | : |type| indicates that the data is Binary and [=WebSocket/binary type=] is 588 | "blob" 589 | :: a new {{Blob}} object, created in the [=relevant Realm=] of the {{WebSocket}} object, that 590 | represents |data| as its raw data [[!FILEAPI]] 591 | 592 | : |type| indicates that the data is Binary and [=WebSocket/binary type=] is 593 | "arraybuffer" 594 | :: a new {{ArrayBuffer}} object, created in the [=relevant Realm=] of the {{WebSocket}} object, 595 | whose contents are |data| 596 |
597 | 598 | 1. [=Fire an event=] named message at the {{WebSocket}} object, 599 | using {{MessageEvent}}, with the {{MessageEvent/origin}} attribute initialized to the serialization of the {{WebSocket}} object's [=url=]'s [=origin=], and the 601 | {{MessageEvent/data}} attribute initialized to |dataForEvent|. 602 | 603 |

User agents are encouraged to check if they can perform the above steps efficiently 604 | before they run the task, picking tasks from other [=task queues=] while they prepare the buffers 605 | if not. For example, if the [=WebSocket/binary type=] is "{{BinaryType/blob}}" when the data 606 | arrived, and the user agent spooled all the data to disk, but just before running the above 607 | [=task=] for this particular message the script switched [=WebSocket/binary type=] to 608 | "{{BinaryType/arraybuffer}}", the user agent would want to page the data back to RAM before running 609 | this [=task=] so as to avoid stalling the main thread while it created the {{ArrayBuffer}} object. 610 | 611 |

612 | 613 |
614 | 615 | Here is an example of how to define a handler for the {{WebSocket/message}} event in the case of 616 | text frames: 617 | 618 | 619 | mysocket.onmessage = function (event) { 620 | if (event.data == 'on') { 621 | turnLampOn(); 622 | } else if (event.data == 'off') { 623 | turnLampOff(); 624 | } 625 | }; 626 | 627 | 628 | The protocol here is a trivial one, with the server just sending "on" or "off" messages. 629 | 630 |
631 | 632 |
633 | 634 | When [=the WebSocket closing handshake is started=], the user agent must [=queue a task=] to change 635 | the [=WebSocket/ready state=] to {{WebSocket/CLOSING}} (2). (If the {{WebSocket/close()}} method 636 | was called, the [=WebSocket/ready state=] will already be set to {{WebSocket/CLOSING}} (2) when 637 | this task runs.) [[!WSP]] 638 | 639 |
640 | 641 |

When [=the WebSocket connection is closed=], possibly [=cleanly=], the user 642 | agent must [=queue a task=] to run the following substeps: 643 | 644 |

645 | 1. Change the [=WebSocket/ready state=] to {{WebSocket/CLOSED}} (3). 646 | 1. If the user agent was required to [=fail the WebSocket connection=], or if the WebSocket connection was closed after being flagged 648 | as full, [=fire an event=] named error at the 649 | {{WebSocket}} object. [[!WSP]] 650 | 1. [=Fire an event=] named close at the {{WebSocket}} object, 651 | using {{CloseEvent}}, with the {{CloseEvent/wasClean}} attribute initialized to true if the 652 | connection closed [=cleanly=] and false otherwise, the {{CloseEvent/code}} attribute initialized 653 | to [=the WebSocket connection close code=], and the {{CloseEvent/reason}} attribute initialized 654 | to the result of applying [=UTF-8 decode without BOM=] to [=the WebSocket connection close 655 | reason=]. [[!WSP]] 656 |
657 | 658 |
659 | 660 | User agents must not convey any failure information to scripts in a way that would allow a 661 | script to distinguish the following situations: 662 | 663 | * A server whose host name could not be resolved. 664 | * A server to which packets could not successfully be routed. 665 | * A server that refused the connection on the specified port. 666 | * A server that failed to correctly perform a TLS handshake (e.g., the server certificate can't be 667 | verified). 668 | * A server that did not complete the opening handshake (e.g. because it was not a WebSocket 669 | server). 670 | * A WebSocket server that sent a correct opening handshake, but that specified options that caused 671 | the client to drop the connection (e.g. the server specified a subprotocol that the client did 672 | not offer). 673 | * A WebSocket server that abruptly closed the connection after successfully completing the 674 | opening handshake. 675 | 676 | In all of these cases, [=the WebSocket connection close code=] would be 1006, as required by 677 | WebSocket Protocol. [[!WSP]] 678 | 679 | Allowing a script to distinguish these cases would allow a script to probe the user's local network 680 | in preparation for an attack. 681 | 682 |

In particular, this means the code 1015 is not used by the user agent (unless the 683 | server erroneously uses it in its close frame, of course). 684 | 685 |

686 | 687 |
688 | 689 | The [=task source=] for all [=tasks=] queued in this section is the 690 | WebSocket task source. 691 | 692 | 693 | # Ping and Pong frames # {#ping-and-pong-frames} 694 | 695 | The WebSocket protocol defines Ping and Pong frames that can be used for keep-alive, 696 | heart-beats, network status probing, latency instrumentation, and so forth. These are not currently 697 | exposed in the API. 698 | 699 | User agents may send ping and unsolicited pong frames as desired, for example in an attempt to 700 | maintain local network NAT mappings, to detect failed connections, or to display latency metrics to 701 | the user. User agents must not use pings or unsolicited pongs to aid the server; it is assumed that 702 | servers will solicit pongs whenever appropriate for the server's needs. 703 | 704 | 707 | 708 | 709 | # The {{CloseEvent}} interface # {#the-closeevent-interface} 710 | 711 | {{WebSocket}} objects use the {{CloseEvent}} interface for their {{WebSocket/close}} events: 712 | 713 | 714 | [Exposed=(Window,Worker)] 715 | interface CloseEvent : Event { 716 | constructor(DOMString type, optional CloseEventInit eventInitDict = {}); 717 | 718 | readonly attribute boolean wasClean; 719 | readonly attribute unsigned short code; 720 | readonly attribute USVString reason; 721 | }; 722 | 723 | dictionary CloseEventInit : EventInit { 724 | boolean wasClean = false; 725 | unsigned short code = 0; 726 | USVString reason = ""; 727 | }; 728 | 729 | 730 |
731 | 732 | : |event| . {{CloseEvent/wasClean}} 733 | :: Returns true if the connection closed cleanly; false otherwise. 734 | : |event| . {{CloseEvent/code}} 735 | :: Returns the WebSocket connection close code provided by the server. 736 | : |event| . {{CloseEvent/reason}} 737 | :: Returns the WebSocket connection close reason provided by the server. 738 | 739 |
740 | 741 | The wasClean attribute must return the value it was initialized 742 | to. It represents whether the connection closed cleanly or not. 743 | 744 | The code attribute must return the value it was initialized 745 | to. It represents the WebSocket connection close code provided by the server. 746 | 747 | The reason attribute must return the value it was initialized 748 | to. It represents the WebSocket connection close reason provided by the server. 749 | 750 | 751 | 752 | # Garbage collection # {#garbage-collection} 753 | 754 | A {{WebSocket}} object whose [=WebSocket/ready state=] was set to {{WebSocket/CONNECTING}} (0) as 755 | of the last time the [=event loop=] reached step 1 must not be garbage 756 | collected if there are any event listeners registered for {{WebSocket/open}} events, 757 | {{WebSocket/message}} events, {{WebSocket/error}} events, or {{WebSocket/close}} events. 758 | 759 | A {{WebSocket}} object whose [=WebSocket/ready state=] was set to {{WebSocket/OPEN}} (1) as of the 760 | last time the [=event loop=] reached step 1 must not be garbage collected 761 | if there are any event listeners registered for {{WebSocket/message}} events, {{WebSocket/error}}, 762 | or {{WebSocket/close}} events. 763 | 764 | A {{WebSocket}} object whose [=WebSocket/ready state=] was set to {{WebSocket/CLOSING}} (2) as of 765 | the last time the [=event loop=] reached step 1 must not be garbage 766 | collected if there are any event listeners registered for {{WebSocket/error}} or {{WebSocket/close}} 767 | events. 768 | 769 | A {{WebSocket}} object with an established 770 | connection that has data queued to be transmitted to the network must not be garbage collected. 771 | [[!WSP]] 772 | 773 | If a {{WebSocket}} object is garbage collected while its connection is still open, the user agent 774 | must [=start the WebSocket closing handshake=], with no status code for the Close 775 | message. [[!WSP]] 776 | 777 |
778 | 779 | If a user agent is to make disappear a {{WebSocket}} object (this happens when a 780 | {{Document}} object goes away), the user agent must follow the first appropriate set of steps from 781 | the following list: 782 | 783 |
784 | 785 |
786 | 787 | : If the WebSocket connection is not yet [=established=] [[!WSP]] 788 | :: [=Fail the WebSocket connection=]. [[!WSP]] 789 | : If the WebSocket closing handshake has not yet been 790 | started [[!WSP]] 791 | :: [=Start the WebSocket closing handshake=], with the status code to use in the 792 | WebSocket Close message being 1001. [[!WSP]] 793 | : Otherwise 794 | :: Do nothing. 795 | 796 |
797 | 798 |
799 | 800 |

Acknowledgments

801 | 802 | Until the creation of this standard in 2021, the text here was maintained in the HTML Standard and Fetch Standard. Thanks to all of the contributors to those 805 | repositories who helped develop the specification, especially Ian Hickson and Anne van Kesteren as 806 | the respective original authors. 807 | 808 | Thanks to 809 | devsnek and 810 | 平野裕 (Yutaka Hirano) 811 | for their contributions after the creation of the WebSockets Standard. 812 | 813 | This standard is written by Adam Rice (Google, ricea@chromium.org). 815 | --------------------------------------------------------------------------------