1
8
9
10
11 package openapi
12
13 import (
14 "bytes"
15 "context"
16 "encoding/json"
17 "encoding/xml"
18 "errors"
19 "fmt"
20 "io"
21 "io/ioutil"
22 "log"
23 "mime/multipart"
24 "net/http"
25 "net/http/httputil"
26 "net/url"
27 "os"
28 "path/filepath"
29 "reflect"
30 "regexp"
31 "strconv"
32 "strings"
33 "time"
34 "unicode/utf8"
35
36 "golang.org/x/oauth2"
37 )
38
39 var (
40 jsonCheck = regexp.MustCompile(`(?i:(?:application|text)/(?:vnd\.[^;]+\+)?json)`)
41 xmlCheck = regexp.MustCompile(`(?i:(?:application|text)/xml)`)
42 )
43
44
45
46 type APIClient struct {
47 cfg *Configuration
48 common service
49
50
51
52 DefaultApi *DefaultApiService
53 }
54
55 type service struct {
56 client *APIClient
57 }
58
59
60
61 func NewAPIClient(cfg *Configuration) *APIClient {
62 if cfg.HTTPClient == nil {
63 cfg.HTTPClient = http.DefaultClient
64 }
65
66 c := &APIClient{}
67 c.cfg = cfg
68 c.common.client = c
69
70
71 c.DefaultApi = (*DefaultApiService)(&c.common)
72
73 return c
74 }
75
76 func atoi(in string) (int, error) {
77 return strconv.Atoi(in)
78 }
79
80
81 func selectHeaderContentType(contentTypes []string) string {
82 if len(contentTypes) == 0 {
83 return ""
84 }
85 if contains(contentTypes, "application/json") {
86 return "application/json"
87 }
88 return contentTypes[0]
89 }
90
91
92 func selectHeaderAccept(accepts []string) string {
93 if len(accepts) == 0 {
94 return ""
95 }
96
97 if contains(accepts, "application/json") {
98 return "application/json"
99 }
100
101 return strings.Join(accepts, ",")
102 }
103
104
105 func contains(haystack []string, needle string) bool {
106 for _, a := range haystack {
107 if strings.EqualFold(a, needle) {
108 return true
109 }
110 }
111 return false
112 }
113
114
115 func typeCheckParameter(obj interface{}, expected string, name string) error {
116
117 if obj == nil {
118 return nil
119 }
120
121
122 if reflect.TypeOf(obj).String() != expected {
123 return fmt.Errorf("expected %s to be of type %s but received %s", name, expected, reflect.TypeOf(obj).String())
124 }
125 return nil
126 }
127
128
129 func parameterToString(obj interface{}, collectionFormat string) string {
130 var delimiter string
131
132 switch collectionFormat {
133 case "pipes":
134 delimiter = "|"
135 case "ssv":
136 delimiter = " "
137 case "tsv":
138 delimiter = "\t"
139 case "csv":
140 delimiter = ","
141 }
142
143 if reflect.TypeOf(obj).Kind() == reflect.Slice {
144 return strings.Trim(strings.Replace(fmt.Sprint(obj), " ", delimiter, -1), "[]")
145 } else if t, ok := obj.(time.Time); ok {
146 return t.Format(time.RFC3339)
147 }
148
149 return fmt.Sprintf("%v", obj)
150 }
151
152
153 func parameterToJson(obj interface{}) (string, error) {
154 jsonBuf, err := json.Marshal(obj)
155 if err != nil {
156 return "", err
157 }
158 return string(jsonBuf), err
159 }
160
161
162 func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) {
163 if c.cfg.Debug {
164 dump, err := httputil.DumpRequestOut(request, true)
165 if err != nil {
166 return nil, err
167 }
168 log.Printf("\n%s\n", string(dump))
169 }
170
171 resp, err := c.cfg.HTTPClient.Do(request)
172 if err != nil {
173 return resp, err
174 }
175
176 if c.cfg.Debug {
177 dump, err := httputil.DumpResponse(resp, true)
178 if err != nil {
179 return resp, err
180 }
181 log.Printf("\n%s\n", string(dump))
182 }
183 return resp, err
184 }
185
186
187
188 func (c *APIClient) GetConfig() *Configuration {
189 return c.cfg
190 }
191
192 type formFile struct {
193 fileBytes []byte
194 fileName string
195 formFileName string
196 }
197
198
199 func (c *APIClient) prepareRequest(
200 ctx context.Context,
201 path string, method string,
202 postBody interface{},
203 headerParams map[string]string,
204 queryParams url.Values,
205 formParams url.Values,
206 formFiles []formFile) (localVarRequest *http.Request, err error) {
207
208 var body *bytes.Buffer
209
210
211 if postBody != nil {
212 contentType := headerParams["Content-Type"]
213 if contentType == "" {
214 contentType = detectContentType(postBody)
215 headerParams["Content-Type"] = contentType
216 }
217
218 body, err = setBody(postBody, contentType)
219 if err != nil {
220 return nil, err
221 }
222 }
223
224
225 if strings.HasPrefix(headerParams["Content-Type"], "multipart/form-data") && len(formParams) > 0 || (len(formFiles) > 0) {
226 if body != nil {
227 return nil, errors.New("Cannot specify postBody and multipart form at the same time.")
228 }
229 body = &bytes.Buffer{}
230 w := multipart.NewWriter(body)
231
232 for k, v := range formParams {
233 for _, iv := range v {
234 if strings.HasPrefix(k, "@") {
235 err = addFile(w, k[1:], iv)
236 if err != nil {
237 return nil, err
238 }
239 } else {
240 w.WriteField(k, iv)
241 }
242 }
243 }
244 for _, formFile := range formFiles {
245 if len(formFile.fileBytes) > 0 && formFile.fileName != "" {
246 w.Boundary()
247 part, err := w.CreateFormFile(formFile.formFileName, filepath.Base(formFile.fileName))
248 if err != nil {
249 return nil, err
250 }
251 _, err = part.Write(formFile.fileBytes)
252 if err != nil {
253 return nil, err
254 }
255 }
256 }
257
258
259 headerParams["Content-Type"] = w.FormDataContentType()
260
261
262 headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len())
263 w.Close()
264 }
265
266 if strings.HasPrefix(headerParams["Content-Type"], "application/x-www-form-urlencoded") && len(formParams) > 0 {
267 if body != nil {
268 return nil, errors.New("Cannot specify postBody and x-www-form-urlencoded form at the same time.")
269 }
270 body = &bytes.Buffer{}
271 body.WriteString(formParams.Encode())
272
273 headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len())
274 }
275
276
277 url, err := url.Parse(path)
278 if err != nil {
279 return nil, err
280 }
281
282
283 if c.cfg.Host != "" {
284 url.Host = c.cfg.Host
285 }
286
287
288 if c.cfg.Scheme != "" {
289 url.Scheme = c.cfg.Scheme
290 }
291
292
293 query := url.Query()
294 for k, v := range queryParams {
295 for _, iv := range v {
296 query.Add(k, iv)
297 }
298 }
299
300
301 url.RawQuery = query.Encode()
302
303
304 if body != nil {
305 localVarRequest, err = http.NewRequest(method, url.String(), body)
306 } else {
307 localVarRequest, err = http.NewRequest(method, url.String(), nil)
308 }
309 if err != nil {
310 return nil, err
311 }
312
313
314 if len(headerParams) > 0 {
315 headers := http.Header{}
316 for h, v := range headerParams {
317 headers[h] = []string{v}
318 }
319 localVarRequest.Header = headers
320 }
321
322
323 localVarRequest.Header.Add("User-Agent", c.cfg.UserAgent)
324
325 if ctx != nil {
326
327 localVarRequest = localVarRequest.WithContext(ctx)
328
329
330
331
332 if tok, ok := ctx.Value(ContextOAuth2).(oauth2.TokenSource); ok {
333
334 var latestToken *oauth2.Token
335 if latestToken, err = tok.Token(); err != nil {
336 return nil, err
337 }
338
339 latestToken.SetAuthHeader(localVarRequest)
340 }
341
342
343 if auth, ok := ctx.Value(ContextBasicAuth).(BasicAuth); ok {
344 localVarRequest.SetBasicAuth(auth.UserName, auth.Password)
345 }
346
347
348 if auth, ok := ctx.Value(ContextAccessToken).(string); ok {
349 localVarRequest.Header.Add("Authorization", "Bearer "+auth)
350 }
351
352 }
353
354 for header, value := range c.cfg.DefaultHeader {
355 localVarRequest.Header.Add(header, value)
356 }
357 return localVarRequest, nil
358 }
359
360 func (c *APIClient) decode(v interface{}, b []byte, contentType string) (err error) {
361 if len(b) == 0 {
362 return nil
363 }
364 if s, ok := v.(*string); ok {
365 *s = string(b)
366 return nil
367 }
368 if f, ok := v.(**os.File); ok {
369 *f, err = ioutil.TempFile("", "HttpClientFile")
370 if err != nil {
371 return
372 }
373 _, err = (*f).Write(b)
374 if err != nil {
375 return
376 }
377 _, err = (*f).Seek(0, io.SeekStart)
378 return
379 }
380 if xmlCheck.MatchString(contentType) {
381 if err = xml.Unmarshal(b, v); err != nil {
382 return err
383 }
384 return nil
385 }
386 if jsonCheck.MatchString(contentType) {
387 if actualObj, ok := v.(interface{ GetActualInstance() interface{} }); ok {
388 if unmarshalObj, ok := actualObj.(interface{ UnmarshalJSON([]byte) error }); ok {
389 if err = unmarshalObj.UnmarshalJSON(b); err != nil {
390 return err
391 }
392 } else {
393 return errors.New("Unknown type with GetActualInstance but no unmarshalObj.UnmarshalJSON defined")
394 }
395 } else if err = json.Unmarshal(b, v); err != nil {
396 return err
397 }
398 return nil
399 }
400 return errors.New("undefined response type")
401 }
402
403
404 func addFile(w *multipart.Writer, fieldName, path string) error {
405 file, err := os.Open(filepath.Clean(path))
406 if err != nil {
407 return err
408 }
409 err = file.Close()
410 if err != nil {
411 return err
412 }
413
414 part, err := w.CreateFormFile(fieldName, filepath.Base(path))
415 if err != nil {
416 return err
417 }
418 _, err = io.Copy(part, file)
419
420 return err
421 }
422
423
424 func reportError(format string, a ...interface{}) error {
425 return fmt.Errorf(format, a...)
426 }
427
428
429 func newStrictDecoder(data []byte) *json.Decoder {
430 dec := json.NewDecoder(bytes.NewBuffer(data))
431 dec.DisallowUnknownFields()
432 return dec
433 }
434
435
436 func setBody(body interface{}, contentType string) (bodyBuf *bytes.Buffer, err error) {
437 if bodyBuf == nil {
438 bodyBuf = &bytes.Buffer{}
439 }
440
441 if reader, ok := body.(io.Reader); ok {
442 _, err = bodyBuf.ReadFrom(reader)
443 } else if fp, ok := body.(**os.File); ok {
444 _, err = bodyBuf.ReadFrom(*fp)
445 } else if b, ok := body.([]byte); ok {
446 _, err = bodyBuf.Write(b)
447 } else if s, ok := body.(string); ok {
448 _, err = bodyBuf.WriteString(s)
449 } else if s, ok := body.(*string); ok {
450 _, err = bodyBuf.WriteString(*s)
451 } else if jsonCheck.MatchString(contentType) {
452 err = json.NewEncoder(bodyBuf).Encode(body)
453 } else if xmlCheck.MatchString(contentType) {
454 err = xml.NewEncoder(bodyBuf).Encode(body)
455 }
456
457 if err != nil {
458 return nil, err
459 }
460
461 if bodyBuf.Len() == 0 {
462 err = fmt.Errorf("invalid body type %s\n", contentType)
463 return nil, err
464 }
465 return bodyBuf, nil
466 }
467
468
469 func detectContentType(body interface{}) string {
470 contentType := "text/plain; charset=utf-8"
471 kind := reflect.TypeOf(body).Kind()
472
473 switch kind {
474 case reflect.Struct, reflect.Map, reflect.Ptr:
475 contentType = "application/json; charset=utf-8"
476 case reflect.String:
477 contentType = "text/plain; charset=utf-8"
478 default:
479 if b, ok := body.([]byte); ok {
480 contentType = http.DetectContentType(b)
481 } else if kind == reflect.Slice {
482 contentType = "application/json; charset=utf-8"
483 }
484 }
485
486 return contentType
487 }
488
489
490 type cacheControl map[string]string
491
492 func parseCacheControl(headers http.Header) cacheControl {
493 cc := cacheControl{}
494 ccHeader := headers.Get("Cache-Control")
495 for _, part := range strings.Split(ccHeader, ",") {
496 part = strings.Trim(part, " ")
497 if part == "" {
498 continue
499 }
500 if strings.ContainsRune(part, '=') {
501 keyval := strings.Split(part, "=")
502 cc[strings.Trim(keyval[0], " ")] = strings.Trim(keyval[1], ",")
503 } else {
504 cc[part] = ""
505 }
506 }
507 return cc
508 }
509
510
511 func CacheExpires(r *http.Response) time.Time {
512
513 var expires time.Time
514 now, err := time.Parse(time.RFC1123, r.Header.Get("date"))
515 if err != nil {
516 return time.Now()
517 }
518 respCacheControl := parseCacheControl(r.Header)
519
520 if maxAge, ok := respCacheControl["max-age"]; ok {
521 lifetime, err := time.ParseDuration(maxAge + "s")
522 if err != nil {
523 expires = now
524 } else {
525 expires = now.Add(lifetime)
526 }
527 } else {
528 expiresHeader := r.Header.Get("Expires")
529 if expiresHeader != "" {
530 expires, err = time.Parse(time.RFC1123, expiresHeader)
531 if err != nil {
532 expires = now
533 }
534 }
535 }
536 return expires
537 }
538
539 func strlen(s string) int {
540 return utf8.RuneCountInString(s)
541 }
542
543
544 type GenericOpenAPIError struct {
545 body []byte
546 error string
547 model interface{}
548 }
549
550
551 func (e GenericOpenAPIError) Error() string {
552 return e.error
553 }
554
555
556 func (e GenericOpenAPIError) Body() []byte {
557 return e.body
558 }
559
560
561 func (e GenericOpenAPIError) Model() interface{} {
562 return e.model
563 }
564
View as plain text