From 31e525661a1cfe18e2a9d07a3bc1b9981fabc11e Mon Sep 17 00:00:00 2001 From: b Date: Tue, 7 Jun 2011 14:23:04 -0700 Subject: [PATCH 1/6] Automatically generate and insert Location header where appropriate --- include/wm_reqdata.hrl | 2 +- src/webmachine.erl | 3 ++- src/webmachine_decision_core.erl | 12 ++++++++++-- src/webmachine_request.erl | 21 +++++++++++++++++++++ src/webmachine_resource.erl | 2 ++ src/wrq.erl | 16 ++++++++++------ 6 files changed, 46 insertions(+), 10 deletions(-) diff --git a/include/wm_reqdata.hrl b/include/wm_reqdata.hrl index 649c38c5..2e5bcac9 100644 --- a/include/wm_reqdata.hrl +++ b/include/wm_reqdata.hrl @@ -1,4 +1,4 @@ --record(wm_reqdata, {method, version, peer, wm_state, +-record(wm_reqdata, {method, scheme, version, peer, wm_state, disp_path, path, raw_path, path_info, path_tokens, app_root,response_code,max_recv_body, max_recv_hunk, req_cookie, req_qs, req_headers, req_body, diff --git a/src/webmachine.erl b/src/webmachine.erl index 2524e0c7..0b27f6cc 100644 --- a/src/webmachine.erl +++ b/src/webmachine.erl @@ -39,11 +39,12 @@ stop() -> new_request(mochiweb, Request) -> Socket = Request:get(socket), Method = Request:get(method), + Scheme = Request:get(scheme), RawPath = Request:get(raw_path), Version = Request:get(version), Headers = Request:get(headers), InitState = #wm_reqstate{socket=Socket, - reqdata=wrq:create(Method,Version,RawPath,Headers)}, + reqdata=wrq:create(Method,Scheme,Version,RawPath,Headers)}, InitReq = {webmachine_request,InitState}, {Peer, ReqState} = InitReq:get_peer(), diff --git a/src/webmachine_decision_core.erl b/src/webmachine_decision_core.erl index de0c4231..3438b40d 100644 --- a/src/webmachine_decision_core.erl +++ b/src/webmachine_decision_core.erl @@ -429,7 +429,16 @@ decision(v3n11) -> case is_list(NewPath) of false -> error_response("create_path not a string"); true -> - wrcall({set_disp_path, NewPath}), + BaseUri = case resource_call(base_uri) of + undefined -> wrcall(base_uri); + Any -> Any + end, + FullPath = wrcall({set_disp_path, filename:join([wrcall(path), NewPath])}), + case wrcall({get_resp_header, "Location"}) of + undefined -> wrcall({set_resp_header, "Location", BaseUri ++ FullPath}); + _ -> ok + end, + Res = accept_helper(), case Res of {respond, Code} -> respond(Code); @@ -665,4 +674,3 @@ variances() -> end end, Accept ++ AcceptEncoding ++ AcceptCharset ++ resource_call(variances). - diff --git a/src/webmachine_request.erl b/src/webmachine_request.erl index fe48a2c9..7d1b64d8 100644 --- a/src/webmachine_request.erl +++ b/src/webmachine_request.erl @@ -121,6 +121,12 @@ x_peername(Default) -> string:strip(lists:last(string:tokens(Hosts, ","))) end. +call(base_uri) -> + RD = ReqState#wm_reqstate.reqdata, + Scheme = erlang:atom_to_list(RD#wm_reqdata.scheme), + Host = string:join(RD#wm_reqdata.host_tokens, "."), + PortString = port_string(Scheme, RD#wm_reqdata.port), + {Scheme ++ "://" ++ Host ++ PortString ++ "/",ReqState}; call(socket) -> {ReqState#wm_reqstate.socket,ReqState}; call(get_reqdata) -> {ReqState#wm_reqstate.reqdata, ReqState}; call({set_reqdata, RD}) -> {ok, ReqState#wm_reqstate{reqdata=RD}}; @@ -792,3 +798,18 @@ load_dispatch_data(Bindings, HostTokens, Port, PathTokens, PathTokens, AppRoot, DispPath}). log_data() -> call(log_data). + +port_string(Scheme, Port) -> + case Scheme of + http -> + case Port of + 80 -> ""; + _ -> ":" ++ erlang:integer_to_list(Port) + end; + https -> + case Port of + 443 -> ""; + _ -> ":" ++ erlang:integer_to_list(Port) + end; + _ -> ":" ++ erlang:integer_to_list(Port) + end. diff --git a/src/webmachine_resource.erl b/src/webmachine_resource.erl index 6f330f95..d215aff3 100644 --- a/src/webmachine_resource.erl +++ b/src/webmachine_resource.erl @@ -65,6 +65,8 @@ default(post_is_create) -> false; default(create_path) -> undefined; +default(base_uri) -> + undefined; default(process_post) -> false; default(language_available) -> diff --git a/src/wrq.erl b/src/wrq.erl index 0e0ccaf5..80459b2a 100644 --- a/src/wrq.erl +++ b/src/wrq.erl @@ -16,11 +16,11 @@ -module(wrq). -author('Justin Sheehy '). --export([create/4,load_dispatch_data/7]). --export([method/1,version/1,peer/1,disp_path/1,path/1,raw_path/1,path_info/1, - response_code/1,req_cookie/1,req_qs/1,req_headers/1,req_body/1, - stream_req_body/2,resp_redirect/1,resp_headers/1,resp_body/1, - app_root/1,path_tokens/1, host_tokens/1, port/1]). +-export([create/4, create/5,load_dispatch_data/7]). +-export([method/1,scheme/1,version/1,peer/1,disp_path/1,path/1,raw_path/1, + path_info/1,response_code/1,req_cookie/1,req_qs/1,req_headers/1, + req_body/1,stream_req_body/2,resp_redirect/1,resp_headers/1, + resp_body/1,app_root/1,path_tokens/1, host_tokens/1, port/1]). -export([path_info/2,get_req_header/2,do_redirect/2,fresh_resp_headers/2, get_resp_header/2,set_resp_header/3,set_resp_headers/2, set_disp_path/2,set_req_body/2,set_resp_body/2,set_response_code/2, @@ -36,7 +36,9 @@ create(Method,Version,RawPath,Headers) -> - create(#wm_reqdata{method=Method,version=Version, + create(Method,http,Version,RawPath,Headers). +create(Method,Scheme,Version,RawPath,Headers) -> + create(#wm_reqdata{method=Method,scheme=Scheme,version=Version, raw_path=RawPath,req_headers=Headers, wm_state=defined_on_call, path="defined_in_create", @@ -71,6 +73,8 @@ load_dispatch_data(PathInfo, HostTokens, Port, PathTokens, AppRoot, method(_RD = #wm_reqdata{method=Method}) -> Method. +scheme(_RD = #wm_reqdata{scheme=Scheme}) -> Scheme. + version(_RD = #wm_reqdata{version=Version}) when is_tuple(Version), size(Version) == 2, is_integer(element(1,Version)), is_integer(element(2,Version)) -> Version. From 89f19b288fb0bbd024df25c65cfc5713414af331 Mon Sep 17 00:00:00 2001 From: b Date: Tue, 7 Jun 2011 14:35:18 -0700 Subject: [PATCH 2/6] Use full path correctly --- src/webmachine_decision_core.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/webmachine_decision_core.erl b/src/webmachine_decision_core.erl index 3438b40d..a2bd3118 100644 --- a/src/webmachine_decision_core.erl +++ b/src/webmachine_decision_core.erl @@ -433,7 +433,8 @@ decision(v3n11) -> undefined -> wrcall(base_uri); Any -> Any end, - FullPath = wrcall({set_disp_path, filename:join([wrcall(path), NewPath])}), + FullPath = filename:join([wrcall(path), NewPath]), + wrcall({set_disp_path, FullPath}), case wrcall({get_resp_header, "Location"}) of undefined -> wrcall({set_resp_header, "Location", BaseUri ++ FullPath}); _ -> ok From 76f61f623ff78279f9bdea1f2b0163b2b0422867 Mon Sep 17 00:00:00 2001 From: b Date: Tue, 7 Jun 2011 15:15:04 -0700 Subject: [PATCH 3/6] Don't put a trailing slash on the default base uri --- src/webmachine_request.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webmachine_request.erl b/src/webmachine_request.erl index 7d1b64d8..80b5711d 100644 --- a/src/webmachine_request.erl +++ b/src/webmachine_request.erl @@ -126,7 +126,7 @@ call(base_uri) -> Scheme = erlang:atom_to_list(RD#wm_reqdata.scheme), Host = string:join(RD#wm_reqdata.host_tokens, "."), PortString = port_string(Scheme, RD#wm_reqdata.port), - {Scheme ++ "://" ++ Host ++ PortString ++ "/",ReqState}; + {Scheme ++ "://" ++ Host ++ PortString,ReqState}; call(socket) -> {ReqState#wm_reqstate.socket,ReqState}; call(get_reqdata) -> {ReqState#wm_reqstate.reqdata, ReqState}; call({set_reqdata, RD}) -> {ok, ReqState#wm_reqstate{reqdata=RD}}; From 7f15e1c88893e16c44a24bb93d3d18b85dd1f3b1 Mon Sep 17 00:00:00 2001 From: b Date: Tue, 7 Jun 2011 15:15:23 -0700 Subject: [PATCH 4/6] Strip trailing slash from user-provided base uri, if present --- src/webmachine_decision_core.erl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/webmachine_decision_core.erl b/src/webmachine_decision_core.erl index a2bd3118..3a50d298 100644 --- a/src/webmachine_decision_core.erl +++ b/src/webmachine_decision_core.erl @@ -431,7 +431,12 @@ decision(v3n11) -> true -> BaseUri = case resource_call(base_uri) of undefined -> wrcall(base_uri); - Any -> Any + Any -> + case lists:last(Any) of + % 47 is "/" + 47 -> lists:sublist(Any, erlang:length(Any) - 1); + _ -> Any + end end, FullPath = filename:join([wrcall(path), NewPath]), wrcall({set_disp_path, FullPath}), From 76d09eb0df9eca640a505cd128e199464b959f6b Mon Sep 17 00:00:00 2001 From: b Date: Tue, 7 Jun 2011 15:54:04 -0700 Subject: [PATCH 5/6] Make sure location path always has a slash at the front --- src/webmachine_decision_core.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webmachine_decision_core.erl b/src/webmachine_decision_core.erl index 3a50d298..54bc9797 100644 --- a/src/webmachine_decision_core.erl +++ b/src/webmachine_decision_core.erl @@ -438,7 +438,7 @@ decision(v3n11) -> _ -> Any end end, - FullPath = filename:join([wrcall(path), NewPath]), + FullPath = filename:join(["/", wrcall(path), NewPath]), wrcall({set_disp_path, FullPath}), case wrcall({get_resp_header, "Location"}) of undefined -> wrcall({set_resp_header, "Location", BaseUri ++ FullPath}); From b8afa6a07d97bf81cdae3c69d80dd8c0969fe931 Mon Sep 17 00:00:00 2001 From: b Date: Tue, 7 Jun 2011 16:34:19 -0700 Subject: [PATCH 6/6] A more readable version of trailing slash stripping --- src/webmachine_decision_core.erl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/webmachine_decision_core.erl b/src/webmachine_decision_core.erl index 54bc9797..e12d687e 100644 --- a/src/webmachine_decision_core.erl +++ b/src/webmachine_decision_core.erl @@ -432,9 +432,8 @@ decision(v3n11) -> BaseUri = case resource_call(base_uri) of undefined -> wrcall(base_uri); Any -> - case lists:last(Any) of - % 47 is "/" - 47 -> lists:sublist(Any, erlang:length(Any) - 1); + case [lists:last(Any)] of + "/" -> lists:sublist(Any, erlang:length(Any) - 1); _ -> Any end end,