I want to proxy remote files through a Sinatra application. This requires streaming an HTTP response with headers from a remote source back to the client, but I can't figure out how to set the headers of the response while using the streaming API inside the block provided by Net::HTTP#get_response
.
For example, this will not set response headers:
get '/file' do
stream do |out|
uri = URI("http://manuals.info.apple.com/en/ipad_user_guide.pdf")
Net::HTTP.get_response(uri) do |file|
headers 'Content-Type' => file.header['Content-Type']
file.read_body { |chunk| out << chunk }
end
end
end
And this results in the error: Net::HTTPOK#read_body called twice (IOError)
:
get '/file' do
response = nil
uri = URI("http://manuals.info.apple.com/en/ipad_user_guide.pdf")
Net::HTTP.get_response(uri) do |file|
headers 'Content-Type' => file.header['Content-Type']
response = stream do |out|
file.read_body { |chunk| out << chunk }
end
end
response
end
I could be wrong but after thinking a bit about this it appears to me that when setting the response headers from inside the stream
helper block, those headers don't get applied into the response because the execution of that block is actually being deferred. So, probably, the block gets evaluated and the response headers get set before it begins executing.
A possible workaround for this is issuing a HEAD request before streaming back the contents of the file.
For example:
get '/file' do
uri = URI('http://manuals.info.apple.com/en/ipad_user_guide.pdf')
# get only header data
head = Net::HTTP.start(uri.host, uri.port) do |http|
http.head(uri.request_uri)
end
# set headers accordingly (all that apply)
headers 'Content-Type' => head['Content-Type']
# stream back the contents
stream do |out|
Net::HTTP.get_response(uri) do |f|
f.read_body { |ch| out << ch }
end
end
end
It may not be ideal for your use case because of the additional request but it should be small enough to not be much of a problem (delay) and it adds the benefit that your app may be able to react if that request fails before sending back any data.
Hope it helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With