1%% ``Licensed under the Apache License, Version 2.0 (the "License");
2%% you may not use this file except in compliance with the License.
3%% You may obtain a copy of the License at
4%%
5%%     http://www.apache.org/licenses/LICENSE-2.0
6%%
7%% Unless required by applicable law or agreed to in writing, software
8%% distributed under the License is distributed on an "AS IS" BASIS,
9%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10%% See the License for the specific language governing permissions and
11%% limitations under the License.
12%%
13%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
14%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
15%% AB. All Rights Reserved.''
16%%
17%%     $Id: mod_alias.erl,v 1.1 2008/12/17 09:53:34 mikpe Exp $
18%%
19-module(mod_alias).
20-export([do/1,real_name/3,real_script_name/3,default_index/2,load/2,path/3]).
21
22-include("httpd.hrl").
23
24%% do
25
26do(Info) ->
27    ?DEBUG("do -> entry",[]),
28    case httpd_util:key1search(Info#mod.data,status) of
29	%% A status code has been generated!
30	{StatusCode,PhraseArgs,Reason} ->
31	    {proceed,Info#mod.data};
32	%% No status code has been generated!
33	undefined ->
34	    case httpd_util:key1search(Info#mod.data,response) of
35		%% No response has been generated!
36		undefined ->
37		    do_alias(Info);
38		%% A response has been generated or sent!
39		Response ->
40		    {proceed,Info#mod.data}
41	    end
42    end.
43
44do_alias(Info) ->
45    ?DEBUG("do_alias -> Request URI: ~p",[Info#mod.request_uri]),
46    {ShortPath,Path,AfterPath} =
47	real_name(Info#mod.config_db,Info#mod.request_uri,
48		  httpd_util:multi_lookup(Info#mod.config_db,alias)),
49    %% Relocate if a trailing slash is missing else proceed!
50    LastChar = lists:last(ShortPath),
51    case file:read_file_info(ShortPath) of
52	{ok,FileInfo} when FileInfo#file_info.type == directory,LastChar /= $/ ->
53	    ?LOG("do_alias -> ~n"
54		 "      ShortPath: ~p~n"
55		 "      LastChar:  ~p~n"
56		 "      FileInfo:  ~p",
57		 [ShortPath,LastChar,FileInfo]),
58	    ServerName = httpd_util:lookup(Info#mod.config_db,server_name),
59	    Port = port_string(httpd_util:lookup(Info#mod.config_db,port,80)),
60	    URL = "http://"++ServerName++Port++Info#mod.request_uri++"/",
61	    ReasonPhrase = httpd_util:reason_phrase(301),
62	    Message = httpd_util:message(301,URL,Info#mod.config_db),
63	    {proceed,
64	     [{response,
65	       {301, ["Location: ", URL, "\r\n"
66		      "Content-Type: text/html\r\n",
67		      "\r\n",
68		      "<HTML>\n<HEAD>\n<TITLE>",ReasonPhrase,
69		      "</TITLE>\n</HEAD>\n"
70		      "<BODY>\n<H1>",ReasonPhrase,
71		      "</H1>\n", Message,
72		      "\n</BODY>\n</HTML>\n"]}}|
73	      [{real_name,{Path,AfterPath}}|Info#mod.data]]};
74	NoFile ->
75	    {proceed,[{real_name,{Path,AfterPath}}|Info#mod.data]}
76    end.
77
78port_string(80) ->
79    "";
80port_string(Port) ->
81    ":"++integer_to_list(Port).
82
83%% real_name
84
85real_name(ConfigDB, RequestURI,[]) ->
86    DocumentRoot = httpd_util:lookup(ConfigDB, document_root, ""),
87    RealName = DocumentRoot++RequestURI,
88    {ShortPath, _AfterPath} = httpd_util:split_path(RealName),
89    {Path, AfterPath}=httpd_util:split_path(default_index(ConfigDB,RealName)),
90    {ShortPath, Path, AfterPath};
91real_name(ConfigDB, RequestURI, [{FakeName,RealName}|Rest]) ->
92    case regexp:match(RequestURI, "^"++FakeName) of
93	{match, _, _} ->
94	    {ok, ActualName, _} = regexp:sub(RequestURI,
95					     "^"++FakeName, RealName),
96	    {ShortPath, _AfterPath} = httpd_util:split_path(ActualName),
97	    {Path, AfterPath} =
98		httpd_util:split_path(default_index(ConfigDB, ActualName)),
99	    {ShortPath, Path, AfterPath};
100	nomatch ->
101	    real_name(ConfigDB,RequestURI,Rest)
102    end.
103
104%% real_script_name
105
106real_script_name(ConfigDB,RequestURI,[]) ->
107    not_a_script;
108real_script_name(ConfigDB,RequestURI,[{FakeName,RealName}|Rest]) ->
109    case regexp:match(RequestURI,"^"++FakeName) of
110	{match,_,_} ->
111	    {ok,ActualName,_}=regexp:sub(RequestURI,"^"++FakeName,RealName),
112	    httpd_util:split_script_path(default_index(ConfigDB,ActualName));
113	nomatch ->
114	    real_script_name(ConfigDB,RequestURI,Rest)
115    end.
116
117%% default_index
118
119default_index(ConfigDB, Path) ->
120    case file:read_file_info(Path) of
121	{ok, FileInfo} when FileInfo#file_info.type == directory ->
122	    DirectoryIndex = httpd_util:lookup(ConfigDB, directory_index, []),
123	    append_index(Path, DirectoryIndex);
124	_ ->
125	    Path
126    end.
127
128append_index(RealName, []) ->
129    RealName;
130append_index(RealName, [Index|Rest]) ->
131    case file:read_file_info(filename:join(RealName, Index)) of
132	{error,Reason} ->
133	    append_index(RealName, Rest);
134	_ ->
135	    filename:join(RealName,Index)
136    end.
137
138%% path
139
140path(Data, ConfigDB, RequestURI) ->
141    case httpd_util:key1search(Data,real_name) of
142	undefined ->
143	    DocumentRoot = httpd_util:lookup(ConfigDB, document_root, ""),
144	    {Path,AfterPath} =
145		httpd_util:split_path(DocumentRoot++RequestURI),
146	    Path;
147	{Path,AfterPath} ->
148	    Path
149    end.
150
151%%
152%% Configuration
153%%
154
155%% load
156
157load([$D,$i,$r,$e,$c,$t,$o,$r,$y,$I,$n,$d,$e,$x,$ |DirectoryIndex],[]) ->
158    {ok, DirectoryIndexes} = regexp:split(DirectoryIndex," "),
159    {ok,[], {directory_index, DirectoryIndexes}};
160load([$A,$l,$i,$a,$s,$ |Alias],[]) ->
161    case regexp:split(Alias," ") of
162	{ok, [FakeName, RealName]} ->
163	    {ok,[],{alias,{FakeName,RealName}}};
164	{ok, _} ->
165	    {error,?NICE(httpd_conf:clean(Alias)++" is an invalid Alias")}
166    end;
167load([$S,$c,$r,$i,$p,$t,$A,$l,$i,$a,$s,$ |ScriptAlias],[]) ->
168    case regexp:split(ScriptAlias," ") of
169	{ok, [FakeName, RealName]} ->
170	    %% Make sure the path always has a trailing slash..
171	    RealName1 = filename:join(filename:split(RealName)),
172	    {ok, [], {script_alias,{FakeName, RealName1++"/"}}};
173	{ok, _} ->
174	    {error, ?NICE(httpd_conf:clean(ScriptAlias)++
175			  " is an invalid ScriptAlias")}
176    end.
177