123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- package utils
- import (
- "io"
- "net/http"
- "strings"
- log "github.com/Sirupsen/logrus"
- )
- // VersionInfo is used to model entities which has a version.
- // It is basically a tupple with name and version.
- type VersionInfo interface {
- Name() string
- Version() string
- }
- func validVersion(version VersionInfo) bool {
- const stopChars = " \t\r\n/"
- name := version.Name()
- vers := version.Version()
- if len(name) == 0 || strings.ContainsAny(name, stopChars) {
- return false
- }
- if len(vers) == 0 || strings.ContainsAny(vers, stopChars) {
- return false
- }
- return true
- }
- // Convert versions to a string and append the string to the string base.
- //
- // Each VersionInfo will be converted to a string in the format of
- // "product/version", where the "product" is get from the Name() method, while
- // version is get from the Version() method. Several pieces of verson information
- // will be concatinated and separated by space.
- func appendVersions(base string, versions ...VersionInfo) string {
- if len(versions) == 0 {
- return base
- }
- verstrs := make([]string, 0, 1+len(versions))
- if len(base) > 0 {
- verstrs = append(verstrs, base)
- }
- for _, v := range versions {
- if !validVersion(v) {
- continue
- }
- verstrs = append(verstrs, v.Name()+"/"+v.Version())
- }
- return strings.Join(verstrs, " ")
- }
- // HTTPRequestDecorator is used to change an instance of
- // http.Request. It could be used to add more header fields,
- // change body, etc.
- type HTTPRequestDecorator interface {
- // ChangeRequest() changes the request accordingly.
- // The changed request will be returned or err will be non-nil
- // if an error occur.
- ChangeRequest(req *http.Request) (newReq *http.Request, err error)
- }
- // HTTPUserAgentDecorator appends the product/version to the user agent field
- // of a request.
- type HTTPUserAgentDecorator struct {
- versions []VersionInfo
- }
- func NewHTTPUserAgentDecorator(versions ...VersionInfo) HTTPRequestDecorator {
- return &HTTPUserAgentDecorator{
- versions: versions,
- }
- }
- func (h *HTTPUserAgentDecorator) ChangeRequest(req *http.Request) (newReq *http.Request, err error) {
- if req == nil {
- return req, nil
- }
- userAgent := appendVersions(req.UserAgent(), h.versions...)
- if len(userAgent) > 0 {
- req.Header.Set("User-Agent", userAgent)
- }
- return req, nil
- }
- type HTTPMetaHeadersDecorator struct {
- Headers map[string][]string
- }
- func (h *HTTPMetaHeadersDecorator) ChangeRequest(req *http.Request) (newReq *http.Request, err error) {
- if h.Headers == nil {
- return req, nil
- }
- for k, v := range h.Headers {
- req.Header[k] = v
- }
- return req, nil
- }
- type HTTPAuthDecorator struct {
- login string
- password string
- }
- func NewHTTPAuthDecorator(login, password string) HTTPRequestDecorator {
- return &HTTPAuthDecorator{
- login: login,
- password: password,
- }
- }
- func (self *HTTPAuthDecorator) ChangeRequest(req *http.Request) (*http.Request, error) {
- req.SetBasicAuth(self.login, self.password)
- return req, nil
- }
- // HTTPRequestFactory creates an HTTP request
- // and applies a list of decorators on the request.
- type HTTPRequestFactory struct {
- decorators []HTTPRequestDecorator
- }
- func NewHTTPRequestFactory(d ...HTTPRequestDecorator) *HTTPRequestFactory {
- return &HTTPRequestFactory{
- decorators: d,
- }
- }
- func (self *HTTPRequestFactory) AddDecorator(d ...HTTPRequestDecorator) {
- self.decorators = append(self.decorators, d...)
- }
- func (self *HTTPRequestFactory) GetDecorators() []HTTPRequestDecorator {
- return self.decorators
- }
- // NewRequest() creates a new *http.Request,
- // applies all decorators in the HTTPRequestFactory on the request,
- // then applies decorators provided by d on the request.
- func (h *HTTPRequestFactory) NewRequest(method, urlStr string, body io.Reader, d ...HTTPRequestDecorator) (*http.Request, error) {
- req, err := http.NewRequest(method, urlStr, body)
- if err != nil {
- return nil, err
- }
- // By default, a nil factory should work.
- if h == nil {
- return req, nil
- }
- for _, dec := range h.decorators {
- req, err = dec.ChangeRequest(req)
- if err != nil {
- return nil, err
- }
- }
- for _, dec := range d {
- req, err = dec.ChangeRequest(req)
- if err != nil {
- return nil, err
- }
- }
- log.Debugf("%v -- HEADERS: %v", req.URL, req.Header)
- return req, err
- }
|