NCBI C++ ToolKit
soap_server.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 
2 /* $Id: soap_server.cpp 91809 2020-12-14 15:36:04Z grichenk $
3  * ===========================================================================
4  *
5  * PUBLIC DOMAIN NOTICE
6  * National Center for Biotechnology Information
7  *
8  * This software/database is a "United States Government Work" under the
9  * terms of the United States Copyright Act. It was written as part of
10  * the author's official duties as a United States Government employee and
11  * thus cannot be copyrighted. This software/database is freely available
12  * to the public for use. The National Library of Medicine and the U.S.
13  * Government have not placed any restriction on its use or reproduction.
14  *
15  * Although all reasonable efforts have been taken to ensure the accuracy
16  * and reliability of the software and data, the NLM and the U.S.
17  * Government do not and cannot warrant the performance or results that
18  * may be obtained by using this software or data. The NLM and the U.S.
19  * Government disclaim all warranties, express or implied, including
20  * warranties of performance, merchantability or fitness for any particular
21  * purpose.
22  *
23  * Please cite the author in any work or product based on this material.
24  *
25  * ===========================================================================
26  *
27  * Author: Andrei Gourianov
28  *
29  * File Description:
30  * SOAP server application class
31  *
32  */
33 
34 #include <ncbi_pch.hpp>
35 #include <corelib/ncbifile.hpp>
37 
38 #include <serial/objistrxml.hpp>
39 #include <serial/objostrxml.hpp>
40 
42 
43 #if defined(SOAPSERVER_INTERNALSTORAGE)
44 
45 static const size_t s_Step = 16;
46 CSoapServerApplication::Storage::Storage(void)
47 {
48  m_Capacity=s_Step;
49  m_Current = 0;
50  m_Buffer = new TWebMethod[m_Capacity];
51 }
52 CSoapServerApplication::Storage::Storage(const Storage& src)
53 {
54  m_Capacity = src.m_Capacity;
55  m_Current = src.m_Current;
56  m_Buffer = new TWebMethod[m_Capacity];
57  memcpy( m_Buffer, src.m_Buffer, m_Capacity * sizeof(TWebMethod));
58 }
59 CSoapServerApplication::Storage::~Storage(void)
60 {
61  delete [] m_Buffer;
62 }
63 CSoapServerApplication::Storage::const_iterator
64 CSoapServerApplication::Storage::begin(void) const
65 {
66  return m_Buffer;
67 }
68 CSoapServerApplication::Storage::const_iterator
69 CSoapServerApplication::Storage::end(void) const
70 {
71  return m_Buffer+m_Current;
72 }
73 void CSoapServerApplication::Storage::push_back(TWebMethod value)
74 {
75  if (m_Current >= m_Capacity) {
76  TWebMethod* newbuf = new TWebMethod[m_Capacity+s_Step];
77  memcpy( newbuf, m_Buffer, m_Capacity * sizeof(TWebMethod));
78  m_Capacity += s_Step;
79  delete [] m_Buffer;
80  m_Buffer = newbuf;
81  }
82  *(m_Buffer + m_Current) = value;
83  ++m_Current;
84 }
85 #endif
86 
87 
89  const string& wsdl_filename, const string& namespace_name)
90  : CCgiApplication(), m_DefNamespace(namespace_name), m_Wsdl(wsdl_filename),
91  m_OmitScopePrefixes(false),
92  m_FaultPostFlags(eDPF_Prefix | eDPF_Severity)
93 {
94 }
95 
96 void CSoapServerApplication::SetDefaultNamespaceName(const string& namespace_name)
97 {
98  m_DefNamespace = namespace_name;
99 }
101 {
102  return m_DefNamespace;
103 }
104 void CSoapServerApplication::SetWsdlFilename(const string& wsdl_filename)
105 {
106  m_Wsdl = wsdl_filename;
107 }
108 
109 
111 {
112  const CCgiRequest& request = ctx.GetRequest();
113  CCgiResponse& response = ctx.GetResponse();
114  response.SetContentType("text/xml");
115  if (!x_ProcessWsdlRequest(response, request)) {
116  x_ProcessSoapRequest(response, request);
117  }
118  response.Flush();
119  return 0;
120 }
121 
122 bool
124  const CCgiRequest& request) const
125 {
126  const TCgiEntries& entries = request.GetEntries();
127  if (entries.empty()) {
128  return false;
129  }
130  for(TCgiEntries::const_iterator i = entries.begin();
131  i != entries.end(); ++i) {
132  if (NStr::CompareNocase(i->first, "wsdl") == 0) {
133  response.WriteHeader();
134  if (!m_Wsdl.empty()) {
135  int len = (int)CFile(m_Wsdl).GetLength();
136  if (len > 0) {
137  char* buf = new char[len];
138  ifstream iw(m_Wsdl.c_str());
139  iw.read(buf,len);
140  response.out().write(buf,len);
141  delete [] buf;
142  }
143  }
144  return true;
145  }
146  }
147  return false;
148 }
149 
150 bool
152  const CCgiRequest& request)
153 {
154  bool input_ok=true;
155  string fault_text;
156  CSoapMessage soap_in, soap_out;
158 
159  vector< TTypeInfoGetter >::const_iterator types_in;
160  for (types_in = m_Types.begin(); types_in != m_Types.end(); ++types_in) {
161  soap_in.RegisterObjectType(*types_in);
162  }
163 // read request
164  if (request.GetInputStream()) {
165  try {
166  unique_ptr<CObjectIStream> is(CObjectIStream::Open(eSerial_Xml,*request.GetInputStream()));
167  if (m_OmitScopePrefixes) {
168  dynamic_cast<CObjectIStreamXml*>(is.get())->SetEnforcedStdXml(true);
169  }
170  *is >> soap_in;
171  }
172  catch (CException& e) {
173  input_ok = false;
174  ERR_POST(e);
175  fault_text = e.ReportAll(m_FaultPostFlags);
176  }
177  catch (exception& e) {
178  input_ok = false;
179  fault_text = e.what();
180  }
181  }
182 #if 1
183  else {
184  input_ok = false;
185  fault_text = "No input stream in CCgiRequest";
186  }
187 #else
188 // for debugging only!
189  else {
190  try {
191 #if 0
192  unique_ptr<CObjectIStream> is(CObjectIStream::Open(eSerial_Xml,"-",eSerial_StdWhenDash));
193 #else
194  unique_ptr<CObjectIStream> is(CObjectIStream::Open(eSerial_Xml,"input.xml"));
195 #endif
196  if (m_OmitScopePrefixes) {
197  dynamic_cast<CObjectIStreamXml*>(is.get())->SetEnforcedStdXml(true);
198  }
199  *is >> soap_in;
200  }
201  catch (CException& e) {
202  input_ok = false;
203  ERR_POST(e);
204  fault_text = e.ReportAll(m_FaultPostFlags);
205  }
206  catch (exception& e) {
207  input_ok = false;
208  fault_text = e.what();
209  }
210  }
211 #endif
212 
213  if (input_ok) {
214  input_ok = false;
215  if (soap_in.GetFaultCode() == CSoapFault::eVersionMismatch) {
216  x_FaultVersionMismatch(soap_out);
217  } else if (soap_in.GetFaultCode() == CSoapFault::eMustUnderstand) {
218  x_FaultMustUnderstand(soap_out);
219  } else {
220 
221  const TListeners* listeners = x_FindListeners(soap_in);
222 // process request
223  if (listeners) {
224  input_ok = true;
225  TListeners::const_iterator it;
226  for (it = listeners->begin(); it != listeners->end(); ++it) {
227  const TWebMethod listener = *it;
228  if (!(this->*listener)(soap_out, soap_in)) {
229  break;
230  }
231  }
232  } else {
233  x_FaultNoListeners(soap_out);
234  }
235  }
236  } else {
237  x_FaultServer(soap_out, fault_text);
238  }
239 
240 // send it back
241  if (!input_ok) {
242  // http://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383529
243  response.SetStatus(500, "Internal Server Error");
244  }
245  response.WriteHeader();
246  {
247  unique_ptr<CObjectOStream> out(CObjectOStream::Open(eSerial_Xml,response.out()));
248  if (m_OmitScopePrefixes) {
249  dynamic_cast<CObjectOStreamXml*>(out.get())->SetEnforcedStdXml(true);
250  }
251  *out << soap_out;
252  }
253  return true;
254 }
255 
258 {
259  const CSoapMessage::TSoapContent& content =
261  CSoapMessage::TSoapContent::const_iterator i;
262  for (i = content.begin(); i != content.end(); ++i) {
263  string name = (*i)->GetThisTypeInfo()->GetName();
264  string ns_name = (*i)->GetNamespaceName();
265  if (ns_name.empty() && (*i)->GetThisTypeInfo()->GetDataSpec() != EDataSpec::eXSD ) {
266  ns_name = m_DefNamespace;
267  }
268  const TListeners* listeners = x_FindListenersByName(name,ns_name);
269  if (listeners) {
270  return listeners;
271  }
272  }
273  for (i = content.begin(); i != content.end(); ++i) {
274  const CAnyContentObject* obj =
275  dynamic_cast<const CAnyContentObject*>(i->GetPointer());
276  if (obj) {
277  string name = obj->GetName();
278  string ns_name = obj->GetNamespaceName();
279  const TListeners* listeners = x_FindListenersByName(name,ns_name);
280  if (listeners) {
281  return listeners;
282  }
283  }
284  }
285  return 0;
286 }
287 
290  const string& namespace_name)
291 {
293  for (l = m_Listeners.find(message_name); l != m_Listeners.end(); ++l) {
294  if ((l->second).first == namespace_name) {
295  return &((l->second).second);
296  }
297  }
298  return 0;
299 }
300 
301 void
303 {
304  if (find(m_Types.begin(), m_Types.end(), type_getter) == m_Types.end()) {
305  m_Types.push_back(type_getter);
306  }
307 }
308 
309 void
311  const string& message_name,
312  const string& namespace_name)
313 {
314  string ns(namespace_name);
315  if (ns.empty()) {
316  ns = m_DefNamespace;
317  }
318  TListeners* listeners = x_FindListenersByName(message_name, ns);
319  if (listeners) {
320  listeners->push_back(listener);
321  } else {
322  TListeners new_listeners;
323  new_listeners.push_back(listener);
325  pair<string const, pair<string,TListeners> >(message_name,
326  make_pair(ns,new_listeners)));
327  }
328 }
329 
330 void
332 {
333  m_OmitScopePrefixes = bOmit;
334 }
335 
336 void
338 {
339  CRef<CSoapFault> fault(new CSoapFault);
340  fault->SetFaultcodeEnum(CSoapFault::eVersionMismatch);
341  fault->SetFaultstring("Server supports SOAP v1.1 only");
342  response.AddObject( *fault, CSoapMessage::eMsgBody);
343 }
344 
345 void
347 {
348  CRef<CSoapFault> fault(new CSoapFault);
349  fault->SetFaultcodeEnum(CSoapFault::eMustUnderstand);
350  fault->SetFaultstring("An immediate child element of the SOAP Header not understood");
351  response.AddObject( *fault, CSoapMessage::eMsgBody);
352 }
353 
354 void
356 {
357  CRef<CSoapFault> fault(new CSoapFault);
358  fault->SetFaultcodeEnum(CSoapFault::eServer);
359  fault->SetFaultstring(text);
360  response.AddObject( *fault, CSoapMessage::eMsgBody);
361 }
362 
363 void
365 {
366  CRef<CSoapFault> fault(new CSoapFault);
367  fault->SetFaultcodeEnum(CSoapFault::eClient);
368  fault->SetFaultstring("Unsupported request type");
369  response.AddObject( *fault, CSoapMessage::eMsgBody);
370 }
371 
372 
#define false
Definition: bool.h:36
Serializable object that stores any combination of parsable data.
Definition: serialbase.hpp:264
CCgiRequest::
Definition: ncbicgi.hpp:685
CFile –.
Definition: ncbifile.hpp:1604
CObjectIStreamXml –.
Definition: objistrxml.hpp:56
CObjectOStreamXml –.
Definition: objostrxml.hpp:54
CRef –.
Definition: ncbiobj.hpp:618
@ eVersionMismatch
Definition: soap_fault.hpp:61
const TSoapContent & GetContent(EMessagePart source) const
void AddObject(const CSerialObject &obj, EMessagePart destination)
CSoapFault::ESoap_FaultcodeEnum GetFaultCode(void) const
void SetDefaultObjectNamespaceName(const string &ns_name)
void RegisterObjectType(TTypeInfoGetter type_getter)
vector< CConstRef< CSerialObject > > TSoapContent
TDiagPostFlags m_FaultPostFlags
const TListeners * x_FindListeners(const CSoapMessage &request)
void SetWsdlFilename(const string &wsdl_filename)
void x_FaultServer(CSoapMessage &response, const string &text) const
void x_FaultVersionMismatch(CSoapMessage &response) const
void SetOmitScopePrefixes(bool bOmit)
void AddMessageListener(TWebMethod listener, const string &message_name, const string &namespace_name=kEmptyStr)
vector< TTypeInfoGetter > m_Types
Definition: soap_server.hpp:98
const string & GetDefaultNamespaceName(void) const
void SetDefaultNamespaceName(const string &namespace_name)
Definition: soap_server.cpp:96
void x_FaultMustUnderstand(CSoapMessage &response) const
void x_FaultNoListeners(CSoapMessage &response) const
vector< TWebMethod > TListeners
Definition: soap_server.hpp:53
multimap< string, pair< string, TListeners > > m_Listeners
Definition: soap_server.hpp:99
bool x_ProcessWsdlRequest(CCgiResponse &response, const CCgiRequest &request) const
CSoapServerApplication(const string &wsdl_filename, const string &namespace_name)
Definition: soap_server.cpp:88
bool(CSoapServerApplication::* TWebMethod)(CSoapMessage &response, const CSoapMessage &request)
Definition: soap_server.hpp:50
void RegisterObjectType(TTypeInfoGetter type_getter)
bool x_ProcessSoapRequest(CCgiResponse &response, const CCgiRequest &request)
TListeners * x_FindListenersByName(const string &message_name, const string &namespace_name)
virtual int ProcessRequest(CCgiContext &ctx)
This is the method you should override.
const_iterator find(const key_type &key) const
Definition: map.hpp:293
const_iterator end() const
Definition: map.hpp:292
iterator insert(const value_type &val)
Definition: map.hpp:305
char value[7]
Definition: config.c:431
CS_CONTEXT * ctx
Definition: t0006.c:12
std::ofstream out("events_result.xml")
main entry point for tests
const TCgiEntries & GetEntries(void) const
Get a set of entries(decoded) received from the client.
Definition: ncbicgi.hpp:1181
void Flush(void) const
Flush output stream.
Definition: ncbicgir.cpp:529
CNcbiOstream & out(void) const
Get output stream. Throw exception if GetOutput() is NULL.
Definition: ncbicgir.cpp:257
void SetStatus(unsigned int code, const string &reason=kEmptyStr)
Definition: ncbicgir.cpp:197
void SetContentType(const string &type)
Set content type (text/html by default if not provided)
Definition: ncbicgir.hpp:337
CNcbiOstream & WriteHeader(void) const
Write HTTP response header to the output stream.
Definition: ncbicgir.hpp:396
CNcbiIstream * GetInputStream(void) const
Return pointer to the input stream.
Definition: ncbicgi.hpp:1196
#define ERR_POST(message)
Error posting with file, line number information but without error codes.
Definition: ncbidiag.hpp:186
@ eDPF_Severity
Severity (default)
Definition: ncbidiag.hpp:697
@ eDPF_Prefix
Prefix (default)
Definition: ncbidiag.hpp:696
string ReportAll(TDiagPostFlags flags=eDPF_Exception) const
Report all exceptions.
Definition: ncbiexpt.cpp:370
virtual const char * what(void) const noexcept
Standard report (includes full backlog).
Definition: ncbiexpt.cpp:342
Int8 GetLength(void) const
Get size of file.
Definition: ncbifile.cpp:3204
const string & GetNamespaceName(void) const
Get namespace name.
TTypeInfo(* TTypeInfoGetter)(void)
Definition: serialdef.hpp:63
const string & GetName(void) const
Get local name.
@ eSerial_StdWhenDash
use std stream when filename is "-"
Definition: serialdef.hpp:129
@ eSerial_Xml
XML.
Definition: serialdef.hpp:75
static CObjectOStream * Open(ESerialDataFormat format, CNcbiOstream &outStream, bool deleteOutStream)
Create serial object writer and attach it to an output stream.
Definition: objostr.cpp:126
static CObjectIStream * Open(ESerialDataFormat format, CNcbiIstream &inStream, bool deleteInStream)
Create serial object reader and attach it to an input stream.
Definition: objistr.cpp:195
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
static int CompareNocase(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2)
Case-insensitive compare of a substring with another string.
Definition: ncbistr.cpp:219
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
char * buf
int i
int len
static void text(MDB_val *v)
Definition: mdb_dump.c:62
Defines classes: CDirEntry, CFile, CDir, CSymLink, CMemoryFile, CFileUtil, CFileLock,...
static wxAcceleratorEntry entries[3]
Modified on Sat Dec 02 09:23:10 2023 by modify_doxy.py rev. 669887