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