diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llmessage/llurlrequest.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llmessage/llurlrequest.cpp')
-rw-r--r-- | linden/indra/llmessage/llurlrequest.cpp | 669 |
1 files changed, 669 insertions, 0 deletions
diff --git a/linden/indra/llmessage/llurlrequest.cpp b/linden/indra/llmessage/llurlrequest.cpp new file mode 100644 index 0000000..c0d8d27 --- /dev/null +++ b/linden/indra/llmessage/llurlrequest.cpp | |||
@@ -0,0 +1,669 @@ | |||
1 | /** | ||
2 | * @file llurlrequest.cpp | ||
3 | * @author Phoenix | ||
4 | * @date 2005-04-28 | ||
5 | * @brief Implementation of the URLRequest class and related classes. | ||
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 | #include "linden_common.h" | ||
31 | #include "llurlrequest.h" | ||
32 | |||
33 | #include <curl/curl.h> | ||
34 | #include <algorithm> | ||
35 | |||
36 | #include "llioutil.h" | ||
37 | #include "llmemtype.h" | ||
38 | #include "llpumpio.h" | ||
39 | #include "llsd.h" | ||
40 | #include "llstring.h" | ||
41 | |||
42 | static const U32 HTTP_STATUS_PIPE_ERROR = 499; | ||
43 | |||
44 | /** | ||
45 | * String constants | ||
46 | */ | ||
47 | const std::string CONTEXT_DEST_URI_SD_LABEL("dest_uri"); | ||
48 | |||
49 | |||
50 | static | ||
51 | size_t headerCallback(void* data, size_t size, size_t nmemb, void* user); | ||
52 | |||
53 | /** | ||
54 | * class LLURLRequestDetail | ||
55 | */ | ||
56 | class LLURLRequestDetail | ||
57 | { | ||
58 | public: | ||
59 | LLURLRequestDetail(); | ||
60 | ~LLURLRequestDetail(); | ||
61 | CURLM* mCurlMulti; | ||
62 | CURL* mCurl; | ||
63 | struct curl_slist* mHeaders; | ||
64 | char* mURL; | ||
65 | char mCurlErrorBuf[CURL_ERROR_SIZE + 1]; /* Flawfinder: ignore */ | ||
66 | bool mNeedToRemoveEasyHandle; | ||
67 | LLBufferArray* mResponseBuffer; | ||
68 | LLChannelDescriptors mChannels; | ||
69 | U8* mLastRead; | ||
70 | U32 mBodyLimit; | ||
71 | bool mIsBodyLimitSet; | ||
72 | }; | ||
73 | |||
74 | LLURLRequestDetail::LLURLRequestDetail() : | ||
75 | mCurlMulti(NULL), | ||
76 | mCurl(NULL), | ||
77 | mHeaders(NULL), | ||
78 | mURL(NULL), | ||
79 | mNeedToRemoveEasyHandle(false), | ||
80 | mResponseBuffer(NULL), | ||
81 | mLastRead(NULL), | ||
82 | mBodyLimit(0), | ||
83 | mIsBodyLimitSet(false) | ||
84 | |||
85 | { | ||
86 | LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); | ||
87 | mCurlErrorBuf[0] = '\0'; | ||
88 | } | ||
89 | |||
90 | LLURLRequestDetail::~LLURLRequestDetail() | ||
91 | { | ||
92 | LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); | ||
93 | if(mCurl) | ||
94 | { | ||
95 | if(mNeedToRemoveEasyHandle && mCurlMulti) | ||
96 | { | ||
97 | curl_multi_remove_handle(mCurlMulti, mCurl); | ||
98 | mNeedToRemoveEasyHandle = false; | ||
99 | } | ||
100 | curl_easy_cleanup(mCurl); | ||
101 | mCurl = NULL; | ||
102 | } | ||
103 | if(mCurlMulti) | ||
104 | { | ||
105 | curl_multi_cleanup(mCurlMulti); | ||
106 | mCurlMulti = NULL; | ||
107 | } | ||
108 | if(mHeaders) | ||
109 | { | ||
110 | curl_slist_free_all(mHeaders); | ||
111 | mHeaders = NULL; | ||
112 | } | ||
113 | delete[] mURL; | ||
114 | mURL = NULL; | ||
115 | mResponseBuffer = NULL; | ||
116 | mLastRead = NULL; | ||
117 | } | ||
118 | |||
119 | |||
120 | /** | ||
121 | * class LLURLRequest | ||
122 | */ | ||
123 | |||
124 | static std::string sCAFile(""); | ||
125 | static std::string sCAPath(""); | ||
126 | |||
127 | LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action) : | ||
128 | mAction(action) | ||
129 | { | ||
130 | LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); | ||
131 | initialize(); | ||
132 | } | ||
133 | |||
134 | LLURLRequest::LLURLRequest( | ||
135 | LLURLRequest::ERequestAction action, | ||
136 | const std::string& url) : | ||
137 | mAction(action) | ||
138 | { | ||
139 | LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); | ||
140 | initialize(); | ||
141 | setURL(url); | ||
142 | } | ||
143 | |||
144 | LLURLRequest::~LLURLRequest() | ||
145 | { | ||
146 | LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); | ||
147 | delete mDetail; | ||
148 | } | ||
149 | |||
150 | void LLURLRequest::setURL(const std::string& url) | ||
151 | { | ||
152 | LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); | ||
153 | if(mDetail->mURL) | ||
154 | { | ||
155 | // *NOTE: if any calls to set the url have been made to curl, | ||
156 | // this will probably lead to a crash. | ||
157 | delete[] mDetail->mURL; | ||
158 | mDetail->mURL = NULL; | ||
159 | } | ||
160 | if(!url.empty()) | ||
161 | { | ||
162 | mDetail->mURL = new char[url.size() + 1]; | ||
163 | url.copy(mDetail->mURL, url.size()); | ||
164 | mDetail->mURL[url.size()] = '\0'; | ||
165 | } | ||
166 | } | ||
167 | |||
168 | void LLURLRequest::addHeader(const char* header) | ||
169 | { | ||
170 | LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); | ||
171 | mDetail->mHeaders = curl_slist_append(mDetail->mHeaders, header); | ||
172 | } | ||
173 | |||
174 | void LLURLRequest::requestEncoding(const char* encoding) | ||
175 | { | ||
176 | LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); | ||
177 | curl_easy_setopt(mDetail->mCurl, CURLOPT_ENCODING, encoding); | ||
178 | } | ||
179 | |||
180 | void LLURLRequest::setBodyLimit(U32 size) | ||
181 | { | ||
182 | mDetail->mBodyLimit = size; | ||
183 | mDetail->mIsBodyLimitSet = true; | ||
184 | } | ||
185 | |||
186 | void LLURLRequest::checkRootCertificate(bool check, const char* caBundle) | ||
187 | { | ||
188 | curl_easy_setopt(mDetail->mCurl, CURLOPT_SSL_VERIFYPEER, (check? TRUE : FALSE)); | ||
189 | if (caBundle) | ||
190 | { | ||
191 | curl_easy_setopt(mDetail->mCurl, CURLOPT_CAINFO, caBundle); | ||
192 | } | ||
193 | } | ||
194 | |||
195 | void LLURLRequest::setCallback(LLURLRequestComplete* callback) | ||
196 | { | ||
197 | LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); | ||
198 | mCompletionCallback = callback; | ||
199 | |||
200 | curl_easy_setopt(mDetail->mCurl, CURLOPT_HEADERFUNCTION, &headerCallback); | ||
201 | curl_easy_setopt(mDetail->mCurl, CURLOPT_WRITEHEADER, callback); | ||
202 | } | ||
203 | |||
204 | // virtual | ||
205 | LLIOPipe::EStatus LLURLRequest::handleError( | ||
206 | LLIOPipe::EStatus status, | ||
207 | LLPumpIO* pump) | ||
208 | { | ||
209 | LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); | ||
210 | if(mCompletionCallback && pump) | ||
211 | { | ||
212 | LLURLRequestComplete* complete = NULL; | ||
213 | complete = (LLURLRequestComplete*)mCompletionCallback.get(); | ||
214 | complete->httpStatus( | ||
215 | HTTP_STATUS_PIPE_ERROR, | ||
216 | LLIOPipe::lookupStatusString(status)); | ||
217 | complete->responseStatus(status); | ||
218 | pump->respond(complete); | ||
219 | mCompletionCallback = NULL; | ||
220 | } | ||
221 | return status; | ||
222 | } | ||
223 | |||
224 | // virtual | ||
225 | LLIOPipe::EStatus LLURLRequest::process_impl( | ||
226 | const LLChannelDescriptors& channels, | ||
227 | buffer_ptr_t& buffer, | ||
228 | bool& eos, | ||
229 | LLSD& context, | ||
230 | LLPumpIO* pump) | ||
231 | { | ||
232 | PUMP_DEBUG; | ||
233 | LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); | ||
234 | //llinfos << "LLURLRequest::process_impl()" << llendl; | ||
235 | if(!buffer) return STATUS_ERROR; | ||
236 | switch(mState) | ||
237 | { | ||
238 | case STATE_INITIALIZED: | ||
239 | { | ||
240 | PUMP_DEBUG; | ||
241 | // We only need to wait for input if we are uploading | ||
242 | // something. | ||
243 | if(((HTTP_PUT == mAction) || (HTTP_POST == mAction)) && !eos) | ||
244 | { | ||
245 | // we're waiting to get all of the information | ||
246 | return STATUS_BREAK; | ||
247 | } | ||
248 | |||
249 | // *FIX: bit of a hack, but it should work. The configure and | ||
250 | // callback method expect this information to be ready. | ||
251 | mDetail->mResponseBuffer = buffer.get(); | ||
252 | mDetail->mChannels = channels; | ||
253 | if(!configure()) | ||
254 | { | ||
255 | return STATUS_ERROR; | ||
256 | } | ||
257 | mState = STATE_WAITING_FOR_RESPONSE; | ||
258 | |||
259 | // *FIX: Maybe we should just go to the next state now... | ||
260 | return STATUS_BREAK; | ||
261 | } | ||
262 | case STATE_WAITING_FOR_RESPONSE: | ||
263 | case STATE_PROCESSING_RESPONSE: | ||
264 | { | ||
265 | PUMP_DEBUG; | ||
266 | const S32 MAX_CALLS = 5; | ||
267 | S32 count = MAX_CALLS; | ||
268 | CURLMcode code; | ||
269 | LLIOPipe::EStatus status = STATUS_BREAK; | ||
270 | S32 queue; | ||
271 | do | ||
272 | { | ||
273 | code = curl_multi_perform(mDetail->mCurlMulti, &queue); | ||
274 | }while((CURLM_CALL_MULTI_PERFORM == code) && (queue > 0) && count--); | ||
275 | CURLMsg* curl_msg; | ||
276 | do | ||
277 | { | ||
278 | curl_msg = curl_multi_info_read(mDetail->mCurlMulti, &queue); | ||
279 | if(curl_msg && (curl_msg->msg == CURLMSG_DONE)) | ||
280 | { | ||
281 | mState = STATE_HAVE_RESPONSE; | ||
282 | |||
283 | CURLcode result = curl_msg->data.result; | ||
284 | switch(result) | ||
285 | { | ||
286 | case CURLE_OK: | ||
287 | case CURLE_WRITE_ERROR: | ||
288 | // NB: The error indication means that we stopped the | ||
289 | // writing due the body limit being reached | ||
290 | if(mCompletionCallback && pump) | ||
291 | { | ||
292 | LLURLRequestComplete* complete = NULL; | ||
293 | complete = (LLURLRequestComplete*) | ||
294 | mCompletionCallback.get(); | ||
295 | complete->responseStatus( | ||
296 | result == CURLE_OK | ||
297 | ? STATUS_OK : STATUS_STOP); | ||
298 | LLPumpIO::links_t chain; | ||
299 | LLPumpIO::LLLinkInfo link; | ||
300 | link.mPipe = mCompletionCallback; | ||
301 | link.mChannels = LLBufferArray::makeChannelConsumer( | ||
302 | channels); | ||
303 | chain.push_back(link); | ||
304 | pump->respond(chain, buffer, context); | ||
305 | mCompletionCallback = NULL; | ||
306 | } | ||
307 | break; | ||
308 | case CURLE_COULDNT_CONNECT: | ||
309 | status = STATUS_NO_CONNECTION; | ||
310 | break; | ||
311 | default: | ||
312 | llwarns << "URLRequest Error: " << curl_msg->data.result | ||
313 | << ", " | ||
314 | #if LL_DARWIN | ||
315 | // curl_easy_strerror was added in libcurl 7.12.0. Unfortunately, the version in the Mac OS X 10.3.9 SDK is 7.10.2... | ||
316 | // There's a problem with the custom curl headers in our build that keeps me from #ifdefing this on the libcurl version number | ||
317 | // (the correct check would be #if LIBCURL_VERSION_NUM >= 0x070c00). We'll fix the header problem soon, but for now | ||
318 | // just punt and print the numeric error code on the Mac. | ||
319 | << curl_msg->data.result | ||
320 | #else // LL_DARWIN | ||
321 | << curl_easy_strerror(curl_msg->data.result) | ||
322 | #endif // LL_DARWIN | ||
323 | << ", " | ||
324 | << (mDetail->mURL ? mDetail->mURL : "<EMPTY URL>") | ||
325 | << llendl; | ||
326 | status = STATUS_ERROR; | ||
327 | break; | ||
328 | } | ||
329 | curl_multi_remove_handle(mDetail->mCurlMulti, mDetail->mCurl); | ||
330 | mDetail->mNeedToRemoveEasyHandle = false; | ||
331 | } | ||
332 | }while(curl_msg && (queue > 0)); | ||
333 | return status; | ||
334 | } | ||
335 | case STATE_HAVE_RESPONSE: | ||
336 | PUMP_DEBUG; | ||
337 | // we already stuffed everything into channel in in the curl | ||
338 | // callback, so we are done. | ||
339 | eos = true; | ||
340 | return STATUS_DONE; | ||
341 | |||
342 | default: | ||
343 | PUMP_DEBUG; | ||
344 | return STATUS_ERROR; | ||
345 | } | ||
346 | } | ||
347 | |||
348 | void LLURLRequest::initialize() | ||
349 | { | ||
350 | LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); | ||
351 | mState = STATE_INITIALIZED; | ||
352 | mDetail = new LLURLRequestDetail; | ||
353 | mDetail->mCurl = curl_easy_init(); | ||
354 | mDetail->mCurlMulti = curl_multi_init(); | ||
355 | curl_easy_setopt(mDetail->mCurl, CURLOPT_NOSIGNAL, 1); | ||
356 | curl_easy_setopt(mDetail->mCurl, CURLOPT_WRITEFUNCTION, &downCallback); | ||
357 | curl_easy_setopt(mDetail->mCurl, CURLOPT_WRITEDATA, this); | ||
358 | curl_easy_setopt(mDetail->mCurl, CURLOPT_READFUNCTION, &upCallback); | ||
359 | curl_easy_setopt(mDetail->mCurl, CURLOPT_READDATA, this); | ||
360 | curl_easy_setopt( | ||
361 | mDetail->mCurl, | ||
362 | CURLOPT_ERRORBUFFER, | ||
363 | mDetail->mCurlErrorBuf); | ||
364 | |||
365 | if(sCAPath != std::string("")) | ||
366 | { | ||
367 | curl_easy_setopt(mDetail->mCurl, CURLOPT_CAPATH, sCAPath.c_str()); | ||
368 | } | ||
369 | if(sCAFile != std::string("")) | ||
370 | { | ||
371 | curl_easy_setopt(mDetail->mCurl, CURLOPT_CAINFO, sCAFile.c_str()); | ||
372 | } | ||
373 | } | ||
374 | |||
375 | bool LLURLRequest::configure() | ||
376 | { | ||
377 | LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); | ||
378 | bool rv = false; | ||
379 | S32 bytes = mDetail->mResponseBuffer->countAfter( | ||
380 | mDetail->mChannels.in(), | ||
381 | NULL); | ||
382 | switch(mAction) | ||
383 | { | ||
384 | case HTTP_GET: | ||
385 | curl_easy_setopt(mDetail->mCurl, CURLOPT_HTTPGET, 1); | ||
386 | curl_easy_setopt(mDetail->mCurl, CURLOPT_FOLLOWLOCATION, 1); | ||
387 | rv = true; | ||
388 | break; | ||
389 | |||
390 | case HTTP_PUT: | ||
391 | // Disable the expect http 1.1 extension. POST and PUT default | ||
392 | // to turning this on, and I am not too sure what it means. | ||
393 | addHeader("Expect:"); | ||
394 | |||
395 | curl_easy_setopt(mDetail->mCurl, CURLOPT_UPLOAD, 1); | ||
396 | curl_easy_setopt(mDetail->mCurl, CURLOPT_INFILESIZE, bytes); | ||
397 | rv = true; | ||
398 | break; | ||
399 | |||
400 | case HTTP_POST: | ||
401 | // Disable the expect http 1.1 extension. POST and PUT default | ||
402 | // to turning this on, and I am not too sure what it means. | ||
403 | addHeader("Expect:"); | ||
404 | |||
405 | // Disable the content type http header. | ||
406 | // *FIX: what should it be? | ||
407 | addHeader("Content-Type:"); | ||
408 | |||
409 | // Set the handle for an http post | ||
410 | curl_easy_setopt(mDetail->mCurl, CURLOPT_POST, 1); | ||
411 | curl_easy_setopt(mDetail->mCurl, CURLOPT_POSTFIELDS, NULL); | ||
412 | curl_easy_setopt(mDetail->mCurl, CURLOPT_POSTFIELDSIZE, bytes); | ||
413 | rv = true; | ||
414 | break; | ||
415 | |||
416 | case HTTP_DELETE: | ||
417 | // Set the handle for an http post | ||
418 | curl_easy_setopt(mDetail->mCurl, CURLOPT_CUSTOMREQUEST, "DELETE"); | ||
419 | rv = true; | ||
420 | break; | ||
421 | |||
422 | default: | ||
423 | llwarns << "Unhandled URLRequest action: " << mAction << llendl; | ||
424 | break; | ||
425 | } | ||
426 | if(rv) | ||
427 | { | ||
428 | if(mDetail->mHeaders) | ||
429 | { | ||
430 | curl_easy_setopt( | ||
431 | mDetail->mCurl, | ||
432 | CURLOPT_HTTPHEADER, | ||
433 | mDetail->mHeaders); | ||
434 | } | ||
435 | curl_easy_setopt(mDetail->mCurl, CURLOPT_URL, mDetail->mURL); | ||
436 | curl_multi_add_handle(mDetail->mCurlMulti, mDetail->mCurl); | ||
437 | mDetail->mNeedToRemoveEasyHandle = true; | ||
438 | } | ||
439 | return rv; | ||
440 | } | ||
441 | |||
442 | // static | ||
443 | size_t LLURLRequest::downCallback( | ||
444 | void* data, | ||
445 | size_t size, | ||
446 | size_t nmemb, | ||
447 | void* user) | ||
448 | { | ||
449 | LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); | ||
450 | LLURLRequest* req = (LLURLRequest*)user; | ||
451 | if(STATE_WAITING_FOR_RESPONSE == req->mState) | ||
452 | { | ||
453 | req->mState = STATE_PROCESSING_RESPONSE; | ||
454 | } | ||
455 | U32 bytes = size * nmemb; | ||
456 | if (req->mDetail->mIsBodyLimitSet) | ||
457 | { | ||
458 | if (bytes > req->mDetail->mBodyLimit) | ||
459 | { | ||
460 | bytes = req->mDetail->mBodyLimit; | ||
461 | req->mDetail->mBodyLimit = 0; | ||
462 | } | ||
463 | else | ||
464 | { | ||
465 | req->mDetail->mBodyLimit -= bytes; | ||
466 | } | ||
467 | } | ||
468 | |||
469 | req->mDetail->mResponseBuffer->append( | ||
470 | req->mDetail->mChannels.out(), | ||
471 | (U8*)data, | ||
472 | bytes); | ||
473 | return bytes; | ||
474 | } | ||
475 | |||
476 | // static | ||
477 | size_t LLURLRequest::upCallback( | ||
478 | void* data, | ||
479 | size_t size, | ||
480 | size_t nmemb, | ||
481 | void* user) | ||
482 | { | ||
483 | LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); | ||
484 | LLURLRequest* req = (LLURLRequest*)user; | ||
485 | S32 bytes = llmin( | ||
486 | (S32)(size * nmemb), | ||
487 | req->mDetail->mResponseBuffer->countAfter( | ||
488 | req->mDetail->mChannels.in(), | ||
489 | req->mDetail->mLastRead)); | ||
490 | req->mDetail->mLastRead = req->mDetail->mResponseBuffer->readAfter( | ||
491 | req->mDetail->mChannels.in(), | ||
492 | req->mDetail->mLastRead, | ||
493 | (U8*)data, | ||
494 | bytes); | ||
495 | return bytes; | ||
496 | } | ||
497 | |||
498 | static | ||
499 | size_t headerCallback(void* data, size_t size, size_t nmemb, void* user) | ||
500 | { | ||
501 | const char* headerLine = (const char*)data; | ||
502 | size_t headerLen = size * nmemb; | ||
503 | LLURLRequestComplete* complete = (LLURLRequestComplete*)user; | ||
504 | |||
505 | // *TODO: This should be a utility in llstring.h: isascii() | ||
506 | for (size_t i = 0; i < headerLen; ++i) | ||
507 | { | ||
508 | if (headerLine[i] < 0) | ||
509 | { | ||
510 | return headerLen; | ||
511 | } | ||
512 | } | ||
513 | |||
514 | size_t sep; | ||
515 | for (sep = 0; sep < headerLen && headerLine[sep] != ':'; ++sep) { } | ||
516 | |||
517 | if (sep < headerLen && complete) | ||
518 | { | ||
519 | std::string key(headerLine, sep); | ||
520 | std::string value(headerLine + sep + 1, headerLen - sep - 1); | ||
521 | |||
522 | key = utf8str_tolower(utf8str_trim(key)); | ||
523 | value = utf8str_trim(value); | ||
524 | |||
525 | complete->header(key, value); | ||
526 | } | ||
527 | else | ||
528 | { | ||
529 | std::string s(headerLine, headerLen); | ||
530 | |||
531 | std::string::iterator end = s.end(); | ||
532 | std::string::iterator pos1 = std::find(s.begin(), end, ' '); | ||
533 | if (pos1 != end) ++pos1; | ||
534 | std::string::iterator pos2 = std::find(pos1, end, ' '); | ||
535 | if (pos2 != end) ++pos2; | ||
536 | std::string::iterator pos3 = std::find(pos2, end, '\r'); | ||
537 | |||
538 | std::string version(s.begin(), pos1); | ||
539 | std::string status(pos1, pos2); | ||
540 | std::string reason(pos2, pos3); | ||
541 | |||
542 | int statusCode = atoi(status.c_str()); | ||
543 | if (statusCode > 0) | ||
544 | { | ||
545 | complete->httpStatus((U32)statusCode, reason); | ||
546 | } | ||
547 | } | ||
548 | |||
549 | return headerLen; | ||
550 | } | ||
551 | |||
552 | //static | ||
553 | void LLURLRequest::setCertificateAuthorityFile(const std::string& file_name) | ||
554 | { | ||
555 | sCAFile = file_name; | ||
556 | } | ||
557 | |||
558 | //static | ||
559 | void LLURLRequest::setCertificateAuthorityPath(const std::string& path) | ||
560 | { | ||
561 | sCAPath = path; | ||
562 | } | ||
563 | |||
564 | /** | ||
565 | * LLContextURLExtractor | ||
566 | */ | ||
567 | // virtual | ||
568 | LLIOPipe::EStatus LLContextURLExtractor::process_impl( | ||
569 | const LLChannelDescriptors& channels, | ||
570 | buffer_ptr_t& buffer, | ||
571 | bool& eos, | ||
572 | LLSD& context, | ||
573 | LLPumpIO* pump) | ||
574 | { | ||
575 | PUMP_DEBUG; | ||
576 | LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); | ||
577 | // The destination host is in the context. | ||
578 | if(context.isUndefined() || !mRequest) | ||
579 | { | ||
580 | return STATUS_PRECONDITION_NOT_MET; | ||
581 | } | ||
582 | |||
583 | // copy in to out, since this just extract the URL and does not | ||
584 | // actually change the data. | ||
585 | LLChangeChannel change(channels.in(), channels.out()); | ||
586 | std::for_each(buffer->beginSegment(), buffer->endSegment(), change); | ||
587 | |||
588 | // find the context url | ||
589 | if(context.has(CONTEXT_DEST_URI_SD_LABEL)) | ||
590 | { | ||
591 | mRequest->setURL(context[CONTEXT_DEST_URI_SD_LABEL]); | ||
592 | return STATUS_DONE; | ||
593 | } | ||
594 | return STATUS_ERROR; | ||
595 | } | ||
596 | |||
597 | |||
598 | /** | ||
599 | * LLURLRequestComplete | ||
600 | */ | ||
601 | LLURLRequestComplete::LLURLRequestComplete() : | ||
602 | mRequestStatus(LLIOPipe::STATUS_ERROR) | ||
603 | { | ||
604 | LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); | ||
605 | } | ||
606 | |||
607 | // virtual | ||
608 | LLURLRequestComplete::~LLURLRequestComplete() | ||
609 | { | ||
610 | LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); | ||
611 | } | ||
612 | |||
613 | //virtual | ||
614 | void LLURLRequestComplete::header(const std::string& header, const std::string& value) | ||
615 | { | ||
616 | } | ||
617 | |||
618 | //virtual | ||
619 | void LLURLRequestComplete::httpStatus(U32 status, const std::string& reason) | ||
620 | { | ||
621 | } | ||
622 | |||
623 | //virtual | ||
624 | void LLURLRequestComplete::complete(const LLChannelDescriptors& channels, | ||
625 | const buffer_ptr_t& buffer) | ||
626 | { | ||
627 | if(STATUS_OK == mRequestStatus) | ||
628 | { | ||
629 | response(channels, buffer); | ||
630 | } | ||
631 | else | ||
632 | { | ||
633 | noResponse(); | ||
634 | } | ||
635 | } | ||
636 | |||
637 | //virtual | ||
638 | void LLURLRequestComplete::response(const LLChannelDescriptors& channels, | ||
639 | const buffer_ptr_t& buffer) | ||
640 | { | ||
641 | llwarns << "LLURLRequestComplete::response default implementation called" | ||
642 | << llendl; | ||
643 | } | ||
644 | |||
645 | //virtual | ||
646 | void LLURLRequestComplete::noResponse() | ||
647 | { | ||
648 | llwarns << "LLURLRequestComplete::noResponse default implementation called" | ||
649 | << llendl; | ||
650 | } | ||
651 | |||
652 | void LLURLRequestComplete::responseStatus(LLIOPipe::EStatus status) | ||
653 | { | ||
654 | LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); | ||
655 | mRequestStatus = status; | ||
656 | } | ||
657 | |||
658 | // virtual | ||
659 | LLIOPipe::EStatus LLURLRequestComplete::process_impl( | ||
660 | const LLChannelDescriptors& channels, | ||
661 | buffer_ptr_t& buffer, | ||
662 | bool& eos, | ||
663 | LLSD& context, | ||
664 | LLPumpIO* pump) | ||
665 | { | ||
666 | PUMP_DEBUG; | ||
667 | complete(channels, buffer); | ||
668 | return STATUS_OK; | ||
669 | } | ||