Router file in Ruby webserver - ruby

PHP has a built in webserver (Example #3) where you can pass in a router file as an argument. Every request will go through that router file where you can do all kinds of things with the request.
php -S localhost:8000 router.php
The router file could look like this:
<?php
// router.php
if (preg_match('/\.(?:png|jpg|jpeg|gif)$/', $_SERVER["REQUEST_URI"])) {
return false; // serve the requested resource as-is.
} else {
echo "<p>Welcome to PHP</p>";
}
?>
Is that also possible with a Ruby webserver like Thin?
Thanks!

This sounds a lot like sinatra, which is a very lightweight web framework for ruby.
For example, in a ruby file (say it's called server.rb):
require 'sinatra'
get "/" do
"hello world"
end
get "/:foo" do
"you typed #{params[:foo]}"
end
and in the terminal:
ruby server.rb
# => listening on port 4567
You can test it by going to localhost:4567 in the browser.

In your case I will use rack, this is a ruby:
Rack includes handlers that connect Rack to all these web application servers (WEBrick, Mongrel etc.).
Rack includes adapters that connect Rack to various web frameworks (Sinatra, Rails etc.).
Between the server and the framework, Rack can be customized to your applications needs using middleware.
In order to use rack you must create rack application:
must answer call method.
The call mehtod is called by the server and must recevive an env variable with the CGI information.
Must return an array with 3 elements:
a) status: integer
b) headers: hash
c) body: An object that responds to each and for every call to each retuns a String.
The fundamental idea behind Rack middleware is – come between the calling client and the server, process the HTTP request before sending it to the server, and processing the HTTP response before returning it to the client.
this is the basic, answer of your question:
test_rack.rb
class MyApp
def call env
[200, {"Content-Type" => "text/html"}, ["Hello Rack Participants"]]
end
end
config.ru
require './test_rack.rb'
run MyApp.new
then start up the application, and make a call to localhost:9292/anything
╭─toni#Antonios-MBP ~/learn/ruby/stackoverflow/scripting ‹ruby-2.2.3#stackoverflow› ‹1.7› ‹SBCL 1.3.5›
╰─$ rackup config.ru
[2016-05-08 11:17:41] INFO WEBrick 1.3.1
[2016-05-08 11:17:41] INFO ruby 2.2.3 (2015-08-18) [x86_64-darwin15]
[2016-05-08 11:17:41] INFO WEBrick::HTTPServer#start: pid=2610 port=9292
::1 - - [08/May/2016:11:18:04 +0200] "GET /patata HTTP/1.1" 200 - 0.0010
::1 - - [08/May/2016:11:18:04 +0200] "GET /favicon.ico HTTP/1.1" 200 - 0.0005
::1 - - [08/May/2016:11:18:09 +0200] "GET /patata/calimero HTTP/1.1" 200 - 0.0003
let's see rack working in console, see the multiple webservers and pass lambda for create the call function
require 'rack'
=> true
irb(main):010:0> Rack::Handler::constants
=> [:CGI, :FastCGI, :Mongrel, :EventedMongrel, :SwiftipliedMongrel, :WEBrick, :LSWS, :SCGI, :Thin]
irb(main):026:0> Rack::Handler::WEBrick.run lambda { |env| [200,{"Content-Type" => "text/plain"}, ["Hello. The time is #{Time.now}"]] }
[2016-05-08 11:22:39] INFO WEBrick 1.3.1
[2016-05-08 11:22:39] INFO ruby 2.2.3 (2015-08-18) [x86_64-darwin15]
[2016-05-08 11:22:39] INFO WEBrick::HTTPServer#start: pid=1798 port=8080
to go further:
https://blog.engineyard.com/2015/understanding-rack-apps-and-middleware
https://github.com/rack/rack

Related

route giving 404 in sinatra

I have just started working on sinatra, now my application is not able to navigate upto route and get data from db, I am always getting 404. This is what I am doing.
File Structure
app
|---->helpers
|----->models
|----->public
|----->routes
| |------->candidate.rb
| |------->init.rb
|----->app.rb
|----->config.ru
config.ru
require './app'
run MyApp
app.rb
require 'json'
require 'sinatra'
require 'data_mapper'
require 'dm-migrations'
require 'sinatra/cross_origin'
require 'logger'
require './models/init'
require './helpers/init'
require './routes/init'
class MyApp < Sinatra::Base
configure :development do
enable :cross_origin
DataMapper::Logger.new($stdout, :debug)
DataMapper.setup(
:default,
'mysql://root:#localhost/hackerrank'
)
end
get '/' do
File.read(File.join('public', 'index.html'))
end
DataMapper.finalize
end
Command
bundle exec rackup -p 4567 config.ru
api in candidate.rb are correct but if i try to access the resource as http://localhost:4567/#/recruiter I am getting 404 .
I am not able to figure out what is wrong I am doing here.
You're getting a 404, since GET '/' only works for the root page and you're trying to load /recruiter. You can change it to GET '/:pagename' and that would fix the 404 problem instantly.
Your codebase looks fine. When you're running your Sinatra app from the terminal, each request shows a log line such as
127.0.0.1 - - [02/Jan/2016 00:43:53] "GET / HTTP/1.1" 200 - 0.0033
Ensure that the HTTP verb and or endpoint/route you see is the one you are expecting (perhaps you are making a POST request when accessing the resource?)

Sinatra logging outside request

I believe I'm missing something with the way Sinatra does logging. I'd like to define a custom logger but also use it outside Sinatra's routes.
My app.rb looks like this:
require 'sinatra'
require 'logger'
logger = Logger.new(STDOUT)
configure do
use Rack::CommonLogger, logger
end
get '/' do
logger.info 'In request'
'Hello, world!'
end
logger.info 'Outside request'
The config.ru like so:
require 'sinatra'
require_relative 'app'
configure do
enable :logging
end
run Sinatra::Application
But when I run the application and curl the URL, I only see the log out during the request, not logger.info 'Outside request' when the application loads.
$ bundle exec rackup
I, [2015-06-22T23:09:32.789802 #6122] INFO -- : Outside request
[2015-06-22 23:09:32] INFO WEBrick 1.3.1
[2015-06-22 23:09:32] INFO ruby 2.1.4 (2014-10-27) [x86_64-linux]
[2015-06-22 23:09:32] INFO WEBrick::HTTPServer#start: pid=6122 port=9292
::1 - - [22/Jun/2015:23:09:48 -0400] "GET / HTTP/1.1" 200 13 0.0059
::1 - - [22/Jun/2015:23:09:48 -0400] "GET / HTTP/1.1" 200 13 0.0124
Hello, world!%
I know I'm missing something fundamental here, any help would be appreciated. Thank you.

Why don't instance variables persist between routes in Sinatra?

I know different ways to make data persist between routes in Sinatra. I'm just trying to understand this more in a Ruby/Object-Oriented way.
My guess is: whenever you rackup a Sinatra app, you're instantiating a Sinatra::Application object. Is it that every time you call a get/post route method, you're creating a new Sinatra::Application so the instance variables will be different?
You're correct. Every time you open a new route, a new instance of your rack/sinatra app is re-instantiated.
You can check this out in a very simple way:
require 'sinatra/base'
class MyApp < Sinatra::Application
get '/' do
puts self.object_id
'Hello world!'
end
end
The output i get from this when opening the browser twice at "localhost:9292" is:
Thin web server (v1.6.2 codename Doc Brown)
Maximum connections set to 1024
Listening on 0.0.0.0:9292, CTRL+C to stop
70308503790680
127.0.0.1 - - [21/Jun/2014 16:10:21] "GET / HTTP/1.1" 200 12 0.0129
70308504166760
127.0.0.1 - - [21/Jun/2014 16:10:22] "GET / HTTP/1.1" 200 12 0.0016
Focus on the fourth and sixth line: you can see that the instances have different ids.
If you just output self, you can see that it's an instance of the MyApp class:
#<MyApp:0x007fbfea3a87c8>
127.0.0.1 - - [21/Jun/2014 16:19:54] "GET / HTTP/1.1" 200 12 0.0124
#<MyApp:0x007fbfea460198>

Ruby, Sinatra , omniauth-github Authentication Failure Callback Error

ok it has been over 5 hours and I am still getting no where. What I am trying to do is setup omniauth-gihub gem in one of my Ruby-Sinatra based applications. Following is What I have done yet.
Added the Gems to the Gemfile (& Ran bundler update command ofcourse):
source 'https://rubygems.org'
gem 'sinatra'
gem 'haml'
gem 'shotgun'
gem 'omniauth', :git => 'git://github.com/intridea/omniauth.git'
gem 'omniauth-github', :git => 'git://github.com/intridea/omniauth-github.git'
Under my app.rb file I have the following code:
#imports
require 'rubygems'
require 'bundler'
require 'sinatra'
require 'omniauth'
require 'omniauth-github'
require 'haml'
require './helpers.rb'
#Configure OmniAuth
use OmniAuth::Builder do
provider :github, ENV['api_key'], ENV['secret'], # Removing the key and secret for security reasons
scope: "user,repo,gist"
end
#Application Settings
set :sessions, true
set :views, 'templates'
#Get Method for Application Root
get '/' do
haml :index
end
#Get/Post Methods For Authentication
%w(get post).each do |method|
send(method, "/auth/:provider/callback") do
env['omniauth.auth']
end
end
The Github application's settings are as follows:
URL = http://127.0.0.1:4567
Callback URL = http://127.0.0.1:4567/auth/github/callback
Now whenever I visit 127.0.0.1:4567/auth/github/callback I get the following error:
I, [2012-07-26T07:05:23.540462 #30458] INFO -- omniauth: (github) Callback phase initiated.
E, [2012-07-26T07:05:23.540700 #30458] ERROR -- omniauth: (github) Authentication failure! invalid_credentials: OmniAuth::Strategies::OAuth2::CallbackError, OmniAuth::Strategies::OAuth2::CallbackError
localhost - - [26/Jul/2012:07:05:23 IST] "GET /auth/github/callback HTTP/1.1" 302 9
- -> /auth/github/callback
localhost - - [26/Jul/2012:07:05:23 IST] "GET /auth/failure?message=invalid_credentials&strategy=github HTTP/1.1" 404 448
- -> /auth/failure?message=invalid_credentials&strategy=github
localhost - - [26/Jul/2012:07:05:23 IST] "GET /favicon.ico HTTP/1.1" 404 447
- -> /favicon.ico
it seems it's not even trying to connect to github, I thought I was already logged in so I logged out of github and try visiting 127.0.0.4567/auth/github/callback again and yes it is not even connecting or sending any information to github.
I have check my api key and the secret and they are correct. I can't really figure out what am I missing and am really tired. Any help or suggestion will be much appreciated.
EDIT::
Okay I found that the code raising the error is as follows in oauth2.rb
def callback_phase
if request.params['error'] || request.params['error_reason']
raise CallbackError.new(request.params['error'], request.params['error_description'] || request.params['error_reason'], request.params['error_uri'])
end
if request.params['state'].to_s.empty? || request.params['state'] != session.delete('omniauth.state')
raise CallbackError.new(nil, :csrf_detected)
end
I feel it is something to do with CSRF.
This might be of interest:
https://github.com/intridea/omniauth-github/issues/12
I was getting the same error as you, and adding scope: 'user' fixed it for me.
I see you're already using scope, but the link might put you on the right track.
Had the same issue - downgrading omniauth-facebook to 1.4.0 fixed it for me. https://github.com/mkdynamic/omniauth-facebook/issues/73

Somehow WEBrick is taking over my Sinatra app launch, how to turn it off?

A while ago, I was fooling around with Node.js (I don't really remember what I did).
Now, whenever I launch Sinatra apps, I get this:
mba:sinatra chromium$ ruby basics.rb
[2011-12-16 18:38:23] INFO WEBrick 1.3.1
[2011-12-16 18:38:23] INFO ruby 1.9.2 (2011-07-09) [x86_64-darwin11.0.1]
== Sinatra/1.3.1 has taken the stage on 4567 for development with backup from WEBrick
[2011-12-16 18:38:23] INFO WEBrick::HTTPServer#start: pid=5708 port=4567
127.0.0.1 - - [16/Dec/2011 18:38:51] "GET / HTTP/1.1" 200 13 0.0072
localhost - - [16/Dec/2011:18:38:51 EST] "GET / HTTP/1.1" 200 13
- -> /
And for each HTTP request, WEBrick logs like 5 more lines.
How do I turn this off? I have no idea why this is happening, because I was doing this with Node.js, not WEBrick.
The line ruby basics.rb means that you are running Sinatra with Ruby, not Node.js.
If you want your Sinatra application launch a simple CGI daemon, not a complete HTTP server, you should use Sinatra::Base, not the normal Sinatra infrastructure. Applications based on Sinatra::Base do not launch WEBRick or any other server at startup and rely on an external HTTP server.
Have a look at the introduction to Sinatra::Base.
That is the normal logging output Sinatra creates.
Check the Readme if you want to turn logging off: https://github.com/sinatra/sinatra

Resources