Bypass not_found filter in Sinatra - ruby

I am trying to configure Sinatra to
Show a simple 404 string in all requests that are not found.
Send a custom 404 video file in one route, when the route fails to fulfill the request.
The minimal code to show the issue:
# somefile.txt
some content
# server.rb
require 'sinatra'
require 'sinatra/reloader'
set :bind, '0.0.0.0'
set :port, 3000
not_found do
content_type :text
"404 Not Found"
end
get '/test' do
# in reality this is a video file, not a text file.
# .. do some work here, and if failed, send 404 file ...
# this does not work, since it triggers the not_found filter above
send_file "somefile.txt", type: :text, status: 404
# this works, but with 200 instead of 404
# send_file "somefile.txt", type: :text
end
The not_found filter captures everything, even the send_file ... status: 404
To me, this seems a little like a bug in send_file, but perhaps I am wrong.
Is there a way to state "skip the not_found filter", or any other more appropriate way to achieve this?
Keep in mind, in reality, this server should return a not found video file, not a text file. I used text here just for simplicity.

That is not a bug, as documentation states,
When a Sinatra::NotFound exception is raised, or the response’s status code is 404, the not_found handler is invoked:
I suppose that you can solve problem by replacing not_found override with error handling like this:
error Sinatra::NotFound do
content_type :text
"404 Not Found"
end
This should trigger only on error, not on response code.

Related

Sinatra - Error Handling

I'm trying to make my sinatra app show a custom error page when an error is raised on the server (e.g. an IOError or ArgumentError).
Currently I'm using AJAX to load the results into a certain #results div, but if and when an error arises on the server, I would like an error page to open up on a new page.
Currently, the IOError is shown on the server and a error is seen in the console (the server responded with a status of 500 (Internal Server Error)). Other than that, nothing happens.
I think that I have to play about with the Javascript (as well as the Sinatra::Base class) but I've spent the whole of yesterday and this morning not getting anywhere.
I would be very grateful for any help. I've created an oversimplified version of my app which I have shown below...
Sinatra_app.rb
require 'sinatra/base'
require9 'sinatra'
require 'slim'
# A helper module
module GVhelpers
def create_results(name)
# raise IOError, "There's a problem..."
return "<p>The Server Says 'Hey #{name}'</p>"
end
end
class GVapp < Sinatra::Base
helpers GVhelpers
set :root, File.dirname(__FILE__)
error do
#error = env['sinatra.error']
slim :"500", :locals => {:error => error}
end
get '/' do
slim :index
end
post '/form' do
name = params[:personName]
create_results(name)
end
end
GVapp.run!
index.slim (in views folder)
script src="/jquery.min.js"
script src="/Gvapp.js"
form#sayHey action="/form" method="post"
| Name:
input type="text" name="personName"
br
input type="submit"
#output
500.slim (in views folder)
h1 Oops! Something went Wonky!
p Apologies, there was an error with your request:
strong request.env['sinatra.error'].message
p If the error persists, please contact the administrator.
Gvapp.js (in public folder)
$(document).ready(function() {
$('#sayHey').submit(function(e) {
e.preventDefault();
$.ajax({
type: 'POST',
url: '/form',
data: $('#sayHey').serialize(),
success: function(response){
$('#output').html(response);
}
})
})
})
Sinatra swallows exceptions when run in the development environment by default and shows its debugging error page instead. So, to trigger your custom error handlers, you have to either run the application inside a Rack environment other than development (probably production), or preferably, tell Sinatra to not use its default error handlers in development mode.
Consider the following, standalone Sinatra application example:
require "sinatra"
#disable :show_exceptions
get "/" do
raise RuntimeError.new("boom")
end
error RuntimeError do
"A RuntimeError occured"
end
If you run this application using the default development environment like this:
$ ruby foo.rb
Then you will get Sinatra’s default error page. If you uncomment the disable line in the example, the error handler will be triggered instead, displaying a page containing "A RuntimeError occured". Alternatively, you can, as explained, run the application in an environment other than development as only that one pre-sets the show_exception setting. You can do that by setting the RACK_ENV environment variable:
$ RACK_ENV=production ruby foo.rb
For development purposes, setting RACK_ENV to production is not the correct way of course. Use disable :show_exceptions instead. You can use a configure block as outlined in the Sinatra README to conditionally disable the setting for the development environment.
configure :development do
disable :show_exceptions
end
That behaviour is documented in Sinatra’s documentation on configuration, along with several other useful settings.

Getting random "read_nonblock': end of file reached (EOFError)" with Net::HTTP.start

When I execute the following code...
http = Net::HTTP.start('jigsaw.w3.org')
http.request_post('/css-validator/validator', ' ', 'Content-type' => "multipart/form-data")
...then I very often get the following error:
EOFError: end of file reached
from /Users/josh/.rvm/rubies/ruby-2.0.0-p353/lib/ruby/2.0.0/net/protocol.rb:153:in `read_nonblock'
Is this only me? What could be the problem? Sometimes it seems to work, but most of the time it doesn't.
The problem seems to be on the side of the host:
Loading http://jigsaw.w3.org/css-validator/DOWNLOAD.html manually in a browser results most of the time in "no data received" at the moment.
I'm trying to set up the downloadable command line version of the validator on my local machine and use this. More info here: How can I validate CSS on internal web pages?

sinatra -- unknown media type

I am writing a blog for games, loading files with extension *.sgf Sinatra doesn't recognize this.
Unknown media type: ".sgf" file: base.rb location: content_type line: 132
The backtrace mentions webrick
/usr/lib/ruby/1.9.1/webrick/httpserver.rb in service
si.service(req, res) /usr/lib/ruby/1.9.1/webrick/httpserver.rb in run
server.service(req, res) /usr/lib/ruby/1.9.1/webrick/server.rb in block in start_thread
block ? block.call(sock) : run(sock)
I caught this since although my Sinatra app works when I do ruby myApp.rb it doesn't work when I do foreman start for Heroku (and it didn't work when I deployed).
You should configure Sinatra to understand your MIME-type:
configure do
mime_type :sgf, 'application/octet-stream'
end
or inplace:
get '/upload' do
content_type :sgf
# Do what you want with the file
end
More info.

How do I get an HTTPS request with SSL client cert to work with Ruby EventMachine?

I am trying to access an HTTPS web service that uses SSL cert authentication using Ruby EventMachine but I am not getting it to work.
I have written the following simple code block to test it end-to-end:
require 'rubygems'
require 'em-http'
EventMachine.run do
url = 'https://foobar.com/'
ssl_opts = {:private_key_file => '/tmp/private.key',
:cert_chain_file => '/tmp/ca.pem',
:verify_peer => false}
http = EventMachine::HttpRequest.new(url).get :ssl => ssl_opts
http.callback do
p http.response_header.status
p http.response_header
p http.response
EventMachine.stop
end
http.errback do
EventMachine.stop
fail "Request failed"
end
end
Running the above outputs <SSL_incomp> followed by the raised RuntimeError message. I have tried running with :verify_peer set to both true and false and it gives me the same error. Running EventMachine::HttpRequest#get without the :ssl option does the same.
I have also tried sending the request to GMail (https://mail.google.com) without the :ssl option (i.e. plain HTTPS without cert) and that works, outputting status code 200, the headers and the body.
I have tried doing the same request to the web service with curl and that works:
curl --silent --cert /tmp/private.key --cacert /tmp/ca.pem https://foobar.com/
I am thinking that I am either using the em-http-request gem or EventMachine incorrectly or that the SSL files are in a format that works with curl but not EventMachine.
I someone knows how to solve the example above or provide a similar example using EventMachine directly would be much appreciated!
The file passed to curl's --cert contains both the cert and the key (unless you pass in a --key separately). Just use /tmp/private.key as the argument to both :private_key_file and :cert_chain_file
See http://github.com/eventmachine/eventmachine/issues/#issue/115 for more details about the issue and a patch that exposes the underlying error (instead of just printing out SSL_incomp).

Having trouble debugging Sinatra app in production

I'm deploying a Sinatra app using passenger. The deployed app is working, but not entirely: some paths work fine, others simply render a blank page. I can't seem to find any major differences between the routes that work and the routes that don't, and I can't seem to track down any errors..
Handlers
I have defined the not_found and error handlers as follows:
not_found do
'404. Bummer!'
end
error do
'Nasty error: ' + env['sinatra.error'].name
end
These work fine on my local machine, both in development and production, but I never see these come up on the server.
Apache Logs
When I tail Apache's access.log and hit one of the broken paths, I see a 500:
helpers [27/Oct/2009:15:54:59 -0400] "GET /admin/member_photos/photos HTTP/1.1" 500 20 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3"
rack_hoptoad
I've also installed and configured rack_hoptoad middleware in my config.ru, but no exceptions are making it to hoptoad.
# Send exceptions to hoptoad
require 'rack_hoptoad'
use Rack::HoptoadNotifier, 'MY_API_KEY'
logging
I've set up logging like so..
set :raise_errors => true
set :logging, true
log = File.new("log/sinatra.log", "a+")
STDOUT.reopen(log)
STDERR.reopen(log)
require 'logger'
configure do
LOGGER = Logger.new("log/sinatra.log")
end
helpers do
def logger
LOGGER
end
end
This setup lets me call logger.info within my routes, which works locally and on the server for the working routes, but the broken paths don't get far enough to call logger.info.
What to do?
Any ideas as to how I can see what's causing the 500 errors? Thanks for any help!
I would try using the Rack::ShowExceptions middleware to try and trace out the problem. In your config.ru add these two lines before the run call:
require 'rubygems'
require 'your-app'
use Rack::ShowExceptions
run YourApp
That should catch and display the backtrace for any exceptions occurring in Rack or in your app. That should give you more details to work with, at least that would be the hope.
Maybe there's something wrong with your log setup?
Redirect STDERR when running the Sinatra server so you can read it. Like:
ruby myapp.rb -p 1234 > log/app.log 2>&1
Thanks for the responses, but I didn't end up needing to use them. I was originally deploying the app in a sub-URI configuration. When I deployed the app to it's own subdomain instead, the problems went away.
So.. I'm not really sure what the problem was, but getting rid of this line is my Apache configuration for the site is what resolved things:
Redirect permanent / https://www.example.org/admin/member_photos/

Resources