github.com/flavio/docker@v0.1.3-0.20170117145210-f63d1a6eec47/api/server/httputils/httputils.go (about)

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