llurlrequest.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:17k
源码类别:

游戏引擎

开发平台:

C++ Builder

  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=viewergpl$
  8.  * 
  9.  * Copyright (c) 2005-2010, Linden Research, Inc.
  10.  * 
  11.  * Second Life Viewer Source Code
  12.  * The source code in this file ("Source Code") is provided by Linden Lab
  13.  * to you under the terms of the GNU General Public License, version 2.0
  14.  * ("GPL"), unless you have obtained a separate licensing agreement
  15.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  16.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  17.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  18.  * 
  19.  * There are special exceptions to the terms and conditions of the GPL as
  20.  * it is applied to this Source Code. View the full text of the exception
  21.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  22.  * online at
  23.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  24.  * 
  25.  * By copying, modifying or distributing this software, you acknowledge
  26.  * that you have read and understood your obligations described above,
  27.  * and agree to abide by those obligations.
  28.  * 
  29.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  30.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  31.  * COMPLETENESS OR PERFORMANCE.
  32.  * $/LicenseInfo$
  33.  */
  34. #include "linden_common.h"
  35. #include "llurlrequest.h"
  36. #include <algorithm>
  37. #include "llcurl.h"
  38. #include "llioutil.h"
  39. #include "llmemtype.h"
  40. #include "llpumpio.h"
  41. #include "llsd.h"
  42. #include "llstring.h"
  43. #include "apr_env.h"
  44. #include "llapr.h"
  45. static const U32 HTTP_STATUS_PIPE_ERROR = 499;
  46. /**
  47.  * String constants
  48.  */
  49. const std::string CONTEXT_DEST_URI_SD_LABEL("dest_uri");
  50. const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes");
  51. static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user);
  52. /**
  53.  * class LLURLRequestDetail
  54.  */
  55. class LLURLRequestDetail
  56. {
  57. public:
  58. LLURLRequestDetail();
  59. ~LLURLRequestDetail();
  60. std::string mURL;
  61. LLCurlEasyRequest* mCurlRequest;
  62. LLBufferArray* mResponseBuffer;
  63. LLChannelDescriptors mChannels;
  64. U8* mLastRead;
  65. U32 mBodyLimit;
  66. S32 mByteAccumulator;
  67. bool mIsBodyLimitSet;
  68. };
  69. LLURLRequestDetail::LLURLRequestDetail() :
  70. mCurlRequest(NULL),
  71. mResponseBuffer(NULL),
  72. mLastRead(NULL),
  73. mBodyLimit(0),
  74. mByteAccumulator(0),
  75. mIsBodyLimitSet(false)
  76. {
  77. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  78. mCurlRequest = new LLCurlEasyRequest();
  79. }
  80. LLURLRequestDetail::~LLURLRequestDetail()
  81. {
  82. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  83. delete mCurlRequest;
  84. mResponseBuffer = NULL;
  85. mLastRead = NULL;
  86. }
  87. /**
  88.  * class LLURLRequest
  89.  */
  90. // static
  91. std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action)
  92. {
  93. static const std::string VERBS[] =
  94. {
  95. "(invalid)",
  96. "HEAD",
  97. "GET",
  98. "PUT",
  99. "POST",
  100. "DELETE",
  101. "MOVE"
  102. };
  103. if(((S32)action <=0) || ((S32)action >= REQUEST_ACTION_COUNT))
  104. {
  105. return VERBS[0];
  106. }
  107. return VERBS[action];
  108. }
  109. LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action) :
  110. mAction(action)
  111. {
  112. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  113. initialize();
  114. }
  115. LLURLRequest::LLURLRequest(
  116. LLURLRequest::ERequestAction action,
  117. const std::string& url) :
  118. mAction(action)
  119. {
  120. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  121. initialize();
  122. setURL(url);
  123. }
  124. LLURLRequest::~LLURLRequest()
  125. {
  126. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  127. delete mDetail;
  128. }
  129. void LLURLRequest::setURL(const std::string& url)
  130. {
  131. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  132. mDetail->mURL = url;
  133. }
  134. void LLURLRequest::addHeader(const char* header)
  135. {
  136. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  137. mDetail->mCurlRequest->slist_append(header);
  138. }
  139. void LLURLRequest::setBodyLimit(U32 size)
  140. {
  141. mDetail->mBodyLimit = size;
  142. mDetail->mIsBodyLimitSet = true;
  143. }
  144. void LLURLRequest::checkRootCertificate(bool check)
  145. {
  146. mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, (check? TRUE : FALSE));
  147. mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, (check? 2 : 0));
  148. mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, "");
  149. }
  150. void LLURLRequest::setCallback(LLURLRequestComplete* callback)
  151. {
  152. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  153. mCompletionCallback = callback;
  154. mDetail->mCurlRequest->setHeaderCallback(&headerCallback, (void*)callback);
  155. }
  156. // Added to mitigate the effect of libcurl looking
  157. // for the ALL_PROXY and http_proxy env variables
  158. // and deciding to insert a Pragma: no-cache
  159. // header! The only usage of this method at the
  160. // time of this writing is in llhttpclient.cpp
  161. // in the request() method, where this method
  162. // is called with use_proxy = FALSE
  163. void LLURLRequest::useProxy(bool use_proxy)
  164. {
  165.     static char *env_proxy;
  166.     if (use_proxy && (env_proxy == NULL))
  167.     {
  168.         apr_status_t status;
  169.         LLAPRPool pool;
  170. status = apr_env_get(&env_proxy, "ALL_PROXY", pool.getAPRPool());
  171.         if (status != APR_SUCCESS)
  172.         {
  173. status = apr_env_get(&env_proxy, "http_proxy", pool.getAPRPool());
  174.         }
  175.         if (status != APR_SUCCESS)
  176.         {
  177.            use_proxy = FALSE;
  178.         }
  179.     }
  180.     lldebugs << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << (env_proxy ? env_proxy : "(null)") << llendl;
  181.     if (env_proxy && use_proxy)
  182.     {
  183. mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, env_proxy);
  184.     }
  185.     else
  186.     {
  187.         mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, "");
  188.     }
  189. }
  190. void LLURLRequest::useProxy(const std::string &proxy)
  191. {
  192.     mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, proxy);
  193. }
  194. // virtual
  195. LLIOPipe::EStatus LLURLRequest::handleError(
  196. LLIOPipe::EStatus status,
  197. LLPumpIO* pump)
  198. {
  199. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  200. if(mCompletionCallback && pump)
  201. {
  202. LLURLRequestComplete* complete = NULL;
  203. complete = (LLURLRequestComplete*)mCompletionCallback.get();
  204. complete->httpStatus(
  205. HTTP_STATUS_PIPE_ERROR,
  206. LLIOPipe::lookupStatusString(status));
  207. complete->responseStatus(status);
  208. pump->respond(complete);
  209. mCompletionCallback = NULL;
  210. }
  211. return status;
  212. }
  213. // virtual
  214. LLIOPipe::EStatus LLURLRequest::process_impl(
  215. const LLChannelDescriptors& channels,
  216. buffer_ptr_t& buffer,
  217. bool& eos,
  218. LLSD& context,
  219. LLPumpIO* pump)
  220. {
  221. PUMP_DEBUG;
  222. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  223. //llinfos << "LLURLRequest::process_impl()" << llendl;
  224. if (!buffer) return STATUS_ERROR;
  225. // we're still waiting or prcessing, check how many
  226. // bytes we have accumulated.
  227. const S32 MIN_ACCUMULATION = 100000;
  228. if(pump && (mDetail->mByteAccumulator > MIN_ACCUMULATION))
  229. {
  230.  // This is a pretty sloppy calculation, but this
  231.  // tries to make the gross assumption that if data
  232.  // is coming in at 56kb/s, then this transfer will
  233.  // probably succeed. So, if we're accumlated
  234.  // 100,000 bytes (MIN_ACCUMULATION) then let's
  235.  // give this client another 2s to complete.
  236.  const F32 TIMEOUT_ADJUSTMENT = 2.0f;
  237.  mDetail->mByteAccumulator = 0;
  238.  pump->adjustTimeoutSeconds(TIMEOUT_ADJUSTMENT);
  239.  lldebugs << "LLURLRequest adjustTimeoutSeconds for request: " << mDetail->mURL << llendl;
  240.  if (mState == STATE_INITIALIZED)
  241.  {
  242.   llinfos << "LLURLRequest adjustTimeoutSeconds called during upload" << llendl;
  243.  }
  244. }
  245. switch(mState)
  246. {
  247. case STATE_INITIALIZED:
  248. {
  249. PUMP_DEBUG;
  250. // We only need to wait for input if we are uploading
  251. // something.
  252. if(((HTTP_PUT == mAction) || (HTTP_POST == mAction)) && !eos)
  253. {
  254. // we're waiting to get all of the information
  255. return STATUS_BREAK;
  256. }
  257. // *FIX: bit of a hack, but it should work. The configure and
  258. // callback method expect this information to be ready.
  259. mDetail->mResponseBuffer = buffer.get();
  260. mDetail->mChannels = channels;
  261. if(!configure())
  262. {
  263. return STATUS_ERROR;
  264. }
  265. mState = STATE_WAITING_FOR_RESPONSE;
  266. // *FIX: Maybe we should just go to the next state now...
  267. return STATUS_BREAK;
  268. }
  269. case STATE_WAITING_FOR_RESPONSE:
  270. case STATE_PROCESSING_RESPONSE:
  271. {
  272. PUMP_DEBUG;
  273. LLIOPipe::EStatus status = STATUS_BREAK;
  274. mDetail->mCurlRequest->perform();
  275. while(1)
  276. {
  277. CURLcode result;
  278. bool newmsg = mDetail->mCurlRequest->getResult(&result);
  279. if(!newmsg)
  280. {
  281. // keep processing
  282. break;
  283. }
  284. mState = STATE_HAVE_RESPONSE;
  285. context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
  286. context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
  287. lldebugs << this << "Setting context to " << context << llendl;
  288. switch(result)
  289. {
  290. case CURLE_OK:
  291. case CURLE_WRITE_ERROR:
  292. // NB: The error indication means that we stopped the
  293. // writing due the body limit being reached
  294. if(mCompletionCallback && pump)
  295. {
  296. LLURLRequestComplete* complete = NULL;
  297. complete = (LLURLRequestComplete*)
  298. mCompletionCallback.get();
  299. complete->responseStatus(
  300. result == CURLE_OK
  301. ? STATUS_OK : STATUS_STOP);
  302. LLPumpIO::links_t chain;
  303. LLPumpIO::LLLinkInfo link;
  304. link.mPipe = mCompletionCallback;
  305. link.mChannels = LLBufferArray::makeChannelConsumer(
  306. channels);
  307. chain.push_back(link);
  308. pump->respond(chain, buffer, context);
  309. mCompletionCallback = NULL;
  310. }
  311. break;
  312. case CURLE_FAILED_INIT:
  313. case CURLE_COULDNT_CONNECT:
  314. status = STATUS_NO_CONNECTION;
  315. break;
  316. default:
  317. llwarns << "URLRequest Error: " << result
  318. << ", "
  319. << LLCurl::strerror(result)
  320. << ", "
  321. << (mDetail->mURL.empty() ? "<EMPTY URL>" : mDetail->mURL)
  322. << llendl;
  323. status = STATUS_ERROR;
  324. break;
  325. }
  326. }
  327. return status;
  328. }
  329. case STATE_HAVE_RESPONSE:
  330. PUMP_DEBUG;
  331. // we already stuffed everything into channel in in the curl
  332. // callback, so we are done.
  333. eos = true;
  334. context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
  335. context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
  336. lldebugs << this << "Setting context to " << context << llendl;
  337. return STATUS_DONE;
  338. default:
  339. PUMP_DEBUG;
  340. context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
  341. context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
  342. lldebugs << this << "Setting context to " << context << llendl;
  343. return STATUS_ERROR;
  344. }
  345. }
  346. void LLURLRequest::initialize()
  347. {
  348. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  349. mState = STATE_INITIALIZED;
  350. mDetail = new LLURLRequestDetail;
  351. mDetail->mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1);
  352. mDetail->mCurlRequest->setWriteCallback(&downCallback, (void*)this);
  353. mDetail->mCurlRequest->setReadCallback(&upCallback, (void*)this);
  354. mRequestTransferedBytes = 0;
  355. mResponseTransferedBytes = 0;
  356. }
  357. bool LLURLRequest::configure()
  358. {
  359. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  360. bool rv = false;
  361. S32 bytes = mDetail->mResponseBuffer->countAfter(
  362.     mDetail->mChannels.in(),
  363. NULL);
  364. switch(mAction)
  365. {
  366. case HTTP_HEAD:
  367. mDetail->mCurlRequest->setopt(CURLOPT_HEADER, 1);
  368. mDetail->mCurlRequest->setopt(CURLOPT_NOBODY, 1);
  369. mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1);
  370. rv = true;
  371. break;
  372. case HTTP_GET:
  373. mDetail->mCurlRequest->setopt(CURLOPT_HTTPGET, 1);
  374. mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1);
  375. rv = true;
  376. break;
  377. case HTTP_PUT:
  378. // Disable the expect http 1.1 extension. POST and PUT default
  379. // to turning this on, and I am not too sure what it means.
  380. addHeader("Expect:");
  381. mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1);
  382. mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes);
  383. rv = true;
  384. break;
  385. case HTTP_POST:
  386. // Disable the expect http 1.1 extension. POST and PUT default
  387. // to turning this on, and I am not too sure what it means.
  388. addHeader("Expect:");
  389. // Disable the content type http header.
  390. // *FIX: what should it be?
  391. addHeader("Content-Type:");
  392. // Set the handle for an http post
  393. mDetail->mCurlRequest->setPost(NULL, bytes);
  394. rv = true;
  395. break;
  396. case HTTP_DELETE:
  397. // Set the handle for an http post
  398. mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "DELETE");
  399. rv = true;
  400. break;
  401. case HTTP_MOVE:
  402. // Set the handle for an http post
  403. mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "MOVE");
  404. // *NOTE: should we check for the Destination header?
  405. rv = true;
  406. break;
  407. default:
  408. llwarns << "Unhandled URLRequest action: " << mAction << llendl;
  409. break;
  410. }
  411. if(rv)
  412. {
  413. mDetail->mCurlRequest->sendRequest(mDetail->mURL);
  414. }
  415. return rv;
  416. }
  417. // static
  418. size_t LLURLRequest::downCallback(
  419. char* data,
  420. size_t size,
  421. size_t nmemb,
  422. void* user)
  423. {
  424. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  425. LLURLRequest* req = (LLURLRequest*)user;
  426. if(STATE_WAITING_FOR_RESPONSE == req->mState)
  427. {
  428. req->mState = STATE_PROCESSING_RESPONSE;
  429. }
  430. U32 bytes = size * nmemb;
  431. if (req->mDetail->mIsBodyLimitSet)
  432. {
  433. if (bytes > req->mDetail->mBodyLimit)
  434. {
  435. bytes = req->mDetail->mBodyLimit;
  436. req->mDetail->mBodyLimit = 0;
  437. }
  438. else
  439. {
  440. req->mDetail->mBodyLimit -= bytes;
  441. }
  442. }
  443. req->mDetail->mResponseBuffer->append(
  444. req->mDetail->mChannels.out(),
  445. (U8*)data,
  446. bytes);
  447. req->mResponseTransferedBytes += bytes;
  448. req->mDetail->mByteAccumulator += bytes;
  449. return bytes;
  450. }
  451. // static
  452. size_t LLURLRequest::upCallback(
  453. char* data,
  454. size_t size,
  455. size_t nmemb,
  456. void* user)
  457. {
  458. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  459. LLURLRequest* req = (LLURLRequest*)user;
  460. S32 bytes = llmin(
  461. (S32)(size * nmemb),
  462. req->mDetail->mResponseBuffer->countAfter(
  463. req->mDetail->mChannels.in(),
  464. req->mDetail->mLastRead));
  465. req->mDetail->mLastRead =  req->mDetail->mResponseBuffer->readAfter(
  466. req->mDetail->mChannels.in(),
  467. req->mDetail->mLastRead,
  468. (U8*)data,
  469. bytes);
  470. req->mRequestTransferedBytes += bytes;
  471. return bytes;
  472. }
  473. static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user)
  474. {
  475. const char* header_line = (const char*)data;
  476. size_t header_len = size * nmemb;
  477. LLURLRequestComplete* complete = (LLURLRequestComplete*)user;
  478. if (!complete || !header_line)
  479. {
  480. return header_len;
  481. }
  482. // *TODO: This should be a utility in llstring.h: isascii()
  483. for (size_t i = 0; i < header_len; ++i)
  484. {
  485. if (header_line[i] < 0)
  486. {
  487. return header_len;
  488. }
  489. }
  490. std::string header(header_line, header_len);
  491. // Per HTTP spec the first header line must be the status line.
  492. if (header.substr(0,5) == "HTTP/")
  493. {
  494. std::string::iterator end = header.end();
  495. std::string::iterator pos1 = std::find(header.begin(), end, ' ');
  496. if (pos1 != end) ++pos1;
  497. std::string::iterator pos2 = std::find(pos1, end, ' ');
  498. if (pos2 != end) ++pos2;
  499. std::string::iterator pos3 = std::find(pos2, end, 'r');
  500. std::string version(header.begin(), pos1);
  501. std::string status(pos1, pos2);
  502. std::string reason(pos2, pos3);
  503. S32 status_code = atoi(status.c_str());
  504. if (status_code > 0)
  505. {
  506. complete->httpStatus((U32)status_code, reason);
  507. return header_len;
  508. }
  509. }
  510. std::string::iterator sep = std::find(header.begin(),header.end(),':');
  511. if (sep != header.end())
  512. {
  513. std::string key(header.begin(), sep);
  514. std::string value(sep + 1, header.end());
  515. key = utf8str_tolower(utf8str_trim(key));
  516. value = utf8str_trim(value);
  517. complete->header(key, value);
  518. }
  519. else
  520. {
  521. LLStringUtil::trim(header);
  522. if (!header.empty())
  523. {
  524. llwarns << "Unable to parse header: " << header << llendl;
  525. }
  526. }
  527. return header_len;
  528. }
  529. /**
  530.  * LLContextURLExtractor
  531.  */
  532. // virtual
  533. LLIOPipe::EStatus LLContextURLExtractor::process_impl(
  534. const LLChannelDescriptors& channels,
  535. buffer_ptr_t& buffer,
  536. bool& eos,
  537. LLSD& context,
  538. LLPumpIO* pump)
  539. {
  540. PUMP_DEBUG;
  541. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  542. // The destination host is in the context.
  543. if(context.isUndefined() || !mRequest)
  544. {
  545. return STATUS_PRECONDITION_NOT_MET;
  546. }
  547. // copy in to out, since this just extract the URL and does not
  548. // actually change the data.
  549. LLChangeChannel change(channels.in(), channels.out());
  550. std::for_each(buffer->beginSegment(), buffer->endSegment(), change);
  551. // find the context url
  552. if(context.has(CONTEXT_DEST_URI_SD_LABEL))
  553. {
  554. mRequest->setURL(context[CONTEXT_DEST_URI_SD_LABEL].asString());
  555. return STATUS_DONE;
  556. }
  557. return STATUS_ERROR;
  558. }
  559. /**
  560.  * LLURLRequestComplete
  561.  */
  562. LLURLRequestComplete::LLURLRequestComplete() :
  563. mRequestStatus(LLIOPipe::STATUS_ERROR)
  564. {
  565. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  566. }
  567. // virtual
  568. LLURLRequestComplete::~LLURLRequestComplete()
  569. {
  570. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  571. }
  572. //virtual 
  573. void LLURLRequestComplete::header(const std::string& header, const std::string& value)
  574. {
  575. }
  576. //virtual 
  577. void LLURLRequestComplete::complete(const LLChannelDescriptors& channels,
  578. const buffer_ptr_t& buffer)
  579. {
  580. if(STATUS_OK == mRequestStatus)
  581. {
  582. response(channels, buffer);
  583. }
  584. else
  585. {
  586. noResponse();
  587. }
  588. }
  589. //virtual 
  590. void LLURLRequestComplete::response(const LLChannelDescriptors& channels,
  591. const buffer_ptr_t& buffer)
  592. {
  593. llwarns << "LLURLRequestComplete::response default implementation called"
  594. << llendl;
  595. }
  596. //virtual 
  597. void LLURLRequestComplete::noResponse()
  598. {
  599. llwarns << "LLURLRequestComplete::noResponse default implementation called"
  600. << llendl;
  601. }
  602. void LLURLRequestComplete::responseStatus(LLIOPipe::EStatus status)
  603. {
  604. LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
  605. mRequestStatus = status;
  606. }
  607. // virtual
  608. LLIOPipe::EStatus LLURLRequestComplete::process_impl(
  609. const LLChannelDescriptors& channels,
  610. buffer_ptr_t& buffer,
  611. bool& eos,
  612. LLSD& context,
  613. LLPumpIO* pump)
  614. {
  615. PUMP_DEBUG;
  616. complete(channels, buffer);
  617. return STATUS_OK;
  618. }