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

Go to the SVN repository for this file.

1 /*
2  * Redistribution and use in source and binary forms, with or without
3  * modification, are permitted provided that the following conditions
4  * are met:
5  *
6  * 1. Redistributions of source code must retain the above copyright
7  * notice, this list of conditions and the following disclaimer.
8  * 2. Redistributions in binary form must reproduce the above copyright
9  * notice, this list of conditions and the following disclaimer in
10  * the documentation and/or other materials provided with the
11  * distribution.
12  * 3. Neither the name of the Author nor the names of its contributors
13  * may be used to endorse or promote products derived from this software
14  * without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
20  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /*
31  * $Id: https_input_impl.cpp 99402 2023-03-22 18:09:14Z satskyse $
32  */
33 
34 #include <string.h>
35 #include <libxml/xmlIO.h>
36 
39 
40 #include "https_input_impl.hpp"
41 
42 
43 
44 
45 using namespace ncbi;
46 
47 
48 namespace {
49 
50  struct https_context {
51  std::string uri_;
52  CConn_HttpStream * stream_;
53  };
54 
55  // See xmlInputMatchCallback
56  // uri: filename or URI
57  // return: 1 if matched, 0 if another input module should be used
58  extern "C" int https_input_match(const char * uri);
59 
60 
61  // See xmlInputOpenCallback
62  // uri: filename or URI
63  // return: https input context or NULL in case of errors
64  extern "C" void * https_input_open(const char * uri);
65 
66 
67  // See xmlInputReadCallback
68  // context: https input context
69  // buffer: the buffer to store data
70  // len: the length of the buffer
71  // return: the number of bytes read or -1 in case of error
72  extern "C" int https_input_read(void * context, char * buffer, int len);
73 
74 
75  // See xmlInputCloseCallback
76  // context: https input context
77  // return: 0 if OK, -1 in case of errors
78  extern "C" int https_input_close(void * context);
79 
80 
81  // There is no good way for the callbacks above to tell about the
82  // errors or warnings. So this is a storage for the custom messages.
83 
84  // Unfortunately at the time of writing the thread_local is not properly
85  // supported by all the compilers we use. So there are a few versions
86  // introduced here.
87  #if defined(_MSC_VER)
88  #ifndef HTTPS_ERRORS_USE_POD
89  #define HTTPS_ERRORS_USE_POD 1
90  #endif
91  __declspec(thread) xml::error_messages * https_messages = NULL;
92  #else
93  #if (defined(NCBI_OS_DARWIN) || defined(NCBI_OS_BSD)) \
94  && defined(NCBI_COMPILER_ANY_CLANG)
95  #ifndef HTTPS_ERRORS_USE_POD
96  #define HTTPS_ERRORS_USE_POD 1
97  #endif
98  __thread xml::error_messages * https_messages = NULL;
99  #else
100  thread_local xml::error_messages https_messages;
101  #endif
102  #endif
103 }
104 
105 
106 
107 namespace xml {
108  namespace impl {
109  // Registers xml input
111  {
112  if (xmlRegisterInputCallbacks(https_input_match,
113  https_input_open,
114  https_input_read,
115  https_input_close) == -1)
116  throw xml::exception("Error registering https input");
117  }
118 
120  {
121  #if defined(HTTPS_ERRORS_USE_POD)
122  if (https_messages)
123  delete https_messages;
124  https_messages = new xml::error_messages;
125  #else
126  https_messages.get_messages().clear();
127  #endif
128  }
129 
131  {
132  #if defined(HTTPS_ERRORS_USE_POD)
133  if (https_messages) {
134  append_to.append_messages(*https_messages);
135  delete https_messages;
136  https_messages = NULL;
137  }
138  #else
139  append_to.append_messages(https_messages);
140  #endif
141  }
142 
145  long line,
146  const std::string & fname)
147  {
148  #if defined(HTTPS_ERRORS_USE_POD)
149  if (https_messages)
150  https_messages->get_messages().push_back(
151  error_message(msg, msg_type,
152  line, fname));
153  #else
154  https_messages.get_messages().push_back(
155  error_message(msg, msg_type,
156  line, fname));
157  #endif
158  }
159 
160  } // namespace impl
161 } // namespace xml
162 
163 
164 namespace {
165 
166  extern "C" int https_input_match(const char * uri)
167  {
168  if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "https://", 8))
169  return 1;
170  return 0;
171  }
172 
173 
174  extern "C" void * https_input_open(const char * uri)
175  {
176  https_context * context = NULL;
177 
178  try {
179  context = new https_context;
180  } catch (...) {
181  xml::impl::append_https_message("Cannot allocate memory for"
182  " an https IO context",
184  0, "");
185  return NULL;
186  }
187 
188  try {
189  context->uri_ = std::string(uri);
190  context->stream_ = new CConn_HttpStream(uri);
191  } catch (const std::exception & exc) {
193  "Error creating https stream for URI " + std::string(uri) +
194  ": " + std::string(exc.what()),
196 
197  delete context;
198  return NULL;
199  } catch (...) {
201  "Unknown error creating https stream for URI " +
202  std::string(uri),
204 
205  delete context;
206  return NULL;
207  }
208 
209  return context;
210  }
211 
212 
213  extern "C" int https_input_read(void * context, char * buffer, int len)
214  {
215  https_context * ctxt = (https_context *) context;
216 
217  if (ctxt->stream_->eof())
218  return 0;
219 
220  try {
221  // Note: the eof bit is set together with the fail bit
222  // Cases:
223  // - good URI, size of content < size of buffer =>
224  // eof == 1, fail == 1, status == 200
225  // - broken URI =>
226  // eof == 1, fail == 1, status == 404
227  // So it was decided to stick on status codes
228  ctxt->stream_->read(buffer, len);
229  if (ctxt->stream_->GetStatusCode() != 200) {
230  char status_buffer[64];
231 
232  snprintf(status_buffer, 64, "%d", ctxt->stream_->GetStatusCode());
234  "Error reading from URI " +
235  ctxt->uri_ + ". Last status: " +
236  std::string(status_buffer) + " (" +
237  ctxt->stream_->GetStatusText() + ")",
239 
240  return -1;
241  }
242  } catch (const std::exception & exc) {
244  "Error reading from URI " +
245  ctxt->uri_ + ": " + std::string(exc.what()),
247  return -1;
248  } catch (...) {
250  "Unknown error reading from URI " +
251  std::string(ctxt->uri_),
253  return -1;
254  }
255 
256  return static_cast<int>(ctxt->stream_->gcount());
257  }
258 
259 
260  extern "C" int https_input_close(void * context)
261  {
262  https_context * ctxt = (https_context *) context;
263 
264  if (ctxt) {
265  delete ctxt->stream_;
266  delete ctxt;
267  }
268  return 0;
269  }
270 }
271 
This stream exchanges data with an HTTP server located at the URL: http[s]://host[:port]/path[?...
The xml::error_message class is used to store a single error message which may appear while parsing o...
Definition: errors.hpp:50
message_type
A type for different type of errors.
Definition: errors.hpp:53
@ type_warning
warning
Definition: errors.hpp:56
The xml::error_messages class is used to store all the error message which are collected while parsin...
Definition: errors.hpp:137
void append_messages(const error_messages &other)
Appends the messages from the other container.
Definition: errors.cpp:147
const error_messages_type & get_messages(void) const
Get the error messages.
Definition: errors.cpp:98
This exception class is thrown by xmlwrapp for all runtime XML-related errors along with the xml::par...
Definition: exception.hpp:64
string
Definition: cgiapp.hpp:687
#define NULL
Definition: ncbistd.hpp:225
int len
This file contains the definition of the xml::exception class.
Magic spell ;-) needed for some weird compilers... very empiric.
void append_https_message(const std::string &msg, error_message::message_type msg_type, long line, const std::string &fname)
void clear_https_messages(void)
void collect_https_messages(xml::error_messages &append_to)
void register_https_input(void)
XML library namespace.
Definition: attributes.hpp:57
static pcre_uint8 * buffer
Definition: pcretest.c:1051
union __declspec(align(16)) SIMDVec
Definition: sse2neon.h:347
Modified on Sat Feb 24 07:47:02 2024 by modify_doxy.py rev. 669887