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,
|
int encode_hybi(u_char const *src, size_t srclength,
|
||||||
char *target, size_t targsize, unsigned int opcode)
|
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;
|
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);
|
target[0] = (char)((opcode & 0x0F) | 0x80);
|
||||||
|
|
||||||
if (b64_sz <= 125) {
|
if ((int)srclength <= 0) {
|
||||||
target[1] = (char) b64_sz;
|
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;
|
payload_offset = 2;
|
||||||
} else if ((b64_sz > 125) && (b64_sz < 65536)) {
|
} else if ((len > 125) && (len < 65536)) {
|
||||||
target[1] = (char) 126;
|
target[1] = (char) 126;
|
||||||
*(u_short*)&(target[2]) = htons(b64_sz);
|
*(u_short*)&(target[2]) = htons(len);
|
||||||
payload_offset = 4;
|
payload_offset = 4;
|
||||||
} else {
|
} else {
|
||||||
handler_emsg("Sending frames larger than 65535 bytes not supported\n");
|
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;
|
//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) {
|
if (len < 0) {
|
||||||
return len;
|
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);
|
//printf(" payload_length: %u, raw remaining: %u\n", payload_length, remaining);
|
||||||
payload = frame + hdr_length + 4*masked;
|
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);
|
handler_msg("Ignoring non-data frame, opcode 0x%x\n", *opcode);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -458,8 +471,13 @@ int decode_hybi(unsigned char *src, size_t srclength,
|
||||||
payload[i] ^= mask[i%4];
|
payload[i] ^= mask[i%4];
|
||||||
}
|
}
|
||||||
|
|
||||||
// base64 decode the data
|
if (*opcode & OPCODE_TEXT) {
|
||||||
len = ws_b64_pton((const char*)payload, target+target_offset, targsize);
|
// 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
|
// Restore the first character of the next frame
|
||||||
payload[payload_length] = save_char;
|
payload[payload_length] = save_char;
|
||||||
|
@ -640,6 +658,7 @@ ws_ctx_t *do_handshake(int sock) {
|
||||||
headers_t *headers;
|
headers_t *headers;
|
||||||
int len, ret, i, offset;
|
int len, ret, i, offset;
|
||||||
ws_ctx_t * ws_ctx;
|
ws_ctx_t * ws_ctx;
|
||||||
|
char *response_protocol;
|
||||||
|
|
||||||
// Peek, but don't read the data
|
// Peek, but don't read the data
|
||||||
len = recv(sock, handshake, 1024, MSG_PEEK);
|
len = recv(sock, handshake, 1024, MSG_PEEK);
|
||||||
|
@ -709,10 +728,21 @@ ws_ctx_t *do_handshake(int sock) {
|
||||||
}
|
}
|
||||||
|
|
||||||
headers = ws_ctx->headers;
|
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) {
|
if (ws_ctx->hybi > 0) {
|
||||||
handler_msg("using protocol HyBi/IETF 6455 %d\n", ws_ctx->hybi);
|
handler_msg("using protocol HyBi/IETF 6455 %d\n", ws_ctx->hybi);
|
||||||
gen_sha1(headers, sha1);
|
gen_sha1(headers, sha1);
|
||||||
sprintf(response, SERVER_HANDSHAKE_HYBI, sha1, "base64");
|
snprintf(response, sizeof(response), SERVER_HANDSHAKE_HYBI, sha1, response_protocol);
|
||||||
} else {
|
} else {
|
||||||
if (ws_ctx->hixie == 76) {
|
if (ws_ctx->hixie == 76) {
|
||||||
handler_msg("using protocol Hixie 76\n");
|
handler_msg("using protocol Hixie 76\n");
|
||||||
|
@ -723,8 +753,8 @@ ws_ctx_t *do_handshake(int sock) {
|
||||||
trailer[0] = '\0';
|
trailer[0] = '\0';
|
||||||
pre = "";
|
pre = "";
|
||||||
}
|
}
|
||||||
sprintf(response, SERVER_HANDSHAKE_HIXIE, pre, headers->origin, pre, scheme,
|
snprintf(response, sizeof(response), SERVER_HANDSHAKE_HIXIE, pre, headers->origin,
|
||||||
headers->host, headers->path, pre, "base64", trailer);
|
pre, scheme, headers->host, headers->path, pre, "base64", trailer);
|
||||||
}
|
}
|
||||||
|
|
||||||
//handler_msg("response: %s\n", response);
|
//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 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 {
|
typedef struct {
|
||||||
char path[1024+1];
|
char path[1024+1];
|
||||||
char host[1024+1];
|
char host[1024+1];
|
||||||
|
@ -44,6 +47,7 @@ typedef struct {
|
||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
int hixie;
|
int hixie;
|
||||||
int hybi;
|
int hybi;
|
||||||
|
int opcode;
|
||||||
headers_t *headers;
|
headers_t *headers;
|
||||||
char *cin_buf;
|
char *cin_buf;
|
||||||
char *cout_buf;
|
char *cout_buf;
|
||||||
|
|
|
@ -158,7 +158,7 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) {
|
||||||
cout_start = 0;
|
cout_start = 0;
|
||||||
if (ws_ctx->hybi) {
|
if (ws_ctx->hybi) {
|
||||||
cout_end = encode_hybi(ws_ctx->cin_buf, bytes,
|
cout_end = encode_hybi(ws_ctx->cin_buf, bytes,
|
||||||
ws_ctx->cout_buf, BUFSIZE, 1);
|
ws_ctx->cout_buf, BUFSIZE, ws_ctx->opcode);
|
||||||
} else {
|
} else {
|
||||||
cout_end = encode_hixie(ws_ctx->cin_buf, bytes,
|
cout_end = encode_hixie(ws_ctx->cin_buf, bytes,
|
||||||
ws_ctx->cout_buf, BUFSIZE);
|
ws_ctx->cout_buf, BUFSIZE);
|
||||||
|
@ -205,7 +205,7 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opcode == 8) {
|
if (opcode == 8) {
|
||||||
handler_emsg("client sent orderly close frame\n");
|
handler_msg("client sent orderly close frame\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue