diff --git a/context.go b/context.go index 08c420b1b8..e9735d28a0 100644 --- a/context.go +++ b/context.go @@ -6,6 +6,7 @@ package gin import ( "errors" + "fmt" "io" "io/ioutil" "math" @@ -880,6 +881,13 @@ func (c *Context) File(filepath string) { http.ServeFile(c.Writer, c.Request, filepath) } +// FileAttachment writes the specified file into the body stream in an efficient way +// On the client side, the file will typically be downloaded with the given filename +func (c *Context) FileAttachment(filepath, filename string) { + c.Writer.Header().Set("content-disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename)) + http.ServeFile(c.Writer, c.Request, filepath) +} + // SSEvent writes a Server-Sent Event into the body stream. func (c *Context) SSEvent(name string, message interface{}) { c.Render(-1, sse.Event{ diff --git a/context_test.go b/context_test.go index 483e16808f..0da5fbe64e 100644 --- a/context_test.go +++ b/context_test.go @@ -979,6 +979,19 @@ func TestContextRenderFile(t *testing.T) { assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type")) } +func TestContextRenderAttachment(t *testing.T) { + w := httptest.NewRecorder() + c, _ := CreateTestContext(w) + newFilename := "new_filename.go" + + c.Request, _ = http.NewRequest("GET", "/", nil) + c.FileAttachment("./gin.go", newFilename) + + assert.Equal(t, 200, w.Code) + assert.Contains(t, w.Body.String(), "func New() *Engine {") + assert.Equal(t, fmt.Sprintf("attachment; filename=\"%s\"", newFilename), w.HeaderMap.Get("Content-Disposition")) +} + // TestContextRenderYAML tests that the response is serialized as YAML // and Content-Type is set to application/x-yaml func TestContextRenderYAML(t *testing.T) {