URL.h
Go to the documentation of this file.
1 
20 #ifndef URL_H_9DAEGSMV
21 #define URL_H_9DAEGSMV
22 
23 #include "uscxml/Common.h"
24 #include "uscxml/messages/Event.h"
25 
26 #define DOWNLOAD_IF_NECESSARY if (!_isDownloaded) { download(true); }
27 
28 #include <string>
29 #include <sstream>
30 #include <map>
31 #include <set>
32 #include <list>
33 #include <thread>
34 #include <condition_variable>
35 #include <curl/curl.h>
36 #include <uriparser/Uri.h>
37 
38 #define USCXML_URI_STRING(obj, field) std::string(obj.field.first, obj.field.afterLast - obj.field.first)
39 
40 namespace uscxml {
41 
42 class URL;
43 
44 class USCXML_API URLMonitor {
45 public:
46  virtual void downloadStarted(const URL& url) {};
47  virtual void downloadCompleted(const URL& url) {};
48  virtual void downloadFailed(const URL& url, int errorCode) {};
49  virtual void headerChunkReceived(const URL& url, const std::string& headerChunk) {};
50  virtual void contentChunkReceived(const URL& url, const std::string& contentChunk) {};
51 };
52 
53 enum URLRequestType {
54  POST,
55  GET
56 };
57 
58 class USCXML_API URLImpl : public std::enable_shared_from_this<URLImpl> {
59 public:
60  URLImpl(const std::string& url);
61  ~URLImpl();
62 
63  bool isAbsolute() const {
64  // see https://sourceforge.net/p/uriparser/bugs/3/
65  return _uri.absolutePath || ((_uri.hostText.first != nullptr) && (_uri.pathHead != nullptr));
66  }
67 
68  std::string scheme() const {
69  return USCXML_URI_STRING(_uri, scheme);
70  }
71 
72  std::string userInfo() const {
73  return USCXML_URI_STRING(_uri, userInfo);
74  }
75 
76  std::string host() const {
77  return USCXML_URI_STRING(_uri, hostText);
78  }
79 
80  std::string port() const {
81  return USCXML_URI_STRING(_uri, portText);
82  }
83 
84  std::string fragment() const {
85  return USCXML_URI_STRING(_uri, fragment);
86  }
87 
88  std::map<std::string, std::string> query() const;
89  std::string path() const;
90  std::list<std::string> pathComponents() const;
91 
92  void normalize();
93 
94  static URL resolve(URLImpl* relativeURL, URLImpl* absoluteURL);
95  static URL resolveWithCWD(URLImpl* relativeURL);
96  static URL refer(URLImpl* absoluteSource, URLImpl* absoluteBase);
97 
98  void addMonitor(URLMonitor* monitor) {
99  _monitors.insert(monitor);
100  }
101  void removeMonitor(URLMonitor* monitor) {
102  _monitors.erase(monitor);
103  }
104 
105  // downloading / uploading
106  void addOutHeader(const std::string& key, const std::string& value) {
107  _outHeader[key] = value;
108  }
109  void setOutContent(const std::string& content) {
110  _outContent = content;
111  _requestType = URLRequestType::POST;
112  }
113  void setRequestType(URLRequestType requestType) {
114  _requestType = requestType;
115 
116  }
117 
118  const std::map<std::string, std::string> getInHeaderFields() {
119  DOWNLOAD_IF_NECESSARY
120  return _inHeaders;
121  }
122 
123  const std::string getInHeaderField(const std::string& key) {
124  DOWNLOAD_IF_NECESSARY
125  if (_inHeaders.find(key) != _inHeaders.end()) {
126  return _inHeaders[key];
127  }
128  return "";
129  }
130 
131  const std::string getStatusCode() const {
132 // DOWNLOAD_IF_NECESSARY
133  return _statusCode;
134  }
135 
136  const std::string getStatusMessage() const {
137 // DOWNLOAD_IF_NECESSARY
138  return _statusMsg;
139  }
140 
141  const std::string getInContent(bool forceReload = false) {
142  if (forceReload)
143  _isDownloaded = false;
144  DOWNLOAD_IF_NECESSARY
145  return _rawInContent.str();
146  }
147 
148  const void download(bool blocking = false);
149 
150  operator Data() const;
151  operator std::string() const;
152 
153 protected:
154  URLImpl();
155  UriUriA _uri;
156  std::string _orig;
157 
158  CURL* getCurlHandle();
159  static size_t writeHandler(void *ptr, size_t size, size_t nmemb, void *userdata);
160  static size_t headerHandler(void *ptr, size_t size, size_t nmemb, void *userdata);
161 
162  void downloadStarted();
163  void downloadCompleted();
164  void downloadFailed(CURLcode errorCode);
165 
166  static void prepareException(ErrorEvent& exception, int errorCode, const std::string& origUri, UriParserStateA* parser);
167 
168  CURL* _handle;
169  std::stringstream _rawInContent;
170  std::stringstream _rawInHeader;
171  std::map<std::string, std::string> _inHeaders;
172 
173  std::string _outContent;
174  std::map<std::string, std::string> _outHeader;
175  URLRequestType _requestType;
176 
177  std::string _statusCode;
178  std::string _statusMsg;
179  bool _isDownloaded;
180  bool _hasFailed;
181  std::string _error;
182 
183  std::condition_variable_any _condVar;
184  std::recursive_mutex _mutex;
185 
186  std::set<URLMonitor*> _monitors;
187 
188  friend class URLFetcher;
189 };
190 
191 class USCXML_API URL {
192 public:
194 
195  URL(const std::string url) : _impl(new URLImpl(url)) {}
196 
197  bool isAbsolute() {
198  return _impl->isAbsolute();
199  }
200 
201  std::string scheme() {
202  return _impl->scheme();
203  }
204 
205  std::string userInfo() {
206  return _impl->userInfo();
207  }
208 
209  std::string host() {
210  return _impl->host();
211  }
212 
213  std::string port() {
214  return _impl->port();
215  }
216 
217  std::string fragment() {
218  return _impl->fragment();
219  }
220 
221  std::map<std::string, std::string> query() {
222  return _impl->query();
223  }
224 
225  std::string path() {
226  return _impl->path();
227  }
228 
229  std::list<std::string> pathComponents() {
230  return _impl->pathComponents();
231  }
232 
233  void normalize() {
234  return _impl->normalize();
235  }
236 
237  static URL resolve(URL relativeURL, URL absoluteURL) {
238  return URLImpl::resolve(relativeURL._impl.get(), absoluteURL._impl.get());
239  }
240 
241  static URL resolveWithCWD(URL relativeURL) {
242  return URLImpl::resolveWithCWD(relativeURL._impl.get());
243  }
244 
245  static URL refer(URL absoluteSource, URL absoluteBase) {
246  return URLImpl::refer(absoluteSource._impl.get(), absoluteBase._impl.get());
247  }
248 
249  void addOutHeader(const std::string& key, const std::string& value) {
250  return _impl->addOutHeader(key, value);
251  }
252 
253  void setOutContent(const std::string& content) {
254  return _impl->setOutContent(content);
255  }
256  void setRequestType(URLRequestType requestType) {
257  return _impl->setRequestType(requestType);
258  }
259 
260  const std::map<std::string, std::string> getInHeaderFields() {
261  return _impl->getInHeaderFields();
262  }
263 
264  const std::string getInHeaderField(const std::string& key) {
265  return _impl->getInHeaderField(key);
266  }
267 
268  const std::string getStatusCode() const {
269  return _impl->getStatusCode();
270  }
271 
272  const std::string getStatusMessage() const {
273  return _impl->getStatusMessage();
274  }
275 
276  const std::string getInContent(bool forceReload = false) {
277  return _impl->getInContent(forceReload);
278  }
279 
280  const void download(bool blocking = false) const {
281  return _impl->download(blocking);
282  }
283 
284  void addMonitor(URLMonitor* monitor) {
285  return _impl->addMonitor(monitor);
286  }
287  void removeMonitor(URLMonitor* monitor) {
288  return _impl->removeMonitor(monitor);
289  }
290 
291  operator Data() const {
292  return _impl->operator Data();
293  }
294 
295  operator std::string() {
296  return (*_impl.get());
297  }
298 
299 protected:
300  std::shared_ptr<URLImpl> _impl;
301  friend class URLFetcher;
302 };
303 
304 class USCXML_API URLFetcher {
305 public:
306  static void fetchURL(URL& url);
307  static void breakURL(URL& url);
308 
309  void start();
310  void stop();
311 
312 protected:
313  URLFetcher();
314  ~URLFetcher();
315 
316  static URLFetcher* _instance;
317  static URLFetcher* getInstance();
318 
319  static void run(void* instance);
320  void perform();
321 
322  std::thread* _thread;
323  std::condition_variable_any _condVar;
324  std::recursive_mutex _mutex;
325  bool _isStarted;
326 
327  std::map<CURL*, URL> _handlesToURLs;
328  CURLM* _multiHandle;
329  char* _envProxy;
330 };
331 
332 }
333 
334 #endif /* end of include guard: URL_H_9DAEGSMV */
Definition: URL.h:44
Definition: InterpreterIssue.cpp:33
Definition: Event.h:191
#define PIMPL_OPERATORS(type)
The usual operators as required for the PIMPL pattern.
Definition: Common.h:60
Definition: URL.h:304
Definition: URL.h:191
Definition: Data.h:44
Definition: URL.h:58