Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 227 additions & 0 deletions spec/std/http/client/request_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
require "spec"
require "http/client/request"

class HTTP::Client
describe Request do
it "serialize GET" do
headers = HTTP::Headers.new
headers["Host"] = "host.example.org"
orignal_headers = headers.dup
request = Request.new "GET", "/", headers

io = MemoryIO.new
request.to_io(io)
io.to_s.should eq("GET / HTTP/1.1\r\nHost: host.example.org\r\n\r\n")
headers.should eq(orignal_headers)
end

it "serialize GET (with query params)" do
headers = HTTP::Headers.new
headers["Host"] = "host.example.org"
orignal_headers = headers.dup
request = Request.new "GET", "/greet?q=hello&name=world", headers

io = MemoryIO.new
request.to_io(io)
io.to_s.should eq("GET /greet?q=hello&name=world HTTP/1.1\r\nHost: host.example.org\r\n\r\n")
headers.should eq(orignal_headers)
end

it "serialize GET (with cookie)" do
headers = HTTP::Headers.new
headers["Host"] = "host.example.org"
orignal_headers = headers.dup
request = Request.new "GET", "/", headers
request.cookies << Cookie.new("foo", "bar")

io = MemoryIO.new
request.to_io(io)
io.to_s.should eq("GET / HTTP/1.1\r\nHost: host.example.org\r\nCookie: foo=bar\r\n\r\n")
headers.should eq(orignal_headers)
end

it "serialize GET (with cookies, from headers)" do
headers = HTTP::Headers.new
headers["Host"] = "host.example.org"
headers["Cookie"] = "foo=bar"
orignal_headers = headers.dup

request = Request.new "GET", "/", headers

io = MemoryIO.new
request.to_io(io)
io.to_s.should eq("GET / HTTP/1.1\r\nHost: host.example.org\r\nCookie: foo=bar\r\n\r\n")

request.cookies["foo"].value.should eq "bar" # Force lazy initialization

io.clear
request.to_io(io)
io.to_s.should eq("GET / HTTP/1.1\r\nHost: host.example.org\r\nCookie: foo=bar\r\n\r\n")

request.cookies["foo"] = "baz"
request.cookies["quux"] = "baz"

io.clear
request.to_io(io)
io.to_s.should eq("GET / HTTP/1.1\r\nHost: host.example.org\r\nCookie: foo=baz; quux=baz\r\n\r\n")
headers.should eq(orignal_headers)
end

it "serialize POST (with body)" do
request = Request.new "POST", "/", body: "thisisthebody"
io = MemoryIO.new
request.to_io(io)
io.to_s.should eq("POST / HTTP/1.1\r\nContent-Length: 13\r\n\r\nthisisthebody")
end

describe "keep-alive" do
it "is false by default in HTTP/1.0" do
request = Request.new "GET", "/", version: "HTTP/1.0"
request.keep_alive?.should be_false
end

it "is true in HTTP/1.0 if `Connection: keep-alive` header is present" do
headers = HTTP::Headers.new
headers["Connection"] = "keep-alive"
orignal_headers = headers.dup
request = Request.new "GET", "/", headers: headers, version: "HTTP/1.0"
request.keep_alive?.should be_true
headers.should eq(orignal_headers)
end

it "is true by default in HTTP/1.1" do
request = Request.new "GET", "/", version: "HTTP/1.1"
request.keep_alive?.should be_true
end

it "is false in HTTP/1.1 if `Connection: close` header is present" do
headers = HTTP::Headers.new
headers["Connection"] = "close"
orignal_headers = headers.dup
request = Request.new "GET", "/", headers: headers, version: "HTTP/1.1"
request.keep_alive?.should be_false
headers.should eq(orignal_headers)
end
end

describe "#path" do
it "returns parsed path" do
request = Request.new("GET", "/api/v3/some/resource?filter=hello&world=test")
request.path.should eq("/api/v3/some/resource")
end

it "falls back to /" do
request = Request.new("GET", "/foo")
request.path = nil
request.path.should eq("/")
end
end

describe "#path=" do
it "sets path" do
request = Request.new("GET", "/api/v3/some/resource?filter=hello&world=test")
request.path = "/api/v2/greet"
request.path.should eq("/api/v2/greet")
end

it "updates @resource" do
request = Request.new("GET", "/api/v3/some/resource?filter=hello&world=test")
request.path = "/api/v2/greet"
request.resource.should eq("/api/v2/greet?filter=hello&world=test")
end

it "updates serialized form" do
request = Request.new("GET", "/api/v3/some/resource?filter=hello&world=test")
request.path = "/api/v2/greet"

io = MemoryIO.new
request.to_io(io)
io.to_s.should eq("GET /api/v2/greet?filter=hello&world=test HTTP/1.1\r\n\r\n")
end
end

describe "#query" do
it "returns request's query" do
request = Request.new("GET", "/api/v3/some/resource?filter=hello&world=test")
request.query.should eq("filter=hello&world=test")
end
end

describe "#query=" do
it "sets query" do
request = Request.new("GET", "/api/v3/some/resource?filter=hello&world=test")
request.query = "q=isearchforsomething&locale=de"
request.query.should eq("q=isearchforsomething&locale=de")
end

it "updates @resource" do
request = Request.new("GET", "/api/v3/some/resource?filter=hello&world=test")
request.query = "q=isearchforsomething&locale=de"
request.resource.should eq("/api/v3/some/resource?q=isearchforsomething&locale=de")
end

it "updates serialized form" do
request = Request.new("GET", "/api/v3/some/resource?filter=hello&world=test")
request.query = "q=isearchforsomething&locale=de"

io = MemoryIO.new
request.to_io(io)
io.to_s.should eq("GET /api/v3/some/resource?q=isearchforsomething&locale=de HTTP/1.1\r\n\r\n")
end
end

describe "#query_params" do
it "returns parsed HTTP::Params" do
request = Request.new("GET", "/api/v3/some/resource?foo=bar&foo=baz&baz=qux")
params = request.query_params

params["foo"].should eq("bar")
params.fetch_all("foo").should eq(["bar", "baz"])
params["baz"].should eq("qux")
end

it "happily parses when query is not a canonical url-encoded string" do
request = Request.new("GET", "/api/v3/some/resource?{\"hello\":\"world\"}")
params = request.query_params
params["{\"hello\":\"world\"}"].should eq("")
params.to_s.should eq("%7B%22hello%22%3A%22world%22%7D=")
end

it "affects #query when modified" do
request = Request.new("GET", "/api/v3/some/resource?foo=bar&foo=baz&baz=qux")
params = request.query_params

params["foo"] = "not-bar"
request.query.should eq("foo=not-bar&foo=baz&baz=qux")
end

it "updates @resource when modified" do
request = Request.new("GET", "/api/v3/some/resource?foo=bar&foo=baz&baz=qux")
params = request.query_params

params["foo"] = "not-bar"
request.resource.should eq("/api/v3/some/resource?foo=not-bar&foo=baz&baz=qux")
end

it "updates serialized form when modified" do
request = Request.new("GET", "/api/v3/some/resource?foo=bar&foo=baz&baz=qux")
params = request.query_params

params["foo"] = "not-bar"

io = MemoryIO.new
request.to_io(io)
io.to_s.should eq("GET /api/v3/some/resource?foo=not-bar&foo=baz&baz=qux HTTP/1.1\r\n\r\n")
end

it "is affected when #query is modified" do
request = Request.new("GET", "/api/v3/some/resource?foo=bar&foo=baz&baz=qux")
params = request.query_params

new_query = "foo=not-bar&foo=not-baz&not-baz=hello&name=world"
request.query = new_query
request.query_params.to_s.should eq(new_query)
end
end
end
end
6 changes: 3 additions & 3 deletions spec/std/http/server/handlers/deflate_handler_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ require "http/server"
describe HTTP::DeflateHandler do
it "doesn't deflates if doesn't have 'deflate' in Accept-Encoding header" do
io = MemoryIO.new
request = HTTP::Request.new("GET", "/")
request = HTTP::Server::Request.new("GET", "/")
response = HTTP::Server::Response.new(io)
context = HTTP::Server::Context.new(request, response)

Expand All @@ -21,7 +21,7 @@ describe HTTP::DeflateHandler do

it "deflates if has deflate in 'deflate' Accept-Encoding header" do
io = MemoryIO.new
request = HTTP::Request.new("GET", "/")
request = HTTP::Server::Request.new("GET", "/")
request.headers["Accept-Encoding"] = "foo, deflate, other"

response = HTTP::Server::Response.new(io)
Expand Down Expand Up @@ -49,7 +49,7 @@ describe HTTP::DeflateHandler do

it "deflates gzip if has deflate in 'deflate' Accept-Encoding header" do
io = MemoryIO.new
request = HTTP::Request.new("GET", "/")
request = HTTP::Server::Request.new("GET", "/")
request.headers["Accept-Encoding"] = "foo, gzip, other"

response = HTTP::Server::Response.new(io)
Expand Down
4 changes: 2 additions & 2 deletions spec/std/http/server/handlers/error_handler_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ require "http/server"
describe HTTP::ErrorHandler do
it "rescues from exception" do
io = MemoryIO.new
request = HTTP::Request.new("GET", "/")
request = HTTP::Server::Request.new("GET", "/")
response = HTTP::Server::Response.new(io)
context = HTTP::Server::Context.new(request, response)

Expand All @@ -23,7 +23,7 @@ describe HTTP::ErrorHandler do

it "can return a generic error message" do
io = MemoryIO.new
request = HTTP::Request.new("GET", "/")
request = HTTP::Server::Request.new("GET", "/")
response = HTTP::Server::Response.new(io)
context = HTTP::Server::Context.new(request, response)

Expand Down
2 changes: 1 addition & 1 deletion spec/std/http/server/handlers/handler_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ end
describe HTTP::Handler do
it "responds with not found if there's no next handler" do
io = MemoryIO.new
request = HTTP::Request.new("GET", "/")
request = HTTP::Server::Request.new("GET", "/")
response = HTTP::Server::Response.new(io)
context = HTTP::Server::Context.new(request, response)

Expand Down
4 changes: 2 additions & 2 deletions spec/std/http/server/handlers/log_handler_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ require "http/server"
describe HTTP::LogHandler do
it "logs" do
io = MemoryIO.new
request = HTTP::Request.new("GET", "/")
request = HTTP::Server::Request.new("GET", "/")
response = HTTP::Server::Response.new(io)
context = HTTP::Server::Context.new(request, response)

Expand All @@ -19,7 +19,7 @@ describe HTTP::LogHandler do

it "does log errors" do
io = MemoryIO.new
request = HTTP::Request.new("GET", "/")
request = HTTP::Server::Request.new("GET", "/")
response = HTTP::Server::Response.new(io)
context = HTTP::Server::Context.new(request, response)

Expand Down
26 changes: 13 additions & 13 deletions spec/std/http/server/handlers/static_file_handler_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -16,79 +16,79 @@ describe HTTP::StaticFileHandler do
file_text = File.read "#{__DIR__}/static/test.txt"

it "should serve a file" do
response = handle HTTP::Request.new("GET", "/test.txt")
response = handle HTTP::Server::Request.new("GET", "/test.txt")
response.status_code.should eq(200)
response.body.should eq(File.read("#{__DIR__}/static/test.txt"))
end

it "should list directory's entries" do
response = handle HTTP::Request.new("GET", "/")
response = handle HTTP::Server::Request.new("GET", "/")
response.status_code.should eq(200)
response.body.should match(/test.txt/)
end

it "should not serve a not found file" do
response = handle HTTP::Request.new("GET", "/not_found_file.txt")
response = handle HTTP::Server::Request.new("GET", "/not_found_file.txt")
response.status_code.should eq(404)
end

it "should not serve a not found directory" do
response = handle HTTP::Request.new("GET", "/not_found_dir/")
response = handle HTTP::Server::Request.new("GET", "/not_found_dir/")
response.status_code.should eq(404)
end

it "should not serve a file as directory" do
response = handle HTTP::Request.new("GET", "/test.txt/")
response = handle HTTP::Server::Request.new("GET", "/test.txt/")
response.status_code.should eq(404)
end

it "should handle only GET and HEAD method" do
%w(GET HEAD).each do |method|
response = handle HTTP::Request.new(method, "/test.txt")
response = handle HTTP::Server::Request.new(method, "/test.txt")
response.status_code.should eq(200)
end

%w(POST PUT DELETE).each do |method|
response = handle HTTP::Request.new(method, "/test.txt")
response = handle HTTP::Server::Request.new(method, "/test.txt")
response.status_code.should eq(404)
response = handle HTTP::Request.new(method, "/test.txt"), false
response = handle HTTP::Server::Request.new(method, "/test.txt"), false
response.status_code.should eq(405)
response.headers["Allow"].should eq("GET, HEAD")
end
end

it "should expand a request path" do
%w(../test.txt ../../test.txt test.txt/../test.txt a/./b/../c/../../test.txt).each do |path|
response = handle HTTP::Request.new("GET", "/#{path}")
response = handle HTTP::Server::Request.new("GET", "/#{path}")
response.status_code.should eq(302)
response.headers["Location"].should eq("/test.txt")
end

# directory
%w(.. ../ ../.. a/.. a/.././b/../).each do |path|
response = handle HTTP::Request.new("GET", "/#{path}")
response = handle HTTP::Server::Request.new("GET", "/#{path}")
response.status_code.should eq(302)
response.headers["Location"].should eq("/")
end
end

it "should unescape a request path" do
%w(test%2Etxt %74%65%73%74%2E%74%78%74).each do |path|
response = handle HTTP::Request.new("GET", "/#{path}")
response = handle HTTP::Server::Request.new("GET", "/#{path}")
response.status_code.should eq(200)
response.body.should eq(file_text)
end

%w(%2E%2E/test.txt found%2F%2E%2E%2Ftest%2Etxt).each do |path|
response = handle HTTP::Request.new("GET", "/#{path}")
response = handle HTTP::Server::Request.new("GET", "/#{path}")
response.status_code.should eq(302)
response.headers["Location"].should eq("/test.txt")
end
end

it "should return 400" do
%w(%00 test.txt%00).each do |path|
response = handle HTTP::Request.new("GET", "/#{path}")
response = handle HTTP::Server::Request.new("GET", "/#{path}")
response.status_code.should eq(400)
end
end
Expand Down
Loading