@@ -5,11 +5,13 @@ import (
5
5
"context"
6
6
"net/http"
7
7
"net/http/httptest"
8
+ "net/url"
8
9
"sort"
9
10
"strconv"
10
11
"time"
11
12
12
13
"github.com/chromedp/cdproto/har"
14
+ "github.com/gorilla/handlers"
13
15
"github.com/speakeasy-api/speakeasy-go-sdk/internal/bodymasking"
14
16
"github.com/speakeasy-api/speakeasy-go-sdk/internal/log"
15
17
"go.uber.org/zap"
@@ -18,20 +20,7 @@ import (
18
20
type harBuilder struct {}
19
21
20
22
func (h * harBuilder ) buildHarFile (ctx context.Context , cw * captureWriter , r * http.Request , startTime time.Time , c * controller ) * har.HAR {
21
- queryParams := r .URL .Query ()
22
- for key , values := range queryParams {
23
- queryParams .Del (key )
24
-
25
- for _ , value := range values {
26
- mask , ok := c .queryStringMasks [key ]
27
- if ok {
28
- value = mask
29
- }
30
-
31
- queryParams .Add (key , value )
32
- }
33
- }
34
- r .URL .RawQuery = queryParams .Encode ()
23
+ resolvedURL := getResolvedURL (r , c )
35
24
36
25
return & har.HAR {
37
26
Log : & har.Log {
@@ -40,15 +29,15 @@ func (h *harBuilder) buildHarFile(ctx context.Context, cw *captureWriter, r *htt
40
29
Name : sdkName ,
41
30
Version : speakeasyVersion ,
42
31
},
43
- Comment : "request capture for " + r . URL .String (),
32
+ Comment : "request capture for " + resolvedURL .String (),
44
33
Entries : []* har.Entry {
45
34
{
46
35
StartedDateTime : startTime .Format (time .RFC3339Nano ),
47
36
Time : float64 (timeSince (startTime ).Milliseconds ()),
48
- Request : h .getHarRequest (ctx , cw , r , c ),
37
+ Request : h .getHarRequest (ctx , cw , r , c , resolvedURL ),
49
38
Response : h .getHarResponse (ctx , cw , r , startTime , c ),
50
- Connection : r . URL .Port (),
51
- ServerIPAddress : r . URL .Hostname (),
39
+ Connection : resolvedURL .Port (),
40
+ ServerIPAddress : resolvedURL .Hostname (),
52
41
Cache : & har.Cache {},
53
42
Timings : & har.Timings {
54
43
Send : - 1 ,
@@ -61,8 +50,50 @@ func (h *harBuilder) buildHarFile(ctx context.Context, cw *captureWriter, r *htt
61
50
}
62
51
}
63
52
53
+ func getResolvedURL (r * http.Request , c * controller ) * url.URL {
54
+ var url * url.URL
55
+
56
+ // Taking advantage of Gorilla's ProxyHeaders parsing to resolve Forwarded headers
57
+ handlers .ProxyHeaders (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
58
+ url = r .URL
59
+ })).ServeHTTP (nil , r )
60
+
61
+ queryParams := url .Query ()
62
+ for key , values := range queryParams {
63
+ queryParams .Del (key )
64
+
65
+ for _ , value := range values {
66
+ mask , ok := c .queryStringMasks [key ]
67
+ if ok {
68
+ value = mask
69
+ }
70
+
71
+ queryParams .Add (key , value )
72
+ }
73
+ }
74
+ url .RawQuery = queryParams .Encode ()
75
+
76
+ if url .IsAbs () {
77
+ return url
78
+ }
79
+
80
+ if url .Scheme == "" {
81
+ if r .TLS != nil {
82
+ url .Scheme = "https"
83
+ } else {
84
+ url .Scheme = "http"
85
+ }
86
+ }
87
+
88
+ if url .Host == "" {
89
+ url .Host = r .Host
90
+ }
91
+
92
+ return url
93
+ }
94
+
64
95
//nolint:funlen
65
- func (h * harBuilder ) getHarRequest (ctx context.Context , cw * captureWriter , r * http.Request , c * controller ) * har.Request {
96
+ func (h * harBuilder ) getHarRequest (ctx context.Context , cw * captureWriter , r * http.Request , c * controller , url * url. URL ) * har.Request {
66
97
reqHeaders := []* har.NameValuePair {}
67
98
for key , headers := range r .Header {
68
99
for _ , headerValue := range headers {
@@ -123,7 +154,7 @@ func (h *harBuilder) getHarRequest(ctx context.Context, cw *captureWriter, r *ht
123
154
124
155
return & har.Request {
125
156
Method : r .Method ,
126
- URL : r . URL .String (),
157
+ URL : url .String (),
127
158
Headers : reqHeaders ,
128
159
QueryString : reqQueryParams ,
129
160
BodySize : bodySize ,
0 commit comments