This commit is a large set of code changes and results in removal of
hundreds, perhaps thousands, of CPU instructions, a portion of which
are on hot code paths.
Most (buffer *) used by lighttpd are not NULL, especially since buffers
were inlined into numerous larger structs such as request_st and chunk.
In the small number of instances where that is not the case, a NULL
check is often performed earlier in a function where that buffer is
later used with a buffer_* func. In the handful of cases that remained,
a NULL check was added, e.g. with r->http_host and r->conf.server_tag.
- check for empty strings at config time and set value to NULL if blank
string will be ignored at runtime; at runtime, simple pointer check
for NULL can be used to check for a value that has been set and is not
blank ("")
- use buffer_is_blank() instead of buffer_string_is_empty(),
and use buffer_is_unset() instead of buffer_is_empty(),
where buffer is known not to be NULL so that NULL check can be skipped
- use buffer_clen() instead of buffer_string_length() when buffer is
known not to be NULL (to avoid NULL check at runtime)
- use buffer_truncate() instead of buffer_string_set_length() to
truncate string, and use buffer_extend() to extend
Examples where buffer known not to be NULL:
- cpv->v.b from config_plugin_values_init is not NULL if T_CONFIG_BOOL
(though we might set it to NULL if buffer_is_blank(cpv->v.b))
- address of buffer is arg (&foo)
(compiler optimizer detects this in most, but not all, cases)
- buffer is checked for NULL earlier in func
- buffer is accessed in same scope without a NULL check (e.g. b->ptr)
internal behavior change:
callers must not pass a NULL buffer to some funcs.
- buffer_init_buffer() requires non-null args
- buffer_copy_buffer() requires non-null args
- buffer_append_string_buffer() requires non-null args
- buffer_string_space() requires non-null arg
improve HTTP/2 behavior when server.max-request-size reached
accept slightly more data than max-request-size if END_STREAM flag recvd
reduce rwin so that client may exceed server.max-request-size, but not
by much. (client might ignore and might send a firehose of data anyway)
accept up to 64k more data to potentially sink data that was in-flight
beyond the rwin, in order to allow server to send 413 Payload Too Large
before resetting the stream.
(thx oldium)
improve handling of HTTP/2 DATA frames received
a short time after sending response
x-ref:
"POST request DATA part for non-existing URI closes HTTP/2 connection prematurely"
https://redmine.lighttpd.net/issues/3078
Note: monotonic time does not change while VM is suspended
Continue to use real time where required by HTTP protocol, for logging
and for other user-visible instances, such as mod_status, as well as for
external databases and caches.
cast high uint8_t byte to uint32_t before bit shifting << 24 to avoid
(pedantic) undefined behavior of uint8_t byte with high bit set when
it is promoted to int and then bit-shifted left 24 bytes. The high bit
gets shifted into the sign-bit, which is technically undefined behavior
in C, but is defined behavior in C++.
x-ref:
"pedantic warning from -fsanitize=undefined"
https://redmine.lighttpd.net/issues/3067
(thx flynn)
fix decoding chunked from backend
truncate response and error out if backend sends excess data
after chunked encoding
x-ref:
"Too much content with HTTP/2.0"
https://redmine.lighttpd.net/issues/3049
relay 1xx from backend over HTTP/2, e.g. 103 Early Hints
(if client is connected using HTTP/2)
enabled by default unless disabled in lighttpd.conf with:
server.feature-flags += ( "server.h2-discard-backend-1xx" = "enable" )
Warning: backends which send 103 Early Hints should check User-Agent
before doing so since naive clients might not handle unexpected 1xx.
Some clients may take the 1xx response as the final response, expecting
only one response. Some clients might not properly handle 100 Continue
if the client did not send Expect: 100-continue with the request.
https://tools.ietf.org/html/rfc8297#section-3 Security Considerations
x-ref:
An HTTP Status Code for Indicating Hints (103 Early Hints)
https://tools.ietf.org/html/rfc8297
allow h2.c layer to modify r->state in addition to r->h2state
Do not retire/release r on error if trailers (as opposed to headers)
(stream r was just allocated in the same scope for headers,
so ok to release)
http_request_parse_header() specialized for HTTP/2 request headers
to be parsed as each field-name and value is HPACK-decoded; send headers
directly from HPACK decoder, rather than double-buffering in chunkqueue
http_request_headers_process_h2() for post-processing
(subsequently incrementally updated using git rebase)
huge props and many thank yous to writers of testing tools used while
developing HTTP/2 support in lighttpd:
h2spec - conformance testing tool for HTTP/2 implementation
https://github.com/summerwind/h2spec
h2load - HTTP/2 benchmarking tool
https://nghttp2.org/documentation/h2load-howto.html
curl - command line tool and library for transferring data with URLs
https://curl.haxx.se/