Modified:
branches/RB-0.2/conf/include.mk.in
branches/RB-0.2/lib/ewgi/include/ewgi.hrl
branches/RB-0.2/lib/ewgi/src/ewgi_api.erl
branches/RB-0.2/lib/ewgi/src/ewgi_application.erl
branches/RB-0.2/lib/ewgi/src/ewgi_mochiweb.erl
branches/RB-0.2/lib/ewgi/src/ewgi_yaws.erl
Log:
Added -spec and -type declarations to header file
Added additional API methods for dealing with headers
Renamed some methods in ewgi_api to be more consistent
Modified: branches/RB-0.2/conf/include.mk.in
==============================================================================
--- branches/RB-0.2/conf/include.mk.in (original)
+++ branches/RB-0.2/conf/include.mk.in Tue Oct 21 10:16:43 2008
@@ -45,6 +45,4 @@
cp $< $@
../ebin/%.$(EMULATOR): %.erl $(wildcard $(YAWSDIR)/lib/*/*/*.hrl)
- "$(ERLC)" $(ERLC_FLAGS) -o ../ebin $<
-
-
+ "$(ERLC)" $(ERLC_FLAGS) -I ../include -o ../ebin $<
Modified: branches/RB-0.2/lib/ewgi/include/ewgi.hrl
==============================================================================
--- branches/RB-0.2/lib/ewgi/include/ewgi.hrl (original)
+++ branches/RB-0.2/lib/ewgi/include/ewgi.hrl Tue Oct 21 10:16:43 2008
@@ -61,11 +61,23 @@
-define(DEFAULT_CHUNKSIZE, 4096).
%% Convenience records representing request/response contexts
--record(ewgi_context, {
- request,
- response
- }).
+%% @type bag() = list()
+-type(bag() :: list()).
+
+%% @type ewgi_read_input() = function()
+-type(ewgi_read_input() :: fun((function(), integer()) -> function())).
+
+%% @type ewgi_write_error() = function()
+-type(ewgi_write_error() :: fun((any()) -> any())).
+
+%% @type ewgi_version() = {integer(), integer()}
+-type(ewgi_version() :: {integer(), integer()}).
+
+%% @type ewgi_spec() = {'ewgi_spec', function(), function(), string(),
+%% ewgi_version(), bag()}
+-type(ewgi_spec() :: {'ewgi_spec', ewgi_read_input(), ewgi_write_error(),
+ string(), ewgi_version(), bag()}).
-record(ewgi_spec, {
read_input,
write_error,
@@ -74,6 +86,24 @@
data % dict
}).
+%% @type ewgi_header_val() = string() | 'undefined'
+-type(ewgi_header_val() :: string() | 'undefined').
+
+%% @type ewgi_header_key() = string()
+-type(ewgi_header_key() :: string()).
+
+%% @type ewgi_http_headers() = {'ewgi_http_headers',
+%% ewgi_header_val(),
+%% ewgi_header_val(),
+%% ewgi_header_val(),
+%% ewgi_header_val(),
+%% ewgi_header_val(),
+%% ewgi_header_val(),
+%% bag()}
+-type(ewgi_http_headers() :: {'ewgi_http_headers', ewgi_header_val(),
+ ewgi_header_val(), ewgi_header_val(),
+ ewgi_header_val(), ewgi_header_val(),
+ ewgi_header_val(), bag()}).
-record(ewgi_http_headers, {
http_accept,
http_cookie,
@@ -84,6 +114,26 @@
other % dict
}).
+%% @type ewgi_request_method() = 'OPTIONS' | 'GET' | 'HEAD' | 'POST'
| 'PUT' |
+%% 'DELETE' | 'TRACE' | 'CONNECT' | string()
+-type(ewgi_request_method() :: 'OPTIONS' | 'GET' | 'HEAD' | 'POST' | 'PUT'
|
+ 'DELETE' | 'TRACE' | 'CONNECT' | string()).
+
+%% @type ewgi_val() = string() | 'undefined'
+-type(ewgi_val() :: string() | 'undefined').
+
+%% @type ewgi_request() :: {'ewgi_request', ewgi_val(), integer(),
ewgi_val(),
+%% ewgi_spec(), ewgi_val(), ewgi_http_headers(),
+%% ewgi_val(), ewgi_val(), ewgi_val(), ewgi_val(),
+%% ewgi_val(), ewgi_val(), ewgi_val(), ewgi_val(),
+%% ewgi_request_method(), ewgi_val(), ewgi_val(),
+%% ewgi_val(), ewgi_val(), ewgi_val()}
+-type(ewgi_request() :: {'ewgi_request', ewgi_val(), integer(), ewgi_val(),
+ ewgi_spec(), ewgi_val(), ewgi_http_headers(),
+ ewgi_val(), ewgi_val(), ewgi_val(), ewgi_val(),
+ ewgi_val(), ewgi_val(), ewgi_val(), ewgi_val(),
+ ewgi_request_method(), ewgi_val(), ewgi_val(),
+ ewgi_val(), ewgi_val(), ewgi_val()}).
-record(ewgi_request, {
auth_type,
content_length,
@@ -107,9 +157,36 @@
server_software
}).
+%% @type stream() = function()
+%% NOTE: function() should actually be stream() but it appears to break
+%% dialyzer at the time of writing.
+-type(stream() :: fun(() -> {} | {any(), function()})).
+
+%% @type ewgi_status() = {integer(), string()}
+-type(ewgi_status() :: {integer(), string()}).
+
+%% @type ewgi_message_body() = binary() | iolist() | stream()
+-type(ewgi_message_body() :: binary() | iolist() | stream()).
+
+%% @type ewgi_response() = {'ewgi_response', ewgi_status(),
+%% [{ewgi_header_key(), ewgi_header_val()}],
+%% ewgi_message_body(), any()}
+-type(ewgi_response() :: {'ewgi_response', ewgi_status(),
+ [{ewgi_header_key(), ewgi_header_val()}],
+ ewgi_message_body(), any()}).
-record(ewgi_response, {
status,
headers=[],
message_body,
err
}).
+
+%% @type ewgi_context() = {'ewgi_context', ewgi_request(), ewgi_response()}
+-type(ewgi_context() :: {'ewgi_context', ewgi_request(), ewgi_response()}).
+-record(ewgi_context, {
+ request,
+ response
+ }).
+
+%% @type ewgi_app() = function()
+-type(ewgi_app() :: fun((ewgi_context()) -> ewgi_context())).
Modified: branches/RB-0.2/lib/ewgi/src/ewgi_api.erl
==============================================================================
--- branches/RB-0.2/lib/ewgi/src/ewgi_api.erl (original)
+++ branches/RB-0.2/lib/ewgi/src/ewgi_api.erl Tue Oct 21 10:16:43 2008
@@ -25,11 +25,17 @@
%%%-------------------------------------------------------------------
-module(ewgi_api).
+-include("ewgi.hrl").
+
%% Record helpers
--export([empty_request/0, empty_response/0, context/2, set_request/2,
- set_response/2, get_request/1, get_response/1]).
+-export([empty_request/0, empty_response/0, context/2, request/2,
response/2,
+ request/1, response/1]).
+
+-export([response_headers/1, response_message_body/1, response_status/1,
+ response_error/1]).
--export([response_headers/1, response_message_body/1, response_status/1]).
+-export([response_headers/2, response_message_body/2, response_status/2,
+ response_error/2]).
%% Request 'get' methods
-export([auth_type/1, content_length/1, content_type/1,
gateway_interface/1,
@@ -46,8 +52,9 @@
server_protocol/2, server_software/2]).
%% Additional request methods
--export([get_all_headers/1, read_input/3, write_error/2, url_scheme/1,
- version/1, get_all_data/1, fetch_data/2, store_data/3]).
+-export([get_header/2, get_all_headers/1, read_input/1, read_input/3,
+ read_input_string/2, write_error/2, url_scheme/1, version/1,
+ get_all_data/1, find_data/2, store_data/3]).
%% Server methods
-export([server_request_foldl/4]).
@@ -56,34 +63,35 @@
-export([parse_qs/1, parse_post/1, urlencode/1, quote/1,
normalize_header/1,
unquote_path/1, path_components/3]).
--include("../include/ewgi.hrl").
-
%% dict module for "overflow" variable bags
-define(DICT, dict).
%%====================================================================
%% API
%%====================================================================
+-spec(empty_request/0 :: () -> ewgi_request()).
empty_request() ->
#ewgi_request{}.
+-spec(empty_response/0 :: () -> ewgi_response()).
empty_response() ->
#ewgi_response{}.
+-spec(context/2 :: (ewgi_request(), ewgi_response()) -> ewgi_context()).
context(Request, Response) when is_record(Request, ewgi_request),
is_record(Response, ewgi_response) ->
#ewgi_context{request=Request, response=Response}.
-set_request(Req, Ctx) when is_record(Req, ewgi_request), is_record(Ctx,
ewgi_context) ->
+request(Req, Ctx) when is_record(Req, ewgi_request), is_record(Ctx,
ewgi_context) ->
Ctx#ewgi_context{request=Req}.
-set_response(Rsp, Ctx) when is_record(Rsp, ewgi_response), is_record(Ctx,
ewgi_context) ->
+response(Rsp, Ctx) when is_record(Rsp, ewgi_response), is_record(Ctx,
ewgi_context) ->
Ctx#ewgi_context{response=Rsp}.
-get_response(#ewgi_context{response=R}) ->
+response(#ewgi_context{response=R}) ->
R.
-get_request(#ewgi_context{request=R}) ->
+request(#ewgi_context{request=R}) ->
R.
response_headers(#ewgi_context{response=#ewgi_response{headers=V}}) ->
@@ -95,6 +103,29 @@
response_message_body(#ewgi_context{response=#ewgi_response{message_body=V}})
->
V.
+response_error(#ewgi_context{response=#ewgi_response{err=V}}) ->
+ V.
+
+response_headers(V, #ewgi_context{response=Rsp0}=Ctx0) ->
+ Rsp = Rsp0#ewgi_response{headers=V},
+ Ctx = Ctx0#ewgi_context{response=Rsp},
+ Ctx.
+
+response_status(V, #ewgi_context{response=Rsp0}=Ctx0) ->
+ Rsp = Rsp0#ewgi_response{status=V},
+ Ctx = Ctx0#ewgi_context{response=Rsp},
+ Ctx.
+
+response_message_body(V, #ewgi_context{response=Rsp0}=Ctx0) ->
+ Rsp = Rsp0#ewgi_response{message_body=V},
+ Ctx = Ctx0#ewgi_context{response=Rsp},
+ Ctx.
+
+response_error(V, #ewgi_context{response=Rsp0}=Ctx0) ->
+ Rsp = Rsp0#ewgi_response{err=V},
+ Ctx = Ctx0#ewgi_context{response=Rsp},
+ Ctx.
+
auth_type(#ewgi_context{request=#ewgi_request{auth_type=V}}) ->
V.
@@ -149,6 +180,30 @@
server_software(#ewgi_context{request=#ewgi_request{server_software=V}}) ->
V.
+get_header(Hdr0, Ctx) when is_list(Hdr0) ->
+ Hdr = string:to_lower(Hdr0),
+ get_header1(Hdr, Ctx).
+
+get_header1("accept",
#ewgi_context{request=#ewgi_request{http_headers=#ewgi_http_headers{http_accept=V}}})
->
+ V;
+get_header1("cookie",
#ewgi_context{request=#ewgi_request{http_headers=#ewgi_http_headers{http_cookie=V}}})
->
+ V;
+get_header1("host",
#ewgi_context{request=#ewgi_request{http_headers=#ewgi_http_headers{http_host=V}}})
->
+ V;
+get_header1("if-modified-since",
#ewgi_context{request=#ewgi_request{http_headers=#ewgi_http_headers{http_if_modified_since=V}}})
->
+ V;
+get_header1("user-agent",
#ewgi_context{request=#ewgi_request{http_headers=#ewgi_http_headers{http_user_agent=V}}})
->
+ V;
+get_header1("x-http-method-override",
#ewgi_context{request=#ewgi_request{http_headers=#ewgi_http_headers{http_x_http_method_override=V}}})
->
+ V;
+get_header1(Hdr,
#ewgi_context{request=#ewgi_request{http_headers=#ewgi_http_headers{other=D}}})
->
+ case ?DICT:find(Hdr, D) of
+ {ok, V} ->
+ V;
+ error ->
+ undefined
+ end.
+
auth_type(V, #ewgi_context{request=Req0}=Ctx0) ->
Req = Req0#ewgi_request{auth_type=V},
Ctx0#ewgi_context{request=Req}.
@@ -230,9 +285,30 @@
{"user-agent", H#ewgi_http_headers.http_user_agent},
{"x-http-method-override",
H#ewgi_http_headers.http_x_http_method_override}|Acc].
+read_input(#ewgi_context{request=#ewgi_request{ewgi=#ewgi_spec{read_input=F}}})
->
+ F.
+
read_input(Callback, Length,
#ewgi_context{request=#ewgi_request{ewgi=#ewgi_spec{read_input=F}}}) ->
F(Callback, Length).
+%% @spec read_input_string(integer(), ewgi_context()) -> string()
+%% @doc Reads the client message body into a string from the EWGI context.
+-spec(read_input_string/2 :: (integer(), ewgi_context()) -> string()).
+
+read_input_string(L, Ctx) when is_integer(L) ->
+ R = read_input(Ctx),
+ Iol = R(read_input_string_cb([]), L),
+ Bin = iolist_to_binary(Iol),
+ binary_to_list(Bin).
+
+read_input_string_cb(Acc) ->
+ F = fun(eof) ->
+ lists:reverse(Acc);
+ ({data, B}) ->
+ read_input_string_cb([B|Acc])
+ end,
+ F.
+
write_error(Msg,
#ewgi_context{request=#ewgi_request{ewgi=#ewgi_spec{write_error=F}}}) ->
F(Msg).
@@ -245,8 +321,16 @@
get_all_data(#ewgi_context{request=#ewgi_request{ewgi=#ewgi_spec{data=D}}})
->
D.
-fetch_data(Key,
#ewgi_context{request=#ewgi_request{ewgi=#ewgi_spec{data=D}}}) ->
- ?DICT:fetch(Key, D).
+find_data(Key, Ctx) ->
+ find_data(Key, Ctx, undefined).
+
+find_data(Key,
#ewgi_context{request=#ewgi_request{ewgi=#ewgi_spec{data=D}}}, Default) ->
+ case ?DICT:find(Key, D) of
+ {ok, V} ->
+ V;
+ error ->
+ Default
+ end.
store_data(Key, Val,
#ewgi_context{request=#ewgi_request{ewgi=#ewgi_spec{data=D0}=E}=Req}=Ctx) ->
D = ?DICT:store(Key, Val, D0),
Modified: branches/RB-0.2/lib/ewgi/src/ewgi_application.erl
==============================================================================
--- branches/RB-0.2/lib/ewgi/src/ewgi_application.erl (original)
+++ branches/RB-0.2/lib/ewgi/src/ewgi_application.erl Tue Oct 21 10:16:43
2008
@@ -31,6 +31,8 @@
%% Useful middleware
-export([module_mw/1, rpc_mw/3, mfa_mw/2]).
+-include("ewgi.hrl").
+
%% Behaviour callback information
-export([behaviour_info/1]).
@@ -39,30 +41,33 @@
behaviour_info(_Other) ->
undefined.
+%% @spec run(Application::ewgi_app(), Context::ewgi_context()) ->
Context1::ewgi_context()
+%% @doc Runs an EWGI application with Context and returns the new Context1.
+-spec(run/2 :: (ewgi_app(), ewgi_context()) -> ewgi_context()).
run(Application, Context) when is_function(Application, 1) ->
Application(Context).
-%% @spec module_mw(Module::term()) -> function()
+%% @spec module_mw(Module::term()) -> ewgi_app()
%% @doc Produces a middleware application which calls the handle/1
function exported by Module.
--spec(module_mw/1 :: (any()) -> fun(({tuple(), tuple()}) -> {tuple(),
tuple()})).
+-spec(module_mw/1 :: (any()) -> ewgi_app()).
module_mw(Module) ->
F = fun(Context) ->
Module:handle(Context)
end,
F.
-%% @spec rpc_mw(Node::atom(), Module::atom(), Fun::atom()) -> function()
+%% @spec rpc_mw(Node::atom(), Module::atom(), Fun::atom()) -> ewgi_app()
%% @doc Produces a middleware application which calls the remote function
Module:Fun on Node.
--spec(rpc_mw/3 :: (atom(), atom(), atom()) -> fun(({tuple(), tuple()}) ->
{tuple(), tuple()})).
+-spec(rpc_mw/3 :: (atom(), atom(), atom()) -> ewgi_app()).
rpc_mw(Node, Module, Fun) ->
F = fun(Context) ->
rpc:call(Node, Module, Fun, [Context])
end,
F.
-%% @spec mfa_mw(Module::atom(), Fun::atom()) -> function()
+%% @spec mfa_mw(Module::atom(), Fun::atom()) -> ewgi_app()
%% @doc Produces a middleware application which calls the function
Module:Fun(Args)
--spec(mfa_mw/2 :: (atom(), atom()) -> fun(({tuple(), tuple()}) ->
{tuple(), tuple()})).
+-spec(mfa_mw/2 :: (atom(), atom()) -> ewgi_app()).
mfa_mw(Module, Fun) when is_atom(Module), is_atom(Fun) ->
F = fun(Context) ->
apply(Module, Fun, [Context])
Modified: branches/RB-0.2/lib/ewgi/src/ewgi_mochiweb.erl
==============================================================================
--- branches/RB-0.2/lib/ewgi/src/ewgi_mochiweb.erl (original)
+++ branches/RB-0.2/lib/ewgi/src/ewgi_mochiweb.erl Tue Oct 21 10:16:43 2008
@@ -28,7 +28,7 @@
%% ewgi callbacks
-export([run/1]).
--include("../include/ewgi.hrl").
+-include("ewgi.hrl").
-define(EWGI2MOCHI(Err, Hdrs), {element(1, Err), Hdrs, element(2, Err)}).
Modified: branches/RB-0.2/lib/ewgi/src/ewgi_yaws.erl
==============================================================================
--- branches/RB-0.2/lib/ewgi/src/ewgi_yaws.erl (original)
+++ branches/RB-0.2/lib/ewgi/src/ewgi_yaws.erl Tue Oct 21 10:16:43 2008
@@ -27,8 +27,8 @@
-export([run/1]).
--include_lib("yaws/include/yaws_api.hrl").
--include("../include/ewgi.hrl").
+-include_lib("yaws_api.hrl").
+-include("ewgi.hrl").
-define(DICT, dict).