allow to set filename for send_file

if the disposition type matches "attachment", this
indicates that the recipient should prompt the user to save the response
locally, rather than process it normally
This commit is contained in:
Anton Maminov 2018-12-23 13:24:27 +02:00
parent a5d8df7382
commit 6f111ffbb0
2 changed files with 52 additions and 17 deletions

View file

@ -1,4 +1,5 @@
require "./spec_helper" require "./spec_helper"
require "./handler_spec"
describe "Macros" do describe "Macros" do
describe "#public_folder" do describe "#public_folder" do
@ -114,6 +115,17 @@ describe "Macros" do
response.headers["Content-Type"].should eq("application/octet-stream") response.headers["Content-Type"].should eq("application/octet-stream")
response.headers["Content-Length"].should eq("6") response.headers["Content-Length"].should eq("6")
end end
it "sends file with given path and given filename" do
get "/" do |env|
send_file env, "./spec/asset/hello.ecr", filename: "image.jpg"
end
request = HTTP::Request.new("GET", "/")
response = call_request_on_app(request)
response.status_code.should eq(200)
response.headers["Content-Disposition"].should eq("attachment; filename=\"image.jpg\"")
end
end end
describe "#gzip" do describe "#gzip" do

View file

@ -109,7 +109,13 @@ end
# ``` # ```
# send_file env, "./path/to/file", "image/jpeg" # send_file env, "./path/to/file", "image/jpeg"
# ``` # ```
def send_file(env : HTTP::Server::Context, path : String, mime_type : String? = nil) #
# Also you can set the filename and the disposition
#
# ```
# send_file env, "./path/to/file", filename: "image.jpg", disposition: "attachment"
# ```
def send_file(env : HTTP::Server::Context, path : String, mime_type : String? = nil, *, filename : String? = nil, disposition : String? = nil)
config = Kemal.config.serve_static config = Kemal.config.serve_static
file_path = File.expand_path(path, Dir.current) file_path = File.expand_path(path, Dir.current)
mime_type ||= Kemal::Utils.mime_type(file_path) mime_type ||= Kemal::Utils.mime_type(file_path)
@ -120,6 +126,7 @@ def send_file(env : HTTP::Server::Context, path : String, mime_type : String? =
request_headers = env.request.headers request_headers = env.request.headers
filesize = File.size(file_path) filesize = File.size(file_path)
filestat = File.info(file_path) filestat = File.info(file_path)
attachment(env, filename, disposition)
Kemal.config.static_headers.try(&.call(env.response, file_path, filestat)) Kemal.config.static_headers.try(&.call(env.response, file_path, filestat))
@ -147,6 +154,31 @@ def send_file(env : HTTP::Server::Context, path : String, mime_type : String? =
return return
end end
# Send a file with given data and default `application/octet-stream` mime_type.
#
# ```
# send_file env, data_slice
# ```
#
# Optionally you can override the mime_type
#
# ```
# send_file env, data_slice, "image/jpeg"
# ```
#
# Also you can set the filename and the disposition
#
# ```
# send_file env, data_slice, filename: "image.jpg", disposition: "attachment"
# ```
def send_file(env : HTTP::Server::Context, data : Slice(UInt8), mime_type : String? = nil, *, filename : String? = nil, disposition : String? = nil)
mime_type ||= "application/octet-stream"
env.response.content_type = mime_type
env.response.content_length = data.bytesize
attachment(env, filename, disposition)
env.response.write data
end
private def multipart(file, env : HTTP::Server::Context) private def multipart(file, env : HTTP::Server::Context)
# See http://httpwg.org/specs/rfc7233.html # See http://httpwg.org/specs/rfc7233.html
fileb = file.size fileb = file.size
@ -188,22 +220,13 @@ private def multipart(file, env : HTTP::Server::Context)
end end
end end
# Send a file with given data and default `application/octet-stream` mime_type. # Set the Content-Disposition to "attachment" with the specified filename,
# # instructing the user agents to prompt to save.
# ``` private def attachment(env : HTTP::Server::Context, filename : String? = nil, disposition : String? = nil)
# send_file env, data_slice disposition = "attachment" if disposition.nil? && filename
# ``` if disposition && filename
# env.response.headers["Content-Disposition"] = "#{disposition}; filename=\"#{File.basename(filename)}\""
# Optionally you can override the mime_type end
#
# ```
# send_file env, data_slice, "image/jpeg"
# ```
def send_file(env : HTTP::Server::Context, data : Slice(UInt8), mime_type : String? = nil)
mime_type ||= "application/octet-stream"
env.response.content_type = mime_type
env.response.content_length = data.bytesize
env.response.write data
end end
# Configures an `HTTP::Server::Response` to compress the response # Configures an `HTTP::Server::Response` to compress the response