24
1
mirror of https://github.com/processone/ejabberd.git synced 2024-07-02 23:06:21 +02:00

Making progress on the Atom interface.

- GET items
- POST items
- GET nodes

HTTP error codes now are the ones XMPP returns.
This commit is contained in:
Eric Cestari 2010-09-07 11:32:14 +02:00
parent a22ebd3c49
commit cd923838c3
2 changed files with 104 additions and 13 deletions

45
doc/http_post.md Normal file
View File

@ -0,0 +1,45 @@
# Managing pubsub nodes through HTTP Atompub #
## Configuration ##
These options will be used by the service to know how to build URLs. Using the previous configuration items the service should be accessed through `http://notify.push.bbc.co.uk:5280/pshb/<host>/<node>/`.
Also, in the ejabberd_http handler configuration, add the identified line.
{5280, ejabberd_http, [
http_poll,
web_admin,
{request_handlers, [{["pshb"], pshb_http}]} % this should be added
]}
## Usage example with cURL ##
### Getting the service document ###
No authentication necessary. All nodes are listed.
curl -i http://<host>:<port>/pshb/<domain>/
### Getting items from a node ###
No authentication done, and all nodes are accessible.
curl -i http://<host>:<port>/pshb/<domain>/<node>/
### Posting a new item ###
curl -u <jid>:<password> -i -X POST -d @entry.atom http://<host>:<port>/pshb/<domain>/<node>
User ability to post is based on node configuration.
### Creating a new node ###
An instant node can be created :
curl -X POST -u cstar@localhost:encore -d "" http://localhost:5280/pshb/localhost

View File

@ -44,19 +44,17 @@
-include("mod_pubsub/pubsub.hrl").
-export([process/2]).
-export([process/2]).
process([_Domain, _Node|_Rest]=LocalPath, #request{auth = Auth} = Request)->
process(LocalPath, #request{auth = Auth} = Request)->
?DEBUG("LocalPath = ~p", [LocalPath]),
case get_auth(Auth) of
%%make sure user belongs to pubsub domain
{User, Domain} ->
out(Request, Request#request.method, LocalPath,{User, Domain});
_ ->
out(Request, Request#request.method, LocalPath,undefined)
end;
process(_LocalPath, _Request)->
error(404).
out(Request, Request#request.method, LocalPath, undefined)
end.
get_auth(Auth) ->
case Auth of
@ -128,13 +126,42 @@ out(Args, 'POST', [Domain, Node]=Uri, {User, _Domain}) ->
?DEBUG("Publishing to ~p~n",[entry_uri(Args, Domain, Node,Slug)]),
{201, [{"location", entry_uri(Args, Domain,Node,Slug)}], Payload};
{error, Error} ->
error(400, Error)
error(Error)
end;
out(Args, 'GET', [Domain]=Uri, From)->
Host = get_host(Uri),
?DEBUG("Host = ~p", [Host]),
case mod_pubsub:tree_action(Host, get_subnodes, [Host, <<>>, From ]) of
[] ->
?DEBUG("Error getting URI ~p : ~p",[Uri, From]),
error(404);
Collections ->
{200, [{"Content-Type", "application/atomsvc+xml"}], "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
++ xml:element_to_string(service(Args,Domain, Collections))}
end;
out(Args, 'POST', [Domain]=Uri, {User, UDomain})->
Host = get_host(Uri),
case mod_pubsub:create_node(Host, Domain, <<>>, {User, UDomain}, "default") of
{error, Error} ->
?ERROR_MSG("Error create node via HTTP : ~p",[Error]),
error(Error); % will probably detail more
{result, [Node]} ->
{200, [{"Content-Type", "application/xml"}], "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
++ xml:element_to_string(Node)}
end;
out(Args, 'POST', [Domain]=Uri, undefined) ->
error(403);
out(Args, 'GET', [Domain, Node, _Item]=URI, _) ->
Failure = fun(Error)->
?DEBUG("Error getting URI ~p : ~p",[URI, Error]),
error(404)
error(Error)
end,
Success = fun(Item)->
Etag =generate_etag(Item),
@ -169,10 +196,10 @@ get_member([_Domain, _Node, Member])->
Member.
collection_uri(R, Domain, Node) ->
base_uri(R, Domain)++ "/" ++Node.
base_uri(R, Domain)++ "/" ++ b2l(Node).
entry_uri(R,Domain, Node, Id)->
collection_uri(R,Domain, Node)++"/"++Id.
collection_uri(R,Domain, Node)++"/"++b2l(Id).
base_uri(#request{host=Host, port=Port}, Domain)->
"http://"++Host++":"++i2l(Port)++"/pshb/" ++ Domain.
@ -208,8 +235,25 @@ collection(Title, Link, Updated, _Id, Entries)->
{xmlelement, "title", [],[{xmlcdata, Title}]} |
Entries
]}.
service(Args, Domain,Collections)->
{xmlelement, "service", [{"xmlns", "http://www.w3.org/2007/app"},
{"xmlns:atom", "http://www.w3.org/2005/Atom"},
{"xmlns:app", "http://www.w3.org/2007/app"}],[
{xmlelement, "workspace", [],[
{xmlelement, "atom:title", [],[{xmlcdata,"Pubsub node Feed for " ++Domain}]} |
lists:map(fun(#pubsub_node{nodeid={_Server, Id}, type=_Type})->
{xmlelement, "collection", [{"href", collection_uri(Args,Domain, Id)}], [
{xmlelement, "atom:title", [], [{xmlcdata, Id}]}
]}
end, Collections)
]}
]}.
%% simple output functions
error({xmlelement, "error", Attrs, _}=Error) ->
Value = list_to_integer(xml:get_attr_s("code", Attrs)),
{Value, [{"Content-type", "application/xml"}], xml:element_to_string(Error)};
error(404)->
{404, [], "Not Found"};
error(403)->
@ -221,7 +265,6 @@ error(401)->
error(Code)->
{Code, [], ""}.
error(Code, Error) when is_list(Error) -> {Code, [], Error};
error(Code, {xmlelement, "error",_,_}=Error) -> {Code, [], xml:element_to_string(Error)};
error(Code, _Error) -> {Code, [], "Bad request"}.
success(200)->
{200, [], ""};
@ -295,4 +338,7 @@ add_zero(L) when is_list(L) -> L.
i2l(I) when is_integer(I) -> integer_to_list(I);
i2l(L) when is_list(L) -> L.
i2l(L) when is_list(L) -> L.
b2l(B) when is_binary(B) -> binary_to_list(B);
b2l(L) when is_list(L) -> L.