From 23fbb26b04921f98c78c600506fa754914f76af2 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 7 Jun 2010 12:35:28 +0000 Subject: OTP-7907: Allow the use of the "new" ssl (essl). OTP-8564: Update deeprication status. OTP-8573: Inets mod_alias URL rewrite. --- lib/inets/src/ftp/Makefile | 28 +-- lib/inets/src/ftp/ftp.erl | 58 +---- lib/inets/src/ftp/ftp_internal.hrl | 13 +- lib/inets/src/http_client/Makefile | 26 +- lib/inets/src/http_client/http.erl | 35 ++- lib/inets/src/http_client/httpc.erl | 36 ++- lib/inets/src/http_client/httpc_handler.erl | 163 ++++++------ lib/inets/src/http_client/httpc_internal.hrl | 14 +- lib/inets/src/http_client/httpc_manager.erl | 16 +- lib/inets/src/http_client/httpc_request.erl | 15 +- lib/inets/src/http_client/httpc_response.erl | 2 +- lib/inets/src/http_lib/Makefile | 27 +- lib/inets/src/http_lib/http_internal.hrl | 27 +- lib/inets/src/http_lib/http_transport.erl | 219 +++++++++++++--- lib/inets/src/http_server/Makefile | 26 +- lib/inets/src/http_server/httpd.erl | 279 ++++++++------------- lib/inets/src/http_server/httpd_acceptor.erl | 16 +- lib/inets/src/http_server/httpd_cgi.erl | 13 +- lib/inets/src/http_server/httpd_conf.erl | 98 +++++--- lib/inets/src/http_server/httpd_esi.erl | 13 +- lib/inets/src/http_server/httpd_internal.hrl | 13 +- lib/inets/src/http_server/httpd_manager.erl | 38 +-- lib/inets/src/http_server/httpd_request.erl | 66 ++++- .../src/http_server/httpd_request_handler.erl | 104 +++++--- lib/inets/src/http_server/mod_alias.erl | 73 +++++- lib/inets/src/http_server/mod_esi.erl | 43 +++- lib/inets/src/inets_app/Makefile | 18 +- lib/inets/src/inets_app/inets.app.src | 1 + lib/inets/src/inets_app/inets.appup.src | 42 ++-- lib/inets/src/inets_app/inets.mk | 45 ++++ lib/inets/src/inets_app/inets_service.erl | 12 +- lib/inets/src/tftp/Makefile | 22 +- 32 files changed, 952 insertions(+), 649 deletions(-) create mode 100644 lib/inets/src/inets_app/inets.mk (limited to 'lib/inets/src') diff --git a/lib/inets/src/ftp/Makefile b/lib/inets/src/ftp/Makefile index 0c15277a18..19b93870df 100644 --- a/lib/inets/src/ftp/Makefile +++ b/lib/inets/src/ftp/Makefile @@ -22,6 +22,7 @@ include $(ERL_TOP)/make/target.mk EBIN = ../../ebin include $(ERL_TOP)/make/$(TARGET)/otp.mk + # ---------------------------------------------------- # Application version # ---------------------------------------------------- @@ -29,6 +30,7 @@ include ../../vsn.mk VSN = $(INETS_VSN) + # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- @@ -52,24 +54,21 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) # ---------------------------------------------------- -# INETS FLAGS +# FLAGS # ---------------------------------------------------- -INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' + +include ../inets_app/inets.mk ifeq ($(FTP_DEBUG),true) INETS_FLAGS += -Dftp_debug endif +ERL_COMPILE_FLAGS += \ + $(INETS_FLAGS) \ + $(INETS_ERL_COMPILE_FLAGS) \ + -I../../include \ + -I../inets_app -# ---------------------------------------------------- -# FLAGS -# ---------------------------------------------------- -INETS_ERL_FLAGS += -I ../inets_app -pa ../../ebin - -ERL_COMPILE_FLAGS += $(INETS_ERL_FLAGS) \ - $(INETS_FLAGS) \ - +'{parse_transform,sys_pre_attributes}' \ - +'{attribute,insert,app_vsn,$(APP_VSN)}' # ---------------------------------------------------- # Targets @@ -89,9 +88,10 @@ docs: include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/src - $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src - $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/src/ftp + $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/ftp + $(INSTALL_DIR) $(RELSYSDIR)/ebin $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin release_docs_spec: diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl index 534fcae675..5ad74851c8 100644 --- a/lib/inets/src/ftp/ftp.erl +++ b/lib/inets/src/ftp/ftp.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -25,14 +25,12 @@ -behaviour(gen_server). -behaviour(inets_service). --deprecated({open, 3, next_major_release}). --deprecated({force_active, 1, next_major_release}). %% API - Client interface -export([cd/2, close/1, delete/2, formaterror/1, lcd/2, lpwd/1, ls/1, ls/2, mkdir/2, nlist/1, nlist/2, - open/1, open/2, open/3, force_active/1, + open/1, open/2, pwd/1, quote/2, recv/2, recv/3, recv_bin/2, recv_chunk_start/2, recv_chunk/1, @@ -133,11 +131,6 @@ open(Host, Port) when is_integer(Port) -> open(Host, [{port, Port}]); %% -%% -open(Host, [H|_] = Flags) when is_atom(H) -> - open(Host, ?FTP_PORT, Flags); -%% - open(Host, Opts) when is_list(Opts) -> ?fcrt("open", [{host, Host}, {opts, Opts}]), try @@ -160,32 +153,6 @@ open(Host, Opts) when is_list(Opts) -> end. -%% -open(Host, Port, Flags) when is_integer(Port) andalso is_list(Flags) -> - ?fcrt("open", [{host, Host}, {port, Port}, {flags, Flags}]), - try - {ok, StartOptions} = start_options([{flags, Flags}]), - ?fcrt("open", [{start_options, StartOptions}]), - {ok, OpenOptions} = open_options([{host, Host}, {port, Port}|Flags]), - ?fcrt("open", [{open_options, OpenOptions}]), - case ftp_sup:start_child([[{client, self()} | StartOptions], []]) of - {ok, Pid} -> - ?fcrt("open - ok", [{pid, Pid}]), - call(Pid, {open, ip_comm, OpenOptions}, plain); - Error1 -> - ?fcrt("open - error", [{error1, Error1}]), - Error1 - end - catch - throw:Error2 -> - Error2 - end. -%% - - - - - %%-------------------------------------------------------------------------- %% user(Pid, User, Pass, ) -> ok | {error, euser} | {error, econn} %% | {error, eacct} @@ -528,16 +495,6 @@ close(Pid) -> cast(Pid, close), ok. -%%-------------------------------------------------------------------------- -%% force_active(Pid) -> ok -%% Pid = pid() -%% -%% Description: Force connection to use active mode. -%%-------------------------------------------------------------------------- -force_active(Pid) -> - error_logger:info_report("This function is deprecated use the mode flag " - "instead"), - call(Pid, force_active, atom). %%-------------------------------------------------------------------------- %% formaterror(Tag) -> string() @@ -886,9 +843,6 @@ handle_call({_, {open, ip_comm, Host, Opts}}, From, State) -> {stop, normal, State2#state{client = undefined}} end; -handle_call({_, force_active}, _, State) -> - {reply, ok, State#state{mode = active}}; - handle_call({_, {user, User, Password}}, From, #state{csock = CSock} = State) when (CSock =/= undefined) -> handle_user(User, Password, "", State#state{client = From}); diff --git a/lib/inets/src/ftp/ftp_internal.hrl b/lib/inets/src/ftp/ftp_internal.hrl index c3fa1e611d..148f8217ba 100644 --- a/lib/inets/src/ftp/ftp_internal.hrl +++ b/lib/inets/src/ftp/ftp_internal.hrl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -21,7 +21,8 @@ -ifndef(ftp_internal_hrl). -define(ftp_internal_hrl, true). --include("inets_internal.hrl"). +-include_lib("inets/src/inets_app/inets_internal.hrl"). + -define(SERVICE, ftpc). -define(fcri(Label, Content), ?report_important(Label, ?SERVICE, Content)). -define(fcrv(Label, Content), ?report_verbose(Label, ?SERVICE, Content)). diff --git a/lib/inets/src/http_client/Makefile b/lib/inets/src/http_client/Makefile index 628c91421f..575c6efaec 100644 --- a/lib/inets/src/http_client/Makefile +++ b/lib/inets/src/http_client/Makefile @@ -60,21 +60,18 @@ ERL_FILES = $(MODULES:%=%.erl) TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) -# ---------------------------------------------------- -# INETS FLAGS -# ---------------------------------------------------- -INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' - - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- -INETS_ERL_FLAGS += -I ../http_lib -I ../inets_app -pa ../../ebin -ERL_COMPILE_FLAGS += $(INETS_ERL_FLAGS) \ - $(INETS_FLAGS) \ - +'{parse_transform,sys_pre_attributes}' \ - +'{attribute,insert,app_vsn,$(APP_VSN)}' +include ../inets_app/inets.mk + +ERL_COMPILE_FLAGS += \ + $(INETS_FLAGS) \ + $(INETS_ERL_COMPILE_FLAGS) \ + -I../../include \ + -I../inets_app \ + -I../http_lib # ---------------------------------------------------- @@ -94,9 +91,10 @@ docs: include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/src - $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src - $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/src/http_client + $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/http_client + $(INSTALL_DIR) $(RELSYSDIR)/ebin $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin release_docs_spec: diff --git a/lib/inets/src/http_client/http.erl b/lib/inets/src/http_client/http.erl index 7e1e90b50e..bbe2fec267 100644 --- a/lib/inets/src/http_client/http.erl +++ b/lib/inets/src/http_client/http.erl @@ -18,21 +18,38 @@ %% %% -%% Description: -%%% This version of the HTTP/1.1 client supports: -%%% - RFC 2616 HTTP 1.1 client part -%%% - RFC 2818 HTTP Over TLS +%%% Description: OLD API MODULE - USE httpc INSTEAD -module(http). -%% API --export([request/1, request/2, request/4, request/5, +-deprecated({request, 1, next_major_release}). +-deprecated({request, 2, next_major_release}). +-deprecated({request, 4, next_major_release}). +-deprecated({request, 5, next_major_release}). +-deprecated({cancel_request, 1, next_major_release}). +-deprecated({cancel_request, 2, next_major_release}). +-deprecated({set_option, 2, next_major_release}). +-deprecated({set_option, 3, next_major_release}). +-deprecated({set_options, 1, next_major_release}). +-deprecated({set_options, 2, next_major_release}). +-deprecated({verify_cookies, 2, next_major_release}). +-deprecated({verify_cookies, 3, next_major_release}). +-deprecated({cookie_header, 1, next_major_release}). +-deprecated({cookie_header, 2, next_major_release}). +-deprecated({stream_next, 1, next_major_release}). +-deprecated({default_profile, 0, next_major_release}). + +%% Deprecated +-export([ + request/1, request/2, request/4, request/5, cancel_request/1, cancel_request/2, set_option/2, set_option/3, set_options/1, set_options/2, - verify_cookies/2, verify_cookies/3, cookie_header/1, - cookie_header/2, stream_next/1, - default_profile/0]). + verify_cookies/2, verify_cookies/3, + cookie_header/1, cookie_header/2, + stream_next/1, + default_profile/0 + ]). %%%========================================================================= diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl index 6deeab6948..851364001c 100644 --- a/lib/inets/src/http_client/httpc.erl +++ b/lib/inets/src/http_client/httpc.erl @@ -48,7 +48,7 @@ stop_service/1, services/0, service_info/1]). --include("http_internal.hrl"). +-include_lib("inets/src/http_lib/http_internal.hrl"). -include("httpc_internal.hrl"). -define(DEFAULT_PROFILE, default). @@ -104,8 +104,14 @@ request(Url, Profile) -> %% HTTPOptions - [HttpOption] %% HTTPOption - {timeout, Time} | {connect_timeout, Time} | %% {ssl, SSLOptions} | {proxy_auth, {User, Password}} -%% Ssloptions = [SSLOption] -%% SSLOption = {verify, code()} | {depth, depth()} | {certfile, path()} | +%% Ssloptions = ssl_options() | +%% {ssl, ssl_options()} | +%% {ossl, ssl_options()} | +%% {essl, ssl_options()} +%% ssl_options() = [ssl_option()] +%% ssl_option() = {verify, code()} | +%% {depth, depth()} | +%% {certfile, path()} | %% {keyfile, path()} | {password, string()} | {cacertfile, path()} | %% {ciphers, string()} %% Options - [Option] @@ -579,7 +585,13 @@ http_options_default() -> error end, SslPost = fun(Value) when is_list(Value) -> - {ok, Value}; + {ok, {?HTTP_DEFAULT_SSL_KIND, Value}}; + ({ssl, SslOptions}) when is_list(SslOptions) -> + {ok, {?HTTP_DEFAULT_SSL_KIND, SslOptions}}; + ({ossl, SslOptions}) when is_list(SslOptions) -> + {ok, {ossl, SslOptions}}; + ({essl, SslOptions}) when is_list(SslOptions) -> + {ok, {essl, SslOptions}}; (_) -> error end, @@ -604,14 +616,14 @@ http_options_default() -> error end, [ - {version, {value, "HTTP/1.1"}, #http_options.version, VersionPost}, - {timeout, {value, ?HTTP_REQUEST_TIMEOUT}, #http_options.timeout, TimeoutPost}, - {autoredirect, {value, true}, #http_options.autoredirect, AutoRedirectPost}, - {ssl, {value, []}, #http_options.ssl, SslPost}, - {proxy_auth, {value, undefined}, #http_options.proxy_auth, ProxyAuthPost}, - {relaxed, {value, false}, #http_options.relaxed, RelaxedPost}, - %% this field has to be *after* the timeout field (as that field is used for the default value) - {connect_timeout, {field, #http_options.timeout}, #http_options.connect_timeout, ConnTimeoutPost} + {version, {value, "HTTP/1.1"}, #http_options.version, VersionPost}, + {timeout, {value, ?HTTP_REQUEST_TIMEOUT}, #http_options.timeout, TimeoutPost}, + {autoredirect, {value, true}, #http_options.autoredirect, AutoRedirectPost}, + {ssl, {value, {?HTTP_DEFAULT_SSL_KIND, []}}, #http_options.ssl, SslPost}, + {proxy_auth, {value, undefined}, #http_options.proxy_auth, ProxyAuthPost}, + {relaxed, {value, false}, #http_options.relaxed, RelaxedPost}, + %% this field has to be *after* the timeout option (as that field is used for the default value) + {connect_timeout, {field, #http_options.timeout}, #http_options.connect_timeout, ConnTimeoutPost} ]. diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl index 5e79d874fb..c34b641b7b 100644 --- a/lib/inets/src/http_client/httpc_handler.erl +++ b/lib/inets/src/http_client/httpc_handler.erl @@ -22,8 +22,8 @@ -behaviour(gen_server). +-include_lib("inets/src/http_lib/http_internal.hrl"). -include("httpc_internal.hrl"). --include("http_internal.hrl"). %%-------------------------------------------------------------------- @@ -177,8 +177,8 @@ stream(BodyPart, Request = #request{stream = Self}, Code) stream(BodyPart, Request = #request{stream = Self}, 404) when (Self =:= self) orelse (Self =:= {self, once}) -> ?hcrt("stream - self with 404", [{stream, Self}]), - httpc_response:send(Request#request.from, - {Request#request.id, stream, BodyPart}), + httpc_response:send(Request#request.from, + {Request#request.id, stream, BodyPart}), {<<>>, Request}; %% Stream to file @@ -286,8 +286,7 @@ handle_call({connect_and_send, #request{address = Address0, handle_call(#request{address = Addr} = Request, _, #state{status = Status, - session = #tcp_session{socket = Socket, - type = pipeline} = Session, + session = #session{type = pipeline} = Session, timers = Timers, options = #options{proxy = Proxy} = _Options, profile_name = ProfileName} = State) @@ -301,7 +300,7 @@ handle_call(#request{address = Addr} = Request, _, Address = handle_proxy(Addr, Proxy), - case httpc_request:send(Address, Request, Socket) of + case httpc_request:send(Address, Session, Request) of ok -> ?hcrd("request sent", []), @@ -320,10 +319,10 @@ handle_call(#request{address = Addr} = Request, _, NewTimers = NewState#state.timers, NewPipeline = queue:in(Request, State#state.pipeline), NewSession = - Session#tcp_session{queue_length = - %% Queue + current - queue:len(NewPipeline) + 1, - client_close = ClientClose}, + Session#session{queue_length = + %% Queue + current + queue:len(NewPipeline) + 1, + client_close = ClientClose}, httpc_manager:insert_session(NewSession, ProfileName), ?hcrd("session updated", []), {reply, ok, State#state{pipeline = NewPipeline, @@ -336,8 +335,8 @@ handle_call(#request{address = Addr} = Request, _, cancel_timer(Timers#timers.queue_timer, timeout_queue), NewSession = - Session#tcp_session{queue_length = 1, - client_close = ClientClose}, + Session#session{queue_length = 1, + client_close = ClientClose}, httpc_manager:insert_session(NewSession, ProfileName), Relaxed = (Request#request.settings)#http_options.relaxed, @@ -357,8 +356,7 @@ handle_call(#request{address = Addr} = Request, _, handle_call(#request{address = Addr} = Request, _, #state{status = Status, - session = #tcp_session{socket = Socket, - type = keep_alive} = Session, + session = #session{type = keep_alive} = Session, timers = Timers, options = #options{proxy = Proxy} = _Options, profile_name = ProfileName} = State) @@ -370,7 +368,7 @@ handle_call(#request{address = Addr} = Request, _, {status, Status}]), Address = handle_proxy(Addr, Proxy), - case httpc_request:send(Address, Request, Socket) of + case httpc_request:send(Address, Session, Request) of ok -> ?hcrd("request sent", []), @@ -389,10 +387,10 @@ handle_call(#request{address = Addr} = Request, _, NewTimers = NewState#state.timers, NewKeepAlive = queue:in(Request, State#state.keep_alive), NewSession = - Session#tcp_session{queue_length = - %% Queue + current - queue:len(NewKeepAlive) + 1, - client_close = ClientClose}, + Session#session{queue_length = + %% Queue + current + queue:len(NewKeepAlive) + 1, + client_close = ClientClose}, httpc_manager:insert_session(NewSession, ProfileName), ?hcrd("session updated", []), {reply, ok, State#state{keep_alive = NewKeepAlive, @@ -405,8 +403,8 @@ handle_call(#request{address = Addr} = Request, _, cancel_timer(Timers#timers.queue_timer, timeout_queue), NewSession = - Session#tcp_session{queue_length = 1, - client_close = ClientClose}, + Session#session{queue_length = 1, + client_close = ClientClose}, httpc_manager:insert_session(NewSession, ProfileName), Relaxed = (Request#request.settings)#http_options.relaxed, @@ -589,13 +587,13 @@ handle_info({ssl_closed, _}, State = #state{request = undefined}) -> %%% Error cases handle_info({tcp_closed, _}, #state{session = Session0} = State) -> - Socket = Session0#tcp_session.socket, - Session = Session0#tcp_session{socket = {remote_close, Socket}}, + Socket = Session0#session.socket, + Session = Session0#session{socket = {remote_close, Socket}}, %% {stop, session_remotly_closed, State}; {stop, normal, State#state{session = Session}}; handle_info({ssl_closed, _}, #state{session = Session0} = State) -> - Socket = Session0#tcp_session.socket, - Session = Session0#tcp_session{socket = {remote_close, Socket}}, + Socket = Session0#session.socket, + Session = Session0#session{socket = {remote_close, Socket}}, %% {stop, session_remotly_closed, State}; {stop, normal, State#state{session = Session}}; handle_info({tcp_error, _, _} = Reason, State) -> @@ -699,19 +697,18 @@ terminate(normal, #state{session = undefined}) -> %% Init error sending, no session information has been setup but %% there is a socket that needs closing. terminate(normal, - #state{request = Request, - session = #tcp_session{id = undefined, - socket = Socket}}) -> - http_transport:close(socket_type(Request), Socket); + #state{session = #session{id = undefined} = Session}) -> + close_socket(Session); %% Socket closed remotely terminate(normal, - #state{session = #tcp_session{socket = {remote_close, Socket}, - id = Id}, + #state{session = #session{socket = {remote_close, Socket}, + socket_type = SocketType, + id = Id}, profile_name = ProfileName, - request = Request, - timers = Timers, - pipeline = Pipeline}) -> + request = Request, + timers = Timers, + pipeline = Pipeline}) -> ?hcrt("terminate(normal) - remote close", [{id, Id}, {profile, ProfileName}]), @@ -728,11 +725,11 @@ terminate(normal, deliver_answers([Request | queue:to_list(Pipeline)]), %% And, just in case, close our side (**really** overkill) - http_transport:close(socket_type(Request), Socket); + http_transport:close(SocketType, Socket); -terminate(_, #state{session = #tcp_session{id = Id, - socket = Socket, - scheme = Scheme}, +terminate(_, #state{session = #session{id = Id, + socket = Socket, + socket_type = SocketType}, request = undefined, profile_name = ProfileName, timers = Timers, @@ -744,7 +741,7 @@ terminate(_, #state{session = #tcp_session{id = Id, maybe_retry_queue(KeepAlive, State), cancel_timer(Timers#timers.queue_timer, timeout_queue), - http_transport:close(socket_type(Scheme), Socket); + http_transport:close(SocketType, Socket); terminate(Reason, #state{request = undefined}) -> ?hcrt("terminate", [{reason, Reason}]), @@ -878,22 +875,23 @@ connect_and_send_first_request(Address, ConnTimeout = Settings#http_options.connect_timeout, case connect(SocketType, Address, Options, ConnTimeout) of {ok, Socket} -> + Session = #session{id = {OrigAddress, self()}, + scheme = Scheme, + socket = Socket, + socket_type = SocketType}, ?hcrd("connected - now send first request", [{socket, Socket}]), - case httpc_request:send(Address, Request, Socket) of + case httpc_request:send(Address, Session, Request) of ok -> ?hcrd("first request sent", []), ClientClose = httpc_request:is_client_closing(Headers), SessionType = httpc_manager:session_type(Options), - Session = - #tcp_session{id = {OrigAddress, self()}, - scheme = Scheme, - socket = Socket, - client_close = ClientClose, - type = SessionType}, + Session2 = + Session#session{client_close = ClientClose, + type = SessionType}, TmpState = State#state{request = Request, - session = Session, + session = Session2, mfa = init_mfa(Request, State), status_line = init_status_line(Request), headers = undefined, @@ -947,21 +945,20 @@ handler_info(#state{request = Request, ?hcrt("handler info", [{request_info, RequestInfo}]), %% Info about the current session/socket - SessionType = Session#tcp_session.type, - QueueLen = case Session#tcp_session.type of + SessionType = Session#session.type, + QueueLen = case SessionType of pipeline -> queue:len(Pipeline); keep_alive -> queue:len(KeepAlive) end, - Socket = Session#tcp_session.socket, - Scheme = Session#tcp_session.scheme, - SocketType = socket_type(Scheme), + Scheme = Session#session.scheme, + Socket = Session#session.socket, + SocketType = Session#session.socket_type, ?hcrt("handler info", [{session_type, SessionType}, {queue_length, QueueLen}, {scheme, Scheme}, - {socket_type, SocketType}, {socket, Socket}]), SocketOpts = http_transport:getopts(SocketType, Socket), @@ -1118,9 +1115,7 @@ handle_response(#state{request = Request, ?hcrd("handle response - continue", []), %% Send request body {_, RequestBody} = Request#request.content, - http_transport:send(socket_type(Session#tcp_session.scheme), - Session#tcp_session.socket, - RequestBody), + send_raw(Session, RequestBody), %% Wait for next response activate_once(Session), Relaxed = (Request#request.settings)#http_options.relaxed, @@ -1217,7 +1212,7 @@ handle_pipeline(#state{status = pipeline, %% If a pipeline that has been idle for some time is not %% closed by the server, the client may want to close it. NewState = activate_queue_timeout(TimeOut, State), - NewSession = Session#tcp_session{queue_length = 0}, + NewSession = Session#session{queue_length = 0}, httpc_manager:insert_session(NewSession, ProfileName), %% Note mfa will be initilized when a new request %% arrives. @@ -1239,9 +1234,9 @@ handle_pipeline(#state{status = pipeline, false -> ?hcrv("next request", [{request, NextRequest}]), NewSession = - Session#tcp_session{queue_length = - %% Queue + current - queue:len(Pipeline) + 1}, + Session#session{queue_length = + %% Queue + current + queue:len(Pipeline) + 1}, httpc_manager:insert_session(NewSession, ProfileName), Relaxed = (NextRequest#request.settings)#http_options.relaxed, @@ -1290,16 +1285,16 @@ handle_keep_alive_queue( %% If a keep_alive session has been idle for some time is not %% closed by the server, the client may want to close it. NewState = activate_queue_timeout(TimeOut, State), - NewSession = Session#tcp_session{queue_length = 0}, + NewSession = Session#session{queue_length = 0}, httpc_manager:insert_session(NewSession, ProfileName), %% Note mfa will be initilized when a new request %% arrives. {noreply, - NewState#state{request = undefined, - mfa = undefined, + NewState#state{request = undefined, + mfa = undefined, status_line = undefined, - headers = undefined, - body = undefined + headers = undefined, + body = undefined } }; {{value, NextRequest}, KeepAlive} -> @@ -1342,10 +1337,12 @@ case_insensitive_header(Str) when is_list(Str) -> case_insensitive_header(Str) -> Str. -activate_once(#tcp_session{scheme = Scheme, socket = Socket}) -> - SocketType = socket_type(Scheme), +activate_once(#session{socket = Socket, socket_type = SocketType}) -> http_transport:setopts(SocketType, Socket, [{active, once}]). +close_socket(#session{socket = Socket, socket_type = SocketType}) -> + http_transport:close(SocketType, Socket). + activate_request_timeout( #state{request = #request{timer = undefined} = Request} = State) -> Timeout = (Request#request.settings)#http_options.timeout, @@ -1378,7 +1375,7 @@ activate_queue_timeout(Time, State) -> State#state{timers = #timers{queue_timer = Ref}}. -is_pipeline_enabled_client(#tcp_session{type = pipeline}) -> +is_pipeline_enabled_client(#session{type = pipeline}) -> true; is_pipeline_enabled_client(_) -> false. @@ -1391,7 +1388,7 @@ is_keep_alive_enabled_server("HTTP/1.0", is_keep_alive_enabled_server(_,_) -> false. -is_keep_alive_connection(Headers, #tcp_session{client_close = ClientClose}) -> +is_keep_alive_connection(Headers, #session{client_close = ClientClose}) -> (not ((ClientClose) orelse httpc_response:is_server_closing(Headers))). try_to_enable_pipeline_or_keep_alive( @@ -1416,7 +1413,7 @@ try_to_enable_pipeline_or_keep_alive( httpc_manager:insert_session(Session, ProfileName), %% Make sure type is keep_alive in session %% as it in this case might be pipeline - NewSession = Session#tcp_session{type = keep_alive}, + NewSession = Session#session{type = keep_alive}, State#state{status = keep_alive, session = NewSession} end; @@ -1551,11 +1548,11 @@ init_status_line(#request{settings = Settings}) -> socket_type(#request{scheme = http}) -> ip_comm; socket_type(#request{scheme = https, settings = Settings}) -> - {ssl, Settings#http_options.ssl}; -socket_type(http) -> - ip_comm; -socket_type(https) -> - {ssl, []}. %% Dummy value ok for ex setopts that does not use this value + Settings#http_options.ssl. +%% socket_type(http) -> +%% ip_comm; +%% socket_type(https) -> +%% {ssl1, []}. %% Dummy value ok for ex setopts that does not use this value start_stream({_Version, _Code, _ReasonPhrase}, _Headers, #request{stream = none} = Request) -> @@ -1624,18 +1621,15 @@ end_stream(SL, R) -> next_body_chunk(#state{request = #request{stream = {self, once}}, - once = once, session = Session} = State) -> - http_transport:setopts(socket_type(Session#tcp_session.scheme), - Session#tcp_session.socket, - [{active, once}]), + once = once, + session = Session} = State) -> + activate_once(Session), State#state{once = inactive}; next_body_chunk(#state{request = #request{stream = {self, once}}, once = inactive} = State) -> State; %% Wait for user to call stream_next next_body_chunk(#state{session = Session} = State) -> - http_transport:setopts(socket_type(Session#tcp_session.scheme), - Session#tcp_session.socket, - [{active, once}]), + activate_once(Session), State. handle_verbose(verbose) -> @@ -1712,6 +1706,11 @@ handle_verbose(_) -> %% ok. +send_raw(#session{socket = Socket, socket_type = SocketType}, Body) -> + http_transport:send(SocketType, Socket, Body). + + + call(Msg, Pid) -> Timeout = infinity, call(Msg, Pid, Timeout). diff --git a/lib/inets/src/http_client/httpc_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl index 4d76c4beb3..3cdd95a02b 100644 --- a/lib/inets/src/http_client/httpc_internal.hrl +++ b/lib/inets/src/http_client/httpc_internal.hrl @@ -18,7 +18,11 @@ %% %% --include("inets_internal.hrl"). +-ifndef(httpc_internal_hrl). +-define(httpc_internal_hrl, true). + +-include_lib("inets/src/inets_app/inets_internal.hrl"). + -define(SERVICE, httpc). -define(hcri(Label, Data), ?report_important(Label, ?SERVICE, Data)). -define(hcrv(Label, Data), ?report_verbose(Label, ?SERVICE, Data)). @@ -104,13 +108,14 @@ } ). --record(tcp_session, +-record(session, { id, % {{Host, Port}, HandlerPid} client_close, % true | false scheme, % http (HTTP/TCP) | https (HTTP/SSL/TCP) socket, % Open socket, used by connection - queue_length = 1, % Current length of pipeline or keep alive queue + socket_type, % socket-type, used by connection + queue_length = 1, % Current length of pipeline or keep-alive queue type % pipeline | keep_alive (wait for response before sending new request) }). @@ -138,3 +143,6 @@ %% path, % string() %% q % query: string() %% }). + + +-endif. % -ifdef(httpc_internal_hrl). diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl index b278077a66..d5d6376369 100644 --- a/lib/inets/src/http_client/httpc_manager.erl +++ b/lib/inets/src/http_client/httpc_manager.erl @@ -21,8 +21,8 @@ -behaviour(gen_server). +-include_lib("inets/src/http_lib/http_internal.hrl"). -include("httpc_internal.hrl"). --include("http_internal.hrl"). %% Internal Application API -export([ @@ -333,7 +333,7 @@ do_init(ProfileName, CookiesDir) -> ?hcrt("create session db", []), SessionDbName = session_db_name(ProfileName), ets:new(SessionDbName, - [public, set, named_table, {keypos, #tcp_session.id}]), + [public, set, named_table, {keypos, #session.id}]), %% Create handler db ?hcrt("create handler/request db", []), @@ -876,12 +876,12 @@ select_session(Method, HostPort, Scheme, SessionType, %% client_close, scheme and type specified. %% The fields id (part of: HandlerPid) and queue_length %% specified. - Pattern = #tcp_session{id = {HostPort, '$1'}, - client_close = false, - scheme = Scheme, - socket = '_', - queue_length = '$2', - type = SessionType}, + Pattern = #session{id = {HostPort, '$1'}, + client_close = false, + scheme = Scheme, + queue_length = '$2', + type = SessionType, + _ = '_'}, %% {'_', {HostPort, '$1'}, false, Scheme, '_', '$2', SessionTyp}, Candidates = ets:match(SessionDb, Pattern), ?hcrd("select session", [{host_port, HostPort}, diff --git a/lib/inets/src/http_client/httpc_request.erl b/lib/inets/src/http_client/httpc_request.erl index 55e0af4b42..d4df97ad40 100644 --- a/lib/inets/src/http_client/httpc_request.erl +++ b/lib/inets/src/http_client/httpc_request.erl @@ -19,12 +19,13 @@ -module(httpc_request). --include("http_internal.hrl"). +-include_lib("inets/src/http_lib/http_internal.hrl"). -include("httpc_internal.hrl"). %%% Internal API -export([send/3, is_idempotent/1, is_client_closing/1]). + %%%========================================================================= %%% Internal application API %%%========================================================================= @@ -39,10 +40,9 @@ %% %% Description: Composes and sends a HTTP-request. %%------------------------------------------------------------------------- -send(SendAddr, #request{scheme = Scheme, socket_opts = SocketOpts} = Request, - Socket) +send(SendAddr, #session{socket = Socket, socket_type = SocketType}, + #request{socket_opts = SocketOpts} = Request) when is_list(SocketOpts) -> - SocketType = socket_type(Scheme), case http_transport:setopts(SocketType, Socket, SocketOpts) of ok -> send(SendAddr, Socket, SocketType, @@ -50,8 +50,7 @@ send(SendAddr, #request{scheme = Scheme, socket_opts = SocketOpts} = Request, {error, Reason} -> {error, {setopts_failed, Reason}} end; -send(SendAddr, #request{scheme = Scheme} = Request, Socket) -> - SocketType = socket_type(Scheme), +send(SendAddr, #session{socket = Socket, socket_type = SocketType}, Request) -> send(SendAddr, Socket, SocketType, Request). send(SendAddr, Socket, SocketType, @@ -209,10 +208,6 @@ headers(_, "HTTP/0.9") -> headers(Headers, _) -> Headers. -socket_type(http) -> - ip_comm; -socket_type(https) -> - {ssl, []}. http_headers([], Headers) -> lists:flatten(Headers); diff --git a/lib/inets/src/http_client/httpc_response.erl b/lib/inets/src/http_client/httpc_response.erl index df7d40a33e..bb9c516259 100644 --- a/lib/inets/src/http_client/httpc_response.erl +++ b/lib/inets/src/http_client/httpc_response.erl @@ -19,7 +19,7 @@ -module(httpc_response). --include("http_internal.hrl"). +-include_lib("inets/src/http_lib/http_internal.hrl"). -include("httpc_internal.hrl"). %% API diff --git a/lib/inets/src/http_lib/Makefile b/lib/inets/src/http_lib/Makefile index 7f4c92861c..5dac3b0c00 100644 --- a/lib/inets/src/http_lib/Makefile +++ b/lib/inets/src/http_lib/Makefile @@ -54,25 +54,17 @@ ERL_FILES = $(MODULES:%=%.erl) TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) -# ---------------------------------------------------- -# INETS FLAGS -# ---------------------------------------------------- -INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' - - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- -INETS_ERL_FLAGS += -I ../inets_app -ifeq ($(WARN_UNUSED_WARS),true) -ERL_COMPILE_FLAGS += +warn_unused_vars -endif +include ../inets_app/inets.mk -ERL_COMPILE_FLAGS += $(INETS_ERL_FLAGS) \ - $(INETS_FLAGS) \ - +'{parse_transform,sys_pre_attributes}' \ - +'{attribute,insert,app_vsn,$(APP_VSN)}' +ERL_COMPILE_FLAGS += \ + $(INETS_FLAGS) \ + $(INETS_ERL_COMPILE_FLAGS) \ + -I../../include \ + -I../inets_app # ---------------------------------------------------- @@ -94,9 +86,10 @@ docs: include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/src - $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src - $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/src/http_lib + $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/http_lib + $(INSTALL_DIR) $(RELSYSDIR)/ebin $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin release_docs_spec: diff --git a/lib/inets/src/http_lib/http_internal.hrl b/lib/inets/src/http_lib/http_internal.hrl index bb2e831727..5440f214b5 100644 --- a/lib/inets/src/http_lib/http_internal.hrl +++ b/lib/inets/src/http_lib/http_internal.hrl @@ -1,28 +1,37 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2002-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2002-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% --include("inets_internal.hrl"). +-ifndef(http_internal_hrl). +-define(http_internal_hrl, true). --define(HTTP_MAX_BODY_SIZE, nolimit). +-include_lib("inets/src/inets_app/inets_internal.hrl"). + +-define(HTTP_MAX_BODY_SIZE, nolimit). -define(HTTP_MAX_HEADER_SIZE, 10240). --define(HTTP_MAX_URI_SIZE, nolimit). +-define(HTTP_MAX_URI_SIZE, nolimit). + +-ifndef(HTTP_DEFAULT_SSL_KIND). +-define(HTTP_DEFAULT_SSL_KIND, ossl). +%% -define(HTTP_DEFAULT_SSL_KIND, essl). +-endif. % -ifdef(HTTP_DEFAULT_SSL_KIND). + %%% Response headers -record(http_response_h,{ @@ -106,3 +115,5 @@ 'last-modified', other=[] % list() - Key/Value list with other headers }). + +-endif. % -ifdef(http_internal_hrl). diff --git a/lib/inets/src/http_lib/http_transport.erl b/lib/inets/src/http_lib/http_transport.erl index 7c2ac626e6..b8121852b8 100644 --- a/lib/inets/src/http_lib/http_transport.erl +++ b/lib/inets/src/http_lib/http_transport.erl @@ -36,7 +36,9 @@ -export([negotiate/3]). --include("inets_internal.hrl"). +-include_lib("inets/src/inets_app/inets_internal.hrl"). +-include("http_internal.hrl"). + -define(SERVICE, httpl). -define(hlri(Label, Content), ?report_important(Label, ?SERVICE, Content)). -define(hlrv(Label, Content), ?report_verbose(Label, ?SERVICE, Content)). @@ -55,6 +57,18 @@ %% Description: Makes sure inet_db or ssl is started. %%------------------------------------------------------------------------- start(ip_comm) -> + do_start_ip_comm(); + +%% This is just for backward compatibillity +start({ssl, _}) -> + do_start_ssl(); +start({ossl, _}) -> + do_start_ssl(); +start({essl, _}) -> + do_start_ssl(). + + +do_start_ip_comm() -> case inet_db:start() of {ok, _} -> ok; @@ -62,8 +76,9 @@ start(ip_comm) -> ok; Error -> Error - end; -start({ssl, _}) -> + end. + +do_start_ssl() -> case ssl:start() of ok -> ok; @@ -97,18 +112,26 @@ connect(ip_comm = _SocketType, {Host, Port}, Opts0, Timeout) [{host, Host}, {port, Port}, {opts, Opts}, {timeout, Timeout}]), gen_tcp:connect(Host, Port, Opts, Timeout); -connect({ssl, SslConfig}, {Host, Port}, _, Timeout) -> - Opts = [binary, {active, false}] ++ SslConfig, - ?hlrt("connect using ssl", - [{host, Host}, {port, Port}, {ssl_config, SslConfig}, - {timeout, Timeout}]), +%% Wrapper for backaward compatibillity +connect({ssl, SslConfig}, Address, Opts, Timeout) -> + connect({?HTTP_DEFAULT_SSL_KIND, SslConfig}, Address, Opts, Timeout); + +connect({ossl, SslConfig}, {Host, Port}, _, Timeout) -> + Opts = [binary, {active, false}, {ssl_imp, old}] ++ SslConfig, + ?hlrt("connect using ossl", + [{host, Host}, + {port, Port}, + {ssl_config, SslConfig}, + {timeout, Timeout}]), ssl:connect(Host, Port, Opts, Timeout); -connect({erl_ssl, SslConfig}, {Host, Port}, _, Timeout) -> +connect({essl, SslConfig}, {Host, Port}, _, Timeout) -> Opts = [binary, {active, false}, {ssl_imp, new}] ++ SslConfig, - ?hlrt("connect using erl_ssl", - [{host, Host}, {port, Port}, {ssl_config, SslConfig}, - {timeout, Timeout}]), + ?hlrt("connect using essl", + [{host, Host}, + {port, Port}, + {ssl_config, SslConfig}, + {timeout, Timeout}]), ssl:connect(Host, Port, Opts, Timeout). @@ -136,13 +159,32 @@ listen(ip_comm, Addr, Port) -> Else end; -listen({ssl, SSLConfig} = Ssl, Addr, Port) -> +%% Wrapper for backaward compatibillity +listen({ssl, SSLConfig}, Addr, Port) -> + ?hlrt("listen (wrapper)", + [{addr, Addr}, + {port, Port}, + {ssl_config, SSLConfig}]), + listen({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Addr, Port); + +listen({ossl, SSLConfig} = Ssl, Addr, Port) -> + ?hlrt("listen (ossl)", + [{addr, Addr}, + {port, Port}, + {ssl_config, SSLConfig}]), Opt = sock_opt(Ssl, Addr, SSLConfig), - ssl:listen(Port, Opt); - -listen({erl_ssl, SSLConfig} = Ssl, Addr, Port) -> + ?hlrt("listen options", [{opt, Opt}]), + ssl:listen(Port, [{ssl_imp, old} | Opt]); + +listen({essl, SSLConfig} = Ssl, Addr, Port) -> + ?hlrt("listen (essl)", + [{addr, Addr}, + {port, Port}, + {ssl_config, SSLConfig}]), Opt = sock_opt(Ssl, Addr, SSLConfig), - ssl:listen(Port, [{ssl_imp, new} | Opt]). + ?hlrt("listen options", [{opt, Opt}]), + Opt2 = [{ssl_imp, new}, {reuseaddr, true} | Opt], + ssl:listen(Port, Opt2). listen_ip_comm(Addr, Port) -> @@ -228,9 +270,17 @@ ip_family_of(IpFamilyStr) -> %%------------------------------------------------------------------------- accept(SocketType, ListenSocket) -> accept(SocketType, ListenSocket, infinity). + accept(ip_comm, ListenSocket, Timeout) -> gen_tcp:accept(ListenSocket, Timeout); -accept({ssl,_SSLConfig}, ListenSocket, Timeout) -> + +%% Wrapper for backaward compatibillity +accept({ssl, SSLConfig}, ListenSocket, Timeout) -> + accept({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, ListenSocket, Timeout); + +accept({ossl, _SSLConfig}, ListenSocket, Timeout) -> + ssl:transport_accept(ListenSocket, Timeout); +accept({essl, _SSLConfig}, ListenSocket, Timeout) -> ssl:transport_accept(ListenSocket, Timeout). @@ -244,7 +294,15 @@ accept({ssl,_SSLConfig}, ListenSocket, Timeout) -> %%------------------------------------------------------------------------- controlling_process(ip_comm, Socket, NewOwner) -> gen_tcp:controlling_process(Socket, NewOwner); -controlling_process({ssl, _}, Socket, NewOwner) -> + +%% Wrapper for backaward compatibillity +controlling_process({ssl, SSLConfig}, Socket, NewOwner) -> + controlling_process({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, NewOwner); + +controlling_process({ossl, _}, Socket, NewOwner) -> + ssl:controlling_process(Socket, NewOwner); + +controlling_process({essl, _}, Socket, NewOwner) -> ssl:controlling_process(Socket, NewOwner). @@ -259,9 +317,23 @@ controlling_process({ssl, _}, Socket, NewOwner) -> setopts(ip_comm, Socket, Options) -> ?hlrt("ip_comm setopts", [{socket, Socket}, {options, Options}]), inet:setopts(Socket, Options); -setopts({ssl, _}, Socket, Options) -> - ?hlrt("ssl setopts", [{socket, Socket}, {options, Options}]), - ssl:setopts(Socket, Options). + +%% Wrapper for backaward compatibillity +setopts({ssl, SSLConfig}, Socket, Options) -> + setopts({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, Options); + +setopts({ossl, _}, Socket, Options) -> + ?hlrt("[o]ssl setopts", [{socket, Socket}, {options, Options}]), + Reason = (catch ssl:setopts(Socket, Options)), + ?hlrt("[o]ssl setopts result", [{reason, Reason}]), + Reason; + + +setopts({essl, _}, Socket, Options) -> + ?hlrt("[e]ssl setopts", [{socket, Socket}, {options, Options}]), + Reason = (catch ssl:setopts(Socket, Options)), + ?hlrt("[e]ssl setopts result", [{reason, Reason}]), + Reason. %%------------------------------------------------------------------------- @@ -283,15 +355,27 @@ getopts(ip_comm, Socket, Options) -> {error, _} -> [] end; -getopts({ssl, _}, Socket, Options) -> + +%% Wrapper for backaward compatibillity +getopts({ssl, SSLConfig}, Socket, Options) -> + getopts({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, Options); + +getopts({ossl, _}, Socket, Options) -> ?hlrt("ssl getopts", [{socket, Socket}, {options, Options}]), + getopts_ssl(Socket, Options); + +getopts({essl, _}, Socket, Options) -> + ?hlrt("essl getopts", [{socket, Socket}, {options, Options}]), + getopts_ssl(Socket, Options). + +getopts_ssl(Socket, Options) -> case ssl:getopts(Socket, Options) of {ok, SocketOpts} -> SocketOpts; {error, _} -> [] end. - + %%------------------------------------------------------------------------- %% getstat(SocketType, Socket) -> socket_stats() @@ -308,8 +392,15 @@ getstat(ip_comm = _SocketType, Socket) -> {error, _} -> [] end; -getstat({ssl, _} = _SocketType, _Socket) -> - %% ?hlrt("ssl getstat", [{socket, Socket}]), + +%% Wrapper for backaward compatibillity +getstat({ssl, SSLConfig}, Socket) -> + getstat({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket); + +getstat({ossl, _} = _SocketType, _Socket) -> + []; + +getstat({essl, _} = _SocketType, _Socket) -> []. @@ -322,7 +413,15 @@ getstat({ssl, _} = _SocketType, _Socket) -> %%------------------------------------------------------------------------- send(ip_comm, Socket, Message) -> gen_tcp:send(Socket, Message); -send({ssl, _}, Socket, Message) -> + +%% Wrapper for backaward compatibillity +send({ssl, SSLConfig}, Socket, Message) -> + send({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, Message); + +send({ossl, _}, Socket, Message) -> + ssl:send(Socket, Message); + +send({essl, _}, Socket, Message) -> ssl:send(Socket, Message). @@ -335,9 +434,18 @@ send({ssl, _}, Socket, Message) -> %%------------------------------------------------------------------------- close(ip_comm, Socket) -> gen_tcp:close(Socket); -close({ssl, _}, Socket) -> + +%% Wrapper for backaward compatibillity +close({ssl, SSLConfig}, Socket) -> + close({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket); + +close({ossl, _}, Socket) -> + ssl:close(Socket); + +close({essl, _}, Socket) -> ssl:close(Socket). + %%------------------------------------------------------------------------- %% peername(SocketType, Socket) -> {Port, SockName} %% SocketType = ip_comm | {ssl, _} @@ -368,7 +476,17 @@ peername(ip_comm, Socket) -> {-1, "unknown"} end; -peername({ssl, _}, Socket) -> +%% Wrapper for backaward compatibillity +peername({ssl, SSLConfig}, Socket) -> + peername({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket); + +peername({ossl, _}, Socket) -> + peername_ssl(Socket); + +peername({essl, _}, Socket) -> + peername_ssl(Socket). + +peername_ssl(Socket) -> case ssl:peername(Socket) of {ok,{{A, B, C, D}, Port}} -> PeerName = integer_to_list(A)++"."++integer_to_list(B)++"."++ @@ -409,7 +527,17 @@ sockname(ip_comm, Socket) -> {-1, "unknown"} end; -sockname({ssl, _}, Socket) -> +%% Wrapper for backaward compatibillity +sockname({ssl, SSLConfig}, Socket) -> + sockname({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket); + +sockname({ossl, _}, Socket) -> + sockname_ssl(Socket); + +sockname({essl, _}, Socket) -> + sockname_ssl(Socket). + +sockname_ssl(Socket) -> case ssl:sockname(Socket) of {ok,{{A, B, C, D}, Port}} -> SockName = integer_to_list(A)++"."++integer_to_list(B)++"."++ @@ -455,22 +583,31 @@ sock_opt2(Opts) -> [{packet, 0}, {active, false} | Opts]. negotiate(ip_comm,_,_) -> + ?hlrt("negotiate(ip_comm)", []), ok; -negotiate({ssl,_},Socket,Timeout) -> - negotiate(Socket, Timeout); -negotiate({erl_ssl, _}, Socket, Timeout) -> - negotiate(Socket, Timeout). - -negotiate(Socket, Timeout) -> +negotiate({ssl, SSLConfig}, Socket, Timeout) -> + ?hlrt("negotiate(ssl)", []), + negotiate({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, Timeout); +negotiate({ossl, _}, Socket, Timeout) -> + ?hlrt("negotiate(ossl)", []), + negotiate_ssl(Socket, Timeout); +negotiate({essl, _}, Socket, Timeout) -> + ?hlrt("negotiate(essl)", []), + negotiate_ssl(Socket, Timeout). + +negotiate_ssl(Socket, Timeout) -> + ?hlrt("negotiate_ssl", [{socket, Socket}, {timeout, Timeout}]), case ssl:ssl_accept(Socket, Timeout) of ok -> ok; - {error, Error} -> - case lists:member(Error, - [timeout,econnreset,esslaccept,esslerrssl]) of + {error, Reason} -> + ?hlrd("negotiate_ssl - accept failed", [{reason, Reason}]), + %% Look for "valid" error reasons + ValidReasons = [timeout, econnreset, esslaccept, esslerrssl], + case lists:member(Reason, ValidReasons) of true -> - {error,normal}; + {error, normal}; false -> - {error, Error} + {error, Reason} end end. diff --git a/lib/inets/src/http_server/Makefile b/lib/inets/src/http_server/Makefile index ce1405011e..879e605217 100644 --- a/lib/inets/src/http_server/Makefile +++ b/lib/inets/src/http_server/Makefile @@ -89,21 +89,18 @@ ERL_FILES = $(MODULES:%=%.erl) TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) -# ---------------------------------------------------- -# INETS FLAGS -# ---------------------------------------------------- -INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' - - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- -INETS_ERL_FLAGS += -I ../http_lib -I ../inets_app -pa ../../ebin -ERL_COMPILE_FLAGS += $(INETS_ERL_FLAGS) \ - $(INETS_FLAGS) \ - +'{parse_transform,sys_pre_attributes}' \ - +'{attribute,insert,app_vsn,$(APP_VSN)}' +include ../inets_app/inets.mk + +ERL_COMPILE_FLAGS += \ + $(INETS_FLAGS) \ + $(INETS_ERL_COMPILE_FLAGS) \ + -I../../include \ + -I../inets_app \ + -I../http_lib # ---------------------------------------------------- @@ -125,9 +122,10 @@ docs: include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/src - $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src - $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/src/http_server + $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/http_server + $(INSTALL_DIR) $(RELSYSDIR)/ebin $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin release_docs_spec: diff --git a/lib/inets/src/http_server/httpd.erl b/lib/inets/src/http_server/httpd.erl index 8fe54ccef6..fb5fa1c758 100644 --- a/lib/inets/src/http_server/httpd.erl +++ b/lib/inets/src/http_server/httpd.erl @@ -24,54 +24,25 @@ -include("httpd.hrl"). --deprecated({start, 0, next_major_release}). --deprecated({start, 1, next_major_release}). --deprecated({start_link, 1, next_major_release}). --deprecated({start_child, 0, next_major_release}). --deprecated({start_child, 1, next_major_release}). --deprecated({stop, 0, next_major_release}). --deprecated({stop, 1, next_major_release}). --deprecated({stop, 2, next_major_release}). --deprecated({stop_child, 0, next_major_release}). --deprecated({stop_child, 1, next_major_release}). --deprecated({stop_child, 2, next_major_release}). --deprecated({restart, 0, next_major_release}). --deprecated({restart, 1, next_major_release}). --deprecated({restart, 2, next_major_release}). --deprecated({block, 0, next_major_release}). --deprecated({block, 1, next_major_release}). --deprecated({block, 2, next_major_release}). --deprecated({block, 3, next_major_release}). --deprecated({block, 4, next_major_release}). --deprecated({unblock, 0, next_major_release}). --deprecated({unblock, 1, next_major_release}). --deprecated({unblock, 2, next_major_release}). %% Behavior callbacks --export([start_standalone/1, start_service/1, stop_service/1, services/0, - service_info/1]). +-export([ + start_standalone/1, + start_service/1, + stop_service/1, + services/0, + service_info/1 + ]). %% API -export([parse_query/1, reload_config/2, info/1, info/2, info/3]). -%% Deprecated --export([start/0, start/1, - start_link/0, start_link/1, - start_child/0,start_child/1, - stop/0,stop/1,stop/2, - stop_child/0,stop_child/1,stop_child/2, - restart/0,restart/1,restart/2]). - -%% Management stuff should be internal functions -%% Will be from r13 --export([block/0,block/1,block/2,block/3,block/4, - unblock/0,unblock/1,unblock/2]). - -%% Internal Debugging and status info stuff... -%% Keep for now should probably be moved to test catalog --export([get_status/1,get_status/2,get_status/3, - get_admin_state/0,get_admin_state/1,get_admin_state/2, - get_usage_state/0,get_usage_state/1,get_usage_state/2]). +%% Internal debugging and status info stuff... +-export([ + get_status/1, get_status/2, get_status/3, + get_admin_state/0, get_admin_state/1, get_admin_state/2, + get_usage_state/0, get_usage_state/1, get_usage_state/2 + ]). %%%======================================================================== %%% API @@ -111,6 +82,7 @@ info(Address, Port, Properties) when is_integer(Port) andalso is_list(Properties) -> httpd_conf:get_config(Address, Port, Properties). + %%%======================================================================== %%% Behavior callbacks %%%======================================================================== @@ -149,6 +121,8 @@ service_info(Pid) -> exit:{noproc, _} -> {error, service_not_available} end. + + %%%-------------------------------------------------------------- %%% Internal functions %%%-------------------------------------------------------------------- @@ -176,6 +150,7 @@ child_name2info({httpd_instance_sup, Address, Port}) -> {ok, [{bind_address, Address}, {port, Port} | Info]} end. + reload(Config, Address, Port) -> Name = make_name(Address,Port), case whereis(Name) of @@ -185,26 +160,12 @@ reload(Config, Address, Port) -> {error,not_started} end. -reload(Addr, Port) when is_integer(Port) -> - Name = make_name(Addr,Port), - case whereis(Name) of - Pid when is_pid(Pid) -> - httpd_manager:reload(Pid, undefined); - _ -> - {error,not_started} - end. %%% ========================================================= -%%% Function: block/0, block/1, block/2, block/3, block/4 -%%% block() -%%% block(Port) -%%% block(ConfigFile) -%%% block(Addr,Port) -%%% block(Port,Mode) -%%% block(ConfigFile,Mode) -%%% block(Addr,Port,Mode) -%%% block(ConfigFile,Mode,Timeout) -%%% block(Addr,Port,Mode,Timeout) +%%% Function: block/3, block/4 +%%% block(Addr, Port, Mode) +%%% block(ConfigFile, Mode, Timeout) +%%% block(Addr, Port, Mode, Timeout) %%% %%% Returns: ok | {error,Reason} %%% @@ -237,58 +198,32 @@ reload(Addr, Port) when is_integer(Port) -> %%% Mode -> disturbing | non_disturbing %%% Timeout -> integer() %%% -block() -> block(undefined,8888,disturbing). - -block(Port) when is_integer(Port) -> - block(undefined,Port,disturbing); - -block(ConfigFile) when is_list(ConfigFile) -> - case get_addr_and_port(ConfigFile) of - {ok,Addr,Port} -> - block(Addr,Port,disturbing); - Error -> - Error - end. - -block(Addr,Port) when is_integer(Port) -> - block(Addr,Port,disturbing); - -block(Port,Mode) when is_integer(Port) andalso is_atom(Mode) -> - block(undefined,Port,Mode); - -block(ConfigFile,Mode) when is_list(ConfigFile) andalso is_atom(Mode) -> - case get_addr_and_port(ConfigFile) of - {ok,Addr,Port} -> - block(Addr,Port,Mode); - Error -> - Error - end. - -block(Addr,Port,disturbing) when is_integer(Port) -> - do_block(Addr,Port,disturbing); -block(Addr,Port,non_disturbing) when is_integer(Port) -> - do_block(Addr,Port,non_disturbing); +block(Addr, Port, disturbing) when is_integer(Port) -> + do_block(Addr, Port, disturbing); +block(Addr, Port, non_disturbing) when is_integer(Port) -> + do_block(Addr, Port, non_disturbing); -block(ConfigFile,Mode,Timeout) when is_list(ConfigFile) andalso - is_atom(Mode) andalso - is_integer(Timeout) -> +block(ConfigFile, Mode, Timeout) + when is_list(ConfigFile) andalso + is_atom(Mode) andalso + is_integer(Timeout) -> case get_addr_and_port(ConfigFile) of - {ok,Addr,Port} -> - block(Addr,Port,Mode,Timeout); + {ok, Addr, Port} -> + block(Addr, Port, Mode, Timeout); Error -> Error end. -block(Addr,Port,non_disturbing,Timeout) +block(Addr, Port, non_disturbing, Timeout) + when is_integer(Port) andalso is_integer(Timeout) -> + do_block(Addr, Port, non_disturbing, Timeout); +block(Addr,Port,disturbing,Timeout) when is_integer(Port) andalso is_integer(Timeout) -> - do_block(Addr,Port,non_disturbing,Timeout); -block(Addr,Port,disturbing,Timeout) when is_integer(Port) andalso - is_integer(Timeout) -> - do_block(Addr,Port,disturbing,Timeout). + do_block(Addr, Port, disturbing, Timeout). -do_block(Addr,Port,Mode) when is_integer(Port) andalso is_atom(Mode) -> +do_block(Addr, Port, Mode) when is_integer(Port) andalso is_atom(Mode) -> Name = make_name(Addr,Port), case whereis(Name) of Pid when is_pid(Pid) -> @@ -298,7 +233,7 @@ do_block(Addr,Port,Mode) when is_integer(Port) andalso is_atom(Mode) -> end. -do_block(Addr,Port,Mode,Timeout) +do_block(Addr, Port, Mode, Timeout) when is_integer(Port) andalso is_atom(Mode) -> Name = make_name(Addr,Port), case whereis(Name) of @@ -310,11 +245,8 @@ do_block(Addr,Port,Mode,Timeout) %%% ========================================================= -%%% Function: unblock/0, unblock/1, unblock/2 -%%% unblock() -%%% unblock(Port) -%%% unblock(ConfigFile) -%%% unblock(Addr,Port) +%%% Function: unblock/2 +%%% unblock(Addr, Port) %%% %%% Description: This function is used to reverse a previous block %%% operation on the HTTP server. @@ -323,16 +255,6 @@ do_block(Addr,Port,Mode,Timeout) %%% Addr -> {A,B,C,D} | string() | undefined %%% ConfigFile -> string() %%% -unblock() -> unblock(undefined,8888). -unblock(Port) when is_integer(Port) -> unblock(undefined,Port); - -unblock(ConfigFile) when is_list(ConfigFile) -> - case get_addr_and_port(ConfigFile) of - {ok,Addr,Port} -> - unblock(Addr,Port); - Error -> - Error - end. unblock(Addr, Port) when is_integer(Port) -> Name = make_name(Addr,Port), @@ -521,80 +443,81 @@ do_reload_config(ConfigList, Mode) -> %%%-------------------------------------------------------------- %%% Deprecated %%%-------------------------------------------------------------- -start() -> - start("/var/tmp/server_root/conf/8888.conf"). -start(ConfigFile) -> - {ok, Pid} = inets:start(httpd, ConfigFile, stand_alone), - unlink(Pid), - {ok, Pid}. +%% start() -> +%% start("/var/tmp/server_root/conf/8888.conf"). -start_link() -> - start("/var/tmp/server_root/conf/8888.conf"). +%% start(ConfigFile) -> +%% {ok, Pid} = inets:start(httpd, ConfigFile, stand_alone), +%% unlink(Pid), +%% {ok, Pid}. -start_link(ConfigFile) when is_list(ConfigFile) -> - inets:start(httpd, ConfigFile, stand_alone). +%% start_link() -> +%% start("/var/tmp/server_root/conf/8888.conf"). -stop() -> - stop(8888). +%% start_link(ConfigFile) when is_list(ConfigFile) -> +%% inets:start(httpd, ConfigFile, stand_alone). -stop(Port) when is_integer(Port) -> - stop(undefined, Port); -stop(Pid) when is_pid(Pid) -> - old_stop(Pid); -stop(ConfigFile) when is_list(ConfigFile) -> - old_stop(ConfigFile). +%% stop() -> +%% stop(8888). -stop(Addr, Port) when is_integer(Port) -> - old_stop(Addr, Port). +%% stop(Port) when is_integer(Port) -> +%% stop(undefined, Port); +%% stop(Pid) when is_pid(Pid) -> +%% old_stop(Pid); +%% stop(ConfigFile) when is_list(ConfigFile) -> +%% old_stop(ConfigFile). -start_child() -> - start_child("/var/tmp/server_root/conf/8888.conf"). +%% stop(Addr, Port) when is_integer(Port) -> +%% old_stop(Addr, Port). -start_child(ConfigFile) -> - httpd_sup:start_child(ConfigFile). +%% start_child() -> +%% start_child("/var/tmp/server_root/conf/8888.conf"). -stop_child() -> - stop_child(8888). +%% start_child(ConfigFile) -> +%% httpd_sup:start_child(ConfigFile). -stop_child(Port) -> - stop_child(undefined, Port). +%% stop_child() -> +%% stop_child(8888). -stop_child(Addr, Port) when is_integer(Port) -> - httpd_sup:stop_child(Addr, Port). +%% stop_child(Port) -> +%% stop_child(undefined, Port). -restart() -> reload(undefined, 8888). +%% stop_child(Addr, Port) when is_integer(Port) -> +%% httpd_sup:stop_child(Addr, Port). -restart(Port) when is_integer(Port) -> - reload(undefined, Port). -restart(Addr, Port) -> - reload(Addr, Port). +%% restart() -> reload(undefined, 8888). -old_stop(Pid) when is_pid(Pid) -> - do_stop(Pid); -old_stop(ConfigFile) when is_list(ConfigFile) -> - case get_addr_and_port(ConfigFile) of - {ok, Addr, Port} -> - old_stop(Addr, Port); - - Error -> - Error - end; -old_stop(_StartArgs) -> - ok. +%% restart(Port) when is_integer(Port) -> +%% reload(undefined, Port). +%% restart(Addr, Port) -> +%% reload(Addr, Port). -old_stop(Addr, Port) when is_integer(Port) -> - Name = old_make_name(Addr, Port), - case whereis(Name) of - Pid when is_pid(Pid) -> - do_stop(Pid), - ok; - _ -> - not_started - end. +%% old_stop(Pid) when is_pid(Pid) -> +%% do_stop(Pid); +%% old_stop(ConfigFile) when is_list(ConfigFile) -> +%% case get_addr_and_port(ConfigFile) of +%% {ok, Addr, Port} -> +%% old_stop(Addr, Port); + +%% Error -> +%% Error +%% end; +%% old_stop(_StartArgs) -> +%% ok. + +%% old_stop(Addr, Port) when is_integer(Port) -> +%% Name = old_make_name(Addr, Port), +%% case whereis(Name) of +%% Pid when is_pid(Pid) -> +%% do_stop(Pid), +%% ok; +%% _ -> +%% not_started +%% end. -do_stop(Pid) -> - exit(Pid, shutdown). +%% do_stop(Pid) -> +%% exit(Pid, shutdown). -old_make_name(Addr,Port) -> - httpd_util:make_name("httpd_instance_sup",Addr,Port). +%% old_make_name(Addr,Port) -> +%% httpd_util:make_name("httpd_instance_sup",Addr,Port). diff --git a/lib/inets/src/http_server/httpd_acceptor.erl b/lib/inets/src/http_server/httpd_acceptor.erl index 568fd3c610..c261eff6b2 100644 --- a/lib/inets/src/http_server/httpd_acceptor.erl +++ b/lib/inets/src/http_server/httpd_acceptor.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -138,9 +138,9 @@ acceptor_loop(Manager, SocketType, ListenSocket, ConfigDb, AcceptTimeout) -> handle_error(Reason, ConfigDb), ?MODULE:acceptor_loop(Manager, SocketType, ListenSocket, ConfigDb, AcceptTimeout); - {'EXIT', Reason} -> - ?hdri("accept exited", [{reason, Reason}]), - handle_error({'EXIT', Reason}, ConfigDb), + {'EXIT', _Reason} = EXIT -> + ?hdri("accept exited", [{reason, _Reason}]), + handle_error(EXIT, ConfigDb), ?MODULE:acceptor_loop(Manager, SocketType, ListenSocket, ConfigDb, AcceptTimeout) end. diff --git a/lib/inets/src/http_server/httpd_cgi.erl b/lib/inets/src/http_server/httpd_cgi.erl index 0532d7d100..c06a06aad3 100644 --- a/lib/inets/src/http_server/httpd_cgi.erl +++ b/lib/inets/src/http_server/httpd_cgi.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -21,7 +21,8 @@ -export([parse_headers/1, handle_headers/1]). --include("inets_internal.hrl"). +-include_lib("inets/src/inets_app/inets_internal.hrl"). + %%%========================================================================= %%% Internal application API diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl index 5ca2e47eb5..8438c4037e 100644 --- a/lib/inets/src/http_server/httpd_conf.erl +++ b/lib/inets/src/http_server/httpd_conf.erl @@ -25,13 +25,15 @@ %% Application internal API -export([load/1, load/2, load_mime_types/1, store/1, store/2, - remove/1, remove_all/1, config/1, get_config/2, get_config/3, - lookup/2, lookup/3, lookup/4, - validate_properties/1]). + remove/1, remove_all/1, get_config/2, get_config/3, + lookup_socket_type/1, + lookup/2, lookup/3, lookup/4, + validate_properties/1]). -define(VMODULE,"CONF"). -include("httpd.hrl"). -include("httpd_internal.hrl"). +-include_lib("inets/src/http_lib/http_internal.hrl"). %%%========================================================================= @@ -216,9 +218,12 @@ load("ServerName " ++ ServerName, []) -> {ok,[],{server_name,clean(ServerName)}}; load("SocketType " ++ SocketType, []) -> - case check_enum(clean(SocketType),["ssl","ip_comm"]) of + %% ssl is the same as HTTP_DEFAULT_SSL_KIND + %% ossl is ssl based on OpenSSL (the "old" ssl) + %% essl is the pure Erlang-based ssl (the "new" ssl) + case check_enum(clean(SocketType), ["ssl", "ossl", "essl", "ip_comm"]) of {ok, ValidSocketType} -> - {ok, [], {socket_type,ValidSocketType}}; + {ok, [], {socket_type, ValidSocketType}}; {error,_} -> {error, ?NICE(clean(SocketType) ++ " is an invalid SocketType")} end; @@ -226,7 +231,7 @@ load("SocketType " ++ SocketType, []) -> load("Port " ++ Port, []) -> case make_integer(Port) of {ok, Integer} -> - {ok, [], {port,Integer}}; + {ok, [], {port, Integer}}; {error, _} -> {error, ?NICE(clean(Port)++" is an invalid Port")} end; @@ -534,7 +539,10 @@ validate_config_params([{server_name, Value} | _]) -> throw({server_name, Value}); validate_config_params([{socket_type, Value} | Rest]) - when (Value =:= ip_comm) orelse (Value =:= ssl) -> + when (Value =:= ip_comm) orelse + (Value =:= ssl) orelse + (Value =:= ossl) orelse + (Value =:= essl) -> validate_config_params(Rest); validate_config_params([{socket_type, Value} | _]) -> throw({socket_type, Value}); @@ -695,6 +703,8 @@ store(ConfigList0) -> ConfigList) catch throw:Error -> + ?hdri("store - config parameter validation failed", + [{error, Error}]), {error, {invalid_option, Error}} end. @@ -741,27 +751,27 @@ remove(ConfigDB) -> ets:delete(ConfigDB), ok. -config(ConfigDB) -> - case httpd_util:lookup(ConfigDB, socket_type,ip_comm) of - ssl -> - case ssl_certificate_file(ConfigDB) of - undefined -> - {error, - "Directive SSLCertificateFile " - "not found in the config file"}; - SSLCertificateFile -> - {ssl, - SSLCertificateFile++ - ssl_certificate_key_file(ConfigDB)++ - ssl_verify_client(ConfigDB)++ - ssl_ciphers(ConfigDB)++ - ssl_password(ConfigDB)++ - ssl_verify_depth(ConfigDB)++ - ssl_ca_certificate_file(ConfigDB)} - end; - ip_comm -> - ip_comm - end. +%% config(ConfigDB) -> +%% case httpd_util:lookup(ConfigDB, socket_type, ip_comm) of +%% ssl -> +%% case ssl_certificate_file(ConfigDB) of +%% undefined -> +%% {error, +%% "Directive SSLCertificateFile " +%% "not found in the config file"}; +%% SSLCertificateFile -> +%% {ssl, +%% SSLCertificateFile++ +%% ssl_certificate_key_file(ConfigDB)++ +%% ssl_verify_client(ConfigDB)++ +%% ssl_ciphers(ConfigDB)++ +%% ssl_password(ConfigDB)++ +%% ssl_verify_depth(ConfigDB)++ +%% ssl_ca_certificate_file(ConfigDB)} +%% end; +%% ip_comm -> +%% ip_comm +%% end. get_config(Address, Port) -> @@ -797,6 +807,38 @@ table(Address, Port) -> httpd_util:make_name("httpd_conf", Address, Port). +lookup_socket_type(ConfigDB) -> + case httpd_util:lookup(ConfigDB, socket_type, ip_comm) of + ip_comm -> + ip_comm; + SSL when (SSL =:= ssl) orelse (SSL =:= ossl) orelse (SSL =:= essl) -> + SSLTag = + if + (SSL =:= ssl) -> + ?HTTP_DEFAULT_SSL_KIND; + true -> + SSL + end, + case ssl_certificate_file(ConfigDB) of + undefined -> + Reason = "Directive SSLCertificateFile " + "not found in the config file", + throw({error, Reason}); + SSLCertificateFile -> + {SSLTag, SSLCertificateFile ++ ssl_config(ConfigDB)} + end + end. + +ssl_config(ConfigDB) -> + ssl_certificate_key_file(ConfigDB) ++ + ssl_verify_client(ConfigDB) ++ + ssl_ciphers(ConfigDB) ++ + ssl_password(ConfigDB) ++ + ssl_verify_depth(ConfigDB) ++ + ssl_ca_certificate_file(ConfigDB). + + + %%%======================================================================== %%% Internal functions %%%======================================================================== diff --git a/lib/inets/src/http_server/httpd_esi.erl b/lib/inets/src/http_server/httpd_esi.erl index b1a75fda52..026ec9a5fe 100644 --- a/lib/inets/src/http_server/httpd_esi.erl +++ b/lib/inets/src/http_server/httpd_esi.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -21,7 +21,8 @@ -export([parse_headers/1, handle_headers/1]). --include("inets_internal.hrl"). +-include_lib("inets/src/inets_app/inets_internal.hrl"). + %%%========================================================================= %%% Internal application API diff --git a/lib/inets/src/http_server/httpd_internal.hrl b/lib/inets/src/http_server/httpd_internal.hrl index 7795ab6c18..38b0ddefd3 100644 --- a/lib/inets/src/http_server/httpd_internal.hrl +++ b/lib/inets/src/http_server/httpd_internal.hrl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -21,7 +21,8 @@ -ifndef(httpd_internal_hrl). -define(httpd_internal_hrl, true). --include("inets_internal.hrl"). +-include_lib("inets/src/inets_app/inets_internal.hrl"). + -define(SERVICE, httpd). -define(hdri(Label, Content), ?report_important(Label, ?SERVICE, Content)). -define(hdrv(Label, Content), ?report_verbose(Label, ?SERVICE, Content)). diff --git a/lib/inets/src/http_server/httpd_manager.erl b/lib/inets/src/http_server/httpd_manager.erl index f2e8763907..b44bc77c41 100644 --- a/lib/inets/src/http_server/httpd_manager.erl +++ b/lib/inets/src/http_server/httpd_manager.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2000-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -238,24 +238,25 @@ init([ConfigFile, ConfigList, AcceptTimeout, Addr, Port]) -> case (catch do_init(ConfigFile, ConfigList, AcceptTimeout, Addr, Port)) of {error, Reason} -> String = lists:flatten( - io_lib:format("Failed initiating " - "web server: ~n~p~n~p~n", - [ConfigFile,Reason])), + io_lib:format("Failed initiating web server: " + "~n~p" + "~n~p" + "~n", [ConfigFile, Reason])), error_logger:error_report(String), {stop, {error, Reason}}; {ok, State} -> {ok, State} end; -init([ConfigFile, ConfigList, AcceptTimeout, Addr, Port, - ListenInfo]) -> +init([ConfigFile, ConfigList, AcceptTimeout, Addr, Port, ListenInfo]) -> process_flag(trap_exit, true), case (catch do_init(ConfigFile, ConfigList, AcceptTimeout, Addr, Port, ListenInfo)) of {error, Reason} -> String = lists:flatten( - io_lib:format("Failed initiating " - "web server: ~n~p~n~p~n", - [ConfigFile,Reason])), + io_lib:format("Failed initiating web server: " + "~n~p" + "~n~p" + "~n", [ConfigFile, Reason])), error_logger:error_report(String), {stop, {error, Reason}}; {ok, State} -> @@ -264,13 +265,14 @@ init([ConfigFile, ConfigList, AcceptTimeout, Addr, Port, do_init(ConfigFile, ConfigList, AcceptTimeout, Addr, Port) -> NewConfigFile = proplists:get_value(file, ConfigList, ConfigFile), - ConfigDB = do_initial_store(ConfigList), - SocketType = httpd_conf:config(ConfigDB), + ConfigDB = do_initial_store(ConfigList), + SocketType = httpd_conf:lookup_socket_type(ConfigDB), case httpd_acceptor_sup:start_acceptor(SocketType, Addr, Port, ConfigDB, AcceptTimeout) of {ok, _Pid} -> - Status = [{max_conn,0}, {last_heavy_load,never}, - {last_connection,never}], + Status = [{max_conn, 0}, + {last_heavy_load, never}, + {last_connection, never}], State = #state{socket_type = SocketType, config_file = NewConfigFile, config_db = ConfigDB, @@ -284,7 +286,7 @@ do_init(ConfigFile, ConfigList, AcceptTimeout, Addr, Port) -> do_init(ConfigFile, ConfigList, AcceptTimeout, Addr, Port, ListenInfo) -> NewConfigFile = proplists:get_value(file, ConfigList, ConfigFile), ConfigDB = do_initial_store(ConfigList), - SocketType = httpd_conf:config(ConfigDB), + SocketType = httpd_conf:lookup_socket_type(ConfigDB), case httpd_acceptor_sup:start_acceptor(SocketType, Addr, Port, ConfigDB, AcceptTimeout, ListenInfo) of diff --git a/lib/inets/src/http_server/httpd_request.erl b/lib/inets/src/http_server/httpd_request.erl index 8eee08e766..883acbf585 100644 --- a/lib/inets/src/http_server/httpd_request.erl +++ b/lib/inets/src/http_server/httpd_request.erl @@ -19,22 +19,35 @@ -module(httpd_request). --include("http_internal.hrl"). +-include_lib("inets/src/http_lib/http_internal.hrl"). -include("httpd.hrl"). +-include("httpd_internal.hrl"). --export([parse/1, whole_body/2, validate/3, update_mod_data/5, - body_data/2]). +-export([ + parse/1, + whole_body/2, + validate/3, + update_mod_data/5, + body_data/2 + ]). %% Callback API - used for example if the header/body is received a %% little at a time on a socket. --export([parse_method/1, parse_uri/1, parse_version/1, parse_headers/1, - whole_body/1]). +-export([ + parse_method/1, parse_uri/1, parse_version/1, parse_headers/1, + whole_body/1 + ]). + %%%========================================================================= %%% Internal application API %%%========================================================================= parse([Bin, MaxSizes]) -> - parse_method(Bin, [], MaxSizes, []). + ?hdrt("parse", [{bin, Bin}, {max_sizes, MaxSizes}]), + parse_method(Bin, [], MaxSizes, []); +parse(Unknown) -> + ?hdrt("parse", [{unknown, Unknown}]), + exit({bad_args, Unknown}). %% Functions that may be returned during the decoding process %% if the input data is incompleate. @@ -119,30 +132,65 @@ update_mod_data(ModData, Method, RequestURI, HTTPVersion, Headers)-> %%% Internal functions %%%======================================================================== parse_method(<<>>, Method, MaxSizes, Result) -> + ?hdrt("parse_method - empty bin", + [{method, Method}, {max_sizes, MaxSizes}, {result, Result}]), {?MODULE, parse_method, [Method, MaxSizes, Result]}; parse_method(<>, Method, MaxSizes, Result) -> + ?hdrt("parse_method - SP begin", + [{rest, Rest}, + {method, Method}, + {max_sizes, MaxSizes}, + {result, Result}]), parse_uri(Rest, [], 0, MaxSizes, [string:strip(lists:reverse(Method)) | Result]); parse_method(<>, Method, MaxSizes, Result) -> + ?hdrt("parse_method", + [{octet, Octet}, + {rest, Rest}, + {method, Method}, + {max_sizes, MaxSizes}, + {result, Result}]), parse_method(Rest, [Octet | Method], MaxSizes, Result). -parse_uri(_, _, CurrSize, {MaxURI, _}, _) when CurrSize > MaxURI, - MaxURI =/= nolimit -> +parse_uri(_, _, CurrSize, {MaxURI, _}, _) + when (CurrSize > MaxURI) andalso (MaxURI =/= nolimit) -> + ?hdrt("parse_uri", + [{current_size, CurrSize}, + {max_uri, MaxURI}]), %% We do not know the version of the client as it comes after the %% uri send the lowest version in the response so that the client %% will be able to handle it. HttpVersion = "HTTP/0.9", {error, {uri_too_long, MaxURI}, HttpVersion}; parse_uri(<<>>, URI, CurrSize, MaxSizes, Result) -> + ?hdrt("parse_uri - empty bin", + [{uri, URI}, + {current_size, CurrSize}, + {max_sz, MaxSizes}, + {result, Result}]), {?MODULE, parse_uri, [URI, CurrSize, MaxSizes, Result]}; parse_uri(<>, URI, _, MaxSizes, Result) -> + ?hdrt("parse_uri - SP begin", + [{uri, URI}, + {max_sz, MaxSizes}, + {result, Result}]), parse_version(Rest, [], MaxSizes, [string:strip(lists:reverse(URI)) | Result]); %% Can happen if it is a simple HTTP/0.9 request e.i "GET /\r\n\r\n" -parse_uri(<> = Data, URI, _,MaxSizes, Result) -> +parse_uri(<> = Data, URI, _, MaxSizes, Result) -> + ?hdrt("parse_uri - CR begin", + [{uri, URI}, + {max_sz, MaxSizes}, + {result, Result}]), parse_version(Data, [], MaxSizes, [string:strip(lists:reverse(URI)) | Result]); parse_uri(<>, URI, CurrSize, MaxSizes, Result) -> + ?hdrt("parse_uri", + [{octet, Octet}, + {uri, URI}, + {curr_sz, CurrSize}, + {max_sz, MaxSizes}, + {result, Result}]), parse_uri(Rest, [Octet | URI], CurrSize + 1, MaxSizes, Result). parse_version(<<>>, Version, MaxSizes, Result) -> diff --git a/lib/inets/src/http_server/httpd_request_handler.erl b/lib/inets/src/http_server/httpd_request_handler.erl index fa832cba3f..a9db6e2058 100644 --- a/lib/inets/src/http_server/httpd_request_handler.erl +++ b/lib/inets/src/http_server/httpd_request_handler.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -101,11 +101,13 @@ init([Manager, ConfigDB, AcceptTimeout]) -> Then = erlang:now(), + ?hdrd("negotiate", []), case http_transport:negotiate(SocketType, Socket, TimeOut) of {error, Error} -> + ?hdrd("negotiation failed", [{error, Error}]), exit(Error); %% Can be 'normal'. ok -> - ?hdrt("negotiated", []), + ?hdrt("negotiation successfull", []), NewTimeout = TimeOut - timer:now_diff(now(),Then) div 1000, continue_init(Manager, ConfigDB, SocketType, Socket, NewTimeout) end. @@ -121,12 +123,9 @@ continue_init(Manager, ConfigDB, SocketType, Socket, TimeOut) -> socket = Socket, init_data = InitData}, - MaxHeaderSize = httpd_util:lookup(ConfigDB, max_header_size, - ?HTTP_MAX_HEADER_SIZE), - MaxURISize = httpd_util:lookup(ConfigDB, max_uri_size, - ?HTTP_MAX_URI_SIZE), - NrOfRequest = httpd_util:lookup(ConfigDB, - max_keep_alive_request, infinity), + MaxHeaderSize = max_header_size(ConfigDB), + MaxURISize = max_uri_size(ConfigDB), + NrOfRequest = max_keep_alive_request(ConfigDB), {_, Status} = httpd_manager:new_connection(Manager), @@ -142,9 +141,10 @@ continue_init(Manager, ConfigDB, SocketType, Socket, TimeOut) -> ?hdrt("activate request timeout", []), NewState = activate_request_timeout(State), - ?hdrt("update socket options", []), - http_transport:setopts(SocketType, Socket, [binary,{packet, 0}, - {active, once}]), + ?hdrt("set socket options (binary, packet & active)", []), + http_transport:setopts(SocketType, Socket, + [binary, {packet, 0}, {active, once}]), + ?hdrt("init done", []), gen_server:enter_loop(?MODULE, [], NewState). @@ -180,21 +180,29 @@ handle_cast(Msg, State) -> %% {stop, Reason, State} %% Description: Handling all non call/cast messages %%-------------------------------------------------------------------- -handle_info({Proto, Socket, Data}, State = +handle_info({Proto, Socket, Data}, #state{mfa = {Module, Function, Args} = MFA, mod = #mod{socket_type = SockType, socket = Socket} = ModData} = State) when (((Proto =:= tcp) orelse (Proto =:= ssl) orelse (Proto =:= dummy)) andalso is_binary(Data)) -> + ?hdrd("received data", [{data, Data}, {proto, Proto}, {socket, Socket}, {socket_type, SockType}, {mfa, MFA}]), - case Module:Function([Data | Args]) of + +%% case (catch Module:Function([Data | Args])) of + PROCESSED = (catch Module:Function([Data | Args])), + + ?hdrt("data processed", [{processing_result, PROCESSED}]), + + case PROCESSED of {ok, Result} -> ?hdrd("data processed", [{result, Result}]), NewState = cancel_request_timeout(State), handle_http_msg(Result, NewState); + {error, {uri_too_long, MaxSize}, Version} -> ?hdrv("uri too long", [{max_size, MaxSize}, {version, Version}]), NewModData = ModData#mod{http_version = Version}, @@ -205,7 +213,8 @@ handle_info({Proto, Socket, Data}, State = {stop, normal, State#state{response_sent = true, mod = NewModData}}; {error, {header_too_long, MaxSize}, Version} -> - ?hdrv("header too long", [{max_size, MaxSize}, {version, Version}]), + ?hdrv("header too long", + [{max_size, MaxSize}, {version, Version}]), NewModData = ModData#mod{http_version = Version}, httpd_response:send_status(NewModData, 413, "Header too long"), Reason = io_lib:format("Header too long, max size is ~p~n", @@ -263,14 +272,16 @@ terminate(Reason, #state{response_sent = false, mod = ModData} = State) -> httpd_response:send_status(ModData, 500, none), error_log(httpd_util:reason_phrase(500), ModData), terminate(Reason, State#state{response_sent = true, mod = ModData}); -terminate(_, State) -> +terminate(_Reason, State) -> do_terminate(State). do_terminate(#state{mod = ModData, manager = Manager} = State) -> catch httpd_manager:done_connection(Manager), cancel_request_timeout(State), + %% receive after 5000 -> ok end, httpd_socket:close(ModData#mod.socket_type, ModData#mod.socket). + %%-------------------------------------------------------------------- %% code_change(OldVsn, State, Extra) -> {ok, NewState} %% @@ -279,6 +290,7 @@ do_terminate(#state{mod = ModData, manager = Manager} = State) -> code_change(_OldVsn, State, _Extra) -> {ok, State}. + %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- @@ -383,9 +395,8 @@ is_host_specified_if_required(_, _, _) -> handle_body(#state{mod = #mod{config_db = ConfigDB}} = State) -> ?hdrt("handle body", []), - MaxHeaderSize = - httpd_util:lookup(ConfigDB, max_header_size, ?HTTP_MAX_HEADER_SIZE), - MaxBodySize = httpd_util:lookup(ConfigDB, max_body_size, nolimit), + MaxHeaderSize = max_header_size(ConfigDB), + MaxBodySize = max_body_size(ConfigDB), case handle_expect(State, MaxBodySize) of ok -> @@ -538,24 +549,23 @@ handle_response(#state{body = Body, {stop, normal, State#state{response_sent = true}}. handle_next_request(#state{mod = #mod{connection = true} = ModData, - max_keep_alive_request = Max} = State, Data) -> + max_keep_alive_request = Max} = State, Data) -> ?hdrt("handle next request", [{max, Max}]), + NewModData = #mod{socket_type = ModData#mod.socket_type, - socket = ModData#mod.socket, - config_db = ModData#mod.config_db, - init_data = ModData#mod.init_data}, - MaxHeaderSize = - httpd_util:lookup(ModData#mod.config_db, - max_header_size, ?HTTP_MAX_HEADER_SIZE), - MaxURISize = httpd_util:lookup(ModData#mod.config_db, max_uri_size, - ?HTTP_MAX_URI_SIZE), - TmpState = State#state{mod = NewModData, - mfa = {httpd_request, parse, [{MaxURISize, - MaxHeaderSize}]}, + socket = ModData#mod.socket, + config_db = ModData#mod.config_db, + init_data = ModData#mod.init_data}, + MaxHeaderSize = max_header_size(ModData#mod.config_db), + MaxURISize = max_uri_size(ModData#mod.config_db), + + MFA = {httpd_request, parse, [{MaxURISize, MaxHeaderSize}]}, + TmpState = State#state{mod = NewModData, + mfa = MFA, max_keep_alive_request = decrease(Max), - headers = undefined, - body = undefined, - response_sent = false}, + headers = undefined, + body = undefined, + response_sent = false}, NewState = activate_request_timeout(TmpState), @@ -596,7 +606,7 @@ decrease(N) -> error_log(ReasonString, Info) -> Error = lists:flatten( - io_lib:format("Error reading request:~s",[ReasonString])), + io_lib:format("Error reading request: ~s", [ReasonString])), error_log(mod_log, Info, Error), error_log(mod_disk_log, Info, Error). @@ -609,3 +619,21 @@ error_log(Mod, #mod{config_db = ConfigDB} = Info, String) -> _ -> ok end. + + +%%-------------------------------------------------------------------- +%% Config access wrapper functions +%%-------------------------------------------------------------------- + +max_header_size(ConfigDB) -> + httpd_util:lookup(ConfigDB, max_header_size, ?HTTP_MAX_HEADER_SIZE). + +max_uri_size(ConfigDB) -> + httpd_util:lookup(ConfigDB, max_uri_size, ?HTTP_MAX_URI_SIZE). + +max_body_size(ConfigDB) -> + httpd_util:lookup(ConfigDB, max_body_size, nolimit). + +max_keep_alive_request(ConfigDB) -> + httpd_util:lookup(ConfigDB, max_keep_alive_request, infinity). + diff --git a/lib/inets/src/http_server/mod_alias.erl b/lib/inets/src/http_server/mod_alias.erl index ec0a12242f..9c5a8cc1c6 100644 --- a/lib/inets/src/http_server/mod_alias.erl +++ b/lib/inets/src/http_server/mod_alias.erl @@ -103,6 +103,19 @@ real_name(ConfigDB, RequestURI, []) -> httpd_util:split_path(default_index(ConfigDB, RealName)), {ShortPath, Path, AfterPath}; +real_name(ConfigDB, RequestURI, [{MP,Replacement}|Rest]) + when element(1, MP) =:= re_pattern -> + case re:run(RequestURI, MP, [{capture,[]}]) of + match -> + NewURI = re:replace(RequestURI, MP, Replacement, [{return,list}]), + {ShortPath,_} = httpd_util:split_path(NewURI), + {Path,AfterPath} = + httpd_util:split_path(default_index(ConfigDB, NewURI)), + {ShortPath, Path, AfterPath}; + nomatch -> + real_name(ConfigDB, RequestURI, Rest) + end; + real_name(ConfigDB, RequestURI, [{FakeName,RealName}|Rest]) -> case inets_regexp:match(RequestURI, "^" ++ FakeName) of {match, _, _} -> @@ -120,6 +133,18 @@ real_name(ConfigDB, RequestURI, [{FakeName,RealName}|Rest]) -> real_script_name(_ConfigDB, _RequestURI, []) -> not_a_script; + +real_script_name(ConfigDB, RequestURI, [{MP,Replacement} | Rest]) + when element(1, MP) =:= re_pattern -> + case re:run(RequestURI, MP, [{capture,[]}]) of + match -> + ActualName = + re:replace(RequestURI, MP, Replacement, [{return,list}]), + httpd_util:split_script_path(default_index(ConfigDB, ActualName)); + nomatch -> + real_script_name(ConfigDB, RequestURI, Rest) + end; + real_script_name(ConfigDB, RequestURI, [{FakeName,RealName} | Rest]) -> case inets_regexp:match(RequestURI, "^" ++ FakeName) of {match,_,_} -> @@ -180,6 +205,8 @@ load("Alias " ++ Alias, []) -> {ok, _} -> {error,?NICE(httpd_conf:clean(Alias)++" is an invalid Alias")} end; +load("ReWrite " ++ Rule, Acc) -> + load_re_write(Rule, Acc, "ReWrite", re_write); load("ScriptAlias " ++ ScriptAlias, []) -> case inets_regexp:split(ScriptAlias, " ") of {ok, [FakeName, RealName]} -> @@ -189,6 +216,24 @@ load("ScriptAlias " ++ ScriptAlias, []) -> {ok, _} -> {error, ?NICE(httpd_conf:clean(ScriptAlias)++ " is an invalid ScriptAlias")} + end; +load("ScriptReWrite " ++ Rule, Acc) -> + load_re_write(Rule, Acc, "ScriptReWrite", script_re_write). + +load_re_write(Rule0, Acc, Type, Tag) -> + case lists:dropwhile( + fun ($\s) -> true; ($\t) -> true; (_) -> false end, + Rule0) of + "" -> + {error, ?NICE(httpd_conf:clean(Rule0)++" is an invalid "++Type)}; + Rule -> + case string:chr(Rule, $\s) of + 0 -> + {ok, Acc, {Tag, {Rule, ""}}}; + N -> + {Re, [_|Replacement]} = lists:split(N-1, Rule), + {ok, Acc, {Tag, {Re, Replacement}}} + end end. store({directory_index, Value} = Conf, _) when is_list(Value) -> @@ -200,16 +245,36 @@ store({directory_index, Value} = Conf, _) when is_list(Value) -> end; store({directory_index, Value}, _) -> {error, {wrong_type, {directory_index, Value}}}; -store({alias, {Fake, Real}} = Conf, _) - when is_list(Fake) andalso is_list(Real) -> +store({alias, {Fake, Real}} = Conf, _) + when is_list(Fake), is_list(Real) -> {ok, Conf}; store({alias, Value}, _) -> {error, {wrong_type, {alias, Value}}}; +store({re_write, {Re, Replacement}} = Conf, _) + when is_list(Re), is_list(Replacement) -> + case re:compile(Re) of + {ok, MP} -> + {ok, {alias, {MP, Replacement}}}; + {error,_} -> + {error, {re_compile, Conf}} + end; +store({re_write, _} = Conf, _) -> + {error, {wrong_type, Conf}}; store({script_alias, {Fake, Real}} = Conf, _) - when is_list(Fake) andalso is_list(Real) -> + when is_list(Fake), is_list(Real) -> {ok, Conf}; store({script_alias, Value}, _) -> - {error, {wrong_type, {script_alias, Value}}}. + {error, {wrong_type, {script_alias, Value}}}; +store({script_re_write, {Re, Replacement}} = Conf, _) + when is_list(Re), is_list(Replacement) -> + case re:compile(Re) of + {ok, MP} -> + {ok, {script_alias, {MP, Replacement}}}; + {error,_} -> + {error, {re_compile, Conf}} + end; +store({script_re_write, _} = Conf, _) -> + {error, {wrong_type, Conf}}. is_directory_index_list([]) -> true; diff --git a/lib/inets/src/http_server/mod_esi.erl b/lib/inets/src/http_server/mod_esi.erl index cb33544540..f7877aa9e2 100644 --- a/lib/inets/src/http_server/mod_esi.erl +++ b/lib/inets/src/http_server/mod_esi.erl @@ -29,6 +29,7 @@ -export([do/1, load/2, store/2]). -include("httpd.hrl"). +-include("httpd_internal.hrl"). -define(VMODULE,"ESI"). -define(DEFAULT_ERL_TIMEOUT,15000). @@ -37,6 +38,7 @@ %%%========================================================================= %%% API %%%========================================================================= + %%-------------------------------------------------------------------------- %% deliver(SessionID, Data) -> ok | {error, bad_sessionID} %% SessionID = pid() @@ -48,7 +50,7 @@ %% request handling process so it can forward it to the client. %%------------------------------------------------------------------------- deliver(SessionID, Data) when is_pid(SessionID) -> - SessionID ! {ok, Data}, + SessionID ! {esi_data, Data}, ok; deliver(_SessionID, _Data) -> {error, bad_sessionID}. @@ -65,6 +67,7 @@ deliver(_SessionID, _Data) -> %% Description: See httpd(3) ESWAPI CALLBACK FUNCTIONS %%------------------------------------------------------------------------- do(ModData) -> + ?hdrt("do", []), case proplists:get_value(status, ModData#mod.data) of {_StatusCode, _PhraseArgs, _Reason} -> {proceed, ModData#mod.data}; @@ -184,6 +187,7 @@ store({erl_script_nocache, Value}, _) -> %%% Internal functions %%%======================================================================== generate_response(ModData) -> + ?hdrt("generate response", []), case scheme(ModData#mod.request_uri, ModData#mod.config_db) of {eval, ESIBody, Modules} -> eval(ModData, ESIBody, Modules); @@ -235,6 +239,7 @@ alias_match_str(Alias, eval_script_alias) -> erl(#mod{method = Method} = ModData, ESIBody, Modules) when (Method =:= "GET") orelse (Method =:= "HEAD") -> + ?hdrt("erl", [{method, Method}]), case httpd_util:split(ESIBody,":|%3A|/",2) of {ok, [ModuleName, FuncAndInput]} -> case httpd_util:split(FuncAndInput,"[\?/]",2) of @@ -260,6 +265,7 @@ erl(#mod{request_uri = ReqUri, method = "PUT", http_version = Version, data = Data}, _ESIBody, _Modules) -> + ?hdrt("erl", [{method, put}]), {proceed, [{status,{501,{"PUT", ReqUri, Version}, ?NICE("Erl mechanism doesn't support method PUT")}}| Data]}; @@ -268,12 +274,14 @@ erl(#mod{request_uri = ReqUri, method = "DELETE", http_version = Version, data = Data}, _ESIBody, _Modules) -> + ?hdrt("erl", [{method, delete}]), {proceed,[{status,{501,{"DELETE", ReqUri, Version}, ?NICE("Erl mechanism doesn't support method DELETE")}}| Data]}; erl(#mod{method = "POST", entity_body = Body} = ModData, ESIBody, Modules) -> + ?hdrt("erl", [{method, post}]), case httpd_util:split(ESIBody,":|%3A|/",2) of {ok,[ModuleName, Function]} -> generate_webpage(ModData, ESIBody, Modules, @@ -289,6 +297,7 @@ generate_webpage(ModData, ESIBody, [all], Module, FunctionName, FunctionName, Input, ScriptElements); generate_webpage(ModData, ESIBody, Modules, Module, FunctionName, Input, ScriptElements) -> + ?hdrt("generate webpage", []), Function = list_to_atom(FunctionName), case lists:member(Module, Modules) of true -> @@ -309,8 +318,9 @@ generate_webpage(ModData, ESIBody, Modules, Module, FunctionName, %% Old API that waits for the dymnamic webpage to be totally generated %% before anythig is sent back to the client. -erl_scheme_webpage_whole(Module, Function, Env, Input, ModData) -> - case (catch Module:Function(Env, Input)) of +erl_scheme_webpage_whole(Mod, Func, Env, Input, ModData) -> + ?hdrt("erl_scheme_webpage_whole", [{module, Mod}, {function, Func}]), + case (catch Mod:Func(Env, Input)) of {'EXIT',{undef, _}} -> {proceed, [{status, {404, ModData#mod.request_uri, "Not found"}} | ModData#mod.data]}; @@ -347,6 +357,7 @@ erl_scheme_webpage_whole(Module, Function, Env, Input, ModData) -> %% in small chunks at the time during generation. erl_scheme_webpage_chunk(Mod, Func, Env, Input, ModData) -> process_flag(trap_exit, true), + ?hdrt("erl_scheme_webpage_chunk", [{module, Mod}, {function, Func}]), Self = self(), %% Spawn worker that generates the webpage. %% It would be nicer to use erlang:function_exported/3 but if the @@ -372,9 +383,12 @@ deliver_webpage_chunk(#mod{config_db = Db} = ModData, Pid) -> deliver_webpage_chunk(ModData, Pid, Timeout). deliver_webpage_chunk(#mod{config_db = Db} = ModData, Pid, Timeout) -> + ?hdrt("deliver_webpage_chunk", [{timeout, Timeout}]), case receive_headers(Timeout) of {error, Reason} -> %% Happens when webpage generator callback/3 is undefined + ?hdrv("deliver_webpage_chunk - failed receiving headers", + [{reason, Reason}]), {error, Reason}; {Headers, Body} -> case httpd_esi:handle_headers(Headers) of @@ -399,6 +413,7 @@ deliver_webpage_chunk(#mod{config_db = Db} = ModData, Pid, Timeout) -> IsDisableChunkedSend) end; timeout -> + ?hdrv("deliver_webpage_chunk - timeout", []), send_headers(ModData, {504, "Timeout"},[{"connection", "close"}]), httpd_socket:close(ModData#mod.socket_type, ModData#mod.socket), process_flag(trap_exit,false), @@ -407,11 +422,17 @@ deliver_webpage_chunk(#mod{config_db = Db} = ModData, Pid, Timeout) -> receive_headers(Timeout) -> receive + {esi_data, Chunk} -> + ?hdrt("receive_headers - received esi data (esi)", []), + httpd_esi:parse_headers(lists:flatten(Chunk)); {ok, Chunk} -> + ?hdrt("receive_headers - received esi data (ok)", []), httpd_esi:parse_headers(lists:flatten(Chunk)); {'EXIT', Pid, erl_scheme_webpage_chunk_undefined} when is_pid(Pid) -> + ?hdrd("receive_headers - exit:chunk-undef", []), {error, erl_scheme_webpage_chunk_undefined}; {'EXIT', Pid, Reason} when is_pid(Pid) -> + ?hdrv("receive_headers - exit", [{reason, Reason}]), exit({mod_esi_linked_process_died, Pid, Reason}) after Timeout -> timeout @@ -427,19 +448,29 @@ handle_body(_, #mod{method = "HEAD"} = ModData, _, _, Size, _) -> {proceed, [{response, {already_sent, 200, Size}} | ModData#mod.data]}; handle_body(Pid, ModData, Body, Timeout, Size, IsDisableChunkedSend) -> + ?hdrt("handle_body - send chunk", [{timeout, Timeout}, {size, Size}]), httpd_response:send_chunk(ModData, Body, IsDisableChunkedSend), receive + {esi_data, Data} -> + ?hdrt("handle_body - received data (esi)", []), + handle_body(Pid, ModData, Data, Timeout, Size + length(Data), + IsDisableChunkedSend); {ok, Data} -> + ?hdrt("handle_body - received data (ok)", []), handle_body(Pid, ModData, Data, Timeout, Size + length(Data), IsDisableChunkedSend); {'EXIT', Pid, normal} when is_pid(Pid) -> + ?hdrt("handle_body - exit:normal", []), httpd_response:send_final_chunk(ModData, IsDisableChunkedSend), {proceed, [{response, {already_sent, 200, Size}} | ModData#mod.data]}; {'EXIT', Pid, Reason} when is_pid(Pid) -> + ?hdrv("handle_body - exit", [{reason, Reason}]), httpd_response:send_final_chunk(ModData, IsDisableChunkedSend), exit({mod_esi_linked_process_died, Pid, Reason}) + after Timeout -> + ?hdrv("handle_body - timeout", []), process_flag(trap_exit,false), httpd_response:send_final_chunk(ModData, IsDisableChunkedSend), exit({mod_esi_linked_process_timeout, Pid}) @@ -473,6 +504,7 @@ eval(#mod{request_uri = ReqUri, method = "PUT", http_version = Version, data = Data}, _ESIBody, _Modules) -> + ?hdrt("eval", [{method, put}]), {proceed,[{status,{501,{"PUT", ReqUri, Version}, ?NICE("Eval mechanism doesn't support method PUT")}}| Data]}; @@ -481,6 +513,7 @@ eval(#mod{request_uri = ReqUri, method = "DELETE", http_version = Version, data = Data}, _ESIBody, _Modules) -> + ?hdrt("eval", [{method, delete}]), {proceed,[{status,{501,{"DELETE", ReqUri, Version}, ?NICE("Eval mechanism doesn't support method DELETE")}}| Data]}; @@ -489,12 +522,14 @@ eval(#mod{request_uri = ReqUri, method = "POST", http_version = Version, data = Data}, _ESIBody, _Modules) -> + ?hdrt("eval", [{method, post}]), {proceed,[{status,{501,{"POST", ReqUri, Version}, ?NICE("Eval mechanism doesn't support method POST")}}| Data]}; eval(#mod{method = Method} = ModData, ESIBody, Modules) - when Method == "GET"; Method == "HEAD" -> + when (Method =:= "GET") orelse (Method =:= "HEAD") -> + ?hdrt("eval", [{method, Method}]), case is_authorized(ESIBody, Modules) of true -> case generate_webpage(ESIBody) of diff --git a/lib/inets/src/inets_app/Makefile b/lib/inets/src/inets_app/Makefile index 33c9e34a3a..4632ff3b68 100644 --- a/lib/inets/src/inets_app/Makefile +++ b/lib/inets/src/inets_app/Makefile @@ -66,19 +66,16 @@ APPUP_SRC = $(APPUP_FILE).src APPUP_TARGET = $(EBIN)/$(APPUP_FILE) -# ---------------------------------------------------- -# INETS FLAGS -# ---------------------------------------------------- -INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' - - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- -ERL_COMPILE_FLAGS += $(INETS_FLAGS) \ - +'{parse_transform,sys_pre_attributes}' \ - +'{attribute,insert,app_vsn,$(APP_VSN)}' +include inets.mk + +ERL_COMPILE_FLAGS += \ + $(INETS_FLAGS) \ + $(INETS_ERL_COMPILE_FLAGS) \ + -I../../include # ---------------------------------------------------- @@ -112,7 +109,8 @@ include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt $(INSTALL_DIR) $(RELSYSDIR)/src - $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/src/inets_app + $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/inets_app $(INSTALL_DIR) $(RELSYSDIR)/ebin $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin diff --git a/lib/inets/src/inets_app/inets.app.src b/lib/inets/src/inets_app/inets.app.src index 04f6365b98..cb036157a5 100644 --- a/lib/inets/src/inets_app/inets.app.src +++ b/lib/inets/src/inets_app/inets.app.src @@ -107,5 +107,6 @@ tftp_sup ]}, {registered,[inets_sup, httpc_manager]}, + %% If the "new" ssl is used then 'crypto' must be started before inets. {applications,[kernel,stdlib]}, {mod,{inets_app,[]}}]}. diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index 718f37b09e..64fe664006 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -18,29 +18,24 @@ {"%VSN%", [ + {"5.3.3", + [ + {restart_application, inets} + ] + }, {"5.3.2", [ - {load_module, http_util, soft_purge, soft_purge, []}, - {load_module, httpc_cookie, soft_purge, soft_purge, []} + {restart_application, inets} ] }, {"5.3.1", [ - {load_module, http_util, soft_purge, soft_purge, []}, - {load_module, httpc, soft_purge, soft_purge, []}, - {load_module, httpc_cookie, soft_purge, soft_purge, []}, - {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_manager]}, - {update, httpc_manager, soft, soft_purge, soft_purge, []} + {restart_application, inets} ] }, {"5.3", [ - {load_module, http_util, soft_purge, soft_purge, []}, - {load_module, httpc, soft_purge, soft_purge, []}, - {load_module, httpc_cookie, soft_purge, soft_purge, []}, - {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_manager]}, - {update, httpc_manager, soft, soft_purge, soft_purge, []}, - {load_module, mod_esi, soft_purge, soft_purge, []} + {restart_application, inets} ] }, {"5.2", @@ -60,29 +55,24 @@ } ], [ + {"5.3.3", + [ + {restart_application, inets} + ] + }, {"5.3.2", [ - {load_module, http_util, soft_purge, soft_purge, []}, - {load_module, httpc_cookie, soft_purge, soft_purge, []} + {restart_application, inets} ] }, {"5.3.1", [ - {load_module, http_util, soft_purge, soft_purge, []}, - {load_module, httpc, soft_purge, soft_purge, []}, - {load_module, httpc_cookie, soft_purge, soft_purge, []}, - {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_manager]}, - {update, httpc_manager, soft, soft_purge, soft_purge, []} + {restart_application, inets} ] }, {"5.3", [ - {load_module, http_util, soft_purge, soft_purge, []}, - {load_module, httpc, soft_purge, soft_purge, []}, - {load_module, httpc_cookie, soft_purge, soft_purge, []}, - {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_manager]}, - {update, httpc_manager, soft, soft_purge, soft_purge, []}, - {load_module, mod_esi, soft_purge, soft_purge, []} + {restart_application, inets} ] }, {"5.2", diff --git a/lib/inets/src/inets_app/inets.mk b/lib/inets/src/inets_app/inets.mk new file mode 100644 index 0000000000..b6e9fe1d96 --- /dev/null +++ b/lib/inets/src/inets_app/inets.mk @@ -0,0 +1,45 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +ifeq ($(INETS_TRACE), io) +ERL_COMPILE_FLAGS += -Dinets_trace_io +endif + +ifeq ($(INETS_DEBUG), true) +ERL_COMPILE_FLAGS += -Dinets_debug +endif + +ifeq ($(USE_INETS_HIPE), true) +ERL_COMPILE_FLAGS += +native +endif + +ifeq ($(WARN_UNUSED_WARS), true) +ERL_COMPILE_FLAGS += +warn_unused_vars +endif + +INETS_APP_VSN_COMPILE_FLAGS = \ + +'{parse_transform,sys_pre_attributes}' \ + +'{attribute,insert,app_vsn,$(APP_VSN)}' + +INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' + +INETS_ERL_COMPILE_FLAGS += \ + -pa $(ERL_TOP)/lib/inets/ebin \ + $(INETS_APP_VSN_COMPILE_FLAGS) + diff --git a/lib/inets/src/inets_app/inets_service.erl b/lib/inets/src/inets_app/inets_service.erl index 3499314d54..e9eb9892f2 100644 --- a/lib/inets/src/inets_app/inets_service.erl +++ b/lib/inets/src/inets_app/inets_service.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -61,5 +61,5 @@ behaviour_info(_) -> %% service_info() -> [{Property, Value}] | {error, Reason} -%% ex: http:service_info() -> [{profile, ProfileName}] +%% ex: httpc:service_info() -> [{profile, ProfileName}] %% httpd:service_info() -> [{host, Host}, {port, Port}] diff --git a/lib/inets/src/tftp/Makefile b/lib/inets/src/tftp/Makefile index b4339da1e2..759b70c8e4 100644 --- a/lib/inets/src/tftp/Makefile +++ b/lib/inets/src/tftp/Makefile @@ -56,17 +56,16 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) # ---------------------------------------------------- -# INETS FLAGS +# FLAGS # ---------------------------------------------------- -INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' +include ../inets_app/inets.mk -# ---------------------------------------------------- -# FLAGS -# ---------------------------------------------------- -ERL_COMPILE_FLAGS += $(INETS_FLAGS) \ - +'{parse_transform,sys_pre_attributes}' \ - +'{attribute,insert,app_vsn,$(APP_VSN)}' +ERL_COMPILE_FLAGS += \ + $(INETS_FLAGS) \ + $(INETS_ERL_COMPILE_FLAGS) \ + -I../../include \ + -I../inets_app # ---------------------------------------------------- @@ -87,9 +86,10 @@ docs: include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/src - $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src - $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/src/tftp + $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/tftp + $(INSTALL_DIR) $(RELSYSDIR)/ebin $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin release_docs_spec: -- cgit v1.2.3