llurlrequest.cpp

Go to the documentation of this file.
00001 
00034 #include "linden_common.h"
00035 #include "llurlrequest.h"
00036 
00037 #include <curl/curl.h>
00038 #include <algorithm>
00039 
00040 #include "llioutil.h"
00041 #include "llmemtype.h"
00042 #include "llpumpio.h"
00043 #include "llsd.h"
00044 #include "llstring.h"
00045 #include "apr-1/apr_env.h"
00046 
00047 static const U32 HTTP_STATUS_PIPE_ERROR = 499;
00048 
00052 const std::string CONTEXT_DEST_URI_SD_LABEL("dest_uri");
00053 
00054 
00055 static
00056 size_t headerCallback(void* data, size_t size, size_t nmemb, void* user);
00057 
00061 class LLURLRequestDetail
00062 {
00063 public:
00064         LLURLRequestDetail();
00065         ~LLURLRequestDetail();
00066         CURLM* mCurlMulti;
00067         CURL* mCurl;
00068         struct curl_slist* mHeaders;
00069         char* mURL;
00070         char mCurlErrorBuf[CURL_ERROR_SIZE + 1];                /* Flawfinder: ignore */
00071         bool mNeedToRemoveEasyHandle;
00072         LLBufferArray* mResponseBuffer;
00073         LLChannelDescriptors mChannels;
00074         U8* mLastRead;
00075         U32 mBodyLimit;
00076         bool mIsBodyLimitSet;
00077 };
00078 
00079 LLURLRequestDetail::LLURLRequestDetail() :
00080         mCurlMulti(NULL),
00081         mCurl(NULL),
00082         mHeaders(NULL),
00083         mURL(NULL),
00084         mNeedToRemoveEasyHandle(false),
00085         mResponseBuffer(NULL),
00086         mLastRead(NULL),
00087         mBodyLimit(0),
00088         mIsBodyLimitSet(false)
00089         
00090 {
00091         LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
00092         mCurlErrorBuf[0] = '\0';
00093 }
00094 
00095 LLURLRequestDetail::~LLURLRequestDetail()
00096 {
00097         LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
00098         if(mCurl)
00099         {
00100                 if(mNeedToRemoveEasyHandle && mCurlMulti)
00101                 {
00102                         curl_multi_remove_handle(mCurlMulti, mCurl);
00103                         mNeedToRemoveEasyHandle = false;
00104                 }
00105                 curl_easy_cleanup(mCurl);
00106                 mCurl = NULL;
00107         }
00108         if(mCurlMulti)
00109         {
00110                 curl_multi_cleanup(mCurlMulti);
00111                 mCurlMulti = NULL;
00112         }
00113         if(mHeaders)
00114         {
00115                 curl_slist_free_all(mHeaders);
00116                 mHeaders = NULL;
00117         }
00118         delete[] mURL;
00119         mURL = NULL;
00120         mResponseBuffer = NULL;
00121         mLastRead = NULL;
00122 }
00123 
00124 
00129 static std::string sCAFile("");
00130 static std::string sCAPath("");
00131 
00132 LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action) :
00133         mAction(action)
00134 {
00135         LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
00136         initialize();
00137 }
00138 
00139 LLURLRequest::LLURLRequest(
00140         LLURLRequest::ERequestAction action,
00141         const std::string& url) :
00142         mAction(action)
00143 {
00144         LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
00145         initialize();
00146         setURL(url);
00147 }
00148 
00149 LLURLRequest::~LLURLRequest()
00150 {
00151         LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
00152         delete mDetail;
00153 }
00154 
00155 void LLURLRequest::setURL(const std::string& url)
00156 {
00157         LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
00158         if(mDetail->mURL)
00159         {
00160                 // *NOTE: if any calls to set the url have been made to curl,
00161                 // this will probably lead to a crash.
00162                 delete[] mDetail->mURL;
00163                 mDetail->mURL = NULL;
00164         }
00165         if(!url.empty())
00166         {
00167                 mDetail->mURL = new char[url.size() + 1];
00168                 url.copy(mDetail->mURL, url.size());
00169                 mDetail->mURL[url.size()] = '\0';
00170         }
00171 }
00172 
00173 void LLURLRequest::addHeader(const char* header)
00174 {
00175         LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
00176         mDetail->mHeaders = curl_slist_append(mDetail->mHeaders, header);
00177 }
00178 
00179 void LLURLRequest::requestEncoding(const char* encoding)
00180 {
00181         LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
00182         curl_easy_setopt(mDetail->mCurl, CURLOPT_ENCODING, encoding);
00183 }
00184 
00185 void LLURLRequest::setBodyLimit(U32 size)
00186 {
00187         mDetail->mBodyLimit = size;
00188         mDetail->mIsBodyLimitSet = true;
00189 }
00190 
00191 void LLURLRequest::checkRootCertificate(bool check, const char* caBundle)
00192 {
00193         curl_easy_setopt(mDetail->mCurl, CURLOPT_SSL_VERIFYPEER, (check? TRUE : FALSE));
00194         if (caBundle)
00195         {
00196                 curl_easy_setopt(mDetail->mCurl, CURLOPT_CAINFO, caBundle);
00197         }
00198 }
00199 
00200 void LLURLRequest::setCallback(LLURLRequestComplete* callback)
00201 {
00202         LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
00203         mCompletionCallback = callback;
00204 
00205         curl_easy_setopt(mDetail->mCurl, CURLOPT_HEADERFUNCTION, &headerCallback);
00206         curl_easy_setopt(mDetail->mCurl, CURLOPT_WRITEHEADER, callback);
00207 }
00208 
00209 // Added to mitigate the effect of libcurl looking
00210 // for the ALL_PROXY and http_proxy env variables
00211 // and deciding to insert a Pragma: no-cache
00212 // header! The only usage of this method at the
00213 // time of this writing is in llhttpclient.cpp
00214 // in the request() method, where this method
00215 // is called with use_proxy = FALSE
00216 void LLURLRequest::useProxy(bool use_proxy)
00217 {
00218     static char *env_proxy;
00219 
00220     if (use_proxy && (env_proxy == NULL))
00221     {
00222         apr_status_t status;
00223         apr_pool_t* pool;
00224         apr_pool_create(&pool, NULL);
00225         status = apr_env_get(&env_proxy, "ALL_PROXY", pool);
00226         if (status != APR_SUCCESS)
00227         {
00228             status = apr_env_get(&env_proxy, "http_proxy", pool);
00229         }
00230         if (status != APR_SUCCESS)
00231         {
00232            use_proxy = FALSE;
00233         }
00234         apr_pool_destroy(pool);
00235     }
00236 
00237 
00238     lldebugs << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << env_proxy << llendl;
00239 
00240     if (env_proxy && use_proxy)
00241     {
00242         curl_easy_setopt(mDetail->mCurl, CURLOPT_PROXY, env_proxy);
00243     }
00244     else
00245     {
00246         curl_easy_setopt(mDetail->mCurl, CURLOPT_PROXY, "");
00247     }
00248 }
00249 
00250 // virtual
00251 LLIOPipe::EStatus LLURLRequest::handleError(
00252         LLIOPipe::EStatus status,
00253         LLPumpIO* pump)
00254 {
00255         LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
00256         if(mCompletionCallback && pump)
00257         {
00258                 LLURLRequestComplete* complete = NULL;
00259                 complete = (LLURLRequestComplete*)mCompletionCallback.get();
00260                 complete->httpStatus(
00261                         HTTP_STATUS_PIPE_ERROR,
00262                         LLIOPipe::lookupStatusString(status));
00263                 complete->responseStatus(status);
00264                 pump->respond(complete);
00265                 mCompletionCallback = NULL;
00266         }
00267         return status;
00268 }
00269 
00270 // virtual
00271 LLIOPipe::EStatus LLURLRequest::process_impl(
00272         const LLChannelDescriptors& channels,
00273         buffer_ptr_t& buffer,
00274         bool& eos,
00275         LLSD& context,
00276         LLPumpIO* pump)
00277 {
00278         PUMP_DEBUG;
00279         LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
00280         //llinfos << "LLURLRequest::process_impl()" << llendl;
00281         if(!buffer) return STATUS_ERROR;
00282         switch(mState)
00283         {
00284         case STATE_INITIALIZED:
00285         {
00286                 PUMP_DEBUG;
00287                 // We only need to wait for input if we are uploading
00288                 // something.
00289                 if(((HTTP_PUT == mAction) || (HTTP_POST == mAction)) && !eos)
00290                 {
00291                         // we're waiting to get all of the information
00292                         return STATUS_BREAK;
00293                 }
00294 
00295                 // *FIX: bit of a hack, but it should work. The configure and
00296                 // callback method expect this information to be ready.
00297                 mDetail->mResponseBuffer = buffer.get();
00298                 mDetail->mChannels = channels;
00299                 if(!configure())
00300                 {
00301                         return STATUS_ERROR;
00302                 }
00303                 mState = STATE_WAITING_FOR_RESPONSE;
00304 
00305                 // *FIX: Maybe we should just go to the next state now...
00306                 return STATUS_BREAK;
00307         }
00308         case STATE_WAITING_FOR_RESPONSE:
00309         case STATE_PROCESSING_RESPONSE:
00310         {
00311                 PUMP_DEBUG;
00312                 const S32 MAX_CALLS = 5;
00313                 S32 count = MAX_CALLS;
00314                 CURLMcode code;
00315                 LLIOPipe::EStatus status = STATUS_BREAK;
00316                 S32 queue;
00317                 do
00318                 {
00319                         LLFastTimer t2(LLFastTimer::FTM_CURL);
00320                         code = curl_multi_perform(mDetail->mCurlMulti, &queue);                 
00321                 }while((CURLM_CALL_MULTI_PERFORM == code) && (queue > 0) && count--);
00322                 CURLMsg* curl_msg;
00323                 do
00324                 {
00325                         curl_msg = curl_multi_info_read(mDetail->mCurlMulti, &queue);
00326                         if(curl_msg && (curl_msg->msg == CURLMSG_DONE))
00327                         {
00328                                 mState = STATE_HAVE_RESPONSE;
00329 
00330                                 CURLcode result = curl_msg->data.result;
00331                                 switch(result)
00332                                 {
00333                                 case CURLE_OK:
00334                                 case CURLE_WRITE_ERROR:
00335                                         // NB: The error indication means that we stopped the
00336                                         // writing due the body limit being reached
00337                                         if(mCompletionCallback && pump)
00338                                         {
00339                                                 LLURLRequestComplete* complete = NULL;
00340                                                 complete = (LLURLRequestComplete*)
00341                                                         mCompletionCallback.get();
00342                                                 complete->responseStatus(
00343                                                                 result == CURLE_OK
00344                                                                         ? STATUS_OK : STATUS_STOP);
00345                                                 LLPumpIO::links_t chain;
00346                                                 LLPumpIO::LLLinkInfo link;
00347                                                 link.mPipe = mCompletionCallback;
00348                                                 link.mChannels = LLBufferArray::makeChannelConsumer(
00349                                                         channels);
00350                                                 chain.push_back(link);
00351                                                 pump->respond(chain, buffer, context);
00352                                                 mCompletionCallback = NULL;
00353                                         }
00354                                         break;
00355                                 case CURLE_COULDNT_CONNECT:
00356                                         status = STATUS_NO_CONNECTION;
00357                                         break;
00358                                 default:
00359                                         llwarns << "URLRequest Error: " << curl_msg->data.result
00360                                                         << ", "
00361 #if LL_DARWIN
00362                                                         // 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...
00363                                                         // There's a problem with the custom curl headers in our build that keeps me from #ifdefing this on the libcurl version number
00364                                                         // (the correct check would be #if LIBCURL_VERSION_NUM >= 0x070c00).  We'll fix the header problem soon, but for now
00365                                                         // just punt and print the numeric error code on the Mac.
00366                                                         << curl_msg->data.result
00367 #else // LL_DARWIN
00368                                                         << curl_easy_strerror(curl_msg->data.result)
00369 #endif // LL_DARWIN
00370                                                         << ", "
00371                                                         << (mDetail->mURL ? mDetail->mURL : "<EMPTY URL>")
00372                                                         << llendl;
00373                                         status = STATUS_ERROR;
00374                                         break;
00375                                 }
00376                                 curl_multi_remove_handle(mDetail->mCurlMulti, mDetail->mCurl);
00377                                 mDetail->mNeedToRemoveEasyHandle = false;
00378                         }
00379                 }while(curl_msg && (queue > 0));
00380                 return status;
00381         }
00382         case STATE_HAVE_RESPONSE:
00383                 PUMP_DEBUG;
00384                 // we already stuffed everything into channel in in the curl
00385                 // callback, so we are done.
00386                 eos = true;
00387                 return STATUS_DONE;
00388 
00389         default:
00390                 PUMP_DEBUG;
00391                 return STATUS_ERROR;
00392         }
00393 }
00394 
00395 void LLURLRequest::initialize()
00396 {
00397         LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
00398         mState = STATE_INITIALIZED;
00399         mDetail = new LLURLRequestDetail;
00400         mDetail->mCurl = curl_easy_init();
00401         mDetail->mCurlMulti = curl_multi_init();
00402         curl_easy_setopt(mDetail->mCurl, CURLOPT_NOSIGNAL, 1);
00403         curl_easy_setopt(mDetail->mCurl, CURLOPT_WRITEFUNCTION, &downCallback);
00404         curl_easy_setopt(mDetail->mCurl, CURLOPT_WRITEDATA, this);
00405         curl_easy_setopt(mDetail->mCurl, CURLOPT_READFUNCTION, &upCallback);
00406         curl_easy_setopt(mDetail->mCurl, CURLOPT_READDATA, this);
00407         curl_easy_setopt(
00408                 mDetail->mCurl,
00409                 CURLOPT_ERRORBUFFER,
00410                 mDetail->mCurlErrorBuf);
00411 
00412         if(sCAPath != std::string(""))
00413         {
00414                 curl_easy_setopt(mDetail->mCurl, CURLOPT_CAPATH, sCAPath.c_str());
00415         }
00416         if(sCAFile != std::string(""))
00417         {
00418                 curl_easy_setopt(mDetail->mCurl, CURLOPT_CAINFO, sCAFile.c_str());
00419         }
00420 }
00421 
00422 bool LLURLRequest::configure()
00423 {
00424         LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
00425         bool rv = false;
00426         S32 bytes = mDetail->mResponseBuffer->countAfter(
00427                 mDetail->mChannels.in(),
00428                 NULL);
00429         switch(mAction)
00430         {
00431         case HTTP_GET:
00432                 curl_easy_setopt(mDetail->mCurl, CURLOPT_HTTPGET, 1);
00433                 curl_easy_setopt(mDetail->mCurl, CURLOPT_FOLLOWLOCATION, 1);
00434                 rv = true;
00435                 break;
00436 
00437         case HTTP_PUT:
00438                 // Disable the expect http 1.1 extension. POST and PUT default
00439                 // to turning this on, and I am not too sure what it means.
00440                 addHeader("Expect:");
00441 
00442                 curl_easy_setopt(mDetail->mCurl, CURLOPT_UPLOAD, 1);
00443                 curl_easy_setopt(mDetail->mCurl, CURLOPT_INFILESIZE, bytes);
00444                 rv = true;
00445                 break;
00446 
00447         case HTTP_POST:
00448                 // Disable the expect http 1.1 extension. POST and PUT default
00449                 // to turning this on, and I am not too sure what it means.
00450                 addHeader("Expect:");
00451 
00452                 // Disable the content type http header.
00453                 // *FIX: what should it be?
00454                 addHeader("Content-Type:");
00455 
00456                 // Set the handle for an http post
00457                 curl_easy_setopt(mDetail->mCurl, CURLOPT_POST, 1);
00458                 curl_easy_setopt(mDetail->mCurl, CURLOPT_POSTFIELDS, NULL);
00459                 curl_easy_setopt(mDetail->mCurl, CURLOPT_POSTFIELDSIZE, bytes);
00460                 rv = true;
00461                 break;
00462 
00463         case HTTP_DELETE:
00464                 // Set the handle for an http post
00465                 curl_easy_setopt(mDetail->mCurl, CURLOPT_CUSTOMREQUEST, "DELETE");
00466                 rv = true;
00467                 break;
00468 
00469         default:
00470                 llwarns << "Unhandled URLRequest action: " << mAction << llendl;
00471                 break;
00472         }
00473         if(rv)
00474         {
00475                 if(mDetail->mHeaders)
00476                 {
00477                         curl_easy_setopt(
00478                                 mDetail->mCurl,
00479                                 CURLOPT_HTTPHEADER,
00480                                 mDetail->mHeaders);
00481                 }
00482                 curl_easy_setopt(mDetail->mCurl, CURLOPT_URL, mDetail->mURL);
00483                 curl_multi_add_handle(mDetail->mCurlMulti, mDetail->mCurl);
00484                 mDetail->mNeedToRemoveEasyHandle = true;
00485         }
00486         return rv;
00487 }
00488 
00489 // static
00490 size_t LLURLRequest::downCallback(
00491         void* data,
00492         size_t size,
00493         size_t nmemb,
00494         void* user)
00495 {
00496         LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
00497         LLURLRequest* req = (LLURLRequest*)user;
00498         if(STATE_WAITING_FOR_RESPONSE == req->mState)
00499         {
00500                 req->mState = STATE_PROCESSING_RESPONSE;
00501         }
00502         U32 bytes = size * nmemb;
00503         if (req->mDetail->mIsBodyLimitSet)
00504         {
00505                 if (bytes > req->mDetail->mBodyLimit)
00506                 {
00507                         bytes = req->mDetail->mBodyLimit;
00508                         req->mDetail->mBodyLimit = 0;
00509                 }
00510                 else
00511                 {
00512                         req->mDetail->mBodyLimit -= bytes;
00513                 }
00514         }
00515 
00516         req->mDetail->mResponseBuffer->append(
00517                 req->mDetail->mChannels.out(),
00518                 (U8*)data,
00519                 bytes);
00520         return bytes;
00521 }
00522 
00523 // static
00524 size_t LLURLRequest::upCallback(
00525         void* data,
00526         size_t size,
00527         size_t nmemb,
00528         void* user)
00529 {
00530         LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
00531         LLURLRequest* req = (LLURLRequest*)user;
00532         S32 bytes = llmin(
00533                 (S32)(size * nmemb),
00534                 req->mDetail->mResponseBuffer->countAfter(
00535                         req->mDetail->mChannels.in(),
00536                         req->mDetail->mLastRead));
00537         req->mDetail->mLastRead =  req->mDetail->mResponseBuffer->readAfter(
00538                 req->mDetail->mChannels.in(),
00539                 req->mDetail->mLastRead,
00540                 (U8*)data,
00541                 bytes);
00542         return bytes;
00543 }
00544 
00545 static
00546 size_t headerCallback(void* data, size_t size, size_t nmemb, void* user)
00547 {
00548         const char* headerLine = (const char*)data;
00549         size_t headerLen = size * nmemb;
00550         LLURLRequestComplete* complete = (LLURLRequestComplete*)user;
00551 
00552         // *TODO: This should be a utility in llstring.h: isascii()
00553         for (size_t i = 0; i < headerLen; ++i)
00554         {
00555                 if (headerLine[i] < 0)
00556                 {
00557                         return headerLen;
00558                 }
00559         }
00560 
00561         size_t sep;
00562         for (sep = 0; sep < headerLen  &&  headerLine[sep] != ':'; ++sep) { }
00563 
00564         if (sep < headerLen && complete)
00565         {
00566                 std::string key(headerLine, sep);
00567                 std::string value(headerLine + sep + 1, headerLen - sep - 1);
00568 
00569                 key = utf8str_tolower(utf8str_trim(key));
00570                 value = utf8str_trim(value);
00571 
00572                 complete->header(key, value);
00573         }
00574         else
00575         {
00576                 std::string s(headerLine, headerLen);
00577 
00578                 std::string::iterator end = s.end();
00579                 std::string::iterator pos1 = std::find(s.begin(), end, ' ');
00580                 if (pos1 != end) ++pos1;
00581                 std::string::iterator pos2 = std::find(pos1, end, ' ');
00582                 if (pos2 != end) ++pos2;
00583                 std::string::iterator pos3 = std::find(pos2, end, '\r');
00584 
00585                 std::string version(s.begin(), pos1);
00586                 std::string status(pos1, pos2);
00587                 std::string reason(pos2, pos3);
00588 
00589                 int statusCode = atoi(status.c_str());
00590                 if (statusCode > 0)
00591                 {
00592                         if (complete)
00593                         {
00594                                 complete->httpStatus((U32)statusCode, reason);
00595                         }
00596                 }
00597         }
00598 
00599         return headerLen;
00600 }
00601 
00602 //static 
00603 void LLURLRequest::setCertificateAuthorityFile(const std::string& file_name)
00604 {
00605         sCAFile = file_name;
00606 }
00607 
00608 //static 
00609 void LLURLRequest::setCertificateAuthorityPath(const std::string& path)
00610 {
00611         sCAPath = path;
00612 }
00613 
00617 // virtual
00618 LLIOPipe::EStatus LLContextURLExtractor::process_impl(
00619         const LLChannelDescriptors& channels,
00620         buffer_ptr_t& buffer,
00621         bool& eos,
00622         LLSD& context,
00623         LLPumpIO* pump)
00624 {
00625         PUMP_DEBUG;
00626         LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
00627         // The destination host is in the context.
00628         if(context.isUndefined() || !mRequest)
00629         {
00630                 return STATUS_PRECONDITION_NOT_MET;
00631         }
00632 
00633         // copy in to out, since this just extract the URL and does not
00634         // actually change the data.
00635         LLChangeChannel change(channels.in(), channels.out());
00636         std::for_each(buffer->beginSegment(), buffer->endSegment(), change);
00637 
00638         // find the context url
00639         if(context.has(CONTEXT_DEST_URI_SD_LABEL))
00640         {
00641                 mRequest->setURL(context[CONTEXT_DEST_URI_SD_LABEL]);
00642                 return STATUS_DONE;
00643         }
00644         return STATUS_ERROR;
00645 }
00646 
00647 
00651 LLURLRequestComplete::LLURLRequestComplete() :
00652         mRequestStatus(LLIOPipe::STATUS_ERROR)
00653 {
00654         LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
00655 }
00656 
00657 // virtual
00658 LLURLRequestComplete::~LLURLRequestComplete()
00659 {
00660         LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
00661 }
00662 
00663 //virtual 
00664 void LLURLRequestComplete::header(const std::string& header, const std::string& value)
00665 {
00666 }
00667 
00668 //virtual 
00669 void LLURLRequestComplete::httpStatus(U32 status, const std::string& reason)
00670 {
00671 }
00672 
00673 //virtual 
00674 void LLURLRequestComplete::complete(const LLChannelDescriptors& channels,
00675                 const buffer_ptr_t& buffer)
00676 {
00677         if(STATUS_OK == mRequestStatus)
00678         {
00679                 response(channels, buffer);
00680         }
00681         else
00682         {
00683                 noResponse();
00684         }
00685 }
00686 
00687 //virtual 
00688 void LLURLRequestComplete::response(const LLChannelDescriptors& channels,
00689                 const buffer_ptr_t& buffer)
00690 {
00691         llwarns << "LLURLRequestComplete::response default implementation called"
00692                 << llendl;
00693 }
00694 
00695 //virtual 
00696 void LLURLRequestComplete::noResponse()
00697 {
00698         llwarns << "LLURLRequestComplete::noResponse default implementation called"
00699                 << llendl;
00700 }
00701 
00702 void LLURLRequestComplete::responseStatus(LLIOPipe::EStatus status)
00703 {
00704         LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
00705         mRequestStatus = status;
00706 }
00707 
00708 // virtual
00709 LLIOPipe::EStatus LLURLRequestComplete::process_impl(
00710         const LLChannelDescriptors& channels,
00711         buffer_ptr_t& buffer,
00712         bool& eos,
00713         LLSD& context,
00714         LLPumpIO* pump)
00715 {
00716         PUMP_DEBUG;
00717         complete(channels, buffer);
00718         return STATUS_OK;
00719 }

Generated on Thu Jul 1 06:09:24 2010 for Second Life Viewer by  doxygen 1.4.7