blob: 1a310ad3de8f9efeaa93fa55eab31fa10573fc0a [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>
Andy Greena1ce6be2013-01-18 11:43:21 +080027#else
28#ifdef LWS_BUILTIN_GETIFADDRS
29#include <getifaddrs.h>
30#else
31#include <ifaddrs.h>
32#endif
33#include <sys/un.h>
34#include <sys/socket.h>
35#include <netdb.h>
36#endif
37
38#ifdef LWS_OPENSSL_SUPPORT
Andy Greena1ce6be2013-01-18 11:43:21 +080039
40static void
41libwebsockets_decode_ssl_error(void)
42{
43 char buf[256];
44 u_long err;
45
46 while ((err = ERR_get_error()) != 0) {
47 ERR_error_string_n(err, buf, sizeof(buf));
Joakim Soderbergb82b0dd2013-02-22 09:28:15 +080048 lwsl_err("*** %lu %s\n", err, buf);
Andy Greena1ce6be2013-01-18 11:43:21 +080049 }
50}
51#endif
52
Andy Greena1ce6be2013-01-18 11:43:21 +080053struct libwebsocket *
54libwebsocket_create_new_server_wsi(struct libwebsocket_context *context)
55{
56 struct libwebsocket *new_wsi;
Andy Greena1ce6be2013-01-18 11:43:21 +080057
58 new_wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket));
59 if (new_wsi == NULL) {
60 lwsl_err("Out of memory for new connection\n");
61 return NULL;
62 }
63
64 memset(new_wsi, 0, sizeof(struct libwebsocket));
Andy Green3182ece2013-01-20 17:08:31 +080065#ifndef LWS_NO_EXTENSIONS
Andy Greena1ce6be2013-01-18 11:43:21 +080066 new_wsi->count_active_extensions = 0;
Andy Green3182ece2013-01-20 17:08:31 +080067#endif
Andy Greena1ce6be2013-01-18 11:43:21 +080068 new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
69
70 /* intialize the instance struct */
71
72 new_wsi->state = WSI_STATE_HTTP;
Andy Greena1ce6be2013-01-18 11:43:21 +080073 new_wsi->mode = LWS_CONNMODE_HTTP_SERVING;
Andy Green224149a2013-02-11 21:43:41 +080074 new_wsi->hdr_parsing_completed = 0;
Andy Greena1ce6be2013-01-18 11:43:21 +080075
Andy Green16ab3182013-02-10 18:02:31 +080076 if (lws_allocate_header_table(new_wsi)) {
77 free(new_wsi);
78 return NULL;
Andy Greena1ce6be2013-01-18 11:43:21 +080079 }
80
81 /*
82 * these can only be set once the protocol is known
83 * we set an unestablished connection's protocol pointer
84 * to the start of the supported list, so it can look
85 * for matching ones during the handshake
86 */
87 new_wsi->protocol = context->protocols;
88 new_wsi->user_space = NULL;
Andy Greena1ce6be2013-01-18 11:43:21 +080089 new_wsi->ietf_spec_revision = 0;
90
Andy Green76b6ea12014-02-15 19:25:50 +080091 /*
92 * outermost create notification for wsi
93 * no user_space because no protocol selection
94 */
95 context->protocols[0].callback(context, new_wsi,
96 LWS_CALLBACK_WSI_CREATE, NULL, NULL, 0);
97
Andy Greena1ce6be2013-01-18 11:43:21 +080098 return new_wsi;
99}
100
101int lws_server_socket_service(struct libwebsocket_context *context,
Patrick Gansterer73882e42014-03-29 08:25:58 +0100102 struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd)
Andy Greena1ce6be2013-01-18 11:43:21 +0800103{
Andy Greena1ce6be2013-01-18 11:43:21 +0800104 struct libwebsocket *new_wsi;
105 int accept_fd;
Bob Robertsac049112013-04-25 09:16:30 +0800106 socklen_t clilen;
Andy Greena1ce6be2013-01-18 11:43:21 +0800107 struct sockaddr_in cli_addr;
108 int n;
Patrick Ganstererac49f1e2014-03-30 10:18:51 +0200109 int len;
Edwin van den Oetelaar0794af92013-01-28 21:53:53 +0800110#ifdef LWS_OPENSSL_SUPPORT
111 int m;
Andy Green23c5f2e2013-02-06 15:43:00 +0900112#ifndef USE_CYASSL
Andy Green1167dd42013-01-28 17:45:34 +0800113 BIO *bio;
Edwin van den Oetelaar0794af92013-01-28 21:53:53 +0800114#endif
Andy Green23c5f2e2013-02-06 15:43:00 +0900115#endif
Andy Greena1ce6be2013-01-18 11:43:21 +0800116
117 switch (wsi->mode) {
118
119 case LWS_CONNMODE_HTTP_SERVING:
Andy Green7cf6cb02013-05-19 14:04:10 +0800120 case LWS_CONNMODE_HTTP_SERVING_ACCEPTED:
Andy Greena1ce6be2013-01-18 11:43:21 +0800121
122 /* handle http headers coming in */
123
Andy Green2764eba2013-12-09 14:16:17 +0800124 /* pending truncated sends have uber priority */
125
126 if (wsi->truncated_send_malloc) {
Patrick Ganstererb47f87b2014-03-30 09:18:05 +0200127 if (pollfd->revents & LWS_POLLOUT)
Andy Green2764eba2013-12-09 14:16:17 +0800128 lws_issue_raw(wsi, wsi->truncated_send_malloc +
129 wsi->truncated_send_offset,
130 wsi->truncated_send_len);
131 /*
132 * we can't afford to allow input processing send
133 * something new, so spin around he event loop until
134 * he doesn't have any partials
135 */
136 break;
137 }
138
Andy Greena1ce6be2013-01-18 11:43:21 +0800139 /* any incoming data ready? */
140
Patrick Ganstererb47f87b2014-03-30 09:18:05 +0200141 if (pollfd->revents & LWS_POLLIN) {
Andy Greena1ce6be2013-01-18 11:43:21 +0800142
143 #ifdef LWS_OPENSSL_SUPPORT
144 if (wsi->ssl)
Andy Greenb5b23192013-02-11 17:13:32 +0800145 len = SSL_read(wsi->ssl,
146 context->service_buffer,
147 sizeof(context->service_buffer));
Andy Greena1ce6be2013-01-18 11:43:21 +0800148 else
149 #endif
Andy Greenb5b23192013-02-11 17:13:32 +0800150 len = recv(pollfd->fd,
151 context->service_buffer,
152 sizeof(context->service_buffer), 0);
Andy Greena1ce6be2013-01-18 11:43:21 +0800153
154 if (len < 0) {
155 lwsl_debug("Socket read returned %d\n", len);
Patrick Gansterer2dbd8372014-02-28 12:37:52 +0100156 if (LWS_ERRNO != LWS_EINTR && LWS_ERRNO != LWS_EAGAIN)
Andy Greenb5b23192013-02-11 17:13:32 +0800157 libwebsocket_close_and_free_session(
158 context, wsi,
159 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greena1ce6be2013-01-18 11:43:21 +0800160 return 0;
161 }
162 if (!len) {
Andy Green224149a2013-02-11 21:43:41 +0800163 lwsl_info("lws_server_skt_srv: read 0 len\n");
164 /* lwsl_info(" state=%d\n", wsi->state); */
165 if (!wsi->hdr_parsing_completed)
166 free(wsi->u.hdr.ah);
Andy Greenb5b23192013-02-11 17:13:32 +0800167 libwebsocket_close_and_free_session(
168 context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
Andy Greena1ce6be2013-01-18 11:43:21 +0800169 return 0;
170 }
171
Andy Green2764eba2013-12-09 14:16:17 +0800172 /* hm this may want to send (via HTTP callback for example) */
173
Andy Greenb5b23192013-02-11 17:13:32 +0800174 n = libwebsocket_read(context, wsi,
175 context->service_buffer, len);
Andy Greena1ce6be2013-01-18 11:43:21 +0800176 if (n < 0)
177 /* we closed wsi */
178 return 0;
Andy Green2764eba2013-12-09 14:16:17 +0800179
180 /* hum he may have used up the writability above */
Andy Green2764eba2013-12-09 14:16:17 +0800181 break;
Andy Greena1ce6be2013-01-18 11:43:21 +0800182 }
183
184 /* this handles POLLOUT for http serving fragments */
185
Patrick Ganstererb47f87b2014-03-30 09:18:05 +0200186 if (!(pollfd->revents & LWS_POLLOUT))
Andy Greena1ce6be2013-01-18 11:43:21 +0800187 break;
188
189 /* one shot */
Patrick Ganstererb47f87b2014-03-30 09:18:05 +0200190 lws_change_pollfd(wsi, LWS_POLLOUT, 0);
Andrew Canaday9769f4f2014-03-23 13:25:07 +0800191#ifdef LWS_USE_LIBEV
Andy Green4dd33852014-04-01 08:36:36 +0800192 if (LWS_LIBEV_ENABLED(context))
193 ev_io_stop(context->io_loop,
194 (struct ev_io *)&wsi->w_write);
Andrew Canaday9769f4f2014-03-23 13:25:07 +0800195#endif /* LWS_USE_LIBEV */
Andy Green7a132792013-12-18 09:48:26 +0800196
Andy Green54cb3462013-02-14 22:23:54 +0800197 if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE) {
198 n = user_callback_handle_rxflow(
199 wsi->protocol->callback,
200 wsi->protocol->owning_server,
201 wsi, LWS_CALLBACK_HTTP_WRITEABLE,
202 wsi->user_space,
203 NULL,
204 0);
205 if (n < 0)
206 libwebsocket_close_and_free_session(
207 context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
Andy Greena1ce6be2013-01-18 11:43:21 +0800208 break;
Andy Green54cb3462013-02-14 22:23:54 +0800209 }
Andy Greena1ce6be2013-01-18 11:43:21 +0800210
Andy Greenb5b23192013-02-11 17:13:32 +0800211 /* nonzero for completion or error */
212 if (libwebsockets_serve_http_file_fragment(context, wsi))
Andy Greena1ce6be2013-01-18 11:43:21 +0800213 libwebsocket_close_and_free_session(context, wsi,
214 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greena1ce6be2013-01-18 11:43:21 +0800215 break;
216
217 case LWS_CONNMODE_SERVER_LISTENER:
218
219 /* pollin means a client has connected to us then */
220
Patrick Ganstererb47f87b2014-03-30 09:18:05 +0200221 if (!(pollfd->revents & LWS_POLLIN))
Andy Greena1ce6be2013-01-18 11:43:21 +0800222 break;
223
224 /* listen socket got an unencrypted connection... */
225
226 clilen = sizeof(cli_addr);
Andy Greene000a702013-01-29 12:37:35 +0800227 lws_latency_pre(context, wsi);
Andy Greena1ce6be2013-01-18 11:43:21 +0800228 accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
229 &clilen);
Andy Greenb5b23192013-02-11 17:13:32 +0800230 lws_latency(context, wsi,
231 "unencrypted accept LWS_CONNMODE_SERVER_LISTENER",
232 accept_fd, accept_fd >= 0);
Andy Greena1ce6be2013-01-18 11:43:21 +0800233 if (accept_fd < 0) {
Patrick Gansterer2dbd8372014-02-28 12:37:52 +0100234 if (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EWOULDBLOCK) {
Andy Greene2160712013-01-28 12:19:10 +0800235 lwsl_debug("accept asks to try again\n");
236 break;
237 }
Patrick Gansterer2dbd8372014-02-28 12:37:52 +0100238 lwsl_warn("ERROR on accept: %s\n", strerror(LWS_ERRNO));
Andy Greena1ce6be2013-01-18 11:43:21 +0800239 break;
240 }
241
Andy Greena690cd02013-02-09 12:25:31 +0800242 lws_set_socket_options(context, accept_fd);
Andy Green6f047ee2013-01-28 11:23:52 +0800243
Andy Greena1ce6be2013-01-18 11:43:21 +0800244 /*
245 * look at who we connected to and give user code a chance
246 * to reject based on client IP. There's no protocol selected
247 * yet so we issue this to protocols[0]
248 */
249
250 if ((context->protocols[0].callback)(context, wsi,
251 LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
Edwin van den Oetelaar8c8a8e12013-02-20 20:56:59 +0800252 NULL, (void *)(long)accept_fd, 0)) {
Andy Greena1ce6be2013-01-18 11:43:21 +0800253 lwsl_debug("Callback denied network connection\n");
254 compatible_close(accept_fd);
255 break;
256 }
257
258 new_wsi = libwebsocket_create_new_server_wsi(context);
259 if (new_wsi == NULL) {
260 compatible_close(accept_fd);
261 break;
262 }
263
264 new_wsi->sock = accept_fd;
265
Andy Green176de272014-02-15 14:36:02 +0800266 /* the transport is accepted... give him time to negotiate */
267 libwebsocket_set_timeout(new_wsi,
268 PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
269 AWAITING_TIMEOUT);
270
Alexandre Erwin Ittnerd578f572014-02-06 23:15:51 -0200271 /*
272 * A new connection was accepted. Give the user a chance to
273 * set properties of the newly created wsi. There's no protocol
274 * selected yet so we issue this to protocols[0]
275 */
276
277 (context->protocols[0].callback)(context, new_wsi,
278 LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, NULL, NULL, 0);
279
Andrew Canaday9769f4f2014-03-23 13:25:07 +0800280#ifdef LWS_USE_LIBEV
Andy Green4dd33852014-04-01 08:36:36 +0800281 if (LWS_LIBEV_ENABLED(context)) {
282 new_wsi->w_read.context = context;
283 new_wsi->w_write.context = context;
284 /*
285 new_wsi->w_read.wsi = new_wsi;
286 new_wsi->w_write.wsi = new_wsi;
287 */
288 struct ev_io* w_read = (struct ev_io*)&(new_wsi->w_read);
289 struct ev_io* w_write = (struct ev_io*)&(new_wsi->w_write);
290 ev_io_init(w_read,libwebsocket_accept_cb,accept_fd,EV_READ);
291 ev_io_init(w_write,libwebsocket_accept_cb,accept_fd,EV_WRITE);
292 }
Andrew Canaday9769f4f2014-03-23 13:25:07 +0800293#endif /* LWS_USE_LIBEV */
Alexandre Erwin Ittnerd578f572014-02-06 23:15:51 -0200294
Andy Greena1ce6be2013-01-18 11:43:21 +0800295#ifdef LWS_OPENSSL_SUPPORT
296 new_wsi->ssl = NULL;
Andy Greene2160712013-01-28 12:19:10 +0800297 if (!context->use_ssl) {
Andy Greena1ce6be2013-01-18 11:43:21 +0800298#endif
Andy Greene2160712013-01-28 12:19:10 +0800299
Andy Greena1ce6be2013-01-18 11:43:21 +0800300 lwsl_debug("accepted new conn port %u on fd=%d\n",
301 ntohs(cli_addr.sin_port), accept_fd);
302
Andy Greene2160712013-01-28 12:19:10 +0800303 insert_wsi_socket_into_fds(context, new_wsi);
304 break;
305#ifdef LWS_OPENSSL_SUPPORT
306 }
307
308 new_wsi->ssl = SSL_new(context->ssl_ctx);
309 if (new_wsi->ssl == NULL) {
310 lwsl_err("SSL_new failed: %s\n",
311 ERR_error_string(SSL_get_error(
312 new_wsi->ssl, 0), NULL));
313 libwebsockets_decode_ssl_error();
314 free(new_wsi);
315 compatible_close(accept_fd);
316 break;
317 }
318
319 SSL_set_ex_data(new_wsi->ssl,
320 openssl_websocket_private_data_index, context);
321
322 SSL_set_fd(new_wsi->ssl, accept_fd);
Andy Green145ecec2014-03-28 14:00:01 +0800323#ifndef USE_CYASSL
Andy Green35c80f92014-03-23 11:53:07 +0800324 SSL_set_mode(new_wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
Andy Green145ecec2014-03-28 14:00:01 +0800325#endif
Joakim Soderbergb378ce92013-02-06 15:29:18 +0900326 #ifdef USE_CYASSL
327 CyaSSL_set_using_nonblock(new_wsi->ssl, 1);
328 #else
Andy Green1167dd42013-01-28 17:45:34 +0800329 bio = SSL_get_rbio(new_wsi->ssl);
330 if (bio)
331 BIO_set_nbio(bio, 1); /* nonblocking */
332 else
333 lwsl_notice("NULL rbio\n");
334 bio = SSL_get_wbio(new_wsi->ssl);
335 if (bio)
336 BIO_set_nbio(bio, 1); /* nonblocking */
337 else
338 lwsl_notice("NULL rbio\n");
Joakim Soderbergb378ce92013-02-06 15:29:18 +0900339 #endif
Andy Green1167dd42013-01-28 17:45:34 +0800340
Andy Greenb5b23192013-02-11 17:13:32 +0800341 /*
Andy Greene2160712013-01-28 12:19:10 +0800342 * we are not accepted yet, but we need to enter ourselves
343 * as a live connection. That way we can retry when more
344 * pieces come if we're not sorted yet
345 */
346
347 wsi = new_wsi;
348 wsi->mode = LWS_CONNMODE_SSL_ACK_PENDING;
349 insert_wsi_socket_into_fds(context, wsi);
350
Andy Greenba85a7d2013-01-28 17:20:41 +0800351 libwebsocket_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT,
352 AWAITING_TIMEOUT);
353
Andy Greenb5b23192013-02-11 17:13:32 +0800354 lwsl_info("inserted SSL accept into fds, trying SSL_accept\n");
Andy Greene2160712013-01-28 12:19:10 +0800355
356 /* fallthru */
357
358 case LWS_CONNMODE_SSL_ACK_PENDING:
359
Patrick Ganstererb47f87b2014-03-30 09:18:05 +0200360 lws_change_pollfd(wsi, LWS_POLLOUT, 0);
Andrew Canaday9769f4f2014-03-23 13:25:07 +0800361#ifdef LWS_USE_LIBEV
Andy Green4dd33852014-04-01 08:36:36 +0800362 if (LWS_LIBEV_ENABLED(context))
363 ev_io_stop(context->io_loop,
364 (struct ev_io *)&wsi->w_write);
Andrew Canaday9769f4f2014-03-23 13:25:07 +0800365#endif /* LWS_USE_LIBEV */
Andy Green7a132792013-12-18 09:48:26 +0800366
Andy Greene000a702013-01-29 12:37:35 +0800367 lws_latency_pre(context, wsi);
James Devine5b34c972013-12-14 11:41:29 +0800368
369 n = recv(wsi->sock, context->service_buffer,
370 sizeof(context->service_buffer), MSG_PEEK);
371
372 /*
373 * optionally allow non-SSL connect on SSL listening socket
374 * This is disabled by default, if enabled it goes around any
375 * SSL-level access control (eg, client-side certs) so leave
376 * it disabled unless you know it's not a problem for you
377 */
378
379 if (context->allow_non_ssl_on_ssl_port && n >= 1 &&
380 context->service_buffer[0] >= ' ') {
381 /*
382 * TLS content-type for Handshake is 0x16
383 * TLS content-type for ChangeCipherSpec Record is 0x14
384 *
385 * A non-ssl session will start with the HTTP method in
386 * ASCII. If we see it's not a legit SSL handshake
387 * kill the SSL for this connection and try to handle
388 * as a HTTP connection upgrade directly.
389 */
390 wsi->use_ssl = 0;
391 SSL_shutdown(wsi->ssl);
392 SSL_free(wsi->ssl);
393 wsi->ssl = NULL;
394 goto accepted;
395 }
396
397 /* normal SSL connection processing path */
398
Andy Greene2160712013-01-28 12:19:10 +0800399 n = SSL_accept(wsi->ssl);
Andy Greenb5b23192013-02-11 17:13:32 +0800400 lws_latency(context, wsi,
401 "SSL_accept LWS_CONNMODE_SSL_ACK_PENDING\n", n, n == 1);
Andy Greene2160712013-01-28 12:19:10 +0800402
403 if (n != 1) {
404 m = SSL_get_error(wsi->ssl, n);
Andy Greenb5b23192013-02-11 17:13:32 +0800405 lwsl_debug("SSL_accept failed %d / %s\n",
406 m, ERR_error_string(m, NULL));
Andy Greene2160712013-01-28 12:19:10 +0800407
408 if (m == SSL_ERROR_WANT_READ) {
Patrick Ganstererb47f87b2014-03-30 09:18:05 +0200409 lws_change_pollfd(wsi, 0, LWS_POLLIN);
Andrew Canaday9769f4f2014-03-23 13:25:07 +0800410#ifdef LWS_USE_LIBEV
Andy Green4dd33852014-04-01 08:36:36 +0800411 if (LWS_LIBEV_ENABLED(context))
412 ev_io_start(context->io_loop,
413 (struct ev_io *)&wsi->w_read);
Andrew Canaday9769f4f2014-03-23 13:25:07 +0800414#endif /* LWS_USE_LIBEV */
Andy Greene2160712013-01-28 12:19:10 +0800415 lwsl_info("SSL_ERROR_WANT_READ\n");
416 break;
417 }
418 if (m == SSL_ERROR_WANT_WRITE) {
Patrick Ganstererb47f87b2014-03-30 09:18:05 +0200419 lws_change_pollfd(wsi, 0, LWS_POLLOUT);
Andrew Canaday9769f4f2014-03-23 13:25:07 +0800420#ifdef LWS_USE_LIBEV
Andy Green4dd33852014-04-01 08:36:36 +0800421 if (LWS_LIBEV_ENABLED(context))
422 ev_io_start(context->io_loop,
423 (struct ev_io *)&wsi->w_write);
Andrew Canaday9769f4f2014-03-23 13:25:07 +0800424#endif /* LWS_USE_LIBEV */
Andy Greene2160712013-01-28 12:19:10 +0800425 break;
426 }
427 lwsl_debug("SSL_accept failed skt %u: %s\n",
James Devine5b34c972013-12-14 11:41:29 +0800428 pollfd->fd,
429 ERR_error_string(m, NULL));
Andy Greenb5b23192013-02-11 17:13:32 +0800430 libwebsocket_close_and_free_session(context, wsi,
James Devine5b34c972013-12-14 11:41:29 +0800431 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greene2160712013-01-28 12:19:10 +0800432 break;
433 }
434
James Devine5b34c972013-12-14 11:41:29 +0800435accepted:
Andy Green176de272014-02-15 14:36:02 +0800436 /* OK, we are accepted... give him some time to negotiate */
437 libwebsocket_set_timeout(wsi,
438 PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
439 AWAITING_TIMEOUT);
Andy Greenba85a7d2013-01-28 17:20:41 +0800440
Andy Greene2160712013-01-28 12:19:10 +0800441 wsi->mode = LWS_CONNMODE_HTTP_SERVING;
442
Andy Green35517092013-02-11 20:10:56 +0800443 lwsl_debug("accepted new SSL conn\n");
Andy Greena1ce6be2013-01-18 11:43:21 +0800444 break;
Andy Greene2160712013-01-28 12:19:10 +0800445#endif
446
Andy Greena1ce6be2013-01-18 11:43:21 +0800447 default:
448 break;
449 }
450 return 0;
451}
Joakim Soderberg63ff1202013-02-11 17:52:23 +0100452
Andy Green4e7a1332013-11-11 07:30:33 +0800453
454static const char *err400[] = {
455 "Bad Request",
456 "Unauthorized",
457 "Payment Required",
458 "Forbidden",
459 "Not Found",
460 "Method Not Allowed",
461 "Not Acceptable",
462 "Proxy Auth Required",
463 "Request Timeout",
464 "Conflict",
465 "Gone",
466 "Length Required",
467 "Precondition Failed",
468 "Request Entity Too Large",
469 "Request URI too Long",
470 "Unsupported Media Type",
471 "Requested Range Not Satisfiable",
472 "Expectation Failed"
473};
474
475static const char *err500[] = {
476 "Internal Server Error",
477 "Not Implemented",
478 "Bad Gateway",
479 "Service Unavailable",
480 "Gateway Timeout",
481 "HTTP Version Not Supported"
482};
483
484/**
485 * libwebsockets_return_http_status() - Return simple http status
486 * @context: libwebsockets context
487 * @wsi: Websocket instance (available from user callback)
488 * @code: Status index, eg, 404
489 * @html_body: User-readable HTML description, or NULL
490 *
491 * Helper to report HTTP errors back to the client cleanly and
492 * consistently
493 */
Andy Green83725d82014-02-27 07:19:21 +0800494LWS_VISIBLE int libwebsockets_return_http_status(
Andy Green4e7a1332013-11-11 07:30:33 +0800495 struct libwebsocket_context *context, struct libwebsocket *wsi,
496 unsigned int code, const char *html_body)
497{
498 int n, m;
499 const char *description = "";
500
501 if (!html_body)
502 html_body = "";
503
504 if (code >= 400 && code < (400 + ARRAY_SIZE(err400)))
505 description = err400[code - 400];
506 if (code >= 500 && code < (500 + ARRAY_SIZE(err500)))
507 description = err500[code - 500];
508
509 n = sprintf((char *)context->service_buffer,
510 "HTTP/1.0 %u %s\x0d\x0a"
511 "Server: libwebsockets\x0d\x0a"
Patrick Ganstererfce64cd2014-02-27 11:42:41 +0100512 "Content-Type: text/html\x0d\x0a\x0d\x0a"
Andy Green4e7a1332013-11-11 07:30:33 +0800513 "<h1>%u %s</h1>%s",
514 code, description, code, description, html_body);
515
516 lwsl_info((const char *)context->service_buffer);
517
518 m = libwebsocket_write(wsi, context->service_buffer, n, LWS_WRITE_HTTP);
519
520 return m;
521}
522
Patrick Gansterer81338aa2014-02-27 03:21:50 +0100523#if defined(WIN32) || defined(_WIN32)
524static inline HANDLE lws_open_file(const char* filename, unsigned long* filelen)
525{
Patrick Gansterercd9d6c52014-02-28 01:29:28 +0100526 HANDLE ret;
527 WCHAR buffer[MAX_PATH];
528
529 MultiByteToWideChar(CP_UTF8, 0, filename, -1, buffer,
530 sizeof(buffer) / sizeof(buffer[0]));
531 ret = CreateFileW(buffer, GENERIC_READ, FILE_SHARE_READ,
532 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
Patrick Gansterer81338aa2014-02-27 03:21:50 +0100533
534 if (ret != LWS_INVALID_FILE)
535 *filelen = GetFileSize(ret, NULL);
536
537 return ret;
538}
539#else
540static inline int lws_open_file(const char* filename, unsigned long* filelen)
541{
542 struct stat stat_buf;
543 int ret = open(filename, O_RDONLY);
544
545 if (ret < 0)
546 return LWS_INVALID_FILE;
547
548 fstat(ret, &stat_buf);
549 *filelen = stat_buf.st_size;
550 return ret;
551}
552#endif
553
Andy Green4e7a1332013-11-11 07:30:33 +0800554/**
555 * libwebsockets_serve_http_file() - Send a file back to the client using http
556 * @context: libwebsockets context
557 * @wsi: Websocket instance (available from user callback)
558 * @file: The file to issue over http
559 * @content_type: The http content type, eg, text/html
560 * @other_headers: NULL or pointer to \0-terminated other header string
561 *
562 * This function is intended to be called from the callback in response
563 * to http requests from the client. It allows the callback to issue
564 * local files down the http link in a single step.
565 *
566 * Returning <0 indicates error and the wsi should be closed. Returning
567 * >0 indicates the file was completely sent and the wsi should be closed.
568 * ==0 indicates the file transfer is started and needs more service later,
569 * the wsi should be left alone.
570 */
571
572LWS_VISIBLE int libwebsockets_serve_http_file(
573 struct libwebsocket_context *context,
574 struct libwebsocket *wsi, const char *file,
575 const char *content_type, const char *other_headers)
576{
Andy Green4e7a1332013-11-11 07:30:33 +0800577 unsigned char *p = context->service_buffer;
578 int ret = 0;
579 int n;
580
Patrick Gansterer81338aa2014-02-27 03:21:50 +0100581 wsi->u.http.fd = lws_open_file(file, &wsi->u.http.filelen);
Andy Green4e7a1332013-11-11 07:30:33 +0800582
Patrick Gansterer81338aa2014-02-27 03:21:50 +0100583 if (wsi->u.http.fd == LWS_INVALID_FILE) {
Andy Green4e7a1332013-11-11 07:30:33 +0800584 lwsl_err("Unable to open '%s'\n", file);
585 libwebsockets_return_http_status(context, wsi,
586 HTTP_STATUS_NOT_FOUND, NULL);
Andy Green4e7a1332013-11-11 07:30:33 +0800587 return -1;
588 }
589
Andy Green4e7a1332013-11-11 07:30:33 +0800590 p += sprintf((char *)p,
591"HTTP/1.0 200 OK\x0d\x0aServer: libwebsockets\x0d\x0a""Content-Type: %s\x0d\x0a",
592 content_type);
593 if (other_headers) {
594 n = strlen(other_headers);
595 memcpy(p, other_headers, n);
596 p += n;
597 }
598 p += sprintf((char *)p,
Patrick Gansterer81338aa2014-02-27 03:21:50 +0100599 "Content-Length: %lu\x0d\x0a\x0d\x0a", wsi->u.http.filelen);
Andy Green4e7a1332013-11-11 07:30:33 +0800600
601 ret = libwebsocket_write(wsi, context->service_buffer,
602 p - context->service_buffer, LWS_WRITE_HTTP);
603 if (ret != (p - context->service_buffer)) {
604 lwsl_err("_write returned %d from %d\n", ret, (p - context->service_buffer));
605 return -1;
606 }
607
608 wsi->u.http.filepos = 0;
609 wsi->state = WSI_STATE_HTTP_ISSUING_FILE;
610
611 return libwebsockets_serve_http_file_fragment(context, wsi);
612}
613