blob: 224a0f27a535a7b8ff7d2759a57b3fa3a2f66fd0 [file] [log] [blame]
Andy Greenb429d482013-01-16 12:21:29 +08001/*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation:
9 * version 2.1 of the License.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301 USA
20 */
21
22#include "private-libwebsockets.h"
23
24#ifdef WIN32
25#include <io.h>
26#endif
27
28static int
29libwebsocket_0405_frame_mask_generate(struct libwebsocket *wsi)
30{
Andy Greenb429d482013-01-16 12:21:29 +080031 int n;
32
33 /* fetch the per-frame nonce */
34
35 n = libwebsockets_get_random(wsi->protocol->owning_server,
Andy Greenb5b23192013-02-11 17:13:32 +080036 wsi->u.ws.frame_masking_nonce_04, 4);
Andy Greenb429d482013-01-16 12:21:29 +080037 if (n != 4) {
38 lwsl_parser("Unable to read from random device %s %d\n",
39 SYSTEM_RANDOM_FILEPATH, n);
40 return 1;
41 }
42
43 /* start masking from first byte of masking key buffer */
Andy Green623a98d2013-01-21 11:04:23 +080044 wsi->u.ws.frame_mask_index = 0;
Andy Greenb429d482013-01-16 12:21:29 +080045
Andy Greenb429d482013-01-16 12:21:29 +080046 return 0;
47}
48
Andy Greencf3590e2013-01-16 14:35:27 +080049#ifdef _DEBUG
Andy Greenb429d482013-01-16 12:21:29 +080050
Peter Pentchev9a4fef72013-03-30 09:52:21 +080051LWS_VISIBLE void lwsl_hexdump(void *vbuf, size_t len)
Andy Greenb429d482013-01-16 12:21:29 +080052{
53 int n;
54 int m;
55 int start;
Andy Greencf3590e2013-01-16 14:35:27 +080056 unsigned char *buf = (unsigned char *)vbuf;
57 char line[80];
58 char *p;
Andy Greenb429d482013-01-16 12:21:29 +080059
60 lwsl_parser("\n");
61
62 for (n = 0; n < len;) {
63 start = n;
Andy Greencf3590e2013-01-16 14:35:27 +080064 p = line;
Andy Greenb429d482013-01-16 12:21:29 +080065
Andy Greencf3590e2013-01-16 14:35:27 +080066 p += sprintf(p, "%04X: ", start);
Andy Greenb429d482013-01-16 12:21:29 +080067
68 for (m = 0; m < 16 && n < len; m++)
Andy Greencf3590e2013-01-16 14:35:27 +080069 p += sprintf(p, "%02X ", buf[n++]);
Andy Greenb429d482013-01-16 12:21:29 +080070 while (m++ < 16)
Andy Greencf3590e2013-01-16 14:35:27 +080071 p += sprintf(p, " ");
Andy Greenb429d482013-01-16 12:21:29 +080072
Andy Greencf3590e2013-01-16 14:35:27 +080073 p += sprintf(p, " ");
Andy Greenb429d482013-01-16 12:21:29 +080074
75 for (m = 0; m < 16 && (start + m) < len; m++) {
Andy Green3182ece2013-01-20 17:08:31 +080076 if (buf[start + m] >= ' ' && buf[start + m] < 127)
Andy Greencf3590e2013-01-16 14:35:27 +080077 *p++ = buf[start + m];
Andy Greenb429d482013-01-16 12:21:29 +080078 else
Andy Greencf3590e2013-01-16 14:35:27 +080079 *p++ = '.';
Andy Greenb429d482013-01-16 12:21:29 +080080 }
81 while (m++ < 16)
Andy Greencf3590e2013-01-16 14:35:27 +080082 *p++ = ' ';
Andy Greenb429d482013-01-16 12:21:29 +080083
Andy Greencf3590e2013-01-16 14:35:27 +080084 *p++ = '\n';
85 *p = '\0';
Andy Green3182ece2013-01-20 17:08:31 +080086 lwsl_debug("%s", line);
Andy Greenb429d482013-01-16 12:21:29 +080087 }
88 lwsl_debug("\n");
89}
90
Andy Greencf3590e2013-01-16 14:35:27 +080091#endif
92
Andy Greenfc7c5e42013-02-23 10:50:10 +080093/*
94 * notice this returns number of bytes sent, or -1
95 */
96
Andy Greenb429d482013-01-16 12:21:29 +080097int lws_issue_raw(struct libwebsocket *wsi, unsigned char *buf, size_t len)
98{
Andy Greene000a702013-01-29 12:37:35 +080099 struct libwebsocket_context *context = wsi->protocol->owning_server;
Andy Greenb429d482013-01-16 12:21:29 +0800100 int n;
Andy Green3182ece2013-01-20 17:08:31 +0800101#ifndef LWS_NO_EXTENSIONS
Andy Greenb429d482013-01-16 12:21:29 +0800102 int m;
103
104 /*
105 * one of the extensions is carrying our data itself? Like mux?
106 */
107
108 for (n = 0; n < wsi->count_active_extensions; n++) {
109 /*
110 * there can only be active extensions after handshake completed
111 * so we can rely on protocol being set already in here
112 */
113 m = wsi->active_extensions[n]->callback(
114 wsi->protocol->owning_server,
115 wsi->active_extensions[n], wsi,
116 LWS_EXT_CALLBACK_PACKET_TX_DO_SEND,
117 wsi->active_extensions_user[n], &buf, len);
118 if (m < 0) {
119 lwsl_ext("Extension reports fatal error\n");
120 return -1;
121 }
122 if (m) /* handled */ {
123/* lwsl_ext("ext sent it\n"); */
Andy Greenfc7c5e42013-02-23 10:50:10 +0800124 return m;
Andy Greenb429d482013-01-16 12:21:29 +0800125 }
126 }
Andy Green3182ece2013-01-20 17:08:31 +0800127#endif
Andy Greenb429d482013-01-16 12:21:29 +0800128 if (!wsi->sock)
129 lwsl_warn("** error 0 sock but expected to send\n");
130
131 /*
132 * nope, send it on the socket directly
133 */
134
135#if 0
136 lwsl_debug(" TX: ");
Andy Green0303db42013-01-17 14:46:43 +0800137 lws_hexdump(buf, len);
Andy Greenb429d482013-01-16 12:21:29 +0800138#endif
139
Andy Greene000a702013-01-29 12:37:35 +0800140 lws_latency_pre(context, wsi);
Andy Greenb429d482013-01-16 12:21:29 +0800141#ifdef LWS_OPENSSL_SUPPORT
142 if (wsi->ssl) {
143 n = SSL_write(wsi->ssl, buf, len);
Andy Greene000a702013-01-29 12:37:35 +0800144 lws_latency(context, wsi, "SSL_write lws_issue_raw", n, n >= 0);
Andy Greenb429d482013-01-16 12:21:29 +0800145 if (n < 0) {
146 lwsl_debug("ERROR writing to socket\n");
147 return -1;
148 }
149 } else {
150#endif
151 n = send(wsi->sock, buf, len, MSG_NOSIGNAL);
Andy Greene000a702013-01-29 12:37:35 +0800152 lws_latency(context, wsi, "send lws_issue_raw", n, n == len);
Andy Greenfc7c5e42013-02-23 10:50:10 +0800153 if (n < 0) {
Andy Greenb5b23192013-02-11 17:13:32 +0800154 lwsl_debug("ERROR writing len %d to skt %d\n", len, n);
Andy Greenb429d482013-01-16 12:21:29 +0800155 return -1;
156 }
157#ifdef LWS_OPENSSL_SUPPORT
158 }
159#endif
Andy Greenfc7c5e42013-02-23 10:50:10 +0800160 return n;
Andy Greenb429d482013-01-16 12:21:29 +0800161}
162
Andy Green3182ece2013-01-20 17:08:31 +0800163#ifdef LWS_NO_EXTENSIONS
164int
165lws_issue_raw_ext_access(struct libwebsocket *wsi,
166 unsigned char *buf, size_t len)
167{
168 return lws_issue_raw(wsi, buf, len);
169}
170#else
Andy Greenb429d482013-01-16 12:21:29 +0800171int
172lws_issue_raw_ext_access(struct libwebsocket *wsi,
173 unsigned char *buf, size_t len)
174{
175 int ret;
176 struct lws_tokens eff_buf;
177 int m;
178 int n;
179
180 eff_buf.token = (char *)buf;
181 eff_buf.token_len = len;
182
183 /*
184 * while we have original buf to spill ourselves, or extensions report
185 * more in their pipeline
186 */
187
188 ret = 1;
189 while (ret == 1) {
190
191 /* default to nobody has more to spill */
192
193 ret = 0;
194
195 /* show every extension the new incoming data */
196
197 for (n = 0; n < wsi->count_active_extensions; n++) {
198 m = wsi->active_extensions[n]->callback(
199 wsi->protocol->owning_server,
200 wsi->active_extensions[n], wsi,
201 LWS_EXT_CALLBACK_PACKET_TX_PRESEND,
202 wsi->active_extensions_user[n], &eff_buf, 0);
203 if (m < 0) {
204 lwsl_ext("Extension: fatal error\n");
205 return -1;
206 }
207 if (m)
208 /*
209 * at least one extension told us he has more
210 * to spill, so we will go around again after
211 */
212 ret = 1;
213 }
214
215 /* assuming they left us something to send, send it */
216
Andy Greenfc7c5e42013-02-23 10:50:10 +0800217 if (eff_buf.token_len) {
218 n = lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
219 eff_buf.token_len);
220 if (n < 0)
Andy Greenb429d482013-01-16 12:21:29 +0800221 return -1;
Andy Greenfc7c5e42013-02-23 10:50:10 +0800222 /*
223 * Keep amount spilled small to minimize chance of this
224 */
225 if (n != eff_buf.token_len) {
Henrik Abelsson2bdbe7a2013-03-07 15:52:53 +0100226 lwsl_err("Unable to spill ext %d vs %d\n",
Andy Greenfc7c5e42013-02-23 10:50:10 +0800227 eff_buf.token_len, n);
228 return -1;
229 }
230
231 }
Andy Greenb429d482013-01-16 12:21:29 +0800232
233 lwsl_parser("written %d bytes to client\n", eff_buf.token_len);
234
235 /* no extension has more to spill */
236
237 if (!ret)
238 break;
239
240 /* we used up what we had */
241
242 eff_buf.token = NULL;
243 eff_buf.token_len = 0;
244
245 /*
246 * Did that leave the pipe choked?
247 */
248
249 if (!lws_send_pipe_choked(wsi))
250 /* no we could add more */
251 continue;
252
253 lwsl_debug("choked\n");
254
255 /*
256 * Yes, he's choked. Don't spill the rest now get a callback
257 * when he is ready to send and take care of it there
258 */
259 libwebsocket_callback_on_writable(
260 wsi->protocol->owning_server, wsi);
261 wsi->extension_data_pending = 1;
262 ret = 0;
263 }
264
Andy Greenfc7c5e42013-02-23 10:50:10 +0800265 return len;
Andy Greenb429d482013-01-16 12:21:29 +0800266}
Andy Green3182ece2013-01-20 17:08:31 +0800267#endif
Andy Greenb429d482013-01-16 12:21:29 +0800268
269/**
270 * libwebsocket_write() - Apply protocol then write data to client
271 * @wsi: Websocket instance (available from user callback)
272 * @buf: The data to send. For data being sent on a websocket
273 * connection (ie, not default http), this buffer MUST have
274 * LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE the pointer
275 * and an additional LWS_SEND_BUFFER_POST_PADDING bytes valid
276 * in the buffer after (buf + len). This is so the protocol
277 * header and trailer data can be added in-situ.
278 * @len: Count of the data bytes in the payload starting from buf
279 * @protocol: Use LWS_WRITE_HTTP to reply to an http connection, and one
280 * of LWS_WRITE_BINARY or LWS_WRITE_TEXT to send appropriate
281 * data on a websockets connection. Remember to allow the extra
282 * bytes before and after buf if LWS_WRITE_BINARY or LWS_WRITE_TEXT
283 * are used.
284 *
285 * This function provides the way to issue data back to the client
286 * for both http and websocket protocols.
287 *
288 * In the case of sending using websocket protocol, be sure to allocate
289 * valid storage before and after buf as explained above. This scheme
290 * allows maximum efficiency of sending data and protocol in a single
291 * packet while not burdening the user code with any protocol knowledge.
Andy Greenfc7c5e42013-02-23 10:50:10 +0800292 *
293 * Return may be -1 for a fatal error needing connection close, or a
294 * positive number reflecting the amount of bytes actually sent. This
295 * can be less than the requested number of bytes due to OS memory
296 * pressure at any given time.
Andy Greenb429d482013-01-16 12:21:29 +0800297 */
298
Peter Pentchev9a4fef72013-03-30 09:52:21 +0800299LWS_VISIBLE int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf,
Andy Greenb429d482013-01-16 12:21:29 +0800300 size_t len, enum libwebsocket_write_protocol protocol)
301{
302 int n;
303 int pre = 0;
304 int post = 0;
Andy Green5738c0e2013-01-21 09:53:35 +0800305 int masked7 = wsi->mode == LWS_CONNMODE_WS_CLIENT;
Andy Greenb429d482013-01-16 12:21:29 +0800306 unsigned char *dropmask = NULL;
307 unsigned char is_masked_bit = 0;
Andy Greenfc7c5e42013-02-23 10:50:10 +0800308 size_t orig_len = len;
Andy Green3182ece2013-01-20 17:08:31 +0800309#ifndef LWS_NO_EXTENSIONS
Andy Greenb429d482013-01-16 12:21:29 +0800310 struct lws_tokens eff_buf;
311 int m;
Andy Green3182ece2013-01-20 17:08:31 +0800312#endif
Andy Greenb429d482013-01-16 12:21:29 +0800313
Joachim Bauchd727e9f2013-06-23 14:47:26 +0800314 if (len == 0 && protocol != LWS_WRITE_CLOSE && protocol != LWS_WRITE_PING && protocol != LWS_WRITE_PONG) {
Andy Greenb429d482013-01-16 12:21:29 +0800315 lwsl_warn("zero length libwebsocket_write attempt\n");
316 return 0;
317 }
318
319 if (protocol == LWS_WRITE_HTTP)
320 goto send_raw;
321
322 /* websocket protocol, either binary or text */
323
324 if (wsi->state != WSI_STATE_ESTABLISHED)
325 return -1;
326
Andy Green3182ece2013-01-20 17:08:31 +0800327#ifndef LWS_NO_EXTENSIONS
Andy Greenb429d482013-01-16 12:21:29 +0800328 /* give a change to the extensions to modify payload */
329 eff_buf.token = (char *)buf;
330 eff_buf.token_len = len;
331
Andy Green0303db42013-01-17 14:46:43 +0800332 switch (protocol) {
333 case LWS_WRITE_PING:
334 case LWS_WRITE_PONG:
335 case LWS_WRITE_CLOSE:
336 break;
337 default:
Andy Greenf7248f82013-01-16 14:35:12 +0800338
339 for (n = 0; n < wsi->count_active_extensions; n++) {
340 m = wsi->active_extensions[n]->callback(
341 wsi->protocol->owning_server,
342 wsi->active_extensions[n], wsi,
343 LWS_EXT_CALLBACK_PAYLOAD_TX,
344 wsi->active_extensions_user[n], &eff_buf, 0);
345 if (m < 0)
346 return -1;
347 }
Andy Greenb429d482013-01-16 12:21:29 +0800348 }
349
350 buf = (unsigned char *)eff_buf.token;
351 len = eff_buf.token_len;
Andy Green3182ece2013-01-20 17:08:31 +0800352#endif
Andy Greenb429d482013-01-16 12:21:29 +0800353
354 switch (wsi->ietf_spec_revision) {
Andy Greenb429d482013-01-16 12:21:29 +0800355 case 13:
356 if (masked7) {
357 pre += 4;
358 dropmask = &buf[0 - pre];
359 is_masked_bit = 0x80;
360 }
Andy Green5738c0e2013-01-21 09:53:35 +0800361
Andy Greenb429d482013-01-16 12:21:29 +0800362 switch (protocol & 0xf) {
363 case LWS_WRITE_TEXT:
Andy Green5738c0e2013-01-21 09:53:35 +0800364 n = LWS_WS_OPCODE_07__TEXT_FRAME;
Andy Greenb429d482013-01-16 12:21:29 +0800365 break;
366 case LWS_WRITE_BINARY:
Andy Green5738c0e2013-01-21 09:53:35 +0800367 n = LWS_WS_OPCODE_07__BINARY_FRAME;
Andy Greenb429d482013-01-16 12:21:29 +0800368 break;
369 case LWS_WRITE_CONTINUATION:
Andy Green5738c0e2013-01-21 09:53:35 +0800370 n = LWS_WS_OPCODE_07__CONTINUATION;
Andy Greenb429d482013-01-16 12:21:29 +0800371 break;
372
373 case LWS_WRITE_CLOSE:
Andy Green5738c0e2013-01-21 09:53:35 +0800374 n = LWS_WS_OPCODE_07__CLOSE;
Andy Greenb429d482013-01-16 12:21:29 +0800375
376 /*
Andy Green5738c0e2013-01-21 09:53:35 +0800377 * 06+ has a 2-byte status code in network order
378 * we can do this because we demand post-buf
Andy Greenb429d482013-01-16 12:21:29 +0800379 */
380
Andy Green623a98d2013-01-21 11:04:23 +0800381 if (wsi->u.ws.close_reason) {
Andy Green5738c0e2013-01-21 09:53:35 +0800382 /* reason codes count as data bytes */
383 buf -= 2;
Andy Green623a98d2013-01-21 11:04:23 +0800384 buf[0] = wsi->u.ws.close_reason >> 8;
385 buf[1] = wsi->u.ws.close_reason;
Andy Green5738c0e2013-01-21 09:53:35 +0800386 len += 2;
Andy Greenb429d482013-01-16 12:21:29 +0800387 }
388 break;
389 case LWS_WRITE_PING:
Andy Green5738c0e2013-01-21 09:53:35 +0800390 n = LWS_WS_OPCODE_07__PING;
Andy Greenb429d482013-01-16 12:21:29 +0800391 break;
392 case LWS_WRITE_PONG:
Andy Green5738c0e2013-01-21 09:53:35 +0800393 n = LWS_WS_OPCODE_07__PONG;
Andy Greenb429d482013-01-16 12:21:29 +0800394 break;
395 default:
Andy Greenb5b23192013-02-11 17:13:32 +0800396 lwsl_warn("lws_write: unknown write opc / protocol\n");
Andy Greenb429d482013-01-16 12:21:29 +0800397 return -1;
398 }
399
400 if (!(protocol & LWS_WRITE_NO_FIN))
401 n |= 1 << 7;
402
403 if (len < 126) {
404 pre += 2;
405 buf[-pre] = n;
406 buf[-pre + 1] = len | is_masked_bit;
407 } else {
408 if (len < 65536) {
409 pre += 4;
410 buf[-pre] = n;
411 buf[-pre + 1] = 126 | is_masked_bit;
412 buf[-pre + 2] = len >> 8;
413 buf[-pre + 3] = len;
414 } else {
415 pre += 10;
416 buf[-pre] = n;
417 buf[-pre + 1] = 127 | is_masked_bit;
418#if defined __LP64__
419 buf[-pre + 2] = (len >> 56) & 0x7f;
420 buf[-pre + 3] = len >> 48;
421 buf[-pre + 4] = len >> 40;
422 buf[-pre + 5] = len >> 32;
423#else
424 buf[-pre + 2] = 0;
425 buf[-pre + 3] = 0;
426 buf[-pre + 4] = 0;
427 buf[-pre + 5] = 0;
428#endif
429 buf[-pre + 6] = len >> 24;
430 buf[-pre + 7] = len >> 16;
431 buf[-pre + 8] = len >> 8;
432 buf[-pre + 9] = len;
433 }
434 }
435 break;
436 }
437
438 /*
439 * Deal with masking if we are in client -> server direction and
440 * the protocol demands it
441 */
442
Andy Green5738c0e2013-01-21 09:53:35 +0800443 if (wsi->mode == LWS_CONNMODE_WS_CLIENT) {
Andy Greenb429d482013-01-16 12:21:29 +0800444
Andy Green5738c0e2013-01-21 09:53:35 +0800445 if (libwebsocket_0405_frame_mask_generate(wsi)) {
Andy Greenb5b23192013-02-11 17:13:32 +0800446 lwsl_err("lws_write: frame mask generation failed\n");
Andy Greenfc7c5e42013-02-23 10:50:10 +0800447 return -1;
Andy Greenb429d482013-01-16 12:21:29 +0800448 }
449
Andy Green5738c0e2013-01-21 09:53:35 +0800450 /*
451 * in v7, just mask the payload
452 */
453 for (n = 4; n < (int)len + 4; n++)
Andy Greenb5b23192013-02-11 17:13:32 +0800454 dropmask[n] = dropmask[n] ^
455 wsi->u.ws.frame_masking_nonce_04[
456 (wsi->u.ws.frame_mask_index++) & 3];
Andy Green5738c0e2013-01-21 09:53:35 +0800457
458 if (dropmask)
459 /* copy the frame nonce into place */
460 memcpy(dropmask,
Andy Green623a98d2013-01-21 11:04:23 +0800461 wsi->u.ws.frame_masking_nonce_04, 4);
Andy Greenb429d482013-01-16 12:21:29 +0800462 }
463
464send_raw:
465
466#if 0
467 lwsl_debug("send %ld: ", len + post);
Andy Green0303db42013-01-17 14:46:43 +0800468 lwsl_hexdump(&buf[-pre], len + post);
Andy Greenb429d482013-01-16 12:21:29 +0800469#endif
470
Andy Green0303db42013-01-17 14:46:43 +0800471 switch (protocol) {
472 case LWS_WRITE_CLOSE:
Andy Greenb5b23192013-02-11 17:13:32 +0800473/* lwsl_hexdump(&buf[-pre], len + post); */
Andy Green0303db42013-01-17 14:46:43 +0800474 case LWS_WRITE_HTTP:
475 case LWS_WRITE_PONG:
476 case LWS_WRITE_PING:
Andy Greenfc7c5e42013-02-23 10:50:10 +0800477 return lws_issue_raw(wsi, (unsigned char *)buf - pre,
478 len + pre + post);
Andy Green0303db42013-01-17 14:46:43 +0800479 default:
480 break;
Andy Greenb429d482013-01-16 12:21:29 +0800481 }
482
483 /*
484 * give any active extensions a chance to munge the buffer
485 * before send. We pass in a pointer to an lws_tokens struct
486 * prepared with the default buffer and content length that's in
487 * there. Rather than rewrite the default buffer, extensions
488 * that expect to grow the buffer can adapt .token to
489 * point to their own per-connection buffer in the extension
490 * user allocation. By default with no extensions or no
491 * extension callback handling, just the normal input buffer is
492 * used then so it is efficient.
493 *
494 * callback returns 1 in case it wants to spill more buffers
495 */
496
Andy Greenfc7c5e42013-02-23 10:50:10 +0800497 n = lws_issue_raw_ext_access(wsi, buf - pre, len + pre + post);
498 if (n < 0)
499 return n;
500
501 return orig_len - ((len - pre + post) -n );
Andy Greenb429d482013-01-16 12:21:29 +0800502}
503
Peter Pentchev9a4fef72013-03-30 09:52:21 +0800504LWS_VISIBLE int libwebsockets_serve_http_file_fragment(
Andy Greenb5b23192013-02-11 17:13:32 +0800505 struct libwebsocket_context *context, struct libwebsocket *wsi)
Andy Greenb8b247d2013-01-22 07:20:08 +0800506{
Andy Greenfc7c5e42013-02-23 10:50:10 +0800507 int n, m;
Andy Greenb8b247d2013-01-22 07:20:08 +0800508
509 while (!lws_send_pipe_choked(wsi)) {
Andy Greenb5b23192013-02-11 17:13:32 +0800510 n = read(wsi->u.http.fd, context->service_buffer,
511 sizeof(context->service_buffer));
Andy Greenb8b247d2013-01-22 07:20:08 +0800512 if (n > 0) {
Andy Greenfc7c5e42013-02-23 10:50:10 +0800513 m = libwebsocket_write(wsi, context->service_buffer, n,
Andy Greenb5b23192013-02-11 17:13:32 +0800514 LWS_WRITE_HTTP);
Andy Greenfc7c5e42013-02-23 10:50:10 +0800515 if (m < 0)
516 return -1;
517
David Gauchard6c582282013-06-29 10:24:16 +0800518 wsi->u.http.filepos += m;
Andy Greenfc7c5e42013-02-23 10:50:10 +0800519 if (m != n)
520 /* adjust for what was not sent */
521 lseek(wsi->u.http.fd, m - n, SEEK_CUR);
Andy Greenb8b247d2013-01-22 07:20:08 +0800522 }
523
Andy Green5ab9c682013-02-10 20:58:04 +0800524 if (n < 0)
Andy Greenfc7c5e42013-02-23 10:50:10 +0800525 return -1; /* caller will close */
Andy Greenb8b247d2013-01-22 07:20:08 +0800526
David Gauchard6c582282013-06-29 10:24:16 +0800527 if (wsi->u.http.filepos == wsi->u.http.filelen) {
Andy Greenb8b247d2013-01-22 07:20:08 +0800528 wsi->state = WSI_STATE_HTTP;
529
530 if (wsi->protocol->callback)
David Gauchard6c582282013-06-29 10:24:16 +0800531 /* ignore callback returned value */
532 user_callback_handle_rxflow(
Andy Greenb5b23192013-02-11 17:13:32 +0800533 wsi->protocol->callback, context, wsi,
534 LWS_CALLBACK_HTTP_FILE_COMPLETION,
535 wsi->user_space, NULL, 0);
David Gauchard6c582282013-06-29 10:24:16 +0800536 return 1; /* >0 indicates completed */
Andy Greenb8b247d2013-01-22 07:20:08 +0800537 }
538 }
539
540 lwsl_notice("choked before able to send whole file (post)\n");
541 libwebsocket_callback_on_writable(context, wsi);
542
David Gauchard6c582282013-06-29 10:24:16 +0800543 return 0; /* indicates further processing must be done */
Andy Greenb8b247d2013-01-22 07:20:08 +0800544}
Andy Greenb429d482013-01-16 12:21:29 +0800545
546/**
547 * libwebsockets_serve_http_file() - Send a file back to the client using http
548 * @context: libwebsockets context
549 * @wsi: Websocket instance (available from user callback)
550 * @file: The file to issue over http
551 * @content_type: The http content type, eg, text/html
552 *
553 * This function is intended to be called from the callback in response
554 * to http requests from the client. It allows the callback to issue
555 * local files down the http link in a single step.
Andy Greenb8b247d2013-01-22 07:20:08 +0800556 *
557 * Returning <0 indicates error and the wsi should be closed. Returning
558 * >0 indicates the file was completely sent and the wsi should be closed.
559 * ==0 indicates the file transfer is started and needs more service later,
560 * the wsi should be left alone.
Andy Greenb429d482013-01-16 12:21:29 +0800561 */
562
Peter Pentchev9a4fef72013-03-30 09:52:21 +0800563LWS_VISIBLE int libwebsockets_serve_http_file(struct libwebsocket_context *context,
Andy Greenb429d482013-01-16 12:21:29 +0800564 struct libwebsocket *wsi, const char *file,
565 const char *content_type)
566{
Andy Greenb429d482013-01-16 12:21:29 +0800567 struct stat stat_buf;
Andy Greenb8b247d2013-01-22 07:20:08 +0800568 unsigned char *p = context->service_buffer;
569 int ret = 0;
Andy Greenb429d482013-01-16 12:21:29 +0800570
Andy Greenb8b247d2013-01-22 07:20:08 +0800571 wsi->u.http.fd = open(file, O_RDONLY
Andy Greenb429d482013-01-16 12:21:29 +0800572#ifdef WIN32
Andy Greenb8b247d2013-01-22 07:20:08 +0800573 | _O_BINARY
Andy Greenb429d482013-01-16 12:21:29 +0800574#endif
Andy Greenb8b247d2013-01-22 07:20:08 +0800575 );
576
577 if (wsi->u.http.fd < 1) {
Andy Green66986b22013-05-03 21:13:35 +0800578 lwsl_err("Unable to open '%s'\n", file);
Andy Greenb5b23192013-02-11 17:13:32 +0800579 p += sprintf((char *)p,
580 "HTTP/1.0 400 Bad\x0d\x0aServer: libwebsockets\x0d\x0a\x0d\x0a"
Andy Greenb429d482013-01-16 12:21:29 +0800581 );
Andy Greenb8b247d2013-01-22 07:20:08 +0800582 wsi->u.http.fd = 0;
Andy Greenfc7c5e42013-02-23 10:50:10 +0800583 /* too small to care about partial, closing anyway */
Andy Greenb8b247d2013-01-22 07:20:08 +0800584 libwebsocket_write(wsi, context->service_buffer,
585 p - context->service_buffer, LWS_WRITE_HTTP);
Andy Greenb429d482013-01-16 12:21:29 +0800586
587 return -1;
588 }
589
Andy Greenb8b247d2013-01-22 07:20:08 +0800590 fstat(wsi->u.http.fd, &stat_buf);
Andy Green623a98d2013-01-21 11:04:23 +0800591 wsi->u.http.filelen = stat_buf.st_size;
Andy Greenb5b23192013-02-11 17:13:32 +0800592 p += sprintf((char *)p,
Andy Greend579a7d2013-02-12 12:53:36 +0800593"HTTP/1.0 200 OK\x0d\x0aServer: libwebsockets\x0d\x0a""Content-Type: %s\x0d\x0a",
Andy Greenb5b23192013-02-11 17:13:32 +0800594 content_type);
595 p += sprintf((char *)p,
596 "Content-Length: %u\x0d\x0a\x0d\x0a",
Andy Greenb429d482013-01-16 12:21:29 +0800597 (unsigned int)stat_buf.st_size);
598
Andy Greenb8b247d2013-01-22 07:20:08 +0800599 ret = libwebsocket_write(wsi, context->service_buffer,
600 p - context->service_buffer, LWS_WRITE_HTTP);
Andy Greenfc7c5e42013-02-23 10:50:10 +0800601 if (ret != (p - context->service_buffer)) {
602 lwsl_err("_write returned %d from %d\n", ret, (p - context->service_buffer));
Andy Greenb8b247d2013-01-22 07:20:08 +0800603 return -1;
Andy Greenfc7c5e42013-02-23 10:50:10 +0800604 }
Andy Greenb429d482013-01-16 12:21:29 +0800605
Andy Green623a98d2013-01-21 11:04:23 +0800606 wsi->u.http.filepos = 0;
Andy Greenb429d482013-01-16 12:21:29 +0800607 wsi->state = WSI_STATE_HTTP_ISSUING_FILE;
608
Andy Greenb8b247d2013-01-22 07:20:08 +0800609 return libwebsockets_serve_http_file_fragment(context, wsi);
Andy Greenb429d482013-01-16 12:21:29 +0800610}
611