transport.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. // Copyright 2015 The Go Authors. All rights reserved.
  2. //
  3. // Use of this source code is governed by a BSD-style
  4. // license that can be found in the LICENSE file or at
  5. // https://developers.google.com/open-source/licenses/bsd.
  6. // This file implements a http.RoundTripper that authenticates
  7. // requests issued against api.github.com endpoint.
  8. package httputil
  9. import (
  10. "net/http"
  11. "net/url"
  12. )
  13. // AuthTransport is an implementation of http.RoundTripper that authenticates
  14. // with the GitHub API.
  15. //
  16. // When both a token and client credentials are set, the latter is preferred.
  17. type AuthTransport struct {
  18. UserAgent string
  19. GithubToken string
  20. GithubClientID string
  21. GithubClientSecret string
  22. Base http.RoundTripper
  23. }
  24. // RoundTrip implements the http.RoundTripper interface.
  25. func (t *AuthTransport) RoundTrip(req *http.Request) (*http.Response, error) {
  26. var reqCopy *http.Request
  27. if t.UserAgent != "" {
  28. reqCopy = copyRequest(req)
  29. reqCopy.Header.Set("User-Agent", t.UserAgent)
  30. }
  31. if req.URL.Host == "api.github.com" && req.URL.Scheme == "https" {
  32. switch {
  33. case t.GithubClientID != "" && t.GithubClientSecret != "":
  34. if reqCopy == nil {
  35. reqCopy = copyRequest(req)
  36. }
  37. if reqCopy.URL.RawQuery == "" {
  38. reqCopy.URL.RawQuery = "client_id=" + t.GithubClientID + "&client_secret=" + t.GithubClientSecret
  39. } else {
  40. reqCopy.URL.RawQuery += "&client_id=" + t.GithubClientID + "&client_secret=" + t.GithubClientSecret
  41. }
  42. case t.GithubToken != "":
  43. if reqCopy == nil {
  44. reqCopy = copyRequest(req)
  45. }
  46. reqCopy.Header.Set("Authorization", "token "+t.GithubToken)
  47. }
  48. }
  49. if reqCopy != nil {
  50. return t.base().RoundTrip(reqCopy)
  51. }
  52. return t.base().RoundTrip(req)
  53. }
  54. // CancelRequest cancels an in-flight request by closing its connection.
  55. func (t *AuthTransport) CancelRequest(req *http.Request) {
  56. type canceler interface {
  57. CancelRequest(req *http.Request)
  58. }
  59. if cr, ok := t.base().(canceler); ok {
  60. cr.CancelRequest(req)
  61. }
  62. }
  63. func (t *AuthTransport) base() http.RoundTripper {
  64. if t.Base != nil {
  65. return t.Base
  66. }
  67. return http.DefaultTransport
  68. }
  69. func copyRequest(req *http.Request) *http.Request {
  70. req2 := new(http.Request)
  71. *req2 = *req
  72. req2.URL = new(url.URL)
  73. *req2.URL = *req.URL
  74. req2.Header = make(http.Header, len(req.Header))
  75. for k, s := range req.Header {
  76. req2.Header[k] = append([]string(nil), s...)
  77. }
  78. return req2
  79. }