func (this PutBlockHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { kc := *this.KeepClient hash := mux.Vars(req)["hash"] hints := mux.Vars(req)["hints"] locator := keepclient.MakeLocator2(hash, hints) var contentLength int64 = -1 if req.Header.Get("Content-Length") != "" { _, err := fmt.Sscanf(req.Header.Get("Content-Length"), "%d", &contentLength) if err != nil { resp.Header().Set("Content-Length", fmt.Sprintf("%d", contentLength)) } } log.Printf("%s: %s %s Content-Length %v", GetRemoteAddress(req), req.Method, hash, contentLength) if contentLength < 1 { http.Error(resp, "Must include Content-Length header", http.StatusLengthRequired) return } if locator.Size > 0 && int64(locator.Size) != contentLength { http.Error(resp, "Locator size hint does not match Content-Length header", http.StatusBadRequest) return } var pass bool var tok string if pass, tok = CheckAuthorizationHeader(kc, this.ApiTokenCache, req); !pass { http.Error(resp, "Missing or invalid Authorization header", http.StatusForbidden) return } // Copy ArvadosClient struct and use the client's API token arvclient := *kc.Arvados arvclient.ApiToken = tok kc.Arvados = &arvclient // Check if the client specified the number of replicas if req.Header.Get("X-Keep-Desired-Replicas") != "" { var r int _, err := fmt.Sscanf(req.Header.Get(keepclient.X_Keep_Desired_Replicas), "%d", &r) if err != nil { kc.Want_replicas = r } } // Now try to put the block through hash, replicas, err := kc.PutHR(hash, req.Body, contentLength) // Tell the client how many successful PUTs we accomplished resp.Header().Set(keepclient.X_Keep_Replicas_Stored, fmt.Sprintf("%d", replicas)) switch err { case nil: // Default will return http.StatusOK log.Printf("%s: %s %s finished, stored %v replicas (desired %v)", GetRemoteAddress(req), req.Method, hash, replicas, kc.Want_replicas) n, err2 := io.WriteString(resp, hash) if err2 != nil { log.Printf("%s: wrote %v bytes to response body and got error %v", n, err2.Error()) } case keepclient.OversizeBlockError: // Too much data http.Error(resp, fmt.Sprintf("Exceeded maximum blocksize %d", keepclient.BLOCKSIZE), http.StatusRequestEntityTooLarge) case keepclient.InsufficientReplicasError: if replicas > 0 { // At least one write is considered success. The // client can decide if getting less than the number of // replications it asked for is a fatal error. // Default will return http.StatusOK n, err2 := io.WriteString(resp, hash) if err2 != nil { log.Printf("%s: wrote %v bytes to response body and got error %v", n, err2.Error()) } } else { http.Error(resp, "", http.StatusServiceUnavailable) } default: http.Error(resp, err.Error(), http.StatusBadGateway) } if err != nil { log.Printf("%s: %s %s stored %v replicas (desired %v) got error %v", GetRemoteAddress(req), req.Method, hash, replicas, kc.Want_replicas, err.Error()) } }
func (this GetBlockHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { kc := *this.KeepClient hash := mux.Vars(req)["hash"] hints := mux.Vars(req)["hints"] locator := keepclient.MakeLocator2(hash, hints) log.Printf("%s: %s %s", GetRemoteAddress(req), req.Method, hash) var pass bool var tok string if pass, tok = CheckAuthorizationHeader(kc, this.ApiTokenCache, req); !pass { http.Error(resp, "Missing or invalid Authorization header", http.StatusForbidden) return } // Copy ArvadosClient struct and use the client's API token arvclient := *kc.Arvados arvclient.ApiToken = tok kc.Arvados = &arvclient var reader io.ReadCloser var err error var blocklen int64 if req.Method == "GET" { reader, blocklen, _, err = kc.AuthorizedGet(hash, locator.Signature, locator.Timestamp) defer reader.Close() } else if req.Method == "HEAD" { blocklen, _, err = kc.AuthorizedAsk(hash, locator.Signature, locator.Timestamp) } if blocklen > 0 { resp.Header().Set("Content-Length", fmt.Sprint(blocklen)) } switch err { case nil: if reader != nil { n, err2 := io.Copy(resp, reader) if n != blocklen { log.Printf("%s: %s %s mismatched return %v with Content-Length %v error %v", GetRemoteAddress(req), req.Method, hash, n, blocklen, err2) } else if err2 == nil { log.Printf("%s: %s %s success returned %v bytes", GetRemoteAddress(req), req.Method, hash, n) } else { log.Printf("%s: %s %s returned %v bytes error %v", GetRemoteAddress(req), req.Method, hash, n, err.Error()) } } else { log.Printf("%s: %s %s success", GetRemoteAddress(req), req.Method, hash) } case keepclient.BlockNotFound: http.Error(resp, "Not found", http.StatusNotFound) default: http.Error(resp, err.Error(), http.StatusBadGateway) } if err != nil { log.Printf("%s: %s %s error %s", GetRemoteAddress(req), req.Method, hash, err.Error()) } }