%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
%%
-module(httpd_script_env).
-export([create_env/3]).
-include("httpd.hrl").
-include("httpd_internal.hrl").
%%%=========================================================================
%%% Internal application API
%%%=========================================================================
%%--------------------------------------------------------------------------
%% create_env(ScriptType, ModData, ScriptElements) -> [{EnvVariable, Value}]
%%
%% ScriptType = cgi | esi
%% ModData = #mod{}
%% ScriptElements = [{Element, Value}]
%% Element = path_info | query_string | entity_body
%% Value = term()
%% EnvVariable = string() - cgi | atom() - esi
%%
%% Description: Creates a list of cgi/esi environment variables and
%% there values.
%%--------------------------------------------------------------------------
create_env(ScriptType, ModData, ScriptElements) ->
create_basic_elements(ScriptType, ModData)
++ create_http_header_elements(ScriptType, ModData#mod.parsed_header)
++ create_script_elements(ScriptType, ModData, ScriptElements)
++ create_mod_interaction_elements(ScriptType, ModData).
%%%========================================================================
%%% Internal functions
%%%========================================================================
which_server(#mod{config_db = ConfigDb}) ->
httpd_util:lookup(ConfigDb, server, ?SERVER_SOFTWARE).
which_port(#mod{config_db = ConfigDb}) ->
httpd_util:lookup(ConfigDb, port, 80).
which_peername(#mod{init_data = #init_data{peername = {_, RemoteAddr}}}) ->
RemoteAddr.
which_peercert(#mod{socket_type = {Type, _}, socket = Socket}) when Type == essl;
Type == ssl ->
case ssl:peercert(Socket) of
{ok, Cert} ->
Cert;
{error, no_peercert} ->
no_peercert;
_ ->
undefined
end;
which_peercert(_) -> %% Not an ssl connection
undefined.
which_resolve(#mod{init_data = #init_data{resolve = Resolve}}) ->
Resolve.
which_name(#mod{config_db = ConfigDB}) ->
httpd_util:lookup(ConfigDB, server_name).
which_method(#mod{method = Method}) ->
Method.
which_request_uri(#mod{request_uri = RUri}) ->
RUri.
create_basic_elements(esi, ModData) ->
[{server_software, which_server(ModData)},
{server_name, which_name(ModData)},
{host_name, which_resolve(ModData)},
{gateway_interface, ?GATEWAY_INTERFACE},
{server_protocol, ?SERVER_PROTOCOL},
{server_port, which_port(ModData)},
{request_method, which_method(ModData)},
{remote_addr, which_peername(ModData)},
{peer_cert, which_peercert(ModData)},
{script_name, which_request_uri(ModData)}];
create_basic_elements(cgi, ModData) ->
[{"SERVER_SOFTWARE", which_server(ModData)},
{"SERVER_NAME", which_name(ModData)},
{"HOST_NAME", which_resolve(ModData)},
{"GATEWAY_INTERFACE", ?GATEWAY_INTERFACE},
{"SERVER_PROTOCOL", ?SERVER_PROTOCOL},
{"SERVER_PORT", integer_to_list(which_port(ModData))},
{"REQUEST_METHOD", which_method(ModData)},
{"REMOTE_ADDR", which_peername(ModData)},
{"SCRIPT_NAME", which_request_uri(ModData)}].
create_http_header_elements(ScriptType, Headers) ->
create_http_header_elements(ScriptType, Headers, []).
create_http_header_elements(_, [], Acc) ->
Acc;
create_http_header_elements(ScriptType, [{Name, [Value | _] = Values } |
Headers], Acc)
when is_list(Value) ->
NewName = lists:map(fun(X) -> if X == $- -> $_; true -> X end end, Name),
Element = http_env_element(ScriptType, NewName, multi_value(Values)),
create_http_header_elements(ScriptType, Headers, [Element | Acc]);
create_http_header_elements(ScriptType, [{Name, Value} | Headers], Acc)
when is_list(Value) ->
NewName = re:replace(Name,"-","_", [{return,list}, global]),
Element = http_env_element(ScriptType, NewName, Value),
create_http_header_elements(ScriptType, Headers, [Element | Acc]).
http_env_element(cgi, VarName, Value) ->
{"HTTP_"++ http_util:to_upper(VarName), Value};
http_env_element(esi, VarName, Value) ->
{list_to_atom("http_"++ http_util:to_lower(VarName)), Value}.
multi_value([]) ->
[];
multi_value([Value]) ->
Value;
multi_value([Value | Rest]) ->
Value ++ ", " ++ multi_value(Rest).
create_script_elements(ScriptType, ModData, ScriptElements) ->
lists:flatmap(fun({Element, Data}) ->
create_script_elements(ScriptType,
Element,
Data, ModData)
end, ScriptElements).
create_script_elements(esi, query_string, QueryString, _) ->
[{query_string, QueryString}];
create_script_elements(cgi, query_string, QueryString, _) ->
[{"QUERY_STRING", QueryString}];
create_script_elements(esi, path_info, PathInfo, ModData) ->
Aliases = httpd_util:multi_lookup(ModData#mod.config_db, alias),
{_,PathTranslated,_} =
mod_alias:real_name(ModData#mod.config_db, PathInfo,
Aliases),
[{path_info, PathInfo},
{path_translated, PathTranslated}];
create_script_elements(cgi, path_info, PathInfo, ModData) ->
Aliases = httpd_util:multi_lookup(ModData#mod.config_db, alias),
{_,PathTranslated,_} =
mod_alias:real_name(ModData#mod.config_db, PathInfo,
Aliases),
[{"PATH_INFO", PathInfo},
{"PATH_TRANSLATED", PathTranslated}];
create_script_elements(esi, entity_body, Body, _) ->
[{content_length, integer_to_list(httpd_util:flatlength(Body))}];
create_script_elements(cgi, entity_body, Body, _) ->
[{"CONTENT_LENGTH", integer_to_list(httpd_util:flatlength(Body))}];
create_script_elements(_, _, _, _) ->
[].
create_mod_interaction_elements(_, ModData)->
case proplists:get_value(remote_user, ModData#mod.data) of
undefined ->
[];
RemoteUser ->
[{remote_user, RemoteUser}]
end.