How can I get only response headers in an em_http_request?
I tried to use this code:
EventMachine.run do
http = EventMachine::HttpRequest.new('my_url').get
http.headers do |headers|
Fiber.current.resume headers
end
end
but I don't want to receive the whole body. How I can stop the request's execution?
http.close doesn't work.
UPD
http.instance_variable_get(:'#conn').close helps me, but may be you know more interesting solution
If you don't want the body, you should do a HEAD request instead of a GET. To terminate the event loop you need to explicitly call EventMachine.stop.
EventMachine.run do
http = EventMachine::HttpRequest.new('my_url').head
http.headers do |headers|
# do something with headers
EventMachine.stop
end
end
Related
I have a Rack web server app to validate in call(env) the provided HTTP query string and return different responses immediately (with appropriate erb) if those bits of validations fail.
I'm calling the following method to provide a response:
def respond(http_status, http_headers, html_body = '')
# Provide HTTP response
html_body = yield if block_given?
[http_status, http_headers, [html_body]]
end
which I gleaned from the web.
I'm then calling respond(...) from different points inside my call(env) method rather like this:
def call(env)
case blah
when '/'
if validation_a_fails
respond(invalid_a)
else
set up a variable for later use...
end
if validation_b_fails
respond(invalid_b)
else
set up another variable for later use...
end
if validation_c_fails
respond(invalid_c)
else
set up something else for later use...
end
else # not root url
respond(404_situation)
end
end
end
I expected that a call to respond(invalid_a) would exit the call method immediately. However, it doesn't. Instead, the rest of the call method are executed.
How can I get the respond(...) to return immediately to the calling browser?
if validation_a_fails
return respond(invalid_a)
else
in your case you can't omit return because you have multiple if-elses so it'd go through them.
I'm using Grape. I want to define a method that runs after the response value has been calculated for a request, I tried following this:
http://www.sinatrarb.com/intro.html#Filters
and ended up with:
after do
puts response
end
however response is not defined. Apparently within this block, self refers to Grape::Endpoint, since after runs after the endpoint handler, I should be able to find the response value, right? I tried self.body however this returns nothing - it does, however, let me change the value of the response, but I want to retrieve the response value that was generated by my handler.
Ahh, so I solved this using rack middleware:
class CaptureResponse < Grape::Middleware::Base
def call!(env)
#env = env
#app_response = #app.call(#env)
body = #app_response[2]
body = body.body if body.kind_of? Rack::BodyProxy
puts body
#app_response
end
end
use CaptureResponse
I have no idea why just slapping in use CaptureResponse in config.ru works but it does!
Hi I have been going through the documentation on Thin and I am reasonably new to eventmachine but I am aware of how Deferrables work. My goal is to understand how Thin works when the body is deferred and streamed part by part.
The following is the example that I'm working with and trying to get my head around.
class DeferrableBody
include EventMachine::Deferrable
def call(body)
body.each do |chunk|
#body_callback.call(chunk)
end
# #body_callback.call()
end
def each &blk
#body_callback = blk
end
end
class AsyncApp
# This is a template async response. N.B. Can't use string for body on 1.9
AsyncResponse = [-1, {}, []].freeze
puts "Aysnc testing #{AsyncResponse.inspect}"
def call(env)
body = DeferrableBody.new
# Get the headers out there asap, let the client know we're alive...
EventMachine::next_tick do
puts "Next tick running....."
env['async.callback'].call [200, {'Content-Type' => 'text/plain'}, body]
end
# Semi-emulate a long db request, instead of a timer, in reality we'd be
# waiting for the response data. Whilst this happens, other connections
# can be serviced.
# This could be any callback based thing though, a deferrable waiting on
# IO data, a db request, an http request, an smtp send, whatever.
EventMachine::add_timer(2) do
puts "Timer started.."
body.call ["Woah, async!\n"]
EventMachine::add_timer(5) {
# This could actually happen any time, you could spawn off to new
# threads, pause as a good looking lady walks by, whatever.
# Just shows off how we can defer chunks of data in the body, you can
# even call this many times.
body.call ["Cheers then!"]
puts "Succeed Called."
body.succeed
}
end
# throw :async # Still works for supporting non-async frameworks...
puts "Async REsponse sent."
AsyncResponse # May end up in Rack :-)
end
end
# The additions to env for async.connection and async.callback absolutely
# destroy the speed of the request if Lint is doing it's checks on env.
# It is also important to note that an async response will not pass through
# any further middleware, as the async response notification has been passed
# right up to the webserver, and the callback goes directly there too.
# Middleware could possibly catch :async, and also provide a different
# async.connection and async.callback.
# use Rack::Lint
run AsyncApp.new
The part which I don't clearly understand is what happens within the DeferrableBody class in the call and the each methods.
I get that the each receives chunks of data once the timer fires as blocks stored in #body_callback and when succeed is called on the body it sends the body but when is yield or call called on those blocks how does it become a single message when sent.
I feel I don't understand closures enough to understand whats happening. Would appreciate any help on this.
Thank you.
Ok I think I figured out how the each blocks works.
Thin on post_init seems to be generating a #request and #response object when the connection comes in. The response object needs to respond to an each method. This is the method we override.
The env['async.callback'] is a closure that is assigned to a method called post_process in the connection.rb class method where the data is actually sent to connection which looks like this
#response.each do |chunk|
trace { chunk }
puts "-- [THIN] sending data #{chunk} ---"
send_data chunk
end
How the response object's each is defined
def each
yield head
if #body.is_a?(String)
yield #body
else
#body.each { |chunk| yield chunk }
end
end
So our env['async.callback'] is basically a method called post_process defined in the connection.rb class accessed via method(:post_process) allowing our method to be handled like a closure, which contains access to the #response object. When the reactor starts it first sends the header data in the next_tick where it yields the head, but the body is empty at this point so nothing gets yielded.
After this our each method overrides the old implementation owned by the #response object so when the add_timers fire the post_process which gets triggered sends the data that we supply using the body.call(["Wooah..."]) to the browser (or wherever)
Completely in awe of macournoyer and the team committing to thin. Please correct my understanding if you feel this is not how it works.
I'm using the Savon gem to make a SOAP request using code similar to what's below. It's working, but I would like to view/capture the request XML without actually making a call to their server. I can view it now after a request is made by sticking a debugger line after the request and inspecting the client variable.
Does anyone know of a way to view the request XML without actually making a request? I want to be able to validate the XML against a schema using Cucumber or Rspec.
client = Savon::Client.new do |wsdl, http|
wsdl.document = "http://fakesite.org/fake.asmx?wsdl"
end
client.request(:testpostdata, :xmlns => "http://fakesite.org/") do
soap.header = { :cAuthentication => {"UserName" => "MyName", "Password" => "MyPassword" } }
soap.body = { :xml_data => to_xml }
end
Using Savon 2 I do it this way, write a method that return the request body from the client.
client = Savon::Client.new(....)
this is not mentioned in the documentation
def get_request
# list of operations can be found using client.operations
ops = client.operation(:action_name_here)
# build the body of the xml inside the message here
ops.build(message: { id: 42, name: "Test User", age: 20 }).to_s
end
You can directly via the Savon::Client#build_request method.
Example:
request = client.build_request(:some_operation, some_payload)
request.body # Get the request body
request.headers # Get the request headers
Take a peak # https://github.com/savonrb/savon/blob/master/lib/savon/request.rb for the full doc.
I am using Savon 2.11 and I can accomplish it with globals in the client:
def client
#client ||= Savon.client(soap_version: 2,
wsdl: config.wsdl,
logger: Rails.logger,
log: true)
end
More info on the globals here.
Then the logger spits out the host, the http verb and the complete xml ("headers" and body) for both request and response.
While I'm sure there's a better way to do this, I just overrode response.
class Savon::SOAP::Request
def response
pp self.request.headers
puts
puts self.request.body
exit
end
end
They've updated the API since the last post. Set this setting in Savon.client: :pretty_print_xml => true. After your call, search the logs for SOAP request:. The output is put to stdout. Check the console console history if you're testing your connection from the console.
Savon uses HTTPI to execute SOAP requests. HTTPI is a common interface on top of various Ruby HTTP clients. You could probably mock/stub the HTTP request executed by Savon via:
HTTPI.expects(:post).with do |http|
SchemaValidation.validate(:get_user, http.body)
end
Please note that I used Mocha for mocking the SOAP request, getting the HTTP body and validating it against some validation method (pseudo-code).
Currently, Savon does not support building up requests without executing them. So the only way to validate the request would be to intercept it.
If you would need Savon to support this feature, please let me know and open a ticket over at GitHub.
EDIT: There's also savon_spec, which is a little helper for basic fixture-based testing with Savon.
I had the same issue and patched Savon as follows:
module Savon
class Client
def get_request_xml operation_name, locals
Savon::Builder.new(operation_name, #wsdl, #globals, locals).pretty
end
end
end
This builds the XML and returns it as a string without sending it to the API endpoint. It doesn't accept a block argument in the same way client.call does, so it won't be able to reproduce every type of request you're making, but it meets my needs for now.
I only need to download the first few kilobytes of a file via HTTP.
I tried
require 'open-uri'
url = 'http://example.com/big-file.dat'
file = open(url)
content = file.read(limit)
But it actually downloads the full file.
This seems to work when using sockets:
require 'socket'
host = "download.thinkbroadband.com"
path = "/1GB.zip" # get 1gb sample file
request = "GET #{path} HTTP/1.0\r\n\r\n"
socket = TCPSocket.open(host,80)
socket.print(request)
# find beginning of response body
buffer = ""
while !buffer.match("\r\n\r\n") do
buffer += socket.read(1)
end
response = socket.read(100) #read first 100 bytes of body
puts response
I'm curious if there is a "ruby way".
This is an old thread, but it's still a question that seems mostly unanswered according to my research. Here's a solution I came up with by monkey-patching Net::HTTP a bit:
require 'net/http'
# provide access to the actual socket
class Net::HTTPResponse
attr_reader :socket
end
uri = URI("http://www.example.com/path/to/file")
begin
Net::HTTP.start(uri.host, uri.port) do |http|
request = Net::HTTP::Get.new(uri.request_uri)
# calling request with a block prevents body from being read
http.request(request) do |response|
# do whatever limited reading you want to do with the socket
x = response.socket.read(100);
end
end
rescue IOError
# ignore
end
The rescue catches the IOError that's thrown when you call HTTP.finish prematurely.
FYI, the socket within the HTTPResponse object isn't a true IO object (it's an internal class called BufferedIO), but it's pretty easy to monkey-patch that, too, to mimic the IO methods you need. For example, another library I was using (exifr) needed the readchar method, which was easy to add:
class Net::BufferedIO
def readchar
read(1)[0].ord
end
end
Check out "OpenURI returns two different objects". You might be able to abuse the methods in there to interrupt downloading/throw away the rest of the result after a preset limit.