Skip to content

Commit

Permalink
HTTP::Client: check host is just a host (#7958)
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite authored Jul 11, 2019
1 parent f7c0e75 commit fa78362
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 0 deletions.
15 changes: 15 additions & 0 deletions spec/std/http/client/client_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,21 @@ module HTTP
typeof(Client.post("http://www.example.com", body: Bytes[65]))
typeof(Client.new("host").post("/", body: Bytes[65]))

describe "from String" do
it "raises when not a host" do
["http://www.example.com",
"www.example.com:8080",
"example.com/path",
"example.com?query",
"http://example.com:bad_port",
"user:pass@domain"].each do |string|
expect_raises(ArgumentError, "The string passed to create an HTTP::Client must be just a host, not #{string.inspect}") do
Client.new(string)
end
end
end
end

describe "from URI" do
it "has sane defaults" do
cl = Client.new(URI.parse("http://example.com"))
Expand Down
19 changes: 19 additions & 0 deletions src/http/client.cr
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ class HTTP::Client
# be used, else the given one. In any case the active context can be accessed through `tls`.
{% if flag?(:without_openssl) %}
def initialize(@host : String, port = nil, tls : Bool = false)
check_host_only(@host)

@tls = nil
if tls
raise "HTTP::Client TLS is disabled because `-D without_openssl` was passed at compile time"
Expand All @@ -135,6 +137,8 @@ class HTTP::Client
end
{% else %}
def initialize(@host : String, port = nil, tls : Bool | OpenSSL::SSL::Context::Client = false)
check_host_only(@host)

@tls = case tls
when true
OpenSSL::SSL::Context::Client.new
Expand All @@ -149,6 +153,21 @@ class HTTP::Client
end
{% end %}

private def check_host_only(string : String)
# When parsing a URI with just a host
# we end up with a URI with just a path
uri = URI.parse(string)
if uri.scheme || uri.host || uri.port || uri.query || uri.user || uri.password || uri.path.includes?('/')
raise_invalid_host(string)
end
rescue URI::Error
raise_invalid_host(string)
end

private def raise_invalid_host(string : String)
raise ArgumentError.new("The string passed to create an HTTP::Client must be just a host, not #{string.inspect}")
end

# Creates a new HTTP client from a URI. Parses the *host*, *port*,
# and *tls* configuration from the URI provided. Port defaults to
# 80 if not specified unless using the https protocol, which defaults
Expand Down

0 comments on commit fa78362

Please sign in to comment.