123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481 |
- package autorest
- // Copyright 2017 Microsoft Corporation
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- import (
- "bytes"
- "encoding/json"
- "fmt"
- "io"
- "io/ioutil"
- "mime/multipart"
- "net/http"
- "net/url"
- "strings"
- )
- const (
- mimeTypeJSON = "application/json"
- mimeTypeOctetStream = "application/octet-stream"
- mimeTypeFormPost = "application/x-www-form-urlencoded"
- headerAuthorization = "Authorization"
- headerContentType = "Content-Type"
- headerUserAgent = "User-Agent"
- )
- // Preparer is the interface that wraps the Prepare method.
- //
- // Prepare accepts and possibly modifies an http.Request (e.g., adding Headers). Implementations
- // must ensure to not share or hold per-invocation state since Preparers may be shared and re-used.
- type Preparer interface {
- Prepare(*http.Request) (*http.Request, error)
- }
- // PreparerFunc is a method that implements the Preparer interface.
- type PreparerFunc func(*http.Request) (*http.Request, error)
- // Prepare implements the Preparer interface on PreparerFunc.
- func (pf PreparerFunc) Prepare(r *http.Request) (*http.Request, error) {
- return pf(r)
- }
- // PrepareDecorator takes and possibly decorates, by wrapping, a Preparer. Decorators may affect the
- // http.Request and pass it along or, first, pass the http.Request along then affect the result.
- type PrepareDecorator func(Preparer) Preparer
- // CreatePreparer creates, decorates, and returns a Preparer.
- // Without decorators, the returned Preparer returns the passed http.Request unmodified.
- // Preparers are safe to share and re-use.
- func CreatePreparer(decorators ...PrepareDecorator) Preparer {
- return DecoratePreparer(
- Preparer(PreparerFunc(func(r *http.Request) (*http.Request, error) { return r, nil })),
- decorators...)
- }
- // DecoratePreparer accepts a Preparer and a, possibly empty, set of PrepareDecorators, which it
- // applies to the Preparer. Decorators are applied in the order received, but their affect upon the
- // request depends on whether they are a pre-decorator (change the http.Request and then pass it
- // along) or a post-decorator (pass the http.Request along and alter it on return).
- func DecoratePreparer(p Preparer, decorators ...PrepareDecorator) Preparer {
- for _, decorate := range decorators {
- p = decorate(p)
- }
- return p
- }
- // Prepare accepts an http.Request and a, possibly empty, set of PrepareDecorators.
- // It creates a Preparer from the decorators which it then applies to the passed http.Request.
- func Prepare(r *http.Request, decorators ...PrepareDecorator) (*http.Request, error) {
- if r == nil {
- return nil, NewError("autorest", "Prepare", "Invoked without an http.Request")
- }
- return CreatePreparer(decorators...).Prepare(r)
- }
- // WithNothing returns a "do nothing" PrepareDecorator that makes no changes to the passed
- // http.Request.
- func WithNothing() PrepareDecorator {
- return func(p Preparer) Preparer {
- return PreparerFunc(func(r *http.Request) (*http.Request, error) {
- return p.Prepare(r)
- })
- }
- }
- // WithHeader returns a PrepareDecorator that sets the specified HTTP header of the http.Request to
- // the passed value. It canonicalizes the passed header name (via http.CanonicalHeaderKey) before
- // adding the header.
- func WithHeader(header string, value string) PrepareDecorator {
- return func(p Preparer) Preparer {
- return PreparerFunc(func(r *http.Request) (*http.Request, error) {
- r, err := p.Prepare(r)
- if err == nil {
- if r.Header == nil {
- r.Header = make(http.Header)
- }
- r.Header.Set(http.CanonicalHeaderKey(header), value)
- }
- return r, err
- })
- }
- }
- // WithHeaders returns a PrepareDecorator that sets the specified HTTP headers of the http.Request to
- // the passed value. It canonicalizes the passed headers name (via http.CanonicalHeaderKey) before
- // adding them.
- func WithHeaders(headers map[string]interface{}) PrepareDecorator {
- h := ensureValueStrings(headers)
- return func(p Preparer) Preparer {
- return PreparerFunc(func(r *http.Request) (*http.Request, error) {
- r, err := p.Prepare(r)
- if err == nil {
- if r.Header == nil {
- r.Header = make(http.Header)
- }
- for name, value := range h {
- r.Header.Set(http.CanonicalHeaderKey(name), value)
- }
- }
- return r, err
- })
- }
- }
- // WithBearerAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose
- // value is "Bearer " followed by the supplied token.
- func WithBearerAuthorization(token string) PrepareDecorator {
- return WithHeader(headerAuthorization, fmt.Sprintf("Bearer %s", token))
- }
- // AsContentType returns a PrepareDecorator that adds an HTTP Content-Type header whose value
- // is the passed contentType.
- func AsContentType(contentType string) PrepareDecorator {
- return WithHeader(headerContentType, contentType)
- }
- // WithUserAgent returns a PrepareDecorator that adds an HTTP User-Agent header whose value is the
- // passed string.
- func WithUserAgent(ua string) PrepareDecorator {
- return WithHeader(headerUserAgent, ua)
- }
- // AsFormURLEncoded returns a PrepareDecorator that adds an HTTP Content-Type header whose value is
- // "application/x-www-form-urlencoded".
- func AsFormURLEncoded() PrepareDecorator {
- return AsContentType(mimeTypeFormPost)
- }
- // AsJSON returns a PrepareDecorator that adds an HTTP Content-Type header whose value is
- // "application/json".
- func AsJSON() PrepareDecorator {
- return AsContentType(mimeTypeJSON)
- }
- // AsOctetStream returns a PrepareDecorator that adds the "application/octet-stream" Content-Type header.
- func AsOctetStream() PrepareDecorator {
- return AsContentType(mimeTypeOctetStream)
- }
- // WithMethod returns a PrepareDecorator that sets the HTTP method of the passed request. The
- // decorator does not validate that the passed method string is a known HTTP method.
- func WithMethod(method string) PrepareDecorator {
- return func(p Preparer) Preparer {
- return PreparerFunc(func(r *http.Request) (*http.Request, error) {
- r.Method = method
- return p.Prepare(r)
- })
- }
- }
- // AsDelete returns a PrepareDecorator that sets the HTTP method to DELETE.
- func AsDelete() PrepareDecorator { return WithMethod("DELETE") }
- // AsGet returns a PrepareDecorator that sets the HTTP method to GET.
- func AsGet() PrepareDecorator { return WithMethod("GET") }
- // AsHead returns a PrepareDecorator that sets the HTTP method to HEAD.
- func AsHead() PrepareDecorator { return WithMethod("HEAD") }
- // AsOptions returns a PrepareDecorator that sets the HTTP method to OPTIONS.
- func AsOptions() PrepareDecorator { return WithMethod("OPTIONS") }
- // AsPatch returns a PrepareDecorator that sets the HTTP method to PATCH.
- func AsPatch() PrepareDecorator { return WithMethod("PATCH") }
- // AsPost returns a PrepareDecorator that sets the HTTP method to POST.
- func AsPost() PrepareDecorator { return WithMethod("POST") }
- // AsPut returns a PrepareDecorator that sets the HTTP method to PUT.
- func AsPut() PrepareDecorator { return WithMethod("PUT") }
- // WithBaseURL returns a PrepareDecorator that populates the http.Request with a url.URL constructed
- // from the supplied baseUrl.
- func WithBaseURL(baseURL string) PrepareDecorator {
- return func(p Preparer) Preparer {
- return PreparerFunc(func(r *http.Request) (*http.Request, error) {
- r, err := p.Prepare(r)
- if err == nil {
- var u *url.URL
- if u, err = url.Parse(baseURL); err != nil {
- return r, err
- }
- if u.Scheme == "" {
- err = fmt.Errorf("autorest: No scheme detected in URL %s", baseURL)
- }
- if err == nil {
- r.URL = u
- }
- }
- return r, err
- })
- }
- }
- // WithCustomBaseURL returns a PrepareDecorator that replaces brace-enclosed keys within the
- // request base URL (i.e., http.Request.URL) with the corresponding values from the passed map.
- func WithCustomBaseURL(baseURL string, urlParameters map[string]interface{}) PrepareDecorator {
- parameters := ensureValueStrings(urlParameters)
- for key, value := range parameters {
- baseURL = strings.Replace(baseURL, "{"+key+"}", value, -1)
- }
- return WithBaseURL(baseURL)
- }
- // WithFormData returns a PrepareDecoratore that "URL encodes" (e.g., bar=baz&foo=quux) into the
- // http.Request body.
- func WithFormData(v url.Values) PrepareDecorator {
- return func(p Preparer) Preparer {
- return PreparerFunc(func(r *http.Request) (*http.Request, error) {
- r, err := p.Prepare(r)
- if err == nil {
- s := v.Encode()
- if r.Header == nil {
- r.Header = make(http.Header)
- }
- r.Header.Set(http.CanonicalHeaderKey(headerContentType), mimeTypeFormPost)
- r.ContentLength = int64(len(s))
- r.Body = ioutil.NopCloser(strings.NewReader(s))
- }
- return r, err
- })
- }
- }
- // WithMultiPartFormData returns a PrepareDecoratore that "URL encodes" (e.g., bar=baz&foo=quux) form parameters
- // into the http.Request body.
- func WithMultiPartFormData(formDataParameters map[string]interface{}) PrepareDecorator {
- return func(p Preparer) Preparer {
- return PreparerFunc(func(r *http.Request) (*http.Request, error) {
- r, err := p.Prepare(r)
- if err == nil {
- var body bytes.Buffer
- writer := multipart.NewWriter(&body)
- for key, value := range formDataParameters {
- if rc, ok := value.(io.ReadCloser); ok {
- var fd io.Writer
- if fd, err = writer.CreateFormFile(key, key); err != nil {
- return r, err
- }
- if _, err = io.Copy(fd, rc); err != nil {
- return r, err
- }
- } else {
- if err = writer.WriteField(key, ensureValueString(value)); err != nil {
- return r, err
- }
- }
- }
- if err = writer.Close(); err != nil {
- return r, err
- }
- if r.Header == nil {
- r.Header = make(http.Header)
- }
- r.Header.Set(http.CanonicalHeaderKey(headerContentType), writer.FormDataContentType())
- r.Body = ioutil.NopCloser(bytes.NewReader(body.Bytes()))
- r.ContentLength = int64(body.Len())
- return r, err
- }
- return r, err
- })
- }
- }
- // WithFile returns a PrepareDecorator that sends file in request body.
- func WithFile(f io.ReadCloser) PrepareDecorator {
- return func(p Preparer) Preparer {
- return PreparerFunc(func(r *http.Request) (*http.Request, error) {
- r, err := p.Prepare(r)
- if err == nil {
- b, err := ioutil.ReadAll(f)
- if err != nil {
- return r, err
- }
- r.Body = ioutil.NopCloser(bytes.NewReader(b))
- r.ContentLength = int64(len(b))
- }
- return r, err
- })
- }
- }
- // WithBool returns a PrepareDecorator that encodes the passed bool into the body of the request
- // and sets the Content-Length header.
- func WithBool(v bool) PrepareDecorator {
- return WithString(fmt.Sprintf("%v", v))
- }
- // WithFloat32 returns a PrepareDecorator that encodes the passed float32 into the body of the
- // request and sets the Content-Length header.
- func WithFloat32(v float32) PrepareDecorator {
- return WithString(fmt.Sprintf("%v", v))
- }
- // WithFloat64 returns a PrepareDecorator that encodes the passed float64 into the body of the
- // request and sets the Content-Length header.
- func WithFloat64(v float64) PrepareDecorator {
- return WithString(fmt.Sprintf("%v", v))
- }
- // WithInt32 returns a PrepareDecorator that encodes the passed int32 into the body of the request
- // and sets the Content-Length header.
- func WithInt32(v int32) PrepareDecorator {
- return WithString(fmt.Sprintf("%v", v))
- }
- // WithInt64 returns a PrepareDecorator that encodes the passed int64 into the body of the request
- // and sets the Content-Length header.
- func WithInt64(v int64) PrepareDecorator {
- return WithString(fmt.Sprintf("%v", v))
- }
- // WithString returns a PrepareDecorator that encodes the passed string into the body of the request
- // and sets the Content-Length header.
- func WithString(v string) PrepareDecorator {
- return func(p Preparer) Preparer {
- return PreparerFunc(func(r *http.Request) (*http.Request, error) {
- r, err := p.Prepare(r)
- if err == nil {
- r.ContentLength = int64(len(v))
- r.Body = ioutil.NopCloser(strings.NewReader(v))
- }
- return r, err
- })
- }
- }
- // WithJSON returns a PrepareDecorator that encodes the data passed as JSON into the body of the
- // request and sets the Content-Length header.
- func WithJSON(v interface{}) PrepareDecorator {
- return func(p Preparer) Preparer {
- return PreparerFunc(func(r *http.Request) (*http.Request, error) {
- r, err := p.Prepare(r)
- if err == nil {
- b, err := json.Marshal(v)
- if err == nil {
- r.ContentLength = int64(len(b))
- r.Body = ioutil.NopCloser(bytes.NewReader(b))
- }
- }
- return r, err
- })
- }
- }
- // WithPath returns a PrepareDecorator that adds the supplied path to the request URL. If the path
- // is absolute (that is, it begins with a "/"), it replaces the existing path.
- func WithPath(path string) PrepareDecorator {
- return func(p Preparer) Preparer {
- return PreparerFunc(func(r *http.Request) (*http.Request, error) {
- r, err := p.Prepare(r)
- if err == nil {
- if r.URL == nil {
- return r, NewError("autorest", "WithPath", "Invoked with a nil URL")
- }
- if r.URL, err = parseURL(r.URL, path); err != nil {
- return r, err
- }
- }
- return r, err
- })
- }
- }
- // WithEscapedPathParameters returns a PrepareDecorator that replaces brace-enclosed keys within the
- // request path (i.e., http.Request.URL.Path) with the corresponding values from the passed map. The
- // values will be escaped (aka URL encoded) before insertion into the path.
- func WithEscapedPathParameters(path string, pathParameters map[string]interface{}) PrepareDecorator {
- parameters := escapeValueStrings(ensureValueStrings(pathParameters))
- return func(p Preparer) Preparer {
- return PreparerFunc(func(r *http.Request) (*http.Request, error) {
- r, err := p.Prepare(r)
- if err == nil {
- if r.URL == nil {
- return r, NewError("autorest", "WithEscapedPathParameters", "Invoked with a nil URL")
- }
- for key, value := range parameters {
- path = strings.Replace(path, "{"+key+"}", value, -1)
- }
- if r.URL, err = parseURL(r.URL, path); err != nil {
- return r, err
- }
- }
- return r, err
- })
- }
- }
- // WithPathParameters returns a PrepareDecorator that replaces brace-enclosed keys within the
- // request path (i.e., http.Request.URL.Path) with the corresponding values from the passed map.
- func WithPathParameters(path string, pathParameters map[string]interface{}) PrepareDecorator {
- parameters := ensureValueStrings(pathParameters)
- return func(p Preparer) Preparer {
- return PreparerFunc(func(r *http.Request) (*http.Request, error) {
- r, err := p.Prepare(r)
- if err == nil {
- if r.URL == nil {
- return r, NewError("autorest", "WithPathParameters", "Invoked with a nil URL")
- }
- for key, value := range parameters {
- path = strings.Replace(path, "{"+key+"}", value, -1)
- }
- if r.URL, err = parseURL(r.URL, path); err != nil {
- return r, err
- }
- }
- return r, err
- })
- }
- }
- func parseURL(u *url.URL, path string) (*url.URL, error) {
- p := strings.TrimRight(u.String(), "/")
- if !strings.HasPrefix(path, "/") {
- path = "/" + path
- }
- return url.Parse(p + path)
- }
- // WithQueryParameters returns a PrepareDecorators that encodes and applies the query parameters
- // given in the supplied map (i.e., key=value).
- func WithQueryParameters(queryParameters map[string]interface{}) PrepareDecorator {
- parameters := ensureValueStrings(queryParameters)
- return func(p Preparer) Preparer {
- return PreparerFunc(func(r *http.Request) (*http.Request, error) {
- r, err := p.Prepare(r)
- if err == nil {
- if r.URL == nil {
- return r, NewError("autorest", "WithQueryParameters", "Invoked with a nil URL")
- }
- v := r.URL.Query()
- for key, value := range parameters {
- d, err := url.QueryUnescape(value)
- if err != nil {
- return r, err
- }
- v.Add(key, d)
- }
- r.URL.RawQuery = v.Encode()
- }
- return r, err
- })
- }
- }
|