Added a parameter to semaphore constructor to avoid ambiguity
[pwlib.git] / src / ptclib / pxmlrpcs.cxx
blob532aff8038e872b1b336e51f8ca2f7ac7a8a2e47
1 /*
2 * pxmlrpcs.cxx
4 * XML/RPC support
6 * Portable Windows Library
8 * Copyright (c) 2002 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
26 * $Log$
27 * Revision 1.6 2003/02/19 01:51:18 robertj
28 * Change to make it easier to set a fault from the server function handler.
30 * Revision 1.5 2002/11/06 22:47:25 robertj
31 * Fixed header comment (copyright etc)
33 * Revision 1.4 2002/10/23 15:57:28 craigs
34 * Fixed problem where no params specified
36 * Revision 1.3 2002/10/17 12:51:01 rogerh
37 * Add a newline at the of the file to silence a gcc compiler warning.
39 * Revision 1.2 2002/10/10 04:43:44 robertj
40 * VxWorks port, thanks Martijn Roest
42 * Revision 1.1 2002/10/02 08:54:01 craigs
43 * Added support for XMLRPC server
47 // This depends on the expat XML library by Jim Clark
48 // See http://www.jclark.com/xml/expat.html for more information
50 #include <ptlib.h>
52 #ifdef __GNUC__
53 #pragma implementation "pxmlrpcs.h"
54 #endif
56 #define DEFAULT_XMPRPC_URL "/RPC2"
58 #include <ptclib/pxmlrpcs.h>
60 #if P_EXPAT
62 PXMLRPCServerResource::PXMLRPCServerResource()
63 : PHTTPResource(DEFAULT_XMPRPC_URL)
67 PXMLRPCServerResource::PXMLRPCServerResource(
68 const PHTTPAuthority & auth) // Authorisation for the resource.
69 : PHTTPResource(DEFAULT_XMPRPC_URL, auth)
72 PXMLRPCServerResource::PXMLRPCServerResource(
73 const PURL & url) // Name of the resource in URL space.
74 : PHTTPResource(url)
78 PXMLRPCServerResource::PXMLRPCServerResource(
79 const PURL & url, // Name of the resource in URL space.
80 const PHTTPAuthority & auth // Authorisation for the resource.
82 : PHTTPResource(url, auth)
86 BOOL PXMLRPCServerResource::SetMethod(const PString & methodName, const PNotifier & func)
88 PWaitAndSignal m(methodMutex);
90 // find the method, or create a new one
91 PXMLRPCServerMethod * methodInfo;
92 PINDEX pos = methodList.GetValuesIndex(methodName);
93 if (pos != P_MAX_INDEX)
94 methodInfo = (PXMLRPCServerMethod *)methodList.GetAt(pos);
95 else {
96 methodInfo = new PXMLRPCServerMethod(methodName);
97 methodList.Append(methodInfo);
100 // set the function
101 methodInfo->methodFunc = func;
103 return TRUE;
106 BOOL PXMLRPCServerResource::LoadHeaders(PHTTPRequest & /*request*/) // Information on this request.
108 return TRUE;
111 BOOL PXMLRPCServerResource::OnPOSTData(PHTTPRequest & request,
112 const PStringToString & /*data*/)
114 PString reply;
116 OnXMLRPCRequest(request.entityBody, reply);
118 request.code = PHTTP::RequestOK;
119 request.outMIME.SetAt(PHTTP::ContentTypeTag, "text/xml");
121 PINDEX len = reply.GetLength();
122 request.server.StartResponse(request.code, request.outMIME, len);
123 return request.server.Write((const char *)reply, len);
127 void PXMLRPCServerResource::OnXMLRPCRequest(const PString & body, PString & reply)
129 // get body of message here
130 PXMLRPCBlock request;
131 BOOL ok = request.Load(body);
133 // if cannot parse XML, set return
134 if (!ok) {
135 reply = FormatFault(PXMLRPC::CannotParseRequestXML, "XML error:" + request.GetErrorString());
136 return;
139 // make sure methodCall is specified as top level
140 if ((request.GetDocumentType() != "methodCall") || (request.GetNumElements() < 1)) {
141 reply = FormatFault(PXMLRPC::RequestHasWrongDocumentType, "document type is not methodCall");
142 return;
145 // make sure methodName is speciified
146 PXMLElement * methodName = request.GetElement("methodName");
147 if (methodName == NULL) {
148 reply = FormatFault(PXMLRPC::RequestHasNoMethodName, "methodCall has no methodName");
149 return;
152 // extract method name
153 if ((methodName->GetSize() != 1) || (methodName->GetElement(0)->IsElement())) {
154 reply = FormatFault(PXMLRPC::MethodNameIsEmpty, "methodName is empty");
155 return;
157 PString method = ((PXMLData *)methodName->GetElement(0))->GetString();
159 // extract params
160 PTRACE(3, "XMLRPC\tReceived XMLRPC request for method " << method);
162 OnXMLRPCRequest(method, request, reply);
165 void PXMLRPCServerResource::OnXMLRPCRequest(const PString & methodName,
166 PXMLRPCBlock & request,
167 PString & reply)
169 methodMutex.Wait();
171 // find the method information
172 PINDEX pos = methodList.GetValuesIndex(methodName);
173 if (pos == P_MAX_INDEX) {
174 reply = FormatFault(PXMLRPC::UnknownMethod, "unknown method " + methodName);
175 return;
177 PXMLRPCServerMethod * methodInfo = (PXMLRPCServerMethod *)methodList.GetAt(pos);
178 PNotifier notifier = methodInfo->methodFunc;
179 methodMutex.Signal();
181 // create paramaters
182 PXMLRPCServerParms p(*this, request);
184 // call the notifier
185 notifier(p, 0);
187 // get the reply
188 if (request.GetFaultCode() != P_MAX_INDEX)
189 reply = FormatFault(request.GetFaultCode(), request.GetFaultText());
190 else {
191 PStringStream r; r << p.response;
192 reply = r;
197 PString PXMLRPCServerResource::FormatFault(PINDEX code, const PString & str)
199 PTRACE(2, "XMLRPC\trequest failed: " << str);
201 PStringStream reply;
202 reply << "<?xml version=\"1.0\"?>\n"
203 "<methodResponse>"
204 "<fault>"
205 "<value>"
206 "<struct>"
207 "<member>"
208 "<name>faultCode</name>"
209 "<value><int>" << code << "</int></value>"
210 "</member>"
211 "<member>"
212 "<name>faultString</name>"
213 "<value><string>" << str << "</string></value>"
214 "</member>"
215 "</struct>"
216 "</value>"
217 "</fault>"
218 "</methodResponse>";
219 return reply;
222 #endif