diff options
Diffstat (limited to 'linden/indra/llmessage/llurlrequest.h')
-rw-r--r-- | linden/indra/llmessage/llurlrequest.h | 414 |
1 files changed, 414 insertions, 0 deletions
diff --git a/linden/indra/llmessage/llurlrequest.h b/linden/indra/llmessage/llurlrequest.h new file mode 100644 index 0000000..788b0e4 --- /dev/null +++ b/linden/indra/llmessage/llurlrequest.h | |||
@@ -0,0 +1,414 @@ | |||
1 | /** | ||
2 | * @file llurlrequest.h | ||
3 | * @author Phoenix | ||
4 | * @date 2005-04-21 | ||
5 | * @brief Declaration of url based requests on pipes. | ||
6 | * | ||
7 | * Copyright (c) 2005-2007, Linden Research, Inc. | ||
8 | * | ||
9 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
10 | * to you under the terms of the GNU General Public License, version 2.0 | ||
11 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
12 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
13 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
14 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
15 | * | ||
16 | * There are special exceptions to the terms and conditions of the GPL as | ||
17 | * it is applied to this Source Code. View the full text of the exception | ||
18 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
19 | * online at http://secondlife.com/developers/opensource/flossexception | ||
20 | * | ||
21 | * By copying, modifying or distributing this software, you acknowledge | ||
22 | * that you have read and understood your obligations described above, | ||
23 | * and agree to abide by those obligations. | ||
24 | * | ||
25 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
26 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
27 | * COMPLETENESS OR PERFORMANCE. | ||
28 | */ | ||
29 | |||
30 | #ifndef LL_LLURLREQUEST_H | ||
31 | #define LL_LLURLREQUEST_H | ||
32 | |||
33 | /** | ||
34 | * This file holds the declaration of useful classes for dealing with | ||
35 | * url based client requests. | ||
36 | */ | ||
37 | |||
38 | #include <string> | ||
39 | #include "lliopipe.h" | ||
40 | #include "llchainio.h" | ||
41 | |||
42 | class LLURLRequestDetail; | ||
43 | |||
44 | class LLURLRequestComplete; | ||
45 | |||
46 | /** | ||
47 | * @class LLURLRequest | ||
48 | * @brief Class to handle url based requests. | ||
49 | * @see LLIOPipe | ||
50 | * | ||
51 | * Currently, this class is implemented on top of curl. From the | ||
52 | * vantage of a programmer using this class, you do not care so much, | ||
53 | * but it's useful to know since in order to accomplish 'non-blocking' | ||
54 | * behavior, we have to use a more expensive curl interface which can | ||
55 | * still block if the server enters a half-accepted state. It would be | ||
56 | * worth the time and effort to eventually port this to a raw client | ||
57 | * socket. | ||
58 | */ | ||
59 | class LLURLRequest : public LLIOPipe | ||
60 | { | ||
61 | public: | ||
62 | /** | ||
63 | * @brief This enumeration is for specifying the type of request. | ||
64 | */ | ||
65 | enum ERequestAction | ||
66 | { | ||
67 | INVALID, | ||
68 | HTTP_GET, | ||
69 | HTTP_PUT, | ||
70 | HTTP_POST, | ||
71 | HTTP_DELETE, | ||
72 | REQUEST_ACTION_COUNT | ||
73 | }; | ||
74 | |||
75 | /** | ||
76 | * @brief Constructor. | ||
77 | * | ||
78 | * @param action One of the ERequestAction enumerations. | ||
79 | */ | ||
80 | LLURLRequest(ERequestAction action); | ||
81 | |||
82 | /** | ||
83 | * @brief Constructor. | ||
84 | * | ||
85 | * @param action One of the ERequestAction enumerations. | ||
86 | * @param url The url of the request. It should already be encoded. | ||
87 | */ | ||
88 | LLURLRequest(ERequestAction action, const std::string& url); | ||
89 | |||
90 | /** | ||
91 | * @brief Destructor. | ||
92 | */ | ||
93 | virtual ~LLURLRequest(); | ||
94 | |||
95 | /* @name Instance methods | ||
96 | */ | ||
97 | //@{ | ||
98 | /** | ||
99 | * @brief Set the url for the request | ||
100 | * | ||
101 | * This method assumes the url is encoded appropriately for the | ||
102 | * request. | ||
103 | * The url must be set somehow before the first call to process(), | ||
104 | * or the url will not be set correctly. | ||
105 | * | ||
106 | */ | ||
107 | void setURL(const std::string& url); | ||
108 | |||
109 | /** | ||
110 | * @brief Add a header to the http post. | ||
111 | * | ||
112 | * The header must be correctly formatted for HTTP requests. This | ||
113 | * provides a raw interface if you know what kind of request you | ||
114 | * will be making during construction of this instance. All | ||
115 | * required headers will be automatically constructed, so this is | ||
116 | * usually useful for encoding parameters. | ||
117 | */ | ||
118 | void addHeader(const char* header); | ||
119 | |||
120 | /** | ||
121 | * @brief Check remote server certificate signed by a known root CA. | ||
122 | * | ||
123 | * Set whether request will check that remote server | ||
124 | * certificates are signed by a known root CA when using HTTPS. | ||
125 | * Use the supplied root certificate bundle if supplied, else use | ||
126 | * the standard bundle as found by libcurl and openssl. | ||
127 | */ | ||
128 | void checkRootCertificate(bool check, const char* caBundle = NULL); | ||
129 | |||
130 | /** | ||
131 | * @brief Request a particular response encoding if available. | ||
132 | * | ||
133 | * This call is a shortcut for requesting a particular encoding | ||
134 | * from the server, eg, 'gzip'. | ||
135 | */ | ||
136 | void requestEncoding(const char* encoding); | ||
137 | |||
138 | /** | ||
139 | * @brief Return at most size bytes of body. | ||
140 | * | ||
141 | * If the body had more bytes than this limit, they will not be | ||
142 | * returned and the connection closed. In this case, STATUS_STOP | ||
143 | * will be passed to responseStatus(); | ||
144 | */ | ||
145 | void setBodyLimit(U32 size); | ||
146 | |||
147 | /** | ||
148 | * @brief Set a completion callback for this URLRequest. | ||
149 | * | ||
150 | * The callback is added to this URLRequet's pump when either the | ||
151 | * entire buffer is known or an error like timeout or connection | ||
152 | * refused has happened. In the case of a complete transfer, this | ||
153 | * object builds a response chain such that the callback and the | ||
154 | * next process consumer get to read the output. | ||
155 | * | ||
156 | * This setup is a little fragile since the url request consumer | ||
157 | * might not just read the data - it may do a channel change, | ||
158 | * which invalidates the input to the callback, but it works well | ||
159 | * in practice. | ||
160 | */ | ||
161 | void setCallback(LLURLRequestComplete* callback); | ||
162 | //@} | ||
163 | |||
164 | /** | ||
165 | * @ brief Set certificate authority file used to verify HTTPS certs. | ||
166 | */ | ||
167 | static void setCertificateAuthorityFile(const std::string& file_name); | ||
168 | |||
169 | /** | ||
170 | * @ brief Set certificate authority path used to verify HTTPS certs. | ||
171 | */ | ||
172 | static void setCertificateAuthorityPath(const std::string& path); | ||
173 | |||
174 | /* @name LLIOPipe virtual implementations | ||
175 | */ | ||
176 | public: | ||
177 | /** | ||
178 | * @brief Give this pipe a chance to handle a generated error | ||
179 | */ | ||
180 | virtual EStatus handleError(EStatus status, LLPumpIO* pump); | ||
181 | |||
182 | protected: | ||
183 | /** | ||
184 | * @brief Process the data in buffer | ||
185 | */ | ||
186 | virtual EStatus process_impl( | ||
187 | const LLChannelDescriptors& channels, | ||
188 | buffer_ptr_t& buffer, | ||
189 | bool& eos, | ||
190 | LLSD& context, | ||
191 | LLPumpIO* pump); | ||
192 | //@} | ||
193 | |||
194 | protected: | ||
195 | enum EState | ||
196 | { | ||
197 | STATE_INITIALIZED, | ||
198 | STATE_WAITING_FOR_RESPONSE, | ||
199 | STATE_PROCESSING_RESPONSE, | ||
200 | STATE_HAVE_RESPONSE, | ||
201 | }; | ||
202 | EState mState; | ||
203 | ERequestAction mAction; | ||
204 | LLURLRequestDetail* mDetail; | ||
205 | LLIOPipe::ptr_t mCompletionCallback; | ||
206 | |||
207 | private: | ||
208 | /** | ||
209 | * @brief Initialize the object. Called during construction. | ||
210 | */ | ||
211 | void initialize(); | ||
212 | |||
213 | /** | ||
214 | * @brief Handle action specific url request configuration. | ||
215 | * | ||
216 | * @return Returns true if this is configured. | ||
217 | */ | ||
218 | bool configure(); | ||
219 | |||
220 | /** | ||
221 | * @brief Download callback method. | ||
222 | */ | ||
223 | static size_t downCallback( | ||
224 | void* data, | ||
225 | size_t size, | ||
226 | size_t nmemb, | ||
227 | void* user); | ||
228 | |||
229 | /** | ||
230 | * @brief Upload callback method. | ||
231 | */ | ||
232 | static size_t upCallback( | ||
233 | void* data, | ||
234 | size_t size, | ||
235 | size_t nmemb, | ||
236 | void* user); | ||
237 | |||
238 | /** | ||
239 | * @brief Declaration of unimplemented method to prevent copy | ||
240 | * construction. | ||
241 | */ | ||
242 | LLURLRequest(const LLURLRequest&); | ||
243 | }; | ||
244 | |||
245 | |||
246 | /** | ||
247 | * @class LLContextURLExtractor | ||
248 | * @brief This class unpacks the url out of a agent usher service so | ||
249 | * it can be packed into a LLURLRequest object. | ||
250 | * @see LLIOPipe | ||
251 | * | ||
252 | * This class assumes that the context is a map that contains an entry | ||
253 | * named CONTEXT_DEST_URI_SD_LABEL. | ||
254 | */ | ||
255 | class LLContextURLExtractor : public LLIOPipe | ||
256 | { | ||
257 | public: | ||
258 | LLContextURLExtractor(LLURLRequest* req) : mRequest(req) {} | ||
259 | ~LLContextURLExtractor() {} | ||
260 | |||
261 | protected: | ||
262 | /* @name LLIOPipe virtual implementations | ||
263 | */ | ||
264 | //@{ | ||
265 | /** | ||
266 | * @brief Process the data in buffer | ||
267 | */ | ||
268 | virtual EStatus process_impl( | ||
269 | const LLChannelDescriptors& channels, | ||
270 | buffer_ptr_t& buffer, | ||
271 | bool& eos, | ||
272 | LLSD& context, | ||
273 | LLPumpIO* pump); | ||
274 | //@} | ||
275 | |||
276 | protected: | ||
277 | LLURLRequest* mRequest; | ||
278 | }; | ||
279 | |||
280 | |||
281 | /** | ||
282 | * @class LLURLRequestComplete | ||
283 | * @brief Class which can optionally be used with an LLURLRequest to | ||
284 | * get notification when the url request is complete. | ||
285 | */ | ||
286 | class LLURLRequestComplete : public LLIOPipe | ||
287 | { | ||
288 | public: | ||
289 | |||
290 | virtual void header(const std::string& header, const std::string& value); | ||
291 | ///< Called once for each header received, prior to httpStatus | ||
292 | |||
293 | virtual void httpStatus(U32 status, const std::string& reason); | ||
294 | ///< Always called on request completion, prior to complete | ||
295 | |||
296 | virtual void complete( | ||
297 | const LLChannelDescriptors& channels, | ||
298 | const buffer_ptr_t& buffer); | ||
299 | |||
300 | /** | ||
301 | * @brief This method is called when we got a valid response. | ||
302 | * | ||
303 | * It is up to class implementers to do something useful here. | ||
304 | */ | ||
305 | virtual void response( | ||
306 | const LLChannelDescriptors& channels, | ||
307 | const buffer_ptr_t& buffer); | ||
308 | |||
309 | /** | ||
310 | * @brief This method is called if there was no response. | ||
311 | * | ||
312 | * It is up to class implementers to do something useful here. | ||
313 | */ | ||
314 | virtual void noResponse(); | ||
315 | |||
316 | /** | ||
317 | * @brief This method will be called by the LLURLRequest object. | ||
318 | * | ||
319 | * If this is set to STATUS_OK or STATUS_STOP, then the transfer | ||
320 | * is asssumed to have worked. This will lead to calling response() | ||
321 | * on the next call to process(). Otherwise, this object will call | ||
322 | * noResponse() on the next call to process. | ||
323 | * @param status The status of the URLRequest. | ||
324 | */ | ||
325 | void responseStatus(EStatus status); | ||
326 | |||
327 | // constructor & destructor. | ||
328 | LLURLRequestComplete(); | ||
329 | virtual ~LLURLRequestComplete(); | ||
330 | |||
331 | protected: | ||
332 | /* @name LLIOPipe virtual implementations | ||
333 | */ | ||
334 | //@{ | ||
335 | /** | ||
336 | * @brief Process the data in buffer | ||
337 | */ | ||
338 | virtual EStatus process_impl( | ||
339 | const LLChannelDescriptors& channels, | ||
340 | buffer_ptr_t& buffer, | ||
341 | bool& eos, | ||
342 | LLSD& context, | ||
343 | LLPumpIO* pump); | ||
344 | //@} | ||
345 | |||
346 | // value to note if we actually got the response. This value | ||
347 | // depends on correct useage from the LLURLRequest instance. | ||
348 | EStatus mRequestStatus; | ||
349 | }; | ||
350 | |||
351 | |||
352 | /** | ||
353 | * @class LLURLRequestClientFactory | ||
354 | * @brief Template class to build url request based client chains | ||
355 | * | ||
356 | * This class eases construction of a basic sd rpc client. Here is an | ||
357 | * example of it's use: | ||
358 | * <code> | ||
359 | * class LLUsefulService : public LLService { ... }<br> | ||
360 | * LLService::registerCreator(<br> | ||
361 | * "useful",<br> | ||
362 | * LLService::creator_t(new LLURLRequestClientFactory<LLUsefulService>))<br> | ||
363 | * </code> | ||
364 | * | ||
365 | * This class should work, but I never got around to using/testing it. | ||
366 | * | ||
367 | */ | ||
368 | #if 0 | ||
369 | template<class Client> | ||
370 | class LLURLRequestClientFactory : public LLChainIOFactory | ||
371 | { | ||
372 | public: | ||
373 | LLURLRequestClientFactory(LLURLRequest::ERequestAction action) {} | ||
374 | LLURLRequestClientFactory( | ||
375 | LLURLRequest::ERequestAction action, | ||
376 | const std::string& fixed_url) : | ||
377 | mAction(action), | ||
378 | mURL(fixed_url) | ||
379 | { | ||
380 | } | ||
381 | virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const | ||
382 | { | ||
383 | lldebugs << "LLURLRequestClientFactory::build" << llendl; | ||
384 | LLIOPipe::ptr_t service(new Client); | ||
385 | chain.push_back(service); | ||
386 | LLURLRequest* http(new LLURLRequest(mAction)); | ||
387 | LLIOPipe::ptr_t http_pipe(http); | ||
388 | // *FIX: how do we know the content type? | ||
389 | //http->addHeader("Content-Type: text/llsd"); | ||
390 | if(mURL.empty()) | ||
391 | { | ||
392 | chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http))); | ||
393 | } | ||
394 | else | ||
395 | { | ||
396 | http->setURL(mURL); | ||
397 | } | ||
398 | chain.push_back(http_pipe); | ||
399 | chain.push_back(service); | ||
400 | return true; | ||
401 | } | ||
402 | |||
403 | protected: | ||
404 | LLURLRequest::ERequestAction mAction; | ||
405 | std::string mURL; | ||
406 | }; | ||
407 | #endif | ||
408 | |||
409 | /** | ||
410 | * External constants | ||
411 | */ | ||
412 | extern const std::string CONTEXT_DEST_URI_SD_LABEL; | ||
413 | |||
414 | #endif // LL_LLURLREQUEST_H | ||