📄 ejabberd_http.erl
字号:
% notice as well as this list of conditions.%% url decode the path and return {Path, QueryPart}url_decode_q_split(Path) -> url_decode_q_split(Path, []).url_decode_q_split([$%, $C, $2, $%, Hi, Lo | Tail], Ack) -> Hex = hex_to_integer([Hi, Lo]), url_decode_q_split(Tail, [Hex|Ack]);url_decode_q_split([$%, $C, $3, $%, Hi, Lo | Tail], Ack) when Hi > $9 -> Hex = hex_to_integer([Hi+4, Lo]), url_decode_q_split(Tail, [Hex|Ack]);url_decode_q_split([$%, $C, $3, $%, Hi, Lo | Tail], Ack) when Hi < $A -> Hex = hex_to_integer([Hi+4+7, Lo]), url_decode_q_split(Tail, [Hex|Ack]);url_decode_q_split([$%, Hi, Lo | Tail], Ack) -> Hex = hex_to_integer([Hi, Lo]), url_decode_q_split(Tail, [Hex|Ack]);url_decode_q_split([$?|T], Ack) -> %% Don't decode the query string here, that is parsed separately. {path_norm_reverse(Ack), T};url_decode_q_split([H|T], Ack) -> url_decode_q_split(T, [H|Ack]);url_decode_q_split([], Ack) -> {path_norm_reverse(Ack), []}.path_norm_reverse("/" ++ T) -> start_dir(0, "/", T);path_norm_reverse( T) -> start_dir(0, "", T).start_dir(N, Path, ".." ) -> rest_dir(N, Path, "");start_dir(N, Path, "/" ++ T ) -> start_dir(N , Path, T);start_dir(N, Path, "./" ++ T ) -> start_dir(N , Path, T);start_dir(N, Path, "../" ++ T ) -> start_dir(N + 1, Path, T);start_dir(N, Path, T ) -> rest_dir (N , Path, T).rest_dir (_N, Path, [] ) -> case Path of [] -> "/"; _ -> Path end;rest_dir (0, Path, [ $/ | T ] ) -> start_dir(0 , [ $/ | Path ], T);rest_dir (N, Path, [ $/ | T ] ) -> start_dir(N - 1, Path , T);rest_dir (0, Path, [ H | T ] ) -> rest_dir (0 , [ H | Path ], T);rest_dir (N, Path, [ _H | T ] ) -> rest_dir (N , Path , T).%% hex_to_integerhex_to_integer(Hex) -> case catch erlang:list_to_integer(Hex, 16) of {'EXIT', _} -> old_hex_to_integer(Hex); X -> X end.old_hex_to_integer(Hex) -> DEHEX = fun (H) when H >= $a, H =< $f -> H - $a + 10; (H) when H >= $A, H =< $F -> H - $A + 10; (H) when H >= $0, H =< $9 -> H - $0 end, lists:foldl(fun(E, Acc) -> Acc*16+DEHEX(E) end, 0, Hex).code_to_phrase(100) -> "Continue";code_to_phrase(101) -> "Switching Protocols ";code_to_phrase(200) -> "OK";code_to_phrase(201) -> "Created";code_to_phrase(202) -> "Accepted";code_to_phrase(203) -> "Non-Authoritative Information";code_to_phrase(204) -> "No Content";code_to_phrase(205) -> "Reset Content";code_to_phrase(206) -> "Partial Content";code_to_phrase(300) -> "Multiple Choices";code_to_phrase(301) -> "Moved Permanently";code_to_phrase(302) -> "Found";code_to_phrase(303) -> "See Other";code_to_phrase(304) -> "Not Modified";code_to_phrase(305) -> "Use Proxy";code_to_phrase(306) -> "(Unused)";code_to_phrase(307) -> "Temporary Redirect";code_to_phrase(400) -> "Bad Request";code_to_phrase(401) -> "Unauthorized";code_to_phrase(402) -> "Payment Required";code_to_phrase(403) -> "Forbidden";code_to_phrase(404) -> "Not Found";code_to_phrase(405) -> "Method Not Allowed";code_to_phrase(406) -> "Not Acceptable";code_to_phrase(407) -> "Proxy Authentication Required";code_to_phrase(408) -> "Request Timeout";code_to_phrase(409) -> "Conflict";code_to_phrase(410) -> "Gone";code_to_phrase(411) -> "Length Required";code_to_phrase(412) -> "Precondition Failed";code_to_phrase(413) -> "Request Entity Too Large";code_to_phrase(414) -> "Request-URI Too Long";code_to_phrase(415) -> "Unsupported Media Type";code_to_phrase(416) -> "Requested Range Not Satisfiable";code_to_phrase(417) -> "Expectation Failed";code_to_phrase(500) -> "Internal Server Error";code_to_phrase(501) -> "Not Implemented";code_to_phrase(502) -> "Bad Gateway";code_to_phrase(503) -> "Service Unavailable";code_to_phrase(504) -> "Gateway Timeout";code_to_phrase(505) -> "HTTP Version Not Supported".parse_auth(Orig = "Basic " ++ Auth64) -> case decode_base64(Auth64) of {error, _Err} -> undefined; Auth -> case string:tokens(Auth, ":") of [User, Pass] -> {User, Pass}; _ -> undefined end end;parse_auth(_) -> undefined.decode_base64([]) -> [];decode_base64([Sextet1,Sextet2,$=,$=|Rest]) -> Bits2x6= (d(Sextet1) bsl 18) bor (d(Sextet2) bsl 12), Octet1=Bits2x6 bsr 16, [Octet1|decode_base64(Rest)];decode_base64([Sextet1,Sextet2,Sextet3,$=|Rest]) -> Bits3x6= (d(Sextet1) bsl 18) bor (d(Sextet2) bsl 12) bor (d(Sextet3) bsl 6), Octet1=Bits3x6 bsr 16, Octet2=(Bits3x6 bsr 8) band 16#ff, [Octet1,Octet2|decode_base64(Rest)];decode_base64([Sextet1,Sextet2,Sextet3,Sextet4|Rest]) -> Bits4x6= (d(Sextet1) bsl 18) bor (d(Sextet2) bsl 12) bor (d(Sextet3) bsl 6) bor d(Sextet4), Octet1=Bits4x6 bsr 16, Octet2=(Bits4x6 bsr 8) band 16#ff, Octet3=Bits4x6 band 16#ff, [Octet1,Octet2,Octet3|decode_base64(Rest)];decode_base64(_CatchAll) -> {error, bad_base64}.d(X) when X >= $A, X =<$Z -> X-65;d(X) when X >= $a, X =<$z -> X-71;d(X) when X >= $0, X =<$9 -> X+4;d($+) -> 62;d($/) -> 63;d(_) -> 63.parse_urlencoded(S) -> parse_urlencoded(S, nokey, [], key).parse_urlencoded([$%, Hi, Lo | Tail], Last, Cur, State) -> Hex = hex_to_integer([Hi, Lo]), parse_urlencoded(Tail, Last, [Hex | Cur], State);parse_urlencoded([$& | Tail], _Last, Cur, key) -> [{lists:reverse(Cur), ""} | parse_urlencoded(Tail, nokey, [], key)]; %% cont keymodeparse_urlencoded([$& | Tail], Last, Cur, value) -> V = {Last, lists:reverse(Cur)}, [V | parse_urlencoded(Tail, nokey, [], key)];parse_urlencoded([$+ | Tail], Last, Cur, State) -> parse_urlencoded(Tail, Last, [$\s | Cur], State);parse_urlencoded([$= | Tail], _Last, Cur, key) -> parse_urlencoded(Tail, lists:reverse(Cur), [], value); %% change modeparse_urlencoded([H | Tail], Last, Cur, State) -> parse_urlencoded(Tail, Last, [H|Cur], State);parse_urlencoded([], Last, Cur, _State) -> [{Last, lists:reverse(Cur)}];parse_urlencoded(undefined, _, _, _) -> [].% The following code is mostly taken from yaws_ssl.erlparse_request(State, Data) -> case Data of [] -> {[], []}; _ -> ?DEBUG("GOT ssl data ~p~n", [Data]), {R, Trail} = case State#state.request_method of undefined -> {R1, Trail1} = get_req(Data), ?DEBUG("Parsed request ~p~n", [R1]), {[R1], Trail1}; _ -> {[], Data} end, {H, Trail2} = get_headers(Trail), {R ++ H, Trail2} end.get_req("\r\n\r\n" ++ _) -> bad_request;get_req("\r\n" ++ Data) -> get_req(Data);get_req(Data) -> {FirstLine, Trail} = lists:splitwith(fun not_eol/1, Data), R = parse_req(FirstLine), {R, Trail}. not_eol($\r)-> false;not_eol($\n) -> false;not_eol(_) -> true.get_word(Line)-> {Word, T} = lists:splitwith(fun(X)-> X /= $\ end, Line), {Word, lists:dropwhile(fun(X) -> X == $\ end, T)}.parse_req(Line) -> {MethodStr, L1} = get_word(Line), ?DEBUG("Method: ~p~n", [MethodStr]), case L1 of [] -> bad_request; _ -> {URI, L2} = get_word(L1), {VersionStr, L3} = get_word(L2), ?DEBUG("URI: ~p~nVersion: ~p~nL3: ~p~n", [URI, VersionStr, L3]), case L3 of [] -> Method = case MethodStr of "GET" -> 'GET'; "POST" -> 'POST'; "HEAD" -> 'HEAD'; "OPTIONS" -> 'OPTIONS'; "TRACE" -> 'TRACE'; "PUT" -> 'PUT'; "DELETE" -> 'DELETE'; S -> S end, Path = case URI of "*" -> % Is this correct? "*"; P -> % FIXME: Handle % absolute URIs {abs_path, P} end, case VersionStr of [] -> {ok, {http_request, Method, Path, {0,9}}}; "HTTP/1.0" -> {ok, {http_request, Method, Path, {1,0}}}; "HTTP/1.1" -> {ok, {http_request, Method, Path, {1,1}}}; _ -> bad_request end; _ -> bad_request end end.get_headers(Tail) -> get_headers([], Tail).get_headers(H, Tail) -> case get_line(Tail) of {incomplete, Tail2} -> {H, Tail2}; {line, Line, Tail2} -> get_headers(H ++ parse_line(Line), Tail2); {lastline, Line, Tail2} -> {H ++ parse_line(Line) ++ [{ok, http_eoh}], Tail2} end.parse_line("Connection:" ++ Con) -> [{ok, {http_header, undefined, 'Connection', undefined, strip_spaces(Con)}}];parse_line("Host:" ++ Con) -> [{ok, {http_header, undefined, 'Host', undefined, strip_spaces(Con)}}];parse_line("Accept:" ++ Con) -> [{ok, {http_header, undefined, 'Accept', undefined, strip_spaces(Con)}}];parse_line("If-Modified-Since:" ++ Con) -> [{ok, {http_header, undefined, 'If-Modified-Since', undefined, strip_spaces(Con)}}];parse_line("If-Match:" ++ Con) -> [{ok, {http_header, undefined, 'If-Match', undefined, strip_spaces(Con)}}];parse_line("If-None-Match:" ++ Con) -> [{ok, {http_header, undefined, 'If-None-Match', undefined, strip_spaces(Con)}}];parse_line("If-Range:" ++ Con) -> [{ok, {http_header, undefined, 'If-Range', undefined, strip_spaces(Con)}}];parse_line("If-Unmodified-Since:" ++ Con) -> [{ok, {http_header, undefined, 'If-Unmodified-Since', undefined, strip_spaces(Con)}}];parse_line("Range:" ++ Con) -> [{ok, {http_header, undefined, 'Range', undefined, strip_spaces(Con)}}];parse_line("User-Agent:" ++ Con) -> [{ok, {http_header, undefined, 'User-Agent', undefined, strip_spaces(Con)}}];parse_line("Accept-Ranges:" ++ Con) -> [{ok, {http_header, undefined, 'Accept-Ranges', undefined, strip_spaces(Con)}}];parse_line("Authorization:" ++ Con) -> [{ok, {http_header, undefined, 'Authorization', undefined, strip_spaces(Con)}}];parse_line("Keep-Alive:" ++ Con) -> [{ok, {http_header, undefined, 'Keep-Alive', undefined, strip_spaces(Con)}}];parse_line("Referer:" ++ Con) -> [{ok, {http_header, undefined, 'Referer', undefined, strip_spaces(Con)}}];parse_line("Content-type:"++Con) -> [{ok, {http_header, undefined, 'Content-Type', undefined, strip_spaces(Con)}}];parse_line("Content-Type:"++Con) -> [{ok, {http_header, undefined, 'Content-Type', undefined, strip_spaces(Con)}}];parse_line("Content-Length:"++Con) -> [{ok, {http_header, undefined, 'Content-Length', undefined, strip_spaces(Con)}}];parse_line("Content-length:"++Con) -> [{ok, {http_header, undefined, 'Content-Length', undefined, strip_spaces(Con)}}];parse_line("Cookie:"++Con) -> [{ok, {http_header, undefined, 'Cookie', undefined, strip_spaces(Con)}}];parse_line("Accept-Language:"++Con) -> [{ok, {http_header, undefined, 'Accept-Language', undefined, strip_spaces(Con)}}];parse_line("Accept-Encoding:"++Con) -> [{ok, {http_header, undefined, 'Accept-Encoding', undefined, strip_spaces(Con)}}];parse_line(S) -> case lists:splitwith(fun(C)->C /= $: end, S) of {Name, [$:|Val]} -> [{ok, {http_header, undefined, Name, undefined, strip_spaces(Val)}}]; _ -> [] end.is_space($\s) -> true;is_space($\r) -> true;is_space($\n) -> true;is_space($\r) -> true;is_space(_) -> false.strip_spaces(String) -> strip_spaces(String, both).strip_spaces(String, left) -> drop_spaces(String);strip_spaces(String, right) -> lists:reverse(drop_spaces(lists:reverse(String)));strip_spaces(String, both) -> strip_spaces(drop_spaces(String), right).drop_spaces([]) -> [];drop_spaces(YS=[X|XS]) -> case is_space(X) of true -> drop_spaces(XS); false -> YS end.is_nb_space(X) -> lists:member(X, [$\s, $\t]). % ret: {line, Line, Trail} | {lastline, Line, Trail}get_line(L) -> get_line(L, []).get_line("\r\n\r\n" ++ Tail, Cur) -> {lastline, lists:reverse(Cur), Tail};get_line("\r\n" ++ Tail, Cur) -> case Tail of [] -> {incomplete, lists:reverse(Cur) ++ "\r\n"}; _ -> case is_nb_space(hd(Tail)) of true -> %% multiline ... continue get_line(Tail, [$\n, $\r | Cur]); false -> {line, lists:reverse(Cur), Tail} end end;get_line([H|T], Cur) -> get_line(T, [H|Cur]).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -