PageRenderTime 69ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llmessage/llurlrequest.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 784 lines | 586 code | 92 blank | 106 comment | 61 complexity | 1fcc1a8de3a442043466cd3e5ae3e7fe MD5 | raw file
Possible License(s): LGPL-2.1
  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. * $LicenseInfo:firstyear=2005&license=viewerlgpl$
  8. * Second Life Viewer Source Code
  9. * Copyright (C) 2010, Linden Research, Inc.
  10. *
  11. * This library is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU Lesser General Public
  13. * License as published by the Free Software Foundation;
  14. * version 2.1 of the License only.
  15. *
  16. * This library is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public
  22. * License along with this library; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. *
  25. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  26. * $/LicenseInfo$
  27. */
  28. #include "linden_common.h"
  29. #include "llurlrequest.h"
  30. #include <algorithm>
  31. #include <openssl/x509_vfy.h>
  32. #include <openssl/ssl.h>
  33. #include "llcurl.h"
  34. #include "llioutil.h"
  35. #include "llmemtype.h"
  36. #include "llproxy.h"
  37. #include "llpumpio.h"
  38. #include "llsd.h"
  39. #include "llstring.h"
  40. #include "apr_env.h"
  41. #include "llapr.h"
  42. static const U32 HTTP_STATUS_PIPE_ERROR = 499;
  43. /**
  44. * String constants
  45. */
  46. const std::string CONTEXT_DEST_URI_SD_LABEL("dest_uri");
  47. const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes");
  48. static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user);
  49. /**
  50. * class LLURLRequestDetail
  51. */
  52. class LLURLRequestDetail
  53. {
  54. public:
  55. LLURLRequestDetail();
  56. ~LLURLRequestDetail();
  57. std::string mURL;
  58. LLCurlEasyRequest* mCurlRequest;
  59. LLIOPipe::buffer_ptr_t mResponseBuffer;
  60. LLChannelDescriptors mChannels;
  61. U8* mLastRead;
  62. U32 mBodyLimit;
  63. S32 mByteAccumulator;
  64. bool mIsBodyLimitSet;
  65. LLURLRequest::SSLCertVerifyCallback mSSLVerifyCallback;
  66. };
  67. LLURLRequestDetail::LLURLRequestDetail() :
  68. mCurlRequest(NULL),
  69. mLastRead(NULL),
  70. mBodyLimit(0),
  71. mByteAccumulator(0),
  72. mIsBodyLimitSet(false),
  73. mSSLVerifyCallback(NULL)
  74. {
  75. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  76. mCurlRequest = new LLCurlEasyRequest();
  77. if(!mCurlRequest->isValid()) //failed.
  78. {
  79. delete mCurlRequest ;
  80. mCurlRequest = NULL ;
  81. }
  82. }
  83. LLURLRequestDetail::~LLURLRequestDetail()
  84. {
  85. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  86. delete mCurlRequest;
  87. mLastRead = NULL;
  88. }
  89. void LLURLRequest::setSSLVerifyCallback(SSLCertVerifyCallback callback, void *param)
  90. {
  91. mDetail->mSSLVerifyCallback = callback;
  92. mDetail->mCurlRequest->setSSLCtxCallback(LLURLRequest::_sslCtxCallback, (void *)this);
  93. mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, true);
  94. mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, 2);
  95. }
  96. // _sslCtxFunction
  97. // Callback function called when an SSL Context is created via CURL
  98. // used to configure the context for custom cert validation
  99. CURLcode LLURLRequest::_sslCtxCallback(CURL * curl, void *sslctx, void *param)
  100. {
  101. LLURLRequest *req = (LLURLRequest *)param;
  102. if(req == NULL || req->mDetail->mSSLVerifyCallback == NULL)
  103. {
  104. SSL_CTX_set_cert_verify_callback((SSL_CTX *)sslctx, NULL, NULL);
  105. return CURLE_OK;
  106. }
  107. SSL_CTX * ctx = (SSL_CTX *) sslctx;
  108. // disable any default verification for server certs
  109. SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
  110. // set the verification callback.
  111. SSL_CTX_set_cert_verify_callback(ctx, req->mDetail->mSSLVerifyCallback, (void *)req);
  112. // the calls are void
  113. return CURLE_OK;
  114. }
  115. /**
  116. * class LLURLRequest
  117. */
  118. // static
  119. std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action)
  120. {
  121. static const std::string VERBS[] =
  122. {
  123. "(invalid)",
  124. "HEAD",
  125. "GET",
  126. "PUT",
  127. "POST",
  128. "DELETE",
  129. "MOVE"
  130. };
  131. if(((S32)action <=0) || ((S32)action >= REQUEST_ACTION_COUNT))
  132. {
  133. return VERBS[0];
  134. }
  135. return VERBS[action];
  136. }
  137. LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action) :
  138. mAction(action)
  139. {
  140. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  141. initialize();
  142. }
  143. LLURLRequest::LLURLRequest(
  144. LLURLRequest::ERequestAction action,
  145. const std::string& url) :
  146. mAction(action)
  147. {
  148. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  149. initialize();
  150. setURL(url);
  151. }
  152. LLURLRequest::~LLURLRequest()
  153. {
  154. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  155. delete mDetail;
  156. mDetail = NULL ;
  157. }
  158. void LLURLRequest::setURL(const std::string& url)
  159. {
  160. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  161. mDetail->mURL = url;
  162. }
  163. std::string LLURLRequest::getURL() const
  164. {
  165. return mDetail->mURL;
  166. }
  167. void LLURLRequest::addHeader(const char* header)
  168. {
  169. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  170. mDetail->mCurlRequest->slist_append(header);
  171. }
  172. void LLURLRequest::setBodyLimit(U32 size)
  173. {
  174. mDetail->mBodyLimit = size;
  175. mDetail->mIsBodyLimitSet = true;
  176. }
  177. void LLURLRequest::setCallback(LLURLRequestComplete* callback)
  178. {
  179. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  180. mCompletionCallback = callback;
  181. mDetail->mCurlRequest->setHeaderCallback(&headerCallback, (void*)callback);
  182. }
  183. // Added to mitigate the effect of libcurl looking
  184. // for the ALL_PROXY and http_proxy env variables
  185. // and deciding to insert a Pragma: no-cache
  186. // header! The only usage of this method at the
  187. // time of this writing is in llhttpclient.cpp
  188. // in the request() method, where this method
  189. // is called with use_proxy = FALSE
  190. void LLURLRequest::useProxy(bool use_proxy)
  191. {
  192. static char *env_proxy;
  193. if (use_proxy && (env_proxy == NULL))
  194. {
  195. apr_status_t status;
  196. LLAPRPool pool;
  197. status = apr_env_get(&env_proxy, "ALL_PROXY", pool.getAPRPool());
  198. if (status != APR_SUCCESS)
  199. {
  200. status = apr_env_get(&env_proxy, "http_proxy", pool.getAPRPool());
  201. }
  202. if (status != APR_SUCCESS)
  203. {
  204. use_proxy = FALSE;
  205. }
  206. }
  207. lldebugs << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << (env_proxy ? env_proxy : "(null)") << llendl;
  208. if (env_proxy && use_proxy)
  209. {
  210. mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, env_proxy);
  211. }
  212. else
  213. {
  214. mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, "");
  215. }
  216. }
  217. void LLURLRequest::useProxy(const std::string &proxy)
  218. {
  219. mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, proxy);
  220. }
  221. void LLURLRequest::allowCookies()
  222. {
  223. mDetail->mCurlRequest->setoptString(CURLOPT_COOKIEFILE, "");
  224. }
  225. //virtual
  226. bool LLURLRequest::isValid()
  227. {
  228. return mDetail->mCurlRequest && mDetail->mCurlRequest->isValid();
  229. }
  230. // virtual
  231. LLIOPipe::EStatus LLURLRequest::handleError(
  232. LLIOPipe::EStatus status,
  233. LLPumpIO* pump)
  234. {
  235. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  236. if(!isValid())
  237. {
  238. return STATUS_EXPIRED ;
  239. }
  240. if(mCompletionCallback && pump)
  241. {
  242. LLURLRequestComplete* complete = NULL;
  243. complete = (LLURLRequestComplete*)mCompletionCallback.get();
  244. complete->httpStatus(
  245. HTTP_STATUS_PIPE_ERROR,
  246. LLIOPipe::lookupStatusString(status));
  247. complete->responseStatus(status);
  248. pump->respond(complete);
  249. mCompletionCallback = NULL;
  250. }
  251. return status;
  252. }
  253. static LLFastTimer::DeclareTimer FTM_PROCESS_URL_REQUEST("URL Request");
  254. // virtual
  255. LLIOPipe::EStatus LLURLRequest::process_impl(
  256. const LLChannelDescriptors& channels,
  257. buffer_ptr_t& buffer,
  258. bool& eos,
  259. LLSD& context,
  260. LLPumpIO* pump)
  261. {
  262. LLFastTimer t(FTM_PROCESS_URL_REQUEST);
  263. PUMP_DEBUG;
  264. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  265. //llinfos << "LLURLRequest::process_impl()" << llendl;
  266. if (!buffer) return STATUS_ERROR;
  267. // we're still waiting or prcessing, check how many
  268. // bytes we have accumulated.
  269. const S32 MIN_ACCUMULATION = 100000;
  270. if(pump && (mDetail->mByteAccumulator > MIN_ACCUMULATION))
  271. {
  272. static LLFastTimer::DeclareTimer FTM_URL_ADJUST_TIMEOUT("Adjust Timeout");
  273. LLFastTimer t(FTM_URL_ADJUST_TIMEOUT);
  274. // This is a pretty sloppy calculation, but this
  275. // tries to make the gross assumption that if data
  276. // is coming in at 56kb/s, then this transfer will
  277. // probably succeed. So, if we're accumlated
  278. // 100,000 bytes (MIN_ACCUMULATION) then let's
  279. // give this client another 2s to complete.
  280. const F32 TIMEOUT_ADJUSTMENT = 2.0f;
  281. mDetail->mByteAccumulator = 0;
  282. pump->adjustTimeoutSeconds(TIMEOUT_ADJUSTMENT);
  283. lldebugs << "LLURLRequest adjustTimeoutSeconds for request: " << mDetail->mURL << llendl;
  284. if (mState == STATE_INITIALIZED)
  285. {
  286. llinfos << "LLURLRequest adjustTimeoutSeconds called during upload" << llendl;
  287. }
  288. }
  289. switch(mState)
  290. {
  291. case STATE_INITIALIZED:
  292. {
  293. PUMP_DEBUG;
  294. // We only need to wait for input if we are uploading
  295. // something.
  296. if(((HTTP_PUT == mAction) || (HTTP_POST == mAction)) && !eos)
  297. {
  298. // we're waiting to get all of the information
  299. return STATUS_BREAK;
  300. }
  301. // *FIX: bit of a hack, but it should work. The configure and
  302. // callback method expect this information to be ready.
  303. mDetail->mResponseBuffer = buffer;
  304. mDetail->mChannels = channels;
  305. if(!configure())
  306. {
  307. return STATUS_ERROR;
  308. }
  309. mState = STATE_WAITING_FOR_RESPONSE;
  310. // *FIX: Maybe we should just go to the next state now...
  311. return STATUS_BREAK;
  312. }
  313. case STATE_WAITING_FOR_RESPONSE:
  314. case STATE_PROCESSING_RESPONSE:
  315. {
  316. PUMP_DEBUG;
  317. LLIOPipe::EStatus status = STATUS_BREAK;
  318. static LLFastTimer::DeclareTimer FTM_URL_PERFORM("Perform");
  319. {
  320. LLFastTimer t(FTM_URL_PERFORM);
  321. if(!mDetail->mCurlRequest->wait())
  322. {
  323. return status ;
  324. }
  325. }
  326. while(1)
  327. {
  328. CURLcode result;
  329. static LLFastTimer::DeclareTimer FTM_PROCESS_URL_REQUEST_GET_RESULT("Get Result");
  330. bool newmsg = false;
  331. {
  332. LLFastTimer t(FTM_PROCESS_URL_REQUEST_GET_RESULT);
  333. newmsg = mDetail->mCurlRequest->getResult(&result);
  334. }
  335. if(!newmsg)
  336. {
  337. // keep processing
  338. break;
  339. }
  340. mState = STATE_HAVE_RESPONSE;
  341. context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
  342. context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
  343. lldebugs << this << "Setting context to " << context << llendl;
  344. switch(result)
  345. {
  346. case CURLE_OK:
  347. case CURLE_WRITE_ERROR:
  348. // NB: The error indication means that we stopped the
  349. // writing due the body limit being reached
  350. if(mCompletionCallback && pump)
  351. {
  352. LLURLRequestComplete* complete = NULL;
  353. complete = (LLURLRequestComplete*)
  354. mCompletionCallback.get();
  355. complete->responseStatus(
  356. result == CURLE_OK
  357. ? STATUS_OK : STATUS_STOP);
  358. LLPumpIO::links_t chain;
  359. LLPumpIO::LLLinkInfo link;
  360. link.mPipe = mCompletionCallback;
  361. link.mChannels = LLBufferArray::makeChannelConsumer(
  362. channels);
  363. chain.push_back(link);
  364. static LLFastTimer::DeclareTimer FTM_PROCESS_URL_PUMP_RESPOND("Pump Respond");
  365. {
  366. LLFastTimer t(FTM_PROCESS_URL_PUMP_RESPOND);
  367. pump->respond(chain, buffer, context);
  368. }
  369. mCompletionCallback = NULL;
  370. }
  371. break;
  372. case CURLE_FAILED_INIT:
  373. case CURLE_COULDNT_CONNECT:
  374. status = STATUS_NO_CONNECTION;
  375. break;
  376. default:
  377. llwarns << "URLRequest Error: " << result
  378. << ", "
  379. << LLCurl::strerror(result)
  380. << ", "
  381. << (mDetail->mURL.empty() ? "<EMPTY URL>" : mDetail->mURL)
  382. << llendl;
  383. status = STATUS_ERROR;
  384. break;
  385. }
  386. }
  387. return status;
  388. }
  389. case STATE_HAVE_RESPONSE:
  390. PUMP_DEBUG;
  391. // we already stuffed everything into channel in in the curl
  392. // callback, so we are done.
  393. eos = true;
  394. context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
  395. context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
  396. lldebugs << this << "Setting context to " << context << llendl;
  397. return STATUS_DONE;
  398. default:
  399. PUMP_DEBUG;
  400. context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
  401. context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
  402. lldebugs << this << "Setting context to " << context << llendl;
  403. return STATUS_ERROR;
  404. }
  405. }
  406. void LLURLRequest::initialize()
  407. {
  408. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  409. mState = STATE_INITIALIZED;
  410. mDetail = new LLURLRequestDetail;
  411. if(!isValid())
  412. {
  413. return ;
  414. }
  415. mDetail->mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1);
  416. mDetail->mCurlRequest->setWriteCallback(&downCallback, (void*)this);
  417. mDetail->mCurlRequest->setReadCallback(&upCallback, (void*)this);
  418. mRequestTransferedBytes = 0;
  419. mResponseTransferedBytes = 0;
  420. }
  421. static LLFastTimer::DeclareTimer FTM_URL_REQUEST_CONFIGURE("URL Configure");
  422. bool LLURLRequest::configure()
  423. {
  424. LLFastTimer t(FTM_URL_REQUEST_CONFIGURE);
  425. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  426. bool rv = false;
  427. S32 bytes = mDetail->mResponseBuffer->countAfter(
  428. mDetail->mChannels.in(),
  429. NULL);
  430. switch(mAction)
  431. {
  432. case HTTP_HEAD:
  433. mDetail->mCurlRequest->setopt(CURLOPT_HEADER, 1);
  434. mDetail->mCurlRequest->setopt(CURLOPT_NOBODY, 1);
  435. mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1);
  436. rv = true;
  437. break;
  438. case HTTP_GET:
  439. mDetail->mCurlRequest->setopt(CURLOPT_HTTPGET, 1);
  440. mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1);
  441. // Set Accept-Encoding to allow response compression
  442. mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, "");
  443. rv = true;
  444. break;
  445. case HTTP_PUT:
  446. // Disable the expect http 1.1 extension. POST and PUT default
  447. // to turning this on, and I am not too sure what it means.
  448. addHeader("Expect:");
  449. mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1);
  450. mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes);
  451. rv = true;
  452. break;
  453. case HTTP_POST:
  454. // Disable the expect http 1.1 extension. POST and PUT default
  455. // to turning this on, and I am not too sure what it means.
  456. addHeader("Expect:");
  457. // Disable the content type http header.
  458. // *FIX: what should it be?
  459. addHeader("Content-Type:");
  460. // Set the handle for an http post
  461. mDetail->mCurlRequest->setPost(NULL, bytes);
  462. // Set Accept-Encoding to allow response compression
  463. mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, "");
  464. rv = true;
  465. break;
  466. case HTTP_DELETE:
  467. // Set the handle for an http post
  468. mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "DELETE");
  469. rv = true;
  470. break;
  471. case HTTP_MOVE:
  472. // Set the handle for an http post
  473. mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "MOVE");
  474. // *NOTE: should we check for the Destination header?
  475. rv = true;
  476. break;
  477. default:
  478. llwarns << "Unhandled URLRequest action: " << mAction << llendl;
  479. break;
  480. }
  481. if(rv)
  482. {
  483. mDetail->mCurlRequest->sendRequest(mDetail->mURL);
  484. }
  485. return rv;
  486. }
  487. // static
  488. size_t LLURLRequest::downCallback(
  489. char* data,
  490. size_t size,
  491. size_t nmemb,
  492. void* user)
  493. {
  494. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  495. LLURLRequest* req = (LLURLRequest*)user;
  496. if(STATE_WAITING_FOR_RESPONSE == req->mState)
  497. {
  498. req->mState = STATE_PROCESSING_RESPONSE;
  499. }
  500. U32 bytes = size * nmemb;
  501. if (req->mDetail->mIsBodyLimitSet)
  502. {
  503. if (bytes > req->mDetail->mBodyLimit)
  504. {
  505. bytes = req->mDetail->mBodyLimit;
  506. req->mDetail->mBodyLimit = 0;
  507. }
  508. else
  509. {
  510. req->mDetail->mBodyLimit -= bytes;
  511. }
  512. }
  513. req->mDetail->mResponseBuffer->append(
  514. req->mDetail->mChannels.out(),
  515. (U8*)data,
  516. bytes);
  517. req->mResponseTransferedBytes += bytes;
  518. req->mDetail->mByteAccumulator += bytes;
  519. return bytes;
  520. }
  521. // static
  522. size_t LLURLRequest::upCallback(
  523. char* data,
  524. size_t size,
  525. size_t nmemb,
  526. void* user)
  527. {
  528. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  529. LLURLRequest* req = (LLURLRequest*)user;
  530. S32 bytes = llmin(
  531. (S32)(size * nmemb),
  532. req->mDetail->mResponseBuffer->countAfter(
  533. req->mDetail->mChannels.in(),
  534. req->mDetail->mLastRead));
  535. req->mDetail->mLastRead = req->mDetail->mResponseBuffer->readAfter(
  536. req->mDetail->mChannels.in(),
  537. req->mDetail->mLastRead,
  538. (U8*)data,
  539. bytes);
  540. req->mRequestTransferedBytes += bytes;
  541. return bytes;
  542. }
  543. static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user)
  544. {
  545. const char* header_line = (const char*)data;
  546. size_t header_len = size * nmemb;
  547. LLURLRequestComplete* complete = (LLURLRequestComplete*)user;
  548. if (!complete || !header_line)
  549. {
  550. return header_len;
  551. }
  552. // *TODO: This should be a utility in llstring.h: isascii()
  553. for (size_t i = 0; i < header_len; ++i)
  554. {
  555. if (header_line[i] < 0)
  556. {
  557. return header_len;
  558. }
  559. }
  560. std::string header(header_line, header_len);
  561. // Per HTTP spec the first header line must be the status line.
  562. if (header.substr(0,5) == "HTTP/")
  563. {
  564. std::string::iterator end = header.end();
  565. std::string::iterator pos1 = std::find(header.begin(), end, ' ');
  566. if (pos1 != end) ++pos1;
  567. std::string::iterator pos2 = std::find(pos1, end, ' ');
  568. if (pos2 != end) ++pos2;
  569. std::string::iterator pos3 = std::find(pos2, end, '\r');
  570. std::string version(header.begin(), pos1);
  571. std::string status(pos1, pos2);
  572. std::string reason(pos2, pos3);
  573. S32 status_code = atoi(status.c_str());
  574. if (status_code > 0)
  575. {
  576. complete->httpStatus((U32)status_code, reason);
  577. return header_len;
  578. }
  579. }
  580. std::string::iterator sep = std::find(header.begin(),header.end(),':');
  581. if (sep != header.end())
  582. {
  583. std::string key(header.begin(), sep);
  584. std::string value(sep + 1, header.end());
  585. key = utf8str_tolower(utf8str_trim(key));
  586. value = utf8str_trim(value);
  587. complete->header(key, value);
  588. }
  589. else
  590. {
  591. LLStringUtil::trim(header);
  592. if (!header.empty())
  593. {
  594. llwarns << "Unable to parse header: " << header << llendl;
  595. }
  596. }
  597. return header_len;
  598. }
  599. static LLFastTimer::DeclareTimer FTM_PROCESS_URL_EXTRACTOR("URL Extractor");
  600. /**
  601. * LLContextURLExtractor
  602. */
  603. // virtual
  604. LLIOPipe::EStatus LLContextURLExtractor::process_impl(
  605. const LLChannelDescriptors& channels,
  606. buffer_ptr_t& buffer,
  607. bool& eos,
  608. LLSD& context,
  609. LLPumpIO* pump)
  610. {
  611. LLFastTimer t(FTM_PROCESS_URL_EXTRACTOR);
  612. PUMP_DEBUG;
  613. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  614. // The destination host is in the context.
  615. if(context.isUndefined() || !mRequest)
  616. {
  617. return STATUS_PRECONDITION_NOT_MET;
  618. }
  619. // copy in to out, since this just extract the URL and does not
  620. // actually change the data.
  621. LLChangeChannel change(channels.in(), channels.out());
  622. std::for_each(buffer->beginSegment(), buffer->endSegment(), change);
  623. // find the context url
  624. if(context.has(CONTEXT_DEST_URI_SD_LABEL))
  625. {
  626. mRequest->setURL(context[CONTEXT_DEST_URI_SD_LABEL].asString());
  627. return STATUS_DONE;
  628. }
  629. return STATUS_ERROR;
  630. }
  631. /**
  632. * LLURLRequestComplete
  633. */
  634. LLURLRequestComplete::LLURLRequestComplete() :
  635. mRequestStatus(LLIOPipe::STATUS_ERROR)
  636. {
  637. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  638. }
  639. // virtual
  640. LLURLRequestComplete::~LLURLRequestComplete()
  641. {
  642. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  643. }
  644. //virtual
  645. void LLURLRequestComplete::header(const std::string& header, const std::string& value)
  646. {
  647. }
  648. //virtual
  649. void LLURLRequestComplete::complete(const LLChannelDescriptors& channels,
  650. const buffer_ptr_t& buffer)
  651. {
  652. if(STATUS_OK == mRequestStatus)
  653. {
  654. response(channels, buffer);
  655. }
  656. else
  657. {
  658. noResponse();
  659. }
  660. }
  661. //virtual
  662. void LLURLRequestComplete::response(const LLChannelDescriptors& channels,
  663. const buffer_ptr_t& buffer)
  664. {
  665. llwarns << "LLURLRequestComplete::response default implementation called"
  666. << llendl;
  667. }
  668. //virtual
  669. void LLURLRequestComplete::noResponse()
  670. {
  671. llwarns << "LLURLRequestComplete::noResponse default implementation called"
  672. << llendl;
  673. }
  674. void LLURLRequestComplete::responseStatus(LLIOPipe::EStatus status)
  675. {
  676. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  677. mRequestStatus = status;
  678. }
  679. static LLFastTimer::DeclareTimer FTM_PROCESS_URL_COMPLETE("URL Complete");
  680. // virtual
  681. LLIOPipe::EStatus LLURLRequestComplete::process_impl(
  682. const LLChannelDescriptors& channels,
  683. buffer_ptr_t& buffer,
  684. bool& eos,
  685. LLSD& context,
  686. LLPumpIO* pump)
  687. {
  688. LLFastTimer t(FTM_PROCESS_URL_COMPLETE);
  689. PUMP_DEBUG;
  690. complete(channels, buffer);
  691. return STATUS_OK;
  692. }