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  }