send.go 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. // Copyright 2016 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package gensupport
  5. import (
  6. "encoding/json"
  7. "errors"
  8. "net/http"
  9. "golang.org/x/net/context"
  10. "golang.org/x/net/context/ctxhttp"
  11. )
  12. // Hook is the type of a function that is called once before each HTTP request
  13. // that is sent by a generated API. It returns a function that is called after
  14. // the request returns.
  15. // Hooks are not called if the context is nil.
  16. type Hook func(ctx context.Context, req *http.Request) func(resp *http.Response)
  17. var hooks []Hook
  18. // RegisterHook registers a Hook to be called before each HTTP request by a
  19. // generated API. Hooks are called in the order they are registered. Each
  20. // hook can return a function; if it is non-nil, it is called after the HTTP
  21. // request returns. These functions are called in the reverse order.
  22. // RegisterHook should not be called concurrently with itself or SendRequest.
  23. func RegisterHook(h Hook) {
  24. hooks = append(hooks, h)
  25. }
  26. // SendRequest sends a single HTTP request using the given client.
  27. // If ctx is non-nil, it calls all hooks, then sends the request with
  28. // ctxhttp.Do, then calls any functions returned by the hooks in reverse order.
  29. func SendRequest(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
  30. // Disallow Accept-Encoding because it interferes with the automatic gzip handling
  31. // done by the default http.Transport. See https://github.com/google/google-api-go-client/issues/219.
  32. if _, ok := req.Header["Accept-Encoding"]; ok {
  33. return nil, errors.New("google api: custom Accept-Encoding headers not allowed")
  34. }
  35. if ctx == nil {
  36. return client.Do(req)
  37. }
  38. // Call hooks in order of registration, store returned funcs.
  39. post := make([]func(resp *http.Response), len(hooks))
  40. for i, h := range hooks {
  41. fn := h(ctx, req)
  42. post[i] = fn
  43. }
  44. // Send request.
  45. resp, err := ctxhttp.Do(ctx, client, req)
  46. // Call returned funcs in reverse order.
  47. for i := len(post) - 1; i >= 0; i-- {
  48. if fn := post[i]; fn != nil {
  49. fn(resp)
  50. }
  51. }
  52. return resp, err
  53. }
  54. // DecodeResponse decodes the body of res into target. If there is no body,
  55. // target is unchanged.
  56. func DecodeResponse(target interface{}, res *http.Response) error {
  57. if res.StatusCode == http.StatusNoContent {
  58. return nil
  59. }
  60. return json.NewDecoder(res.Body).Decode(target)
  61. }