func serverHasBlob(bs blobserver.BlobStatter, br *blobref.BlobRef) (have bool, err error) { ch := make(chan blobref.SizedBlobRef, 1) go func() { err = bs.StatBlobs(ch, []*blobref.BlobRef{br}, 0) close(ch) }() for _ = range ch { have = true } return }
func handleStat(conn http.ResponseWriter, req *http.Request, storage blobserver.BlobStatter) { if w, ok := storage.(blobserver.ContextWrapper); ok { storage = w.WrapContext(req) } toStat := make([]*blobref.BlobRef, 0) switch req.Method { case "POST": fallthrough case "GET": camliVersion := req.FormValue("camliversion") if camliVersion == "" { httputil.BadRequestError(conn, "No camliversion") return } n := 0 for { n++ key := fmt.Sprintf("blob%v", n) value := req.FormValue(key) if value == "" { n-- break } if n > maxStatBlobs { httputil.BadRequestError(conn, "Too many stat blob checks") return } ref := blobref.Parse(value) if ref == nil { httputil.BadRequestError(conn, "Bogus blobref for key "+key) return } toStat = append(toStat, ref) } default: httputil.BadRequestError(conn, "Invalid method.") return } waitSeconds := 0 if waitStr := req.FormValue("maxwaitsec"); waitStr != "" { waitSeconds, _ = strconv.Atoi(waitStr) switch { case waitSeconds < 0: waitSeconds = 0 case waitSeconds > 30: // TODO: don't hard-code 30. push this up into a blobserver interface // for getting the configuration of the server (ultimately a flag in // in the binary) waitSeconds = 30 } } statRes := make([]map[string]interface{}, 0) if len(toStat) > 0 { blobch := make(chan blobref.SizedBlobRef) resultch := make(chan error, 1) go func() { err := storage.StatBlobs(blobch, toStat, time.Duration(waitSeconds)*time.Second) close(blobch) resultch <- err }() for sb := range blobch { ah := make(map[string]interface{}) ah["blobRef"] = sb.BlobRef.String() ah["size"] = sb.Size statRes = append(statRes, ah) } err := <-resultch if err != nil { log.Printf("Stat error: %v", err) conn.WriteHeader(http.StatusInternalServerError) return } } configer, _ := storage.(blobserver.Configer) ret, err := commonUploadResponse(configer, req) if err != nil { httputil.ServeError(conn, req, err) } ret["canLongPoll"] = false if configer != nil { if conf := configer.Config(); conf != nil { ret["canLongPoll"] = conf.CanLongPoll } } ret["stat"] = statRes httputil.ReturnJSON(conn, ret) }
func handleStat(conn http.ResponseWriter, req *http.Request, storage blobserver.BlobStatter) { res := new(protocol.StatResponse) if configer, ok := storage.(blobserver.Configer); ok { if conf := configer.Config(); conf != nil { res.CanLongPoll = conf.CanLongPoll } } needStat := map[blob.Ref]bool{} switch req.Method { case "POST": fallthrough case "GET", "HEAD": camliVersion := req.FormValue("camliversion") if camliVersion == "" { httputil.BadRequestError(conn, "No camliversion") return } n := 0 for { n++ key := fmt.Sprintf("blob%v", n) value := req.FormValue(key) if value == "" { n-- break } if n > maxStatBlobs { httputil.BadRequestError(conn, "Too many stat blob checks") return } ref, ok := blob.Parse(value) if !ok { httputil.BadRequestError(conn, "Bogus blobref for key "+key) return } needStat[ref] = true } default: httputil.BadRequestError(conn, "Invalid method.") return } waitSeconds := 0 if waitStr := req.FormValue("maxwaitsec"); waitStr != "" { waitSeconds, _ = strconv.Atoi(waitStr) switch { case waitSeconds < 0: waitSeconds = 0 case waitSeconds > 30: // TODO: don't hard-code 30. push this up into a blobserver interface // for getting the configuration of the server (ultimately a flag in // in the binary) waitSeconds = 30 } } deadline := time.Now().Add(time.Duration(waitSeconds) * time.Second) toStat := make([]blob.Ref, 0, len(needStat)) buildToStat := func() { toStat = toStat[:0] for br := range needStat { toStat = append(toStat, br) } } for len(needStat) > 0 { buildToStat() blobch := make(chan blob.SizedRef) resultch := make(chan error, 1) go func() { err := storage.StatBlobs(blobch, toStat) close(blobch) resultch <- err }() for sb := range blobch { res.Stat = append(res.Stat, &protocol.RefAndSize{ Ref: sb.Ref, Size: uint32(sb.Size), }) delete(needStat, sb.Ref) } err := <-resultch if err != nil { log.Printf("Stat error: %v", err) conn.WriteHeader(http.StatusInternalServerError) return } if len(needStat) == 0 || waitSeconds == 0 || time.Now().After(deadline) { break } buildToStat() blobserver.WaitForBlob(storage, deadline, toStat) } httputil.ReturnJSON(conn, res) }