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