diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index e51052bb..90bf652e 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -3687,6 +3687,7 @@ struct lws_process_html_args { int len; /**< length of the original data at p */ int max_len; /**< maximum length we can grow the data to */ int final; /**< set if this is the last chunk of the file */ + int chunked; /**< 0 == unchunked, 1 == produce chunk headers (incompatible with HTTP/2) */ }; typedef const char *(*lws_process_html_state_cb)(void *data, int index); diff --git a/lib/output.c b/lib/output.c index 525ba109..5885c66f 100644 --- a/lib/output.c +++ b/lib/output.c @@ -663,8 +663,9 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi) poss = context->pt_serv_buf_size - n - LWS_H2_FRAME_HEADER_LENGTH; - if (poss > wsi->http.tx_content_remain) - poss = wsi->http.tx_content_remain; + if (wsi->http.tx_content_length) + if (poss > wsi->http.tx_content_remain) + poss = wsi->http.tx_content_remain; /* * if there is a hint about how much we will do well to send at one time, @@ -717,12 +718,13 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi) lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, context->timeout_secs); - if (wsi->sending_chunked) { + if (wsi->interpreting) { args.p = (char *)p; args.len = n; args.max_len = (unsigned int)poss + 128; args.final = wsi->http.filepos + n == wsi->http.filelen; + args.chunked = wsi->sending_chunked; if (user_callback_handle_rxflow( wsi->vhost->protocols[ (int)wsi->protocol_interpret_idx].callback, @@ -745,7 +747,7 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi) } #endif m = lws_write(wsi, p, n, - wsi->http.filepos == wsi->http.filelen ? + wsi->http.filepos + amount == wsi->http.filelen ? LWS_WRITE_HTTP_FINAL : LWS_WRITE_HTTP ); diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 80f22401..04b312ca 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -1921,6 +1921,7 @@ struct lws { unsigned int cache_intermediaries:1; unsigned int favoured_pollin:1; unsigned int sending_chunked:1; + unsigned int interpreting:1; unsigned int already_did_cce:1; unsigned int told_user_closed:1; unsigned int waiting_to_send_close_frame:1; diff --git a/lib/server/server.c b/lib/server/server.c index 5bb8ee11..aa76e171 100644 --- a/lib/server/server.c +++ b/lib/server/server.c @@ -531,7 +531,9 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin, n = (int)strlen(path); if (n > (int)strlen(pvo->name) && !strcmp(&path[n - strlen(pvo->name)], pvo->name)) { - wsi->sending_chunked = 1; + wsi->interpreting = 1; + if (!wsi->http2_substream) + wsi->sending_chunked = 1; wsi->protocol_interpret_idx = (char)(lws_intptr_t)pvo->value; lwsl_info("want %s interpreted by %s\n", path, @@ -1125,6 +1127,7 @@ lws_http_action(struct lws *wsi) args.len = uri_len; args.max_len = hit->auth_mask; args.final = 0; /* used to signal callback dealt with it */ + args.chunked = 0; n = wsi->protocol->callback(wsi, LWS_CALLBACK_CHECK_ACCESS_RIGHTS, @@ -2865,17 +2868,19 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type, return -1; #endif - if (!wsi->sending_chunked) { - if (lws_add_http_header_content_length(wsi, - total_content_length, - &p, end)) - return -1; - } else { - if (lws_add_http_header_by_token(wsi, + if (!wsi->http2_substream) { + if (!wsi->sending_chunked) { + if (lws_add_http_header_content_length(wsi, + total_content_length, + &p, end)) + return -1; + } else { + if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_TRANSFER_ENCODING, (unsigned char *)"chunked", 7, &p, end)) - return -1; + return -1; + } } if (wsi->cache_secs && wsi->cache_reuse) { @@ -3075,31 +3080,33 @@ skip: sp++; } - /* no space left for final chunk trailer */ - if (args->final && args->len + 7 >= args->max_len) - return -1; + if (args->chunked) { + /* no space left for final chunk trailer */ + if (args->final && args->len + 7 >= args->max_len) + return -1; - n = sprintf(buffer, "%X\x0d\x0a", args->len); + n = sprintf(buffer, "%X\x0d\x0a", args->len); - args->p -= n; - memcpy(args->p, buffer, n); - args->len += n; + args->p -= n; + memcpy(args->p, buffer, n); + args->len += n; - if (args->final) { - sp = args->p + args->len; - *sp++ = '\x0d'; - *sp++ = '\x0a'; - *sp++ = '0'; - *sp++ = '\x0d'; - *sp++ = '\x0a'; - *sp++ = '\x0d'; - *sp++ = '\x0a'; - args->len += 7; - } else { - sp = args->p + args->len; - *sp++ = '\x0d'; - *sp++ = '\x0a'; - args->len += 2; + if (args->final) { + sp = args->p + args->len; + *sp++ = '\x0d'; + *sp++ = '\x0a'; + *sp++ = '0'; + *sp++ = '\x0d'; + *sp++ = '\x0a'; + *sp++ = '\x0d'; + *sp++ = '\x0a'; + args->len += 7; + } else { + sp = args->p + args->len; + *sp++ = '\x0d'; + *sp++ = '\x0a'; + args->len += 2; + } } return 0;