// HTTP handler for a GET of a specific doc attachment func (h *handler) handleGetAttachment() error { docid := h.PathVar("docid") attachmentName := h.PathVar("attach") revid := h.getQuery("rev") body, err := h.db.GetRev(docid, revid, false, nil) if err != nil { return err } if body == nil { return kNotFoundError } meta, ok := db.BodyAttachments(body)[attachmentName].(map[string]interface{}) if !ok { return base.HTTPErrorf(http.StatusNotFound, "missing attachment %s", attachmentName) } digest := meta["digest"].(string) data, err := h.db.GetAttachment(db.AttachmentKey(digest)) if err != nil { return err } h.setHeader("Etag", strconv.Quote(digest)) if contentType, ok := meta["content_type"].(string); ok { h.setHeader("Content-Type", contentType) } if encoding, ok := meta["encoding"].(string); ok { h.setHeader("Content-Encoding", encoding) } if h.privs == adminPrivs { // #720 h.setHeader("Content-Disposition", fmt.Sprintf("attachment; filename=%q", attachmentName)) } h.response.Write(data) return nil }
// HTTP handler for a GET of a specific doc attachment func (h *handler) handleGetAttachment() error { docid := h.PathVar("docid") attachmentName := h.PathVar("attach") revid := h.getQuery("rev") body, err := h.db.GetRev(docid, revid, false, nil) if err != nil { return err } if body == nil { return kNotFoundError } meta, ok := db.BodyAttachments(body)[attachmentName].(map[string]interface{}) if !ok { return base.HTTPErrorf(http.StatusNotFound, "missing attachment %s", attachmentName) } digest := meta["digest"].(string) data, err := h.db.GetAttachment(db.AttachmentKey(digest)) if err != nil { return err } status, start, end := h.handleRange(uint64(len(data))) if status > 299 { return base.HTTPErrorf(status, "") } else if status == http.StatusPartialContent { data = data[start:end] } h.setHeader("Content-Length", strconv.FormatUint(uint64(len(data)), 10)) h.setHeader("Etag", strconv.Quote(digest)) if contentType, ok := meta["content_type"].(string); ok { h.setHeader("Content-Type", contentType) } if encoding, ok := meta["encoding"].(string); ok { if h.getOptBoolQuery("content_encoding", true) { h.setHeader("Content-Encoding", encoding) } else { // Couchbase Lite wants to download the encoded form directly and store it that way, // but some HTTP client libraries like NSURLConnection will automatically decompress // the HTTP response if it has a Content-Encoding header. As a workaround, allow the // client to add ?content_encoding=false to the request URL to disable setting this // header. h.setHeader("X-Content-Encoding", encoding) h.setHeader("Content-Type", "application/gzip") } } if h.privs == adminPrivs { // #720 h.setHeader("Content-Disposition", fmt.Sprintf("attachment; filename=%q", attachmentName)) } h.response.WriteHeader(status) h.response.Write(data) return nil }
// HTTP handler for a PUT of an attachment func (h *handler) handlePutAttachment() error { docid := h.PathVar("docid") attachmentName := h.PathVar("attach") attachmentContentType := h.rq.Header.Get("Content-Type") if attachmentContentType == "" { attachmentContentType = "application/octet-stream" } revid := h.getQuery("rev") if revid == "" { revid = h.rq.Header.Get("If-Match") } attachmentData, err := h.readBody() if err != nil { return err } body, err := h.db.GetRev(docid, revid, false, nil) if err != nil && base.IsDocNotFoundError(err) { // couchdb creates empty body on attachment PUT // for non-existant doc id body = db.Body{} body["_rev"] = revid } else if err != nil { return err } else if body != nil { body["_rev"] = revid } // find attachment (if it existed) attachments := db.BodyAttachments(body) if attachments == nil { attachments = make(map[string]interface{}) } // create new attachment attachment := make(map[string]interface{}) attachment["data"] = attachmentData attachment["content_type"] = attachmentContentType //attach it attachments[attachmentName] = attachment body["_attachments"] = attachments newRev, err := h.db.Put(docid, body) if err != nil { return err } h.setHeader("Etag", strconv.Quote(newRev)) h.writeJSONStatus(http.StatusCreated, db.Body{"ok": true, "id": docid, "rev": newRev}) return nil }