Repository: caddyserver/caddy
File: modules/caddyhttp/server.go (Go)

Code before:
			s.accessLogger.Warn("failed to enable full duplex", zap.Error(err))
		}
	}

	// encode the request for logging purposes before
	// it enters any handler chain; this is necessary
	// to capture the original request in case it gets
	// modified during handling
	shouldLogCredentials := s.Logs != nil && s.Logs.ShouldLogCredentials
	loggableReq := zap.Object("request", LoggableHTTPRequest{
		Request:              r,
		ShouldLogCredentials: shouldLogCredentials,
	})
	errLog := s.errorLogger.With(loggableReq)

	var duration time.Duration

	if s.shouldLogRequest(r) {
		wrec := NewResponseRecorder(w, nil, nil)
		w = wrec

		// wrap the request body in a LengthReader
		// so we can track the number of bytes read from it
		var bodyReader *lengthReader
		if r.Body != nil {
			bodyReader = getLengthReader(r.Body)
			r.Body = bodyReader
		}

		// capture the original version of the request
		accLog := s.accessLogger.With(loggableReq)

		defer s.logRequest(accLog, r, wrec, &duration, repl, bodyReader, shouldLogCredentials)
	}

	start := time.Now()

	// guarantee ACME HTTP challenges; handle them
	// separately from any user-defined handlers
	if s.tlsApp.HandleHTTPChallenge(w, r) {
		duration = time.Since(start)
		return
	}

	// execute the primary handler chain
	err := s.primaryHandlerChain.ServeHTTP(w, r)
	duration = time.Since(start)

	// if no errors, we're done!
	if err == nil {
		return

Review comment (suggestion):
I think it should be safe to just do it like this:

```suggestion
			bodyReader = getLengthReader(r.Body)
			defer putLengthReader(bodyReader)
```

Because `defer` runs in reverse order on the way out, so `defer s.logRequest` will run before `defer putLengthReader`.

Code after:
			s.accessLogger.Warn("failed to enable full duplex", zap.Error(err))
		}
	}

	// encode the request for logging purposes before
	// it enters any handler chain; this is necessary
	// to capture the original request in case it gets
	// modified during handling
	shouldLogCredentials := s.Logs != nil && s.Logs.ShouldLogCredentials
	loggableReq := zap.Object("request", LoggableHTTPRequest{
		Request:              r,
		ShouldLogCredentials: shouldLogCredentials,
	})
	errLog := s.errorLogger.With(loggableReq)

	var duration time.Duration

	if s.shouldLogRequest(r) {
		wrec := NewResponseRecorder(w, nil, nil)
		w = wrec

		// wrap the request body in a LengthReader
		// so we can track the number of bytes read from it
		var bodyReader *lengthReader
		if r.Body != nil {
			bodyReader = getLengthReader(r.Body)
			defer putLengthReader(bodyReader)
			r.Body = bodyReader
		}

		// capture the original version of the request
		accLog := s.accessLogger.With(loggableReq)

		defer s.logRequest(accLog, r, wrec, &duration, repl, bodyReader, shouldLogCredentials)
	}

	start := time.Now()

	// guarantee ACME HTTP challenges; handle them
	// separately from any user-defined handlers
	if s.tlsApp.HandleHTTPChallenge(w, r) {
		duration = time.Since(start)
		return
	}

	// execute the primary handler chain
	err := s.primaryHandlerChain.ServeHTTP(w, r)
	duration = time.Since(start)

	// if no errors, we're done!
	if err == nil {