Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b03077b
refactor: decouple writer in requests printing functions
xenOs76 Nov 29, 2025
ab47545
refactor: decouple enable flag and header generation for SetProxyProt…
xenOs76 Nov 29, 2025
c447ab5
refactor: PrintCmd function call in requests_handlers
xenOs76 Nov 29, 2025
6080649
ci: add some tests for requests
xenOs76 Nov 29, 2025
c562210
fix: non-TLS test case out of main loop in TestPrintResponseDebug
xenOs76 Nov 29, 2025
101de86
refactor: check nil http Response in PrintResponseDebug
xenOs76 Nov 29, 2025
cb65898
refactor: manage error in PrintRequestDebug call
xenOs76 Nov 29, 2025
7eccb1b
fix: typo in TestNewHTTPClientFromRequestConfig
xenOs76 Nov 29, 2025
6c67a1d
refactor: TestPrintRespondeDebug to decrease assert check over partia…
xenOs76 Nov 29, 2025
97b2229
fix: typos in TestPrintRequestDebug
xenOs76 Nov 29, 2025
0c05e61
refactor: SetServerName check for empty string and url as input
xenOs76 Nov 29, 2025
3e31574
refactor: tests related to SetServerName
xenOs76 Nov 29, 2025
15b1478
fix: typos in tests
xenOs76 Nov 29, 2025
93bcea6
refactor: TestPrintCmd to check for partial string match
xenOs76 Nov 29, 2025
7035520
refactor: remove unused error retuened by SetProxyProtocolV2
xenOs76 Nov 29, 2025
3f7bfa4
fix: error checking and typos
xenOs76 Nov 29, 2025
40358d3
ci: add go code checks to GitHub Actions
xenOs76 Nov 29, 2025
beaca2d
ci: update checkout and Setup Go actions
xenOs76 Nov 29, 2025
9c4eb6d
fix: error assertion in SetClientTimeout test
xenOs76 Nov 29, 2025
23d605b
ci: wrap go-version in release action and update go.mod
xenOs76 Nov 29, 2025
463ba58
refactor: error handling
xenOs76 Nov 29, 2025
e20fa09
refactor: validate transportAddress value returned by RequestConfig H…
xenOs76 Nov 29, 2025
e3f9841
refactor: validate on empty byte list instead of comparing when Print…
xenOs76 Nov 29, 2025
0e46054
refactor: update test struct to manage cases causing errors
xenOs76 Nov 29, 2025
d4203ab
refactor: test loops using t.Parallel() to import a local copy of the…
xenOs76 Nov 29, 2025
b5a27a7
ci: test errors in PrintResponseDebug
xenOs76 Nov 29, 2025
e9b5db3
refactor: replace assert with require in SetInsecureSkipVerify
xenOs76 Nov 29, 2025
de18e71
ci: test malformed HTTP client in SetServerName
xenOs76 Nov 29, 2025
969f42b
ci: add tests to check nil or incomplete HTTP client in RequestHTTPCl…
xenOs76 Nov 29, 2025
cdf659e
refactor: require no error in SetClientTimeout
xenOs76 Nov 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 69 additions & 31 deletions internal/requests/requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
"crypto/x509"
"errors"
"fmt"
"io"
"net"
"net/http"
"net/http/httputil"
"os"
"strings"
"time"

Expand Down Expand Up @@ -181,11 +183,13 @@
return r
}

func (r *RequestsMetaConfig) PrintCmd() {
func (r *RequestsMetaConfig) PrintCmd(w io.Writer) {
if r.RequestVerbose {
fmt.Println()
fmt.Println(style.LgSprintf(style.Cmd, "Requests"))
fmt.Println()
fmt.Fprintf(
w,
"\n%s\n",
style.LgSprintf(style.Cmd, "Requests"),
)
}
}

Expand All @@ -201,50 +205,62 @@
}
}

func (r *RequestConfig) PrintRequestDebug(req *http.Request) {
func (r *RequestConfig) PrintRequestDebug(w io.Writer, req *http.Request) error {
if req == nil {
return errors.New("nil pointer to http.Request")
}

if r.RequestDebug {
reqDump, err := httputil.DumpRequestOut(req, true)
if err != nil {
fmt.Printf("Warning: failed to dump request: %v\n", err)
return
fmt.Fprintf(w, "Warning: failed to dump request: %v\n", err)
return err
}

fmt.Printf("Requesting url: %s\n", req.URL)
fmt.Printf("Request dump:\n%s\n", string(reqDump))
_, err = fmt.Fprintf(w, "Requesting url: %s\nRequest dump:\n%s\n", req.URL, string(reqDump))

return err
}

return nil
}

func (r *RequestConfig) PrintResponseDebug(resp *http.Response) {
func (r *RequestConfig) PrintResponseDebug(w io.Writer, resp *http.Response) {

Check failure on line 228 in internal/requests/requests.go

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this method to reduce its Cognitive Complexity from 17 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=xenOs76_https-wrench&issues=AZrO-GCXJZbHrzp7Z5ba&open=AZrO-GCXJZbHrzp7Z5ba&pullRequest=10
// TODO: return an error

Check warning on line 229 in internal/requests/requests.go

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this TODO comment.

See more on https://sonarcloud.io/project/issues?id=xenOs76_https-wrench&issues=AZrPLimqVwhrarSxhOYw&open=AZrPLimqVwhrarSxhOYw&pullRequest=10
if resp == nil {
return
}

if r.ResponseDebug {
respDump, err := httputil.DumpResponse(resp, true)
if err != nil {
fmt.Printf("Warning: failed to dump response: %v\n", err)
fmt.Fprintf(w, "Warning: failed to dump response: %v\n", err)
return
}

fmt.Printf("Requested url: %s\n", resp.Request.URL)
fmt.Printf("Response dump:\n%s\n", string(respDump))
fmt.Fprintf(w, "Requested url: %s\n", resp.Request.URL)
fmt.Fprintf(w, "Response dump:\n%s\n", string(respDump))

if resp.TLS != nil {
fmt.Println("TLS:")
fmt.Printf("Version: %v\n", TLSVersionName(resp.TLS.Version))
fmt.Printf("CipherSuite: %v\n", cipherSuiteName(resp.TLS.CipherSuite))
fmt.Fprintln(w, "TLS:")
fmt.Fprintf(w, "Version: %v\n", TLSVersionName(resp.TLS.Version))
fmt.Fprintf(w, "CipherSuite: %v\n", cipherSuiteName(resp.TLS.CipherSuite))

for i, cert := range resp.TLS.PeerCertificates {
fmt.Printf("Certificate %d:\n", i)
fmt.Fprintf(w, "Certificate %d:\n", i)
certinfo.PrintCertInfo(cert, 1)
}

for i, chain := range resp.TLS.VerifiedChains {
fmt.Printf("Verified Chain %d:\n", i)
fmt.Fprintf(w, "Verified Chain %d:\n", i)

for j, cert := range chain {
fmt.Printf(" Cert %d:\n", j)
fmt.Fprintf(w, " Cert %d:\n", j)
certinfo.PrintCertInfo(cert, 2)
}
}
} else {
fmt.Println("TLS: Not available (non-TLS connection)")
fmt.Fprintln(w, "TLS: Not available (non-TLS connection)")
}
}
}
Comment thread
xenOs76 marked this conversation as resolved.
Expand Down Expand Up @@ -275,6 +291,14 @@
"*RequestHTTPClient.client is nil. Use NewRequestHTTPClient to initialize")
}

if serverName == emptyString {
return nil, errors.New("serverName cannot be empty")
}

if strings.Contains(serverName, "://") {
return nil, fmt.Errorf("serverName should be a hostname, not a URL: %s", serverName)
}

transport, ok := rc.client.Transport.(*http.Transport)
if !ok {
return nil, fmt.Errorf("expected *http.Transport, got %T", rc.client.Transport)
Expand Down Expand Up @@ -406,9 +430,15 @@
return rc, nil
}

func (rc *RequestHTTPClient) SetProxyProtocolV2(header proxyproto.Header) (*RequestHTTPClient, error) {
func (rc *RequestHTTPClient) SetProxyProtocolV2(enable bool) *RequestHTTPClient {
rc.enableProxyProtoV2 = enable

return rc
}

func (rc *RequestHTTPClient) SetProxyProtocolHeader(header proxyproto.Header) (*RequestHTTPClient, error) {
if rc.transportAddress == emptyString {
return nil, errors.New("SetProxyProtocolV2 failed: transportOverrideURL not set")
return nil, errors.New("SetProxyProtocolHeader failed: transportOverrideURL not set")
}

if rc.client == nil {
Expand Down Expand Up @@ -457,18 +487,17 @@
"*RequestHTTPClient.client is nil. Use NewRequestHTTPClient to initialize")
}

if timeout < 0 {
return nil, fmt.Errorf("timeout value must be positive: %v provided", timeout)
}

t := time.Duration(timeout) * time.Second
rc.client.Timeout = t

return rc, nil
}

func NewHTTPClientFromRequestConfig(r RequestConfig, serverName string, caPool *x509.CertPool) (*RequestHTTPClient, error) {
if r.EnableProxyProtocolV2 && r.TransportOverrideURL == emptyString {
return nil, errors.New(
"if EnableProxyProtocolV2 is true, a TransportOverrideURL must be set")
}

reqClient := NewRequestHTTPClient()

_, err := reqClient.SetCACertsPool(caPool)
Expand Down Expand Up @@ -501,15 +530,22 @@
return nil, fmt.Errorf("SetTransportOverride error: %w", err)
}

reqClient.SetProxyProtocolV2(r.EnableProxyProtocolV2)

if r.EnableProxyProtocolV2 && r.TransportOverrideURL == emptyString {
return nil, errors.New(
"if EnableProxyProtocolV2 is true, a TransportOverrideURL must be set")
}

if r.EnableProxyProtocolV2 && reqClient.transportAddress != emptyString {
header, err := proxyProtoHeaderFromRequest(r, serverName)
if err != nil {
return nil, fmt.Errorf("error creating proxyproto Header: %w", err)
}

_, err = reqClient.SetProxyProtocolV2(header)
_, err = reqClient.SetProxyProtocolHeader(header)
if err != nil {
return nil, fmt.Errorf("SetProxyProtocolV2 error: %w", err)
return nil, fmt.Errorf("SetProxyProtocolHeader error: %w", err)
}
}

Expand Down Expand Up @@ -563,7 +599,9 @@
req.Header.Add(header.Key, header.Value)
}

r.PrintRequestDebug(req)
if err := r.PrintRequestDebug(os.Stdout, req); err != nil {
fmt.Fprintf(os.Stderr, "Warning: PrintRequestDebug failed: %v\n", err)
}

resp, err := reqClient.client.Do(req)
if err != nil {
Expand All @@ -580,7 +618,7 @@
continue
}

r.PrintResponseDebug(resp)
r.PrintResponseDebug(os.Stdout, resp)

responseData.Response = resp

Expand Down
3 changes: 2 additions & 1 deletion internal/requests/requests_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"net"
"net/http"
"net/url"
"os"
"regexp"
"slices"
"strconv"
Expand Down Expand Up @@ -205,7 +206,7 @@ func proxyProtoHeaderFromRequest(r RequestConfig, serverName string) (proxyproto
func HandleRequests(cfg *RequestsMetaConfig) (map[string][]ResponseData, error) {
responseDataMap := make(map[string][]ResponseData)

cfg.PrintCmd()
cfg.PrintCmd(os.Stdout)

for _, r := range cfg.Requests {
responseDataList, err := processHTTPRequestsByHost(
Expand Down
Loading
Loading