1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20%%
21
22-module(httpd_script_env).
23
24-export([create_env/3]).
25
26-include("httpd.hrl").
27-include("httpd_internal.hrl").
28
29%%%=========================================================================
30%%%  Internal application API
31%%%=========================================================================
32%%--------------------------------------------------------------------------
33%% create_env(ScriptType, ModData, ScriptElements) -> [{EnvVariable, Value}]
34%%
35%%	ScriptType = cgi | esi
36%%	ModData = #mod{}
37%%      ScriptElements = [{Element, Value}]
38%%      Element = path_info | query_string | entity_body
39%%      Value = term()
40%%      EnvVariable = string() - cgi | atom() - esi
41%%
42%% Description: Creates a list of cgi/esi environment variables and
43%% there values.
44%%--------------------------------------------------------------------------
45create_env(ScriptType, ModData, ScriptElements) ->
46    create_basic_elements(ScriptType, ModData)
47	++ create_http_header_elements(ScriptType, ModData#mod.parsed_header)
48	++ create_script_elements(ScriptType, ModData, ScriptElements)
49	++ create_mod_interaction_elements(ScriptType, ModData).
50
51%%%========================================================================
52%%% Internal functions
53%%%========================================================================
54
55which_server(#mod{config_db = ConfigDb}) ->
56    httpd_util:lookup(ConfigDb, server, ?SERVER_SOFTWARE).
57
58which_port(#mod{config_db = ConfigDb}) ->
59    httpd_util:lookup(ConfigDb, port, 80).
60
61which_peername(#mod{init_data = #init_data{peername = {_, RemoteAddr}}}) ->
62    RemoteAddr.
63
64which_peercert(#mod{socket_type = {Type, _}, socket = Socket}) when Type == essl;
65								    Type == ssl ->
66    case ssl:peercert(Socket) of
67	{ok, Cert} ->
68	    Cert;
69	{error, no_peercert} ->
70	    no_peercert;
71	_  ->
72	    undefined
73    end;
74which_peercert(_) -> %% Not an ssl connection
75    undefined.
76
77
78which_resolve(#mod{init_data = #init_data{resolve = Resolve}}) ->
79    Resolve.
80
81which_name(#mod{config_db = ConfigDB}) ->
82    httpd_util:lookup(ConfigDB, server_name).
83
84which_method(#mod{method = Method}) ->
85    Method.
86
87which_request_uri(#mod{request_uri = RUri}) ->
88    RUri.
89
90create_basic_elements(esi, ModData) ->
91    [{server_software,   which_server(ModData)},
92     {server_name,       which_name(ModData)},
93     {host_name,         which_resolve(ModData)},
94     {gateway_interface, ?GATEWAY_INTERFACE},
95     {server_protocol,   ?SERVER_PROTOCOL},
96     {server_port,       which_port(ModData)},
97     {request_method,    which_method(ModData)},
98     {remote_addr,       which_peername(ModData)},
99     {peer_cert,         which_peercert(ModData)},
100     {script_name,       which_request_uri(ModData)}];
101
102create_basic_elements(cgi, ModData) ->
103    [{"SERVER_SOFTWARE",   which_server(ModData)},
104     {"SERVER_NAME",       which_name(ModData)},
105     {"HOST_NAME",         which_resolve(ModData)},
106     {"GATEWAY_INTERFACE", ?GATEWAY_INTERFACE},
107     {"SERVER_PROTOCOL",   ?SERVER_PROTOCOL},
108     {"SERVER_PORT",       integer_to_list(which_port(ModData))},
109     {"REQUEST_METHOD",    which_method(ModData)},
110     {"REMOTE_ADDR",       which_peername(ModData)},
111     {"SCRIPT_NAME",       which_request_uri(ModData)}].
112
113create_http_header_elements(ScriptType, Headers) ->
114    create_http_header_elements(ScriptType, Headers, []).
115
116create_http_header_elements(_, [], Acc) ->
117    Acc;
118create_http_header_elements(ScriptType, [{Name, [Value | _] = Values } |
119					 Headers], Acc)
120  when is_list(Value) ->
121    NewName = lists:map(fun(X) -> if X == $- -> $_; true -> X end end, Name),
122    Element = http_env_element(ScriptType, NewName, multi_value(Values)),
123    create_http_header_elements(ScriptType, Headers, [Element | Acc]);
124
125create_http_header_elements(ScriptType, [{Name, Value} | Headers], Acc)
126  when is_list(Value) ->
127    NewName = re:replace(Name,"-","_", [{return,list}, global]),
128    Element = http_env_element(ScriptType, NewName, Value),
129    create_http_header_elements(ScriptType, Headers, [Element | Acc]).
130
131http_env_element(cgi, VarName, Value)  ->
132    {"HTTP_"++ http_util:to_upper(VarName), Value};
133http_env_element(esi, VarName, Value)  ->
134    {list_to_atom("http_"++ http_util:to_lower(VarName)), Value}.
135
136multi_value([]) ->
137  [];
138multi_value([Value]) ->
139  Value;
140multi_value([Value | Rest]) ->
141  Value ++ ", " ++ multi_value(Rest).
142
143create_script_elements(ScriptType, ModData, ScriptElements) ->
144    lists:flatmap(fun({Element, Data}) ->
145			  create_script_elements(ScriptType,
146						 Element,
147						 Data, ModData)
148		  end, ScriptElements).
149
150create_script_elements(esi, query_string, QueryString, _) ->
151    [{query_string, QueryString}];
152create_script_elements(cgi, query_string, QueryString, _) ->
153    [{"QUERY_STRING", QueryString}];
154create_script_elements(esi, path_info, PathInfo, ModData) ->
155    Aliases = httpd_util:multi_lookup(ModData#mod.config_db, alias),
156    {_,PathTranslated,_} =
157	mod_alias:real_name(ModData#mod.config_db, PathInfo,
158			    Aliases),
159    [{path_info, PathInfo},
160     {path_translated, PathTranslated}];
161create_script_elements(cgi, path_info, PathInfo, ModData) ->
162    Aliases = httpd_util:multi_lookup(ModData#mod.config_db, alias),
163    {_,PathTranslated,_} =
164	mod_alias:real_name(ModData#mod.config_db, PathInfo,
165			    Aliases),
166    [{"PATH_INFO", PathInfo},
167     {"PATH_TRANSLATED", PathTranslated}];
168create_script_elements(esi, entity_body, Body, _) ->
169    [{content_length, integer_to_list(httpd_util:flatlength(Body))}];
170create_script_elements(cgi, entity_body, Body, _) ->
171    [{"CONTENT_LENGTH", integer_to_list(httpd_util:flatlength(Body))}];
172create_script_elements(_, _, _, _) ->
173    [].
174
175create_mod_interaction_elements(_, ModData)->
176    case proplists:get_value(remote_user, ModData#mod.data) of
177	undefined ->
178	    [];
179	RemoteUser ->
180	    [{remote_user, RemoteUser}]
181    end.
182