Merge branch '21535-multi-wf-delete'
[arvados.git] / services / keepproxy / keepproxy.go
index eaa64b0ed2bf4dcf38a10ac2490de7de051709ab..97a5ad65929094897e4b8fbf9b9c12b3de1633e2 100644 (file)
@@ -23,6 +23,7 @@ import (
        "git.arvados.org/arvados.git/sdk/go/health"
        "git.arvados.org/arvados.git/sdk/go/httpserver"
        "git.arvados.org/arvados.git/sdk/go/keepclient"
+       "git.arvados.org/arvados.git/services/keepstore"
        "github.com/gorilla/mux"
        lru "github.com/hashicorp/golang-lru"
        "github.com/prometheus/client_golang/prometheus"
@@ -175,13 +176,18 @@ func (h *proxyHandler) checkAuthorizationHeader(req *http.Request) (pass bool, t
        return true, tok, user
 }
 
-// We need to make a private copy of the default http transport early
-// in initialization, then make copies of our private copy later. It
-// won't be safe to copy http.DefaultTransport itself later, because
-// its private mutexes might have already been used. (Without this,
-// the test suite sometimes panics "concurrent map writes" in
-// net/http.(*Transport).removeIdleConnLocked().)
-var defaultTransport = *(http.DefaultTransport.(*http.Transport))
+// We can't copy the default http transport because http.Transport has
+// a mutex field, so we make our own using the values of the exported
+// fields.
+var defaultTransport = http.Transport{
+       Proxy:                 http.DefaultTransport.(*http.Transport).Proxy,
+       DialContext:           http.DefaultTransport.(*http.Transport).DialContext,
+       ForceAttemptHTTP2:     http.DefaultTransport.(*http.Transport).ForceAttemptHTTP2,
+       MaxIdleConns:          http.DefaultTransport.(*http.Transport).MaxIdleConns,
+       IdleConnTimeout:       http.DefaultTransport.(*http.Transport).IdleConnTimeout,
+       TLSHandshakeTimeout:   http.DefaultTransport.(*http.Transport).TLSHandshakeTimeout,
+       ExpectContinueTimeout: http.DefaultTransport.(*http.Transport).ExpectContinueTimeout,
+}
 
 type proxyHandler struct {
        http.Handler
@@ -195,14 +201,23 @@ type proxyHandler struct {
 func newHandler(ctx context.Context, kc *keepclient.KeepClient, timeout time.Duration, cluster *arvados.Cluster) (service.Handler, error) {
        rest := mux.NewRouter()
 
-       transport := defaultTransport
-       transport.DialContext = (&net.Dialer{
-               Timeout:   keepclient.DefaultConnectTimeout,
-               KeepAlive: keepclient.DefaultKeepAlive,
-               DualStack: true,
-       }).DialContext
-       transport.TLSClientConfig = arvadosclient.MakeTLSConfig(kc.Arvados.ApiInsecure)
-       transport.TLSHandshakeTimeout = keepclient.DefaultTLSHandshakeTimeout
+       // We can't copy the default http transport because
+       // http.Transport has a mutex field, so we copy the fields
+       // that we know have non-zero values in http.DefaultTransport.
+       transport := &http.Transport{
+               Proxy:                 http.DefaultTransport.(*http.Transport).Proxy,
+               ForceAttemptHTTP2:     http.DefaultTransport.(*http.Transport).ForceAttemptHTTP2,
+               MaxIdleConns:          http.DefaultTransport.(*http.Transport).MaxIdleConns,
+               IdleConnTimeout:       http.DefaultTransport.(*http.Transport).IdleConnTimeout,
+               ExpectContinueTimeout: http.DefaultTransport.(*http.Transport).ExpectContinueTimeout,
+               DialContext: (&net.Dialer{
+                       Timeout:   keepclient.DefaultConnectTimeout,
+                       KeepAlive: keepclient.DefaultKeepAlive,
+                       DualStack: true,
+               }).DialContext,
+               TLSClientConfig:     arvadosclient.MakeTLSConfig(kc.Arvados.ApiInsecure),
+               TLSHandshakeTimeout: keepclient.DefaultTLSHandshakeTimeout,
+       }
 
        cacheQ, err := lru.New2Q(500)
        if err != nil {
@@ -213,7 +228,7 @@ func newHandler(ctx context.Context, kc *keepclient.KeepClient, timeout time.Dur
                Handler:    rest,
                KeepClient: kc,
                timeout:    timeout,
-               transport:  &transport,
+               transport:  transport,
                apiTokenCache: &apiTokenCache{
                        tokens:     cacheQ,
                        expireTime: 300,
@@ -257,10 +272,9 @@ func (h *proxyHandler) checkLoop(resp http.ResponseWriter, req *http.Request) er
 }
 
 func setCORSHeaders(resp http.ResponseWriter) {
-       resp.Header().Set("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, OPTIONS")
-       resp.Header().Set("Access-Control-Allow-Origin", "*")
-       resp.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Length, Content-Type, X-Keep-Desired-Replicas")
-       resp.Header().Set("Access-Control-Max-Age", "86486400")
+       keepstore.SetCORSHeaders(resp)
+       acam := "Access-Control-Allow-Methods"
+       resp.Header().Set(acam, resp.Header().Get(acam)+", POST")
 }
 
 type invalidPathHandler struct{}
@@ -290,14 +304,13 @@ func (h *proxyHandler) Get(resp http.ResponseWriter, req *http.Request) {
        var err error
        var status int
        var expectLength, responseLength int64
-       var proxiedURI = "-"
 
        logger := ctxlog.FromContext(req.Context())
        defer func() {
                httpserver.SetResponseLogFields(req.Context(), logrus.Fields{
+                       "locator":        locator,
                        "expectLength":   expectLength,
                        "responseLength": responseLength,
-                       "proxiedURI":     proxiedURI,
                        "err":            err,
                })
                if status != http.StatusOK {
@@ -306,6 +319,7 @@ func (h *proxyHandler) Get(resp http.ResponseWriter, req *http.Request) {
        }()
 
        kc := h.makeKeepClient(req)
+       kc.DiskCacheSize = keepclient.DiskCacheDisabled
 
        var pass bool
        var tok string
@@ -330,9 +344,9 @@ func (h *proxyHandler) Get(resp http.ResponseWriter, req *http.Request) {
 
        switch req.Method {
        case "HEAD":
-               expectLength, proxiedURI, err = kc.Ask(locator)
+               expectLength, _, err = kc.Ask(locator)
        case "GET":
-               reader, expectLength, proxiedURI, err = kc.Get(locator)
+               reader, expectLength, _, err = kc.Get(locator)
                if reader != nil {
                        defer reader.Close()
                }
@@ -405,9 +419,9 @@ func (h *proxyHandler) Put(resp http.ResponseWriter, req *http.Request) {
        locatorIn := mux.Vars(req)["locator"]
 
        // Check if the client specified storage classes
-       if req.Header.Get("X-Keep-Storage-Classes") != "" {
+       if req.Header.Get(keepclient.XKeepStorageClasses) != "" {
                var scl []string
-               for _, sc := range strings.Split(req.Header.Get("X-Keep-Storage-Classes"), ",") {
+               for _, sc := range strings.Split(req.Header.Get(keepclient.XKeepStorageClasses), ",") {
                        scl = append(scl, strings.Trim(sc, " "))
                }
                kc.SetStorageClasses(scl)
@@ -508,9 +522,9 @@ func (h *proxyHandler) Put(resp http.ResponseWriter, req *http.Request) {
 // ServeHTTP implementation for IndexHandler
 // Supports only GET requests for /index/{prefix:[0-9a-f]{0,32}}
 // For each keep server found in LocalRoots:
-//   Invokes GetIndex using keepclient
-//   Expects "complete" response (terminating with blank new line)
-//   Aborts on any errors
+// - Invokes GetIndex using keepclient
+// - Expects "complete" response (terminating with blank new line)
+// - Aborts on any errors
 // Concatenates responses from all those keep servers and returns
 func (h *proxyHandler) Index(resp http.ResponseWriter, req *http.Request) {
        setCORSHeaders(resp)
@@ -565,7 +579,7 @@ func (h *proxyHandler) Index(resp http.ResponseWriter, req *http.Request) {
 }
 
 func (h *proxyHandler) makeKeepClient(req *http.Request) *keepclient.KeepClient {
-       kc := *h.KeepClient
+       kc := h.KeepClient.Clone()
        kc.RequestID = req.Header.Get("X-Request-Id")
        kc.HTTPClient = &proxyClient{
                client: &http.Client{
@@ -574,5 +588,5 @@ func (h *proxyHandler) makeKeepClient(req *http.Request) *keepclient.KeepClient
                },
                proto: req.Proto,
        }
-       return &kc
+       return kc
 }