diff --git a/lib/handshake.c b/lib/handshake.c index f8146c75..206156c1 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -70,6 +70,31 @@ interpret_key(const char *key, unsigned long *result) return 0; } +/* + * -04 of the protocol (actually the 80th version) has a radically different + * handshake. The 04 spec gives the following idea + * + * The handshake from the client looks as follows: + * + * GET /chat HTTP/1.1 + * Host: server.example.com + * Upgrade: websocket + * Connection: Upgrade + * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== + * Sec-WebSocket-Origin: http://example.com + * Sec-WebSocket-Protocol: chat, superchat + * Sec-WebSocket-Version: 4 + * + * The handshake from the server looks as follows: + * + * HTTP/1.1 101 Switching Protocols + * Upgrade: websocket + * Connection: Upgrade + * Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo= + * Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC== + * Sec-WebSocket-Protocol: chat + */ + /* * We have to take care about parsing because the headers may be split * into multiple fragments. They may contain unknown headers with arbitrary diff --git a/lib/parsers.c b/lib/parsers.c index 42f821ab..64725828 100644 --- a/lib/parsers.c +++ b/lib/parsers.c @@ -32,6 +32,10 @@ const struct lws_tokens lws_tokens[WSI_TOKEN_COUNT] = { [WSI_TOKEN_ORIGIN] = { "Origin:", 7 }, [WSI_TOKEN_DRAFT] = { "Sec-WebSocket-Draft:", 20 }, [WSI_TOKEN_CHALLENGE] = { "\x0d\x0a", 2 }, + + [WSI_TOKEN_KEY] = { "Sec-WebSocket-Key:", 18 }, + [WSI_TOKEN_VERSION] = { "Sec-WebSocket-Version:", 22 }, + }; int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c) @@ -49,7 +53,8 @@ int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c) case WSI_TOKEN_ORIGIN: case WSI_TOKEN_DRAFT: case WSI_TOKEN_CHALLENGE: - + case WSI_TOKEN_KEY: + case WSI_TOKEN_VERSION: debug("WSI_TOKEN_(%d) '%c'\n", wsi->parser_state, c); /* collect into malloc'd buffers */ @@ -93,14 +98,26 @@ int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c) wsi->utf8_token[wsi->parser_state].token[ wsi->utf8_token[wsi->parser_state].token_len++] = c; - /* special payload limiting */ - if (wsi->parser_state == WSI_TOKEN_CHALLENGE && - wsi->utf8_token[wsi->parser_state].token_len == 8) { - debug("Setting WSI_PARSING_COMPLETE\n"); - wsi->parser_state = WSI_PARSING_COMPLETE; - break; - } + /* per-protocol end of headers management */ + if (wsi->parser_state != WSI_TOKEN_CHALLENGE) + break; + + /* -76 has no version header */ + if (!wsi->utf8_token[WSI_TOKEN_VERSION].token_len && + wsi->utf8_token[wsi->parser_state].token_len != 8) + break; + + /* <= 03 has old handshake with version header */ + if (wsi->utf8_token[WSI_TOKEN_VERSION].token_len && + atoi(wsi->utf8_token[WSI_TOKEN_VERSION].token) < 4 && + wsi->utf8_token[wsi->parser_state].token_len != 8) + break; + + /* For any supported protocol we have enough payload */ + + debug("Setting WSI_PARSING_COMPLETE\n"); + wsi->parser_state = WSI_PARSING_COMPLETE; break; /* collecting and checking a name part */ diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 27694c0c..2d02cc2c 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -92,6 +92,10 @@ enum lws_token_indexes { WSI_TOKEN_DRAFT, WSI_TOKEN_CHALLENGE, + /* new for 04 */ + WSI_TOKEN_KEY, + WSI_TOKEN_VERSION, + /* always last real token index*/ WSI_TOKEN_COUNT, /* parser state additions */