@@ -10,9 +10,11 @@ import (
10
10
"io"
11
11
"net/http"
12
12
"net/url"
13
+ "strings"
13
14
"sync"
14
15
"time"
15
16
17
+ "github.com/NVIDIA/aistore/api/apc"
16
18
"github.com/NVIDIA/aistore/cmn/cos"
17
19
)
18
20
38
40
39
41
var (
40
42
hpool sync.Pool
43
+ hmap sync.Map
41
44
req0 http.Request
42
45
)
43
46
@@ -125,27 +128,70 @@ func (u *HreqArgs) ReqWith(timeout time.Duration) (*http.Request, context.Contex
125
128
return req , ctx , cancel , nil
126
129
}
127
130
128
- func newRequest (method , urls string ) (* http.Request , error ) {
129
- // 1. parse
130
- // TODO: split (before url.Path) and (after), and optimize
131
- u , err := url .Parse (urls )
132
- if err != nil {
133
- return nil , err
131
+ func splitUpath (surl string ) (prefix , path string ) {
132
+ const (
133
+ minSchemeHostLen = 10
134
+ )
135
+ i := strings .Index (surl , apc .URLPathObjects .S )
136
+ if i <= minSchemeHostLen {
137
+ return "" , ""
138
+ }
139
+ prefix , path = surl [:i ], surl [i :]
140
+ for _ , c := range path { // reject control characters and space
141
+ if c < 0x20 || c == 0x7f {
142
+ return "" , ""
143
+ }
144
+ }
145
+ return prefix , path
146
+ }
147
+
148
+ func newRequest (method , surl string ) (* http.Request , error ) {
149
+ var (
150
+ err error
151
+ u * url.URL
152
+ )
153
+ // 1. fast path: split and reuse "/v1/objects/" url
154
+ prefix , path := splitUpath (surl )
155
+ if prefix == "" {
156
+ u , err = url .Parse (surl )
157
+ if err != nil {
158
+ return nil , err
159
+ }
160
+ } else if parsed , ok := hmap .Load (prefix ); ok {
161
+ u = parsed .(* url.URL )
162
+ tmp := * u // shallow copy (not to mutate the cached one)
163
+
164
+ p , q , ok := strings .Cut (path , "?" )
165
+ if ok {
166
+ tmp .RawQuery = q
167
+ } else {
168
+ tmp .RawQuery = ""
169
+ }
170
+ decoded , _ := url .PathUnescape (p )
171
+ tmp .Path = decoded
172
+ tmp .RawPath = p
173
+
174
+ u = & tmp
175
+ } else {
176
+ u , err = url .Parse (surl )
177
+ if err != nil {
178
+ return nil , err
179
+ }
180
+ hmap .Store (prefix , u )
134
181
}
135
182
136
183
// 2. reuse and initialize request
137
184
req := hreqAlloc ()
138
- {
139
- req .Method = method
140
- req .URL = u
141
- req .Proto = "HTTP/1.1"
142
- req .ProtoMajor = 1
143
- req .ProtoMinor = 1
144
- if req .Header == nil {
145
- req .Header = make (http.Header , 4 )
146
- }
147
- req .Host = u .Host
185
+ req .Method = method
186
+ req .URL = u
187
+ req .Proto = "HTTP/1.1"
188
+ req .ProtoMajor = 1
189
+ req .ProtoMinor = 1
190
+ if req .Header == nil {
191
+ req .Header = make (http.Header , 4 )
148
192
}
193
+ req .Host = u .Host
194
+
149
195
return req , nil
150
196
}
151
197
0 commit comments