github.com/vieux/docker@v0.6.3-0.20161004191708-e097c2a938c7/api/server/httputils/httputils.go (about) 1 package httputils 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "net/http" 8 "strings" 9 10 "golang.org/x/net/context" 11 12 "github.com/docker/docker/api" 13 ) 14 15 // APIVersionKey is the client's requested API version. 16 const APIVersionKey = "api-version" 17 18 // UAStringKey is used as key type for user-agent string in net/context struct 19 const UAStringKey = "upstream-user-agent" 20 21 // APIFunc is an adapter to allow the use of ordinary functions as Docker API endpoints. 22 // Any function that has the appropriate signature can be registered as an API endpoint (e.g. getVersion). 23 type APIFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error 24 25 // HijackConnection interrupts the http response writer to get the 26 // underlying connection and operate with it. 27 func HijackConnection(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) { 28 conn, _, err := w.(http.Hijacker).Hijack() 29 if err != nil { 30 return nil, nil, err 31 } 32 // Flush the options to make sure the client sets the raw mode 33 conn.Write([]byte{}) 34 return conn, conn, nil 35 } 36 37 // CloseStreams ensures that a list for http streams are properly closed. 38 func CloseStreams(streams ...interface{}) { 39 for _, stream := range streams { 40 if tcpc, ok := stream.(interface { 41 CloseWrite() error 42 }); ok { 43 tcpc.CloseWrite() 44 } else if closer, ok := stream.(io.Closer); ok { 45 closer.Close() 46 } 47 } 48 } 49 50 // CheckForJSON makes sure that the request's Content-Type is application/json. 51 func CheckForJSON(r *http.Request) error { 52 ct := r.Header.Get("Content-Type") 53 54 // No Content-Type header is ok as long as there's no Body 55 if ct == "" { 56 if r.Body == nil || r.ContentLength == 0 { 57 return nil 58 } 59 } 60 61 // Otherwise it better be json 62 if api.MatchesContentType(ct, "application/json") { 63 return nil 64 } 65 return fmt.Errorf("Content-Type specified (%s) must be 'application/json'", ct) 66 } 67 68 // ParseForm ensures the request form is parsed even with invalid content types. 69 // If we don't do this, POST method without Content-type (even with empty body) will fail. 70 func ParseForm(r *http.Request) error { 71 if r == nil { 72 return nil 73 } 74 if err := r.ParseForm(); err != nil && !strings.HasPrefix(err.Error(), "mime:") { 75 return err 76 } 77 return nil 78 } 79 80 // WriteJSON writes the value v to the http response stream as json with standard json encoding. 81 func WriteJSON(w http.ResponseWriter, code int, v interface{}) error { 82 w.Header().Set("Content-Type", "application/json") 83 w.WriteHeader(code) 84 enc := json.NewEncoder(w) 85 enc.SetEscapeHTML(false) 86 return enc.Encode(v) 87 } 88 89 // VersionFromContext returns an API version from the context using APIVersionKey. 90 // It panics if the context value does not have version.Version type. 91 func VersionFromContext(ctx context.Context) (ver string) { 92 if ctx == nil { 93 return 94 } 95 val := ctx.Value(APIVersionKey) 96 if val == nil { 97 return 98 } 99 return val.(string) 100 }