diff options
Diffstat (limited to 'src/cowboy_http_req.erl')
-rw-r--r-- | src/cowboy_http_req.erl | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/src/cowboy_http_req.erl b/src/cowboy_http_req.erl new file mode 100644 index 0000000..27583c1 --- /dev/null +++ b/src/cowboy_http_req.erl @@ -0,0 +1,157 @@ +%% Copyright (c) 2011, Loïc Hoguin <[email protected]> +%% +%% Permission to use, copy, modify, and/or distribute this software for any +%% purpose with or without fee is hereby granted, provided that the above +%% copyright notice and this permission notice appear in all copies. +%% +%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +-module(cowboy_http_req). +-export([ + listener/1, method/1, version/1, peer/1, + host/1, raw_host/1, + path/1, raw_path/1, + qs_val/2, qs_val/3, qs_vals/1, raw_qs/1, + binding/2, binding/3, bindings/1, + header/2, header/3, headers/1 +%% cookie/2, cookie/3, cookies/1 @todo +]). %% API. + +-include("include/types.hrl"). +-include("include/http.hrl"). +-include_lib("eunit/include/eunit.hrl"). + +%% API. + +-spec listener(Req::#http_req{}) -> {Listener::atom(), Req::#http_req{}}. +listener(Req) -> + {Req#http_req.listener, Req}. + +-spec method(Req::#http_req{}) -> {Method::http_method(), Req::#http_req{}}. +method(Req) -> + {Req#http_req.method, Req}. + +-spec version(Req::#http_req{}) -> {Version::http_version(), Req::#http_req{}}. +version(Req) -> + {Req#http_req.version, Req}. + +-spec peer(Req::#http_req{}) + -> {{Address::ip_address(), Port::port_number()}, Req::#http_req{}}. +peer(Req) -> + {Req#http_req.peer, Req}. + +-spec host(Req::#http_req{}) -> {Host::path_tokens(), Req::#http_req{}}. +host(Req) -> + {Req#http_req.host, Req}. + +-spec raw_host(Req::#http_req{}) -> {RawHost::string(), Req::#http_req{}}. +raw_host(Req) -> + {Req#http_req.raw_host, Req}. + +-spec path(Req::#http_req{}) -> {Path::path_tokens(), Req::#http_req{}}. +path(Req) -> + {Req#http_req.path, Req}. + +-spec raw_path(Req::#http_req{}) -> {RawPath::string(), Req::#http_req{}}. +raw_path(Req) -> + {Req#http_req.raw_path, Req}. + +-spec qs_val(Name::atom(), Req::#http_req{}) + -> {Value::string(), Req::#http_req{}}. +qs_val(Name, Req=#http_req{raw_qs=RawQs, qs_vals=undefined}) -> + QsVals = parse_qs(RawQs), + qs_val(Name, Req#http_req{qs_vals=QsVals}); +qs_val(Name, Req) -> + {Name, Value} = lists:keyfind(Name, 1, Req#http_req.qs_vals), + {Value, Req}. + +-spec qs_val(Name::atom(), Default::term(), Req::#http_req{}) + -> {Value::string() | term(), Req::#http_req{}}. +qs_val(Name, Default, Req=#http_req{raw_qs=RawQs, qs_vals=undefined}) -> + QsVals = parse_qs(RawQs), + qs_val(Name, Default, Req#http_req{qs_vals=QsVals}); +qs_val(Name, Default, Req) -> + Value = proplists:get_value(Name, Req#http_req.qs_vals, Default), + {Value, Req}. + +-spec qs_vals(Req::#http_req{}) -> list({Name::atom(), Value::string()}). +qs_vals(Req=#http_req{raw_qs=RawQs, qs_vals=undefined}) -> + QsVals = parse_qs(RawQs), + qs_vals(Req#http_req{qs_vals=QsVals}); +qs_vals(Req=#http_req{qs_vals=QsVals}) -> + {QsVals, Req}. + +-spec raw_qs(Req::#http_req{}) -> {RawQs::string(), Req::#http_req{}}. +raw_qs(Req) -> + {Req#http_req.raw_qs, Req}. + +-spec binding(Name::atom(), Req::#http_req{}) + -> {Value::string(), Req::#http_req{}}. +binding(Name, Req) -> + {Name, Value} = lists:keyfind(Name, 1, Req#http_req.bindings), + {Value, Req}. + +-spec binding(Name::atom(), Default::term(), Req::#http_req{}) + -> {Value::string() | term(), Req::#http_req{}}. +binding(Name, Default, Req) -> + Value = proplists:get_value(Name, Req#http_req.bindings, Default), + {Value, Req}. + +-spec bindings(Req::#http_req{}) + -> {list({Name::atom(), Value::string()}), Req::#http_req{}}. +bindings(Req) -> + {Req#http_req.bindings, Req}. + +-spec header(Name::atom() | string(), Req::#http_req{}) + -> {Value::string(), Req::#http_req{}}. +header(Name, Req) -> + {Name, Value} = lists:keyfind(Name, 1, Req#http_req.headers), + {Value, Req}. + +-spec header(Name::atom() | string(), Default::term(), Req::#http_req{}) + -> {Value::string() | term(), Req::#http_req{}}. +header(Name, Default, Req) -> + Value = proplists:get_value(Name, Req#http_req.headers, Default), + {Value, Req}. + +-spec headers(Req::#http_req{}) + -> {list({Name::atom() | string(), Value::string()}), Req::#http_req{}}. +headers(Req) -> + {Req#http_req.headers, Req}. + +%% Internal. + +-spec parse_qs(Qs::string()) -> list({Name::string(), Value::string()}). +parse_qs(Qs) -> + Tokens = string:tokens(Qs, "&"), + [case string:chr(Token, $=) of + 0 -> + {Token, true}; + N -> + {Name, [$=|Value]} = lists:split(N - 1, Token), + {Name, Value} + end || Token <- Tokens]. + +%% Tests. + +-ifdef(TEST). + +parse_qs_test_() -> + %% {Qs, Result} + Tests = [ + {"", []}, + {"a=b", [{"a", "b"}]}, + {"aaa=bbb", [{"aaa", "bbb"}]}, + {"a&b", [{"a", true}, {"b", true}]}, + {"a=b&c&d=e", [{"a", "b"}, {"c", true}, {"d", "e"}]}, + {"a=b=c=d=e&f=g", [{"a", "b=c=d=e"}, {"f", "g"}]} + ], + [{Qs, fun() -> R = parse_qs(Qs) end} || {Qs, R} <- Tests]. + +-endif. |