Skip to content

Commit

Permalink
WebSockets client: Add test and fix issues. (#109)
Browse files Browse the repository at this point in the history
* Adds a test that uses a publicly available echo endpoint.
* Didn't correctly buffer data received in the same packet as the
headers.
* Wrongly sent two Host: headers.
  • Loading branch information
Erik Corry authored Jul 26, 2023
1 parent 6a227f4 commit 1e9de1e
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 6 deletions.
3 changes: 1 addition & 2 deletions src/client.toit
Original file line number Diff line number Diff line change
Expand Up @@ -346,10 +346,9 @@ class Client:
headers = headers ? headers.copy : Headers
MAX_REDIRECTS.repeat:
nonce := WebSocket.add_client_upgrade_headers_ headers
headers.add "Host" parsed.host_with_port
response/Response? := null
try_to_reuse_ parsed: | connection |
request := connection.new_request GET parsed.path headers
request/RequestOutgoing := connection.new_request GET parsed.path headers
response = request.send
if follow_redirects and
(is_regular_redirect_ response.status_code
Expand Down
6 changes: 3 additions & 3 deletions src/connection.toit
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ class Connection:
else:
// Return a writer that doesn't accept any data.
body_writer = ContentLengthWriter this writer_ 0
if not headers.matches "Connection" "upgrade":
if not headers.matches "Connection" "Upgrade":
headers.set "Content-Length" "0"

// Set this before doing blocking operations on the socket, so that we
Expand Down Expand Up @@ -323,8 +323,8 @@ A $tcp.Socket doesn't support ungetting data that was already read for it, so we
*/
class DetachedSocket_ implements tcp.Socket:
socket_/tcp.Socket
buffered_/ByteArray? := null
constructor .socket_ buffered_:
buffered_/ByteArray? := ?
constructor .socket_ .buffered_:

local_address -> net.SocketAddress:
return socket_.local_address
Expand Down
2 changes: 1 addition & 1 deletion src/web_socket.toit
Original file line number Diff line number Diff line change
Expand Up @@ -245,10 +245,10 @@ class WebSocket:
// The WebSocket nonce is not very important and does not need to be
// cryptographically random.
nonce := base64.encode (ByteArray 16: random 0x100)
headers.add "Connection" "Upgrade"
headers.add "Upgrade" "websocket"
headers.add "Sec-WebSocket-Key" nonce
headers.add "Sec-WebSocket-Version" "13"
headers.add "Connection" "Upgrade"
return nonce

static check_client_upgrade_response_ response/Response nonce/string -> none:
Expand Down
28 changes: 28 additions & 0 deletions tests/websocket_client_test.toit
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (C) 2023 Toitware ApS.
// Use of this source code is governed by a Zero-Clause BSD license that can
// be found in the tests/TESTS_LICENSE file.
import certificate_roots
import expect show *
import http
import net

URI ::= "wss://echo.websocket.events/"
// This header is required by the WebSocket endpoint.
ORIGIN ::= { "Origin": "http://echo.websocket.events" }
MSG1 ::= "Hello, from Toit!"
MSG2 ::= #[0xff, 0x00, 103]

main:
network := net.open
client := http.Client network --root_certificates=[certificate_roots.ISRG_ROOT_X1]
web_socket := client.web_socket --uri=URI --headers=(http.Headers.from_map ORIGIN)
greeting := web_socket.receive
expect_equals "echo.websocket.events sponsored by Lob.com" greeting
print greeting
web_socket.send MSG1
echo := web_socket.receive
expect_equals MSG1 echo
web_socket.send MSG2
echo_bytes := web_socket.receive
expect_equals MSG2 echo_bytes

0 comments on commit 1e9de1e

Please sign in to comment.