blob: 4547a34ef3988371edaf42cb4cf6dc32b633d0bf [file] [log] [blame]
Andy Greena1ce6be2013-01-18 11:43:21 +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
23#include "private-libwebsockets.h"
24
Andreas Pakulat68bd4bd2013-10-28 15:18:04 +010025#if defined(WIN32) || defined(_WIN32)
Andy Greena1ce6be2013-01-18 11:43:21 +080026#include <tchar.h>
27#include <io.h>
28#else
29#ifdef LWS_BUILTIN_GETIFADDRS
30#include <getifaddrs.h>
31#else
32#include <ifaddrs.h>
33#endif
34#include <sys/un.h>
35#include <sys/socket.h>
36#include <netdb.h>
37#endif
38
39#ifdef LWS_OPENSSL_SUPPORT
Andy Greena1ce6be2013-01-18 11:43:21 +080040
41static void
42libwebsockets_decode_ssl_error(void)
43{
44 char buf[256];
45 u_long err;
46
47 while ((err = ERR_get_error()) != 0) {
48 ERR_error_string_n(err, buf, sizeof(buf));
Joakim Soderbergb82b0dd2013-02-22 09:28:15 +080049 lwsl_err("*** %lu %s\n", err, buf);
Andy Greena1ce6be2013-01-18 11:43:21 +080050 }
51}
52#endif
53
Andy Greena1ce6be2013-01-18 11:43:21 +080054struct libwebsocket *
55libwebsocket_create_new_server_wsi(struct libwebsocket_context *context)
56{
57 struct libwebsocket *new_wsi;
Andy Greena1ce6be2013-01-18 11:43:21 +080058
59 new_wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket));
60 if (new_wsi == NULL) {
61 lwsl_err("Out of memory for new connection\n");
62 return NULL;
63 }
64
65 memset(new_wsi, 0, sizeof(struct libwebsocket));
Andy Green3182ece2013-01-20 17:08:31 +080066#ifndef LWS_NO_EXTENSIONS
Andy Greena1ce6be2013-01-18 11:43:21 +080067 new_wsi->count_active_extensions = 0;
Andy Green3182ece2013-01-20 17:08:31 +080068#endif
Andy Greena1ce6be2013-01-18 11:43:21 +080069 new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
70
71 /* intialize the instance struct */
72
73 new_wsi->state = WSI_STATE_HTTP;
Andy Greena1ce6be2013-01-18 11:43:21 +080074 new_wsi->mode = LWS_CONNMODE_HTTP_SERVING;
Andy Green224149a2013-02-11 21:43:41 +080075 new_wsi->hdr_parsing_completed = 0;
Andy Greena1ce6be2013-01-18 11:43:21 +080076
Andy Green16ab3182013-02-10 18:02:31 +080077 if (lws_allocate_header_table(new_wsi)) {
78 free(new_wsi);
79 return NULL;
Andy Greena1ce6be2013-01-18 11:43:21 +080080 }
81
82 /*
83 * these can only be set once the protocol is known
84 * we set an unestablished connection's protocol pointer
85 * to the start of the supported list, so it can look
86 * for matching ones during the handshake
87 */
88 new_wsi->protocol = context->protocols;
89 new_wsi->user_space = NULL;
Andy Greena1ce6be2013-01-18 11:43:21 +080090 new_wsi->ietf_spec_revision = 0;
91
Andy Green76b6ea12014-02-15 19:25:50 +080092 /*
93 * outermost create notification for wsi
94 * no user_space because no protocol selection
95 */
96 context->protocols[0].callback(context, new_wsi,
97 LWS_CALLBACK_WSI_CREATE, NULL, NULL, 0);
98
Andy Greena1ce6be2013-01-18 11:43:21 +080099 return new_wsi;
100}
101
102int lws_server_socket_service(struct libwebsocket_context *context,
103 struct libwebsocket *wsi, struct pollfd *pollfd)
104{
Andy Greena1ce6be2013-01-18 11:43:21 +0800105 struct libwebsocket *new_wsi;
106 int accept_fd;
Bob Robertsac049112013-04-25 09:16:30 +0800107 socklen_t clilen;
Andy Greena1ce6be2013-01-18 11:43:21 +0800108 struct sockaddr_in cli_addr;
109 int n;
Andy Greena1ce6be2013-01-18 11:43:21 +0800110 ssize_t len;
Edwin van den Oetelaar0794af92013-01-28 21:53:53 +0800111#ifdef LWS_OPENSSL_SUPPORT
112 int m;
Andy Green23c5f2e2013-02-06 15:43:00 +0900113#ifndef USE_CYASSL
Andy Green1167dd42013-01-28 17:45:34 +0800114 BIO *bio;
Edwin van den Oetelaar0794af92013-01-28 21:53:53 +0800115#endif
Andy Green23c5f2e2013-02-06 15:43:00 +0900116#endif
Andy Greena1ce6be2013-01-18 11:43:21 +0800117
118 switch (wsi->mode) {
119
120 case LWS_CONNMODE_HTTP_SERVING:
Andy Green7cf6cb02013-05-19 14:04:10 +0800121 case LWS_CONNMODE_HTTP_SERVING_ACCEPTED:
Andy Greena1ce6be2013-01-18 11:43:21 +0800122
123 /* handle http headers coming in */
124
Andy Green2764eba2013-12-09 14:16:17 +0800125 /* pending truncated sends have uber priority */
126
127 if (wsi->truncated_send_malloc) {
128 if (pollfd->revents & POLLOUT)
129 lws_issue_raw(wsi, wsi->truncated_send_malloc +
130 wsi->truncated_send_offset,
131 wsi->truncated_send_len);
132 /*
133 * we can't afford to allow input processing send
134 * something new, so spin around he event loop until
135 * he doesn't have any partials
136 */
137 break;
138 }
139
Andy Greena1ce6be2013-01-18 11:43:21 +0800140 /* any incoming data ready? */
141
142 if (pollfd->revents & POLLIN) {
143
144 #ifdef LWS_OPENSSL_SUPPORT
145 if (wsi->ssl)
Andy Greenb5b23192013-02-11 17:13:32 +0800146 len = SSL_read(wsi->ssl,
147 context->service_buffer,
148 sizeof(context->service_buffer));
Andy Greena1ce6be2013-01-18 11:43:21 +0800149 else
150 #endif
Andy Greenb5b23192013-02-11 17:13:32 +0800151 len = recv(pollfd->fd,
152 context->service_buffer,
153 sizeof(context->service_buffer), 0);
Andy Greena1ce6be2013-01-18 11:43:21 +0800154
155 if (len < 0) {
156 lwsl_debug("Socket read returned %d\n", len);
157 if (errno != EINTR && errno != EAGAIN)
Andy Greenb5b23192013-02-11 17:13:32 +0800158 libwebsocket_close_and_free_session(
159 context, wsi,
160 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greena1ce6be2013-01-18 11:43:21 +0800161 return 0;
162 }
163 if (!len) {
Andy Green224149a2013-02-11 21:43:41 +0800164 lwsl_info("lws_server_skt_srv: read 0 len\n");
165 /* lwsl_info(" state=%d\n", wsi->state); */
166 if (!wsi->hdr_parsing_completed)
167 free(wsi->u.hdr.ah);
Andy Greenb5b23192013-02-11 17:13:32 +0800168 libwebsocket_close_and_free_session(
169 context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
Andy Greena1ce6be2013-01-18 11:43:21 +0800170 return 0;
171 }
172
Andy Green2764eba2013-12-09 14:16:17 +0800173 /* hm this may want to send (via HTTP callback for example) */
174
Andy Greenb5b23192013-02-11 17:13:32 +0800175 n = libwebsocket_read(context, wsi,
176 context->service_buffer, len);
Andy Greena1ce6be2013-01-18 11:43:21 +0800177 if (n < 0)
178 /* we closed wsi */
179 return 0;
Andy Green2764eba2013-12-09 14:16:17 +0800180
181 /* hum he may have used up the writability above */
Andy Green2764eba2013-12-09 14:16:17 +0800182 break;
Andy Greena1ce6be2013-01-18 11:43:21 +0800183 }
184
185 /* this handles POLLOUT for http serving fragments */
186
187 if (!(pollfd->revents & POLLOUT))
188 break;
189
190 /* one shot */
Andy Green91f19d82013-12-21 11:18:34 +0800191 lws_change_pollfd(wsi, POLLOUT, 0);
Andy Green7a132792013-12-18 09:48:26 +0800192
Andy Green54cb3462013-02-14 22:23:54 +0800193 if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE) {
194 n = user_callback_handle_rxflow(
195 wsi->protocol->callback,
196 wsi->protocol->owning_server,
197 wsi, LWS_CALLBACK_HTTP_WRITEABLE,
198 wsi->user_space,
199 NULL,
200 0);
201 if (n < 0)
202 libwebsocket_close_and_free_session(
203 context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
Andy Greena1ce6be2013-01-18 11:43:21 +0800204 break;
Andy Green54cb3462013-02-14 22:23:54 +0800205 }
Andy Greena1ce6be2013-01-18 11:43:21 +0800206
Andy Greenb5b23192013-02-11 17:13:32 +0800207 /* nonzero for completion or error */
208 if (libwebsockets_serve_http_file_fragment(context, wsi))
Andy Greena1ce6be2013-01-18 11:43:21 +0800209 libwebsocket_close_and_free_session(context, wsi,
210 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greena1ce6be2013-01-18 11:43:21 +0800211 break;
212
213 case LWS_CONNMODE_SERVER_LISTENER:
214
215 /* pollin means a client has connected to us then */
216
217 if (!(pollfd->revents & POLLIN))
218 break;
219
220 /* listen socket got an unencrypted connection... */
221
222 clilen = sizeof(cli_addr);
Andy Greene000a702013-01-29 12:37:35 +0800223 lws_latency_pre(context, wsi);
Andy Greena1ce6be2013-01-18 11:43:21 +0800224 accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
225 &clilen);
Andy Greenb5b23192013-02-11 17:13:32 +0800226 lws_latency(context, wsi,
227 "unencrypted accept LWS_CONNMODE_SERVER_LISTENER",
228 accept_fd, accept_fd >= 0);
Andy Greena1ce6be2013-01-18 11:43:21 +0800229 if (accept_fd < 0) {
Andy Greene2160712013-01-28 12:19:10 +0800230 if (errno == EAGAIN || errno == EWOULDBLOCK) {
231 lwsl_debug("accept asks to try again\n");
232 break;
233 }
Andy Greena1ce6be2013-01-18 11:43:21 +0800234 lwsl_warn("ERROR on accept: %s\n", strerror(errno));
235 break;
236 }
237
Andy Greena690cd02013-02-09 12:25:31 +0800238 lws_set_socket_options(context, accept_fd);
Andy Green6f047ee2013-01-28 11:23:52 +0800239
Andy Greena1ce6be2013-01-18 11:43:21 +0800240 /*
241 * look at who we connected to and give user code a chance
242 * to reject based on client IP. There's no protocol selected
243 * yet so we issue this to protocols[0]
244 */
245
246 if ((context->protocols[0].callback)(context, wsi,
247 LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
Edwin van den Oetelaar8c8a8e12013-02-20 20:56:59 +0800248 NULL, (void *)(long)accept_fd, 0)) {
Andy Greena1ce6be2013-01-18 11:43:21 +0800249 lwsl_debug("Callback denied network connection\n");
250 compatible_close(accept_fd);
251 break;
252 }
253
254 new_wsi = libwebsocket_create_new_server_wsi(context);
255 if (new_wsi == NULL) {
256 compatible_close(accept_fd);
257 break;
258 }
259
260 new_wsi->sock = accept_fd;
261
Andy Green176de272014-02-15 14:36:02 +0800262 /* the transport is accepted... give him time to negotiate */
263 libwebsocket_set_timeout(new_wsi,
264 PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
265 AWAITING_TIMEOUT);
266
Alexandre Erwin Ittnerd578f572014-02-06 23:15:51 -0200267 /*
268 * A new connection was accepted. Give the user a chance to
269 * set properties of the newly created wsi. There's no protocol
270 * selected yet so we issue this to protocols[0]
271 */
272
273 (context->protocols[0].callback)(context, new_wsi,
274 LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, NULL, NULL, 0);
275
276
Andy Greena1ce6be2013-01-18 11:43:21 +0800277#ifdef LWS_OPENSSL_SUPPORT
278 new_wsi->ssl = NULL;
Andy Greene2160712013-01-28 12:19:10 +0800279 if (!context->use_ssl) {
Andy Greena1ce6be2013-01-18 11:43:21 +0800280#endif
Andy Greene2160712013-01-28 12:19:10 +0800281
Andy Greena1ce6be2013-01-18 11:43:21 +0800282 lwsl_debug("accepted new conn port %u on fd=%d\n",
283 ntohs(cli_addr.sin_port), accept_fd);
284
Andy Greene2160712013-01-28 12:19:10 +0800285 insert_wsi_socket_into_fds(context, new_wsi);
286 break;
287#ifdef LWS_OPENSSL_SUPPORT
288 }
289
290 new_wsi->ssl = SSL_new(context->ssl_ctx);
291 if (new_wsi->ssl == NULL) {
292 lwsl_err("SSL_new failed: %s\n",
293 ERR_error_string(SSL_get_error(
294 new_wsi->ssl, 0), NULL));
295 libwebsockets_decode_ssl_error();
296 free(new_wsi);
297 compatible_close(accept_fd);
298 break;
299 }
300
301 SSL_set_ex_data(new_wsi->ssl,
302 openssl_websocket_private_data_index, context);
303
304 SSL_set_fd(new_wsi->ssl, accept_fd);
305
Joakim Soderbergb378ce92013-02-06 15:29:18 +0900306 #ifdef USE_CYASSL
307 CyaSSL_set_using_nonblock(new_wsi->ssl, 1);
308 #else
Andy Green1167dd42013-01-28 17:45:34 +0800309 bio = SSL_get_rbio(new_wsi->ssl);
310 if (bio)
311 BIO_set_nbio(bio, 1); /* nonblocking */
312 else
313 lwsl_notice("NULL rbio\n");
314 bio = SSL_get_wbio(new_wsi->ssl);
315 if (bio)
316 BIO_set_nbio(bio, 1); /* nonblocking */
317 else
318 lwsl_notice("NULL rbio\n");
Joakim Soderbergb378ce92013-02-06 15:29:18 +0900319 #endif
Andy Green1167dd42013-01-28 17:45:34 +0800320
Andy Greenb5b23192013-02-11 17:13:32 +0800321 /*
Andy Greene2160712013-01-28 12:19:10 +0800322 * we are not accepted yet, but we need to enter ourselves
323 * as a live connection. That way we can retry when more
324 * pieces come if we're not sorted yet
325 */
326
327 wsi = new_wsi;
328 wsi->mode = LWS_CONNMODE_SSL_ACK_PENDING;
329 insert_wsi_socket_into_fds(context, wsi);
330
Andy Greenba85a7d2013-01-28 17:20:41 +0800331 libwebsocket_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT,
332 AWAITING_TIMEOUT);
333
Andy Greenb5b23192013-02-11 17:13:32 +0800334 lwsl_info("inserted SSL accept into fds, trying SSL_accept\n");
Andy Greene2160712013-01-28 12:19:10 +0800335
336 /* fallthru */
337
338 case LWS_CONNMODE_SSL_ACK_PENDING:
339
Andy Green91f19d82013-12-21 11:18:34 +0800340 lws_change_pollfd(wsi, POLLOUT, 0);
Andy Green7a132792013-12-18 09:48:26 +0800341
Andy Greene000a702013-01-29 12:37:35 +0800342 lws_latency_pre(context, wsi);
James Devine5b34c972013-12-14 11:41:29 +0800343
344 n = recv(wsi->sock, context->service_buffer,
345 sizeof(context->service_buffer), MSG_PEEK);
346
347 /*
348 * optionally allow non-SSL connect on SSL listening socket
349 * This is disabled by default, if enabled it goes around any
350 * SSL-level access control (eg, client-side certs) so leave
351 * it disabled unless you know it's not a problem for you
352 */
353
354 if (context->allow_non_ssl_on_ssl_port && n >= 1 &&
355 context->service_buffer[0] >= ' ') {
356 /*
357 * TLS content-type for Handshake is 0x16
358 * TLS content-type for ChangeCipherSpec Record is 0x14
359 *
360 * A non-ssl session will start with the HTTP method in
361 * ASCII. If we see it's not a legit SSL handshake
362 * kill the SSL for this connection and try to handle
363 * as a HTTP connection upgrade directly.
364 */
365 wsi->use_ssl = 0;
366 SSL_shutdown(wsi->ssl);
367 SSL_free(wsi->ssl);
368 wsi->ssl = NULL;
369 goto accepted;
370 }
371
372 /* normal SSL connection processing path */
373
Andy Greene2160712013-01-28 12:19:10 +0800374 n = SSL_accept(wsi->ssl);
Andy Greenb5b23192013-02-11 17:13:32 +0800375 lws_latency(context, wsi,
376 "SSL_accept LWS_CONNMODE_SSL_ACK_PENDING\n", n, n == 1);
Andy Greene2160712013-01-28 12:19:10 +0800377
378 if (n != 1) {
379 m = SSL_get_error(wsi->ssl, n);
Andy Greenb5b23192013-02-11 17:13:32 +0800380 lwsl_debug("SSL_accept failed %d / %s\n",
381 m, ERR_error_string(m, NULL));
Andy Greene2160712013-01-28 12:19:10 +0800382
383 if (m == SSL_ERROR_WANT_READ) {
Andy Green91f19d82013-12-21 11:18:34 +0800384 lws_change_pollfd(wsi, 0, POLLIN);
Andy Greene2160712013-01-28 12:19:10 +0800385 lwsl_info("SSL_ERROR_WANT_READ\n");
386 break;
387 }
388 if (m == SSL_ERROR_WANT_WRITE) {
Andy Green91f19d82013-12-21 11:18:34 +0800389 lws_change_pollfd(wsi, 0, POLLOUT);
Andy Greene2160712013-01-28 12:19:10 +0800390 break;
391 }
392 lwsl_debug("SSL_accept failed skt %u: %s\n",
James Devine5b34c972013-12-14 11:41:29 +0800393 pollfd->fd,
394 ERR_error_string(m, NULL));
Andy Greenb5b23192013-02-11 17:13:32 +0800395 libwebsocket_close_and_free_session(context, wsi,
James Devine5b34c972013-12-14 11:41:29 +0800396 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greene2160712013-01-28 12:19:10 +0800397 break;
398 }
399
James Devine5b34c972013-12-14 11:41:29 +0800400accepted:
Andy Green176de272014-02-15 14:36:02 +0800401 /* OK, we are accepted... give him some time to negotiate */
402 libwebsocket_set_timeout(wsi,
403 PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
404 AWAITING_TIMEOUT);
Andy Greenba85a7d2013-01-28 17:20:41 +0800405
Andy Greene2160712013-01-28 12:19:10 +0800406 wsi->mode = LWS_CONNMODE_HTTP_SERVING;
407
Andy Green35517092013-02-11 20:10:56 +0800408 lwsl_debug("accepted new SSL conn\n");
Andy Greena1ce6be2013-01-18 11:43:21 +0800409 break;
Andy Greene2160712013-01-28 12:19:10 +0800410#endif
411
Andy Greena1ce6be2013-01-18 11:43:21 +0800412 default:
413 break;
414 }
415 return 0;
416}
Joakim Soderberg63ff1202013-02-11 17:52:23 +0100417
Andy Green4e7a1332013-11-11 07:30:33 +0800418
419static const char *err400[] = {
420 "Bad Request",
421 "Unauthorized",
422 "Payment Required",
423 "Forbidden",
424 "Not Found",
425 "Method Not Allowed",
426 "Not Acceptable",
427 "Proxy Auth Required",
428 "Request Timeout",
429 "Conflict",
430 "Gone",
431 "Length Required",
432 "Precondition Failed",
433 "Request Entity Too Large",
434 "Request URI too Long",
435 "Unsupported Media Type",
436 "Requested Range Not Satisfiable",
437 "Expectation Failed"
438};
439
440static const char *err500[] = {
441 "Internal Server Error",
442 "Not Implemented",
443 "Bad Gateway",
444 "Service Unavailable",
445 "Gateway Timeout",
446 "HTTP Version Not Supported"
447};
448
449/**
450 * libwebsockets_return_http_status() - Return simple http status
451 * @context: libwebsockets context
452 * @wsi: Websocket instance (available from user callback)
453 * @code: Status index, eg, 404
454 * @html_body: User-readable HTML description, or NULL
455 *
456 * Helper to report HTTP errors back to the client cleanly and
457 * consistently
458 */
459LWS_VISIBLE int libwebsockets_return_http_status(
460 struct libwebsocket_context *context, struct libwebsocket *wsi,
461 unsigned int code, const char *html_body)
462{
463 int n, m;
464 const char *description = "";
465
466 if (!html_body)
467 html_body = "";
468
469 if (code >= 400 && code < (400 + ARRAY_SIZE(err400)))
470 description = err400[code - 400];
471 if (code >= 500 && code < (500 + ARRAY_SIZE(err500)))
472 description = err500[code - 500];
473
474 n = sprintf((char *)context->service_buffer,
475 "HTTP/1.0 %u %s\x0d\x0a"
476 "Server: libwebsockets\x0d\x0a"
477 "Mime-Type: text/html\x0d\x0a\x0d\x0a"
478 "<h1>%u %s</h1>%s",
479 code, description, code, description, html_body);
480
481 lwsl_info((const char *)context->service_buffer);
482
483 m = libwebsocket_write(wsi, context->service_buffer, n, LWS_WRITE_HTTP);
484
485 return m;
486}
487
488/**
489 * libwebsockets_serve_http_file() - Send a file back to the client using http
490 * @context: libwebsockets context
491 * @wsi: Websocket instance (available from user callback)
492 * @file: The file to issue over http
493 * @content_type: The http content type, eg, text/html
494 * @other_headers: NULL or pointer to \0-terminated other header string
495 *
496 * This function is intended to be called from the callback in response
497 * to http requests from the client. It allows the callback to issue
498 * local files down the http link in a single step.
499 *
500 * Returning <0 indicates error and the wsi should be closed. Returning
501 * >0 indicates the file was completely sent and the wsi should be closed.
502 * ==0 indicates the file transfer is started and needs more service later,
503 * the wsi should be left alone.
504 */
505
506LWS_VISIBLE int libwebsockets_serve_http_file(
507 struct libwebsocket_context *context,
508 struct libwebsocket *wsi, const char *file,
509 const char *content_type, const char *other_headers)
510{
511 struct stat stat_buf;
512 unsigned char *p = context->service_buffer;
513 int ret = 0;
514 int n;
515
516 wsi->u.http.fd = open(file, O_RDONLY
517#ifdef WIN32
518 | _O_BINARY
519#endif
520 );
521
522 if (wsi->u.http.fd < 1) {
523 lwsl_err("Unable to open '%s'\n", file);
524 libwebsockets_return_http_status(context, wsi,
525 HTTP_STATUS_NOT_FOUND, NULL);
526 wsi->u.http.fd = -1;
527 return -1;
528 }
529
530 fstat(wsi->u.http.fd, &stat_buf);
531 wsi->u.http.filelen = stat_buf.st_size;
532 p += sprintf((char *)p,
533"HTTP/1.0 200 OK\x0d\x0aServer: libwebsockets\x0d\x0a""Content-Type: %s\x0d\x0a",
534 content_type);
535 if (other_headers) {
536 n = strlen(other_headers);
537 memcpy(p, other_headers, n);
538 p += n;
539 }
540 p += sprintf((char *)p,
541 "Content-Length: %u\x0d\x0a\x0d\x0a",
542 (unsigned int)stat_buf.st_size);
543
544 ret = libwebsocket_write(wsi, context->service_buffer,
545 p - context->service_buffer, LWS_WRITE_HTTP);
546 if (ret != (p - context->service_buffer)) {
547 lwsl_err("_write returned %d from %d\n", ret, (p - context->service_buffer));
548 return -1;
549 }
550
551 wsi->u.http.filepos = 0;
552 wsi->state = WSI_STATE_HTTP_ISSUING_FILE;
553
554 return libwebsockets_serve_http_file_fragment(context, wsi);
555}
556