mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
introduce 76 00 client support
This adds 76/00 client support to libwebsockets. It's still shipped by browsers and more importantly still the only version supported by server stuff like socket.io. Signed-off-by: Andy Green <andy@warmcat.com>
This commit is contained in:
parent
a54986f36e
commit
eeaacb39c7
4 changed files with 229 additions and 9 deletions
|
@ -99,6 +99,8 @@ libwebsocket_client_connect(struct libwebsocket_context *this,
|
|||
wsi->xor_mask = xor_no_mask;
|
||||
|
||||
switch (wsi->ietf_spec_revision) {
|
||||
case 0:
|
||||
break;
|
||||
case 4:
|
||||
wsi->xor_mask = xor_mask_04;
|
||||
break;
|
||||
|
|
|
@ -304,6 +304,47 @@ libwebsockets_get_peer_addresses(int fd, char *name, int name_len,
|
|||
}
|
||||
}
|
||||
|
||||
void libwebsockets_00_spaceout(char *key, int spaces, int seed)
|
||||
{
|
||||
char *p;
|
||||
|
||||
key++;
|
||||
while (spaces--) {
|
||||
if (*key && (seed & 1))
|
||||
key++;
|
||||
seed >>= 1;
|
||||
|
||||
p = key + strlen(key);
|
||||
while (p >= key) {
|
||||
p[1] = p[0];
|
||||
p--;
|
||||
}
|
||||
*key++ = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
void libwebsockets_00_spam(char *key, int count, int seed)
|
||||
{
|
||||
char *p;
|
||||
|
||||
key++;
|
||||
while (count--) {
|
||||
|
||||
if (*key && (seed & 1))
|
||||
key++;
|
||||
seed >>= 1;
|
||||
|
||||
p = key + strlen(key);
|
||||
while (p >= key) {
|
||||
p[1] = p[0];
|
||||
p--;
|
||||
}
|
||||
*key++ = 0x21 + ((seed & 0xffff) % 15);
|
||||
/* 4 would use it up too fast.. not like it matters */
|
||||
seed >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* libwebsocket_service_fd() - Service polled socket with something waiting
|
||||
* @this: Websocket context
|
||||
|
@ -760,6 +801,19 @@ libwebsocket_service_fd(struct libwebsocket_context *this,
|
|||
sizeof wsi->key_b64);
|
||||
|
||||
/*
|
||||
* 00 example client handshake
|
||||
*
|
||||
* GET /socket.io/websocket HTTP/1.1
|
||||
* Upgrade: WebSocket
|
||||
* Connection: Upgrade
|
||||
* Host: 127.0.0.1:9999
|
||||
* Origin: http://127.0.0.1
|
||||
* Sec-WebSocket-Key1: 1 0 2#0W 9 89 7 92 ^
|
||||
* Sec-WebSocket-Key2: 7 7Y 4328 B2v[8(z1
|
||||
* Cookie: socketio=websocket
|
||||
*
|
||||
* (Á®Ä0¶†≥
|
||||
*
|
||||
* 04 example client handshake
|
||||
*
|
||||
* GET /chat HTTP/1.1
|
||||
|
@ -773,6 +827,93 @@ libwebsocket_service_fd(struct libwebsocket_context *this,
|
|||
*/
|
||||
|
||||
p += sprintf(p, "GET %s HTTP/1.1\x0d\x0a", wsi->c_path);
|
||||
|
||||
if (wsi->ietf_spec_revision == 0) {
|
||||
unsigned char spaces_1, spaces_2;
|
||||
unsigned int max_1, max_2;
|
||||
unsigned int num_1, num_2;
|
||||
unsigned long product_1, product_2;
|
||||
char key_1[40];
|
||||
char key_2[40];
|
||||
unsigned int seed;
|
||||
unsigned int count;
|
||||
char challenge[16];
|
||||
|
||||
read(this->fd_random, &spaces_1, sizeof(char));
|
||||
read(this->fd_random, &spaces_2, sizeof(char));
|
||||
|
||||
spaces_1 = (spaces_1 % 12) + 1;
|
||||
spaces_2 = (spaces_2 % 12) + 1;
|
||||
|
||||
max_1 = 4294967295 / spaces_1;
|
||||
max_2 = 4294967295 / spaces_2;
|
||||
|
||||
read(this->fd_random, &num_1, sizeof(int));
|
||||
read(this->fd_random, &num_2, sizeof(int));
|
||||
|
||||
num_1 = (num_1 % max_1);
|
||||
num_2 = (num_2 % max_2);
|
||||
|
||||
challenge[0] = num_1 >> 24;
|
||||
challenge[1] = num_1 >> 16;
|
||||
challenge[2] = num_1 >> 8;
|
||||
challenge[3] = num_1;
|
||||
challenge[4] = num_2 >> 24;
|
||||
challenge[5] = num_2 >> 16;
|
||||
challenge[6] = num_2 >> 8;
|
||||
challenge[7] = num_2;
|
||||
|
||||
product_1 = num_1 * spaces_1;
|
||||
product_2 = num_2 * spaces_2;
|
||||
|
||||
sprintf(key_1, "%lu", product_1);
|
||||
sprintf(key_2, "%lu", product_2);
|
||||
|
||||
read(this->fd_random, &seed, sizeof(int));
|
||||
read(this->fd_random, &count, sizeof(int));
|
||||
|
||||
libwebsockets_00_spam(key_1, (count % 12) + 1, seed);
|
||||
|
||||
read(this->fd_random, &seed, sizeof(int));
|
||||
read(this->fd_random, &count, sizeof(int));
|
||||
|
||||
libwebsockets_00_spam(key_2, (count % 12) + 1, seed);
|
||||
|
||||
read(this->fd_random, &seed, sizeof(int));
|
||||
|
||||
libwebsockets_00_spaceout(key_1, spaces_1, seed);
|
||||
libwebsockets_00_spaceout(key_2, spaces_2, seed >> 16);
|
||||
|
||||
p += sprintf(p, "Upgrade: websocket\x0d\x0a"
|
||||
"Connection: Upgrade\x0d\x0aHost: %s\x0d\x0a",
|
||||
wsi->c_host);
|
||||
if (wsi->c_origin)
|
||||
p += sprintf(p, "Origin: %s\x0d\x0a",
|
||||
wsi->c_origin);
|
||||
|
||||
if (wsi->c_protocol)
|
||||
p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a",
|
||||
wsi->c_protocol);
|
||||
|
||||
p += sprintf(p, "Sec-WebSocket-Key1: %s\x0d\x0a",
|
||||
key_1);
|
||||
p += sprintf(p, "Sec-WebSocket-Key2: %s\x0d\x0a",
|
||||
key_2);
|
||||
|
||||
p += sprintf(p, "\x0d\x0a");
|
||||
|
||||
read(this->fd_random, p, 8);
|
||||
memcpy(&challenge[8], p, 8);
|
||||
p += 8;
|
||||
|
||||
/* precompute what we want to see from the server */
|
||||
|
||||
MD5((unsigned char *)challenge, 16,
|
||||
(unsigned char *)wsi->initial_handshake_hash_base64);
|
||||
|
||||
goto issue_hdr;
|
||||
}
|
||||
|
||||
p += sprintf(p, "Host: %s\x0d\x0a", wsi->c_host);
|
||||
p += sprintf(p, "Upgrade: websocket\x0d\x0a");
|
||||
p += sprintf(p, "Connection: Upgrade\x0d\x0a"
|
||||
|
@ -789,13 +930,6 @@ libwebsocket_service_fd(struct libwebsocket_context *this,
|
|||
p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a\x0d\x0a",
|
||||
wsi->ietf_spec_revision);
|
||||
|
||||
/* done with these now */
|
||||
|
||||
free(wsi->c_path);
|
||||
free(wsi->c_host);
|
||||
if (wsi->c_origin)
|
||||
free(wsi->c_origin);
|
||||
|
||||
/* prepare the expected server accept response */
|
||||
|
||||
strcpy((char *)buf, wsi->key_b64);
|
||||
|
@ -806,6 +940,15 @@ libwebsocket_service_fd(struct libwebsocket_context *this,
|
|||
lws_b64_encode_string(hash, 20,
|
||||
wsi->initial_handshake_hash_base64,
|
||||
sizeof wsi->initial_handshake_hash_base64);
|
||||
issue_hdr:
|
||||
|
||||
/* done with these now */
|
||||
|
||||
free(wsi->c_path);
|
||||
free(wsi->c_host);
|
||||
if (wsi->c_origin)
|
||||
free(wsi->c_origin);
|
||||
|
||||
|
||||
/* send our request to the server */
|
||||
|
||||
|
@ -877,6 +1020,54 @@ libwebsocket_service_fd(struct libwebsocket_context *this,
|
|||
goto bail3;
|
||||
}
|
||||
|
||||
/*
|
||||
* 00 / 76 -->
|
||||
*
|
||||
* HTTP/1.1 101 WebSocket Protocol Handshake
|
||||
* Upgrade: WebSocket
|
||||
* Connection: Upgrade
|
||||
* Sec-WebSocket-Origin: http://127.0.0.1
|
||||
* Sec-WebSocket-Location: ws://127.0.0.1:9999/socket.io/websocket
|
||||
*
|
||||
* xxxxxxxxxxxxxxxx
|
||||
*/
|
||||
|
||||
if (wsi->ietf_spec_revision == 0) {
|
||||
if (!wsi->utf8_token[WSI_TOKEN_HTTP].token_len ||
|
||||
!wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len ||
|
||||
!wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len ||
|
||||
!wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len ||
|
||||
(!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len &&
|
||||
wsi->c_protocol != NULL)) {
|
||||
fprintf(stderr, "libwebsocket_client_handshake "
|
||||
"missing required header(s)\n");
|
||||
pkt[len] = '\0';
|
||||
fprintf(stderr, "%s", pkt);
|
||||
goto bail3;
|
||||
}
|
||||
|
||||
strtolower(wsi->utf8_token[WSI_TOKEN_HTTP].token);
|
||||
if (strcmp(wsi->utf8_token[WSI_TOKEN_HTTP].token,
|
||||
"101 websocket protocol handshake")) {
|
||||
fprintf(stderr, "libwebsocket_client_handshake "
|
||||
"server sent bad HTTP response '%s'\n",
|
||||
wsi->utf8_token[WSI_TOKEN_HTTP].token);
|
||||
goto bail3;
|
||||
}
|
||||
|
||||
if (wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len < 16) {
|
||||
fprintf(stderr, "libwebsocket_client_handshake "
|
||||
"challenge reply too short %d\n",
|
||||
wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len);
|
||||
pkt[len] = '\0';
|
||||
fprintf(stderr, "%s", pkt);
|
||||
goto bail3;
|
||||
|
||||
}
|
||||
|
||||
goto select_protocol;
|
||||
}
|
||||
|
||||
/*
|
||||
* well, what the server sent looked reasonable for syntax.
|
||||
* Now let's confirm it sent all the necessary headers
|
||||
|
@ -929,6 +1120,7 @@ libwebsocket_service_fd(struct libwebsocket_context *this,
|
|||
goto bail3;
|
||||
}
|
||||
|
||||
select_protocol:
|
||||
|
||||
pc = wsi->c_protocol;
|
||||
|
||||
|
@ -999,6 +1191,22 @@ libwebsocket_service_fd(struct libwebsocket_context *this,
|
|||
}
|
||||
|
||||
check_accept:
|
||||
|
||||
if (wsi->ietf_spec_revision == 0) {
|
||||
|
||||
if (memcmp(wsi->initial_handshake_hash_base64,
|
||||
wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 16)) {
|
||||
fprintf(stderr, "libwebsocket_client_handshake "
|
||||
"failed 00 challenge compare\n");
|
||||
|
||||
pkt[len] = '\0';
|
||||
fprintf(stderr, "%s", pkt);
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
goto accept_ok;
|
||||
}
|
||||
|
||||
/*
|
||||
* Confirm his accept token is the one we precomputed
|
||||
*/
|
||||
|
@ -1026,6 +1234,8 @@ libwebsocket_service_fd(struct libwebsocket_context *this,
|
|||
SHA1(buf, strlen((char *)buf), wsi->masking_key_04);
|
||||
}
|
||||
|
||||
accept_ok:
|
||||
|
||||
/* allocate the per-connection user memory (if any) */
|
||||
|
||||
if (wsi->protocol->per_session_data_size) {
|
||||
|
|
|
@ -124,7 +124,7 @@ enum lws_token_indexes {
|
|||
};
|
||||
|
||||
/*
|
||||
* From 06 sped
|
||||
* From 06 spec
|
||||
1000
|
||||
|
||||
1000 indicates a normal closure, meaning whatever purpose the
|
||||
|
|
|
@ -114,11 +114,19 @@ int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c)
|
|||
if (wsi->parser_state != WSI_TOKEN_CHALLENGE)
|
||||
break;
|
||||
|
||||
/* -76 has no version header */
|
||||
/* -76 has no version header ... server */
|
||||
if (!wsi->utf8_token[WSI_TOKEN_VERSION].token_len &&
|
||||
wsi->mode != LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY &&
|
||||
wsi->utf8_token[wsi->parser_state].token_len != 8)
|
||||
break;
|
||||
|
||||
/* -76 has no version header ... client */
|
||||
if (!wsi->utf8_token[WSI_TOKEN_VERSION].token_len &&
|
||||
wsi->mode == LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY &&
|
||||
wsi->utf8_token[wsi->parser_state].token_len != 16)
|
||||
break;
|
||||
|
||||
|
||||
/* <= 03 has old handshake with version header needs 8 bytes */
|
||||
if (wsi->utf8_token[WSI_TOKEN_VERSION].token_len &&
|
||||
atoi(wsi->utf8_token[WSI_TOKEN_VERSION].token) < 4 &&
|
||||
|
|
Loading…
Add table
Reference in a new issue