Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Fix improperly configured host in generated urls #9838

Closed
wants to merge 1 commit into from

5 participants

@schneems
Collaborator

If the host in default_url_options is accidentally set with a protocol such as

host: "http://example.com"

then the generated url will have the protocol twice http://http://example.com which is not what the user intended. Likely they wanted to define a host host: "example.com" and a protocol: "http://" but did not know the convention.

This may not the most common problem, but when it happens it can go undetected for a while. I accidentally added http:// out of habit recently only to find all the links in my emails were broken after deploying a demo site to production. Rather than allow this accident go undetected, we can fix the problem in line by properly setting the protocol and host.

I was able to find this related question on stack overflow: http://stackoverflow.com/questions/5878329/rails-3-devise-how-do-i-make-the-email-confirmation-links-use-secure-https-n where the answer was highly upvoted.

This is based off of work in #7415 cc/ @pixeltrix

back port of #9794

ATP Action Mailer and Action Pack

@schneems schneems Fix improperly configured host in generated urls
If the host in `default_url_options` is accidentally set with a protocol such as 

```
host: "http://example.com"
``` 

then the generated url will have the protocol twice `http://http://example.com` which is not what the user intended. Likely they wanted to define a host `host: "example.com"` and a `protocol: "http://"` but did not know the convention.

This may not the most common problem, but when it happens it can go undetected for a while. I accidentally added `http://` out of habit recently only to find all the links in my emails were broken after deploying a demo site to production. Rather than allow this accident go undetected, we can fix the problem in line by properly setting the protocol and host.


I was able to find this related question on stack overflow: http://stackoverflow.com/questions/5878329/rails-3-devise-how-do-i-make-the-email-confirmation-links-use-secure-https-n where the answer was highly upvoted.

This is based off of work in #7415 cc/ @pixeltrix

back port of #9794

ATP Action Mailer and Action Pack
3f11317
@schneems
Collaborator

@pixeltrix would also be nice if we ignored host's with backslashes or used a more intelligent joining method like File.joins otherwise we end up with this

bar_path(host: 'example.com/')

Turns into example.com//bar

@pixeltrix
Owner

We could always chomp it:

>> "http://www.example.com/".chomp('/')
=> "http://www.example.com"
@schneems schneems referenced this pull request from a commit in schneems/rails
@schneems schneems Remove double trailing slash on url generation
Mentioned in #9838

Currently this:
```
bar_path(host: 'example.com/')
```

Turns into `example.com//bar`

Which is not correct, this PR fixes that issue.

ATP actionpack cc @pixeltrix
33b55ed
@josevalim
Owner

Ok, let me do the grumpy old man job: it is to a certain point the responsibility of the user to provide correct data. However, it is our responsibility to document and name our API as clearly as possible.

That said, :host is a very clear name. A host does not contain a schema. A host does not contain paths. I think normalizing those things is a waste of resource for the 99% of the correct cases at the cost of teaching wrong semantics to users!

So I'm :-1: on this one. :heart:

@schneems
Collaborator
@ekampp

I have had this problem as well, back when I didn't know these things. An instructive error would have been lovely, to let me know that rails made that distinction.

@knappe

I've seen this error often in various applications. In fact, I've seen it enough that I ended up doing some checks and manipulating the url mailed out to ensure both a host and protocol were specified to prevent this particular error from happening in a recent application.

:+1:

@pixeltrix
Owner

I don't think we need to backport this now that Rails 4.0 has been released.

@pixeltrix pixeltrix closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 20, 2013
  1. @schneems

    Fix improperly configured host in generated urls

    schneems authored
    If the host in `default_url_options` is accidentally set with a protocol such as 
    
    ```
    host: "http://example.com"
    ``` 
    
    then the generated url will have the protocol twice `http://http://example.com` which is not what the user intended. Likely they wanted to define a host `host: "example.com"` and a `protocol: "http://"` but did not know the convention.
    
    This may not the most common problem, but when it happens it can go undetected for a while. I accidentally added `http://` out of habit recently only to find all the links in my emails were broken after deploying a demo site to production. Rather than allow this accident go undetected, we can fix the problem in line by properly setting the protocol and host.
    
    
    I was able to find this related question on stack overflow: http://stackoverflow.com/questions/5878329/rails-3-devise-how-do-i-make-the-email-confirmation-links-use-secure-https-n where the answer was highly upvoted.
    
    This is based off of work in #7415 cc/ @pixeltrix
    
    back port of #9794
    
    ATP Action Mailer and Action Pack
This page is out of date. Refresh to see the latest.
View
8 actionpack/CHANGELOG.md
@@ -1,5 +1,13 @@
## unreleased ##
+* Allow default url options to accept host with protocol such as `http://`
+
+ config.action_mailer.default_url_options = { host: "http://mydomain.com" }
+
+ Backport #9794
+
+ *Richard Schneeman*
+
* `ActiveSupport::NumberHelper#number_to_human` returns the number unaltered when
the units hash does not contain the needed key, e.g. when the number provided is less
than the largest key proivided.
View
13 actionpack/lib/action_dispatch/http/url.rb
@@ -28,8 +28,9 @@ def url_for(options = {})
rewritten_url = ""
unless options[:only_path]
+ protocol = extract_protocol(options)
unless options[:protocol] == false
- rewritten_url << (options[:protocol] || "http")
+ rewritten_url << protocol
rewritten_url << ":" unless rewritten_url.match(%r{:|//})
end
rewritten_url << "//" unless rewritten_url.match("//")
@@ -67,6 +68,16 @@ def rewrite_authentication(options)
end
end
+ # Extracts protocol http:// or https:// from options[:host]
+ # needs to be called whether the :protocol is being used or not
+ def extract_protocol(options)
+ if options[:host] && match = options[:host].match(/(^.*:\/\/)(.*)/)
+ options[:protocol] ||= match[1]
+ options[:host] = match[2]
+ end
+ options[:protocol] || "http"
+ end
+
def host_or_subdomain_and_domain(options)
return options[:host] if !named_host?(options[:host]) || (options[:subdomain].nil? && options[:domain].nil?)
View
8 actionpack/test/dispatch/url_generation_test.rb
@@ -39,6 +39,14 @@ def app
https!
assert_equal "http://www.example.com/foo", foo_url(:protocol => "http")
end
+
+ test "extracting protocol from host when protocol not present" do
+ assert_equal "httpz://www.example.com/foo", foo_url(host: "httpz://www.example.com", protocol: nil)
+ end
+
+ test "formatting host when protocol is present" do
+ assert_equal "http://www.example.com/foo", foo_url(host: "httpz://www.example.com", protocol: "http://")
+ end
end
end
Something went wrong with that request. Please try again.