func (s *server) download(ctx context.Context, w http.ResponseWriter, r *http.Request) { log := MustFromLogContext(ctx) p := lib.MustFromContext(ctx) pp := s.getPhysicalPath(p) log.Info("physical path is %s", pp) fd, err := os.Open(pp) if err == syscall.ENOENT { log.Error(err.Error()) http.Error(w, "", http.StatusNotFound) return } if err != nil { log.Error(err) http.Error(w, "", http.StatusInternalServerError) return } log.Infof("opened %s", pp) info, err := fd.Stat() if err != nil { log.Error(err) http.Error(w, "", http.StatusInternalServerError) return } log.Infof("stated %s got size %d", pp, info.Size()) if info.IsDir() { log.Errorf("%s is a directory", pp) http.Error(w, "", http.StatusBadRequest) return } defer fd.Close() _, err = io.Copy(w, fd) if err != nil { log.Error(err) http.Error(w, "", http.StatusInternalServerError) return } log.Infof("copied %s to res.body", pp) }
func (s *server) upload(ctx context.Context, w http.ResponseWriter, r *http.Request) { log := MustFromLogContext(ctx) p := lib.MustFromContext(ctx) pp := s.getPhysicalPath(p) log.Infof("physical path is %s", pp) tmpFn, tmpFile, err := s.tmpFile() if err != nil { log.Error(err) http.Error(w, "", http.StatusInternalServerError) return } log.Infof("created tmp file %s", tmpFn) var mw io.Writer var hasher hash.Hash var isChecksumed bool var computedChecksum string switch s.p.checksum { case "md5": hasher = md5.New() isChecksumed = true mw = io.MultiWriter(tmpFile, hasher) case "sha1": hasher = sha1.New() isChecksumed = true mw = io.MultiWriter(tmpFile, hasher) case "adler32": hasher = adler32.New() isChecksumed = true mw = io.MultiWriter(tmpFile, hasher) default: mw = io.MultiWriter(tmpFile) } // TODO(labkode) Sometimes ContentLength = -1 because it is a binary // upload with TransferEncoding: chunked. // Instead using Copy we shoudl use a LimitedReader with a max file upload // configuration value. _, err = io.Copy(mw, r.Body) if err != nil { log.Error(err) http.Error(w, "", http.StatusInternalServerError) return } chk := s.getChecksumInfo(r) if isChecksumed { log.Infof("file sent with checksum %s", chk.String()) // checksums are given in hexadecimal format. computedChecksum = fmt.Sprintf("%x", string(hasher.Sum(nil))) if chk.Type == s.p.checksum && chk.Type != "" { isCorrupted := computedChecksum != chk.Sum if isCorrupted { log.Errorf("corrupted file. expected %s and got %s", s.p.checksum+":"+computedChecksum, chk.Sum) http.Error(w, "", http.StatusPreconditionFailed) return } } } log.Infof("copied r.Body into tmp file %s", tmpFn) err = tmpFile.Close() if err != nil { log.Error(err) http.Error(w, "", http.StatusInternalServerError) return } log.Infof("closed tmp file %s", tmpFn) if err = os.Rename(tmpFn, pp); err != nil { log.Error(err) http.Error(w, "", http.StatusInternalServerError) return } log.Infof("renamed tmp file %s to %s", tmpFn, pp) con, err := grpc.Dial(s.p.prop, grpc.WithInsecure()) if err != nil { log.Error(err) http.Error(w, "", http.StatusInternalServerError) return } defer con.Close() log.Infof("created connection to %s", s.p.prop) client := pb.NewPropClient(con) in := &pb.PutReq{} in.Path = p in.AccessToken = authlib.MustFromTokenContext(ctx) in.Checksum = chk.String() _, err = client.Put(ctx, in) if err != nil { log.Error(err) http.Error(w, "", http.StatusInternalServerError) return } log.Infof("saved path %s into %s", p, s.p.prop) w.WriteHeader(http.StatusCreated) }