Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge remote-tracking branch 'origin/from-boss'

  • Loading branch information...
commit 736a094a42964e91ae1c5b2c377f556f5572015f 2 parents 52da9c7 + 4aa2102
@choptastic choptastic authored
View
104 src/misultin_bridge_modules/misultin_request_bridge.erl
@@ -5,15 +5,11 @@
init/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
+ headers/1, header/2, cookies/1,
+ query_params/1, post_params/1, request_body/1,
+ socket/1, recv_from_socket/3
]).
-
-%% @todo could not figure out how to get the socket from misultin
-%% so could not implement socket/1, recv_from_socket/3 that are
-%% present in other request modules
-
init(Req) ->
Req.
@@ -28,36 +24,70 @@ uri(Req) ->
Req:get(uri).
peer_ip(Req) ->
- Req:get(peer_addr).
+ case Req:get(peer_addr) of
+ {ok, IP} -> IP;
+ IP -> IP
+ end.
peer_port(Req) ->
Req:get(peer_port).
+header(connection, Req) ->
+ misultin_utility:get_key_value('Connection', Req:get(headers));
+header(accept, Req) ->
+ misultin_utility:get_key_value('Accept', Req:get(headers));
+header(host, Req) ->
+ misultin_utility:get_key_value('Host', Req:get(headers));
+header(if_modified_since, Req) ->
+ misultin_utility:get_key_value('If-Modified-Since', Req:get(headers));
+header(if_match, Req) ->
+ misultin_utility:get_key_value('If-Match', Req:get(headers));
+header(if_none_match, Req) ->
+ misultin_utility:get_key_value('If-None-Match', Req:get(headers));
+header(if_range, Req) ->
+ misultin_utility:get_key_value('If-Range', Req:get(headers));
+header(if_unmodified_since, Req) ->
+ misultin_utility:get_key_value('If-Unmodified-Since', Req:get(headers));
+header(range, Req) ->
+ misultin_utility:get_key_value('Range', Req:get(headers));
+header(referer, Req) ->
+ misultin_utility:get_key_value('Referer', Req:get(headers));
+header(user_agent, Req) ->
+ misultin_utility:get_key_value('User-Agent', Req:get(headers));
+header(accept_ranges, Req) ->
+ misultin_utility:get_key_value('Accept-Ranges', Req:get(headers));
+header(cookie, Req) ->
+ misultin_utility:get_key_value('Cookie', Req:get(headers));
+header(keep_alive, Req) ->
+ misultin_utility:get_key_value('Keep-Alive', Req:get(headers));
+header(location, Req) ->
+ misultin_utility:get_key_value('Location', Req:get(headers));
+header(content_length, Req) ->
+ misultin_utility:get_key_value('Content-Length', Req:get(headers));
+header(content_type, Req) ->
+ misultin_utility:get_key_value('Content-Type', Req:get(headers));
+header(content_encoding, Req) ->
+ misultin_utility:get_key_value('Content-Encoding', Req:get(headers));
+header(authorization, Req) ->
+ misultin_utility:get_key_value('Authorization', Req:get(headers));
+header(x_forwarded_for, Req) ->
+ misultin_utility:get_key_value('X-Forwarded-For', Req:get(headers));
+header(transfer_encoding, Req) ->
+ misultin_utility:get_key_value('Transfer-Encoding', Req:get(headers));
+header(accept_language, Req) ->
+ misultin_utility:get_key_value('Accept-Language', Req:get(headers));
+header(Header, Req) ->
+ misultin_utility:get_key_value(Header, Req:get(headers)).
+
headers(Req) ->
- Headers = Req:get(headers),
- F = fun(Header) -> proplists:get_value(Header, Headers) end,
- Headers1 = [
- {connection, F('Connection')},
- {accept, F('Accept')},
- {host, F('Host')},
- {if_modified_since, F('If-Modified-Since')},
- {if_match, F('If-Match')},
- {if_none_match, F('If-Range')},
- {if_unmodified_since, F('If-Unmodified-Since')},
- {range, F('Range')},
- {referer, F('Referer')},
- {user_agent, F('User-Agent')},
- {accept_ranges, F('Accept-Ranges')},
- {cookie, F('Cookie')},
- {keep_alive, F('Keep-Alive')},
- {location, F('Location')},
- {content_length, F('Content-Length')},
- {content_type, F('Content-Type')},
- {content_encoding, F('Content-Encoding')},
- {authorization, F('Authorization')},
- {transfer_encoding, F('Transfer-Encoding')}
+ Headers1 = [ connection, accept, host, if_modified_since,
+ if_match, if_none_match, if_range, if_unmodified_since,
+ range, referer, user_agent, accept_language, accept_ranges, cookie,
+ keep_alive, location, content_length, content_type,
+ content_encoding, authorization, x_forwarded_for, transfer_encoding
],
- [{K, V} || {K, V} <- Headers1, V /= undefined].
+ Headers2 = lists:map(fun(H) -> {H, header(H, Req)} end, Headers1),
+ [{K, V} || {K, V} <- Headers2, V /= undefined].
cookies(Req) ->
Headers = headers(Req),
@@ -81,3 +111,15 @@ post_params(Req) ->
request_body(Req) ->
Req:get(body).
+
+socket(Req) ->
+ Req:get(socket).
+
+recv_from_socket(Length, Timeout, Req) ->
+ Socket = socket(Req),
+ case gen_tcp:recv(Socket, Length, Timeout) of
+ {ok, Data} ->
+ Data;
+ _Other ->
+ exit(normal)
+ end.
View
9 src/misultin_bridge_modules/misultin_response_bridge.erl
@@ -1,9 +1,12 @@
-module (misultin_response_bridge).
-behaviour (simple_bridge_response).
-include_lib ("simple_bridge.hrl").
--export ([build_response/2]).
+-export ([build_response/2,init/1]).
-build_response(Req, Res) ->
+init({Req,DocRoot}) ->
+ {Req,DocRoot}.
+
+build_response({Req, DocRoot}, Res) ->
% Some values...
Code = Res#response.statuscode,
case Res#response.data of
@@ -18,7 +21,7 @@ build_response(Req, Res) ->
% Send the misultin response...
Req:respond(Code, Headers, Body);
{file, Path} ->
- Req:file([Path])
+ Req:file([DocRoot, Path])
end.
create_cookie_header(Cookie) ->
View
132 src/mochiweb_bridge_modules/mochiweb_request_bridge.erl
@@ -9,81 +9,123 @@
init/1,
request_method/1, path/1, uri/1,
peer_ip/1, peer_port/1,
- headers/1, cookies/1,
+ headers/1, header/2, cookies/1,
query_params/1, post_params/1, request_body/1,
socket/1, recv_from_socket/3
]).
-%% Mochiweb's max request size is 1MB, let's updated it to 1GB
--define(MAX_BODY_SIZE, (1024*1024*1024)).
+%% Max Body of 10MB by default
+-define(MAX_RECV_BODY,(1024*1024*10)).
-init({Req, DocRoot}) ->
- {Req, DocRoot}.
+init(Req) ->
+ Req.
-request_method({Req, _DocRoot}) ->
+request_method(Req) ->
Req:get(method).
-path({Req, _DocRoot}) ->
+path(Req) ->
RawPath = Req:get(raw_path),
{Path, _, _} = mochiweb_util:urlsplit_path(RawPath),
Path.
-uri({Req, _DocRoot}) ->
+uri(Req) ->
Req:get(raw_path).
-peer_ip({Req, _DocRoot}) ->
- Socket = Req:get(socket),
- {ok, {IP, _Port}} = inet:peername(Socket),
- IP.
+peer_ip(Req) ->
+ case Req:get(socket) of
+ false -> {127, 0, 0, 1};
+ Socket ->
+ {ok, {IP, _Port}} = mochiweb_socket:peername(Socket),
+ IP
+ end.
-peer_port({Req, _DocRoot}) ->
+peer_port(Req) ->
Socket = Req:get(socket),
- {ok, {_IP, Port}} = inet:peername(Socket),
+ {ok, {_IP, Port}} = mochiweb_socket:peername(Socket),
Port.
+
+header(connection, Req) ->
+ Req:get_header_value("connection");
+header(accept, Req) ->
+ Req:get_header_value("accept");
+header(host, Req) ->
+ Req:get_header_value("host");
+header(if_modified_since, Req) ->
+ Req:get_header_value("if-modified-since");
+header(if_match, Req) ->
+ Req:get_header_value("if-match");
+header(if_none_match, Req) ->
+ Req:get_header_value("if-none-match");
+header(if_unmodified_since, Req) ->
+ Req:get_header_value("if-unmodified-since");
+header(if_range, Req) ->
+ Req:get_header_value("if-range");
+header(range, Req) ->
+ Req:get_header_value("range");
+header(user_agent, Req) ->
+ Req:get_header_value("user-agent");
+header(accept_language, Req) ->
+ Req:get_header_value("accept-language");
+header(accept_ranges, Req) ->
+ Req:get_header_value("accept-ranges");
+header(cookie, Req) ->
+ Req:get_header_value("cookie");
+header(keep_alive, Req) ->
+ Req:get_header_value("keep-alive");
+header(location, Req) ->
+ Req:get_header_value("location");
+header(content_length, Req) ->
+ Req:get_header_value("content-length");
+header(content_type, Req) ->
+ Req:get_header_value("content-type");
+header(content_encoding, Req) ->
+ Req:get_header_value("content-encoding");
+header(authorization, Req) ->
+ Req:get_header_value("authorization");
+header(x_forwarded_for, Req) ->
+ Req:get_header_value("x-forwarded-for");
+header(transfer_encoding, Req) ->
+ Req:get_header_value("transfer-encoding");
+header(Header, Req) ->
+ Req:get_header_value(Header).
-headers({Req, _DocRoot}) ->
- F = fun(Header) -> Req:get_header_value(Header) end,
- Headers1 = [
- {connection, F("connection")},
- {accept, F("accept")},
- {host, F("host")},
- {if_modified_since, F("if-modified-since")},
- {if_match, F("if-match")},
- {if_none_match, F("if-range")},
- {if_unmodified_since, F("if-unmodified-since")},
- {range, F("range")},
- {referer, F("referer")},
- {user_agent, F("user-agent")},
- {accept_ranges, F("accept-ranges")},
- {cookie, F("cookie")},
- {keep_alive, F("keep-alive")},
- {location, F("location")},
- {content_length, F("content-length")},
- {content_type, F("content-type")},
- {content_encoding, F("content-encoding")},
- {authorization, F("authorization")},
- {x_forwarded_for, F("x-forwarded-for")},
- {transfer_encoding, F("transfer-encoding")}
+headers(Req) ->
+ Headers = [connection, accept, host, if_modified_since,
+ connection, accept, host, if_modified_since, if_match,
+ if_none_match, if_unmodified_since, if_range, range,
+ referer, user_agent, accept_language, accept_ranges,
+ cookie, keep_alive, location, content_length, content_type,
+ content_encoding, authorization, x_forwarded_for, transfer_encoding
],
+ Headers1 = lists:map(fun(H) -> {H, header(H, Req)} end, Headers),
[{K, V} || {K, V} <- Headers1, V /= undefined].
-cookies({Req, _DocRoot}) ->
+cookies(Req) ->
Req:parse_cookie().
-query_params({Req, _DocRoot}) ->
+query_params(Req) ->
Req:parse_qs().
-post_params({Req, _DocRoot}) ->
+post_params(Req) ->
Req:parse_post().
-request_body({Req, _DocRoot}) ->
- Req:recv_body(?MAX_BODY_SIZE).
+request_body(Req) ->
+ MaxBody = case application:get_env(mochiweb,max_request_size) of
+ undefined ->
+ ?MAX_RECV_BODY;
+ Max when is_integer(Max) ->
+ Max;
+ Other ->
+ error_logger:warning_msg("Mochiweb Simple Bridge Configuration Error! Unknown value for 'mochiweb' application variable 'max_request_size': ~p. Expected: integer() or undefined. Using Default of ~p~n",[Other,?MAX_RECV_BODY]),
+ ?MAX_RECV_BODY
+ end,
+ Req:recv_body(MaxBody).
-socket({Req, _DocRoot}) ->
+socket(Req) ->
Req:get(socket).
-recv_from_socket(Length, Timeout, {Req, DocRoot}) ->
- Socket = socket({Req, DocRoot}),
+recv_from_socket(Length, Timeout, Req) ->
+ Socket = socket(Req),
case gen_tcp:recv(Socket, Length, Timeout) of
{ok, Data} ->
put(mochiweb_request_recv, true),
View
14 src/mochiweb_bridge_modules/mochiweb_response_bridge.erl
@@ -22,7 +22,8 @@ build_response({Req, DocRoot}, Res) ->
[create_cookie_header(X) || X <- Res#response.cookies]
]),
- % Ensure content type...
+ %
+ % 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
@@ -34,13 +35,14 @@ build_response({Req, DocRoot}, Res) ->
Req:respond({Code, Headers2, Body});
{file, Path} ->
%% Calculate expire date far into future...
- Seconds = calendar:datetime_to_gregorian_seconds(calendar:local_time()),
- TenYears = 10 * 365 * 24 * 60 * 60,
- Seconds1 = calendar:gregorian_seconds_to_datetime(Seconds + TenYears),
- ExpireDate = httpd_util:rfc1123_date(Seconds1),
+ %% This method copied from Evan Miller's implementation
+ {{Y, _, _}, _} = calendar:local_time(),
+
+ ExpireDate = httpd_util:rfc1123_date(),
+ ExpireDate1 = re:replace(ExpireDate, " \\d\\d\\d\\d ", io_lib:format(" ~4.4.0w ", [Y + 10])),
%% Create the response telling Mochiweb to serve the file...
- Headers = [{"Expires", ExpireDate}],
+ Headers = [{"Expires", ExpireDate1}],
Req:serve_file(tl(Path), DocRoot, Headers)
end.
View
53 src/simple_bridge_request_wrapper.erl
@@ -43,13 +43,20 @@ cookie(Cookie) ->
query_params() -> Mod:query_params(Req).
+query_param(Param) ->
+ proplists:get_value(Param, query_params()).
+
post_params() ->
case {request_method(), IsMultiPart} of
{'POST', true} -> PostParams;
{'POST', false} -> Mod:post_params(Req);
+ {'PUT', false} -> Mod:post_params(Req);
_ -> []
end.
+post_param(Param) ->
+ proplists:get_value(Param, post_params()).
+
post_files() -> PostFiles.
request_body() -> Mod:request_body(Req).
@@ -69,3 +76,49 @@ recv_from_socket(Length, Timeout) ->
end.
error() -> Error.
+
+deep_post_params() ->
+ Params = post_params(),
+ parse_deep_post_params(Params, []).
+
+deep_post_param(Path) ->
+ find_deep_post_param(Path, deep_post_params()).
+
+find_deep_post_param([], Params) ->
+ Params;
+find_deep_post_param([Index|Rest], Params) when is_integer(Index) ->
+ find_deep_post_param(Rest, lists:nth(Index, Params));
+find_deep_post_param([Index|Rest], Params) when is_list(Index) ->
+ find_deep_post_param(Rest, proplists:get_value(Index, Params)).
+
+parse_deep_post_params([], Acc) ->
+ Acc;
+parse_deep_post_params([{Key, Value}|Rest], Acc) ->
+ case re:run(Key, "^(\\w+)(?:\\[([\\w\\[\\]]+)\\])?$", [{capture, all_but_first, list}]) of
+ {match, [Key]} ->
+ parse_deep_post_params(Rest, [{Key, Value}|Acc]);
+ {match, [KeyName, Path]} ->
+ PathList = re:split(Path, "\\]\\[", [{return, list}]),
+ parse_deep_post_params(Rest, insert_into(Acc, [KeyName|PathList], Value))
+ end.
+
+insert_into(_List, [], Value) ->
+ Value;
+insert_into(undefined, PathList, Value) ->
+ insert_into([], PathList, Value);
+insert_into(N, PathList, Value) when is_integer(N) ->
+ insert_into([], PathList, Value);
+insert_into(List, [ThisKey|Rest], Value) ->
+ case catch list_to_integer(ThisKey) of
+ {'EXIT', _} ->
+ ExistingVal = proplists:get_value(ThisKey, List),
+ [{ThisKey, insert_into(ExistingVal, Rest, Value)}|
+ proplists:delete(ThisKey, List)];
+ N when N < erlang:length(List) ->
+ ExistingVal = lists:nth(N+1, List),
+ lists:sublist(List, N) ++ [insert_into(ExistingVal, Rest, Value)|
+ lists:nthtail(N+1, List)];
+ N when N >= erlang:length(List) ->
+ List ++ lists:reverse([insert_into(undefined, Rest, Value)|
+ lists:seq(0, N - erlang:length(List) - 1)])
+ end.
View
2  src/simple_bridge_response_wrapper.erl
@@ -13,7 +13,7 @@ status_code(StatusCode) ->
header(Name, Value) ->
Header = #header { name=Name, value=Value },
Headers = Res#response.headers,
- Headers1 = [X || X <- Headers, X#header.name /= Name],
+ 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).
Please sign in to comment.
Something went wrong with that request. Please try again.