⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ejabberd_http.erl

📁 ejabberd-0.7.5 分布式Jabber服务器
💻 ERL
📖 第 1 页 / 共 2 页
字号:
%%%----------------------------------------------------------------------%%% File    : ejabberd_http.erl%%% Author  : Alexey Shchepin <alexey@sevcom.net>%%% Purpose : %%% Created : 27 Feb 2004 by Alexey Shchepin <alexey@sevcom.net>%%% Id      : $Id: ejabberd_http.erl,v 1.16 2004/09/30 21:54:39 aleksey Exp $%%%-----------------------------------------------------------------------module(ejabberd_http).-author('alexey@sevcom.net').-vsn('$Revision: 1.16 $ ').%% External exports-export([start/2,	 start_link/2,	 receive_headers/1]).-include("ejabberd.hrl").-include("jlib.hrl").-include("ejabberd_http.hrl").-record(state, {sockmod,		socket,		request_method,		request_version,		request_path,		request_auth,		request_keepalive,		request_content_length,		request_lang = "en",		use_http_poll = false,		use_web_admin = false,		end_of_request = false,		trail = ""	       }).-define(XHTML_DOCTYPE,	"<?xml version='1.0'?>\n"	"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" "	"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n").-define(HTML_DOCTYPE,	"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n").start(SockData, Opts) ->    supervisor:start_child(ejabberd_http_sup, [SockData, Opts]).start_link({SockMod, Socket}, Opts) ->    TLSEnabled = lists:member(tls, Opts),    TLSOpts = lists:filter(fun({certfile, _}) -> true;			      (_) -> false			   end, Opts),    {SockMod1, Socket1} =	if	    TLSEnabled ->		inet:setopts(Socket, [{recbuf, 8192}]),		{ok, TLSSocket} = tls:tcp_to_tls(Socket, TLSOpts),		{tls, TLSSocket};	    true ->		{SockMod, Socket}	end,    case SockMod1 of	gen_tcp ->	    inet:setopts(Socket1, [{packet, http}, {recbuf, 8192}]);	_ ->	    ok    end,    UseHTTPPoll = lists:member(http_poll, Opts),    UseWebAdmin = lists:member(web_admin, Opts),    ?DEBUG("S: ~p~n", [{UseHTTPPoll, UseWebAdmin}]),    ?INFO_MSG("started: ~p", [{SockMod1, Socket1}]),    {ok, proc_lib:spawn_link(ejabberd_http,			     receive_headers,			     [#state{sockmod = SockMod1,				     socket = Socket1,				     use_http_poll = UseHTTPPoll,				     use_web_admin = UseWebAdmin}])}.send_text(State, Text) ->    (State#state.sockmod):send(State#state.socket, Text).receive_headers(State) ->    SockMod = State#state.sockmod,    Socket = State#state.socket,    Data = SockMod:recv(Socket, 0, 300000),    case State#state.sockmod of	gen_tcp ->	    NewState = process_header(State, Data),	    case NewState#state.end_of_request of		true ->		    ok;		_ ->		    receive_headers(NewState)	    end;	_ ->	    case Data of		{ok, Binary} ->		    {Request, Trail} = parse_request(					 State,					 State#state.trail ++ binary_to_list(Binary)),		    State1 = State#state{trail = Trail},		    NewState = lists:foldl(				 fun(D, S) ->					case S#state.end_of_request of					    true ->						S;					    _ ->						process_header(S, D)					end				 end, State1, Request),		    case NewState#state.end_of_request of			true ->			    ok;			_ ->			    receive_headers(NewState)		    end;		_ ->		    ok	    end    end.process_header(State, Data) ->    SockMod = State#state.sockmod,    Socket = State#state.socket,    case Data of	{ok, {http_request, Method, Path, Version}} ->	    KeepAlive = case Version of		{1, 1} ->		    true;		_ ->		    false	    end,	    State#state{request_method = Method,			request_version = Version,			request_path = Path,			request_keepalive = KeepAlive};	{ok, {http_header, _, 'Connection', _, Conn}} ->	    KeepAlive1 = case Conn of		"keep-alive" ->		    true;		"close" ->		    false;		_ ->		    State#state.request_keepalive	    end,	    State#state{request_keepalive = KeepAlive1};	{ok, {http_header, _, 'Authorization', _, Auth}} ->	    State#state{request_auth = parse_auth(Auth)};	{ok, {http_header, _, 'Content-Length', _, SLen}} ->	    case catch list_to_integer(SLen) of		Len when is_integer(Len) ->		    State#state{request_content_length = Len};		_ ->		    State	    end;	{ok, {http_header, _, 'Accept-Language', _, Langs}} ->	    State#state{request_lang = parse_lang(Langs)};	{ok, {http_header, _, _, _, _}} ->	    State;	{ok, http_eoh} ->	    ?INFO_MSG("(~w) http query: ~w ~s~n",		      [State#state.socket,		       State#state.request_method,		       element(2, State#state.request_path)]),	    Out = process_request(State),	    send_text(State, Out),	    case State#state.request_keepalive of		true ->		    case SockMod of			gen_tcp ->			    inet:setopts(Socket, [{packet, http}]);			_ ->			    ok		    end,		    #state{sockmod = SockMod,			   socket = Socket,			   use_http_poll = State#state.use_http_poll,			   use_web_admin = State#state.use_web_admin};		_ ->		    #state{end_of_request = true}	    end;	{error, _Reason} ->	    #state{end_of_request = true};	_ ->	    #state{end_of_request = true}    end.process_request(#state{request_method = 'GET',		       request_path = {abs_path, Path},		       request_auth = Auth,		       request_lang = Lang,		       use_http_poll = UseHTTPPoll,		       use_web_admin = UseWebAdmin}) ->    User = case Auth of	       {U, P} ->		   case ejabberd_auth:check_password(U, P) of		       true ->			   U;		       false ->			   unauthorized		   end;	       _ ->		   undefined	   end,    case User of	unauthorized ->	    make_xhtml_output(	      401,	      [{"WWW-Authenticate", "basic realm=\"ejabberd\""}],	      ejabberd_web:make_xhtml([{xmlelement, "h1", [],					[{xmlcdata, "401 Unauthorized"}]}]));	_ ->	    case (catch url_decode_q_split(Path)) of		{'EXIT', _} ->		    process_request(false);		{NPath, Query} ->		    LQuery = case (catch parse_urlencoded(Query)) of				 {'EXIT', _Reason} ->				     [];				 LQ ->				     LQ			     end,		    LPath = string:tokens(NPath, "/"),		    Request = #request{method = 'GET',				       path = LPath,				       q = LQuery,				       user = User,				       lang = Lang},		    case ejabberd_web:process_get({UseHTTPPoll, UseWebAdmin},						  Request) of			El when element(1, El) == xmlelement ->			    make_xhtml_output(200, [], El);			{Status, Headers, El} when			      element(1, El) == xmlelement ->			    make_xhtml_output(Status, Headers, El);			Text when is_list(Text) ->			    make_text_output(200, [], Text);			{Status, Headers, Text} when			      is_list(Text) ->			    make_text_output(Status, Headers, Text)		    end	    end    end;process_request(#state{request_method = 'POST',		       request_path = {abs_path, Path},		       request_auth = Auth,		       request_content_length = Len,		       request_lang = Lang,		       sockmod = SockMod,		       socket = Socket,		       use_http_poll = UseHTTPPoll,		       use_web_admin = UseWebAdmin} = State)  when is_integer(Len) ->    User = case Auth of	       {U, P} ->		   case ejabberd_auth:check_password(U, P) of		       true ->			   U;		       false ->			   unauthorized		   end;	       _ ->		   undefined	   end,    case User of	unauthorized ->	    make_xhtml_output(	      401,	      [{"WWW-Authenticate", "basic realm=\"ejabberd\""}],	      ejabberd_web:make_xhtml([{xmlelement, "h1", [],					[{xmlcdata, "401 Unauthorized"}]}]));	_ ->    	    case SockMod of		gen_tcp ->		    inet:setopts(Socket, [{packet, 0}]);		_ ->		    ok	    end,	    Data = recv_data(State, Len),	    ?DEBUG("client data: ~p~n", [Data]),	    case (catch url_decode_q_split(Path)) of		{'EXIT', _} ->		    process_request(false);		{NPath, Query} ->		    LPath = string:tokens(NPath, "/"),		    LQuery = case (catch parse_urlencoded(Data)) of				 {'EXIT', _Reason} ->				     [];				 LQ ->				     LQ			     end,		    Request = #request{method = 'POST',				       path = LPath,				       q = LQuery,				       user = User,				       data = Data,				       lang = Lang},		    case ejabberd_web:process_get({UseHTTPPoll, UseWebAdmin},						  Request) of			El when element(1, El) == xmlelement ->			    make_xhtml_output(200, [], El);			{Status, Headers, El} when			      element(1, El) == xmlelement ->			    make_xhtml_output(Status, Headers, El);			Text when is_list(Text) ->			    make_text_output(200, [], Text);			{Status, Headers, Text} when is_list(Text) ->			    make_text_output(Status, Headers, Text)		    end	    end    end;process_request(_) ->    make_xhtml_output(      400,      [],      ejabberd_web:make_xhtml([{xmlelement, "h1", [],				[{xmlcdata, "400 Bad Request"}]}])).recv_data(State, Len) ->    recv_data(State, Len, []).recv_data(State, 0, Acc) ->    binary_to_list(list_to_binary(Acc));recv_data(State, Len, Acc) ->    case State#state.trail of	[] ->	    case (State#state.sockmod):recv(State#state.socket, Len, 300000) of		{ok, Data} ->		    recv_data(State, Len - size(Data), [Acc | Data]);		_ ->		    ""	    end;	_ ->	    Trail = State#state.trail,	    recv_data(State#state{trail = ""}, Len - length(Trail), [Acc | Trail])    end.make_xhtml_output(Status, Headers, XHTML) ->    Data = case lists:member(html, Headers) of	       true ->		   list_to_binary([?HTML_DOCTYPE,				   xml:element_to_string(XHTML)]);	       _ ->		   list_to_binary([?XHTML_DOCTYPE,				   xml:element_to_string(XHTML)])	   end,    Headers1 = case lists:keysearch("Content-Type", 1, Headers) of		   {value, _} ->		       [{"Content-Length", integer_to_list(size(Data))} |			Headers];		   _ ->		       [{"Content-Type", "text/html; charset=utf-8"},			{"Content-Length", integer_to_list(size(Data))} |			Headers]	       end,    H = lists:map(fun({Attr, Val}) ->			  [Attr, ": ", Val, "\r\n"];		     (_) ->			  []		  end, Headers1),    SL = ["HTTP/1.1 ", integer_to_list(Status), " ",	  code_to_phrase(Status), "\r\n"],    [SL, H, "\r\n", Data].make_text_output(Status, Headers, Text) ->    Data = list_to_binary(Text),    Headers1 = case lists:keysearch("Content-Type", 1, Headers) of		   {value, _} ->		       [{"Content-Length", integer_to_list(size(Data))} |			Headers];		   _ ->		       [{"Content-Type", "text/html; charset=utf-8"},			{"Content-Length", integer_to_list(size(Data))} |			Headers]	       end,    H = lists:map(fun({Attr, Val}) ->			  [Attr, ": ", Val, "\r\n"]		  end, Headers1),    SL = ["HTTP/1.1 ", integer_to_list(Status), " ",	  code_to_phrase(Status), "\r\n"],    [SL, H, "\r\n", Data].    parse_lang(Langs) ->    case string:tokens(Langs, ",; ") of	[First | _] ->	    First;	[] ->	    "en"    end.% Code below is taken (with some modifications) from the yaws webserver, which% is distributed under the folowing license:%% This software (the yaws webserver) is free software.% Parts of this software is Copyright (c) Claes Wikstrom <klacke@hyber.org>% Any use or misuse of the source code is hereby freely allowed.%% 1. Redistributions of source code must retain the above copyright%    notice as well as this list of conditions.%% 2. Redistributions in binary form must reproduce the above copyright

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -