preparer.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. package autorest
  2. // Copyright 2017 Microsoft Corporation
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. import (
  16. "bytes"
  17. "context"
  18. "encoding/json"
  19. "encoding/xml"
  20. "fmt"
  21. "io"
  22. "io/ioutil"
  23. "mime/multipart"
  24. "net/http"
  25. "net/url"
  26. "strings"
  27. )
  28. const (
  29. mimeTypeJSON = "application/json"
  30. mimeTypeOctetStream = "application/octet-stream"
  31. mimeTypeFormPost = "application/x-www-form-urlencoded"
  32. headerAuthorization = "Authorization"
  33. headerAuxAuthorization = "x-ms-authorization-auxiliary"
  34. headerContentType = "Content-Type"
  35. headerUserAgent = "User-Agent"
  36. )
  37. // used as a key type in context.WithValue()
  38. type ctxPrepareDecorators struct{}
  39. // WithPrepareDecorators adds the specified PrepareDecorators to the provided context.
  40. // If no PrepareDecorators are provided the context is unchanged.
  41. func WithPrepareDecorators(ctx context.Context, prepareDecorator []PrepareDecorator) context.Context {
  42. if len(prepareDecorator) == 0 {
  43. return ctx
  44. }
  45. return context.WithValue(ctx, ctxPrepareDecorators{}, prepareDecorator)
  46. }
  47. // GetPrepareDecorators returns the PrepareDecorators in the provided context or the provided default PrepareDecorators.
  48. func GetPrepareDecorators(ctx context.Context, defaultPrepareDecorators ...PrepareDecorator) []PrepareDecorator {
  49. inCtx := ctx.Value(ctxPrepareDecorators{})
  50. if pd, ok := inCtx.([]PrepareDecorator); ok {
  51. return pd
  52. }
  53. return defaultPrepareDecorators
  54. }
  55. // Preparer is the interface that wraps the Prepare method.
  56. //
  57. // Prepare accepts and possibly modifies an http.Request (e.g., adding Headers). Implementations
  58. // must ensure to not share or hold per-invocation state since Preparers may be shared and re-used.
  59. type Preparer interface {
  60. Prepare(*http.Request) (*http.Request, error)
  61. }
  62. // PreparerFunc is a method that implements the Preparer interface.
  63. type PreparerFunc func(*http.Request) (*http.Request, error)
  64. // Prepare implements the Preparer interface on PreparerFunc.
  65. func (pf PreparerFunc) Prepare(r *http.Request) (*http.Request, error) {
  66. return pf(r)
  67. }
  68. // PrepareDecorator takes and possibly decorates, by wrapping, a Preparer. Decorators may affect the
  69. // http.Request and pass it along or, first, pass the http.Request along then affect the result.
  70. type PrepareDecorator func(Preparer) Preparer
  71. // CreatePreparer creates, decorates, and returns a Preparer.
  72. // Without decorators, the returned Preparer returns the passed http.Request unmodified.
  73. // Preparers are safe to share and re-use.
  74. func CreatePreparer(decorators ...PrepareDecorator) Preparer {
  75. return DecoratePreparer(
  76. Preparer(PreparerFunc(func(r *http.Request) (*http.Request, error) { return r, nil })),
  77. decorators...)
  78. }
  79. // DecoratePreparer accepts a Preparer and a, possibly empty, set of PrepareDecorators, which it
  80. // applies to the Preparer. Decorators are applied in the order received, but their affect upon the
  81. // request depends on whether they are a pre-decorator (change the http.Request and then pass it
  82. // along) or a post-decorator (pass the http.Request along and alter it on return).
  83. func DecoratePreparer(p Preparer, decorators ...PrepareDecorator) Preparer {
  84. for _, decorate := range decorators {
  85. p = decorate(p)
  86. }
  87. return p
  88. }
  89. // Prepare accepts an http.Request and a, possibly empty, set of PrepareDecorators.
  90. // It creates a Preparer from the decorators which it then applies to the passed http.Request.
  91. func Prepare(r *http.Request, decorators ...PrepareDecorator) (*http.Request, error) {
  92. if r == nil {
  93. return nil, NewError("autorest", "Prepare", "Invoked without an http.Request")
  94. }
  95. return CreatePreparer(decorators...).Prepare(r)
  96. }
  97. // WithNothing returns a "do nothing" PrepareDecorator that makes no changes to the passed
  98. // http.Request.
  99. func WithNothing() PrepareDecorator {
  100. return func(p Preparer) Preparer {
  101. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  102. return p.Prepare(r)
  103. })
  104. }
  105. }
  106. // WithHeader returns a PrepareDecorator that sets the specified HTTP header of the http.Request to
  107. // the passed value. It canonicalizes the passed header name (via http.CanonicalHeaderKey) before
  108. // adding the header.
  109. func WithHeader(header string, value string) PrepareDecorator {
  110. return func(p Preparer) Preparer {
  111. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  112. r, err := p.Prepare(r)
  113. if err == nil {
  114. setHeader(r, http.CanonicalHeaderKey(header), value)
  115. }
  116. return r, err
  117. })
  118. }
  119. }
  120. // WithHeaders returns a PrepareDecorator that sets the specified HTTP headers of the http.Request to
  121. // the passed value. It canonicalizes the passed headers name (via http.CanonicalHeaderKey) before
  122. // adding them.
  123. func WithHeaders(headers map[string]interface{}) PrepareDecorator {
  124. h := ensureValueStrings(headers)
  125. return func(p Preparer) Preparer {
  126. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  127. r, err := p.Prepare(r)
  128. if err == nil {
  129. if r.Header == nil {
  130. r.Header = make(http.Header)
  131. }
  132. for name, value := range h {
  133. r.Header.Set(http.CanonicalHeaderKey(name), value)
  134. }
  135. }
  136. return r, err
  137. })
  138. }
  139. }
  140. // WithBearerAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose
  141. // value is "Bearer " followed by the supplied token.
  142. func WithBearerAuthorization(token string) PrepareDecorator {
  143. return WithHeader(headerAuthorization, fmt.Sprintf("Bearer %s", token))
  144. }
  145. // AsContentType returns a PrepareDecorator that adds an HTTP Content-Type header whose value
  146. // is the passed contentType.
  147. func AsContentType(contentType string) PrepareDecorator {
  148. return WithHeader(headerContentType, contentType)
  149. }
  150. // WithUserAgent returns a PrepareDecorator that adds an HTTP User-Agent header whose value is the
  151. // passed string.
  152. func WithUserAgent(ua string) PrepareDecorator {
  153. return WithHeader(headerUserAgent, ua)
  154. }
  155. // AsFormURLEncoded returns a PrepareDecorator that adds an HTTP Content-Type header whose value is
  156. // "application/x-www-form-urlencoded".
  157. func AsFormURLEncoded() PrepareDecorator {
  158. return AsContentType(mimeTypeFormPost)
  159. }
  160. // AsJSON returns a PrepareDecorator that adds an HTTP Content-Type header whose value is
  161. // "application/json".
  162. func AsJSON() PrepareDecorator {
  163. return AsContentType(mimeTypeJSON)
  164. }
  165. // AsOctetStream returns a PrepareDecorator that adds the "application/octet-stream" Content-Type header.
  166. func AsOctetStream() PrepareDecorator {
  167. return AsContentType(mimeTypeOctetStream)
  168. }
  169. // WithMethod returns a PrepareDecorator that sets the HTTP method of the passed request. The
  170. // decorator does not validate that the passed method string is a known HTTP method.
  171. func WithMethod(method string) PrepareDecorator {
  172. return func(p Preparer) Preparer {
  173. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  174. r.Method = method
  175. return p.Prepare(r)
  176. })
  177. }
  178. }
  179. // AsDelete returns a PrepareDecorator that sets the HTTP method to DELETE.
  180. func AsDelete() PrepareDecorator { return WithMethod("DELETE") }
  181. // AsGet returns a PrepareDecorator that sets the HTTP method to GET.
  182. func AsGet() PrepareDecorator { return WithMethod("GET") }
  183. // AsHead returns a PrepareDecorator that sets the HTTP method to HEAD.
  184. func AsHead() PrepareDecorator { return WithMethod("HEAD") }
  185. // AsMerge returns a PrepareDecorator that sets the HTTP method to MERGE.
  186. func AsMerge() PrepareDecorator { return WithMethod("MERGE") }
  187. // AsOptions returns a PrepareDecorator that sets the HTTP method to OPTIONS.
  188. func AsOptions() PrepareDecorator { return WithMethod("OPTIONS") }
  189. // AsPatch returns a PrepareDecorator that sets the HTTP method to PATCH.
  190. func AsPatch() PrepareDecorator { return WithMethod("PATCH") }
  191. // AsPost returns a PrepareDecorator that sets the HTTP method to POST.
  192. func AsPost() PrepareDecorator { return WithMethod("POST") }
  193. // AsPut returns a PrepareDecorator that sets the HTTP method to PUT.
  194. func AsPut() PrepareDecorator { return WithMethod("PUT") }
  195. // WithBaseURL returns a PrepareDecorator that populates the http.Request with a url.URL constructed
  196. // from the supplied baseUrl. Query parameters will be encoded as required.
  197. func WithBaseURL(baseURL string) PrepareDecorator {
  198. return func(p Preparer) Preparer {
  199. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  200. r, err := p.Prepare(r)
  201. if err == nil {
  202. var u *url.URL
  203. if u, err = url.Parse(baseURL); err != nil {
  204. return r, err
  205. }
  206. if u.Scheme == "" {
  207. return r, fmt.Errorf("autorest: No scheme detected in URL %s", baseURL)
  208. }
  209. if u.RawQuery != "" {
  210. // handle unencoded semicolons (ideally the server would send them already encoded)
  211. u.RawQuery = strings.Replace(u.RawQuery, ";", "%3B", -1)
  212. q, err := url.ParseQuery(u.RawQuery)
  213. if err != nil {
  214. return r, err
  215. }
  216. u.RawQuery = q.Encode()
  217. }
  218. r.URL = u
  219. }
  220. return r, err
  221. })
  222. }
  223. }
  224. // WithBytes returns a PrepareDecorator that takes a list of bytes
  225. // which passes the bytes directly to the body
  226. func WithBytes(input *[]byte) PrepareDecorator {
  227. return func(p Preparer) Preparer {
  228. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  229. r, err := p.Prepare(r)
  230. if err == nil {
  231. if input == nil {
  232. return r, fmt.Errorf("Input Bytes was nil")
  233. }
  234. r.ContentLength = int64(len(*input))
  235. r.Body = ioutil.NopCloser(bytes.NewReader(*input))
  236. }
  237. return r, err
  238. })
  239. }
  240. }
  241. // WithCustomBaseURL returns a PrepareDecorator that replaces brace-enclosed keys within the
  242. // request base URL (i.e., http.Request.URL) with the corresponding values from the passed map.
  243. func WithCustomBaseURL(baseURL string, urlParameters map[string]interface{}) PrepareDecorator {
  244. parameters := ensureValueStrings(urlParameters)
  245. for key, value := range parameters {
  246. baseURL = strings.Replace(baseURL, "{"+key+"}", value, -1)
  247. }
  248. return WithBaseURL(baseURL)
  249. }
  250. // WithFormData returns a PrepareDecoratore that "URL encodes" (e.g., bar=baz&foo=quux) into the
  251. // http.Request body.
  252. func WithFormData(v url.Values) PrepareDecorator {
  253. return func(p Preparer) Preparer {
  254. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  255. r, err := p.Prepare(r)
  256. if err == nil {
  257. s := v.Encode()
  258. setHeader(r, http.CanonicalHeaderKey(headerContentType), mimeTypeFormPost)
  259. r.ContentLength = int64(len(s))
  260. r.Body = ioutil.NopCloser(strings.NewReader(s))
  261. }
  262. return r, err
  263. })
  264. }
  265. }
  266. // WithMultiPartFormData returns a PrepareDecoratore that "URL encodes" (e.g., bar=baz&foo=quux) form parameters
  267. // into the http.Request body.
  268. func WithMultiPartFormData(formDataParameters map[string]interface{}) PrepareDecorator {
  269. return func(p Preparer) Preparer {
  270. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  271. r, err := p.Prepare(r)
  272. if err == nil {
  273. var body bytes.Buffer
  274. writer := multipart.NewWriter(&body)
  275. for key, value := range formDataParameters {
  276. if rc, ok := value.(io.ReadCloser); ok {
  277. var fd io.Writer
  278. if fd, err = writer.CreateFormFile(key, key); err != nil {
  279. return r, err
  280. }
  281. if _, err = io.Copy(fd, rc); err != nil {
  282. return r, err
  283. }
  284. } else {
  285. if err = writer.WriteField(key, ensureValueString(value)); err != nil {
  286. return r, err
  287. }
  288. }
  289. }
  290. if err = writer.Close(); err != nil {
  291. return r, err
  292. }
  293. setHeader(r, http.CanonicalHeaderKey(headerContentType), writer.FormDataContentType())
  294. r.Body = ioutil.NopCloser(bytes.NewReader(body.Bytes()))
  295. r.ContentLength = int64(body.Len())
  296. return r, err
  297. }
  298. return r, err
  299. })
  300. }
  301. }
  302. // WithFile returns a PrepareDecorator that sends file in request body.
  303. func WithFile(f io.ReadCloser) PrepareDecorator {
  304. return func(p Preparer) Preparer {
  305. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  306. r, err := p.Prepare(r)
  307. if err == nil {
  308. b, err := ioutil.ReadAll(f)
  309. if err != nil {
  310. return r, err
  311. }
  312. r.Body = ioutil.NopCloser(bytes.NewReader(b))
  313. r.ContentLength = int64(len(b))
  314. }
  315. return r, err
  316. })
  317. }
  318. }
  319. // WithBool returns a PrepareDecorator that encodes the passed bool into the body of the request
  320. // and sets the Content-Length header.
  321. func WithBool(v bool) PrepareDecorator {
  322. return WithString(fmt.Sprintf("%v", v))
  323. }
  324. // WithFloat32 returns a PrepareDecorator that encodes the passed float32 into the body of the
  325. // request and sets the Content-Length header.
  326. func WithFloat32(v float32) PrepareDecorator {
  327. return WithString(fmt.Sprintf("%v", v))
  328. }
  329. // WithFloat64 returns a PrepareDecorator that encodes the passed float64 into the body of the
  330. // request and sets the Content-Length header.
  331. func WithFloat64(v float64) PrepareDecorator {
  332. return WithString(fmt.Sprintf("%v", v))
  333. }
  334. // WithInt32 returns a PrepareDecorator that encodes the passed int32 into the body of the request
  335. // and sets the Content-Length header.
  336. func WithInt32(v int32) PrepareDecorator {
  337. return WithString(fmt.Sprintf("%v", v))
  338. }
  339. // WithInt64 returns a PrepareDecorator that encodes the passed int64 into the body of the request
  340. // and sets the Content-Length header.
  341. func WithInt64(v int64) PrepareDecorator {
  342. return WithString(fmt.Sprintf("%v", v))
  343. }
  344. // WithString returns a PrepareDecorator that encodes the passed string into the body of the request
  345. // and sets the Content-Length header.
  346. func WithString(v string) PrepareDecorator {
  347. return func(p Preparer) Preparer {
  348. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  349. r, err := p.Prepare(r)
  350. if err == nil {
  351. r.ContentLength = int64(len(v))
  352. r.Body = ioutil.NopCloser(strings.NewReader(v))
  353. }
  354. return r, err
  355. })
  356. }
  357. }
  358. // WithJSON returns a PrepareDecorator that encodes the data passed as JSON into the body of the
  359. // request and sets the Content-Length header.
  360. func WithJSON(v interface{}) PrepareDecorator {
  361. return func(p Preparer) Preparer {
  362. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  363. r, err := p.Prepare(r)
  364. if err == nil {
  365. b, err := json.Marshal(v)
  366. if err == nil {
  367. r.ContentLength = int64(len(b))
  368. r.Body = ioutil.NopCloser(bytes.NewReader(b))
  369. }
  370. }
  371. return r, err
  372. })
  373. }
  374. }
  375. // WithXML returns a PrepareDecorator that encodes the data passed as XML into the body of the
  376. // request and sets the Content-Length header.
  377. func WithXML(v interface{}) PrepareDecorator {
  378. return func(p Preparer) Preparer {
  379. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  380. r, err := p.Prepare(r)
  381. if err == nil {
  382. b, err := xml.Marshal(v)
  383. if err == nil {
  384. // we have to tack on an XML header
  385. withHeader := xml.Header + string(b)
  386. bytesWithHeader := []byte(withHeader)
  387. r.ContentLength = int64(len(bytesWithHeader))
  388. setHeader(r, headerContentLength, fmt.Sprintf("%d", len(bytesWithHeader)))
  389. r.Body = ioutil.NopCloser(bytes.NewReader(bytesWithHeader))
  390. }
  391. }
  392. return r, err
  393. })
  394. }
  395. }
  396. // WithPath returns a PrepareDecorator that adds the supplied path to the request URL. If the path
  397. // is absolute (that is, it begins with a "/"), it replaces the existing path.
  398. func WithPath(path string) PrepareDecorator {
  399. return func(p Preparer) Preparer {
  400. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  401. r, err := p.Prepare(r)
  402. if err == nil {
  403. if r.URL == nil {
  404. return r, NewError("autorest", "WithPath", "Invoked with a nil URL")
  405. }
  406. if r.URL, err = parseURL(r.URL, path); err != nil {
  407. return r, err
  408. }
  409. }
  410. return r, err
  411. })
  412. }
  413. }
  414. // WithEscapedPathParameters returns a PrepareDecorator that replaces brace-enclosed keys within the
  415. // request path (i.e., http.Request.URL.Path) with the corresponding values from the passed map. The
  416. // values will be escaped (aka URL encoded) before insertion into the path.
  417. func WithEscapedPathParameters(path string, pathParameters map[string]interface{}) PrepareDecorator {
  418. parameters := escapeValueStrings(ensureValueStrings(pathParameters))
  419. return func(p Preparer) Preparer {
  420. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  421. r, err := p.Prepare(r)
  422. if err == nil {
  423. if r.URL == nil {
  424. return r, NewError("autorest", "WithEscapedPathParameters", "Invoked with a nil URL")
  425. }
  426. for key, value := range parameters {
  427. path = strings.Replace(path, "{"+key+"}", value, -1)
  428. }
  429. if r.URL, err = parseURL(r.URL, path); err != nil {
  430. return r, err
  431. }
  432. }
  433. return r, err
  434. })
  435. }
  436. }
  437. // WithPathParameters returns a PrepareDecorator that replaces brace-enclosed keys within the
  438. // request path (i.e., http.Request.URL.Path) with the corresponding values from the passed map.
  439. func WithPathParameters(path string, pathParameters map[string]interface{}) PrepareDecorator {
  440. parameters := ensureValueStrings(pathParameters)
  441. return func(p Preparer) Preparer {
  442. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  443. r, err := p.Prepare(r)
  444. if err == nil {
  445. if r.URL == nil {
  446. return r, NewError("autorest", "WithPathParameters", "Invoked with a nil URL")
  447. }
  448. for key, value := range parameters {
  449. path = strings.Replace(path, "{"+key+"}", value, -1)
  450. }
  451. if r.URL, err = parseURL(r.URL, path); err != nil {
  452. return r, err
  453. }
  454. }
  455. return r, err
  456. })
  457. }
  458. }
  459. func parseURL(u *url.URL, path string) (*url.URL, error) {
  460. p := strings.TrimRight(u.String(), "/")
  461. if !strings.HasPrefix(path, "/") {
  462. path = "/" + path
  463. }
  464. return url.Parse(p + path)
  465. }
  466. // WithQueryParameters returns a PrepareDecorators that encodes and applies the query parameters
  467. // given in the supplied map (i.e., key=value).
  468. func WithQueryParameters(queryParameters map[string]interface{}) PrepareDecorator {
  469. parameters := MapToValues(queryParameters)
  470. return func(p Preparer) Preparer {
  471. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  472. r, err := p.Prepare(r)
  473. if err == nil {
  474. if r.URL == nil {
  475. return r, NewError("autorest", "WithQueryParameters", "Invoked with a nil URL")
  476. }
  477. v := r.URL.Query()
  478. for key, value := range parameters {
  479. for i := range value {
  480. d, err := url.QueryUnescape(value[i])
  481. if err != nil {
  482. return r, err
  483. }
  484. value[i] = d
  485. }
  486. v[key] = value
  487. }
  488. r.URL.RawQuery = v.Encode()
  489. }
  490. return r, err
  491. })
  492. }
  493. }