mirror of https://github.com/docker/docs.git
				
				
				
			
		
			
				
	
	
		
			171 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			171 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
| package utils
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"io"
 | |
| 	"net/http"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| // 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 {
 | |
| 	stopChars := " \t\r\n/"
 | |
| 	if strings.ContainsAny(version.Name(), stopChars) {
 | |
| 		return false
 | |
| 	}
 | |
| 	if strings.ContainsAny(version.Version(), 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
 | |
| 	}
 | |
| 
 | |
| 	var buf bytes.Buffer
 | |
| 	if len(base) > 0 {
 | |
| 		buf.Write([]byte(base))
 | |
| 	}
 | |
| 
 | |
| 	for _, v := range versions {
 | |
| 		name := []byte(v.Name())
 | |
| 		version := []byte(v.Version())
 | |
| 
 | |
| 		if len(name) == 0 || len(version) == 0 {
 | |
| 			continue
 | |
| 		}
 | |
| 		if !validVersion(v) {
 | |
| 			continue
 | |
| 		}
 | |
| 		buf.Write([]byte(v.Name()))
 | |
| 		buf.Write([]byte("/"))
 | |
| 		buf.Write([]byte(v.Version()))
 | |
| 		buf.Write([]byte(" "))
 | |
| 	}
 | |
| 	return buf.String()
 | |
| }
 | |
| 
 | |
| // 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 {
 | |
| 	ret := new(HTTPUserAgentDecorator)
 | |
| 	ret.versions = versions
 | |
| 	return ret
 | |
| }
 | |
| 
 | |
| 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 {
 | |
| 	ret := new(HTTPAuthDecorator)
 | |
| 	ret.login = login
 | |
| 	ret.password = password
 | |
| 	return ret
 | |
| }
 | |
| 
 | |
| 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...)
 | |
| }
 | |
| 
 | |
| // 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
 | |
| 		}
 | |
| 	}
 | |
| 	Debugf("%v -- HEADERS: %v", req.URL, req.Header)
 | |
| 	return req, err
 | |
| }
 |