Adding a querystring to rack-rewrite response - ruby

I've got a simple 301 redirect to capture all non .com domains I have registered for my site as follows:
DOMAIN = 'www.mywebsite.com'
use Rack::Rewrite do
r301 %r{.*}, "http://#{DOMAIN}$&", :if => Proc.new {|rack_env|
rack_env['SERVER_NAME'] != DOMAIN && ENV["RACK_ENV"] == 'production'
}
end
I'd like to add a querystring to the response to add the original domain in the format
?utm_source=#{rack_env['SERVER_NAME']}
But can't quite work out how not to crash the server :) Can it be done & retain any original query string?
It's unlikely that anyone will hit any subpages under the main domain, but when I drop the $& from the rewrite, and replace it with my string, it blows up with no errors in the logs...

I think the reason your original code won't work is because rack_env is not available within your second argument as it's a block argument to the third. Does that make sense?
You can however pass a Proc as the second argument of a redirect, so I think something like this should work (partially tested :)
DOMAIN = 'www.mywebsite.com'
ORIGINAL_REQUEST = Proc.new do |match, rack_env|
"#{DOMAIN}?utm_source=#{rack_env['REQUEST_URI']}"
end
use Rack::Rewrite do
r301 %r{.*}, ORIGINAL_REQUEST, :if => Proc.new {|rack_env|
rack_env['SERVER_NAME'] != DOMAIN && ENV["RACK_ENV"] == 'production'
}
end

Related

Sinatra Route returns nothing

I have a very simple example where sinatra simply returns no output.
The program enters the if clause but the block is not finished and therefore nothing is sent to rack, nothing goes to the browser... not a single character.
require 'sinatra'
get '/' do
var='confirmed'
if var == 'confirmed'
'Confirmed'
end
if var == 'declined'
'Declined'
end
end
The question is now: Is adding a "return" or "next" the way this is usually done? With it, its running... But I never found an example in the net that had to use a next statement...
So, is the "if logic" usually somewhere else and there is only a single erb :xyz at the end of a route?
I am confused...
You have the answer mostly. You always need to send something to rack to get a response.
You probably have a view to show the status on then you add at the end something like this (You can have multiple erb blocks just add for each route a erb call):
get '/' do
var='confirmed'
if var == 'confirmed'
st = 'Confirmed'
end
if var == 'declined'
st = 'Declined'
end
erb :myViewName, :locals => {:status => st}
end
Or just use return like this, if your response is just a string. Be aware that everything after this return isn't executed:
if var == 'confirmed'
return 'Confirmed'
end
It's nothing to do with the way Sinatra works, really. It's more of a Ruby matter. According to Sinatra readme:
The return value of a route block determines at least the response body passed on to the HTTP client, or at least the next middleware in the Rack stack. Most commonly, this is a string, as in the above examples. But other values are also accepted.
The problem in your code is that your last if is a statement itself. If your var variable isn't "declined", then the if block evaluates to nil, and as it is the last value in your route block, this is what gets returned by Sinatra.
When you use explicit return, you don't get to the second if and don't have this issue, which is why it works with explicit return.
You would not need an explicit return with a if/elsif block like this:
# This is one single statement that would return either confirmed or declined
# Request will always return a non-nil value
get '/' do
...
if var == 'confirmed'
'Confirmed'
elsif var == 'declined'
'Declined'
end
end
Or a case/when block:
# This is one single statement that would return either confirmed or declined
# Request will always return a non-nil value
get '/' do
...
case var
when 'confirmed' then 'Confirmed'
when 'declined' then 'Declined'
end
end

ruby sinatra how to redirect with regex

I am trying to move stuff at root to /en/ directory to make my little service multi-lingual.
So, I want to redirect this url
mysite.com/?year=2018
to
mysite.com/en/?year=2018
My code is like
get %r{^/(\?year\=\d{4})$} do |c|
redirect "/en/#{c}"
end
but it seems like I never get #{c} part from the url.
Why is that? or are there just better ways to do this?
Thanks!
You can use the request.path variable to get the information you're looking for.
For example,
get "/something" do
puts request.path # => "/something"
redirect "/en#{request.path}"
end
However if you are using query parameters (i.e. ?yeah=2000) you'll have to manually pass those off to the redirect route.
Kind of non-intuitively, there's a helper method for this in ActiveRecord.
require 'active_record'
get "/something" do
puts params.to_param
# if params[:year] is 2000, you'll get "year=2000"
redirect "/en#{request.path}?#{params.to_param}"
end
You could alternatively write your own helper method pretty easily:
def hash_to_param_string(hash)
hash.reduce("") do |string, (key, val)|
string << "#{key}=#{val}&"
end
end
puts hash_to_param_string({key1: "val1", key2: "val2"})
# => "key1=val1&key2=val2"

Sinatra URL Matching with question mark?

Is there a way to match urls with Sinatra using question mark?
get '/:id?inspect' do
# ...
end
get '/:id?last' do
# ...
end
get '/:id' do
# ...
end
I tried escaping the question mark \?, regex etc, but none of those worked.
I don't want to retrieve the value of inspect or last. I only want to know if they were supplied in the url.
Is that possible?
You can’t directly do what you want. When describing the route, Sinatra treats ? as defining an optional parameter, and doesn’t provide a way to escape it.
In a url a ? separates the path from the query string, and Sinatra only uses the path when matching routes. The contents of the query string are parsed and available in params, and the raw string is available as request.query_string.
Your url scheme seems rather unusual, but one possibility if you want to avoid checking the query_string in the actual route could be to create a custom condition to apply to the routes, and check in there:
set(:query) { |val| condition { request.query_string == val } }
get '/:id', :query => 'inspect' do
# ...
end
get '/:id', :query => 'last' do
# ...
end
get '/:id' do
# ...
end
A standard route is not defined by query parameters and should not be. Why don't you use a if construct on the params in the get /:id route?
I also suggest that when you want to set a query parameter in the request you set it like this: /:id?inspect=true (provide a dummy value)

Rails - appending query parameters to existing URL

I have an application controller method called redirect back or default which is used to redirect users to the page they were requesting after login
def redirect_back_or_default(default)
redirect_to(session[:return_to] || default)
session[:return_to] = nil
end
I would like to be able to optionally add URL parameters (for some analytics tracking) to the url, but am not sure of the best way. I'd like to change the method signature to this
def redirect_back_or_default(default, params=nil)
redirect_to(session[:return_to] || default)
session[:return_to] = nil
end
and somehow attach the params to the existing URL. Is there a standard ruby or ROR way to do this? I could obviously brute force check to see if there is a query string as part of the URL with regex and manually build the query string, but I was hoping there is an easier standard way of doing this.
From here:
To pass parameters with redirect_to
you simply add them. Like ...
redirect_to :controller => 'another', :action => 'def', :param1 => 'some', :param2 => 'thing', :param => 'else'
standart approach
def redirect_to_back_or_default(default = "/")
back = case request.env["HTTP_REFERER"]
when request.fullpath
default
when nil
default
else
:back
end
redirect_to back
end

How to check if a URL is valid

How can I check if a string is a valid URL?
For example:
http://hello.it => yes
http:||bra.ziz, => no
If this is a valid URL how can I check if this is relative to a image file?
Notice:
As pointed by #CGuess, there's a bug with this issue and it's been documented for over 9 years now that validation is not the purpose of this regular expression (see https://bugs.ruby-lang.org/issues/6520).
Use the URI module distributed with Ruby:
require 'uri'
if url =~ URI::regexp
# Correct URL
end
Like Alexander Günther said in the comments, it checks if a string contains a URL.
To check if the string is a URL, use:
url =~ /\A#{URI::regexp}\z/
If you only want to check for web URLs (http or https), use this:
url =~ /\A#{URI::regexp(['http', 'https'])}\z/
Similar to the answers above, I find using this regex to be slightly more accurate:
URI::DEFAULT_PARSER.regexp[:ABS_URI]
That will invalidate URLs with spaces, as opposed to URI.regexp which allows spaces for some reason.
I have recently found a shortcut that is provided for the different URI rgexps. You can access any of URI::DEFAULT_PARSER.regexp.keys directly from URI::#{key}.
For example, the :ABS_URI regexp can be accessed from URI::ABS_URI.
The problem with the current answers is that a URI is not an URL.
A URI can be further classified as a locator, a name, or both. The
term "Uniform Resource Locator" (URL) refers to the subset of URIs
that, in addition to identifying a resource, provide a means of
locating the resource by describing its primary access mechanism
(e.g., its network "location").
Since URLs are a subset of URIs, it is clear that matching specifically for URIs will successfully match undesired values. For example, URNs:
"urn:isbn:0451450523" =~ URI::regexp
=> 0
That being said, as far as I know, Ruby doesn't have a default way to parse URLs , so you'll most likely need a gem to do so. If you need to match URLs specifically in HTTP or HTTPS format, you could do something like this:
uri = URI.parse(my_possible_url)
if uri.kind_of?(URI::HTTP) or uri.kind_of?(URI::HTTPS)
# do your stuff
end
I prefer the Addressable gem. I have found that it handles URLs more intelligently.
require 'addressable/uri'
SCHEMES = %w(http https)
def valid_url?(url)
parsed = Addressable::URI.parse(url) or return false
SCHEMES.include?(parsed.scheme)
rescue Addressable::URI::InvalidURIError
false
end
This is a fairly old entry, but I thought I'd go ahead and contribute:
String.class_eval do
def is_valid_url?
uri = URI.parse self
uri.kind_of? URI::HTTP
rescue URI::InvalidURIError
false
end
end
Now you can do something like:
if "http://www.omg.wtf".is_valid_url?
p "huzzah!"
end
For me, I use this regular expression:
/\A(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?\z/ix
Option:
i - case insensitive
x - ignore whitespace in regex
You can set this method to check URL validation:
def valid_url?(url)
return false if url.include?("<script")
url_regexp = /\A(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?\z/ix
url =~ url_regexp ? true : false
end
To use it:
valid_url?("http://stackoverflow.com/questions/1805761/check-if-url-is-valid-ruby")
Testing with wrong URLs:
http://ruby3arabi - result is invalid
http://http://ruby3arabi.com - result is invalid
http:// - result is invalid
http://test.com\n<script src=\"nasty.js\"> (Just simply check "<script")
127.0.0.1 - not support IP address
Test with correct URLs:
http://ruby3arabi.com - result is valid
http://www.ruby3arabi.com - result is valid
https://www.ruby3arabi.com - result is valid
https://www.ruby3arabi.com/article/1 - result is valid
https://www.ruby3arabi.com/websites/58e212ff6d275e4bf9000000?locale=en - result is valid
In general,
/^#{URI::regexp}$/
will work well, but if you only want to match http or https, you can pass those in as options to the method:
/^#{URI::regexp(%w(http https))}$/
That tends to work a little better, if you want to reject protocols like ftp://.
This is a little bit old but here is how I do it. Use Ruby's URI module to parse the URL. If it can be parsed then it's a valid URL. (But that doesn't mean accessible.)
URI supports many schemes, plus you can add custom schemes yourself:
irb> uri = URI.parse "http://hello.it" rescue nil
=> #<URI::HTTP:0x10755c50 URL:http://hello.it>
irb> uri.instance_values
=> {"fragment"=>nil,
"registry"=>nil,
"scheme"=>"http",
"query"=>nil,
"port"=>80,
"path"=>"",
"host"=>"hello.it",
"password"=>nil,
"user"=>nil,
"opaque"=>nil}
irb> uri = URI.parse "http:||bra.ziz" rescue nil
=> nil
irb> uri = URI.parse "ssh://hello.it:5888" rescue nil
=> #<URI::Generic:0x105fe938 URL:ssh://hello.it:5888>
[26] pry(main)> uri.instance_values
=> {"fragment"=>nil,
"registry"=>nil,
"scheme"=>"ssh",
"query"=>nil,
"port"=>5888,
"path"=>"",
"host"=>"hello.it",
"password"=>nil,
"user"=>nil,
"opaque"=>nil}
See the documentation for more information about the URI module.
You could also use a regex, maybe something like http://www.geekzilla.co.uk/View2D3B0109-C1B2-4B4E-BFFD-E8088CBC85FD.htm assuming this regex is correct (I haven't fully checked it) the following will show the validity of the url.
url_regex = Regexp.new("((https?|ftp|file):((//)|(\\\\))+[\w\d:\##%/;$()~_?\+-=\\\\.&]*)")
urls = [
"http://hello.it",
"http:||bra.ziz"
]
urls.each { |url|
if url =~ url_regex then
puts "%s is valid" % url
else
puts "%s not valid" % url
end
}
The above example outputs:
http://hello.it is valid
http:||bra.ziz not valid

Resources