C websockify: support for binary websocket protocol with HyBi/RFC 6455.
The server prefers binary over base64 encoding, given a choice. This is required as noVNC no longer supports base64 encoding.
This commit is contained in:
parent
3a03e3c59d
commit
4202818be9
|
@ -335,24 +335,32 @@ int decode_hixie(char *src, size_t srclength,
|
|||
int encode_hybi(u_char const *src, size_t srclength,
|
||||
char *target, size_t targsize, unsigned int opcode)
|
||||
{
|
||||
unsigned long long b64_sz, len_offset = 1, payload_offset = 2;
|
||||
unsigned long long payload_offset = 2;
|
||||
int len = 0;
|
||||
|
||||
if ((int)srclength <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
b64_sz = ((srclength - 1) / 3) * 4 + 4;
|
||||
if (opcode != OPCODE_TEXT && opcode != OPCODE_BINARY) {
|
||||
handler_emsg("Invalid opcode. Opcode must be 0x01 for text mode, or 0x02 for binary mode.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
target[0] = (char)((opcode & 0x0F) | 0x80);
|
||||
|
||||
if (b64_sz <= 125) {
|
||||
target[1] = (char) b64_sz;
|
||||
if ((int)srclength <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (opcode & OPCODE_TEXT) {
|
||||
len = ((srclength - 1) / 3) * 4 + 4;
|
||||
} else {
|
||||
len = srclength;
|
||||
}
|
||||
|
||||
if (len <= 125) {
|
||||
target[1] = (char) len;
|
||||
payload_offset = 2;
|
||||
} else if ((b64_sz > 125) && (b64_sz < 65536)) {
|
||||
} else if ((len > 125) && (len < 65536)) {
|
||||
target[1] = (char) 126;
|
||||
*(u_short*)&(target[2]) = htons(b64_sz);
|
||||
*(u_short*)&(target[2]) = htons(len);
|
||||
payload_offset = 4;
|
||||
} else {
|
||||
handler_emsg("Sending frames larger than 65535 bytes not supported\n");
|
||||
|
@ -362,8 +370,13 @@ int encode_hybi(u_char const *src, size_t srclength,
|
|||
//payload_offset = 10;
|
||||
}
|
||||
|
||||
len = ws_b64_ntop(src, srclength, target+payload_offset, targsize-payload_offset);
|
||||
|
||||
if (opcode & OPCODE_TEXT) {
|
||||
len = ws_b64_ntop(src, srclength, target+payload_offset, targsize-payload_offset);
|
||||
} else {
|
||||
memcpy(target+payload_offset, src, srclength);
|
||||
len = srclength;
|
||||
}
|
||||
|
||||
if (len < 0) {
|
||||
return len;
|
||||
}
|
||||
|
@ -433,7 +446,7 @@ int decode_hybi(unsigned char *src, size_t srclength,
|
|||
//printf(" payload_length: %u, raw remaining: %u\n", payload_length, remaining);
|
||||
payload = frame + hdr_length + 4*masked;
|
||||
|
||||
if (*opcode != 1 && *opcode != 2) {
|
||||
if (*opcode != OPCODE_TEXT && *opcode != OPCODE_BINARY) {
|
||||
handler_msg("Ignoring non-data frame, opcode 0x%x\n", *opcode);
|
||||
continue;
|
||||
}
|
||||
|
@ -458,8 +471,13 @@ int decode_hybi(unsigned char *src, size_t srclength,
|
|||
payload[i] ^= mask[i%4];
|
||||
}
|
||||
|
||||
// base64 decode the data
|
||||
len = ws_b64_pton((const char*)payload, target+target_offset, targsize);
|
||||
if (*opcode & OPCODE_TEXT) {
|
||||
// base64 decode the data
|
||||
len = ws_b64_pton((const char*)payload, target+target_offset, targsize);
|
||||
} else {
|
||||
memcpy(target+target_offset, payload, payload_length);
|
||||
len = payload_length;
|
||||
}
|
||||
|
||||
// Restore the first character of the next frame
|
||||
payload[payload_length] = save_char;
|
||||
|
@ -640,6 +658,7 @@ ws_ctx_t *do_handshake(int sock) {
|
|||
headers_t *headers;
|
||||
int len, ret, i, offset;
|
||||
ws_ctx_t * ws_ctx;
|
||||
char *response_protocol;
|
||||
|
||||
// Peek, but don't read the data
|
||||
len = recv(sock, handshake, 1024, MSG_PEEK);
|
||||
|
@ -709,10 +728,21 @@ ws_ctx_t *do_handshake(int sock) {
|
|||
}
|
||||
|
||||
headers = ws_ctx->headers;
|
||||
|
||||
response_protocol = strtok(headers->protocols, ",");
|
||||
if (!response_protocol || !strlen(response_protocol)) {
|
||||
ws_ctx->opcode = OPCODE_BINARY;
|
||||
response_protocol = "null";
|
||||
} else if (!strcmp(response_protocol, "base64")) {
|
||||
ws_ctx->opcode = OPCODE_TEXT;
|
||||
} else {
|
||||
ws_ctx->opcode = OPCODE_BINARY;
|
||||
}
|
||||
|
||||
if (ws_ctx->hybi > 0) {
|
||||
handler_msg("using protocol HyBi/IETF 6455 %d\n", ws_ctx->hybi);
|
||||
gen_sha1(headers, sha1);
|
||||
sprintf(response, SERVER_HANDSHAKE_HYBI, sha1, "base64");
|
||||
snprintf(response, sizeof(response), SERVER_HANDSHAKE_HYBI, sha1, response_protocol);
|
||||
} else {
|
||||
if (ws_ctx->hixie == 76) {
|
||||
handler_msg("using protocol Hixie 76\n");
|
||||
|
@ -723,8 +753,8 @@ ws_ctx_t *do_handshake(int sock) {
|
|||
trailer[0] = '\0';
|
||||
pre = "";
|
||||
}
|
||||
sprintf(response, SERVER_HANDSHAKE_HIXIE, pre, headers->origin, pre, scheme,
|
||||
headers->host, headers->path, pre, "base64", trailer);
|
||||
snprintf(response, sizeof(response), SERVER_HANDSHAKE_HIXIE, pre, headers->origin,
|
||||
pre, scheme, headers->host, headers->path, pre, "base64", trailer);
|
||||
}
|
||||
|
||||
//handler_msg("response: %s\n", response);
|
||||
|
|
|
@ -26,6 +26,9 @@ Sec-WebSocket-Protocol: %s\r\n\
|
|||
|
||||
#define POLICY_RESPONSE "<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\" /></cross-domain-policy>\n"
|
||||
|
||||
#define OPCODE_TEXT 0x01
|
||||
#define OPCODE_BINARY 0x02
|
||||
|
||||
typedef struct {
|
||||
char path[1024+1];
|
||||
char host[1024+1];
|
||||
|
@ -44,6 +47,7 @@ typedef struct {
|
|||
SSL *ssl;
|
||||
int hixie;
|
||||
int hybi;
|
||||
int opcode;
|
||||
headers_t *headers;
|
||||
char *cin_buf;
|
||||
char *cout_buf;
|
||||
|
|
|
@ -158,7 +158,7 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) {
|
|||
cout_start = 0;
|
||||
if (ws_ctx->hybi) {
|
||||
cout_end = encode_hybi(ws_ctx->cin_buf, bytes,
|
||||
ws_ctx->cout_buf, BUFSIZE, 1);
|
||||
ws_ctx->cout_buf, BUFSIZE, ws_ctx->opcode);
|
||||
} else {
|
||||
cout_end = encode_hixie(ws_ctx->cin_buf, bytes,
|
||||
ws_ctx->cout_buf, BUFSIZE);
|
||||
|
@ -205,7 +205,7 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) {
|
|||
}
|
||||
|
||||
if (opcode == 8) {
|
||||
handler_emsg("client sent orderly close frame\n");
|
||||
handler_msg("client sent orderly close frame\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue