github valyala/fasthttp v1.75.0

2 hours ago

v1.75.0 improves HTTP parsing and serialization, URI processing, cached file serving, and client connection handling. It also fixes cookie injection, request/response framing problems, and excessive CPU or memory consumption from certain inputs.

Go 1.26 or newer is now required. #2395

Performance improvements

  • HTTP parsing: request headers are parsed and validated in one pass, with common methods and HTTP/1.1 recognized directly. Header values, case conversion, host validation, and control-byte checks process multiple bytes at a time. The parser also avoids repeatedly scanning the same incomplete header block when data arrives in small reads. #2413, #2414, #2428, #2423, #2412, #2438
  • HTTP writing: fewer header and response copies, cached serialized Server and Date lines, faster HTTP date formatting, and fewer flushes around chunked trailers. Large buffered responses can use writev on TCP and Unix connections; TLS and streamed bodies retain the buffered path. #2425, #2415, #2434, #2426, #2433
  • URI processing: memoized authority parsing, a fast path for /, faster quoting and validation, and linear-time path normalization. #2411, #2423, #2453
  • Static files: cached files of up to 8 KiB can be served from memory, avoiding a file read on each cache hit and releasing the file descriptor. The new small-file content cache is bounded to 4096 files, or at most 32 MiB per FS; the existing cache metadata is separate. Changes to these files become visible after cache expiration (CacheDuration, 10 seconds by default). #2446
  • Client and server overhead: clients avoid redundant deadline updates when no timeout is active. The opt-in Server.LazyRequestTime avoids reading the clock until RequestCtx.Time() is called; with this option, the returned time is the time of the first call. The benchmark comparison below uses the default setting. #2439, #2404

Security fixes and hardening

  • Streamed request bodies are drained before connection reuse. With StreamRequestBody enabled, the server drains unread body data before reusing the connection, with a 256 KiB drain limit, or closes the connection when safe draining is not possible. Responses are flushed before draining so early replies reach clients still uploading, and response streams can consume the request body before its remaining size is checked. #2368, #2461
  • Rejected 100-continue requests close the connection. A denied request could previously leave its body unread and have those bytes interpreted as the next request, desynchronizing a reused connection. #2450
  • Cookie setters prevent additional-cookie injection. RequestHeader.SetCookie and its byte variants now sanitize semicolons in names and values, so one logical cookie cannot become multiple cookies on the wire. #2393
  • Bounded zstd decoding limits decoder memory demand as well as output. A small compressed frame could previously declare a large decoder window even when a decoded-body limit was configured. Positive BodyUnzstdWithLimit limits now select a memory-limited decoder, with caps rounded up in 8 MiB buckets; exceeding the decoder limit returns ErrBodyTooLarge. #2407
  • Path normalization avoids quadratic work. Repeated separators and dot segments are processed in linear time, reducing the CPU amplification possible with crafted request targets. Incomplete headers arriving one byte at a time also avoid repeated full-block scans. #2453, #2413
  • Bodyless responses preserve framing. HEAD and status-defined bodyless responses no longer emit trailer bytes that can be mistaken for the next response. Serialization suppresses forbidden Content-Length and Transfer-Encoding on 1xx/204 responses. Explicit content-type metadata and permitted 304 metadata remain supported. #2441, #2447, #2457
  • Pipeline clients gain a response-body limit and better failure cleanup. Set the new PipelineClient.MaxResponseBodySize to a positive value to reject oversized responses, including with Response.StreamBody; the default remains unlimited. Idle workers now retire after errors, abandoned requests release their streams, and failed connection establishment is throttled. #2427, #2458

Argument sorting now honors any negative comparator result in Args.Sort and Args.SortKeys, and static-file serving rejects zero-length suffix byte ranges (bytes=-0) with 416 Range Not Satisfiable. #2459, #2460

Other significant changes include opt-in ETags for FS, a net/http request conversion function, improved adaptor handling of flushes, aborts and trailers, and fixes to shutdown and per-IP connection lifetimes. #2399, #2104, #2429, #2445, #2352, #2402

Benchmark results

Compared v1.74.0 with master 6141d3a on Ubuntu 26.04, an AMD EPYC 9454, and Go 1.27.1. Each benchmark has ten samples per revision, run alternately with the same inputs and CPU affinity. Negative percentages mean less time per operation. All rows below have p < 0.001.

Benchmark v1.74.0 Release candidate Time/op change
Minimal GET, pipeline depth 64 484.30 ns 278.05 ns -42.6%
Browser-shaped GET, pipeline depth 16 1.080 µs 722.55 ns -33.1%
Request-header parsing 561.80 ns 348.15 ns -38.0%
Response-header parsing 466.95 ns 277.55 ns -40.6%
Request-header writing 49.84 ns 37.45 ns -24.8%
Response-header writing 68.64 ns 40.99 ns -40.3%
Cached 1 KiB file, directory 2.324 µs 611.85 ns -73.7%
Cached 1 KiB file, os.DirFS 3.805 µs 612.30 ns -83.9%
URI path with query string 91.39 ns 46.06 ns -49.6%
HTTP date formatting 108.25 ns 28.59 ns -73.6%
Trickled ~4 KiB headers, one byte per read 1385.784 µs 191.257 µs -86.2%
8 KiB path of repeated / 352.529 µs 54.330 µs -84.6%
~8 KiB path of repeated /a/.. 96.733 µs 22.253 µs -77.0%
TCP client/server round trips, small response 5.193 µs 5.030 µs -3.1%
TCP client/server round trips, 64 KiB response 15.302 µs 13.478 µs -11.9%

The pipelined serving and file benchmarks use an in-memory connection with writes discarded. The two TCP rows include real loopback networking. These results describe the selected workloads; TCP gains are smaller than the gains in parsing and serialization. Server.LazyRequestTime remains disabled in this comparison.

What's Changed

Compatibility

Security and hardening

Performance

  • perf: parse request headers in one validating pass by @h2zi in #2413
  • perf: scan the request header block once while parsing by @gaby in #2424
  • perf: serve small cached files from memory in FS by @gaby in #2446
  • perf: serialize responses with fewer copies and send large ones with writev by @h2zi in #2415
  • perf: cut redundant copies out of header serialization by @gaby in #2425
  • perf: scan header values, control bytes and case eight bytes at a time by @gaby in #2428
  • perf: speed up host validation and query/path quoting- #154 by @gaby in #2423
  • perf: memoize authority parsing and fast-path the root path by @h2zi in #2411
  • perf: recognize GET, POST, HEAD and HTTP/1.1 without byte-wise validation by @h2zi in #2414
  • perf: scan the request target for control bytes a word at a time by @h2zi in #2412
  • perf: skip redundant deadline updates on client connections by @gaby in #2439
  • perf: preform the Date header line once a second by @h2zi in #2434
  • perf: format HTTP dates without time.AppendFormat by @gaby in #2426
  • perf: keep the last chunk buffered for the trailer section by @h2zi in #2433
  • perf: keep the control-byte scans inlinable by @h2zi in #2438
  • fix: request time left at zero, and an opt in Server.LazyRequestTime by @ReneWerner87 in #2404

Features

Fixes

  • fix: preserve response behavior while draining streamed requests by @erikdubbelboer in #2461
  • fix: per-IP wrapper lifetime, TLS state unwrapping and ConnState timing by @h2zi in #2352
  • fix: carry net/http handler contracts through the fasthttpadaptor by @h2zi in #2429
  • Carry response trailers through the fasthttpadaptor by @h2zi in #2445
  • fix: write trailers for buffered bodies in Request.Write and Response.Write by @aaydin-tr in #2378
  • Start compressing a streamed body when the server reads it by @h2zi in #2442
  • fix: synchronize RequestCtx.Done() with ShutdownWithContext by @cpsc in #2402
  • fix: admit TimeoutHandler requests on servers driven by ServeConn by @h2zi in #2431
  • fix: serve queued waiters when SetMaxConns grows the limit by @h2zi in #2430
  • fix: recheck idle connections before queuing waiters by @HarveyBase in #2394
  • fix: recognize case-insensitive and multi-value Connection: close (#2418) by @littfed in #2420
  • fix: preserve zero Max-Age when parsing cookies by @jakezwang in #2405
  • fix: accept a negative Max-Age when parsing cookies by @SulimanAbdulrazzaq in #2416
  • Preserve NoDefaultContentType across client response resets by @CSXizhang in #2455
  • fix(fs): reject zero-length suffix byte ranges by @kevin9327 in #2460
  • fix(args): use comparator sign in Sort and SortKeys by @sergioperezcheco in #2459
  • fix: preserve redirect path normalization setting in Request.CopyTo by @cuishuang in #2389
  • fix: normalize a trailing /. path segment by @sachhg in #2392
  • fix: mask ConnRequestNum into its 32-bit RequestCtx.ID field by @h2zi in #2432
  • Return no values from PeekAll for absent special headers by @youdie006 in #2401
  • Leave an empty upfront Server or User-Agent out of PeekAll by @h2zi in #2443
  • Skip RFC-valid empty elements in VisitHeaderParams by @vzer200 in #2388
  • fix(request): warn when Request.Body() is called on streamed requests by @VedantMadane in #2350

Documentation, tests and tooling

  • docs: show how to read a bounded response prefix by @fzlzjerry in #2369
  • docs: clarify that ShutdownWithContext error does not freeze the Server by @hazyhaar in #2422
  • test: add benchmarks for pipelined and browser-shaped serving by @h2zi in #2409
  • test: scale hard-coded deadlines with testTimeout by @h2zi in #2410
  • Update golangci-lint to v2.13.2 and get rid of the separate gosec action by @erikdubbelboer in #2386

Dependency updates

  • chore(deps): bump github.com/klauspost/compress from 1.20.0 to 1.20.1 by @dependabot[bot] in #2448
  • chore(deps): bump golang.org/x/net from 0.58.0 to 0.59.0 by @dependabot[bot] in #2397
  • chore(deps): bump github.com/molecule-man/go-brrr from 1.0.1 to 1.1.1 by @dependabot[bot] in #2417

New Contributors

Full Changelog: v1.74.0...v1.75.0

Don't miss a new fasthttp release

NewReleases is sending notifications on new releases.