Permalink
Browse files

Add Cowboy 0.8 support

  • Loading branch information...
1 parent eb0e45a commit 78b87917e5d6efeed4f3c01bed0d23c736bfb8ca @RomanShestakov RomanShestakov committed with Feb 13, 2013
View
3 .gitignore
@@ -2,3 +2,6 @@ erl_crash.dump
*~
.*.sw?
.eunit/
+/deps/*
+test/logs/*
+logs
View
2 Makefile
@@ -10,4 +10,4 @@ clean:
./rebar clean
test: compile
- ./rebar eunit
+ ./rebar ct
View
2 include/simple_bridge.hrl
@@ -9,3 +9,5 @@
-record(uploaded_file, { original_name, temp_file, size }).
-record(request_cache, {request, docroot="", body=""}).
-compile({parse_transform,pmod_pt}).
+
+-define(B2L(B), simple_bridge_util:b2l(B)).
View
14 rebar.config
@@ -1,11 +1,15 @@
% -*- Erlang -*-
%% vim: ts=4 sw=4 et ft=erlang
+{lib_dirs,["deps"]}.
+{src_dirs, ["src", "test"]}.
+{erl_opts, [debug_info, fail_on_warning]}.
+{cover_enabled, true}.
+{xref_checks, [undefined_function_calls]}.
+
{deps, [
{mimetypes, ".*", {git, "git://github.com/spawngrid/mimetypes.git", "HEAD"}},
- {pmod_transform, ".*", {git, "git://github.com/choptastic/pmod_transform.git", "HEAD"}}
+ {pmod_transform, ".*", {git, "git://github.com/choptastic/pmod_transform.git", "HEAD"}},
+ {ranch, ".*", {git, "git://github.com/extend/ranch.git", "HEAD"}},
+ {cowboy, ".*", {git, "git://github.com/extend/cowboy", "HEAD"}}
]}.
-
-{erl_opts, [fail_on_warning, debug_info]}.
-{cover_enabled, true}.
-{xref_checks, [undefined_function_calls]}.
View
172 src/cowboy_bridge_modules/cowboy_request_bridge.erl
@@ -8,143 +8,111 @@
-include_lib ("simple_bridge.hrl").
-export ([
- init/1,
- protocol/1, request_method/1, path/1, uri/1,
- peer_ip/1, peer_port/1,
- headers/1, cookies/1,
- query_params/1, post_params/1, request_body/1,
- socket/1, recv_from_socket/3
-]).
-
--define(GET,_RequestCache=#request_cache{request=Req}=cowboy_request_server:get(ReqKey)).
--define(PUT,cowboy_request_server:set(ReqKey,NewRequestCache)).
-
-new_key() ->
- {cowboy_bridge,now()}.
-
-init({Req,DocRoot}) ->
+ init/1,
+ protocol/1,
+ request_method/1,
+ path/1,
+ uri/1,
+ peer_ip/1,
+ peer_port/1,
+ headers/1,
+ cookies/1,
+ query_params/1,
+ post_params/1,
+ request_body/1,
+ recv_from_socket/3
+ ]).
+
+init(Req) ->
ReqKey = new_key(),
- NewRequestCache = #request_cache{
- body=not_loaded,
- request=Req,
- docroot=DocRoot
- },
- ?PUT,
+ put_key(ReqKey, #request_cache{body = not_loaded, request = Req}),
ReqKey.
protocol(_ReqKey) -> undefined.
request_method(ReqKey) ->
- ?GET,
- {Method, Req} = cowboy_http_req:method(Req),
- Method.
+ {_RequestCache, Req} = get_key(ReqKey),
+ {Method, Req} = cowboy_req:method(Req),
+ list_to_atom(?B2L(Method)).
path(ReqKey) ->
- ?GET,
- {Path, Req} = cowboy_http_req:path(Req),
- case Path of
- [] -> "/";
- _ -> "/" ++ b2l(filename:join(Path)) %Mochweb returns path as /path and Cowboy does not
- end.
+ {_RequestCache, Req} = get_key(ReqKey),
+ {Path, Req} = cowboy_req:path(Req),
+ ?B2L(Path).
uri(ReqKey) ->
- ?GET,
- {RawPath, Req} = case cowboy_http_req:raw_path(Req) of
- undefined -> {undefined, ok};
- {P, R} -> {P, R}
- end,
- b2l(RawPath).
+ {_RequestCache, Req} = get_key(ReqKey),
+ {URL, Req} = cowboy_req:url(Req),
+ ?B2L(URL).
peer_ip(ReqKey) ->
- ?GET,
- {{IP, _Port}, NewReq} = cowboy_http_req:peer(Req),
- NewRequestCache = _RequestCache#request_cache{request=NewReq},
- ?PUT,
+ {RequestCache, Req} = get_key(ReqKey),
+ {{IP, _Port}, NewReq} = cowboy_req:peer(Req),
+ put_key(ReqKey, RequestCache#request_cache{request = NewReq}),
IP.
peer_port(ReqKey) ->
- ?GET,
- {Port, NewReq} = cowboy_http_req:port(Req),
- NewRequestCache = _RequestCache#request_cache{request=NewReq},
- ?PUT,
+ {RequestCache, Req} = get_key(ReqKey),
+ {{_IP, Port}, NewReq} = cowboy_req:peer(Req),
+ put_key(ReqKey, RequestCache#request_cache{request = NewReq}),
Port.
headers(ReqKey) ->
- ?GET,
- {Headers,Req} = cowboy_http_req:headers(Req),
- [{simple_bridge_util:atomize_header(Header),b2l(Val)} || {Header,Val} <- Headers].
-
+ {_RequestCache, Req} = get_key(ReqKey),
+ {Headers, Req} = cowboy_req:headers(Req),
+ [{simple_bridge_util:atomize_header(Header), ?B2L(Val)} || {Header, Val} <- Headers].
cookies(ReqKey) ->
- ?GET,
- {Cookies, NewReq} = cowboy_http_req:cookies(Req),
- NewRequestCache = _RequestCache#request_cache{request=NewReq},
- ?PUT,
- [{b2l(K),b2l(V)} || {K,V} <- Cookies].
+ {RequestCache, Req} = get_key(ReqKey),
+ {Cookies, NewReq} = cowboy_req:cookies(Req),
+ put_key(ReqKey, RequestCache#request_cache{request = NewReq}),
+ [{?B2L(K), ?B2L(V)} || {K, V} <- Cookies].
query_params(ReqKey) ->
- ?GET,
- {QsVals, NewReq} = cowboy_http_req:qs_vals(Req),
- NewRequestCache = _RequestCache#request_cache{request=NewReq},
- ?PUT,
- [{b2l(K),b2l(V)} || {K,V} <- QsVals].
-
-
+ {RequestCache, Req} = get_key(ReqKey),
+ {QsVals, NewReq} = cowboy_req:qs_vals(Req),
+ put_key(ReqKey, RequestCache#request_cache{request = NewReq}),
+ [{?B2L(K), ?B2L(V)} || {K, V} <- QsVals].
post_params(ReqKey) ->
- Body = request_body(ReqKey,binary),
- BodyQs = parse_qs(Body),
- [{b2l(K),b2l(V)} || {K,V} <- BodyQs].
+ Body = request_body(ReqKey, binary),
+ BodyQs = parse_qs(Body),
+ [{?B2L(K), ?B2L(V)} || {K, V} <- BodyQs].
request_body(ReqKey) ->
- request_body(ReqKey,string).
+ request_body(ReqKey, string).
-request_body(ReqKey,binary) ->
- ?GET,
+request_body(ReqKey, string) ->
+ ?B2L(request_body(ReqKey, binary));
+request_body(ReqKey, binary) ->
+ {RequestCache, Req} = get_key(ReqKey),
%% We cache the body here because we can't request the body twice in cowboy or it'll crash
- {Body,NewReq} = case _RequestCache#request_cache.body of
- not_loaded ->
- {ok, B, R} = cowboy_http_req:body(Req),
- {B,R};
- B -> {B,Req}
- end,
- NewRequestCache = _RequestCache#request_cache {
- body=Body,
- request=NewReq
- },
- ?PUT,
- Body;
-request_body(ReqKey,string) ->
- b2l(request_body(ReqKey,binary)).
-
-
-socket(ReqKey) ->
- ?GET,
- {ok, _Transport, Socket} = cowboy_http_req:transport(Req),
- Socket.
+ {Body, NewReq} =
+ case RequestCache#request_cache.body of
+ not_loaded ->
+ {ok, B, R} = cowboy_req:body(Req),
+ {B, R};
+ B -> {B, Req}
+ end,
+ put_key(ReqKey, RequestCache#request_cache{body = Body, request = NewReq}),
+ Body.
%% TODO: Cowboy's stream_body doesn't support customizable Length and Timeout
recv_from_socket(_Length, _Timeout, ReqKey) ->
- ?GET,
- %cowboy_http_req:init_stream(
- case cowboy_http_req:stream_body(Req) of
+ {RequestCache, Req} = get_key(ReqKey),
+ case cowboy_req:stream_body(Req) of
{ok, Data, NewReq} ->
- NewRequestCache = _RequestCache#request_cache{request=NewReq},
- ?PUT,
+ put_key(ReqKey, RequestCache#request_cache{request = NewReq}),
Data;
{done, NewReq} ->
- NewRequestCache = _RequestCache#request_cache{request=NewReq},
- ?PUT,
+ put_key(ReqKey, RequestCache#request_cache{request = NewReq}),
<<"">>;
{error, Reason} ->
exit({error, Reason}) %% exit(normal) instead?
end.
-
-
%% parse_qs, borrowed from Cowboy by Loic Hugian :)
-parse_qs(<<>>) ->
- [];
+parse_qs(<<>>) -> [];
parse_qs(Qs) ->
URLDecode = fun cowboy_http:urldecode/1,
Tokens = binary:split(Qs, <<"&">>, [global, trim]),
@@ -153,9 +121,11 @@ parse_qs(Qs) ->
[Name, Value] -> {URLDecode(Name), URLDecode(Value)}
end || Token <- Tokens].
+get_key(ReqKey) ->
+ RequestCache = #request_cache{request = Req} = cowboy_request_server:get(ReqKey),
+ {RequestCache, Req}.
-b2l(B) when is_binary(B) ->
- binary_to_list(B);
-b2l(B) ->
- B.
+put_key(ReqKey, NewRequestCache) ->
+ cowboy_request_server:set(ReqKey, NewRequestCache).
+new_key() -> {cowboy_bridge, erlang:make_ref()}.
View
143 src/cowboy_bridge_modules/cowboy_response_bridge.erl
@@ -8,46 +8,38 @@
-include_lib ("simple_bridge.hrl").
-export ([build_response/2,init/1]).
-
-init(Request) when
- is_tuple(Request),
- element(1,Request)==simple_bridge_request_wrapper,
- element(2,Request)==cowboy_request_bridge ->
- element(3,Request); %% The third element of Request is the RequestKey from response_bridge
-init({Req,DocRoot}) ->
+init(Request) when
+ is_tuple(Request),
+ element(1, Request) == simple_bridge_request_wrapper,
+ element(2, Request) == cowboy_request_bridge ->
+ element(3, Request); %% The third element of Request is the RequestKey from response_bridge
+init(Req) ->
%% Since cowboy request and response information are the same, this synchronizes it
- cowboy_request_bridge:init({Req,DocRoot}).
+ cowboy_request_bridge:init(Req).
build_response(ReqKey, Res) ->
- RequestCache = #request_cache{request=Req,docroot=DocRoot} = cowboy_request_server:get(ReqKey),
+ RequestCache = #request_cache{request = Req} = cowboy_request_server:get(ReqKey),
% Some values...
Code = Res#response.statuscode,
case Res#response.data of
{data, Body} ->
-
% Assemble headers...
- Headers = lists:flatten([
- [{X#header.name, X#header.value} || X <- Res#response.headers]
- ]),
+ Headers = lists:flatten([[{X#header.name, X#header.value} || X <- Res#response.headers]]),
% Ensure content type...
F = fun(Key) -> lists:keymember(Key, 1, Headers) end,
HasContentType = lists:any(F, ["content-type", "Content-Type", "CONTENT-TYPE"]),
- Headers2 = case HasContentType of
- true -> Headers;
- false -> [{"Content-Type", "text/html"}|Headers]
- end,
+ Headers2 =
+ case HasContentType of
+ true -> Headers;
+ false -> [{"Content-Type", "text/html"} | Headers]
+ end,
% Send the cowboy cookies
- {ok, FinReq} = send(Code,Headers2,Res#response.cookies,Body,Req),
-
- NewRequestCache = RequestCache#request_cache{
- request=FinReq
- },
- cowboy_request_server:set(ReqKey,NewRequestCache),
- {ok,FinReq};
-
+ {ok, FinReq} = send(Code, Headers2, Res#response.cookies, Body, Req),
+ cowboy_request_server:set(ReqKey, RequestCache#request_cache{request = FinReq}),
+ {ok, FinReq};
{file, P} ->
%% Note: that this entire {file, Path} section should be avoided
@@ -62,69 +54,46 @@ build_response(ReqKey, Res) ->
%% and
%% https://github.com/choptastic/nitrogen/blob/master/rel/overlay/cowboy/site/src/nitrogen_sup.erl
-
- % Cowboy path starts with / so we need to remove it
- Path = strip_leading_slash(P),
-
- ExpireDate = simple_bridge_util:expires(years, 10),
-
- [$. | Ext] = filename:extension(Path),
- Mimetype = mimetypes:extension(Ext),
-
- Headers = [
- {"Expires", ExpireDate},
- {"Content-Type",Mimetype}
- ],
-
- io:format("Serving static file ~p from docroot of ~p ~n",[Path, DocRoot]),
-
- FullPath = filename:join(DocRoot, Path),
- {ok, FinReq} = case file:read_file(FullPath) of
- {error,enoent} ->
- {ok, _R} = send(404,[],[],"Not Found",Req);
- {ok,Bin} ->
- {ok, _R} = send(200,Headers,[],Bin,Req)
- end,
-
- NewRequestCache = RequestCache#request_cache{
- request=FinReq
- },
- cowboy_request_server:set(ReqKey,NewRequestCache),
- {ok, FinReq}
+ %% % Cowboy path starts with / so we need to remove it
+ %% Path = strip_leading_slash(P),
+ %% ExpireDate = simple_bridge_util:expires(years, 10),
+ %% [$. | Ext] = filename:extension(Path),
+ %% Mimetype = mimetypes:extension(Ext),
+ %% Headers = [{"Expires", ExpireDate}, {"Content-Type",Mimetype}],
+
+ %% io:format("Serving static file ~p from docroot of ~p ~n",[Path, DocRoot]),
+
+ %% FullPath = filename:join(DocRoot, Path),
+ %% {ok, FinReq} =
+ %% case file:read_file(FullPath) of
+ %% {error,enoent} -> {ok, _R} = send(404, [], [], "Not Found", Req);
+ %% {ok,Bin} -> {ok, _R} = send(200, Headers, [], Bin, Req)
+ %% end,
+ %% cowboy_request_server:set(ReqKey, RequestCache#request_cache{request = FinReq}),
+ %% {ok, FinReq}
+ throw({error, P, fix_cowboy_routing})
end.
-
-%% Just to strip leading slash, as cowboy tends to do this.
-%% If no leading slash, just return the path.
-strip_leading_slash([$/ | Path]) ->
- Path;
-strip_leading_slash(Path) ->
- Path.
-
-
-send(Code,Headers,Cookies,Body,Req) ->
- Req1 = prepare_cookies(Req,Cookies),
- Req2 = prepare_headers(Req1,Headers),
- {ok, Req3} = cowboy_http_req:set_resp_body(Body,Req2),
- {ok, _ReqFinal} = cowboy_http_req:reply(Code, Req3).
-
-prepare_cookies(Req,Cookies) ->
- lists:foldl(fun(C,R) ->
- Name = iol2b(C#cookie.name),
- Value = iol2b(C#cookie.value),
- Path = iol2b(C#cookie.path),
+%% %% Just to strip leading slash, as cowboy tends to do this.
+%% %% If no leading slash, just return the path.
+%% strip_leading_slash([$/ | Path]) -> Path;
+%% strip_leading_slash(Path) -> Path.
+
+send(Code, Headers, Cookies, Body, Req) ->
+ Req1 = prepare_cookies(Req, Cookies),
+ Req2 = prepare_headers(Req1, Headers),
+ Req3 = cowboy_req:set_resp_body(Body, Req2),
+ {ok, _ReqFinal} = cowboy_req:reply(Code, Req3).
+
+prepare_cookies(Req, Cookies) ->
+ lists:foldl(fun(C, R) ->
+ Name = C#cookie.name,
+ Value = ?B2L(C#cookie.value),
+ Path = C#cookie.path,
SecsToLive = C#cookie.minutes_to_live * 60,
- Options = [{path,Path},{max_age,SecsToLive}],
- {ok,NewReq} = cowboy_http_req:set_resp_cookie(Name,Value,Options,R),
- NewReq
- end,Req,Cookies).
-
-prepare_headers(Req,Headers) ->
- lists:foldl(fun({Header,Value},R) ->
- {ok,NewReq} = cowboy_http_req:set_resp_header(iol2b(Header),iol2b(Value),R),
- NewReq
- end,Req,Headers).
-
+ Options = [{path, Path}, {max_age, SecsToLive}],
+ cowboy_req:set_resp_cookie(Name, Value, Options, R)
+ end, Req, Cookies).
-iol2b(V) when is_binary(V) -> V;
-iol2b(V) -> iolist_to_binary(V).
+prepare_headers(Req, Headers) ->
+ lists:foldl(fun({Header, Value}, R) -> cowboy_req:set_resp_header(Header, Value, R) end, Req, Headers).
View
14 src/simple_bridge_request_wrapper.erl
@@ -22,9 +22,9 @@ peer_port() -> Mod:peer_port(Req).
headers() -> Mod:headers(Req).
-header(Header) ->
+header(Header) ->
case erlang:function_exported(Mod, header, 2) of
- true ->
+ true ->
Mod:header(Header, Req);
false ->
Headers = Mod:headers(Req),
@@ -35,7 +35,7 @@ cookies() -> Mod:cookies(Req).
cookie(Cookie) ->
case erlang:function_exported(Mod, cookie, 2) of
- true ->
+ true ->
Mod:cookie(Cookie, Req);
false ->
Cookies = Mod:cookies(Req),
@@ -50,8 +50,8 @@ query_param(Param) ->
query_param(Param, DefaultValue) ->
proplists:get_value(Param, query_params(), DefaultValue).
-post_params() ->
- case {request_method(), IsMultiPart} of
+post_params() ->
+ case {request_method(), IsMultiPart} of
{'POST', true} -> PostParams;
{'POST', false} -> Mod:post_params(Req);
{'PUT', false} -> Mod:post_params(Req);
@@ -74,15 +74,15 @@ post_files() -> PostFiles.
request_body() -> Mod:request_body(Req).
-socket() ->
+socket() ->
case erlang:function_exported(Mod, socket, 1) of
true -> Mod:socket(Req);
false -> throw({not_supported, Mod, socket})
end.
get_peername() -> inet:peername(socket()).
-recv_from_socket(Length, Timeout) ->
+recv_from_socket(Length, Timeout) ->
case erlang:function_exported(Mod, recv_from_socket, 3) of
true -> Mod:recv_from_socket(Length, Timeout, Req);
false -> throw({not_supported, Mod, recv_from_socket})
View
16 src/simple_bridge_response_wrapper.erl
@@ -6,38 +6,38 @@
-include_lib ("simple_bridge.hrl").
-compile(export_all).
-status_code(StatusCode) ->
+status_code(StatusCode) ->
Res1 = Res#response { statuscode=StatusCode },
?MODULE:new(Mod, Req, Res1).
-header(Name, Value) ->
+header(Name, Value) ->
Header = #header { name=Name, value=Value },
Headers = Res#response.headers,
Headers1 = [X || X <- Headers, X#header.name /= Name orelse X#header.name =:= "Set-Cookie"],
Headers2 = [Header|Headers1],
Res1 = Res#response { headers=Headers2 },
- ?MODULE:new(Mod, Req, Res1).
+ ?MODULE:new(Mod, Req, Res1).
-clear_headers() ->
+clear_headers() ->
Res1 = Res#response { headers=[] },
?MODULE:new(Mod, Req, Res1).
cookie(Name, Value) ->
cookie(Name, Value, "/", 20).
-cookie(Name, Value, Path, MinutesToLive) ->
+cookie(Name, Value, Path, MinutesToLive) ->
Cookie = #cookie { name=Name, value=Value, path=Path, minutes_to_live=MinutesToLive },
Cookies = Res#response.cookies,
Cookies1 = [X || X <- Cookies, X#cookie.name /= Name],
Cookies2 = [Cookie|Cookies1],
Res1 = Res#response { cookies=Cookies2 },
- ?MODULE:new(Mod, Req, Res1).
+ ?MODULE:new(Mod, Req, Res1).
-clear_cookies() ->
+clear_cookies() ->
Res1 = Res#response { cookies=[] },
?MODULE:new(Mod, Req, Res1).
-data(Data) ->
+data(Data) ->
Res1 = Res#response { data={data, Data} },
?MODULE:new(Mod, Req, Res1).
View
12 src/simple_bridge_util.erl
@@ -1,9 +1,10 @@
% vim: ts=4 sw=4 et
-module(simple_bridge_util).
-export([
- atomize_header/1,
- expires/2
-]).
+ atomize_header/1,
+ expires/2,
+ b2l/1
+ ]).
%% converts a Header to a lower-case, underscored version
@@ -13,7 +14,7 @@ atomize_header(Header) when is_binary(Header) ->
atomize_header(Header) when is_atom(Header) ->
atomize_header(atom_to_list(Header));
atomize_header(Header) when is_list(Header) ->
- LowerUnderscore = fun(H) ->
+ LowerUnderscore = fun(H) ->
if
H >= 65 andalso H =< 90 ->
H + 32; % Convert "A" to "a" by adding 32 to its ASCII val
@@ -32,3 +33,6 @@ expires(years, Years) when is_integer(Years) ->
ExpireDate = httpd_util:rfc1123_date(),
_FinalExpiresDate = re:replace(ExpireDate, " \\d\\d\\d\\d ", io_lib:format(" ~4.4.0w ", [Y + Years])).
+
+b2l(B) when is_binary(B) -> binary_to_list(B);
+b2l(B) -> B.
View
126 test/cowboy_request_bridge_SUITE.erl
@@ -0,0 +1,126 @@
+-module(cowboy_request_bridge_SUITE).
+-compile(export_all).
+-include_lib("common_test/include/ct.hrl").
+
+suite() -> [{timetrap,{seconds,30}}].
+all() -> [{group, onrequest}].
+
+groups() -> [{onrequest, [], [request]}].
+
+%% for cowboy 0.8
+init_per_suite(Config) ->
+ application:start(crypto),
+ application:start(ranch),
+ application:start(cowboy),
+ Config.
+
+end_per_suite(_Config) ->
+ application:stop(cowboy),
+ application:stop(ranch),
+ application:stop(crypto),
+ ok.
+
+init_per_group(onrequest, Config) ->
+ Port = 33084,
+ Transport = ranch_tcp,
+ {ok, _} = cowboy:start_http(onrequest, 100, [{port, Port}], [
+ {env, [{dispatch, init_dispatch()}]},
+ {max_keepalive, 50},
+ {timeout, 500}
+ ]),
+ {ok, Client} = cowboy_client:init([]),
+ [{scheme, <<"http">>}, {port, Port}, {opts, []},
+ {transport, Transport}, {client, Client} | Config].
+
+end_per_group(Name, _) ->
+ cowboy:stop_listener(Name),
+ ok.
+
+init_dispatch() ->
+ cowboy_router:compile([{"localhost", [{'_', cowboy_request_bridge_SUITE, []}]}]).
+
+build_url(Path, Config) ->
+ {scheme, Scheme} = lists:keyfind(scheme, 1, Config),
+ {port, Port} = lists:keyfind(port, 1, Config),
+ PortBin = list_to_binary(integer_to_list(Port)),
+ PathBin = list_to_binary(Path),
+ << Scheme/binary, "://localhost:", PortBin/binary, PathBin/binary >>.
+
+
+-define(PATH, "/page").
+-define(QUERY_STRING, "query_string=type").
+-define(EXPECTED_RESPONSE, <<"Simple Bridge Response">>).
+
+request(Config) ->
+ Client = ?config(client, Config),
+ URL = build_url(?PATH ++ "?" ++ ?QUERY_STRING, Config),
+ ct:log("-> url ~p", [URL]),
+ {ok, Client2} = cowboy_client:request(<<"GET">>, URL, Client),
+ {ok, 200, Headers, Client3} = cowboy_client:response(Client2),
+ {ok, Body, _} = cowboy_client:response_body(Client3),
+ ct:log("-> response Body: ~p", [Body]),
+ ?EXPECTED_RESPONSE = Body,
+ ok.
+
+%% RequestBridge interface
+%% {init, 1}, % Should accept the request value passed by the http server.
+%% {protocol, 1}, % http | https | undefined
+%% {request_method, 1}, % GET, POST, etc.
+%% {uri, 1}, % The uri (path and querystring)
+%% {path, 1}, % Just the path. (http://server.com/<PATH>?querystring)
+%% {headers, 1}, % Return a proplist of headers, key and value are strings.
+%% {cookies, 1}, % Return a proplist of cookies, key and value are strings.
+%% {query_params, 1}, % Return a proplist of query parameters, key and value are strings.
+%% {post_params, 1}, % Return a proplist of post parameters, key and value are strings.
+%% {peer_ip, 1} % The remote IP address
+
+%% handle to process http request
+-record(state, {headers, body}).
+init({_Transport, http}, Req, _Opts) ->
+ {ok, Req, #state{}}.
+
+handle(Req, State) ->
+ ct:log("-> init RequestBridge and ResponseBridge", []),
+ %% init RequestBridge and ResponseBridge
+ RequestBridge = simple_bridge:make_request(cowboy_request_bridge, Req),
+ ResponseBridge = simple_bridge:make_response(cowboy_response_bridge, RequestBridge),
+
+ %% test API functions for RequestBridge interface
+ Protocol = RequestBridge:protocol(),
+ ct:log("-> Protocol ~p", [Protocol]),
+
+ ct:log("-> RequestMethod ~p", [RequestMethod = RequestBridge:request_method()]),
+ 'GET' = RequestMethod,
+
+ ct:log("-> URI ~p", [URI = RequestBridge:uri()]),
+ "http://localhost:33084/page?query_string=type" = URI,
+
+ ct:log("-> Path ~p", [Path = RequestBridge:path()]),
+ ?PATH = Path,
+
+ ct:log("-> Headers ~p", [Headers = RequestBridge:headers()]),
+ [{host, _},{user_agent,"Cow"}] = Headers,
+
+ ct:log("-> Cookies ~p", [Cookies = RequestBridge:cookies()]),
+ [] = Cookies,
+
+ ct:log("-> Query_params ~p", [Query_params = RequestBridge:query_params()]),
+ [{"query_string","type"}] = Query_params,
+
+ ct:log("-> Post_params ~p", [Post_params = RequestBridge:post_params()]),
+ [] = Post_params,
+
+ ct:log("-> Peer_IP ~p", [Peer_IP = RequestBridge:peer_ip()]),
+ {127,0,0,1} = Peer_IP,
+
+ %% test ResponseBridge
+ %% create response
+ ResponseBridge1 = ResponseBridge:data(binary_to_list(?EXPECTED_RESPONSE)),
+ {ok, Req2} = ResponseBridge1:build_response(),
+ ct:log("-> Response ~p", [Req2]),
+
+ ct:log("-> send response", []),
+ {ok, Req2, State}.
+
+terminate(_Reason, _Req, _State) ->
+ ok.
View
22 test/nitrogen_handler.erl
@@ -0,0 +1,22 @@
+%% Feel free to use, reuse and abuse the code in this file.
+
+-module(nitrogen_handler).
+-behaviour(cowboy_http_handler).
+-export([init/3, handle/2, terminate/3]).
+-include_lib("common_test/include/ct.hrl").
+-record(state, {headers, body}).
+
+init({_Transport, http}, Req, _Opts) ->
+ {ok, Req, #state{}}.
+
+handle(Req, State) ->
+ RequestBridge = simple_bridge:make_request(cowboy_request_bridge, Req),
+ ResponseBridge = simple_bridge:make_response(cowboy_response_bridge, RequestBridge),
+ %% Establishes the context with the Request and Response Bridges
+ nitrogen:init_request(RequestBridge, ResponseBridge),
+ {ok, Req2} = nitrogen:run(),
+ {ok, Req2, State}.
+
+terminate(_Reason, _Req, _State) ->
+ ok.
+

0 comments on commit 78b8791

Please sign in to comment.