0
Fork 0
mirror of https://github.com/ninenines/cowboy.git synced 2025-07-14 04:10:24 +00:00

Add more tests to the rfc7230 suite

Found more bugs! Unfortunately no fix for them in this commit.
This commit is contained in:
Loïc Hoguin 2017-11-24 00:16:19 +01:00
parent 14173d5929
commit ce32e1985a
No known key found for this signature in database
GPG key ID: 8A9DF795F6FED764
3 changed files with 120 additions and 46 deletions

View file

@ -0,0 +1,9 @@
%% This module sends a message to the pid passed in a header.
-module(send_message_h).
-export([init/2]).
init(Req, State) ->
Pid = list_to_pid(binary_to_list(cowboy_req:header(<<"x-test-pid">>, Req))),
Pid ! {Pid, self(), init, Req, State},
{ok, cowboy_req:reply(200, Req), State}.

View file

@ -91,7 +91,7 @@ end_per_group(Name, _) ->
%% Dispatch configuration.
init_dispatch(Config) ->
init_dispatch(_) ->
cowboy_router:compile([
{"localhost", [
{"/chunked_response", http_chunked, []},

View file

@ -24,7 +24,7 @@
all() -> [{group, http}].
groups() -> [{http, [parallel], ct_helper:all(?MODULE)}]. %% @todo parallel
groups() -> [{http, [parallel], ct_helper:all(?MODULE)}].
init_per_group(Name = http, Config) ->
cowboy_test:init_http(Name = http, #{
@ -38,7 +38,8 @@ init_routes(_) -> [
{"localhost", [
{"/", hello_h, []},
{"/echo/:key[/:arg]", echo_h, []},
{"/length/echo/:key", echo_h, []}
{"/length/echo/:key", echo_h, []},
{"/send_message", send_message_h, []}
%% @todo Something is clearly wrong about routing * right now.
%% {"*", asterisk_h, []}
]},
@ -1443,22 +1444,66 @@ pipeline(Config) ->
%Abusive traffic can come from the form of too many requests in a
%given amount of time, or too many concurrent connections. Limits
%must be subject to configuration. (RFC7230 6.4)
%
%close_inactive_connections(Config) ->
%The server must close inactive connections. The timeout
%must be subject to configuration. (RFC7230 6.5)
%
close_inactive_connections(Config) ->
doc("The server must close inactive connections. The timeout "
"must be subject to configuration. (RFC7230 6.5)"),
Client = raw_open(Config),
{error, closed} = raw_recv(Client, 0, 6000).
%@todo
%The server must monitor connections for the close signal
%and close the socket on its end accordingly. (RFC7230 6.5)
%
%@todo
%A connection close may occur at any time. (RFC7230 6.5)
%
%ignore_requests_after_connection_close(Config) ->
%The server must not process any request after sending or
%receiving the "close" connection option. (RFC7230 6.6)
%
ignore_requests_after_request_connection_close(Config) ->
doc("The server must not process any request after "
"receiving the \"close\" connection option. (RFC7230 6.6)"),
Self = self(),
#{code := 200, client := Client} = do_raw(Config, [
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"Connection: close\r\n"
"\r\n"
"GET /send_message HTTP/1.1\r\n"
"Host: localhost\r\n"
"x-test-pid: ", pid_to_list(Self), "\r\n"
"\r\n"]),
{error, closed} = raw_recv(Client, 0, 1000),
%% We receive a message if the second request is wrongly processed.
receive
{Self, _, init, Req, Opts} ->
error({init, Req, Opts})
after 1000 ->
ok
end.
ignore_requests_after_response_connection_close(Config) ->
doc("The server must not process any request after "
"sending the \"close\" connection option. (RFC7230 6.6)"),
Self = self(),
#{code := 200} = do_raw(Config, [
[
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"\r\n"
|| _ <- lists:seq(1, 100)],
"GET /send_message HTTP/1.1\r\n"
"Host: localhost\r\n"
"x-test-pid: ", pid_to_list(Self), "\r\n"
"\r\n"]),
%% We have a separate test for the connection close so we don't
%% double check the connection gets closed here. We only need to
%% know whether the 101st request was wrongly processed.
receive
{Self, _, init, Req, Opts} ->
error({init, Req, Opts})
after 1000 ->
ok
end.
%@todo
%The server must close the connection in stages to avoid the
%TCP reset problem. The server starts by closing the write
@ -1467,53 +1512,73 @@ pipeline(Config) ->
%last response has been received by the client, or until
%a close or timeout occurs. The server then fully close the
%connection. (6.6)
%
%%% Routing.
%
%% Routing.
%```
%Host = authority ; same as authority-form
%```
%
%reject_missing_host(Config) ->
%An HTTP/1.1 request that lacks a host header must be rejected with
%a 400 status code and the closing of the connection. (RFC7230 5.4)
%
%%% @todo http/1.0 missing_host(Config) ->
reject_missing_host(Config) ->
doc("An HTTP/1.1 request that lacks a host header must be rejected with "
"a 400 status code and the closing of the connection. (RFC7230 5.4)"),
#{code := 400, client := Client} = do_raw(Config, [
"GET / HTTP/1.1\r\n"
"\r\n"]),
{error, closed} = raw_recv(Client, 0, 1000).
%% @todo http/1.0 missing_host(Config) ->
%An HTTP/1.0 request that lack a host header is valid. Behavior
%for these requests is configuration dependent. (RFC7230 5.5)
%
%reject_invalid_host(Config) ->
%A request with an invalid host header must be rejected with a
%400 status code and the closing of the connection. (RFC7230 5.4)
%
%reject_userinfo(Config) ->
%An authority component with a userinfo component (and its
%"@" delimiter) is invalid. The request must be rejected with
%a 400 status code and the closing of the connection. (RFC7230 2.7.1)
%
%reject_absolute_form_different_host(Config) ->
%When using absolute-form the URI authority component must be
%identical to the host header. Invalid requests must be rejected
%with a 400 status code and the closing of the connection. (RFC7230 5.4)
%
reject_invalid_host(Config) ->
doc("A request with an invalid host header must be rejected with a "
"400 status code and the closing of the connection. (RFC7230 5.4)"),
#{code := 400, client := Client} = do_raw(Config, [
"GET / HTTP/1.1\r\n"
"Host: localhost:port\r\n"
"\r\n"]),
{error, closed} = raw_recv(Client, 0, 1000).
reject_userinfo(Config) ->
doc("An authority component with a userinfo component (and its "
"\"@\" delimiter) is invalid. The request must be rejected with "
"a 400 status code and the closing of the connection. (RFC7230 2.7.1)"),
#{code := 400, client := Client} = do_raw(Config, [
"GET / HTTP/1.1\r\n"
"Host: user@localhost\r\n"
"\r\n"]),
{error, closed} = raw_recv(Client, 0, 1000).
reject_absolute_form_different_host(Config) ->
doc("When using absolute-form the URI authority component must be "
"identical to the host header. Invalid requests must be rejected "
"with a 400 status code and the closing of the connection. (RFC7230 5.4)"),
#{code := 400, client := Client} = do_raw(Config, [
"GET http://example.org/ HTTP/1.1\r\n"
"Host: localhost\r\n"
"\r\n"]),
{error, closed} = raw_recv(Client, 0, 1000).
%reject_authority_form_different_host(Config) ->
%When using authority-form the URI authority component must be
%identical to the host header. Invalid requests must be rejected
%with a 400 status code and the closing of the connection.
%
%empty_host(Config) ->
%The host header is empty when the authority component is undefined. (RFC7230 5.4)
%
%@todo
%The effective request URI can be rebuilt by concatenating scheme,
%"://", authority, path and query components. (RFC7230 5.5)
%
%% The effective request URI can be rebuilt by concatenating scheme,
%% "://", authority, path and query components. (RFC7230 5.5)
%%
%% This is covered in req_SUITE in the tests for cowboy_req:uri/1,2.
%@todo
%Resources with identical URI except for the scheme component
%must be treated as different. (RFC7230 2.7.2)
%
%%% Response.
%
%% Response.
%@todo
%A server can send more than one response per request only when a
%1xx response is sent preceding the final response. (RFC7230 5.6)