mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-24 16:23:40 +01:00
Merge branch 'master' of github.com:processone/ejabberd
Conflicts: test/ejabberd_SUITE.erl
This commit is contained in:
commit
f57f267c54
1
.gitignore
vendored
1
.gitignore
vendored
@ -29,6 +29,7 @@
|
|||||||
/doc/version.tex
|
/doc/version.tex
|
||||||
/ebin/
|
/ebin/
|
||||||
/ejabberd.init
|
/ejabberd.init
|
||||||
|
/ejabberd.service
|
||||||
/ejabberdctl.example
|
/ejabberdctl.example
|
||||||
XmppAddr.hrl
|
XmppAddr.hrl
|
||||||
/rel/ejabberd/
|
/rel/ejabberd/
|
||||||
|
@ -1,301 +0,0 @@
|
|||||||
-- LDAPv3 ASN.1 specification, taken from RFC 2251
|
|
||||||
|
|
||||||
-- Lightweight-Directory-Access-Protocol-V3 DEFINITIONS
|
|
||||||
ELDAPv3 DEFINITIONS
|
|
||||||
IMPLICIT TAGS ::=
|
|
||||||
|
|
||||||
BEGIN
|
|
||||||
|
|
||||||
LDAPMessage ::= SEQUENCE {
|
|
||||||
messageID MessageID,
|
|
||||||
protocolOp CHOICE {
|
|
||||||
bindRequest BindRequest,
|
|
||||||
bindResponse BindResponse,
|
|
||||||
unbindRequest UnbindRequest,
|
|
||||||
searchRequest SearchRequest,
|
|
||||||
searchResEntry SearchResultEntry,
|
|
||||||
searchResDone SearchResultDone,
|
|
||||||
searchResRef SearchResultReference,
|
|
||||||
modifyRequest ModifyRequest,
|
|
||||||
modifyResponse ModifyResponse,
|
|
||||||
addRequest AddRequest,
|
|
||||||
addResponse AddResponse,
|
|
||||||
delRequest DelRequest,
|
|
||||||
delResponse DelResponse,
|
|
||||||
modDNRequest ModifyDNRequest,
|
|
||||||
modDNResponse ModifyDNResponse,
|
|
||||||
compareRequest CompareRequest,
|
|
||||||
compareResponse CompareResponse,
|
|
||||||
abandonRequest AbandonRequest,
|
|
||||||
extendedReq ExtendedRequest,
|
|
||||||
extendedResp ExtendedResponse },
|
|
||||||
controls [0] Controls OPTIONAL }
|
|
||||||
|
|
||||||
MessageID ::= INTEGER (0 .. maxInt)
|
|
||||||
|
|
||||||
maxInt INTEGER ::= 2147483647 -- (2^^31 - 1) --
|
|
||||||
|
|
||||||
LDAPString ::= OCTET STRING
|
|
||||||
|
|
||||||
LDAPOID ::= OCTET STRING
|
|
||||||
|
|
||||||
LDAPDN ::= LDAPString
|
|
||||||
|
|
||||||
RelativeLDAPDN ::= LDAPString
|
|
||||||
|
|
||||||
AttributeType ::= LDAPString
|
|
||||||
|
|
||||||
AttributeDescription ::= LDAPString
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Wahl, et. al. Standards Track [Page 44]
|
|
||||||
--
|
|
||||||
-- RFC 2251 LDAPv3 December 1997
|
|
||||||
|
|
||||||
|
|
||||||
AttributeDescriptionList ::= SEQUENCE OF
|
|
||||||
AttributeDescription
|
|
||||||
|
|
||||||
AttributeValue ::= OCTET STRING
|
|
||||||
|
|
||||||
AttributeValueAssertion ::= SEQUENCE {
|
|
||||||
attributeDesc AttributeDescription,
|
|
||||||
assertionValue AssertionValue }
|
|
||||||
|
|
||||||
AssertionValue ::= OCTET STRING
|
|
||||||
|
|
||||||
Attribute ::= SEQUENCE {
|
|
||||||
type AttributeDescription,
|
|
||||||
vals SET OF AttributeValue }
|
|
||||||
|
|
||||||
MatchingRuleId ::= LDAPString
|
|
||||||
|
|
||||||
LDAPResult ::= SEQUENCE {
|
|
||||||
resultCode ENUMERATED {
|
|
||||||
success (0),
|
|
||||||
operationsError (1),
|
|
||||||
protocolError (2),
|
|
||||||
timeLimitExceeded (3),
|
|
||||||
sizeLimitExceeded (4),
|
|
||||||
compareFalse (5),
|
|
||||||
compareTrue (6),
|
|
||||||
authMethodNotSupported (7),
|
|
||||||
strongAuthRequired (8),
|
|
||||||
-- 9 reserved --
|
|
||||||
referral (10), -- new
|
|
||||||
adminLimitExceeded (11), -- new
|
|
||||||
unavailableCriticalExtension (12), -- new
|
|
||||||
confidentialityRequired (13), -- new
|
|
||||||
saslBindInProgress (14), -- new
|
|
||||||
noSuchAttribute (16),
|
|
||||||
undefinedAttributeType (17),
|
|
||||||
inappropriateMatching (18),
|
|
||||||
constraintViolation (19),
|
|
||||||
attributeOrValueExists (20),
|
|
||||||
invalidAttributeSyntax (21),
|
|
||||||
-- 22-31 unused --
|
|
||||||
noSuchObject (32),
|
|
||||||
aliasProblem (33),
|
|
||||||
invalidDNSyntax (34),
|
|
||||||
-- 35 reserved for undefined isLeaf --
|
|
||||||
aliasDereferencingProblem (36),
|
|
||||||
-- 37-47 unused --
|
|
||||||
inappropriateAuthentication (48),
|
|
||||||
|
|
||||||
-- Wahl, et. al. Standards Track [Page 45]
|
|
||||||
--
|
|
||||||
-- RFC 2251 LDAPv3 December 1997
|
|
||||||
|
|
||||||
|
|
||||||
invalidCredentials (49),
|
|
||||||
insufficientAccessRights (50),
|
|
||||||
busy (51),
|
|
||||||
unavailable (52),
|
|
||||||
unwillingToPerform (53),
|
|
||||||
loopDetect (54),
|
|
||||||
-- 55-63 unused --
|
|
||||||
namingViolation (64),
|
|
||||||
objectClassViolation (65),
|
|
||||||
notAllowedOnNonLeaf (66),
|
|
||||||
notAllowedOnRDN (67),
|
|
||||||
entryAlreadyExists (68),
|
|
||||||
objectClassModsProhibited (69),
|
|
||||||
-- 70 reserved for CLDAP --
|
|
||||||
affectsMultipleDSAs (71), -- new
|
|
||||||
-- 72-79 unused --
|
|
||||||
other (80) },
|
|
||||||
-- 81-90 reserved for APIs --
|
|
||||||
matchedDN LDAPDN,
|
|
||||||
errorMessage LDAPString,
|
|
||||||
referral [3] Referral OPTIONAL }
|
|
||||||
|
|
||||||
Referral ::= SEQUENCE OF LDAPURL
|
|
||||||
|
|
||||||
LDAPURL ::= LDAPString -- limited to characters permitted in URLs
|
|
||||||
|
|
||||||
Controls ::= SEQUENCE OF Control
|
|
||||||
|
|
||||||
Control ::= SEQUENCE {
|
|
||||||
controlType LDAPOID,
|
|
||||||
criticality BOOLEAN DEFAULT FALSE,
|
|
||||||
controlValue OCTET STRING OPTIONAL }
|
|
||||||
|
|
||||||
BindRequest ::= [APPLICATION 0] SEQUENCE {
|
|
||||||
version INTEGER (1 .. 127),
|
|
||||||
name LDAPDN,
|
|
||||||
authentication AuthenticationChoice }
|
|
||||||
|
|
||||||
AuthenticationChoice ::= CHOICE {
|
|
||||||
simple [0] OCTET STRING,
|
|
||||||
-- 1 and 2 reserved
|
|
||||||
sasl [3] SaslCredentials }
|
|
||||||
|
|
||||||
SaslCredentials ::= SEQUENCE {
|
|
||||||
mechanism LDAPString,
|
|
||||||
credentials OCTET STRING OPTIONAL }
|
|
||||||
|
|
||||||
BindResponse ::= [APPLICATION 1] SEQUENCE {
|
|
||||||
|
|
||||||
-- Wahl, et. al. Standards Track [Page 46]
|
|
||||||
--
|
|
||||||
-- RFC 2251 LDAPv3 December 1997
|
|
||||||
|
|
||||||
|
|
||||||
COMPONENTS OF LDAPResult,
|
|
||||||
serverSaslCreds [7] OCTET STRING OPTIONAL }
|
|
||||||
|
|
||||||
UnbindRequest ::= [APPLICATION 2] NULL
|
|
||||||
|
|
||||||
SearchRequest ::= [APPLICATION 3] SEQUENCE {
|
|
||||||
baseObject LDAPDN,
|
|
||||||
scope ENUMERATED {
|
|
||||||
baseObject (0),
|
|
||||||
singleLevel (1),
|
|
||||||
wholeSubtree (2) },
|
|
||||||
derefAliases ENUMERATED {
|
|
||||||
neverDerefAliases (0),
|
|
||||||
derefInSearching (1),
|
|
||||||
derefFindingBaseObj (2),
|
|
||||||
derefAlways (3) },
|
|
||||||
sizeLimit INTEGER (0 .. maxInt),
|
|
||||||
timeLimit INTEGER (0 .. maxInt),
|
|
||||||
typesOnly BOOLEAN,
|
|
||||||
filter Filter,
|
|
||||||
attributes AttributeDescriptionList }
|
|
||||||
|
|
||||||
Filter ::= CHOICE {
|
|
||||||
and [0] SET OF Filter,
|
|
||||||
or [1] SET OF Filter,
|
|
||||||
not [2] Filter,
|
|
||||||
equalityMatch [3] AttributeValueAssertion,
|
|
||||||
substrings [4] SubstringFilter,
|
|
||||||
greaterOrEqual [5] AttributeValueAssertion,
|
|
||||||
lessOrEqual [6] AttributeValueAssertion,
|
|
||||||
present [7] AttributeDescription,
|
|
||||||
approxMatch [8] AttributeValueAssertion,
|
|
||||||
extensibleMatch [9] MatchingRuleAssertion }
|
|
||||||
|
|
||||||
SubstringFilter ::= SEQUENCE {
|
|
||||||
type AttributeDescription,
|
|
||||||
-- at least one must be present
|
|
||||||
substrings SEQUENCE OF CHOICE {
|
|
||||||
initial [0] LDAPString,
|
|
||||||
any [1] LDAPString,
|
|
||||||
final [2] LDAPString } }
|
|
||||||
|
|
||||||
MatchingRuleAssertion ::= SEQUENCE {
|
|
||||||
matchingRule [1] MatchingRuleId OPTIONAL,
|
|
||||||
type [2] AttributeDescription OPTIONAL,
|
|
||||||
matchValue [3] AssertionValue,
|
|
||||||
dnAttributes [4] BOOLEAN DEFAULT FALSE }
|
|
||||||
|
|
||||||
-- Wahl, et. al. Standards Track [Page 47]
|
|
||||||
--
|
|
||||||
-- RFC 2251 LDAPv3 December 1997
|
|
||||||
|
|
||||||
SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
|
|
||||||
objectName LDAPDN,
|
|
||||||
attributes PartialAttributeList }
|
|
||||||
|
|
||||||
PartialAttributeList ::= SEQUENCE OF SEQUENCE {
|
|
||||||
type AttributeDescription,
|
|
||||||
vals SET OF AttributeValue }
|
|
||||||
|
|
||||||
SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL
|
|
||||||
|
|
||||||
SearchResultDone ::= [APPLICATION 5] LDAPResult
|
|
||||||
|
|
||||||
ModifyRequest ::= [APPLICATION 6] SEQUENCE {
|
|
||||||
object LDAPDN,
|
|
||||||
modification SEQUENCE OF SEQUENCE {
|
|
||||||
operation ENUMERATED {
|
|
||||||
add (0),
|
|
||||||
delete (1),
|
|
||||||
replace (2) },
|
|
||||||
modification AttributeTypeAndValues } }
|
|
||||||
|
|
||||||
AttributeTypeAndValues ::= SEQUENCE {
|
|
||||||
type AttributeDescription,
|
|
||||||
vals SET OF AttributeValue }
|
|
||||||
|
|
||||||
ModifyResponse ::= [APPLICATION 7] LDAPResult
|
|
||||||
|
|
||||||
AddRequest ::= [APPLICATION 8] SEQUENCE {
|
|
||||||
entry LDAPDN,
|
|
||||||
attributes AttributeList }
|
|
||||||
|
|
||||||
AttributeList ::= SEQUENCE OF SEQUENCE {
|
|
||||||
type AttributeDescription,
|
|
||||||
vals SET OF AttributeValue }
|
|
||||||
|
|
||||||
AddResponse ::= [APPLICATION 9] LDAPResult
|
|
||||||
|
|
||||||
DelRequest ::= [APPLICATION 10] LDAPDN
|
|
||||||
|
|
||||||
DelResponse ::= [APPLICATION 11] LDAPResult
|
|
||||||
|
|
||||||
ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
|
|
||||||
entry LDAPDN,
|
|
||||||
newrdn RelativeLDAPDN,
|
|
||||||
deleteoldrdn BOOLEAN,
|
|
||||||
newSuperior [0] LDAPDN OPTIONAL }
|
|
||||||
|
|
||||||
ModifyDNResponse ::= [APPLICATION 13] LDAPResult
|
|
||||||
|
|
||||||
-- Wahl, et. al. Standards Track [Page 48]
|
|
||||||
--
|
|
||||||
-- RFC 2251 LDAPv3 December 1997
|
|
||||||
|
|
||||||
|
|
||||||
CompareRequest ::= [APPLICATION 14] SEQUENCE {
|
|
||||||
entry LDAPDN,
|
|
||||||
ava AttributeValueAssertion }
|
|
||||||
|
|
||||||
CompareResponse ::= [APPLICATION 15] LDAPResult
|
|
||||||
|
|
||||||
AbandonRequest ::= [APPLICATION 16] MessageID
|
|
||||||
|
|
||||||
ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
|
|
||||||
requestName [0] LDAPOID,
|
|
||||||
requestValue [1] OCTET STRING OPTIONAL }
|
|
||||||
|
|
||||||
ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
|
|
||||||
COMPONENTS OF LDAPResult,
|
|
||||||
responseName [10] LDAPOID OPTIONAL,
|
|
||||||
response [11] OCTET STRING OPTIONAL }
|
|
||||||
|
|
||||||
passwdModifyOID LDAPOID ::= "1.3.6.1.4.1.4203.1.11.1"
|
|
||||||
|
|
||||||
PasswdModifyRequestValue ::= SEQUENCE {
|
|
||||||
userIdentity [0] OCTET STRING OPTIONAL,
|
|
||||||
oldPasswd [1] OCTET STRING OPTIONAL,
|
|
||||||
newPasswd [2] OCTET STRING OPTIONAL }
|
|
||||||
|
|
||||||
PasswdModifyResponseValue ::= SEQUENCE {
|
|
||||||
genPasswd [0] OCTET STRING OPTIONAL }
|
|
||||||
|
|
||||||
END
|
|
||||||
|
|
||||||
|
|
@ -46,12 +46,13 @@
|
|||||||
%% to command, so that the command can perform additional check.
|
%% to command, so that the command can perform additional check.
|
||||||
|
|
||||||
-record(ejabberd_commands,
|
-record(ejabberd_commands,
|
||||||
{name :: atom(),
|
{name :: atom(),
|
||||||
tags = [] :: [atom()] | '_' | '$2',
|
tags = [] :: [atom()] | '_' | '$2',
|
||||||
desc = "" :: string() | '_' | '$3',
|
desc = "" :: string() | '_' | '$3',
|
||||||
longdesc = "" :: string() | '_',
|
longdesc = "" :: string() | '_',
|
||||||
version = 0 :: integer(),
|
version = 0 :: integer(),
|
||||||
module :: atom() | '_',
|
weight = 1 :: integer(),
|
||||||
|
module :: atom() | '_',
|
||||||
function :: atom() | '_',
|
function :: atom() | '_',
|
||||||
args = [] :: [aterm()] | '_' | '$1' | '$2',
|
args = [] :: [aterm()] | '_' | '$1' | '$2',
|
||||||
policy = restricted :: open | restricted | admin | user,
|
policy = restricted :: open | restricted | admin | user,
|
||||||
|
@ -8,11 +8,11 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
{deps, [{lager, ".*", {git, "https://github.com/basho/lager", {tag, "3.2.1"}}},
|
{deps, [{lager, ".*", {git, "https://github.com/basho/lager", {tag, "3.2.1"}}},
|
||||||
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.5"}}},
|
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.6"}}},
|
||||||
{cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.4"}}},
|
{cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.4"}}},
|
||||||
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.7"}}},
|
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.7"}}},
|
||||||
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.6"}}},
|
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.6"}}},
|
||||||
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.15"}}},
|
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.16"}}},
|
||||||
{stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.7"}}},
|
{stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.7"}}},
|
||||||
{esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.8"}}},
|
{esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.8"}}},
|
||||||
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.6"}}},
|
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.6"}}},
|
||||||
|
@ -225,7 +225,6 @@ start_apps() ->
|
|||||||
ejabberd:start_app(fast_tls),
|
ejabberd:start_app(fast_tls),
|
||||||
ejabberd:start_app(fast_xml),
|
ejabberd:start_app(fast_xml),
|
||||||
ejabberd:start_app(stringprep),
|
ejabberd:start_app(stringprep),
|
||||||
http_p1:start(),
|
|
||||||
ejabberd:start_app(cache_tab).
|
ejabberd:start_app(cache_tab).
|
||||||
|
|
||||||
opt_type(net_ticktime) ->
|
opt_type(net_ticktime) ->
|
||||||
|
@ -471,7 +471,7 @@ process(_Handlers,
|
|||||||
[{<<"href">>, <<"https://www.ejabberd.im">>},
|
[{<<"href">>, <<"https://www.ejabberd.im">>},
|
||||||
{<<"title">>, <<"ejabberd XMPP server">>}],
|
{<<"title">>, <<"ejabberd XMPP server">>}],
|
||||||
<<"ejabberd">>),
|
<<"ejabberd">>),
|
||||||
?C(" is maintained by "),
|
?C(<<" is maintained by ">>),
|
||||||
?XAC(<<"a">>,
|
?XAC(<<"a">>,
|
||||||
[{<<"href">>, <<"https://www.process-one.net">>},
|
[{<<"href">>, <<"https://www.process-one.net">>},
|
||||||
{<<"title">>, <<"ProcessOne - Leader in Instant Messaging and Push Solutions">>}],
|
{<<"title">>, <<"ProcessOne - Leader in Instant Messaging and Push Solutions">>}],
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
start() ->
|
start() ->
|
||||||
[code:add_patha(module_ebin_dir(Module))
|
[code:add_patha(module_ebin_dir(Module))
|
||||||
|| {Module, _} <- installed()],
|
|| {Module, _} <- installed()],
|
||||||
application:start(inets),
|
p1_http:start(),
|
||||||
ejabberd_commands:register_commands(get_commands_spec()).
|
ejabberd_commands:register_commands(get_commands_spec()).
|
||||||
|
|
||||||
stop() ->
|
stop() ->
|
||||||
@ -271,10 +271,10 @@ geturl(Url, Hdrs, UsrOpts) ->
|
|||||||
[U, Pass] -> [{proxy_user, U}, {proxy_password, Pass}];
|
[U, Pass] -> [{proxy_user, U}, {proxy_password, Pass}];
|
||||||
_ -> []
|
_ -> []
|
||||||
end,
|
end,
|
||||||
case httpc:request(get, {Url, Hdrs}, Host++User++UsrOpts++[{version, "HTTP/1.0"}], []) of
|
case p1_http:request(get, Url, Hdrs, [], Host++User++UsrOpts++[{version, "HTTP/1.0"}]) of
|
||||||
{ok, {{_, 200, _}, Headers, Response}} ->
|
{ok, 200, Headers, Response} ->
|
||||||
{ok, Headers, Response};
|
{ok, Headers, Response};
|
||||||
{ok, {{_, Code, _}, _Headers, Response}} ->
|
{ok, Code, _Headers, Response} ->
|
||||||
{error, {Code, Response}};
|
{error, {Code, Response}};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
|
358
src/http_p1.erl
358
src/http_p1.erl
@ -1,358 +0,0 @@
|
|||||||
%%%----------------------------------------------------------------------
|
|
||||||
%%% File : http_p1.erl
|
|
||||||
%%% Author : Emilio Bustos <ebustos@process-one.net>
|
|
||||||
%%% Purpose : Provide a common API for inets / lhttpc / ibrowse
|
|
||||||
%%% Created : 29 Jul 2010 by Emilio Bustos <ebustos@process-one.net>
|
|
||||||
%%%
|
|
||||||
%%%
|
|
||||||
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
|
|
||||||
%%%
|
|
||||||
%%% This program is free software; you can redistribute it and/or
|
|
||||||
%%% modify it under the terms of the GNU General Public License as
|
|
||||||
%%% published by the Free Software Foundation; either version 2 of the
|
|
||||||
%%% License, or (at your option) any later version.
|
|
||||||
%%%
|
|
||||||
%%% This program is distributed in the hope that it will be useful,
|
|
||||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
%%% General Public License for more details.
|
|
||||||
%%%
|
|
||||||
%%% You should have received a copy of the GNU General Public License along
|
|
||||||
%%% with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
%%%
|
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
|
|
||||||
-module(http_p1).
|
|
||||||
|
|
||||||
-author('ebustos@process-one.net').
|
|
||||||
|
|
||||||
-export([start/0, stop/0, get/1, get/2, post/2, post/3,
|
|
||||||
request/3, request/4, request/5,
|
|
||||||
get_pool_size/0, set_pool_size/1]).
|
|
||||||
|
|
||||||
-include("logger.hrl").
|
|
||||||
|
|
||||||
-define(USE_INETS, 1).
|
|
||||||
% -define(USE_LHTTPC, 1).
|
|
||||||
% -define(USE_IBROWSE, 1).
|
|
||||||
% inets used as default if none specified
|
|
||||||
|
|
||||||
-ifdef(USE_IBROWSE).
|
|
||||||
|
|
||||||
start() ->
|
|
||||||
ejabberd:start_app(ibrowse).
|
|
||||||
|
|
||||||
stop() ->
|
|
||||||
application:stop(ibrowse).
|
|
||||||
|
|
||||||
request(Method, URL, Hdrs, Body, Opts) ->
|
|
||||||
TimeOut = proplists:get_value(timeout, Opts, infinity),
|
|
||||||
Options = [{inactivity_timeout, TimeOut}
|
|
||||||
| proplists:delete(timeout, Opts)],
|
|
||||||
case ibrowse:send_req(URL, Hdrs, Method, Body, Options)
|
|
||||||
of
|
|
||||||
{ok, Status, Headers, Response} ->
|
|
||||||
{ok, jlib:binary_to_integer(Status), Headers,
|
|
||||||
Response};
|
|
||||||
{error, Reason} -> {error, Reason}
|
|
||||||
end.
|
|
||||||
|
|
||||||
get_pool_size() ->
|
|
||||||
application:get_env(ibrowse, default_max_sessions, 10).
|
|
||||||
|
|
||||||
set_pool_size(Size) ->
|
|
||||||
application:set_env(ibrowse, default_max_sessions, Size).
|
|
||||||
|
|
||||||
-else.
|
|
||||||
|
|
||||||
-ifdef(USE_LHTTPC).
|
|
||||||
|
|
||||||
start() ->
|
|
||||||
ejabberd:start_app(lhttpc).
|
|
||||||
|
|
||||||
stop() ->
|
|
||||||
application:stop(lhttpc).
|
|
||||||
|
|
||||||
request(Method, URL, Hdrs, Body, Opts) ->
|
|
||||||
{[TO, SO], Rest} = proplists:split(Opts, [timeout, socket_options]),
|
|
||||||
TimeOut = proplists:get_value(timeout, TO, infinity),
|
|
||||||
SockOpt = proplists:get_value(socket_options, SO, []),
|
|
||||||
Options = [{connect_options, SockOpt} | Rest],
|
|
||||||
Result = lhttpc:request(URL, Method, Hdrs, Body, TimeOut, Options),
|
|
||||||
?DEBUG("HTTP request -> response:~n"
|
|
||||||
"** Method = ~p~n"
|
|
||||||
"** URI = ~s~n"
|
|
||||||
"** Body = ~s~n"
|
|
||||||
"** Hdrs = ~p~n"
|
|
||||||
"** Timeout = ~p~n"
|
|
||||||
"** Options = ~p~n"
|
|
||||||
"** Response = ~p",
|
|
||||||
[Method, URL, Body, Hdrs, TimeOut, Options, Result]),
|
|
||||||
case Result of
|
|
||||||
{ok, {{Status, _Reason}, Headers, Response}} ->
|
|
||||||
{ok, Status, Headers, (Response)};
|
|
||||||
{error, Reason} -> {error, Reason}
|
|
||||||
end.
|
|
||||||
|
|
||||||
get_pool_size() ->
|
|
||||||
Opts = proplists:get_value(lhttpc_manager, lhttpc_manager:list_pools()),
|
|
||||||
proplists:get_value(max_pool_size,Opts).
|
|
||||||
|
|
||||||
set_pool_size(Size) ->
|
|
||||||
lhttpc_manager:set_max_pool_size(lhttpc_manager, Size).
|
|
||||||
|
|
||||||
-else.
|
|
||||||
|
|
||||||
start() ->
|
|
||||||
ejabberd:start_app(inets).
|
|
||||||
|
|
||||||
stop() ->
|
|
||||||
application:stop(inets).
|
|
||||||
|
|
||||||
to_list(Str) when is_binary(Str) ->
|
|
||||||
binary_to_list(Str);
|
|
||||||
to_list(Str) ->
|
|
||||||
Str.
|
|
||||||
|
|
||||||
request(Method, URLRaw, HdrsRaw, Body, Opts) ->
|
|
||||||
Hdrs = lists:map(fun({N, V}) ->
|
|
||||||
{to_list(N), to_list(V)}
|
|
||||||
end, HdrsRaw),
|
|
||||||
URL = to_list(URLRaw),
|
|
||||||
|
|
||||||
Request = case Method of
|
|
||||||
get -> {URL, Hdrs};
|
|
||||||
head -> {URL, Hdrs};
|
|
||||||
delete -> {URL, Hdrs};
|
|
||||||
_ -> % post, etc.
|
|
||||||
{URL, Hdrs,
|
|
||||||
to_list(proplists:get_value(<<"content-type">>, HdrsRaw, [])),
|
|
||||||
Body}
|
|
||||||
end,
|
|
||||||
Options = case proplists:get_value(timeout, Opts,
|
|
||||||
infinity)
|
|
||||||
of
|
|
||||||
infinity -> proplists:delete(timeout, Opts);
|
|
||||||
_ -> Opts
|
|
||||||
end,
|
|
||||||
case httpc:request(Method, Request, Options, []) of
|
|
||||||
{ok, {{_, Status, _}, Headers, Response}} ->
|
|
||||||
{ok, Status, Headers, Response};
|
|
||||||
{error, Reason} -> {error, Reason}
|
|
||||||
end.
|
|
||||||
|
|
||||||
get_pool_size() ->
|
|
||||||
{ok, Size} = httpc:get_option(max_sessions),
|
|
||||||
Size.
|
|
||||||
|
|
||||||
set_pool_size(Size) ->
|
|
||||||
httpc:set_option(max_sessions, Size).
|
|
||||||
|
|
||||||
-endif.
|
|
||||||
|
|
||||||
-endif.
|
|
||||||
|
|
||||||
-type({header,
|
|
||||||
{type, 63, tuple,
|
|
||||||
[{type, 63, union,
|
|
||||||
[{type, 63, string, []}, {type, 63, atom, []}]},
|
|
||||||
{type, 63, string, []}]},
|
|
||||||
[]}).
|
|
||||||
|
|
||||||
-type({headers,
|
|
||||||
{type, 64, list, [{type, 64, header, []}]}, []}).
|
|
||||||
|
|
||||||
-type({option,
|
|
||||||
{type, 67, union,
|
|
||||||
[{type, 67, tuple,
|
|
||||||
[{atom, 67, connect_timeout}, {type, 67, timeout, []}]},
|
|
||||||
{type, 68, tuple,
|
|
||||||
[{atom, 68, timeout}, {type, 68, timeout, []}]},
|
|
||||||
{type, 70, tuple,
|
|
||||||
[{atom, 70, send_retry},
|
|
||||||
{type, 70, non_neg_integer, []}]},
|
|
||||||
{type, 71, tuple,
|
|
||||||
[{atom, 71, partial_upload},
|
|
||||||
{type, 71, union,
|
|
||||||
[{type, 71, non_neg_integer, []},
|
|
||||||
{atom, 71, infinity}]}]},
|
|
||||||
{type, 72, tuple,
|
|
||||||
[{atom, 72, partial_download}, {type, 72, pid, []},
|
|
||||||
{type, 72, union,
|
|
||||||
[{type, 72, non_neg_integer, []},
|
|
||||||
{atom, 72, infinity}]}]}]},
|
|
||||||
[]}).
|
|
||||||
|
|
||||||
-type({options,
|
|
||||||
{type, 74, list, [{type, 74, option, []}]}, []}).
|
|
||||||
|
|
||||||
-type({result,
|
|
||||||
{type, 76, union,
|
|
||||||
[{type, 76, tuple,
|
|
||||||
[{atom, 76, ok},
|
|
||||||
{type, 76, tuple,
|
|
||||||
[{type, 76, tuple,
|
|
||||||
[{type, 76, pos_integer, []}, {type, 76, string, []}]},
|
|
||||||
{type, 76, headers, []}, {type, 76, string, []}]}]},
|
|
||||||
{type, 77, tuple,
|
|
||||||
[{atom, 77, error}, {type, 77, atom, []}]}]},
|
|
||||||
[]}).
|
|
||||||
|
|
||||||
%% @spec (URL) -> Result
|
|
||||||
%% URL = string()
|
|
||||||
%% Result = {ok, StatusCode, Hdrs, ResponseBody}
|
|
||||||
%% | {error, Reason}
|
|
||||||
%% StatusCode = integer()
|
|
||||||
%% ResponseBody = string()
|
|
||||||
%% Reason = connection_closed | connect_timeout | timeout
|
|
||||||
%% @doc Sends a GET request.
|
|
||||||
%% Would be the same as calling `request(get, URL, [])',
|
|
||||||
%% that is {@link request/3} with an empty header list.
|
|
||||||
%% @end
|
|
||||||
%% @see request/3
|
|
||||||
-spec get(string()) -> result().
|
|
||||||
get(URL) -> request(get, URL, []).
|
|
||||||
|
|
||||||
%% @spec (URL, Hdrs) -> Result
|
|
||||||
%% URL = string()
|
|
||||||
%% Hdrs = [{Header, Value}]
|
|
||||||
%% Header = string()
|
|
||||||
%% Value = string()
|
|
||||||
%% Result = {ok, StatusCode, Hdrs, ResponseBody}
|
|
||||||
%% | {error, Reason}
|
|
||||||
%% StatusCode = integer()
|
|
||||||
%% ResponseBody = string()
|
|
||||||
%% Reason = connection_closed | connect_timeout | timeout
|
|
||||||
%% @doc Sends a GET request.
|
|
||||||
%% Would be the same as calling `request(get, URL, Hdrs)'.
|
|
||||||
%% @end
|
|
||||||
%% @see request/3
|
|
||||||
-spec get(string(), headers()) -> result().
|
|
||||||
get(URL, Hdrs) -> request(get, URL, Hdrs).
|
|
||||||
|
|
||||||
%% @spec (URL, RequestBody) -> Result
|
|
||||||
%% URL = string()
|
|
||||||
%% RequestBody = string()
|
|
||||||
%% Result = {ok, StatusCode, Hdrs, ResponseBody}
|
|
||||||
%% | {error, Reason}
|
|
||||||
%% StatusCode = integer()
|
|
||||||
%% ResponseBody = string()
|
|
||||||
%% Reason = connection_closed | connect_timeout | timeout
|
|
||||||
%% @doc Sends a POST request with form data.
|
|
||||||
%% Would be the same as calling
|
|
||||||
%% `request(post, URL, [{"content-type", "x-www-form-urlencoded"}], Body)'.
|
|
||||||
%% @end
|
|
||||||
%% @see request/4
|
|
||||||
-spec post(string(), string()) -> result().
|
|
||||||
post(URL, Body) ->
|
|
||||||
request(post, URL,
|
|
||||||
[{<<"content-type">>, <<"x-www-form-urlencoded">>}],
|
|
||||||
Body).
|
|
||||||
|
|
||||||
%% @spec (URL, Hdrs, RequestBody) -> Result
|
|
||||||
%% URL = string()
|
|
||||||
%% Hdrs = [{Header, Value}]
|
|
||||||
%% Header = string()
|
|
||||||
%% Value = string()
|
|
||||||
%% RequestBody = string()
|
|
||||||
%% Result = {ok, StatusCode, Hdrs, ResponseBody}
|
|
||||||
%% | {error, Reason}
|
|
||||||
%% StatusCode = integer()
|
|
||||||
%% ResponseBody = string()
|
|
||||||
%% Reason = connection_closed | connect_timeout | timeout
|
|
||||||
%% @doc Sends a POST request.
|
|
||||||
%% Would be the same as calling
|
|
||||||
%% `request(post, URL, Hdrs, Body)'.
|
|
||||||
%% @end
|
|
||||||
%% @see request/4
|
|
||||||
-spec post(string(), headers(), string()) -> result().
|
|
||||||
post(URL, Hdrs, Body) ->
|
|
||||||
NewHdrs = case [X
|
|
||||||
|| {X, _} <- Hdrs,
|
|
||||||
str:to_lower(X) == <<"content-type">>]
|
|
||||||
of
|
|
||||||
[] ->
|
|
||||||
[{<<"content-type">>, <<"x-www-form-urlencoded">>}
|
|
||||||
| Hdrs];
|
|
||||||
_ -> Hdrs
|
|
||||||
end,
|
|
||||||
request(post, URL, NewHdrs, Body).
|
|
||||||
|
|
||||||
%% @spec (Method, URL, Hdrs) -> Result
|
|
||||||
%% Method = atom()
|
|
||||||
%% URL = string()
|
|
||||||
%% Hdrs = [{Header, Value}]
|
|
||||||
%% Header = string()
|
|
||||||
%% Value = string()
|
|
||||||
%% Result = {ok, StatusCode, Hdrs, ResponseBody}
|
|
||||||
%% | {error, Reason}
|
|
||||||
%% StatusCode = integer()
|
|
||||||
%% ResponseBody = string()
|
|
||||||
%% Reason = connection_closed | connect_timeout | timeout
|
|
||||||
%% @doc Sends a request without a body.
|
|
||||||
%% Would be the same as calling `request(Method, URL, Hdrs, [], [])',
|
|
||||||
%% that is {@link request/5} with an empty body.
|
|
||||||
%% @end
|
|
||||||
%% @see request/5
|
|
||||||
-spec request(atom(), string(), headers()) -> result().
|
|
||||||
request(Method, URL, Hdrs) ->
|
|
||||||
request(Method, URL, Hdrs, [], []).
|
|
||||||
|
|
||||||
%% @spec (Method, URL, Hdrs, RequestBody) -> Result
|
|
||||||
%% Method = atom()
|
|
||||||
%% URL = string()
|
|
||||||
%% Hdrs = [{Header, Value}]
|
|
||||||
%% Header = string()
|
|
||||||
%% Value = string()
|
|
||||||
%% RequestBody = string()
|
|
||||||
%% Result = {ok, StatusCode, Hdrs, ResponseBody}
|
|
||||||
%% | {error, Reason}
|
|
||||||
%% StatusCode = integer()
|
|
||||||
%% ResponseBody = string()
|
|
||||||
%% Reason = connection_closed | connect_timeout | timeout
|
|
||||||
%% @doc Sends a request with a body.
|
|
||||||
%% Would be the same as calling
|
|
||||||
%% `request(Method, URL, Hdrs, Body, [])', that is {@link request/5}
|
|
||||||
%% with no options.
|
|
||||||
%% @end
|
|
||||||
%% @see request/5
|
|
||||||
-spec request(atom(), string(), headers(), string()) -> result().
|
|
||||||
request(Method, URL, Hdrs, Body) ->
|
|
||||||
request(Method, URL, Hdrs, Body, []).
|
|
||||||
|
|
||||||
%% @spec (Method, URL, Hdrs, RequestBody, Options) -> Result
|
|
||||||
%% Method = atom()
|
|
||||||
%% URL = string()
|
|
||||||
%% Hdrs = [{Header, Value}]
|
|
||||||
%% Header = string()
|
|
||||||
%% Value = string()
|
|
||||||
%% RequestBody = string()
|
|
||||||
%% Options = [Option]
|
|
||||||
%% Option = {timeout, Milliseconds | infinity} |
|
|
||||||
%% {connect_timeout, Milliseconds | infinity} |
|
|
||||||
%% {socket_options, [term()]} |
|
|
||||||
|
|
||||||
%% Milliseconds = integer()
|
|
||||||
%% Result = {ok, StatusCode, Hdrs, ResponseBody}
|
|
||||||
%% | {error, Reason}
|
|
||||||
%% StatusCode = integer()
|
|
||||||
%% ResponseBody = string()
|
|
||||||
%% Reason = connection_closed | connect_timeout | timeout
|
|
||||||
%% @doc Sends a request with a body.
|
|
||||||
%% Would be the same as calling
|
|
||||||
%% `request(Method, URL, Hdrs, Body, [])', that is {@link request/5}
|
|
||||||
%% with no options.
|
|
||||||
%% @end
|
|
||||||
%% @see request/5
|
|
||||||
-spec request(atom(), string(), headers(), string(), options()) -> result().
|
|
||||||
|
|
||||||
% ibrowse {response_format, response_format()} |
|
|
||||||
% Options - [option()]
|
|
||||||
% Option - {sync, boolean()} | {stream, StreamTo} | {body_format, body_format()} | {full_result,
|
|
||||||
% boolean()} | {headers_as_is, boolean()}
|
|
||||||
%body_format() = string() | binary()
|
|
||||||
% The body_format option is only valid for the synchronous request and the default is string.
|
|
||||||
% When making an asynchronous request the body will always be received as a binary.
|
|
||||||
% lhttpc: always binary
|
|
||||||
|
|
@ -176,8 +176,8 @@ get_commands_spec() ->
|
|||||||
desc = "Check if the password hash is correct",
|
desc = "Check if the password hash is correct",
|
||||||
longdesc = "Allowed hash methods: md5, sha.",
|
longdesc = "Allowed hash methods: md5, sha.",
|
||||||
module = ?MODULE, function = check_password_hash,
|
module = ?MODULE, function = check_password_hash,
|
||||||
args = [{user, binary}, {host, binary}, {passwordhash, string},
|
args = [{user, binary}, {host, binary}, {passwordhash, binary},
|
||||||
{hashmethod, string}],
|
{hashmethod, binary}],
|
||||||
args_example = [<<"peter">>, <<"myserver.com">>,
|
args_example = [<<"peter">>, <<"myserver.com">>,
|
||||||
<<"5ebe2294ecd0e0f08eab7690d2a6ee69">>, <<"md5">>],
|
<<"5ebe2294ecd0e0f08eab7690d2a6ee69">>, <<"md5">>],
|
||||||
args_desc = ["User name to check", "Server to check",
|
args_desc = ["User name to check", "Server to check",
|
||||||
|
@ -273,7 +273,7 @@ handle(Call, Auth, Args, Version) when is_atom(Call), is_list(Args) ->
|
|||||||
fun ({Key, binary}, Acc) ->
|
fun ({Key, binary}, Acc) ->
|
||||||
[{Key, <<>>}|Acc];
|
[{Key, <<>>}|Acc];
|
||||||
({Key, string}, Acc) ->
|
({Key, string}, Acc) ->
|
||||||
[{Key, <<>>}|Acc];
|
[{Key, ""}|Acc];
|
||||||
({Key, integer}, Acc) ->
|
({Key, integer}, Acc) ->
|
||||||
[{Key, 0}|Acc];
|
[{Key, 0}|Acc];
|
||||||
({Key, {list, _}}, Acc) ->
|
({Key, {list, _}}, Acc) ->
|
||||||
@ -406,10 +406,10 @@ format_arg(Elements, {list, ElementsDef})
|
|||||||
format_arg(Arg, integer) when is_integer(Arg) -> Arg;
|
format_arg(Arg, integer) when is_integer(Arg) -> Arg;
|
||||||
format_arg(Arg, binary) when is_list(Arg) -> process_unicode_codepoints(Arg);
|
format_arg(Arg, binary) when is_list(Arg) -> process_unicode_codepoints(Arg);
|
||||||
format_arg(Arg, binary) when is_binary(Arg) -> Arg;
|
format_arg(Arg, binary) when is_binary(Arg) -> Arg;
|
||||||
format_arg(Arg, string) when is_list(Arg) -> process_unicode_codepoints(Arg);
|
format_arg(Arg, string) when is_list(Arg) -> Arg;
|
||||||
format_arg(Arg, string) when is_binary(Arg) -> Arg;
|
format_arg(Arg, string) when is_binary(Arg) -> binary_to_list(Arg);
|
||||||
format_arg(undefined, binary) -> <<>>;
|
format_arg(undefined, binary) -> <<>>;
|
||||||
format_arg(undefined, string) -> <<>>;
|
format_arg(undefined, string) -> "";
|
||||||
format_arg(Arg, Format) ->
|
format_arg(Arg, Format) ->
|
||||||
?ERROR_MSG("don't know how to format Arg ~p for format ~p", [Arg, Format]),
|
?ERROR_MSG("don't know how to format Arg ~p for format ~p", [Arg, Format]),
|
||||||
throw({invalid_parameter,
|
throw({invalid_parameter,
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
-record(state,
|
-record(state,
|
||||||
{host, docroot, accesslog, accesslogfd,
|
{host, docroot, accesslog, accesslogfd,
|
||||||
directory_indices, custom_headers, default_content_type,
|
directory_indices, custom_headers, default_content_type,
|
||||||
content_types = []}).
|
content_types = [], user_access = none}).
|
||||||
|
|
||||||
-define(PROCNAME, ejabberd_mod_http_fileserver).
|
-define(PROCNAME, ejabberd_mod_http_fileserver).
|
||||||
|
|
||||||
@ -133,7 +133,8 @@ start_link(Host, Opts) ->
|
|||||||
init([Host, Opts]) ->
|
init([Host, Opts]) ->
|
||||||
try initialize(Host, Opts) of
|
try initialize(Host, Opts) of
|
||||||
{DocRoot, AccessLog, AccessLogFD, DirectoryIndices,
|
{DocRoot, AccessLog, AccessLogFD, DirectoryIndices,
|
||||||
CustomHeaders, DefaultContentType, ContentTypes} ->
|
CustomHeaders, DefaultContentType, ContentTypes,
|
||||||
|
UserAccess} ->
|
||||||
{ok, #state{host = Host,
|
{ok, #state{host = Host,
|
||||||
accesslog = AccessLog,
|
accesslog = AccessLog,
|
||||||
accesslogfd = AccessLogFD,
|
accesslogfd = AccessLogFD,
|
||||||
@ -141,7 +142,8 @@ init([Host, Opts]) ->
|
|||||||
directory_indices = DirectoryIndices,
|
directory_indices = DirectoryIndices,
|
||||||
custom_headers = CustomHeaders,
|
custom_headers = CustomHeaders,
|
||||||
default_content_type = DefaultContentType,
|
default_content_type = DefaultContentType,
|
||||||
content_types = ContentTypes}}
|
content_types = ContentTypes,
|
||||||
|
user_access = UserAccess}}
|
||||||
catch
|
catch
|
||||||
throw:Reason ->
|
throw:Reason ->
|
||||||
{stop, Reason}
|
{stop, Reason}
|
||||||
@ -165,7 +167,15 @@ initialize(Host, Opts) ->
|
|||||||
[]),
|
[]),
|
||||||
DefaultContentType = gen_mod:get_opt(default_content_type, Opts,
|
DefaultContentType = gen_mod:get_opt(default_content_type, Opts,
|
||||||
fun iolist_to_binary/1,
|
fun iolist_to_binary/1,
|
||||||
?DEFAULT_CONTENT_TYPE),
|
?DEFAULT_CONTENT_TYPE),
|
||||||
|
UserAccess0 = gen_mod:get_opt(must_authenticate_with, Opts,
|
||||||
|
mod_opt_type(must_authenticate_with),
|
||||||
|
[]),
|
||||||
|
UserAccess = case UserAccess0 of
|
||||||
|
[] -> none;
|
||||||
|
_ ->
|
||||||
|
dict:from_list(UserAccess0)
|
||||||
|
end,
|
||||||
ContentTypes = build_list_content_types(
|
ContentTypes = build_list_content_types(
|
||||||
gen_mod:get_opt(content_types, Opts,
|
gen_mod:get_opt(content_types, Opts,
|
||||||
fun(L) when is_list(L) ->
|
fun(L) when is_list(L) ->
|
||||||
@ -180,7 +190,7 @@ initialize(Host, Opts) ->
|
|||||||
[str:join([[$*, K, " -> ", V] || {K, V} <- ContentTypes],
|
[str:join([[$*, K, " -> ", V] || {K, V} <- ContentTypes],
|
||||||
<<", ">>)]),
|
<<", ">>)]),
|
||||||
{DocRoot, AccessLog, AccessLogFD, DirectoryIndices,
|
{DocRoot, AccessLog, AccessLogFD, DirectoryIndices,
|
||||||
CustomHeaders, DefaultContentType, ContentTypes}.
|
CustomHeaders, DefaultContentType, ContentTypes, UserAccess}.
|
||||||
|
|
||||||
|
|
||||||
%% @spec (AdminCTs::[CT], Default::[CT]) -> [CT]
|
%% @spec (AdminCTs::[CT], Default::[CT]) -> [CT]
|
||||||
@ -246,10 +256,11 @@ try_open_log(FN, Host) ->
|
|||||||
%% {stop, Reason, State}
|
%% {stop, Reason, State}
|
||||||
%% Description: Handling call messages
|
%% Description: Handling call messages
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
handle_call({serve, LocalPath}, _From, State) ->
|
handle_call({serve, LocalPath, Auth}, _From, State) ->
|
||||||
Reply = serve(LocalPath, State#state.docroot, State#state.directory_indices,
|
Reply = serve(LocalPath, Auth, State#state.docroot, State#state.directory_indices,
|
||||||
State#state.custom_headers,
|
State#state.custom_headers,
|
||||||
State#state.default_content_type, State#state.content_types),
|
State#state.default_content_type, State#state.content_types,
|
||||||
|
State#state.user_access),
|
||||||
{reply, Reply, State};
|
{reply, Reply, State};
|
||||||
handle_call(_Request, _From, State) ->
|
handle_call(_Request, _From, State) ->
|
||||||
{reply, ok, State}.
|
{reply, ok, State}.
|
||||||
@ -305,9 +316,9 @@ code_change(_OldVsn, State, _Extra) ->
|
|||||||
%% @doc Handle an HTTP request.
|
%% @doc Handle an HTTP request.
|
||||||
%% LocalPath is the part of the requested URL path that is "local to the module".
|
%% LocalPath is the part of the requested URL path that is "local to the module".
|
||||||
%% Returns the page to be sent back to the client and/or HTTP status code.
|
%% Returns the page to be sent back to the client and/or HTTP status code.
|
||||||
process(LocalPath, Request) ->
|
process(LocalPath, #request{host = Host, auth = Auth} = Request) ->
|
||||||
?DEBUG("Requested ~p", [LocalPath]),
|
?DEBUG("Requested ~p", [LocalPath]),
|
||||||
try gen_server:call(get_proc_name(Request#request.host), {serve, LocalPath}) of
|
try gen_server:call(get_proc_name(Host), {serve, LocalPath, Auth}) of
|
||||||
{FileSize, Code, Headers, Contents} ->
|
{FileSize, Code, Headers, Contents} ->
|
||||||
add_to_log(FileSize, Code, Request),
|
add_to_log(FileSize, Code, Request),
|
||||||
{Code, Headers, Contents}
|
{Code, Headers, Contents}
|
||||||
@ -318,21 +329,38 @@ process(LocalPath, Request) ->
|
|||||||
ejabberd_web:error(not_found)
|
ejabberd_web:error(not_found)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
serve(LocalPath, DocRoot, DirectoryIndices, CustomHeaders, DefaultContentType, ContentTypes) ->
|
|
||||||
FileName = filename:join(filename:split(DocRoot) ++ LocalPath),
|
serve(LocalPath, Auth, DocRoot, DirectoryIndices, CustomHeaders, DefaultContentType,
|
||||||
case file:read_file_info(FileName) of
|
ContentTypes, UserAccess) ->
|
||||||
{error, enoent} -> ?HTTP_ERR_FILE_NOT_FOUND;
|
CanProceed = case {UserAccess, Auth} of
|
||||||
{error, enotdir} -> ?HTTP_ERR_FILE_NOT_FOUND;
|
{none, _} -> true;
|
||||||
{error, eacces} -> ?HTTP_ERR_FORBIDDEN;
|
{_, {User, Pass}} ->
|
||||||
{ok, #file_info{type = directory}} -> serve_index(FileName,
|
case dict:find(User, UserAccess) of
|
||||||
DirectoryIndices,
|
{ok, Pass} -> true;
|
||||||
CustomHeaders,
|
_ -> false
|
||||||
DefaultContentType,
|
end;
|
||||||
ContentTypes);
|
_ ->
|
||||||
{ok, FileInfo} -> serve_file(FileInfo, FileName,
|
false
|
||||||
CustomHeaders,
|
end,
|
||||||
DefaultContentType,
|
case CanProceed of
|
||||||
ContentTypes)
|
true ->
|
||||||
|
FileName = filename:join(filename:split(DocRoot) ++ LocalPath),
|
||||||
|
case file:read_file_info(FileName) of
|
||||||
|
{error, enoent} -> ?HTTP_ERR_FILE_NOT_FOUND;
|
||||||
|
{error, enotdir} -> ?HTTP_ERR_FILE_NOT_FOUND;
|
||||||
|
{error, eacces} -> ?HTTP_ERR_FORBIDDEN;
|
||||||
|
{ok, #file_info{type = directory}} -> serve_index(FileName,
|
||||||
|
DirectoryIndices,
|
||||||
|
CustomHeaders,
|
||||||
|
DefaultContentType,
|
||||||
|
ContentTypes);
|
||||||
|
{ok, FileInfo} -> serve_file(FileInfo, FileName,
|
||||||
|
CustomHeaders,
|
||||||
|
DefaultContentType,
|
||||||
|
ContentTypes)
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
?HTTP_ERR_FORBIDDEN
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% Troll through the directory indices attempting to find one which
|
%% Troll through the directory indices attempting to find one which
|
||||||
@ -466,6 +494,14 @@ mod_opt_type(default_content_type) ->
|
|||||||
mod_opt_type(directory_indices) ->
|
mod_opt_type(directory_indices) ->
|
||||||
fun (L) when is_list(L) -> L end;
|
fun (L) when is_list(L) -> L end;
|
||||||
mod_opt_type(docroot) -> fun (A) -> A end;
|
mod_opt_type(docroot) -> fun (A) -> A end;
|
||||||
|
mod_opt_type(must_authenticate_with) ->
|
||||||
|
fun (L) when is_list(L) ->
|
||||||
|
lists:map(fun(UP) when is_binary(UP) ->
|
||||||
|
[K, V] = binary:split(UP, <<":">>),
|
||||||
|
{K, V}
|
||||||
|
end, L)
|
||||||
|
end;
|
||||||
mod_opt_type(_) ->
|
mod_opt_type(_) ->
|
||||||
[accesslog, content_types, custom_headers,
|
[accesslog, content_types, custom_headers,
|
||||||
default_content_type, directory_indices, docroot].
|
default_content_type, directory_indices, docroot,
|
||||||
|
must_authenticate_with].
|
||||||
|
@ -89,9 +89,9 @@ loop(_State) -> receive stop -> ok end.
|
|||||||
%% TODO: Support comment lines starting by %
|
%% TODO: Support comment lines starting by %
|
||||||
update_bl_c2s() ->
|
update_bl_c2s() ->
|
||||||
?INFO_MSG("Updating C2S Blacklist", []),
|
?INFO_MSG("Updating C2S Blacklist", []),
|
||||||
case httpc:request(?BLC2S) of
|
case p1_http:get(?BLC2S) of
|
||||||
{ok, 200, _Headers, Body} ->
|
{ok, 200, _Headers, Body} ->
|
||||||
IPs = str:tokens(Body, <<"\n">>),
|
IPs = str:tokens(iolist_to_binary(Body), <<"\n">>),
|
||||||
ets:delete_all_objects(bl_c2s),
|
ets:delete_all_objects(bl_c2s),
|
||||||
lists:foreach(fun (IP) ->
|
lists:foreach(fun (IP) ->
|
||||||
ets:insert(bl_c2s,
|
ets:insert(bl_c2s,
|
||||||
|
@ -3548,6 +3548,7 @@ make_opts(StateData) ->
|
|||||||
?MAKE_CONFIG_OPT(#config.allow_voice_requests),
|
?MAKE_CONFIG_OPT(#config.allow_voice_requests),
|
||||||
?MAKE_CONFIG_OPT(#config.allow_subscription),
|
?MAKE_CONFIG_OPT(#config.allow_subscription),
|
||||||
?MAKE_CONFIG_OPT(#config.mam),
|
?MAKE_CONFIG_OPT(#config.mam),
|
||||||
|
?MAKE_CONFIG_OPT(#config.presence_broadcast),
|
||||||
?MAKE_CONFIG_OPT(#config.voice_request_min_interval),
|
?MAKE_CONFIG_OPT(#config.voice_request_min_interval),
|
||||||
?MAKE_CONFIG_OPT(#config.vcard),
|
?MAKE_CONFIG_OPT(#config.vcard),
|
||||||
{captcha_whitelist,
|
{captcha_whitelist,
|
||||||
|
@ -93,12 +93,10 @@ mod_opt_type(auth_type) ->
|
|||||||
end;
|
end;
|
||||||
mod_opt_type(recbuf) ->
|
mod_opt_type(recbuf) ->
|
||||||
fun (I) when is_integer(I), I > 0 -> I end;
|
fun (I) when is_integer(I), I > 0 -> I end;
|
||||||
mod_opt_type(shaper) ->
|
mod_opt_type(shaper) -> fun acl:shaper_rules_validator/1;
|
||||||
fun (A) when is_atom(A) -> A end;
|
|
||||||
mod_opt_type(sndbuf) ->
|
mod_opt_type(sndbuf) ->
|
||||||
fun (I) when is_integer(I), I > 0 -> I end;
|
fun (I) when is_integer(I), I > 0 -> I end;
|
||||||
mod_opt_type(access) ->
|
mod_opt_type(access) -> fun acl:access_rules_validator/1;
|
||||||
fun (A) when is_atom(A) -> A end;
|
|
||||||
mod_opt_type(host) -> fun iolist_to_binary/1;
|
mod_opt_type(host) -> fun iolist_to_binary/1;
|
||||||
mod_opt_type(hostname) -> fun iolist_to_binary/1;
|
mod_opt_type(hostname) -> fun iolist_to_binary/1;
|
||||||
mod_opt_type(ip) ->
|
mod_opt_type(ip) ->
|
||||||
|
@ -251,7 +251,7 @@ init([ServerHost, Opts]) ->
|
|||||||
Host = gen_mod:get_opt_host(ServerHost, Opts, <<"pubsub.@HOST@">>),
|
Host = gen_mod:get_opt_host(ServerHost, Opts, <<"pubsub.@HOST@">>),
|
||||||
ejabberd_router:register_route(Host, ServerHost),
|
ejabberd_router:register_route(Host, ServerHost),
|
||||||
Access = gen_mod:get_opt(access_createnode, Opts,
|
Access = gen_mod:get_opt(access_createnode, Opts,
|
||||||
fun(A) when is_atom(A) -> A end, all),
|
fun acl:access_rules_validator/1, all),
|
||||||
PepOffline = gen_mod:get_opt(ignore_pep_from_offline, Opts,
|
PepOffline = gen_mod:get_opt(ignore_pep_from_offline, Opts,
|
||||||
fun(A) when is_boolean(A) -> A end, true),
|
fun(A) when is_boolean(A) -> A end, true),
|
||||||
IQDisc = gen_mod:get_opt(iqdisc, Opts,
|
IQDisc = gen_mod:get_opt(iqdisc, Opts,
|
||||||
@ -262,7 +262,7 @@ init([ServerHost, Opts]) ->
|
|||||||
fun(A) when is_integer(A) andalso A >= 0 -> A end, ?MAXITEMS),
|
fun(A) when is_integer(A) andalso A >= 0 -> A end, ?MAXITEMS),
|
||||||
MaxSubsNode = gen_mod:get_opt(max_subscriptions_node, Opts,
|
MaxSubsNode = gen_mod:get_opt(max_subscriptions_node, Opts,
|
||||||
fun(A) when is_integer(A) andalso A >= 0 -> A end, undefined),
|
fun(A) when is_integer(A) andalso A >= 0 -> A end, undefined),
|
||||||
pubsub_index:init(Host, ServerHost, Opts),
|
[pubsub_index:init(Host, ServerHost, Opts) || gen_mod:db_type(ServerHost, ?MODULE)==mnesia],
|
||||||
{Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts),
|
{Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts),
|
||||||
DefaultModule = plugin(Host, hd(Plugins)),
|
DefaultModule = plugin(Host, hd(Plugins)),
|
||||||
BaseOptions = DefaultModule:options(),
|
BaseOptions = DefaultModule:options(),
|
||||||
@ -3899,8 +3899,7 @@ purge_offline(Host, LJID, Node) ->
|
|||||||
Error
|
Error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
mod_opt_type(access_createnode) ->
|
mod_opt_type(access_createnode) -> fun acl:access_rules_validator/1;
|
||||||
fun (A) when is_atom(A) -> A end;
|
|
||||||
mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
|
mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
|
||||||
mod_opt_type(host) -> fun iolist_to_binary/1;
|
mod_opt_type(host) -> fun iolist_to_binary/1;
|
||||||
mod_opt_type(ignore_pep_from_offline) ->
|
mod_opt_type(ignore_pep_from_offline) ->
|
||||||
|
@ -613,14 +613,11 @@ check_ip_access(undefined, _IPAccess) ->
|
|||||||
check_ip_access(IPAddress, IPAccess) ->
|
check_ip_access(IPAddress, IPAccess) ->
|
||||||
acl:match_rule(global, IPAccess, IPAddress).
|
acl:match_rule(global, IPAccess, IPAddress).
|
||||||
|
|
||||||
mod_opt_type(access) ->
|
mod_opt_type(access) -> fun acl:access_rules_validator/1;
|
||||||
fun acl:access_rules_validator/1;
|
mod_opt_type(access_from) -> fun acl:access_rules_validator/1;
|
||||||
mod_opt_type(access_from) ->
|
|
||||||
fun (A) when is_atom(A) -> A end;
|
|
||||||
mod_opt_type(captcha_protected) ->
|
mod_opt_type(captcha_protected) ->
|
||||||
fun (B) when is_boolean(B) -> B end;
|
fun (B) when is_boolean(B) -> B end;
|
||||||
mod_opt_type(ip_access) ->
|
mod_opt_type(ip_access) -> fun acl:access_rules_validator/1;
|
||||||
fun acl:access_rules_validator/1;
|
|
||||||
mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1;
|
mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1;
|
||||||
mod_opt_type(password_strength) ->
|
mod_opt_type(password_strength) ->
|
||||||
fun (N) when is_number(N), N >= 0 -> N end;
|
fun (N) when is_number(N), N >= 0 -> N end;
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
path_to_node/1, can_fetch_item/2, is_subscribed/1]).
|
path_to_node/1, can_fetch_item/2, is_subscribed/1]).
|
||||||
|
|
||||||
init(_Host, _ServerHost, _Opts) ->
|
init(_Host, _ServerHost, _Opts) ->
|
||||||
%pubsub_subscription:init(),
|
%pubsub_subscription:init(Host, ServerHost, Opts),
|
||||||
mnesia:create_table(pubsub_state,
|
mnesia:create_table(pubsub_state,
|
||||||
[{disc_copies, [node()]},
|
[{disc_copies, [node()]},
|
||||||
{type, ordered_set},
|
{type, ordered_set},
|
||||||
|
@ -61,7 +61,7 @@
|
|||||||
encode_host_like/1]).
|
encode_host_like/1]).
|
||||||
|
|
||||||
init(_Host, _ServerHost, _Opts) ->
|
init(_Host, _ServerHost, _Opts) ->
|
||||||
%%pubsub_subscription_sql:init(),
|
%%pubsub_subscription_sql:init(Host, ServerHost, Opts),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
terminate(_Host, _ServerHost) ->
|
terminate(_Host, _ServerHost) ->
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
-author("bjc@kublai.com").
|
-author("bjc@kublai.com").
|
||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([init/0, subscribe_node/3, unsubscribe_node/3,
|
-export([init/3, subscribe_node/3, unsubscribe_node/3,
|
||||||
get_subscription/3, set_subscription/4,
|
get_subscription/3, set_subscription/4,
|
||||||
make_subid/0,
|
make_subid/0,
|
||||||
get_options_xform/2, parse_options_xform/1]).
|
get_options_xform/2, parse_options_xform/1]).
|
||||||
@ -73,7 +73,7 @@
|
|||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% API
|
%% API
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
init() -> ok = create_table().
|
init(_Host, _ServerHost, _Opts) -> ok = create_table().
|
||||||
|
|
||||||
subscribe_node(JID, NodeId, Options) ->
|
subscribe_node(JID, NodeId, Options) ->
|
||||||
case catch mnesia:sync_dirty(fun add_subscription/3, [JID, NodeId, Options])
|
case catch mnesia:sync_dirty(fun add_subscription/3, [JID, NodeId, Options])
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
-author("pablo.polvorin@process-one.net").
|
-author("pablo.polvorin@process-one.net").
|
||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([init/0, subscribe_node/3, unsubscribe_node/3,
|
-export([init/3, subscribe_node/3, unsubscribe_node/3,
|
||||||
get_subscription/3, set_subscription/4,
|
get_subscription/3, set_subscription/4,
|
||||||
make_subid/0,
|
make_subid/0,
|
||||||
get_options_xform/2, parse_options_xform/1]).
|
get_options_xform/2, parse_options_xform/1]).
|
||||||
@ -71,7 +71,7 @@
|
|||||||
%% API
|
%% API
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
|
|
||||||
init() -> ok = create_table().
|
init(_Host, _ServerHost, _Opts) -> ok = create_table().
|
||||||
|
|
||||||
-spec subscribe_node(_JID :: _, _NodeId :: _, Options :: [] | mod_pubsub:subOptions()) ->
|
-spec subscribe_node(_JID :: _, _NodeId :: _, Options :: [] | mod_pubsub:subOptions()) ->
|
||||||
{result, mod_pubsub:subId()}.
|
{result, mod_pubsub:subId()}.
|
||||||
|
39
src/rest.erl
39
src/rest.erl
@ -28,7 +28,7 @@
|
|||||||
-behaviour(ejabberd_config).
|
-behaviour(ejabberd_config).
|
||||||
|
|
||||||
-export([start/1, stop/1, get/2, get/3, post/4, delete/2,
|
-export([start/1, stop/1, get/2, get/3, post/4, delete/2,
|
||||||
request/6, with_retry/4, opt_type/1]).
|
put/4, patch/4, request/6, with_retry/4, opt_type/1]).
|
||||||
|
|
||||||
-include("logger.hrl").
|
-include("logger.hrl").
|
||||||
|
|
||||||
@ -36,14 +36,14 @@
|
|||||||
-define(CONNECT_TIMEOUT, 8000).
|
-define(CONNECT_TIMEOUT, 8000).
|
||||||
|
|
||||||
start(Host) ->
|
start(Host) ->
|
||||||
http_p1:start(),
|
p1_http:start(),
|
||||||
Pool_size =
|
Pool_size =
|
||||||
ejabberd_config:get_option({ext_api_http_pool_size, Host},
|
ejabberd_config:get_option({ext_api_http_pool_size, Host},
|
||||||
fun(X) when is_integer(X), X > 0->
|
fun(X) when is_integer(X), X > 0->
|
||||||
X
|
X
|
||||||
end,
|
end,
|
||||||
100),
|
100),
|
||||||
http_p1:set_pool_size(Pool_size).
|
p1_http:set_pool_size(Pool_size).
|
||||||
|
|
||||||
stop(_Host) ->
|
stop(_Host) ->
|
||||||
ok.
|
ok.
|
||||||
@ -71,18 +71,17 @@ delete(Server, Path) ->
|
|||||||
request(Server, delete, Path, [], "application/json", <<>>).
|
request(Server, delete, Path, [], "application/json", <<>>).
|
||||||
|
|
||||||
post(Server, Path, Params, Content) ->
|
post(Server, Path, Params, Content) ->
|
||||||
Data = case catch jiffy:encode(Content) of
|
Data = encode_json(Content),
|
||||||
{'EXIT', Reason} ->
|
|
||||||
?ERROR_MSG("HTTP content encodage failed:~n"
|
|
||||||
"** Content = ~p~n"
|
|
||||||
"** Err = ~p",
|
|
||||||
[Content, Reason]),
|
|
||||||
<<>>;
|
|
||||||
Encoded ->
|
|
||||||
Encoded
|
|
||||||
end,
|
|
||||||
request(Server, post, Path, Params, "application/json", Data).
|
request(Server, post, Path, Params, "application/json", Data).
|
||||||
|
|
||||||
|
put(Server, Path, Params, Content) ->
|
||||||
|
Data = encode_json(Content),
|
||||||
|
request(Server, put, Path, Params, "application/json", Data).
|
||||||
|
|
||||||
|
patch(Server, Path, Params, Content) ->
|
||||||
|
Data = encode_json(Content),
|
||||||
|
request(Server, patch, Path, Params, "application/json", Data).
|
||||||
|
|
||||||
request(Server, Method, Path, Params, Mime, Data) ->
|
request(Server, Method, Path, Params, Mime, Data) ->
|
||||||
URI = url(Server, Path, Params),
|
URI = url(Server, Path, Params),
|
||||||
Opts = [{connect_timeout, ?CONNECT_TIMEOUT},
|
Opts = [{connect_timeout, ?CONNECT_TIMEOUT},
|
||||||
@ -91,7 +90,7 @@ request(Server, Method, Path, Params, Mime, Data) ->
|
|||||||
{"content-type", Mime},
|
{"content-type", Mime},
|
||||||
{"User-Agent", "ejabberd"}],
|
{"User-Agent", "ejabberd"}],
|
||||||
Begin = os:timestamp(),
|
Begin = os:timestamp(),
|
||||||
Result = case catch http_p1:request(Method, URI, Hdrs, Data, Opts) of
|
Result = case catch p1_http:request(Method, URI, Hdrs, Data, Opts) of
|
||||||
{ok, Code, _, <<>>} ->
|
{ok, Code, _, <<>>} ->
|
||||||
{ok, Code, []};
|
{ok, Code, []};
|
||||||
{ok, Code, _, <<" ">>} ->
|
{ok, Code, _, <<" ">>} ->
|
||||||
@ -147,6 +146,18 @@ request(Server, Method, Path, Params, Mime, Data) ->
|
|||||||
%%% HTTP helpers
|
%%% HTTP helpers
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
encode_json(Content) ->
|
||||||
|
case catch jiffy:encode(Content) of
|
||||||
|
{'EXIT', Reason} ->
|
||||||
|
?ERROR_MSG("HTTP content encodage failed:~n"
|
||||||
|
"** Content = ~p~n"
|
||||||
|
"** Err = ~p",
|
||||||
|
[Content, Reason]),
|
||||||
|
<<>>;
|
||||||
|
Encoded ->
|
||||||
|
Encoded
|
||||||
|
end.
|
||||||
|
|
||||||
base_url(Server, Path) ->
|
base_url(Server, Path) ->
|
||||||
Tail = case iolist_to_binary(Path) of
|
Tail = case iolist_to_binary(Path) of
|
||||||
<<$/, Ok/binary>> -> Ok;
|
<<$/, Ok/binary>> -> Ok;
|
||||||
|
11
src/str.erl
11
src/str.erl
@ -93,7 +93,10 @@ rchr(B, C) ->
|
|||||||
-spec str(binary(), binary()) -> non_neg_integer().
|
-spec str(binary(), binary()) -> non_neg_integer().
|
||||||
|
|
||||||
str(B1, B2) ->
|
str(B1, B2) ->
|
||||||
string:str(binary_to_list(B1), binary_to_list(B2)).
|
case binary:match(B1, B2) of
|
||||||
|
{R, _Len} -> R+1;
|
||||||
|
_ -> 0
|
||||||
|
end.
|
||||||
|
|
||||||
-spec rstr(binary(), binary()) -> non_neg_integer().
|
-spec rstr(binary(), binary()) -> non_neg_integer().
|
||||||
|
|
||||||
@ -113,7 +116,7 @@ cspan(B1, B2) ->
|
|||||||
-spec copies(binary(), non_neg_integer()) -> binary().
|
-spec copies(binary(), non_neg_integer()) -> binary().
|
||||||
|
|
||||||
copies(B, N) ->
|
copies(B, N) ->
|
||||||
iolist_to_binary(string:copies(binary_to_list(B), N)).
|
binary:copy(B, N).
|
||||||
|
|
||||||
-spec words(binary()) -> pos_integer().
|
-spec words(binary()) -> pos_integer().
|
||||||
|
|
||||||
@ -201,7 +204,7 @@ join(L, Sep) ->
|
|||||||
-spec substr(binary(), pos_integer()) -> binary().
|
-spec substr(binary(), pos_integer()) -> binary().
|
||||||
|
|
||||||
substr(B, N) ->
|
substr(B, N) ->
|
||||||
iolist_to_binary(string:substr(binary_to_list(B), N)).
|
binary_part(B, N-1, byte_size(B)-N+1).
|
||||||
|
|
||||||
-spec chr(binary(), char()) -> non_neg_integer().
|
-spec chr(binary(), char()) -> non_neg_integer().
|
||||||
|
|
||||||
@ -221,7 +224,7 @@ chars(C, N) ->
|
|||||||
-spec substr(binary(), pos_integer(), non_neg_integer()) -> binary().
|
-spec substr(binary(), pos_integer(), non_neg_integer()) -> binary().
|
||||||
|
|
||||||
substr(B, S, E) ->
|
substr(B, S, E) ->
|
||||||
iolist_to_binary(string:substr(binary_to_list(B), S, E)).
|
binary_part(B, S-1, E).
|
||||||
|
|
||||||
-spec strip(binary(), both | left | right, char()) -> binary().
|
-spec strip(binary(), both | left | right, char()) -> binary().
|
||||||
|
|
||||||
|
@ -481,9 +481,22 @@ format_element(El) ->
|
|||||||
false -> io_lib:format(" ~s~n", El)
|
false -> io_lib:format(" ~s~n", El)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
substitute_forwarded(#mam_result{sub_els = Sub} = El) ->
|
||||||
|
El#mam_result{sub_els = [substitute_forwarded(SEl) || SEl <- Sub]};
|
||||||
|
substitute_forwarded(#carbons_sent{forwarded = Sub} = El) ->
|
||||||
|
El#carbons_sent{forwarded = [substitute_forwarded(SEl) || SEl <- Sub]};
|
||||||
|
substitute_forwarded(#message{sub_els = Sub} = El) ->
|
||||||
|
El#message{sub_els = [substitute_forwarded(SEl) || SEl <- Sub]};
|
||||||
|
substitute_forwarded(#forwarded{delay = Delay, xml_els = Sub}) ->
|
||||||
|
#forwarded_decoded{delay = Delay, sub_els = [xmpp:decode(SEl) || SEl <- Sub]};
|
||||||
|
substitute_forwarded(El) ->
|
||||||
|
El.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
decode(El, NS, Opts) ->
|
decode(El, NS, Opts) ->
|
||||||
try
|
try
|
||||||
Pkt = xmpp:decode(El, NS, Opts),
|
Pkt = substitute_forwarded(xmpp:decode(El, NS, Opts)),
|
||||||
ct:pal("RECV:~n~s~n~s",
|
ct:pal("RECV:~n~s~n~s",
|
||||||
[format_element(El), xmpp:pp(Pkt)]),
|
[format_element(El), xmpp:pp(Pkt)]),
|
||||||
Pkt
|
Pkt
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
-include("mod_proxy65.hrl").
|
-include("mod_proxy65.hrl").
|
||||||
-include("xmpp_codec.hrl").
|
-include("xmpp_codec.hrl").
|
||||||
|
|
||||||
|
-record(forwarded_decoded, {delay :: #delay{},
|
||||||
|
sub_els = [] :: [fxml:xmlel()]}).
|
||||||
|
|
||||||
-define(STREAM_TRAILER, <<"</stream:stream>">>).
|
-define(STREAM_TRAILER, <<"</stream:stream>">>).
|
||||||
|
|
||||||
-define(PUBSUB(Node), <<(?NS_PUBSUB)/binary, "#", Node>>).
|
-define(PUBSUB(Node), <<(?NS_PUBSUB)/binary, "#", Node>>).
|
||||||
|
Loading…
Reference in New Issue
Block a user