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