Skip to content

Commit 3a73391

Browse files
author
Igor Drozdov
committed
Define Do function for Gitlab net client
In future, we'll need to perform http requests for Geo related code area. We cannot use retryable requests because: - It's not necessary for the to be retryable - In order to retry, the whole request body is stored in RAM, while we need to stream large blobs of data This commit: - Extracts logging into a separate round tripper in order to reuse it for other http requests by default - Defines Do function that accepts raw request as an argument
1 parent 336c4a5 commit 3a73391

File tree

3 files changed

+77
-37
lines changed

3 files changed

+77
-37
lines changed

client/gitlabnet.go

+15-34
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ import (
1212

1313
"github.com/golang-jwt/jwt/v4"
1414
"github.com/hashicorp/go-retryablehttp"
15-
16-
"gitlab.com/gitlab-org/labkit/log"
1715
)
1816

1917
const (
@@ -107,7 +105,11 @@ func newRequest(ctx context.Context, method, host, path string, data interface{}
107105
return request, nil
108106
}
109107

110-
func parseError(resp *http.Response) error {
108+
func parseError(resp *http.Response, respErr error) error {
109+
if respErr != nil {
110+
return &ApiError{"Internal API unreachable"}
111+
}
112+
111113
if resp.StatusCode >= 200 && resp.StatusCode <= 399 {
112114
return nil
113115
}
@@ -129,6 +131,15 @@ func (c *GitlabNetClient) Post(ctx context.Context, path string, data interface{
129131
return c.DoRequest(ctx, http.MethodPost, normalizePath(path), data)
130132
}
131133

134+
func (c *GitlabNetClient) Do(request *http.Request) (*http.Response, error) {
135+
response, err := c.httpClient.RetryableHTTP.HTTPClient.Do(request)
136+
if err := parseError(response, err); err != nil {
137+
return nil, err
138+
}
139+
140+
return response, nil
141+
}
142+
132143
func (c *GitlabNetClient) DoRequest(ctx context.Context, method, path string, data interface{}) (*http.Response, error) {
133144
request, err := newRequest(ctx, method, c.httpClient.Host, path, data)
134145
if err != nil {
@@ -152,43 +163,13 @@ func (c *GitlabNetClient) DoRequest(ctx context.Context, method, path string, da
152163
}
153164
request.Header.Set(apiSecretHeaderName, tokenString)
154165

155-
originalRemoteIP, ok := ctx.Value(OriginalRemoteIPContextKey{}).(string)
156-
if ok {
157-
request.Header.Add("X-Forwarded-For", originalRemoteIP)
158-
}
159-
160166
request.Header.Add("Content-Type", "application/json")
161167
request.Header.Add("User-Agent", c.userAgent)
162-
request.Close = true
163-
164-
start := time.Now()
165168

166169
response, err := c.httpClient.RetryableHTTP.Do(request)
167-
fields := log.Fields{
168-
"method": method,
169-
"url": request.URL.String(),
170-
"duration_ms": time.Since(start) / time.Millisecond,
171-
}
172-
logger := log.WithContextFields(ctx, fields)
173-
174-
if err != nil {
175-
logger.WithError(err).Error("Internal API unreachable")
176-
return nil, &ApiError{"Internal API unreachable"}
177-
}
178-
179-
if response != nil {
180-
logger = logger.WithField("status", response.StatusCode)
181-
}
182-
if err := parseError(response); err != nil {
183-
logger.WithError(err).Error("Internal API error")
170+
if err := parseError(response, err); err != nil {
184171
return nil, err
185172
}
186173

187-
if response.ContentLength >= 0 {
188-
logger = logger.WithField("content_length_bytes", response.ContentLength)
189-
}
190-
191-
logger.Info("Finished HTTP request")
192-
193174
return response, nil
194175
}

client/httpclient.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ import (
1414
"time"
1515

1616
"github.com/hashicorp/go-retryablehttp"
17-
"gitlab.com/gitlab-org/labkit/correlation"
18-
"gitlab.com/gitlab-org/labkit/tracing"
1917
)
2018

2119
const (
@@ -121,7 +119,7 @@ func NewHTTPClientWithOpts(gitlabURL, gitlabRelativeURLRoot, caFile, caPath stri
121119
c.RetryWaitMax = hcc.retryWaitMax
122120
c.RetryWaitMin = hcc.retryWaitMin
123121
c.Logger = nil
124-
c.HTTPClient.Transport = correlation.NewInstrumentedRoundTripper(tracing.NewRoundTripper(transport))
122+
c.HTTPClient.Transport = newTransport(transport)
125123
c.HTTPClient.Timeout = readTimeout(readTimeoutSeconds)
126124

127125
client := &HttpClient{RetryableHTTP: c, Host: host}

client/transport.go

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package client
2+
3+
import (
4+
"net/http"
5+
"time"
6+
7+
"gitlab.com/gitlab-org/labkit/correlation"
8+
"gitlab.com/gitlab-org/labkit/log"
9+
"gitlab.com/gitlab-org/labkit/tracing"
10+
)
11+
12+
type transport struct {
13+
next http.RoundTripper
14+
}
15+
16+
func (rt *transport) RoundTrip(request *http.Request) (*http.Response, error) {
17+
ctx := request.Context()
18+
19+
originalRemoteIP, ok := ctx.Value(OriginalRemoteIPContextKey{}).(string)
20+
if ok {
21+
request.Header.Add("X-Forwarded-For", originalRemoteIP)
22+
}
23+
request.Close = true
24+
request.Header.Add("User-Agent", defaultUserAgent)
25+
26+
start := time.Now()
27+
28+
response, err := rt.next.RoundTrip(request)
29+
30+
fields := log.Fields{
31+
"method": request.Method,
32+
"url": request.URL.String(),
33+
"duration_ms": time.Since(start) / time.Millisecond,
34+
}
35+
logger := log.WithContextFields(ctx, fields)
36+
37+
if err != nil {
38+
logger.WithError(err).Error("Internal API unreachable")
39+
return response, err
40+
}
41+
42+
logger = logger.WithField("status", response.StatusCode)
43+
44+
if response.StatusCode >= 400 {
45+
logger.WithError(err).Error("Internal API error")
46+
return response, err
47+
}
48+
49+
if response.ContentLength >= 0 {
50+
logger = logger.WithField("content_length_bytes", response.ContentLength)
51+
}
52+
53+
logger.Info("Finished HTTP request")
54+
55+
return response, nil
56+
}
57+
58+
func newTransport(next http.RoundTripper) http.RoundTripper {
59+
t := &transport{next: next}
60+
return correlation.NewInstrumentedRoundTripper(tracing.NewRoundTripper(t))
61+
}

0 commit comments

Comments
 (0)