github.com/jjyr/docker@v1.5.0-rc2/utils/http.go (about) 1 package utils 2 3 import ( 4 "io" 5 "net/http" 6 "strings" 7 8 log "github.com/Sirupsen/logrus" 9 ) 10 11 // VersionInfo is used to model entities which has a version. 12 // It is basically a tupple with name and version. 13 type VersionInfo interface { 14 Name() string 15 Version() string 16 } 17 18 func validVersion(version VersionInfo) bool { 19 const stopChars = " \t\r\n/" 20 name := version.Name() 21 vers := version.Version() 22 if len(name) == 0 || strings.ContainsAny(name, stopChars) { 23 return false 24 } 25 if len(vers) == 0 || strings.ContainsAny(vers, stopChars) { 26 return false 27 } 28 return true 29 } 30 31 // Convert versions to a string and append the string to the string base. 32 // 33 // Each VersionInfo will be converted to a string in the format of 34 // "product/version", where the "product" is get from the Name() method, while 35 // version is get from the Version() method. Several pieces of verson information 36 // will be concatinated and separated by space. 37 func appendVersions(base string, versions ...VersionInfo) string { 38 if len(versions) == 0 { 39 return base 40 } 41 42 verstrs := make([]string, 0, 1+len(versions)) 43 if len(base) > 0 { 44 verstrs = append(verstrs, base) 45 } 46 47 for _, v := range versions { 48 if !validVersion(v) { 49 continue 50 } 51 verstrs = append(verstrs, v.Name()+"/"+v.Version()) 52 } 53 return strings.Join(verstrs, " ") 54 } 55 56 // HTTPRequestDecorator is used to change an instance of 57 // http.Request. It could be used to add more header fields, 58 // change body, etc. 59 type HTTPRequestDecorator interface { 60 // ChangeRequest() changes the request accordingly. 61 // The changed request will be returned or err will be non-nil 62 // if an error occur. 63 ChangeRequest(req *http.Request) (newReq *http.Request, err error) 64 } 65 66 // HTTPUserAgentDecorator appends the product/version to the user agent field 67 // of a request. 68 type HTTPUserAgentDecorator struct { 69 versions []VersionInfo 70 } 71 72 func NewHTTPUserAgentDecorator(versions ...VersionInfo) HTTPRequestDecorator { 73 return &HTTPUserAgentDecorator{ 74 versions: versions, 75 } 76 } 77 78 func (h *HTTPUserAgentDecorator) ChangeRequest(req *http.Request) (newReq *http.Request, err error) { 79 if req == nil { 80 return req, nil 81 } 82 83 userAgent := appendVersions(req.UserAgent(), h.versions...) 84 if len(userAgent) > 0 { 85 req.Header.Set("User-Agent", userAgent) 86 } 87 return req, nil 88 } 89 90 type HTTPMetaHeadersDecorator struct { 91 Headers map[string][]string 92 } 93 94 func (h *HTTPMetaHeadersDecorator) ChangeRequest(req *http.Request) (newReq *http.Request, err error) { 95 if h.Headers == nil { 96 return req, nil 97 } 98 for k, v := range h.Headers { 99 req.Header[k] = v 100 } 101 return req, nil 102 } 103 104 type HTTPAuthDecorator struct { 105 login string 106 password string 107 } 108 109 func NewHTTPAuthDecorator(login, password string) HTTPRequestDecorator { 110 return &HTTPAuthDecorator{ 111 login: login, 112 password: password, 113 } 114 } 115 116 func (self *HTTPAuthDecorator) ChangeRequest(req *http.Request) (*http.Request, error) { 117 req.SetBasicAuth(self.login, self.password) 118 return req, nil 119 } 120 121 // HTTPRequestFactory creates an HTTP request 122 // and applies a list of decorators on the request. 123 type HTTPRequestFactory struct { 124 decorators []HTTPRequestDecorator 125 } 126 127 func NewHTTPRequestFactory(d ...HTTPRequestDecorator) *HTTPRequestFactory { 128 return &HTTPRequestFactory{ 129 decorators: d, 130 } 131 } 132 133 func (self *HTTPRequestFactory) AddDecorator(d ...HTTPRequestDecorator) { 134 self.decorators = append(self.decorators, d...) 135 } 136 137 func (self *HTTPRequestFactory) GetDecorators() []HTTPRequestDecorator { 138 return self.decorators 139 } 140 141 // NewRequest() creates a new *http.Request, 142 // applies all decorators in the HTTPRequestFactory on the request, 143 // then applies decorators provided by d on the request. 144 func (h *HTTPRequestFactory) NewRequest(method, urlStr string, body io.Reader, d ...HTTPRequestDecorator) (*http.Request, error) { 145 req, err := http.NewRequest(method, urlStr, body) 146 if err != nil { 147 return nil, err 148 } 149 150 // By default, a nil factory should work. 151 if h == nil { 152 return req, nil 153 } 154 for _, dec := range h.decorators { 155 req, err = dec.ChangeRequest(req) 156 if err != nil { 157 return nil, err 158 } 159 } 160 for _, dec := range d { 161 req, err = dec.ChangeRequest(req) 162 if err != nil { 163 return nil, err 164 } 165 } 166 log.Debugf("%v -- HEADERS: %v", req.URL, req.Header) 167 return req, err 168 }