Permalink
Browse files

cleaned up the redirect feature. It was poorly implemented and poorly…

… documented. This fix is backwards compatible for users using redirect in confd.conf. However, it is NOT backwards compatible for embedded users that specify the redirect_map explicitly in their #sconf{} records. The required changes for embedded users should be evident from the code. The new required format is documented in the code where #sconf{} is defined

git-svn-id: https://erlyaws.svn.sourceforge.net/svnroot/erlyaws/trunk/yaws@1391 9fbdc01b-0d2c-0410-bfb7-fb27d70d8b52
  • Loading branch information...
1 parent 1fd27af commit 814bae12cb0f2d39b3220515037e2439d70b1466 @klacke committed Feb 13, 2009
Showing with 145 additions and 71 deletions.
  1. +4 −1 include/yaws.hrl
  2. +2 −2 include/yaws_api.hrl
  3. +2 −1 man/yaws.1
  4. +48 −8 man/yaws.conf.5
  5. +10 −1 src/yaws.erl
  6. +42 −13 src/yaws_api.erl
  7. +20 −12 src/yaws_config.erl
  8. +17 −33 src/yaws_server.erl
View
@@ -157,7 +157,10 @@
-record(sconf,
{port = 8000, %% which port is this server listening to
flags = ?SC_DEF,
- redirect_map=[], %% redirect all requests to HostPort
+ redirect_map=[], %% a list of
+ %% {Prefix, #url{}, append|noappend}
+ %% #url{} can be partially populated
+
rhost, %% forced redirect host (+ optional port)
rmethod, %% forced redirect method
docroot, %% path to the docs
View
@@ -75,8 +75,8 @@
-record(url,
- {scheme,
- host,
+ {scheme, %% undefined means not set
+ host, %% undefined means not set
port, %% undefined means not set
path = [],
querypart = []}).
View
@@ -23,7 +23,8 @@ mode. Use this when developing yaws code.
.TP
\fB\-w | --winteractive\fR
Cygwin inteactive mode (werl)
-\fB\--daemon\fR
+.TP
+\fB\-D | --daemon\fR
Daemon mode. This will start yaws as a daemon.
.TP
\fB\--heart\fR
View
@@ -268,8 +268,10 @@ in each chunk is determined by the this parameter.
The deafult value is 10240.
.TP
-\fB dav = true | false\fR
-Turns on the DAV protocol for this server.
+\fBdav = true | false\fR
+Turns on the DAV protocol for this server. The dav support
+in yaws is highly limited. If dav is turned on, .yaws processing
+of .yaws pages is turned off.
.TP
\fBtilde_expand = true|false \fR
@@ -428,12 +430,50 @@ Ends an SSL definition
Defines an redirect mapping. The following items are allowed
within a matching pair of <redirect> and </redirect> delimiters.
-.TP
-\fBPath = [Scheme://]Host[:Port]\fR
-All accesses to Path will be redirected to [Scheme://]Host[:Port]Path.
-Scheme and Port is optional. The default is to use the servers scheme
-and port, rsheme and rport will be used if defined. To redirect
-all references to a site use "/" as Path.
+We can have a series of
+
+\fB Path = URL\fR or
+
+\fB Path = file\fR
+
+All accesses to Path will be redirected to URL/Path or alternatively
+to scheme:host:port/file/Path if a file is used. Note that the original
+path is appended to the redirected url. So if we for example have:
+
+.nf
+<redirect>
+ /foo = http://www.mysite.org/zapp
+ /bar = /tomato.html
+</redirect>
+.fi
+
+Asumming this config resides on a site called http://abc.com,
+We have the following redirects:
+
+http://abc.com/foo -> http://www.mysite.org/zapp/foo
+
+http://abc.com/foo/test -> http://www.mysite.org/zapp/foo/test
+
+http://abc.com/bar -> http://abc.com/bar
+
+http://abc.com/bar/x/y/z -> http://abc.com/bar/x/y/z
+
+Sometimes we do not want to have the original path
+appended to the redirected path. To get that behaviour we
+specify the config with '==' instead of '='.
+
+<redirect>
+ /foo == http://www.mysite.org/zapp
+ /bar = /tomato.html
+</redirect>
+
+Now a request for http://abc.com/foo/x/y/z simply gets redirected
+to http://www.mysite.org/zapp. This is typically used when we simply
+want a static redirect at some place in the docroot.
+
+When we specify a file as target for the redirect, the redir will
+be to the current http(s) server.
+
.TP
\fB<auth> ... </auth>\fR
View
@@ -99,7 +99,7 @@
-export([sconf_to_srvstr/1,
redirect_host/2, redirect_port/1,
redirect_scheme_port/1, redirect_scheme/1,
- tmpdir/0,
+ tmpdir/0, split_at/2,
id_dir/1, ctl_file/1]).
@@ -2189,3 +2189,12 @@ get_chunk(Fd, N, Asz,SSL) ->
exit(normal)
end.
+%% split inputstring at first occurrence of Char
+split_at(String, Char) ->
+ split_at(String, Char, []).
+split_at([H|T], H, Ack) ->
+ {lists:reverse(Ack), T};
+split_at([H|T], Char, Ack) ->
+ split_at(T, Char, [H|Ack]);
+split_at([], _Char, Ack) ->
+ {lists:reverse(Ack), []}.
View
@@ -26,7 +26,8 @@
htmlize/1, htmlize_char/1, f/2, fl/1]).
-export([find_cookie_val/2, secs/0,
url_decode/1, url_decode_q_split/1,
- url_encode/1, parse_url/1, parse_url/2, format_url/1]).
+ url_encode/1, parse_url/1, parse_url/2, format_url/1,
+ format_partial_url/2]).
-export([is_absolute_URI/1]).
-export([path_norm/1, path_norm_reverse/1,
sanitize_file_name/1]).
@@ -1070,7 +1071,7 @@ parse_url(Str, Strict) ->
"file://" ++ Rest ->
parse_url(host, Strict, #url{scheme = file}, Rest, []);
_ when Strict == sloppy ->
- parse_url(host, Strict, #url{scheme = http}, Str, [])
+ parse_url(host, Strict, #url{scheme = undefined}, Str, [])
end.
@@ -1112,9 +1113,46 @@ parse_url(path, Strict, U, Str, Ack) ->
end.
+%% used to construct redir headers from partial URLs such
+%% as e.g. /foo/bar
+
+format_partial_url(Url, SC) ->
+ [if
+ Url#url.scheme == undefined ->
+ yaws:redirect_scheme(SC);
+ true ->
+ yaws:to_string(Url#url.scheme) ++ "://"
+ end,
+ if
+ Url#url.host == undefined ->
+ yaws:redirect_host(SC, undefined);
+ true ->
+ Url#url.host
+ end,
+ if
+ Url#url.port == undefined ->
+ yaws:redirect_port(SC);
+ true ->
+ [$: | integer_to_list(Url#url.port)]
+ end,
+ Url#url.path,
+ if
+ Url#url.querypart == [] ->
+ [];
+ true ->
+ [$?|Url#url.querypart]
+ end
+ ].
+
+
format_url(Url) when record(Url, url) ->
[
- yaws:to_string(Url#url.scheme), "://",
+ if
+ Url#url.scheme == undefined ->
+ "http://";
+ true ->
+ yaws:to_string(Url#url.scheme) ++ "://"
+ end,
Url#url.host,
if
Url#url.port == undefined ->
@@ -1669,15 +1707,6 @@ binding_exists(Key) ->
_ -> true
end.
-%% split inputstring at first occurrence of Char
-split_at(String, Char) ->
- split_at(String, Char, []).
-split_at([H|T], H, Ack) ->
- {lists:reverse(Ack), T};
-split_at([H|T], Char, Ack) ->
- split_at(T, Char, [H|Ack]);
-split_at([], _Char, Ack) ->
- {[], lists:reverse(Ack)}.
%% Return the parsed url that the client requested.
@@ -1686,7 +1715,7 @@ request_url(ARG) ->
Headers = ARG#arg.headers,
{abs_path, Path} = (ARG#arg.req)#http_request.path,
DecPath = url_decode(Path),
- {P,Q} = split_at(DecPath, $?),
+ {P,Q} = yaws:split_at(DecPath, $?),
#url{scheme = case SC#sconf.ssl of
undefined ->
"http";
View
@@ -1068,20 +1068,28 @@ fload(FD, server_redirect, _GC, _C, _Cs, Lno, eof, _RedirMap) ->
fload(FD, server_redirect, GC, C, Cs, Lno, Chars, RedirMap) ->
%%?Debug("Chars: ~s", [Chars]),
Next = io:get_line(FD, ''),
- case toks(Chars) of
+ Toks = toks(Chars),
+ case Toks of
[] ->
fload(FD, server_redirect, GC, C, Cs, Lno+1, Next, RedirMap);
- [Path, '=', MethodHostPort] ->
- Entry = case MethodHostPort of
- "http://"++HostPort ->
- {Path, "http://", HostPort};
- "https://"++HostPort ->
- {Path, "https://", HostPort};
- HostPort ->
- {Path, HostPort}
- end,
- fload(FD, server_redirect, GC, C, Cs, Lno+1, Next,
- [Entry|RedirMap]);
+ [Path, '=', URL] ->
+ io:format(" = ~p ~p~n", [URL, Toks]),
+ try yaws_api:parse_url(URL, sloppy) of
+ U when record(U, url) ->
+ fload(FD, server_redirect, GC, C, Cs, Lno+1, Next,
+ [{Path, U, append}|RedirMap])
+ catch _:_ ->
+ {error, ?F("bad redir ~p at line ~w", [URL, Lno])}
+ end;
+ [Path, '=', '=', URL] ->
+ io:format(" == ~p~n", [URL]),
+ try yaws_api:parse_url(URL, sloppy) of
+ U when record(U, url) ->
+ fload(FD, server_redirect, GC, C, Cs, Lno+1, Next,
+ [{Path, U, noappend}|RedirMap])
+ catch _:_ ->
+ {error, ?F("Bad redir ~p at line ~w", [URL, Lno])}
+ end;
['<', "/redirect", '>'] ->
C2 = C#sconf{redirect_map = lists:reverse(RedirMap)},
fload(FD, server, GC, C2, Cs, Lno+1, Next);
View
@@ -1464,7 +1464,6 @@ handle_request(CliSock, ARG, N) ->
IsRev = is_revproxy(DecPath, SC#sconf.revproxy),
IsRedirect = is_redirect_map(DecPath,
SC#sconf.redirect_map),
-
case {IsAuth, IsRev, IsRedirect} of
{{appmod, Mod}, _, _} ->
%%This isn't the standard 'appmod' branch
@@ -1488,9 +1487,8 @@ handle_request(CliSock, ARG, N) ->
appmoddata=undefined
},
handle_ut(CliSock, ARG2, UT, N);
- {_, _, {true, MethodHostPort}} ->
- deliver_302_map(CliSock, Req, ARG1,
- MethodHostPort);
+ {_, _, {true, Redir}} ->
+ deliver_302_map(CliSock, Req, ARG1, Redir);
{true, false, _} ->
%%'main' branch so to speak. Most
%% requests pass through here.
@@ -1628,14 +1626,7 @@ is_revproxy(Path, [{Prefix, URL} | Tail]) ->
is_redirect_map(_, []) ->
false;
-is_redirect_map(Path, [E={Prefix, _}|Tail]) ->
- case yaws:is_prefix(Prefix, Path) of
- {true, _} ->
- {true, E};
- false ->
- is_redirect_map(Path, Tail)
- end;
-is_redirect_map(Path, [E={Prefix,_,_}|Tail]) ->
+is_redirect_map(Path, [E={Prefix, _URL, _AppendMode}|Tail]) ->
case yaws:is_prefix(Prefix, Path) of
{true, _} ->
{true, E};
@@ -1644,8 +1635,6 @@ is_redirect_map(Path, [E={Prefix,_,_}|Tail]) ->
end.
-
-
%% Return values:
%% continue, done, {page, Page}
@@ -1914,31 +1903,26 @@ deliver_302(CliSock, _Req, Arg, Path) ->
deliver_accumulated(CliSock),
done_or_continue().
-
-deliver_302_map(CliSock, Req, Arg, MethodHostPort) ->
+
+deliver_302_map(CliSock, Req, Arg,
+ {_Prefix,URL,Mode}) when is_record(URL,url) ->
?Debug("in redir 302 ",[]),
H = get(outh),
- SC=get(sc),
DecPath = safe_decode_path(Req#http_request.path),
- {Scheme, RedirHost} =
- case MethodHostPort of
- {_,Method,HostPort} ->
- {Method, HostPort};
- {_,HostPort} ->
- {yaws:redirect_scheme(SC), HostPort}
- end,
- Loc = case string:tokens(DecPath, "?") of
- [P] ->
- ["Location: ", Scheme, RedirHost, P, "\r\n"];
- [P, Q] ->
- ["Location: ", Scheme, RedirHost, P, "?", Q, "\r\n"]
+ {P, Q} = yaws:split_at(DecPath, $?),
+ LocPath = yaws_api:format_partial_url(URL, get(sc)),
+ Loc = if
+ Mode == append, Q == [] ->
+ ["Location: ", LocPath, P, "\r\n"];
+ Mode == append, Q /= [] ->
+ ["Location: ", LocPath, P, "?", Q, "\r\n"];
+ Mode == noappend,Q == [] ->
+ ["Location: ", LocPath, "\r\n"];
+ Mode == noappend,Q /= [] ->
+ ["Location: ", LocPath, "?", Q, "\r\n"]
end,
-
-
Headers = Arg#arg.headers,
-
{DoClose, _Chunked} = yaws:dcc(Req, Headers),
-
new_redir_h(H#outh{
connection = yaws:make_connection_close_header(DoClose),
doclose = DoClose,

0 comments on commit 814bae1

Please sign in to comment.