15 image "bpa-restapi-agent/internal/app"
17 "github.com/gorilla/mux"
20 // imageHandler is used to store backend implementations objects
21 // Also simplifies mocking for unit testing purposes
22 type imageHandler struct {
23 // Interface that implements Image operations
24 // We will set this variable with a mock interface for testing
25 client image.ImageManager
29 // CreateHandler handles creation of the image entry in the database
31 func (h imageHandler) createHandler(w http.ResponseWriter, r *http.Request) {
34 // Implemenation using multipart form
35 // Review and enable/remove at a later date
36 // Set Max size to 16mb here
37 err := r.ParseMultipartForm(16777216)
39 http.Error(w, err.Error(), http.StatusUnprocessableEntity)
43 jsn := bytes.NewBuffer([]byte(r.FormValue("metadata")))
44 err = json.NewDecoder(jsn).Decode(&v)
47 http.Error(w, "Empty body", http.StatusBadRequest)
50 http.Error(w, err.Error(), http.StatusUnprocessableEntity)
55 if v.ImageName == "" {
56 http.Error(w, "Missing name in POST request", http.StatusBadRequest)
62 http.Error(w, "Missing Owner in POST request", http.StatusBadRequest)
66 if v.ImageLength == 0 {
67 e := "Improper upload length"
68 w.WriteHeader(http.StatusBadRequest)
73 //Read the file section and ignore the header
74 file, _, err := r.FormFile("file")
76 http.Error(w, "Unable to process file", http.StatusUnprocessableEntity)
83 ret, err := h.client.Create(v)
85 http.Error(w, err.Error(), http.StatusInternalServerError)
89 w.Header().Set("Content-Type", "application/json")
90 w.WriteHeader(http.StatusCreated)
91 err = json.NewEncoder(w).Encode(ret)
93 http.Error(w, err.Error(), http.StatusInternalServerError)
99 // getHandler handles GET operations on a particular name
101 func (h imageHandler) getHandler(w http.ResponseWriter, r *http.Request) {
103 imageName := vars["imgname"]
105 ret, err := h.client.Get(imageName)
107 http.Error(w, err.Error(), http.StatusInternalServerError)
111 w.Header().Set("Content-Type", "application/json")
112 w.WriteHeader(http.StatusOK)
113 err = json.NewEncoder(w).Encode(ret)
115 http.Error(w, err.Error(), http.StatusInternalServerError)
120 // deleteHandler handles DELETE operations on a particular record
121 func (h imageHandler) deleteHandler(w http.ResponseWriter, r *http.Request) {
123 imageName := vars["imgname"]
125 err := h.client.Delete(imageName)
127 http.Error(w, err.Error(), http.StatusInternalServerError)
131 w.WriteHeader(http.StatusNoContent)
134 // UpdateHandler handles Update operations on a particular image
135 func (h imageHandler) updateHandler(w http.ResponseWriter, r *http.Request) {
138 imageName := vars["imgname"]
140 err := r.ParseMultipartForm(16777216)
142 http.Error(w, err.Error(), http.StatusUnprocessableEntity)
146 jsn := bytes.NewBuffer([]byte(r.FormValue("metadata")))
147 err = json.NewDecoder(jsn).Decode(&v)
150 http.Error(w, "Empty body", http.StatusBadRequest)
153 http.Error(w, err.Error(), http.StatusUnprocessableEntity)
158 if v.ImageName == "" {
159 http.Error(w, "Missing name in PUT request", http.StatusBadRequest)
163 // Owner is required.
165 http.Error(w, "Missing Owner in PUT request", http.StatusBadRequest)
169 //Read the file section and ignore the header
170 file, _, err := r.FormFile("file")
172 http.Error(w, "Unable to process file", http.StatusUnprocessableEntity)
178 ret, err := h.client.Update(imageName, v)
180 http.Error(w, err.Error(), http.StatusInternalServerError)
184 w.Header().Set("Content-Type", "application/json")
185 w.WriteHeader(http.StatusCreated)
186 err = json.NewEncoder(w).Encode(ret)
188 http.Error(w, err.Error(), http.StatusInternalServerError)
193 // File upload is handled by the patchHandler
195 func (h imageHandler) patchHandler(w http.ResponseWriter, r *http.Request) {
196 log.Println("going to patch file")
198 imageName := vars["imgname"]
199 file, err := h.client.Get(imageName)
201 http.Error(w, err.Error(), http.StatusInternalServerError)
204 if *file.UploadComplete == true {
205 e := "Upload already completed"
206 w.WriteHeader(http.StatusUnprocessableEntity)
210 off, err := strconv.Atoi(r.Header.Get("Upload-Offset"))
212 log.Println("Improper upload offset", err)
213 w.WriteHeader(http.StatusBadRequest)
216 log.Printf("Upload offset %d\n", off)
217 if *file.ImageOffset != off {
218 e := fmt.Sprintf("Expected Offset %d got offset %d", *file.ImageOffset, off)
219 w.WriteHeader(http.StatusConflict)
224 log.Println("Content length is", r.Header.Get("Content-Length"))
225 clh := r.Header.Get("Content-Length")
226 cl, err := strconv.Atoi(clh)
228 log.Println("unknown content length")
229 w.WriteHeader(http.StatusInternalServerError)
233 if cl != (file.ImageLength - *file.ImageOffset) {
234 e := fmt.Sprintf("Content length doesn't match upload length. Expected content length %d got %d", file.ImageLength-*file.ImageOffset, cl)
236 w.WriteHeader(http.StatusBadRequest)
241 body, err := ioutil.ReadAll(r.Body)
243 log.Printf("Received file partially %s\n", err)
244 log.Println("Size of received file ", len(body))
247 fp, _, err := h.client.GetDirPath(imageName)
249 log.Printf("unable to get file path %s\n", err)
250 w.WriteHeader(http.StatusInternalServerError)
253 f, err := os.OpenFile(fp, os.O_APPEND|os.O_WRONLY, 0644)
255 log.Printf("unable to open file %s\n", err)
256 w.WriteHeader(http.StatusInternalServerError)
261 n, err := f.WriteAt(body, int64(off))
263 log.Printf("unable to write %s", err)
264 w.WriteHeader(http.StatusInternalServerError)
267 log.Println("number of bytes written ", n)
268 no := *file.ImageOffset + n
269 file.ImageOffset = &no
271 uo := strconv.Itoa(*file.ImageOffset)
272 w.Header().Set("Upload-Offset", uo)
273 if *file.ImageOffset == file.ImageLength {
274 log.Println("upload completed successfully")
275 *file.UploadComplete = true
278 _, err = h.client.Update(imageName, file)
280 log.Println("Error while updating file", err)
281 w.WriteHeader(http.StatusInternalServerError)
284 w.WriteHeader(http.StatusNoContent)