@@ -19,7 +19,7 @@ import (
1919type Response struct {
2020 http.ResponseWriter
2121 logger * slog.Logger
22- // beforeFuncs are functions that are called just before the response (status) is written. Happens only once, during WriteHeader call.
22+ // beforeFuncs are functions that are called just before the final response (status) is written. Happens only once, during WriteHeader call.
2323 beforeFuncs []func ()
2424 // afterFuncs are functions that are called just after the response is written. During every `Write` method call.
2525 afterFuncs []func ()
@@ -33,7 +33,7 @@ func NewResponse(w http.ResponseWriter, logger *slog.Logger) (r *Response) {
3333 return & Response {ResponseWriter : w , logger : logger }
3434}
3535
36- // Before registers a function which is called just before the response (status) is written.
36+ // Before registers a function which is called just before the final response (status) is written.
3737func (r * Response ) Before (fn func ()) {
3838 r .beforeFuncs = append (r .beforeFuncs , fn )
3939}
@@ -46,12 +46,18 @@ func (r *Response) After(fn func()) {
4646// WriteHeader sends an HTTP response header with status code. If WriteHeader is
4747// not called explicitly, the first call to Write will trigger an implicit
4848// WriteHeader(http.StatusOK). Thus explicit calls to WriteHeader are mainly
49- // used to send error codes.
49+ // used to send error codes or informational responses.
50+ // Informational responses (100-199, except 101 Switching Protocols) are sent
51+ // immediately without changing Status or Committed or calling Before functions.
5052func (r * Response ) WriteHeader (code int ) {
5153 if r .Committed {
5254 r .logger .Error ("echo: response already written to client" )
5355 return
5456 }
57+ if code >= 100 && code < 200 && code != http .StatusSwitchingProtocols {
58+ r .ResponseWriter .WriteHeader (code )
59+ return
60+ }
5561 r .Status = code
5662 for _ , fn := range r .beforeFuncs {
5763 fn ()
@@ -141,6 +147,10 @@ type delayedStatusWriter struct {
141147}
142148
143149func (w * delayedStatusWriter ) WriteHeader (statusCode int ) {
150+ if statusCode >= 100 && statusCode < 200 && statusCode != http .StatusSwitchingProtocols {
151+ w .ResponseWriter .WriteHeader (statusCode )
152+ return
153+ }
144154 // in case something else writes status code explicitly before us we need mark response committed
145155 w .committed = true
146156 w .ResponseWriter .WriteHeader (statusCode )
@@ -175,10 +185,10 @@ func (w *delayedStatusWriter) Unwrap() http.ResponseWriter {
175185// headResponseWriter captures the response that a GET handler would produce for a
176186// rewritten HEAD request, suppresses the body, and preserves response metadata.
177187//
178- // The writer buffers status until the downstream handler returns, so it
188+ // The writer buffers the final status until the downstream handler returns, so it
179189// can compute a Content-Length value from the number of body bytes that would have
180190// been written by the GET handler. If the handler already sets Content-Length
181- // explicitly, that value is preserved.
191+ // explicitly, that value is preserved. Informational responses are forwarded immediately.
182192//
183193// Flush is intentionally a no-op because emitting headers early would prevent
184194// finalizing Content-Length after the handler completes.
@@ -197,6 +207,10 @@ func (w *headResponseWriter) WriteHeader(code int) {
197207 if w .wroteStatus {
198208 return
199209 }
210+ if code >= 100 && code < 200 && code != http .StatusSwitchingProtocols {
211+ w .rw .WriteHeader (code )
212+ return
213+ }
200214 w .wroteStatus = true
201215 w .status = code
202216 if r , err := UnwrapResponse (w .rw ); err == nil {
0 commit comments