From 5d5556876715bfcaee96e647ec02696f0f4d9524 Mon Sep 17 00:00:00 2001 From: Jarek Kowalski Date: Thu, 12 Dec 2019 21:18:14 -0800 Subject: [PATCH] server: added /api/v1/objects/:id that retrieves contents of object given its ID --- internal/server/api_object_get.go | 50 +++++++++++++++++++++++++++++++ internal/server/server.go | 2 +- 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 internal/server/api_object_get.go diff --git a/internal/server/api_object_get.go b/internal/server/api_object_get.go new file mode 100644 index 000000000..8dd160804 --- /dev/null +++ b/internal/server/api_object_get.go @@ -0,0 +1,50 @@ +package server + +import ( + "net/http" + "strings" + "time" + + "github.com/kopia/kopia/repo/object" +) + +func (s *Server) handleObjectGet(w http.ResponseWriter, r *http.Request) { + if r.Method != "GET" { + http.Error(w, "incompatible HTTP method", http.StatusMethodNotAllowed) + return + } + + oidstr := r.URL.Path[strings.LastIndex(r.URL.Path, "/")+1:] + + oid, err := object.ParseID(oidstr) + if err != nil { + http.Error(w, "invalid object id", http.StatusBadRequest) + return + } + + obj, err := s.rep.Objects.Open(r.Context(), oid) + if err == object.ErrObjectNotFound { + http.Error(w, "object not found", http.StatusNotFound) + return + } + + if cid, _, ok := oid.ContentID(); ok && cid.Prefix() == "k" { + w.Header().Set("Content-Type", "application/json") + } + + fname := oid.String() + if p := r.URL.Query().Get("fname"); p != "" { + fname = p + w.Header().Set("Content-Disposition", "attachment; filename=\""+p+"\"") + } + + mtime := time.Now() + + if p := r.URL.Query().Get("mtime"); p != "" { + if m, err := time.Parse(time.RFC3339Nano, p); err == nil { + mtime = m + } + } + + http.ServeContent(w, r, fname, mtime, obj) +} diff --git a/internal/server/server.go b/internal/server/server.go index 4165369a5..95d73ac78 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -41,7 +41,7 @@ func (s *Server) APIHandlers() http.Handler { mux.HandleFunc("/api/v1/sources/resume", s.handleAPI(s.handleResume, "POST")) mux.HandleFunc("/api/v1/sources/upload", s.handleAPI(s.handleUpload, "POST")) mux.HandleFunc("/api/v1/sources/cancel", s.handleAPI(s.handleCancel, "POST")) - + mux.HandleFunc("/api/v1/objects/", s.handleObjectGet) return mux }