Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 377 lines (307 sloc) 9.582 kB
f8ed8c8 @nicolasff Started implementing the new WebSocket protocol
authored
1 #include "sha1/sha1.h"
bac0ed9 @nicolasff Added base-64 encoding to WebSocket handshake.
authored
2 #include "libb64/cencode.h"
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
3 #include "websocket.h"
4 #include "client.h"
5 #include "cmd.h"
6 #include "worker.h"
7 #include "pool.h"
2cfc27d @nicolasff Fix websockets for recent versions of Chrome
authored
8 #include "http.h"
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
9
b3f2b2f @nicolasff Support Redis wire protocol over HTML5 WebSockets.
authored
10 /* message parsers */
11 #include "formats/json.h"
12 #include "formats/raw.h"
13
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <errno.h>
227e180 @nicolasff More compatibility fixes with endian.h
authored
19 #include <sys/param.h>
20
cd9fd9a @nicolasff Refactoring, commenting.
authored
21 /**
5190c16 @nicolasff Updated WebSocket protocol to RFC6455.
authored
22 * This code uses the WebSocket specification from RFC 6455.
23 * A copy is available at http://www.rfc-editor.org/rfc/rfc6455.txt
cd9fd9a @nicolasff Refactoring, commenting.
authored
24 */
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
25
741db1b @nicolasff Removed endian.h
authored
26 /* custom 64-bit encoding functions to avoid portability issues */
27 #define webdis_ntohl64(p) \
28 ((((uint64_t)((p)[0])) << 0) + (((uint64_t)((p)[1])) << 8) +\
29 (((uint64_t)((p)[2])) << 16) + (((uint64_t)((p)[3])) << 24) +\
30 (((uint64_t)((p)[4])) << 32) + (((uint64_t)((p)[5])) << 40) +\
31 (((uint64_t)((p)[6])) << 48) + (((uint64_t)((p)[7])) << 56))
32
33 #define webdis_htonl64(p) {\
34 (char)(((p & ((uint64_t)0xff << 0)) >> 0) & 0xff), (char)(((p & ((uint64_t)0xff << 8)) >> 8) & 0xff), \
35 (char)(((p & ((uint64_t)0xff << 16)) >> 16) & 0xff), (char)(((p & ((uint64_t)0xff << 24)) >> 24) & 0xff), \
36 (char)(((p & ((uint64_t)0xff << 32)) >> 32) & 0xff), (char)(((p & ((uint64_t)0xff << 40)) >> 40) & 0xff), \
37 (char)(((p & ((uint64_t)0xff << 48)) >> 48) & 0xff), (char)(((p & ((uint64_t)0xff << 56)) >> 56) & 0xff) }
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
38 static int
bac0ed9 @nicolasff Added base-64 encoding to WebSocket handshake.
authored
39 ws_compute_handshake(struct http_client *c, char *out, size_t *out_sz) {
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
40
f8ed8c8 @nicolasff Started implementing the new WebSocket protocol
authored
41 unsigned char *buffer, sha1_output[20];
6925709 @nicolasff Websocket protocol, now sending proper Sec-WebSocket-Accept header.
authored
42 char magic[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
f8ed8c8 @nicolasff Started implementing the new WebSocket protocol
authored
43 SHA1Context ctx;
6925709 @nicolasff Websocket protocol, now sending proper Sec-WebSocket-Accept header.
authored
44 base64_encodestate b64_ctx;
9b2cada @nicolasff Fixed byte-ordering in SHA1, added separate Origin header, and added …
authored
45 int pos, i;
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
46
47 // websocket handshake
f8ed8c8 @nicolasff Started implementing the new WebSocket protocol
authored
48 const char *key = client_get_header(c, "Sec-WebSocket-Key");
6925709 @nicolasff Websocket protocol, now sending proper Sec-WebSocket-Accept header.
authored
49 size_t key_sz = key?strlen(key):0, buffer_sz = key_sz + sizeof(magic) - 1;
50 buffer = calloc(buffer_sz, 1);
51
52 // concatenate key and guid in buffer
53 memcpy(buffer, key, key_sz);
54 memcpy(buffer+key_sz, magic, sizeof(magic)-1);
55
56 // compute sha-1
57 SHA1Reset(&ctx);
58 SHA1Input(&ctx, buffer, buffer_sz);
59 SHA1Result(&ctx);
9b2cada @nicolasff Fixed byte-ordering in SHA1, added separate Origin header, and added …
authored
60 for(i = 0; i < 5; ++i) { // put in correct byte order before memcpy.
61 ctx.Message_Digest[i] = ntohl(ctx.Message_Digest[i]);
62 }
63 memcpy(sha1_output, (unsigned char*)ctx.Message_Digest, 20);
6925709 @nicolasff Websocket protocol, now sending proper Sec-WebSocket-Accept header.
authored
64
65 // encode `sha1_output' in base 64, into `out'.
66 base64_init_encodestate(&b64_ctx);
67 pos = base64_encode_block((const char*)sha1_output, 20, out, &b64_ctx);
68 base64_encode_blockend(out + pos, &b64_ctx);
69
70 // compute length, without \n
71 *out_sz = strlen(out);
72 if(out[*out_sz-1] == '\n')
73 (*out_sz)--;
74
75 free(buffer);
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
76
77 return 0;
78 }
79
80 int
81 ws_handshake_reply(struct http_client *c) {
82
83 int ret;
bac0ed9 @nicolasff Added base-64 encoding to WebSocket handshake.
authored
84 char sha1_handshake[40];
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
85 char *buffer = NULL, *p;
86 const char *origin = NULL, *host = NULL;
f8ed8c8 @nicolasff Started implementing the new WebSocket protocol
authored
87 size_t origin_sz = 0, host_sz = 0, handshake_sz = 0, sz;
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
88
5190c16 @nicolasff Updated WebSocket protocol to RFC6455.
authored
89 char template0[] = "HTTP/1.1 101 Switching Protocols\r\n"
90 "Upgrade: websocket\r\n"
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
91 "Connection: Upgrade\r\n"
92 "Sec-WebSocket-Origin: "; /* %s */
93 char template1[] = "\r\n"
94 "Sec-WebSocket-Location: ws://"; /* %s%s */
95 char template2[] = "\r\n"
96 "Origin: http://"; /* %s */
6925709 @nicolasff Websocket protocol, now sending proper Sec-WebSocket-Accept header.
authored
97 char template3[] = "\r\n"
98 "Sec-WebSocket-Accept: "; /* %s */
99 char template4[] = "\r\n\r\n";
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
100
101 if((origin = client_get_header(c, "Origin"))) {
102 origin_sz = strlen(origin);
9b2cada @nicolasff Fixed byte-ordering in SHA1, added separate Origin header, and added …
authored
103 } else if((origin = client_get_header(c, "Sec-WebSocket-Origin"))) {
104 origin_sz = strlen(origin);
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
105 }
106 if((host = client_get_header(c, "Host"))) {
107 host_sz = strlen(host);
108 }
109
110 /* need those headers */
111 if(!origin || !origin_sz || !host || !host_sz || !c->path || !c->path_sz) {
112 return -1;
113 }
114
6925709 @nicolasff Websocket protocol, now sending proper Sec-WebSocket-Accept header.
authored
115 memset(sha1_handshake, 0, sizeof(sha1_handshake));
f8ed8c8 @nicolasff Started implementing the new WebSocket protocol
authored
116 if(ws_compute_handshake(c, &sha1_handshake[0], &handshake_sz) != 0) {
cd9fd9a @nicolasff Refactoring, commenting.
authored
117 /* failed to compute handshake. */
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
118 return -1;
119 }
120
121 sz = sizeof(template0)-1 + origin_sz
122 + sizeof(template1)-1 + host_sz + c->path_sz
123 + sizeof(template2)-1 + host_sz
6925709 @nicolasff Websocket protocol, now sending proper Sec-WebSocket-Accept header.
authored
124 + sizeof(template3)-1 + handshake_sz
125 + sizeof(template4)-1;
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
126
127 p = buffer = malloc(sz);
128
129 /* Concat all */
130
131 /* template0 */
6925709 @nicolasff Websocket protocol, now sending proper Sec-WebSocket-Accept header.
authored
132 memcpy(p, template0, sizeof(template0)-1);
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
133 p += sizeof(template0)-1;
134 memcpy(p, origin, origin_sz);
135 p += origin_sz;
136
137 /* template1 */
6925709 @nicolasff Websocket protocol, now sending proper Sec-WebSocket-Accept header.
authored
138 memcpy(p, template1, sizeof(template1)-1);
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
139 p += sizeof(template1)-1;
140 memcpy(p, host, host_sz);
141 p += host_sz;
142 memcpy(p, c->path, c->path_sz);
143 p += c->path_sz;
144
145 /* template2 */
6925709 @nicolasff Websocket protocol, now sending proper Sec-WebSocket-Accept header.
authored
146 memcpy(p, template2, sizeof(template2)-1);
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
147 p += sizeof(template2)-1;
148 memcpy(p, host, host_sz);
149 p += host_sz;
150
151 /* template3 */
6925709 @nicolasff Websocket protocol, now sending proper Sec-WebSocket-Accept header.
authored
152 memcpy(p, template3, sizeof(template3)-1);
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
153 p += sizeof(template3)-1;
f8ed8c8 @nicolasff Started implementing the new WebSocket protocol
authored
154 memcpy(p, &sha1_handshake[0], handshake_sz);
6925709 @nicolasff Websocket protocol, now sending proper Sec-WebSocket-Accept header.
authored
155 p += handshake_sz;
156
157 /* template4 */
158 memcpy(p, template4, sizeof(template4)-1);
159 p += sizeof(template4)-1;
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
160
6925709 @nicolasff Websocket protocol, now sending proper Sec-WebSocket-Accept header.
authored
161 /* send data to client */
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
162 ret = write(c->fd, buffer, sz);
e35374c @nicolasff Removed 2 unused warnings.
authored
163 (void)ret;
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
164 free(buffer);
165
166 return 0;
167 }
168
169
170 static int
171 ws_execute(struct http_client *c, const char *frame, size_t frame_len) {
172
173 struct cmd*(*fun_extract)(struct http_client *, const char *, size_t) = NULL;
b3f2b2f @nicolasff Support Redis wire protocol over HTML5 WebSockets.
authored
174 formatting_fun fun_reply = NULL;
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
175
b3f2b2f @nicolasff Support Redis wire protocol over HTML5 WebSockets.
authored
176 if((c->path_sz == 1 && strncmp(c->path, "/", 1) == 0) ||
177 strncmp(c->path, "/.json", 6) == 0) {
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
178 fun_extract = json_ws_extract;
b3f2b2f @nicolasff Support Redis wire protocol over HTML5 WebSockets.
authored
179 fun_reply = json_reply;
180 } else if(strncmp(c->path, "/.raw", 5) == 0) {
181 fun_extract = raw_ws_extract;
182 fun_reply = raw_reply;
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
183 }
184
185 if(fun_extract) {
b3f2b2f @nicolasff Support Redis wire protocol over HTML5 WebSockets.
authored
186
187 /* Parse websocket frame into a cmd object. */
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
188 struct cmd *cmd = fun_extract(c, frame, frame_len);
b3f2b2f @nicolasff Support Redis wire protocol over HTML5 WebSockets.
authored
189
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
190 if(cmd) {
239c900 @nicolasff HTTP version in reply.
authored
191 /* copy client info into cmd. */
192 cmd_setup(cmd, c);
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
193 cmd->is_websocket = 1;
194
e9da83d @jmorse If a websocket SUBSCRIBEs, use new redis context.
jmorse authored
195 if (c->pub_sub != NULL) {
196 /* This client already has its own connection
197 * to Redis due to a subscription; use it from
198 * now on. */
199 cmd->ac = c->pub_sub->ac;
200 } else if (cmd_is_subscribe(cmd)) {
201 /* New subscribe command; make new Redis context
202 * for this client */
540b1a9 @nicolasff Create new connection for new separate DBs.
authored
203 cmd->ac = pool_connect(c->w->pool, cmd->database, 0);
e9da83d @jmorse If a websocket SUBSCRIBEs, use new redis context.
jmorse authored
204 c->pub_sub = cmd;
205 cmd->pub_sub_client = c;
206 } else {
207 /* get Redis connection from pool */
208 cmd->ac = (redisAsyncContext*)pool_get_context(c->w->pool);
209 }
239c900 @nicolasff HTTP version in reply.
authored
210
211 /* send it off */
b01cb75 @nicolasff Disconnect broken SUBSCRIBE clients.
authored
212 cmd_send(cmd, fun_reply);
b3f2b2f @nicolasff Support Redis wire protocol over HTML5 WebSockets.
authored
213
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
214 return 0;
215 }
216 }
217
218 return -1;
219 }
220
1014ed5 @nicolasff Read messages from WebSocket client.
authored
221 static struct ws_msg *
022861e @nicolasff WebSocket fixes.
authored
222 ws_msg_new() {
223 return calloc(1, sizeof(struct ws_msg));
224 }
225
226 static void
227 ws_msg_add(struct ws_msg *m, const char *p, size_t psz, const unsigned char *mask) {
1014ed5 @nicolasff Read messages from WebSocket client.
authored
228
022861e @nicolasff WebSocket fixes.
authored
229 /* add data to frame */
1014ed5 @nicolasff Read messages from WebSocket client.
authored
230 size_t i;
022861e @nicolasff WebSocket fixes.
authored
231 m->payload = realloc(m->payload, m->payload_sz + psz);
232 memcpy(m->payload + m->payload_sz, p, psz);
1014ed5 @nicolasff Read messages from WebSocket client.
authored
233
022861e @nicolasff WebSocket fixes.
authored
234 /* apply mask */
1014ed5 @nicolasff Read messages from WebSocket client.
authored
235 for(i = 0; i < psz && mask; ++i) {
022861e @nicolasff WebSocket fixes.
authored
236 m->payload[m->payload_sz + i] = (unsigned char)p[i] ^ mask[i%4];
1014ed5 @nicolasff Read messages from WebSocket client.
authored
237 }
238
022861e @nicolasff WebSocket fixes.
authored
239 /* save new size */
240 m->payload_sz += psz;
1014ed5 @nicolasff Read messages from WebSocket client.
authored
241 }
242
243 static void
022861e @nicolasff WebSocket fixes.
authored
244 ws_msg_free(struct ws_msg **m) {
1014ed5 @nicolasff Read messages from WebSocket client.
authored
245
022861e @nicolasff WebSocket fixes.
authored
246 free((*m)->payload);
247 free(*m);
248 *m = NULL;
1014ed5 @nicolasff Read messages from WebSocket client.
authored
249 }
250
5190c16 @nicolasff Updated WebSocket protocol to RFC6455.
authored
251 static enum ws_state
1014ed5 @nicolasff Read messages from WebSocket client.
authored
252 ws_parse_data(const char *frame, size_t sz, struct ws_msg **msg) {
253
5190c16 @nicolasff Updated WebSocket protocol to RFC6455.
authored
254 int has_mask;
022861e @nicolasff WebSocket fixes.
authored
255 uint64_t len;
1014ed5 @nicolasff Read messages from WebSocket client.
authored
256 const char *p;
257 unsigned char mask[4];
258
259 /* parse frame and extract contents */
5190c16 @nicolasff Updated WebSocket protocol to RFC6455.
authored
260 if(sz < 8) {
261 return WS_READING;
262 }
1014ed5 @nicolasff Read messages from WebSocket client.
authored
263
264 has_mask = frame[1] & 0x80 ? 1:0;
265
266 /* get payload length */
267 len = frame[1] & 0x7f; /* remove leftmost bit */
268 if(len <= 125) { /* data starts right after the mask */
269 p = frame + 2 + (has_mask ? 4 : 0);
270 if(has_mask) memcpy(&mask, frame + 2, sizeof(mask));
271 } else if(len == 126) {
022861e @nicolasff WebSocket fixes.
authored
272 uint16_t sz16;
273 memcpy(&sz16, frame + 2, sizeof(uint16_t));
274 len = ntohs(sz16);
1014ed5 @nicolasff Read messages from WebSocket client.
authored
275 p = frame + 4 + (has_mask ? 4 : 0);
276 if(has_mask) memcpy(&mask, frame + 4, sizeof(mask));
277 } else if(len == 127) {
741db1b @nicolasff Removed endian.h
authored
278 len = webdis_ntohl64(frame+2);
022861e @nicolasff WebSocket fixes.
authored
279 p = frame + 10 + (has_mask ? 4 : 0);
280 if(has_mask) memcpy(&mask, frame + 10, sizeof(mask));
5385f9c @nicolasff Fixed warnings seen on FreeBSD.
authored
281 } else {
282 return WS_ERROR;
1014ed5 @nicolasff Read messages from WebSocket client.
authored
283 }
284
285 /* we now have the (possibly masked) data starting in p, and its length. */
286 if(len > sz - (p - frame)) { /* not enough data */
5190c16 @nicolasff Updated WebSocket protocol to RFC6455.
authored
287 return WS_READING;
1014ed5 @nicolasff Read messages from WebSocket client.
authored
288 }
289
022861e @nicolasff WebSocket fixes.
authored
290 if(!*msg)
291 *msg = ws_msg_new();
292 ws_msg_add(*msg, p, len, has_mask ? mask : NULL);
293 (*msg)->total_sz += len + (p - frame);
1014ed5 @nicolasff Read messages from WebSocket client.
authored
294
022861e @nicolasff WebSocket fixes.
authored
295 if(frame[0] & 0x80) { /* FIN bit set */
296 return WS_MSG_COMPLETE;
297 } else {
298 return WS_READING; /* need more data */
299 }
1014ed5 @nicolasff Read messages from WebSocket client.
authored
300 }
301
302
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
303 /**
304 * Process some data just received on the socket.
305 */
5190c16 @nicolasff Updated WebSocket protocol to RFC6455.
authored
306 enum ws_state
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
307 ws_add_data(struct http_client *c) {
1014ed5 @nicolasff Read messages from WebSocket client.
authored
308
5190c16 @nicolasff Updated WebSocket protocol to RFC6455.
authored
309 enum ws_state state;
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
310
022861e @nicolasff WebSocket fixes.
authored
311 state = ws_parse_data(c->buffer, c->sz, &c->frame);
1014ed5 @nicolasff Read messages from WebSocket client.
authored
312
5190c16 @nicolasff Updated WebSocket protocol to RFC6455.
authored
313 if(state == WS_MSG_COMPLETE) {
022861e @nicolasff WebSocket fixes.
authored
314 int ret = ws_execute(c, c->frame->payload, c->frame->payload_sz);
1014ed5 @nicolasff Read messages from WebSocket client.
authored
315
5190c16 @nicolasff Updated WebSocket protocol to RFC6455.
authored
316 /* remove frame from client buffer */
022861e @nicolasff WebSocket fixes.
authored
317 http_client_remove_data(c, c->frame->total_sz);
318
319 /* free frame and set back to NULL */
320 ws_msg_free(&c->frame);
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
321
322 if(ret != 0) {
cd9fd9a @nicolasff Refactoring, commenting.
authored
323 /* can't process frame. */
5190c16 @nicolasff Updated WebSocket protocol to RFC6455.
authored
324 return WS_ERROR;
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
325 }
326 }
5190c16 @nicolasff Updated WebSocket protocol to RFC6455.
authored
327 return state;
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
328 }
329
330 int
331 ws_reply(struct cmd *cmd, const char *p, size_t sz) {
332
5190c16 @nicolasff Updated WebSocket protocol to RFC6455.
authored
333 char *frame = malloc(sz + 8); /* create frame by prepending header */
5385f9c @nicolasff Fixed warnings seen on FreeBSD.
authored
334 size_t frame_sz = 0;
2cfc27d @nicolasff Fix websockets for recent versions of Chrome
authored
335 struct http_response *r;
336 if (frame == NULL)
337 return -1;
5190c16 @nicolasff Updated WebSocket protocol to RFC6455.
authored
338
339 /*
340 The length of the "Payload data", in bytes: if 0-125, that is the
341 payload length. If 126, the following 2 bytes interpreted as a
342 16-bit unsigned integer are the payload length. If 127, the
343 following 8 bytes interpreted as a 64-bit unsigned integer (the
344 most significant bit MUST be 0) are the payload length.
345 */
346 frame[0] = '\x81';
347 if(sz <= 125) {
348 frame[1] = sz;
349 memcpy(frame + 2, p, sz);
350 frame_sz = sz + 2;
351 } else if (sz > 125 && sz <= 65536) {
352 uint16_t sz16 = htons(sz);
353 frame[1] = 126;
354 memcpy(frame + 2, &sz16, 2);
355 memcpy(frame + 4, p, sz);
356 frame_sz = sz + 4;
357 } else if (sz > 65536) {
741db1b @nicolasff Removed endian.h
authored
358 char sz64[8] = webdis_htonl64(sz);
5190c16 @nicolasff Updated WebSocket protocol to RFC6455.
authored
359 frame[1] = 127;
741db1b @nicolasff Removed endian.h
authored
360 memcpy(frame + 2, sz64, 8);
5190c16 @nicolasff Updated WebSocket protocol to RFC6455.
authored
361 memcpy(frame + 10, p, sz);
362 frame_sz = sz + 10;
363 }
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
364
365 /* send WS frame */
2cfc27d @nicolasff Fix websockets for recent versions of Chrome
authored
366 r = http_response_init(cmd->w, 0, NULL);
367 if (r == NULL)
368 return -1;
5190c16 @nicolasff Updated WebSocket protocol to RFC6455.
authored
369
2cfc27d @nicolasff Fix websockets for recent versions of Chrome
authored
370 r->out = frame;
371 r->out_sz = frame_sz;
372 r->sent = 0;
373 http_schedule_write(cmd->fd, r);
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
374
2cfc27d @nicolasff Fix websockets for recent versions of Chrome
authored
375 return 0;
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
376 }
Something went wrong with that request. Please try again.