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. if r.Header == nil {
  115. r.Header = make(http.Header)
  116. }
  117. r.Header.Set(http.CanonicalHeaderKey(header), value)
  118. }
  119. return r, err
  120. })
  121. }
  122. }
  123. // WithHeaders returns a PrepareDecorator that sets the specified HTTP headers of the http.Request to
  124. // the passed value. It canonicalizes the passed headers name (via http.CanonicalHeaderKey) before
  125. // adding them.
  126. func WithHeaders(headers map[string]interface{}) PrepareDecorator {
  127. h := ensureValueStrings(headers)
  128. return func(p Preparer) Preparer {
  129. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  130. r, err := p.Prepare(r)
  131. if err == nil {
  132. if r.Header == nil {
  133. r.Header = make(http.Header)
  134. }
  135. for name, value := range h {
  136. r.Header.Set(http.CanonicalHeaderKey(name), value)
  137. }
  138. }
  139. return r, err
  140. })
  141. }
  142. }
  143. // WithBearerAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose
  144. // value is "Bearer " followed by the supplied token.
  145. func WithBearerAuthorization(token string) PrepareDecorator {
  146. return WithHeader(headerAuthorization, fmt.Sprintf("Bearer %s", token))
  147. }
  148. // AsContentType returns a PrepareDecorator that adds an HTTP Content-Type header whose value
  149. // is the passed contentType.
  150. func AsContentType(contentType string) PrepareDecorator {
  151. return WithHeader(headerContentType, contentType)
  152. }
  153. // WithUserAgent returns a PrepareDecorator that adds an HTTP User-Agent header whose value is the
  154. // passed string.
  155. func WithUserAgent(ua string) PrepareDecorator {
  156. return WithHeader(headerUserAgent, ua)
  157. }
  158. // AsFormURLEncoded returns a PrepareDecorator that adds an HTTP Content-Type header whose value is
  159. // "application/x-www-form-urlencoded".
  160. func AsFormURLEncoded() PrepareDecorator {
  161. return AsContentType(mimeTypeFormPost)
  162. }
  163. // AsJSON returns a PrepareDecorator that adds an HTTP Content-Type header whose value is
  164. // "application/json".
  165. func AsJSON() PrepareDecorator {
  166. return AsContentType(mimeTypeJSON)
  167. }
  168. // AsOctetStream returns a PrepareDecorator that adds the "application/octet-stream" Content-Type header.
  169. func AsOctetStream() PrepareDecorator {
  170. return AsContentType(mimeTypeOctetStream)
  171. }
  172. // WithMethod returns a PrepareDecorator that sets the HTTP method of the passed request. The
  173. // decorator does not validate that the passed method string is a known HTTP method.
  174. func WithMethod(method string) PrepareDecorator {
  175. return func(p Preparer) Preparer {
  176. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  177. r.Method = method
  178. return p.Prepare(r)
  179. })
  180. }
  181. }
  182. // AsDelete returns a PrepareDecorator that sets the HTTP method to DELETE.
  183. func AsDelete() PrepareDecorator { return WithMethod("DELETE") }
  184. // AsGet returns a PrepareDecorator that sets the HTTP method to GET.
  185. func AsGet() PrepareDecorator { return WithMethod("GET") }
  186. // AsHead returns a PrepareDecorator that sets the HTTP method to HEAD.
  187. func AsHead() PrepareDecorator { return WithMethod("HEAD") }
  188. // AsMerge returns a PrepareDecorator that sets the HTTP method to MERGE.
  189. func AsMerge() PrepareDecorator { return WithMethod("MERGE") }
  190. // AsOptions returns a PrepareDecorator that sets the HTTP method to OPTIONS.
  191. func AsOptions() PrepareDecorator { return WithMethod("OPTIONS") }
  192. // AsPatch returns a PrepareDecorator that sets the HTTP method to PATCH.
  193. func AsPatch() PrepareDecorator { return WithMethod("PATCH") }
  194. // AsPost returns a PrepareDecorator that sets the HTTP method to POST.
  195. func AsPost() PrepareDecorator { return WithMethod("POST") }
  196. // AsPut returns a PrepareDecorator that sets the HTTP method to PUT.
  197. func AsPut() PrepareDecorator { return WithMethod("PUT") }
  198. // WithBaseURL returns a PrepareDecorator that populates the http.Request with a url.URL constructed
  199. // from the supplied baseUrl.
  200. func WithBaseURL(baseURL string) PrepareDecorator {
  201. return func(p Preparer) Preparer {
  202. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  203. r, err := p.Prepare(r)
  204. if err == nil {
  205. var u *url.URL
  206. if u, err = url.Parse(baseURL); err != nil {
  207. return r, err
  208. }
  209. if u.Scheme == "" {
  210. err = fmt.Errorf("autorest: No scheme detected in URL %s", baseURL)
  211. }
  212. if err == nil {
  213. r.URL = u
  214. }
  215. }
  216. return r, err
  217. })
  218. }
  219. }
  220. // WithBytes returns a PrepareDecorator that takes a list of bytes
  221. // which passes the bytes directly to the body
  222. func WithBytes(input *[]byte) PrepareDecorator {
  223. return func(p Preparer) Preparer {
  224. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  225. r, err := p.Prepare(r)
  226. if err == nil {
  227. if input == nil {
  228. return r, fmt.Errorf("Input Bytes was nil")
  229. }
  230. r.ContentLength = int64(len(*input))
  231. r.Body = ioutil.NopCloser(bytes.NewReader(*input))
  232. }
  233. return r, err
  234. })
  235. }
  236. }
  237. // WithCustomBaseURL returns a PrepareDecorator that replaces brace-enclosed keys within the
  238. // request base URL (i.e., http.Request.URL) with the corresponding values from the passed map.
  239. func WithCustomBaseURL(baseURL string, urlParameters map[string]interface{}) PrepareDecorator {
  240. parameters := ensureValueStrings(urlParameters)
  241. for key, value := range parameters {
  242. baseURL = strings.Replace(baseURL, "{"+key+"}", value, -1)
  243. }
  244. return WithBaseURL(baseURL)
  245. }
  246. // WithFormData returns a PrepareDecoratore that "URL encodes" (e.g., bar=baz&foo=quux) into the
  247. // http.Request body.
  248. func WithFormData(v url.Values) PrepareDecorator {
  249. return func(p Preparer) Preparer {
  250. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  251. r, err := p.Prepare(r)
  252. if err == nil {
  253. s := v.Encode()
  254. if r.Header == nil {
  255. r.Header = make(http.Header)
  256. }
  257. r.Header.Set(http.CanonicalHeaderKey(headerContentType), mimeTypeFormPost)
  258. r.ContentLength = int64(len(s))
  259. r.Body = ioutil.NopCloser(strings.NewReader(s))
  260. }
  261. return r, err
  262. })
  263. }
  264. }
  265. // WithMultiPartFormData returns a PrepareDecoratore that "URL encodes" (e.g., bar=baz&foo=quux) form parameters
  266. // into the http.Request body.
  267. func WithMultiPartFormData(formDataParameters map[string]interface{}) PrepareDecorator {
  268. return func(p Preparer) Preparer {
  269. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  270. r, err := p.Prepare(r)
  271. if err == nil {
  272. var body bytes.Buffer
  273. writer := multipart.NewWriter(&body)
  274. for key, value := range formDataParameters {
  275. if rc, ok := value.(io.ReadCloser); ok {
  276. var fd io.Writer
  277. if fd, err = writer.CreateFormFile(key, key); err != nil {
  278. return r, err
  279. }
  280. if _, err = io.Copy(fd, rc); err != nil {
  281. return r, err
  282. }
  283. } else {
  284. if err = writer.WriteField(key, ensureValueString(value)); err != nil {
  285. return r, err
  286. }
  287. }
  288. }
  289. if err = writer.Close(); err != nil {
  290. return r, err
  291. }
  292. if r.Header == nil {
  293. r.Header = make(http.Header)
  294. }
  295. r.Header.Set(http.CanonicalHeaderKey(headerContentType), writer.FormDataContentType())
  296. r.Body = ioutil.NopCloser(bytes.NewReader(body.Bytes()))
  297. r.ContentLength = int64(body.Len())
  298. return r, err
  299. }
  300. return r, err
  301. })
  302. }
  303. }
  304. // WithFile returns a PrepareDecorator that sends file in request body.
  305. func WithFile(f io.ReadCloser) PrepareDecorator {
  306. return func(p Preparer) Preparer {
  307. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  308. r, err := p.Prepare(r)
  309. if err == nil {
  310. b, err := ioutil.ReadAll(f)
  311. if err != nil {
  312. return r, err
  313. }
  314. r.Body = ioutil.NopCloser(bytes.NewReader(b))
  315. r.ContentLength = int64(len(b))
  316. }
  317. return r, err
  318. })
  319. }
  320. }
  321. // WithBool returns a PrepareDecorator that encodes the passed bool into the body of the request
  322. // and sets the Content-Length header.
  323. func WithBool(v bool) PrepareDecorator {
  324. return WithString(fmt.Sprintf("%v", v))
  325. }
  326. // WithFloat32 returns a PrepareDecorator that encodes the passed float32 into the body of the
  327. // request and sets the Content-Length header.
  328. func WithFloat32(v float32) PrepareDecorator {
  329. return WithString(fmt.Sprintf("%v", v))
  330. }
  331. // WithFloat64 returns a PrepareDecorator that encodes the passed float64 into the body of the
  332. // request and sets the Content-Length header.
  333. func WithFloat64(v float64) PrepareDecorator {
  334. return WithString(fmt.Sprintf("%v", v))
  335. }
  336. // WithInt32 returns a PrepareDecorator that encodes the passed int32 into the body of the request
  337. // and sets the Content-Length header.
  338. func WithInt32(v int32) PrepareDecorator {
  339. return WithString(fmt.Sprintf("%v", v))
  340. }
  341. // WithInt64 returns a PrepareDecorator that encodes the passed int64 into the body of the request
  342. // and sets the Content-Length header.
  343. func WithInt64(v int64) PrepareDecorator {
  344. return WithString(fmt.Sprintf("%v", v))
  345. }
  346. // WithString returns a PrepareDecorator that encodes the passed string into the body of the request
  347. // and sets the Content-Length header.
  348. func WithString(v string) PrepareDecorator {
  349. return func(p Preparer) Preparer {
  350. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  351. r, err := p.Prepare(r)
  352. if err == nil {
  353. r.ContentLength = int64(len(v))
  354. r.Body = ioutil.NopCloser(strings.NewReader(v))
  355. }
  356. return r, err
  357. })
  358. }
  359. }
  360. // WithJSON returns a PrepareDecorator that encodes the data passed as JSON into the body of the
  361. // request and sets the Content-Length header.
  362. func WithJSON(v interface{}) PrepareDecorator {
  363. return func(p Preparer) Preparer {
  364. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  365. r, err := p.Prepare(r)
  366. if err == nil {
  367. b, err := json.Marshal(v)
  368. if err == nil {
  369. r.ContentLength = int64(len(b))
  370. r.Body = ioutil.NopCloser(bytes.NewReader(b))
  371. }
  372. }
  373. return r, err
  374. })
  375. }
  376. }
  377. // WithXML returns a PrepareDecorator that encodes the data passed as XML into the body of the
  378. // request and sets the Content-Length header.
  379. func WithXML(v interface{}) PrepareDecorator {
  380. return func(p Preparer) Preparer {
  381. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  382. r, err := p.Prepare(r)
  383. if err == nil {
  384. b, err := xml.Marshal(v)
  385. if err == nil {
  386. // we have to tack on an XML header
  387. withHeader := xml.Header + string(b)
  388. bytesWithHeader := []byte(withHeader)
  389. r.ContentLength = int64(len(bytesWithHeader))
  390. r.Body = ioutil.NopCloser(bytes.NewReader(bytesWithHeader))
  391. }
  392. }
  393. return r, err
  394. })
  395. }
  396. }
  397. // WithPath returns a PrepareDecorator that adds the supplied path to the request URL. If the path
  398. // is absolute (that is, it begins with a "/"), it replaces the existing path.
  399. func WithPath(path string) PrepareDecorator {
  400. return func(p Preparer) Preparer {
  401. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  402. r, err := p.Prepare(r)
  403. if err == nil {
  404. if r.URL == nil {
  405. return r, NewError("autorest", "WithPath", "Invoked with a nil URL")
  406. }
  407. if r.URL, err = parseURL(r.URL, path); err != nil {
  408. return r, err
  409. }
  410. }
  411. return r, err
  412. })
  413. }
  414. }
  415. // WithEscapedPathParameters returns a PrepareDecorator that replaces brace-enclosed keys within the
  416. // request path (i.e., http.Request.URL.Path) with the corresponding values from the passed map. The
  417. // values will be escaped (aka URL encoded) before insertion into the path.
  418. func WithEscapedPathParameters(path string, pathParameters map[string]interface{}) PrepareDecorator {
  419. parameters := escapeValueStrings(ensureValueStrings(pathParameters))
  420. return func(p Preparer) Preparer {
  421. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  422. r, err := p.Prepare(r)
  423. if err == nil {
  424. if r.URL == nil {
  425. return r, NewError("autorest", "WithEscapedPathParameters", "Invoked with a nil URL")
  426. }
  427. for key, value := range parameters {
  428. path = strings.Replace(path, "{"+key+"}", value, -1)
  429. }
  430. if r.URL, err = parseURL(r.URL, path); err != nil {
  431. return r, err
  432. }
  433. }
  434. return r, err
  435. })
  436. }
  437. }
  438. // WithPathParameters returns a PrepareDecorator that replaces brace-enclosed keys within the
  439. // request path (i.e., http.Request.URL.Path) with the corresponding values from the passed map.
  440. func WithPathParameters(path string, pathParameters map[string]interface{}) PrepareDecorator {
  441. parameters := ensureValueStrings(pathParameters)
  442. return func(p Preparer) Preparer {
  443. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  444. r, err := p.Prepare(r)
  445. if err == nil {
  446. if r.URL == nil {
  447. return r, NewError("autorest", "WithPathParameters", "Invoked with a nil URL")
  448. }
  449. for key, value := range parameters {
  450. path = strings.Replace(path, "{"+key+"}", value, -1)
  451. }
  452. if r.URL, err = parseURL(r.URL, path); err != nil {
  453. return r, err
  454. }
  455. }
  456. return r, err
  457. })
  458. }
  459. }
  460. func parseURL(u *url.URL, path string) (*url.URL, error) {
  461. p := strings.TrimRight(u.String(), "/")
  462. if !strings.HasPrefix(path, "/") {
  463. path = "/" + path
  464. }
  465. return url.Parse(p + path)
  466. }
  467. // WithQueryParameters returns a PrepareDecorators that encodes and applies the query parameters
  468. // given in the supplied map (i.e., key=value).
  469. func WithQueryParameters(queryParameters map[string]interface{}) PrepareDecorator {
  470. parameters := ensureValueStrings(queryParameters)
  471. return func(p Preparer) Preparer {
  472. return PreparerFunc(func(r *http.Request) (*http.Request, error) {
  473. r, err := p.Prepare(r)
  474. if err == nil {
  475. if r.URL == nil {
  476. return r, NewError("autorest", "WithQueryParameters", "Invoked with a nil URL")
  477. }
  478. v := r.URL.Query()
  479. for key, value := range parameters {
  480. d, err := url.QueryUnescape(value)
  481. if err != nil {
  482. return r, err
  483. }
  484. v.Add(key, d)
  485. }
  486. r.URL.RawQuery = v.Encode()
  487. }
  488. return r, err
  489. })
  490. }
  491. }