8
8
"context"
9
9
"errors"
10
10
"fmt"
11
+ "io"
11
12
"net/http"
12
13
"net/url"
13
14
"strings"
@@ -17,7 +18,7 @@ import (
17
18
"code.gitea.io/gitea/modules/proxy"
18
19
)
19
20
20
- const batchSize = 20
21
+ const httpBatchSize = 20
21
22
22
23
// HTTPClient is used to communicate with the LFS server
23
24
// https://github.com/git-lfs/git-lfs/blob/main/docs/api/batch.md
@@ -29,7 +30,7 @@ type HTTPClient struct {
29
30
30
31
// BatchSize returns the preferred size of batchs to process
31
32
func (c * HTTPClient ) BatchSize () int {
32
- return batchSize
33
+ return httpBatchSize
33
34
}
34
35
35
36
func newHTTPClient (endpoint * url.URL , httpTransport * http.Transport ) * HTTPClient {
@@ -43,28 +44,25 @@ func newHTTPClient(endpoint *url.URL, httpTransport *http.Transport) *HTTPClient
43
44
Transport : httpTransport ,
44
45
}
45
46
47
+ basic := & BasicTransferAdapter {hc }
46
48
client := & HTTPClient {
47
- client : hc ,
48
- endpoint : strings .TrimSuffix (endpoint .String (), "/" ),
49
- transfers : make (map [string ]TransferAdapter ),
49
+ client : hc ,
50
+ endpoint : strings .TrimSuffix (endpoint .String (), "/" ),
51
+ transfers : map [string ]TransferAdapter {
52
+ basic .Name (): basic ,
53
+ },
50
54
}
51
55
52
- basic := & BasicTransferAdapter {hc }
53
-
54
- client .transfers [basic .Name ()] = basic
55
-
56
56
return client
57
57
}
58
58
59
59
func (c * HTTPClient ) transferNames () []string {
60
60
keys := make ([]string , len (c .transfers ))
61
-
62
61
i := 0
63
62
for k := range c .transfers {
64
63
keys [i ] = k
65
64
i ++
66
65
}
67
-
68
66
return keys
69
67
}
70
68
@@ -74,40 +72,24 @@ func (c *HTTPClient) batch(ctx context.Context, operation string, objects []Poin
74
72
url := fmt .Sprintf ("%s/objects/batch" , c .endpoint )
75
73
76
74
request := & BatchRequest {operation , c .transferNames (), nil , objects }
77
-
78
75
payload := new (bytes.Buffer )
79
76
err := json .NewEncoder (payload ).Encode (request )
80
77
if err != nil {
81
78
log .Error ("Error encoding json: %v" , err )
82
79
return nil , err
83
80
}
84
81
85
- log .Trace ("Calling: %s" , url )
86
-
87
- req , err := http .NewRequestWithContext (ctx , "POST" , url , payload )
82
+ req , err := createRequest (ctx , http .MethodPost , url , map [string ]string {"Content-Type" : MediaType }, payload )
88
83
if err != nil {
89
- log .Error ("Error creating request: %v" , err )
90
84
return nil , err
91
85
}
92
- req .Header .Set ("Content-type" , MediaType )
93
- req .Header .Set ("Accept" , MediaType )
94
86
95
- res , err := c .client . Do ( req )
87
+ res , err := performRequest ( ctx , c .client , req )
96
88
if err != nil {
97
- select {
98
- case <- ctx .Done ():
99
- return nil , ctx .Err ()
100
- default :
101
- }
102
- log .Error ("Error while processing request: %v" , err )
103
89
return nil , err
104
90
}
105
91
defer res .Body .Close ()
106
92
107
- if res .StatusCode != http .StatusOK {
108
- return nil , fmt .Errorf ("Unexpected server response: %s" , res .Status )
109
- }
110
-
111
93
var response BatchResponse
112
94
err = json .NewDecoder (res .Body ).Decode (& response )
113
95
if err != nil {
@@ -177,7 +159,7 @@ func (c *HTTPClient) performOperation(ctx context.Context, objects []Pointer, dc
177
159
link , ok := object .Actions ["upload" ]
178
160
if ! ok {
179
161
log .Debug ("%+v" , object )
180
- return errors .New ("Missing action 'upload'" )
162
+ return errors .New ("missing action 'upload'" )
181
163
}
182
164
183
165
content , err := uc (object .Pointer , nil )
@@ -187,8 +169,6 @@ func (c *HTTPClient) performOperation(ctx context.Context, objects []Pointer, dc
187
169
188
170
err = transferAdapter .Upload (ctx , link , object .Pointer , content )
189
171
190
- content .Close ()
191
-
192
172
if err != nil {
193
173
return err
194
174
}
@@ -203,7 +183,7 @@ func (c *HTTPClient) performOperation(ctx context.Context, objects []Pointer, dc
203
183
link , ok := object .Actions ["download" ]
204
184
if ! ok {
205
185
log .Debug ("%+v" , object )
206
- return errors .New ("Missing action 'download'" )
186
+ return errors .New ("missing action 'download'" )
207
187
}
208
188
209
189
content , err := transferAdapter .Download (ctx , link )
@@ -219,3 +199,59 @@ func (c *HTTPClient) performOperation(ctx context.Context, objects []Pointer, dc
219
199
220
200
return nil
221
201
}
202
+
203
+ // createRequest creates a new request, and sets the headers.
204
+ func createRequest (ctx context.Context , method , url string , headers map [string ]string , body io.Reader ) (* http.Request , error ) {
205
+ log .Trace ("createRequest: %s" , url )
206
+ req , err := http .NewRequestWithContext (ctx , method , url , body )
207
+ if err != nil {
208
+ log .Error ("Error creating request: %v" , err )
209
+ return nil , err
210
+ }
211
+
212
+ for key , value := range headers {
213
+ req .Header .Set (key , value )
214
+ }
215
+ req .Header .Set ("Accept" , MediaType )
216
+
217
+ return req , nil
218
+ }
219
+
220
+ // performRequest sends a request, optionally performs a callback on the request and returns the response.
221
+ // If the status code is 200, the response is returned, and it will contain a non-nil Body.
222
+ // Otherwise, it will return an error, and the Body will be nil or closed.
223
+ func performRequest (ctx context.Context , client * http.Client , req * http.Request ) (* http.Response , error ) {
224
+ log .Trace ("performRequest: %s" , req .URL )
225
+ res , err := client .Do (req )
226
+ if err != nil {
227
+ select {
228
+ case <- ctx .Done ():
229
+ return res , ctx .Err ()
230
+ default :
231
+ }
232
+ log .Error ("Error while processing request: %v" , err )
233
+ return res , err
234
+ }
235
+
236
+ if res .StatusCode != http .StatusOK {
237
+ defer res .Body .Close ()
238
+ return res , handleErrorResponse (res )
239
+ }
240
+
241
+ return res , nil
242
+ }
243
+
244
+ func handleErrorResponse (resp * http.Response ) error {
245
+ var er ErrorResponse
246
+ err := json .NewDecoder (resp .Body ).Decode (& er )
247
+ if err != nil {
248
+ if err == io .EOF {
249
+ return io .ErrUnexpectedEOF
250
+ }
251
+ log .Error ("Error decoding json: %v" , err )
252
+ return err
253
+ }
254
+
255
+ log .Trace ("ErrorResponse: %v" , er )
256
+ return errors .New (er .Message )
257
+ }
0 commit comments