win32: enable 64-bit file lengths
[platform/upstream/libwebsockets.git] / lib / server.c
index 35eb753..54e974a 100644 (file)
@@ -308,6 +308,9 @@ lws_get_mimetype(const char *file, const struct lws_http_mount *m)
        if (!strcmp(&file[n - 4], ".ttf"))
                return "application/x-font-ttf";
 
+       if (!strcmp(&file[n - 4], ".otf"))
+               return "application/font-woff";
+
        if (!strcmp(&file[n - 5], ".woff"))
                return "application/font-woff";
 
@@ -349,28 +352,32 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
 {
        const struct lws_protocol_vhost_options *pvo = m->interpret;
        struct lws_process_html_args args;
-       const char *mimetype, *vpath;
-#if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP8266) && \
-    !defined(LWS_WITH_ESP32)
+       const char *mimetype;
+#if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP8266)
        const struct lws_plat_file_ops *fops;
+       const char *vpath;
        lws_fop_flags_t fflags = LWS_O_RDONLY;
+#if defined(WIN32) && defined(LWS_HAVE__STAT32I64)
+       struct _stat32i64 st;
+#else
        struct stat st;
+#endif
        int spin = 0;
 #endif
        char path[256], sym[512];
        unsigned char *p = (unsigned char *)sym + 32 + LWS_PRE, *start = p;
        unsigned char *end = p + sizeof(sym) - 32 - LWS_PRE;
-#if !defined(WIN32) && LWS_POSIX
+#if !defined(WIN32) && LWS_POSIX && !defined(LWS_WITH_ESP32)
        size_t len;
 #endif
        int n;
 
        lws_snprintf(path, sizeof(path) - 1, "%s/%s", origin, uri);
 
+#if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP8266)
+
        fflags |= lws_vfs_prepare_flags(wsi);
 
-#if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP8266) && \
-    !defined(LWS_WITH_ESP32)
        do {
                spin++;
                fops = lws_vfs_select_fops(wsi->context->fops, path, &vpath);
@@ -389,17 +396,33 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
                /* if it can't be statted, don't try */
                if (fflags & LWS_FOP_FLAG_VIRTUAL)
                        break;
-
+#if defined(LWS_WITH_ESP32)
+               break;
+#endif
+#if !defined(WIN32)
                if (fstat(wsi->u.http.fop_fd->fd, &st)) {
                        lwsl_info("unable to stat %s\n", path);
                        goto bail;
                }
+#else
+#if defined(LWS_HAVE__STAT32I64)
+               if (_stat32i64(path, &st)) {
+                       lwsl_info("unable to stat %s\n", path);
+                       goto bail;
+               }
+#else
+               if (stat(path, &st)) {
+                       lwsl_info("unable to stat %s\n", path);
+                       goto bail;
+               }
+#endif
+#endif
 
                wsi->u.http.fop_fd->mod_time = (uint32_t)st.st_mtime;
                fflags |= LWS_FOP_FLAG_MOD_TIME_VALID;
 
                lwsl_debug(" %s mode %d\n", path, S_IFMT & st.st_mode);
-#if !defined(WIN32) && LWS_POSIX
+#if !defined(WIN32) && LWS_POSIX && !defined(LWS_WITH_ESP32)
                if ((S_IFMT & st.st_mode) == S_IFLNK) {
                        len = readlink(path, sym, sizeof(sym) - 1);
                        if (len) {
@@ -730,7 +753,7 @@ lws_http_action(struct lws *wsi)
                lws_hdr_copy(wsi, content_length_str,
                             sizeof(content_length_str) - 1,
                             WSI_TOKEN_HTTP_CONTENT_LENGTH);
-               wsi->u.http.content_length = atoi(content_length_str);
+               wsi->u.http.content_length = atoll(content_length_str);
        }
 
        if (wsi->http2_substream) {
@@ -1049,7 +1072,6 @@ lws_http_action(struct lws *wsi)
                        NULL, /* replace with cgi path */
                        NULL
                };
-               unsigned char *p, *end, buffer[1024];
 
                lwsl_debug("%s: cgi\n", __func__);
                cmd[0] = hit->origin;
@@ -1064,17 +1086,6 @@ lws_http_action(struct lws *wsi)
                        lwsl_err("%s: cgi failed\n", __func__);
                        return -1;
                }
-               p = buffer + LWS_PRE;
-               end = p + sizeof(buffer) - LWS_PRE;
-
-               if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
-                       return 1;
-               if (lws_add_http_header_by_token(wsi, WSI_TOKEN_CONNECTION,
-                               (unsigned char *)"close", 5, &p, end))
-                       return 1;
-               n = lws_write(wsi, buffer + LWS_PRE,
-                             p - (buffer + LWS_PRE),
-                             LWS_WRITE_HTTP_HEADERS);
 
                goto deal_body;
        }
@@ -1152,7 +1163,6 @@ transaction_result_n:
 #endif
 }
 
-
 int
 lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
 {
@@ -1448,7 +1458,7 @@ upgrade_ws:
                         */
                        lwsl_info("defaulting to prot handler %d\n",
                                wsi->vhost->default_protocol_index);
-                       n = 0;
+                       n = wsi->vhost->default_protocol_index;
                        wsi->protocol = &wsi->vhost->protocols[
                                      (int)wsi->vhost->default_protocol_index];
                }
@@ -1489,30 +1499,7 @@ upgrade_ws:
                        goto bail_nuke_ah;
                }
 
-               /*
-                * stitch protocol choice into the vh protocol linked list
-                * We always insert ourselves at the start of the list
-                *
-                * X <-> B
-                * X <-> pAn <-> pB
-                */
-               //lwsl_err("%s: pre insert vhost start wsi %p, that wsi prev == %p\n",
-               //              __func__,
-               //              wsi->vhost->same_vh_protocol_list[n],
-               //              wsi->same_vh_protocol_prev);
-               wsi->same_vh_protocol_prev = /* guy who points to us */
-                       &wsi->vhost->same_vh_protocol_list[n];
-               wsi->same_vh_protocol_next = /* old first guy is our next */
-                               wsi->vhost->same_vh_protocol_list[n];
-               /* we become the new first guy */
-               wsi->vhost->same_vh_protocol_list[n] = wsi;
-
-               if (wsi->same_vh_protocol_next)
-                       /* old first guy points back to us now */
-                       wsi->same_vh_protocol_next->same_vh_protocol_prev =
-                                       &wsi->same_vh_protocol_next;
-
-
+               lws_same_vh_protocol_insert(wsi, n);
 
                /* we are upgrading to ws, so http/1.1 and keepalive +
                 * pipelined header considerations about keeping the ah around
@@ -1736,6 +1723,21 @@ lws_http_transaction_completed(struct lws *wsi)
                if (!wsi->more_rx_waiting) {
                        wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
                        lws_header_table_detach(wsi, 1);
+#ifdef LWS_OPENSSL_SUPPORT
+                       /*
+                        * additionally... if we are hogging an SSL instance
+                        * with no pending pipelined headers (or ah now), and
+                        * SSL is scarce, drop this connection without waiting
+                        */
+
+                       if (wsi->vhost->use_ssl &&
+                           wsi->context->simultaneous_ssl_restriction &&
+                           wsi->context->simultaneous_ssl ==
+                                  wsi->context->simultaneous_ssl_restriction) {
+                               lwsl_info("%s: simultaneous_ssl_restriction and nothing pipelined\n", __func__);
+                               return 1;
+                       }
+#endif
                } else
                        lws_header_table_reset(wsi, 1);
        }
@@ -1757,6 +1759,7 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
 {
        struct lws_context *context = vh->context;
        struct lws *new_wsi = lws_create_new_server_wsi(vh);
+       struct lws_context_per_thread *pt;
        int n, ssl = 0;
 
        if (!new_wsi) {
@@ -1764,6 +1767,8 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
                        compatible_close(fd.sockfd);
                return NULL;
        }
+       pt = &context->pt[(int)new_wsi->tsi];
+       lws_stats_atomic_bump(context, pt, LWSSTATS_C_CONNECTIONS, 1);
 
        if (parent) {
                new_wsi->parent = parent;
@@ -1781,19 +1786,30 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
                                 vh_prot_name, new_wsi->vhost->name);
                        goto bail;
                }
-               if (lws_ensure_user_space(new_wsi))
+               if (lws_ensure_user_space(new_wsi)) {
+                       lwsl_notice("OOM trying to get user_space\n");
                        goto bail;
+               }
        } else
-               new_wsi->protocol = &context->vhost_list->
-                                       protocols[vh->default_protocol_index];
+               if (type & LWS_ADOPT_HTTP) /* he will transition later */
+                       new_wsi->protocol =
+                               &vh->protocols[vh->default_protocol_index];
+               else { /* this is the only time he will transition */
+                       lws_bind_protocol(new_wsi,
+                               &vh->protocols[vh->raw_protocol_index]);
+                       lws_union_transition(new_wsi, LWSCM_RAW);
+               }
 
        if (type & LWS_ADOPT_SOCKET) { /* socket desc */
                lwsl_debug("%s: new wsi %p, sockfd %d\n", __func__, new_wsi,
                           (int)(size_t)fd.sockfd);
 
-               /* the transport is accepted... give him time to negotiate */
-               lws_set_timeout(new_wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
-                               context->timeout_secs);
+               if (type & LWS_ADOPT_HTTP)
+                       /* the transport is accepted...
+                        * give him time to negotiate */
+                       lws_set_timeout(new_wsi,
+                                       PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
+                                       context->timeout_secs);
 
 #if LWS_POSIX == 0
 #if defined(LWS_WITH_ESP8266)
@@ -1817,15 +1833,6 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
                else
                        n = LWS_CALLBACK_RAW_ADOPT;
        }
-       if ((new_wsi->protocol->callback)(
-                       new_wsi, n, NULL, NULL, 0)) {
-               if (type & LWS_ADOPT_SOCKET) {
-                       /* force us off the timeout list by hand */
-                       lws_set_timeout(new_wsi, NO_PENDING_TIMEOUT, 0);
-                       compatible_close(new_wsi->desc.sockfd);
-               }
-               goto bail;
-       }
 
        if (!LWS_SSL_ENABLED(new_wsi->vhost) || !(type & LWS_ADOPT_ALLOW_SSL) ||
            !(type & LWS_ADOPT_SOCKET)) {
@@ -1848,6 +1855,7 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
 
        lws_libev_accept(new_wsi, new_wsi->desc);
        lws_libuv_accept(new_wsi, new_wsi->desc);
+       lws_libevent_accept(new_wsi, new_wsi->desc);
 
        if (!ssl) {
                if (insert_wsi_socket_into_fds(context, new_wsi)) {
@@ -1860,9 +1868,21 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
                        goto fail;
                }
 
-       if (type & LWS_ADOPT_HTTP)
-               if (!lws_header_table_attach(new_wsi, 0))
+       /*
+        *  by deferring callback to this point, after insertion to fds,
+        * lws_callback_on_writable() can work from the callback
+        */
+       if ((new_wsi->protocol->callback)(
+                       new_wsi, n, new_wsi->user_space, NULL, 0))
+               goto fail;
+
+       if (type & LWS_ADOPT_HTTP) {
+               if (!lws_header_table_attach(new_wsi, 0)) {
                        lwsl_debug("Attached ah immediately\n");
+               } else {
+                       lwsl_notice("%s: waiting for ah\n", __func__);
+               }
+       }
 
        return new_wsi;
 
@@ -1873,11 +1893,13 @@ fail:
        return NULL;
 
 bail:
+       lwsl_notice("%s: exiting on bail\n", __func__);
        if (parent)
                parent->child_list = new_wsi->sibling_list;
        if (new_wsi->user_space)
                lws_free(new_wsi->user_space);
        lws_free(new_wsi);
+       compatible_close(fd.sockfd);
 
        return NULL;
 }
@@ -1995,8 +2017,10 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
        struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
        lws_sockfd_type accept_fd = LWS_SOCK_INVALID;
        struct allocated_headers *ah;
+       lws_sock_file_fd_type fd;
+       int opts = LWS_ADOPT_SOCKET | LWS_ADOPT_ALLOW_SSL;
 #if LWS_POSIX
-       struct sockaddr_in cli_addr;
+       struct sockaddr_storage cli_addr;
        socklen_t clilen;
 #endif
        int n, len;
@@ -2059,7 +2083,7 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
                                //lwsl_err("wsi %p: missing ah\n", wsi);
                                /* no autoservice beacuse we will do it next */
                                if (lws_header_table_attach(wsi, 0)) {
-                                       lwsl_err("wsi %p: failed to acquire ah\n", wsi);
+                                       lwsl_info("wsi %p: failed to acquire ah\n", wsi);
                                        goto try_pollout;
                                }
                        }
@@ -2181,6 +2205,16 @@ try_pollout:
                }
 
                if (wsi->mode == LWSCM_RAW) {
+                       lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB, 1);
+#if defined(LWS_WITH_STATS)
+                       {
+                               uint64_t ul = time_in_microseconds() - wsi->active_writable_req_us;
+
+                               lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_WRITABLE_DELAY, ul);
+                               lws_stats_atomic_max(wsi->context, pt, LWSSTATS_MS_WORST_WRITABLE_DELAY, ul);
+                               wsi->active_writable_req_us = 0;
+                       }
+#endif
                        n = user_callback_handle_rxflow(wsi->protocol->callback,
                                        wsi, LWS_CALLBACK_RAW_WRITEABLE,
                                        wsi->user_space, NULL, 0);
@@ -2195,6 +2229,18 @@ try_pollout:
                        break;
 
                if (wsi->state != LWSS_HTTP_ISSUING_FILE) {
+
+                       lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB, 1);
+#if defined(LWS_WITH_STATS)
+                       {
+                               uint64_t ul = time_in_microseconds() - wsi->active_writable_req_us;
+
+                               lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_WRITABLE_DELAY, ul);
+                               lws_stats_atomic_max(wsi->context, pt, LWSSTATS_MS_WORST_WRITABLE_DELAY, ul);
+                               wsi->active_writable_req_us = 0;
+                       }
+#endif
+
                        n = user_callback_handle_rxflow(wsi->protocol->callback,
                                        wsi, LWS_CALLBACK_HTTP_WRITEABLE,
                                        wsi->user_space, NULL, 0);
@@ -2223,6 +2269,23 @@ try_pollout:
                        if (!(pollfd->revents & LWS_POLLIN) || !(pollfd->events & LWS_POLLIN))
                                break;
 
+#ifdef LWS_OPENSSL_SUPPORT
+                       /*
+                        * can we really accept it, with regards to SSL limit?
+                        * another vhost may also have had POLLIN on his listener this
+                        * round and used it up already
+                        */
+
+                       if (wsi->vhost->use_ssl &&
+                           context->simultaneous_ssl_restriction &&
+                           context->simultaneous_ssl ==
+                                         context->simultaneous_ssl_restriction)
+                               /* no... ignore it, he won't come again until we are
+                                * below the simultaneous_ssl_restriction limit and
+                                * POLLIN is enabled on him again
+                                */
+                               break;
+#endif
                        /* listen socket got an unencrypted connection... */
 
                        clilen = sizeof(cli_addr);
@@ -2234,7 +2297,7 @@ try_pollout:
                        if (accept_fd < 0) {
                                if (LWS_ERRNO == LWS_EAGAIN ||
                                    LWS_ERRNO == LWS_EWOULDBLOCK) {
-                                       lwsl_err("accept asks to try again\n");
+//                                     lwsl_err("accept asks to try again\n");
                                        break;
                                }
                                lwsl_err("ERROR on accept: %s\n", strerror(LWS_ERRNO));
@@ -2243,8 +2306,17 @@ try_pollout:
 
                        lws_plat_set_socket_options(wsi->vhost, accept_fd);
 
-                       lwsl_debug("accepted new conn  port %u on fd=%d\n",
-                                         ntohs(cli_addr.sin_port), accept_fd);
+#if defined(LWS_USE_IPV6)
+                       lwsl_debug("accepted new conn port %u on fd=%d\n",
+                                         ((cli_addr.ss_family == AF_INET6) ?
+                                         ntohs(((struct sockaddr_in6 *) &cli_addr)->sin6_port) :
+                                         ntohs(((struct sockaddr_in *) &cli_addr)->sin_port)),
+                                         accept_fd);
+#else
+                       lwsl_debug("accepted new conn port %u on fd=%d\n",
+                                         ntohs(((struct sockaddr_in *) &cli_addr)->sin_port),
+                                         accept_fd);
+#endif
 
 #else
                        /* not very beautiful... */
@@ -2263,7 +2335,12 @@ try_pollout:
                                break;
                        }
 
-                       if (!lws_adopt_socket_vhost(wsi->vhost, accept_fd))
+                       if (!(wsi->vhost->options & LWS_SERVER_OPTION_ONLY_RAW))
+                               opts |= LWS_ADOPT_HTTP;
+
+                       fd.sockfd = accept_fd;
+                       if (!lws_adopt_descriptor_vhost(wsi->vhost, opts, fd,
+                                                       NULL, NULL))
                                /* already closed cleanly as necessary */
                                return 1;
 
@@ -2300,7 +2377,7 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
        unsigned char *response = pt->serv_buf + LWS_PRE;
        unsigned char *p = response;
        unsigned char *end = p + context->pt_serv_buf_size - LWS_PRE;
-       unsigned long computed_total_content_length;
+       lws_filepos_t computed_total_content_length;
        int ret = 0, cclen = 8, n = HTTP_STATUS_OK;
        lws_fop_flags_t fflags = LWS_O_RDONLY;
 #if defined(LWS_WITH_RANGES)
@@ -2397,7 +2474,7 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
                 *  Precompute it for the main response header
                 */
 
-               computed_total_content_length = (unsigned long)rp->agg +
+               computed_total_content_length = (lws_filepos_t)rp->agg +
                                                6 /* final _lws\r\n */;
 
                lws_ranges_reset(rp);
@@ -2418,7 +2495,7 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
        }
 
        if (ranges == 1) {
-               computed_total_content_length = (unsigned long)rp->agg;
+               computed_total_content_length = (lws_filepos_t)rp->agg;
                n = lws_snprintf(cache_control, sizeof(cache_control), "bytes %llu-%llu/%llu",
                                rp->start, rp->end, rp->extent);
 
@@ -2513,6 +2590,7 @@ lws_interpret_incoming_packet(struct lws *wsi, unsigned char **buf, size_t len)
                }
 
                if (wsi->u.ws.rx_draining_ext) {
+                       // lwsl_notice("draining with 0\n");
                        m = lws_rx_sm(wsi, 0);
                        if (m < 0)
                                return -1;
@@ -2524,7 +2602,8 @@ lws_interpret_incoming_packet(struct lws *wsi, unsigned char **buf, size_t len)
                        wsi->rxflow_pos++;
 
                /* consume payload bytes efficiently */
-               if (wsi->lws_rx_parse_state ==
+               if (
+                   wsi->lws_rx_parse_state ==
                    LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED) {
                        m = lws_payload_until_length_exhausted(wsi, buf, &len);
                        if (wsi->rxflow_buffer)
@@ -2549,7 +2628,7 @@ lws_server_get_canonical_hostname(struct lws_context *context,
 {
        if (lws_check_opt(info->options, LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME))
                return;
-#if LWS_POSIX
+#if LWS_POSIX && !defined(LWS_WITH_ESP32)
        /* find canonical hostname */
        gethostname((char *)context->canonical_hostname,
                    sizeof(context->canonical_hostname) - 1);
@@ -2941,6 +3020,8 @@ struct lws_spa {
        char *storage;
        char *end;
        int max_storage;
+
+       char finalized;
 };
 
 static int
@@ -3056,6 +3137,10 @@ lws_spa_process(struct lws_spa *ludspa, const char *in, int len)
                lwsl_err("%s: NULL spa\n", __func__);
                return -1;
        }
+       /* we reject any junk after the last part arrived and we finalized */
+       if (ludspa->finalized)
+               return 0;
+
        return lws_urldecode_s_process(ludspa->s, in, len);
 }
 
@@ -3085,6 +3170,8 @@ lws_spa_finalize(struct lws_spa *spa)
                spa->s = NULL;
        }
 
+       spa->finalized = 1;
+
        return 0;
 }
 
@@ -3093,6 +3180,32 @@ lws_spa_destroy(struct lws_spa *spa)
 {
        int n = 0;
 
+       lwsl_notice("%s: destroy spa %p\n", __func__, spa);
+
+       if (spa->s)
+               lws_urldecode_s_destroy(spa->s);
+
+       lwsl_debug("%s %p %p %p %p\n", __func__,
+                       spa->param_length,
+                       spa->params,
+                       spa->storage,
+                       spa
+                       );
+
+       lws_free(spa->param_length);
+       lws_free(spa->params);
+       lws_free(spa->storage);
+       lws_free(spa);
+
+       return n;
+}
+
+#if 0
+LWS_VISIBLE LWS_EXTERN int
+lws_spa_destroy(struct lws_spa *spa)
+{
+       int n = 0;
+
        lwsl_info("%s: destroy spa %p\n", __func__, spa);
 
        if (spa->s)
@@ -3107,7 +3220,7 @@ lws_spa_destroy(struct lws_spa *spa)
 
        return n;
 }
-
+#endif
 LWS_VISIBLE LWS_EXTERN int
 lws_chunked_html_process(struct lws_process_html_args *args,
                         struct lws_process_html_state *s)