(req *http.Request)
| 71 | } |
| 72 | |
| 73 | func (d *dumper) dumpRequest(req *http.Request) error { |
| 74 | dumpPath := d.dumpPath + SuffixRequest |
| 75 | if err := os.MkdirAll(filepath.Dir(dumpPath), 0o755); err != nil { |
| 76 | return xerrors.Errorf("create dump dir: %w", err) |
| 77 | } |
| 78 | |
| 79 | // Read and restore body |
| 80 | var bodyBytes []byte |
| 81 | if req.Body != nil { |
| 82 | var err error |
| 83 | bodyBytes, err = io.ReadAll(req.Body) |
| 84 | if err != nil { |
| 85 | return xerrors.Errorf("read request body: %w", err) |
| 86 | } |
| 87 | req.Body = io.NopCloser(bytes.NewReader(bodyBytes)) |
| 88 | } |
| 89 | |
| 90 | prettyBody := prettyPrintJSON(bodyBytes) |
| 91 | |
| 92 | // Build raw HTTP request format |
| 93 | var buf bytes.Buffer |
| 94 | _, err := fmt.Fprintf(&buf, "%s %s %s\r\n", req.Method, req.URL.RequestURI(), req.Proto) |
| 95 | if err != nil { |
| 96 | return xerrors.Errorf("write request uri: %w", err) |
| 97 | } |
| 98 | err = d.writeRedactedHeaders(&buf, req.Header, sensitiveRequestHeaders, map[string]string{ |
| 99 | "Content-Length": fmt.Sprintf("%d", len(prettyBody)), |
| 100 | }) |
| 101 | if err != nil { |
| 102 | return xerrors.Errorf("write request headers: %w", err) |
| 103 | } |
| 104 | |
| 105 | _, err = fmt.Fprintf(&buf, "\r\n") |
| 106 | if err != nil { |
| 107 | return xerrors.Errorf("write request header terminator: %w", err) |
| 108 | } |
| 109 | // bytes.Buffer writes to in-memory storage and never return errors. |
| 110 | _, _ = buf.Write(prettyBody) |
| 111 | _ = buf.WriteByte('\n') |
| 112 | |
| 113 | return os.WriteFile(dumpPath, buf.Bytes(), 0o644) //nolint:gosec // https://github.com/coder/aibridge/pull/256#discussion_r3072143983 |
| 114 | } |
| 115 | |
| 116 | func (d *dumper) dumpResponse(resp *http.Response) error { |
| 117 | dumpPath := d.dumpPath + SuffixResponse |
no test coverage detected