Part of duplicate code analysis: #3207
Summary
Two separate functions in internal/server/ independently implement the same "read HTTP request body, process it, restore it for downstream handlers" pattern. The guard logic (r.Method == "POST" && r.Body != nil, io.ReadAll, then r.Body = io.NopCloser(bytes.NewBuffer(...))) is duplicated across ~15 lines in two files.
Duplication Details
Pattern: Read-process-restore of http.Request.Body
// http_helpers.go (logHTTPRequestBody)
if r.Method != "POST" || r.Body == nil {
return
}
bodyBytes, err := io.ReadAll(r.Body)
if err != nil || len(bodyBytes) == 0 {
return
}
// ... process bodyBytes ...
r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
// sdk_logging.go (WithSDKLogging)
if r.Method == "POST" && r.Body != nil {
requestBody, err = io.ReadAll(r.Body)
if err == nil && len(requestBody) > 0 {
r.Body = io.NopCloser(bytes.NewBuffer(requestBody))
// ... process requestBody ...
}
}
Impact Analysis
- Maintainability: If the body-restore idiom needs to change (e.g., to use a
bytes.Reader instead of bytes.Buffer, or to handle large bodies with limits), it must be updated in two places.
- Bug Risk: Low today, but divergence is possible — e.g. one site already uses inverted guard logic (
!= "POST" early return vs == "POST" positive guard).
- Code Bloat: ~12 lines of near-identical plumbing repeated unnecessarily.
Refactoring Recommendations
-
Extract a shared helper peekRequestBody(r *http.Request) ([]byte, error) in internal/server/http_helpers.go (or a new internal/httputil function) that:
- Checks method and body presence
- Reads the body
- Restores it with
io.NopCloser
- Returns the bytes (caller decides what to do with them)
// Suggested location: internal/server/http_helpers.go or internal/httputil/httputil.go
func peekRequestBody(r *http.Request) ([]byte, error) {
if r.Method != http.MethodPost || r.Body == nil {
return nil, nil
}
b, err := io.ReadAll(r.Body)
if err != nil {
return nil, err
}
r.Body = io.NopCloser(bytes.NewBuffer(b))
return b, nil
}
-
Update callers to use the helper and apply their own post-processing on the returned bytes.
-
Estimated effort: 1–2 hours including tests.
Implementation Checklist
Parent Issue
See parent analysis report: #3207
Related to #3207
Generated by Duplicate Code Detector · ◷
Part of duplicate code analysis: #3207
Summary
Two separate functions in
internal/server/independently implement the same "read HTTP request body, process it, restore it for downstream handlers" pattern. The guard logic (r.Method == "POST" && r.Body != nil,io.ReadAll, thenr.Body = io.NopCloser(bytes.NewBuffer(...))) is duplicated across ~15 lines in two files.Duplication Details
Pattern: Read-process-restore of
http.Request.BodySeverity: Medium
Occurrences: 2 independent implementations
Locations:
internal/server/http_helpers.golines 106–136 (logHTTPRequestBody)internal/server/sdk_logging.golines 55–76 (WithSDKLogging)Shared code structure:
Impact Analysis
bytes.Readerinstead ofbytes.Buffer, or to handle large bodies with limits), it must be updated in two places.!= "POST"early return vs== "POST"positive guard).Refactoring Recommendations
Extract a shared helper
peekRequestBody(r *http.Request) ([]byte, error)ininternal/server/http_helpers.go(or a newinternal/httputilfunction) that:io.NopCloserUpdate callers to use the helper and apply their own post-processing on the returned bytes.
Estimated effort: 1–2 hours including tests.
Implementation Checklist
peekRequestBodyhelper (or equivalent) in a shared locationlogHTTPRequestBodyinhttp_helpers.goto use the helperWithSDKLogginginsdk_logging.goto use the helpermake testto confirm no behaviour changeParent Issue
See parent analysis report: #3207
Related to #3207