Invoking halt in sinatra does not set sinatra.error - sinatra

My use case is that I would like to do error handling in sinatra. For this I am setting up the error handler as follows
error 0..600 do
##logger.error("error reason #{env['sinatra.error']}")
end
The sinatra.error variable gets set fine if the error was caused by explicitly raising an exception
get '/' do
raise "Fail the request"
end
But if halt is used to terminate the request then sinatra.error does not get set. Looking into sinatra code this appears to be as expected because throwing :halt causes the control flow to go all the way up to invoke and thus bypassing the setting of sinatra.error variable.
My question is how to use the error handler along with the halt so that I can get the cause of the error in the error handler.

I think the behavior you're seeing stems from the intended purpose of halt. When you call it, you aren't necessarily signaling in error; you just want execution to stop immediately, which can be particularly useful in a filter. If you check Sinatra's README, it says that you use halt to "immediately stop a request within a filter or route use". Granted, you will usually do it because of an error.
It is also interesting to notice that the error handler you defined gets called not only when errors occur, but also when regular requests are served, including ones with status 200. And in those cases, env[sinatra.error] won't be set either.
What you can do in your error handler is to check for an exception and, if it's not available, check the response code. For example (note that this is a classical application):
error 0..600 do
boom = #env['sinatra.error']
status = response.status
case
when boom != nil
puts 'exception: ' + boom
when status != 200
puts 'error: ' + status
end
end
One consequence is that, in this handler, normal requests are indistinguishable from those interrupted by halt, because both generate a 200 status code. However, if you are using halt to report errors, then you should be using an error code like 500 anyway.

Related

a call to query consoleText returns with HttpStatus 100 - how to deal with that?

I am working on a program than launches Jenkins jobs using the REST API. After the job has completed, I'd like to get its log, so I call http://jenkins.domain.com/job/my_job_name/#/consoleText in my code.
In 75% of the cases that works and I get the text in return. But there a some cases where it comes back with HttpStatus 100 and no text. (Opening the URL with the browser then shows the text, so clearly there is something to return.) (I haven't found any pattern that would explain it, like "exceptionally large log" or so.)
I found no documentation about calls returning 100 and have no idea how to proceed. Simple repeating the call gives the same result. So how can I get the expected result?
Surprisingly "exceptionally large" was the answer. This caused a timeout (followed by some inappropriate handling) in the library that I used to handle the HttpGet. (Fortunately it was fixed very quickly.)

403 - Insufficient Permission only on accountSummaries call

I'm getting rejected only on the accountSummaries/list management call, everything else works fine - heck, it works even when executing it from the reference page! I double checked that the account being used was correct and, as I said, I have no issues performing the simple accounts/list call.
I'm using the python library, and for both of those calls no parameters are needed (so the chance of some embarrassing error are very low).
Basically I'm simply getting the service client and performing the simplest possible call:
a = client.AnalyticsManagementClient() # super simple wrapper
a._service.management().accounts().list().execute()
a._service.management().accountSummaries().list().execute()
The first call works fine, the second one returns a 403 error. Anyone have an idea why that might happen?
Full error is HttpError: <HttpError 403 when requesting https://www.googleapis.com/analytics/v3/management/accountSummaries?alt=json returned "Insufficient Permission">
It was just a scope issue: accounts needs at least one among
https://www.googleapis.com/auth/analytics
https://www.googleapis.com/auth/analytics.edit
https://www.googleapis.com/auth/analytics.readonly
while accountSummaries allows only the last two; it seems to be the only one that does not work with the analytics scope, which is the one our client was requesting.

Zend framework- how to stop execution and redirect to the error controller

I want to catch php errors so i used set_error_handler('handler_function') when i echo the error message , 'Zend_Controller_Response_Exception' with message 'Cannot send headers; headers already sent' is thrown when i used the following lines
$fc=Zend_Controller_Front::getInstance();
$fc->getResponse()->setBody($error);
an error happened 'call to setBody method of a non-object'
i tried to throw an exception from the error handler but this depend on the error occurring before bootstrapping is displayed directly after bootstrapping displayed in errorController
i used $fc->throwExceptions(false) to ensure it will send exceptions to error controller
when i do nothing in the error handler the execution is continued
what i need is to have one place to handle all errors
if there is a way to redirect to the error controller with error in params this will be good
IMO best way to handle these errors is to register error handler that will convert any error/fatal error to exception. I guess that response is not created yet. You have to use $fc's setResponse() method to create new response. I would guess that converting to exception should work in any case. Same as exceptions from Zend classes work.

Injecting a custom die() handler into mod_perl SOAP handler

We're using a $server = SOAP::Transport::HTTP::Apache->new; $server->dispatch_with(...) over here as a backend to a JS-based application. Should the underlying module die, it sends back a nice error message that gets displayed by the JS code.
The problem is, I would like more detailed messages (e.g. Carp::longmess), and a hard copy of those on STDERR.
How can I inject a custom exception handler into SOAP::Transport::HTTP::Apache with minimal code modifications?
(This is a large and old project we can't afford to rewrite, though honestly it deserves a rewrite).
UPDATE: here's a sample error message:
<soap:Body><soap:Fault>
<faultcode>soap:Server</faultcode><faultstring>Column
'allocation' cannot be null at
/usr/local/lib/perl5/site_perl/5.8.8/Tangram/Storage.pm
line 686. </faultstring></soap:Fault></soap:Body>
I get a Tangram error but this is unlikely a bug in Tangram and anyway I need a full stack-trace. OTOH, the die message got into a SOAP message which is not a normal die action so there's a handler somewhere -- which I want to customize a bit.
The error handler is located under SOAP::Transport::HTTP::Server::_output_soap_fault. Try a grep on <faultcode> in the perl INC paths.

Merb Router: how to return a 406 error

Is it possible to have the router return an error code (or an entire rack response) in response to a matched route?
E.g. I have move from WordPress to a home grown blogging solution. Search engines are hitting URLs like '/?tag=ruby' that need to return a 406 error. Instead, the router dutifully routes them to the same place as '/' I can match the URLs I want to get rid of but I don't know what to do with them
This is not obvious, but it is effective.
Solution:
match('/',:query_string=>/.+/).defer_to do |request, params|
raise Merb::ControllerExceptions::NotAcceptable,
"Query String Unknown: #{request.query_string}"
end
Explanation:
In order to trigger a 406 error we need to raise Merb::ControllerExceptions::NotAcceptable but if we do this while setting up the routes it helps exactly no one. Instead we need to wait until Merb is handling the request. this is what the defer_to block does. When the request comes in we raise the error and it is caught and handled just as it would be if we through this error from a controller.
Problems
One of the goals of my original question was to avoid having to go through all of the dispatching overhead. Instead this solution is dispatched through the exceptions controller which more computationally expensive then [406,{'content-type'=>'text/plain},['406 Not Acceptable']]