v1.78.0 fixes lost responses during graceful shutdown and makes streamed bodies report truncation reliably. It also improves redirect handling, preserves multipart uploads when copying requests, and speeds up path normalization, query parsing, header operations, and concurrent client requests.
Server and streaming fixes
- Graceful shutdown preserves responses on keep-alive connections. An idle connection could be closed just as its next request entered the handler, leaving the client with EOF even though the handler had done the work. Shutdown now closes the idle connection before the handler runs or lets the active request finish. Buffered pipelined responses are flushed before the connection closes. #2537
- Incomplete chunked streams report an error. Streamed request and response bodies now report
io.ErrUnexpectedEOFif the peer closes at a chunk boundary before the terminating chunk arrives. If the trailer section is incomplete, the stream returnsErrBrokenChunkwrappingio.ErrUnexpectedEOF. #2515, #2538 - Adapted
net/httphandlers preserve the final response after a 1xx status. A handler that writes103 Early Hintsfollowed by200 OKnow sends the200and its body. The adaptor does not forward the interim status;101 Switching Protocolsremains final. #2516 - Body-buffer retention is scoped to the request that enabled it. The server clears a handler's
Request.KeepBodyBufferandResponse.KeepBodyBuffersettings before resetting for the next keep-alive request, so oversized buffers can be released according to the configured pool limit. #2508
Redirects, URIs, and authentication
- Redirects preserve links such as
mailto:and native-app callbacks.RequestCtx.Redirectkeeps targets with a scheme but no//intact. When the client receives a non-HTTP target of that form, it returns the 3xx response with itsLocationand no error. For references matching the base scheme,URI.Updateresolves the remainder as relative:http:nextagainsthttp://host/a/bresolves tohttp://host/a/next. #2503, #2506, #2507 - An invalid redirect location stops the client before it sends another request. When
Locationcannot be parsed, the client returns the redirect response and the parse error. The newURI.UpdateBytesErrexposes that error to callers;URI.UpdateandURI.UpdateBytesretain their existing behavior. #2523 - An explicit
Authorizationheader takes precedence over URL credentials. When the header is empty, Basic authentication uses the percent-decoded username and password from the URI:p%40ssbecomesp@ss, and a literal+stays+.URI.Parsealso validates IPv6 literals with zone identifiers and rejects an empty zone. #2526, #2529, #2535
Forms, cookies, and compression
- Multipart forms parse and copy correctly. Form media types and the
boundaryparameter name are matched case-insensitively. Multipart parsing accepts optional whitespace around;and preserves semicolons inside quoted parameter values.Request.CopyToalso preserves uploads parsed directly from the incoming body, so forwarding the copy no longer sends an empty body. #2511, #2512, #2517, #2521 - Cookie parsing preserves usable attributes.
Expiresagain accepts RFC 1123 dates with zone names such asUTC. An unusableDomainorPathis ignored without discarding the cookie or skipping later attributes such asHttpOnly. #2519, #2524 - Compression works with single-file roots, mixed-case encodings, and zstd level zero.
FScan again serve compressed content whenRootnames a file, keeping compressed copies in its parent directory. Body decoders matchContent-Encodingcase-insensitively, and zstd level0selects the default level instead of panicking. #2505, #2509, #2510
Performance improvements
Path normalization skips unnecessary dot-segment checks for filenames such as /app.min.js. Query parsing locates escapes while splitting arguments, header operations avoid redundant scans, and Client.Do reduces contention between concurrent callers. #2513
In the PR benchmarks, parsing paths with file extensions took 40% less time, query parsing took 29% less time, and concurrent Client.Do dispatch with a no-op transport took 19% less time at GOMAXPROCS=4. End-to-end improvements were smaller: 4–6% less time for cached small files and 6–8% less time for in-memory client requests. Allocation counts were unchanged, and the pipelined server benchmarks showed no significant change. #2513
What's Changed
Performance
Server, streaming, and adaptor fixes
- fix: don't drop responses on keep-alive connections during Shutdown by @aaydin-tr in #2537
- fix: report a chunked body stream truncated at a chunk boundary by @jaeminbird in #2515
- Expand HTTP fuzz coverage and reject truncated chunked streams by @erikdubbelboer in #2538
- fix(fasthttpadaptor): don't take a 1xx as the final status by @jaeminbird in #2516
- fix: clear KeepBodyBuffer before resetting between keep-alive requests by @jaeminbird in #2508
Redirects, URIs, and authentication
- fix: keep redirect URIs that have a scheme but no authority by @LuisFigueroaG in #2503
- fix(client): don't follow redirects to non-HTTP schemes by @LuisFigueroaG in #2506
- fix: resolve same-scheme references without "//" as relative by @LuisFigueroaG in #2507
- fix: stop following a redirect whose Location can't be parsed by @gaby in #2523
- fix: decode percent-encoded userinfo in URI.Parse by @LuisFigueroaG in #2526
- fix: don't replace a set Authorization header with the URI userinfo by @LuisFigueroaG in #2529
- fix: validate IPv6 literals that have a zone in URI.Parse by @b84330808 in #2535
Forms and cookies
- fix: match form media types and the boundary parameter case-insensitively by @LuisFigueroaG in #2511
- fix: allow optional whitespace around ';' in multipart/form-data by @LuisFigueroaG in #2512
- fix: don't end a multipart/form-data parameter at a ';' inside quotes by @LuisFigueroaG in #2517
- fix: copy a multipart body that was parsed as it was read in Request.CopyTo by @gaby in #2521
- fix(cookie): accept Expires dates in a time zone other than GMT by @LuisFigueroaG in #2519
- fix(cookie): ignore a Domain or Path that can't be used instead of failing to parse by @gaby in #2524
Compression and other fixes
- fix(fs): allow compression when Root is a file by @erikdubbelboer in #2505
- fix: match Content-Encoding case-insensitively when decoding bodies by @LuisFigueroaG in #2509
- fix: map zstd level 0 to the default level instead of panicking by @jaeminbird in #2510
- fix(reuseport): return ErrNoReusePort again when SO_REUSEPORT is unsupported by @ElsiPotka in #2527
- fix(pprofhandler): serve the index at /debug/pprof/ again by @nk-batman21 in #2530
Dependency updates
- chore(deps): bump github.com/molecule-man/go-brrr from 1.3.0 to 1.3.1 by @dependabot[bot] in #2514
- chore(deps): bump golang.org/x/net from 0.61.0 to 0.62.0 by @dependabot[bot] in #2532
New Contributors
- @jaeminbird made their first contribution in #2508
- @ElsiPotka made their first contribution in #2527
- @b84330808 made their first contribution in #2535
Full Changelog: v1.77.0...v1.78.0