[lxc-devel] [lxd/master] allow passing in-memory buffers to a FileResponse

tych0 on Github lxc-bot at linuxcontainers.org
Thu Dec 22 17:47:10 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 361 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20161222/b2ba9646/attachment.bin>
-------------- next part --------------
From 1f2133a9cba692175d2ead6314499c81511a87cc Mon Sep 17 00:00:00 2001
From: Tycho Andersen <tycho.andersen at canonical.com>
Date: Thu, 22 Dec 2016 08:38:03 -0700
Subject: [PATCH] allow passing in-memory buffers to a FileResponse

Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
 lxd/response.go | 56 +++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 39 insertions(+), 17 deletions(-)

diff --git a/lxd/response.go b/lxd/response.go
index 1116857..ec3ea59 100644
--- a/lxd/response.go
+++ b/lxd/response.go
@@ -9,6 +9,7 @@ import (
 	"mime/multipart"
 	"net/http"
 	"os"
+	"time"
 
 	"github.com/mattn/go-sqlite3"
 
@@ -106,6 +107,7 @@ type fileResponseEntry struct {
 	identifier string
 	path       string
 	filename   string
+	buffer     []byte /* either a path or a buffer must be provided */
 }
 
 type fileResponse struct {
@@ -129,24 +131,38 @@ func (r *fileResponse) Render(w http.ResponseWriter) error {
 
 	// For a single file, return it inline
 	if len(r.files) == 1 {
-		f, err := os.Open(r.files[0].path)
-		if err != nil {
-			return err
-		}
-		defer f.Close()
+		var rs io.ReadSeeker
+		var mt time.Time
+		var sz int64
+
+		if r.files[0].path == "" {
+			rs = bytes.NewReader(r.files[0].buffer)
+			mt = time.Now()
+			sz = int64(len(r.files[0].buffer))
+		} else {
+			f, err := os.Open(r.files[0].path)
+			if err != nil {
+				return err
+			}
+			defer f.Close()
 
-		fi, err := f.Stat()
-		if err != nil {
-			return err
+			fi, err := f.Stat()
+			if err != nil {
+				return err
+			}
+
+			mt = fi.ModTime()
+			sz = fi.Size()
+			rs = f
 		}
 
 		w.Header().Set("Content-Type", "application/octet-stream")
-		w.Header().Set("Content-Length", fmt.Sprintf("%d", fi.Size()))
+		w.Header().Set("Content-Length", fmt.Sprintf("%d", sz))
 		w.Header().Set("Content-Disposition", fmt.Sprintf("inline;filename=%s", r.files[0].filename))
 
-		http.ServeContent(w, r.req, r.files[0].filename, fi.ModTime(), f)
-		if r.removeAfterServe {
-			err = os.Remove(r.files[0].path)
+		http.ServeContent(w, r.req, r.files[0].filename, mt, rs)
+		if r.files[0].path != "" && r.removeAfterServe {
+			err := os.Remove(r.files[0].path)
 			if err != nil {
 				return err
 			}
@@ -160,18 +176,24 @@ func (r *fileResponse) Render(w http.ResponseWriter) error {
 	mw := multipart.NewWriter(body)
 
 	for _, entry := range r.files {
-		fd, err := os.Open(entry.path)
-		if err != nil {
-			return err
+		var rd io.Reader
+		if entry.path != "" {
+			fd, err := os.Open(entry.path)
+			if err != nil {
+				return err
+			}
+			defer fd.Close()
+			rd = fd
+		} else {
+			rd = bytes.NewReader(entry.buffer)
 		}
-		defer fd.Close()
 
 		fw, err := mw.CreateFormFile(entry.identifier, entry.filename)
 		if err != nil {
 			return err
 		}
 
-		_, err = io.Copy(fw, fd)
+		_, err = io.Copy(fw, rd)
 		if err != nil {
 			return err
 		}


More information about the lxc-devel mailing list