00001
00033 #include "linden_common.h"
00034
00035 #include "llhttpassetstorage.h"
00036
00037 #include <sys/stat.h>
00038
00039 #include "indra_constants.h"
00040 #include "message.h"
00041 #include "llvfile.h"
00042 #include "llvfs.h"
00043
00044 #ifdef LL_STANDALONE
00045 # include <zlib.h>
00046 #else
00047 # include "zlib/zlib.h"
00048 #endif
00049
00050 const U32 MAX_RUNNING_REQUESTS = 1;
00051 const F32 MAX_PROCESSING_TIME = 0.005f;
00052 const S32 CURL_XFER_BUFFER_SIZE = 65536;
00053
00054 const F32 GET_URL_TO_FILE_TIMEOUT = 1800.0f;
00055
00056 const S32 COMPRESSED_INPUT_BUFFER_SIZE = 4096;
00057
00058 const S32 HTTP_OK = 200;
00059 const S32 HTTP_PUT_OK = 201;
00060 const S32 HTTP_NO_CONTENT = 204;
00061 const S32 HTTP_MISSING = 404;
00062 const S32 HTTP_SERVER_BAD_GATEWAY = 502;
00063 const S32 HTTP_SERVER_TEMP_UNAVAILABLE = 503;
00064
00066
00067
00069 struct LLTempAssetData
00070 {
00071 LLUUID mAssetID;
00072 LLUUID mAgentID;
00073 std::string mHostName;
00074 };
00075
00077
00079
00080 class LLHTTPAssetRequest : public LLAssetRequest
00081 {
00082 public:
00083 LLHTTPAssetRequest(LLHTTPAssetStorage *asp, const LLUUID &uuid,
00084 LLAssetType::EType type, LLAssetStorage::ERequestType rt,
00085 const char *url, CURLM *curl_multi);
00086 virtual ~LLHTTPAssetRequest();
00087
00088 void setupCurlHandle();
00089 void cleanupCurlHandle();
00090
00091 void prepareCompressedUpload();
00092 void finishCompressedUpload();
00093 size_t readCompressedData(void* data, size_t size);
00094
00095 static size_t curlCompressedUploadCallback(
00096 void *data, size_t size, size_t nmemb, void *user_data);
00097
00098 virtual LLSD getTerseDetails() const;
00099 virtual LLSD getFullDetails() const;
00100
00101 public:
00102 LLHTTPAssetStorage *mAssetStoragep;
00103
00104 CURL *mCurlHandle;
00105 CURLM *mCurlMultiHandle;
00106 char *mURLBuffer;
00107 struct curl_slist *mHTTPHeaders;
00108 LLVFile *mVFile;
00109 LLUUID mTmpUUID;
00110 LLAssetStorage::ERequestType mRequestType;
00111
00112 bool mZInitialized;
00113 z_stream mZStream;
00114 char* mZInputBuffer;
00115 bool mZInputExhausted;
00116
00117 FILE *mFP;
00118 };
00119
00120
00121 LLHTTPAssetRequest::LLHTTPAssetRequest(LLHTTPAssetStorage *asp,
00122 const LLUUID &uuid,
00123 LLAssetType::EType type,
00124 LLAssetStorage::ERequestType rt,
00125 const char *url,
00126 CURLM *curl_multi)
00127 : LLAssetRequest(uuid, type),
00128 mZInitialized(false)
00129 {
00130 mAssetStoragep = asp;
00131 mCurlHandle = NULL;
00132 mCurlMultiHandle = curl_multi;
00133 mVFile = NULL;
00134 mRequestType = rt;
00135 mHTTPHeaders = NULL;
00136 mFP = NULL;
00137 mZInputBuffer = NULL;
00138 mZInputExhausted = false;
00139
00140 mURLBuffer = new char[strlen(url) + 1];
00141 if (mURLBuffer)
00142 {
00143 strcpy(mURLBuffer, url);
00144 }
00145 }
00146
00147 LLHTTPAssetRequest::~LLHTTPAssetRequest()
00148 {
00149
00150 if (mCurlHandle)
00151 {
00152 curl_multi_remove_handle(mCurlMultiHandle, mCurlHandle);
00153 cleanupCurlHandle();
00154 }
00155 if (mHTTPHeaders)
00156 {
00157 curl_slist_free_all(mHTTPHeaders);
00158 }
00159 delete[] mURLBuffer;
00160 delete mVFile;
00161 finishCompressedUpload();
00162 }
00163
00164
00165 LLSD LLHTTPAssetRequest::getTerseDetails() const
00166 {
00167 LLSD sd = LLAssetRequest::getTerseDetails();
00168
00169 sd["url"] = mURLBuffer;
00170
00171 return sd;
00172 }
00173
00174
00175 LLSD LLHTTPAssetRequest::getFullDetails() const
00176 {
00177 LLSD sd = LLAssetRequest::getFullDetails();
00178
00179 if (mCurlHandle)
00180 {
00181 long curl_response = -1;
00182 long curl_connect = -1;
00183 double curl_total_time = -1.0f;
00184 double curl_size_upload = -1.0f;
00185 double curl_size_download = -1.0f;
00186 long curl_content_length_upload = -1;
00187 long curl_content_length_download = -1;
00188 long curl_request_size = -1;
00189 const char* curl_content_type = NULL;
00190
00191 curl_easy_getinfo(mCurlHandle, CURLINFO_HTTP_CODE, &curl_response);
00192 curl_easy_getinfo(mCurlHandle, CURLINFO_HTTP_CONNECTCODE, &curl_connect);
00193 curl_easy_getinfo(mCurlHandle, CURLINFO_TOTAL_TIME, &curl_total_time);
00194 curl_easy_getinfo(mCurlHandle, CURLINFO_SIZE_UPLOAD, &curl_size_upload);
00195 curl_easy_getinfo(mCurlHandle, CURLINFO_SIZE_DOWNLOAD, &curl_size_download);
00196 curl_easy_getinfo(mCurlHandle, CURLINFO_CONTENT_LENGTH_UPLOAD, &curl_content_length_upload);
00197 curl_easy_getinfo(mCurlHandle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &curl_content_length_download);
00198 curl_easy_getinfo(mCurlHandle, CURLINFO_REQUEST_SIZE, &curl_request_size);
00199 curl_easy_getinfo(mCurlHandle, CURLINFO_CONTENT_TYPE, &curl_content_type);
00200
00201 sd["curl_response_code"] = (int) curl_response;
00202 sd["curl_http_connect_code"] = (int) curl_connect;
00203 sd["curl_total_time"] = curl_total_time;
00204 sd["curl_size_upload"] = curl_size_upload;
00205 sd["curl_size_download"] = curl_size_download;
00206 sd["curl_content_length_upload"] = (int) curl_content_length_upload;
00207 sd["curl_content_length_download"] = (int) curl_content_length_download;
00208 sd["curl_request_size"] = (int) curl_request_size;
00209 if (curl_content_type)
00210 {
00211 sd["curl_content_type"] = curl_content_type;
00212 }
00213 else
00214 {
00215 sd["curl_content_type"] = "";
00216 }
00217 }
00218
00219 sd["temp_id"] = mTmpUUID;
00220 sd["request_type"] = LLAssetStorage::getRequestName(mRequestType);
00221 sd["z_initialized"] = mZInitialized;
00222 sd["z_input_exhausted"] = mZInputExhausted;
00223
00224 S32 file_size = -1;
00225 if (mFP)
00226 {
00227 struct stat file_stat;
00228 int file_desc = fileno(mFP);
00229 if ( fstat(file_desc, &file_stat) == 0)
00230 {
00231 file_size = file_stat.st_size;
00232 }
00233 }
00234 sd["file_size"] = file_size;
00235
00236 return sd;
00237 }
00238
00239
00240 void LLHTTPAssetRequest::setupCurlHandle()
00241 {
00242 mCurlHandle = curl_easy_init();
00243 curl_easy_setopt(mCurlHandle, CURLOPT_NOSIGNAL, 1);
00244 curl_easy_setopt(mCurlHandle, CURLOPT_NOPROGRESS, 1);
00245 curl_easy_setopt(mCurlHandle, CURLOPT_URL, mURLBuffer);
00246 curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, this);
00247 if (LLAssetStorage::RT_DOWNLOAD == mRequestType)
00248 {
00249 curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");
00250
00251
00252
00253
00254
00255 }
00256
00257
00258 if (mZInitialized)
00259 {
00260 curl_easy_setopt(mCurlHandle, CURLOPT_PROXY, "");
00261
00262 }
00263 mHTTPHeaders = curl_slist_append(mHTTPHeaders, "Pragma:");
00264
00265
00266 curl_easy_setopt(mCurlHandle, CURLOPT_HTTPHEADER, mHTTPHeaders);
00267 if (mAssetStoragep)
00268 {
00269
00270 mAssetStoragep->addRunningRequest(mRequestType, this);
00271 }
00272 else
00273 {
00274 llerrs << "LLHTTPAssetRequest::setupCurlHandle - No asset storage associated with this request!" << llendl;
00275 }
00276 }
00277
00278 void LLHTTPAssetRequest::cleanupCurlHandle()
00279 {
00280 curl_easy_cleanup(mCurlHandle);
00281 if (mAssetStoragep)
00282 {
00283
00284 mAssetStoragep->removeRunningRequest(mRequestType, this);
00285 }
00286 else
00287 {
00288 llerrs << "LLHTTPAssetRequest::~LLHTTPAssetRequest - No asset storage associated with this request!" << llendl;
00289 }
00290 mCurlHandle = NULL;
00291 }
00292
00293 void LLHTTPAssetRequest::prepareCompressedUpload()
00294 {
00295 mZStream.next_in = Z_NULL;
00296 mZStream.avail_in = 0;
00297 mZStream.zalloc = Z_NULL;
00298 mZStream.zfree = Z_NULL;
00299 mZStream.opaque = Z_NULL;
00300
00301 int r = deflateInit2(&mZStream,
00302 1,
00303 Z_DEFLATED,
00304 15 + 16,
00305 8,
00306 Z_DEFAULT_STRATEGY);
00307
00308 if (r != Z_OK)
00309 {
00310 llerrs << "LLHTTPAssetRequest::prepareCompressedUpload defalateInit2() failed" << llendl;
00311 }
00312
00313 mZInitialized = true;
00314 mZInputBuffer = new char[COMPRESSED_INPUT_BUFFER_SIZE];
00315 mZInputExhausted = false;
00316
00317 mVFile = new LLVFile(gAssetStorage->mVFS,
00318 getUUID(), getType(), LLVFile::READ);
00319 }
00320
00321 void LLHTTPAssetRequest::finishCompressedUpload()
00322 {
00323 if (mZInitialized)
00324 {
00325 llinfos << "LLHTTPAssetRequest::finishCompressedUpload: "
00326 << "read " << mZStream.total_in << " byte asset file, "
00327 << "uploaded " << mZStream.total_out << " byte compressed asset"
00328 << llendl;
00329
00330 deflateEnd(&mZStream);
00331 delete[] mZInputBuffer;
00332 }
00333 }
00334
00335 size_t LLHTTPAssetRequest::readCompressedData(void* data, size_t size)
00336 {
00337 llassert(mZInitialized);
00338
00339 mZStream.next_out = (Bytef*)data;
00340 mZStream.avail_out = size;
00341
00342 while (mZStream.avail_out > 0)
00343 {
00344 if (mZStream.avail_in == 0 && !mZInputExhausted)
00345 {
00346 S32 to_read = llmin(COMPRESSED_INPUT_BUFFER_SIZE,
00347 (S32)(mVFile->getSize() - mVFile->tell()));
00348
00349 if ( to_read > 0 )
00350 {
00351 mVFile->read((U8*)mZInputBuffer, to_read);
00352 mZStream.next_in = (Bytef*)mZInputBuffer;
00353 mZStream.avail_in = mVFile->getLastBytesRead();
00354 }
00355
00356 mZInputExhausted = mZStream.avail_in == 0;
00357 }
00358
00359 int r = deflate(&mZStream,
00360 mZInputExhausted ? Z_FINISH : Z_NO_FLUSH);
00361
00362 if (r == Z_STREAM_END || r < 0 || mZInputExhausted)
00363 {
00364 if (r < 0)
00365 {
00366 llwarns << "LLHTTPAssetRequest::readCompressedData: deflate returned error code "
00367 << (S32) r << llendl;
00368 }
00369 break;
00370 }
00371 }
00372
00373 return size - mZStream.avail_out;
00374 }
00375
00376
00377 size_t LLHTTPAssetRequest::curlCompressedUploadCallback(
00378 void *data, size_t size, size_t nmemb, void *user_data)
00379 {
00380 size_t num_read = 0;
00381
00382 if (gAssetStorage)
00383 {
00384 CURL *curl_handle = (CURL *)user_data;
00385 LLHTTPAssetRequest *req = NULL;
00386 curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, &req);
00387 if (req)
00388 {
00389 num_read = req->readCompressedData(data, size * nmemb);
00390 }
00391 }
00392
00393 return num_read;
00394 }
00395
00397
00399
00400
00401 LLHTTPAssetStorage::LLHTTPAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
00402 LLVFS *vfs, const LLHost &upstream_host,
00403 const char *web_host,
00404 const char *local_web_host,
00405 const char *host_name)
00406 : LLAssetStorage(msg, xfer, vfs, upstream_host)
00407 {
00408 _init(web_host, local_web_host, host_name);
00409 }
00410
00411 LLHTTPAssetStorage::LLHTTPAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
00412 LLVFS *vfs,
00413 const char *web_host,
00414 const char *local_web_host,
00415 const char *host_name)
00416 : LLAssetStorage(msg, xfer, vfs)
00417 {
00418 _init(web_host, local_web_host, host_name);
00419 }
00420
00421 void LLHTTPAssetStorage::_init(const char *web_host, const char *local_web_host, const char* host_name)
00422 {
00423 mBaseURL = web_host;
00424 mLocalBaseURL = local_web_host;
00425 mHostName = host_name;
00426
00427
00428
00429 mCurlMultiHandle = curl_multi_init();
00430 }
00431
00432 LLHTTPAssetStorage::~LLHTTPAssetStorage()
00433 {
00434 curl_multi_cleanup(mCurlMultiHandle);
00435 mCurlMultiHandle = NULL;
00436
00437
00438 }
00439
00440
00441 void LLHTTPAssetStorage::storeAssetData(
00442 const LLUUID& uuid,
00443 LLAssetType::EType type,
00444 LLAssetStorage::LLStoreAssetCallback callback,
00445 void* user_data,
00446 bool temp_file,
00447 bool is_priority,
00448 bool store_local,
00449 const LLUUID& requesting_agent_id,
00450 bool user_waiting,
00451 F64 timeout)
00452 {
00453 if (mVFS->getExists(uuid, type))
00454 {
00455 LLAssetRequest *req = new LLAssetRequest(uuid, type);
00456 req->mUpCallback = callback;
00457 req->mUserData = user_data;
00458 req->mRequestingAgentID = requesting_agent_id;
00459 req->mIsUserWaiting = user_waiting;
00460 req->mTimeout = timeout;
00461
00462
00463 S32 size = mVFS->getSize(uuid, type);
00464 const char *message;
00465 if( store_local )
00466 {
00467 message = "Added to local upload queue";
00468 }
00469 else
00470 {
00471 message = "Added to upload queue";
00472 }
00473 reportMetric( uuid, type, NULL, requesting_agent_id, size, MR_OKAY, __FILE__, __LINE__, message );
00474
00475
00476 if(store_local)
00477 {
00478 mPendingLocalUploads.push_back(req);
00479 }
00480 else if(is_priority)
00481 {
00482 mPendingUploads.push_front(req);
00483 }
00484 else
00485 {
00486 mPendingUploads.push_back(req);
00487 }
00488 }
00489 else
00490 {
00491 llwarns << "AssetStorage: attempt to upload non-existent vfile " << uuid << ":" << LLAssetType::lookup(type) << llendl;
00492 if (callback)
00493 {
00494
00495 reportMetric( uuid, type, NULL, requesting_agent_id, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" );
00496 callback(uuid, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LL_EXSTAT_NONEXISTENT_FILE);
00497 }
00498 }
00499 }
00500
00501
00502 void LLHTTPAssetStorage::storeAssetData(
00503 const char* filename,
00504 const LLUUID& asset_id,
00505 LLAssetType::EType asset_type,
00506 LLStoreAssetCallback callback,
00507 void* user_data,
00508 bool temp_file,
00509 bool is_priority,
00510 bool user_waiting,
00511 F64 timeout)
00512 {
00513 llinfos << "LLAssetStorage::storeAssetData (legacy)" << asset_id << ":" << LLAssetType::lookup(asset_type) << llendl;
00514
00515 LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest;
00516
00517 legacy->mUpCallback = callback;
00518 legacy->mUserData = user_data;
00519
00520 FILE *fp = LLFile::fopen(filename, "rb");
00521 S32 size = 0;
00522 if (fp)
00523 {
00524 fseek(fp, 0, SEEK_END);
00525 size = ftell(fp);
00526 fseek(fp, 0, SEEK_SET);
00527 }
00528
00529 if( size )
00530 {
00531 LLVFile file(mVFS, asset_id, asset_type, LLVFile::WRITE);
00532
00533 file.setMaxSize(size);
00534
00535 const S32 buf_size = 65536;
00536 U8 copy_buf[buf_size];
00537 while ((size = (S32)fread(copy_buf, 1, buf_size, fp)))
00538 {
00539 file.write(copy_buf, size);
00540 }
00541 fclose(fp);
00542
00543
00544 if (temp_file)
00545 {
00546 LLFile::remove(filename);
00547 }
00548
00549
00550 storeAssetData(
00551 asset_id,
00552 asset_type,
00553 legacyStoreDataCallback,
00554 (void**)legacy,
00555 temp_file,
00556 is_priority,
00557 false,
00558 LLUUID::null,
00559 user_waiting,
00560 timeout);
00561 }
00562 else
00563 {
00564 if( fp )
00565 {
00566
00567 reportMetric( asset_id, asset_type, filename, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file was zero length" );
00568 fclose( fp );
00569 }
00570 else
00571 {
00572
00573 reportMetric( asset_id, asset_type, filename, LLUUID::null, 0, MR_FILE_NONEXIST, __FILE__, __LINE__, "The file didn't exist" );
00574 }
00575 if (callback)
00576 {
00577 callback(LLUUID::null, user_data, LL_ERR_CANNOT_OPEN_FILE, LL_EXSTAT_BLOCKED_FILE);
00578 }
00579 delete legacy;
00580 }
00581 }
00582
00583
00584 LLSD LLHTTPAssetStorage::getPendingDetails(LLAssetStorage::ERequestType rt,
00585 LLAssetType::EType asset_type,
00586 const std::string& detail_prefix) const
00587 {
00588 LLSD sd = LLAssetStorage::getPendingDetails(rt, asset_type, detail_prefix);
00589 const request_list_t* running = getRunningList(rt);
00590 if (running)
00591 {
00592
00593 S32 num_pending = sd["requests"].size();
00594 S32 i;
00595 for (i = 0; i < num_pending; ++i)
00596 {
00597 LLSD& pending = sd["requests"][i];
00598
00599 const LLAssetRequest* req = findRequest(running,
00600 LLAssetType::lookup(pending["type"].asString().c_str()),
00601 pending["asset_id"]);
00602 if (req)
00603 {
00604
00605 LLURI detail_url = pending["detail"];
00606 pending = req->getTerseDetails();
00607 pending["detail"] = detail_url;
00608 pending["is_running"] = true;
00609 }
00610 else
00611 {
00612 pending["is_running"] = false;
00613 }
00614 }
00615 }
00616 return sd;
00617 }
00618
00619
00620 LLSD LLHTTPAssetStorage::getPendingRequest(LLAssetStorage::ERequestType rt,
00621 LLAssetType::EType asset_type,
00622 const LLUUID& asset_id) const
00623 {
00624
00625 const request_list_t* running = getRunningList(rt);
00626 if (running)
00627 {
00628 LLSD sd = LLAssetStorage::getPendingRequest(running, asset_type, asset_id);
00629 if (sd)
00630 {
00631 sd["is_running"] = true;
00632 return sd;
00633 }
00634 }
00635 LLSD sd = LLAssetStorage::getPendingRequest(rt, asset_type, asset_id);
00636 if (sd)
00637 {
00638 sd["is_running"] = false;
00639 }
00640 return sd;
00641 }
00642
00643
00644 bool LLHTTPAssetStorage::deletePendingRequest(LLAssetStorage::ERequestType rt,
00645 LLAssetType::EType asset_type,
00646 const LLUUID& asset_id)
00647 {
00648
00649 request_list_t* running = getRunningList(rt);
00650 if (running)
00651 {
00652 LLAssetRequest* req = findRequest(running, asset_type, asset_id);
00653 if (req)
00654 {
00655
00656 running->remove(req);
00657
00658
00659 request_list_t* pending = getRequestList(rt);
00660 if (pending)
00661 {
00662 request_list_t::iterator result = std::find_if(pending->begin(), pending->end(),
00663 std::bind2nd(ll_asset_request_equal<LLAssetRequest*>(), req));
00664 if (pending->end() != result)
00665 {
00666
00667 LLAssetRequest* pending_req = *result;
00668 pending->remove(pending_req);
00669
00670 if (!pending_req->mIsUserWaiting)
00671 {
00672 pending->push_back(pending_req);
00673 }
00674 else
00675 {
00676 if (pending_req->mUpCallback)
00677 {
00678 pending_req->mUpCallback(pending_req->getUUID(), pending_req->mUserData, -1, LL_EXSTAT_REQUEST_DROPPED);
00679 }
00680
00681 }
00682
00683 llinfos << "Asset " << getRequestName(rt) << " request for "
00684 << asset_id << "." << LLAssetType::lookup(asset_type)
00685 << " removed from curl and placed at the end of the pending queue."
00686 << llendl;
00687 }
00688 else
00689 {
00690 llwarns << "Unable to find pending " << getRequestName(rt) << " request for "
00691 << asset_id << "." << LLAssetType::lookup(asset_type) << llendl;
00692 }
00693 }
00694 delete req;
00695
00696 return true;
00697 }
00698 }
00699 return LLAssetStorage::deletePendingRequest(rt, asset_type, asset_id);
00700 }
00701
00702
00703 void LLHTTPAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType type,
00704 void (*callback)(LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat),
00705 void *user_data, BOOL duplicate,
00706 BOOL is_priority)
00707 {
00708
00709 LLAssetRequest *req = new LLAssetRequest(uuid, type);
00710 req->mDownCallback = callback;
00711 req->mUserData = user_data;
00712 req->mIsPriority = is_priority;
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723 if (req->getType() == LLAssetType::AT_TEXTURE)
00724 {
00725 mPendingDownloads.push_back(req);
00726 }
00727 else
00728 {
00729 mPendingDownloads.push_front(req);
00730 }
00731 }
00732
00733 LLAssetRequest* LLHTTPAssetStorage::findNextRequest(LLAssetStorage::request_list_t& pending,
00734 LLAssetStorage::request_list_t& running)
00735 {
00736
00737 if (running.size() >= MAX_RUNNING_REQUESTS
00738 || pending.size() <= running.size()) return NULL;
00739
00740
00741 request_list_t::iterator running_begin = running.begin();
00742 request_list_t::iterator running_end = running.end();
00743
00744 request_list_t::iterator pending_iter = pending.begin();
00745 request_list_t::iterator pending_end = pending.end();
00746
00747 for (; pending_iter != pending.end(); ++pending_iter)
00748 {
00749 LLAssetRequest* req = *pending_iter;
00750
00751 if (running_end == std::find_if(running_begin, running_end,
00752 std::bind2nd(ll_asset_request_equal<LLAssetRequest*>(), req)))
00753 {
00754
00755 return req;
00756 }
00757 }
00758 return NULL;
00759 }
00760
00761
00762 void LLHTTPAssetStorage::checkForTimeouts()
00763 {
00764 CURLMcode mcode;
00765 LLAssetRequest *req;
00766 while ( (req = findNextRequest(mPendingDownloads, mRunningDownloads)) )
00767 {
00768
00769
00770
00771 char tmp_url[MAX_STRING];
00772 char uuid_str[UUID_STR_LENGTH];
00773 req->getUUID().toString(uuid_str);
00774 std::string base_url = getBaseURL(req->getUUID(), req->getType());
00775 snprintf(tmp_url, sizeof(tmp_url), "%s/%36s.%s", base_url.c_str() , uuid_str, LLAssetType::lookup(req->getType()));
00776
00777 LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(),
00778 req->getType(), RT_DOWNLOAD, tmp_url, mCurlMultiHandle);
00779 new_req->mTmpUUID.generate();
00780
00781
00782 new_req->setupCurlHandle();
00783 curl_easy_setopt(new_req->mCurlHandle, CURLOPT_FOLLOWLOCATION, TRUE);
00784 curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEFUNCTION, &curlDownCallback);
00785 curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEDATA, new_req->mCurlHandle);
00786
00787 mcode = curl_multi_add_handle(mCurlMultiHandle, new_req->mCurlHandle);
00788 if (mcode > CURLM_OK)
00789 {
00790
00791
00792 new_req->cleanupCurlHandle();
00793 deletePendingRequest(RT_DOWNLOAD, new_req->getType(), new_req->getUUID());
00794 break;
00795 }
00796 else
00797 {
00798 llinfos << "Requesting " << new_req->mURLBuffer << llendl;
00799 }
00800 }
00801
00802 while ( (req = findNextRequest(mPendingUploads, mRunningUploads)) )
00803 {
00804
00805
00806 bool do_compress = req->getType() == LLAssetType::AT_OBJECT;
00807
00808 char tmp_url[MAX_STRING];
00809 char uuid_str[UUID_STR_LENGTH];
00810 req->getUUID().toString(uuid_str);
00811 snprintf(tmp_url, sizeof(tmp_url),
00812 do_compress ? "%s/%s.%s.gz" : "%s/%s.%s",
00813 mBaseURL.c_str(), uuid_str, LLAssetType::lookup(req->getType()));
00814
00815 LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(),
00816 req->getType(), RT_UPLOAD, tmp_url, mCurlMultiHandle);
00817
00818 if (req->mIsUserWaiting)
00819 {
00820 new_req->mTime = req->mTime;
00821 new_req->mTimeout = req->mTimeout;
00822 new_req->mIsUserWaiting = req->mIsUserWaiting;
00823 }
00824
00825 if (do_compress)
00826 {
00827 new_req->prepareCompressedUpload();
00828 }
00829
00830
00831 new_req->setupCurlHandle();
00832 curl_easy_setopt(new_req->mCurlHandle, CURLOPT_UPLOAD, 1);
00833 curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEFUNCTION, &nullOutputCallback);
00834
00835 if (do_compress)
00836 {
00837 curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READFUNCTION,
00838 &LLHTTPAssetRequest::curlCompressedUploadCallback);
00839 }
00840 else
00841 {
00842 LLVFile file(mVFS, req->getUUID(), req->getType());
00843 curl_easy_setopt(new_req->mCurlHandle, CURLOPT_INFILESIZE, file.getSize());
00844 curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READFUNCTION,
00845 &curlUpCallback);
00846 }
00847 curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READDATA, new_req->mCurlHandle);
00848
00849 mcode = curl_multi_add_handle(mCurlMultiHandle, new_req->mCurlHandle);
00850 if (mcode > CURLM_OK)
00851 {
00852
00853
00854 new_req->cleanupCurlHandle();
00855 deletePendingRequest(RT_UPLOAD, new_req->getType(), new_req->getUUID());
00856 break;
00857 }
00858 else
00859 {
00860
00861 LLVFile file(mVFS,new_req->getUUID(),new_req->getType());
00862 S32 size = file.getSize();
00863 llinfos << "Requesting PUT " << new_req->mURLBuffer << ", asset size: " << size << " bytes" << llendl;
00864 if (size == 0)
00865 {
00866 llwarns << "Rejecting zero size PUT request!" << llendl;
00867 new_req->cleanupCurlHandle();
00868 deletePendingRequest(RT_UPLOAD, new_req->getType(), new_req->getUUID());
00869 }
00870 }
00871
00872 }
00873
00874 while ( (req = findNextRequest(mPendingLocalUploads, mRunningLocalUploads)) )
00875 {
00876
00877 LLVFile file(mVFS, req->getUUID(), req->getType());
00878
00879 char tmp_url[MAX_STRING];
00880 char uuid_str[UUID_STR_LENGTH];
00881 req->getUUID().toString(uuid_str);
00882
00883
00884 snprintf(tmp_url, sizeof(tmp_url), "%s/%36s.%s", mLocalBaseURL.c_str(), uuid_str, LLAssetType::lookup(req->getType()));
00885
00886 LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(),
00887 req->getType(), RT_LOCALUPLOAD, tmp_url, mCurlMultiHandle);
00888 new_req->mRequestingAgentID = req->mRequestingAgentID;
00889
00890
00891 new_req->setupCurlHandle();
00892 curl_easy_setopt(new_req->mCurlHandle, CURLOPT_PUT, 1);
00893 curl_easy_setopt(new_req->mCurlHandle, CURLOPT_INFILESIZE, file.getSize());
00894 curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEFUNCTION, &nullOutputCallback);
00895 curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READFUNCTION, &curlUpCallback);
00896 curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READDATA, new_req->mCurlHandle);
00897
00898 mcode = curl_multi_add_handle(mCurlMultiHandle, new_req->mCurlHandle);
00899 if (mcode > CURLM_OK)
00900 {
00901
00902
00903 new_req->cleanupCurlHandle();
00904 deletePendingRequest(RT_LOCALUPLOAD, new_req->getType(), new_req->getUUID());
00905 break;
00906 }
00907 else
00908 {
00909
00910 S32 size = file.getSize();
00911
00912 llinfos << "TAT: LLHTTPAssetStorage::checkForTimeouts() : pending local!"
00913 << " Requesting PUT " << new_req->mURLBuffer << ", asset size: " << size << " bytes" << llendl;
00914 if (size == 0)
00915 {
00916
00917 llwarns << "Rejecting zero size PUT request!" << llendl;
00918 new_req->cleanupCurlHandle();
00919 deletePendingRequest(RT_UPLOAD, new_req->getType(), new_req->getUUID());
00920 }
00921
00922 }
00923
00924 }
00925 S32 count = 0;
00926 int queue_length;
00927 do
00928 {
00929 mcode = curl_multi_perform(mCurlMultiHandle, &queue_length);
00930 count++;
00931 } while (mcode == CURLM_CALL_MULTI_PERFORM && (count < 5));
00932
00933 CURLMsg *curl_msg;
00934 do
00935 {
00936 curl_msg = curl_multi_info_read(mCurlMultiHandle, &queue_length);
00937 if (curl_msg && curl_msg->msg == CURLMSG_DONE)
00938 {
00939 long curl_result = 0;
00940 S32 xfer_result = LL_ERR_NOERR;
00941
00942 LLHTTPAssetRequest *req = NULL;
00943 curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_PRIVATE, &req);
00944
00945
00946 curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_HTTP_CODE, &curl_result);
00947 if (RT_UPLOAD == req->mRequestType || RT_LOCALUPLOAD == req->mRequestType)
00948 {
00949 if (curl_msg->data.result == CURLE_OK &&
00950 ( curl_result == HTTP_OK
00951 || curl_result == HTTP_PUT_OK
00952 || curl_result == HTTP_NO_CONTENT))
00953 {
00954 llinfos << "Success uploading " << req->getUUID() << " to " << req->mURLBuffer << llendl;
00955 if (RT_LOCALUPLOAD == req->mRequestType)
00956 {
00957 addTempAssetData(req->getUUID(), req->mRequestingAgentID, mHostName);
00958 }
00959 }
00960 else if (curl_msg->data.result == CURLE_COULDNT_CONNECT ||
00961 curl_msg->data.result == CURLE_OPERATION_TIMEOUTED ||
00962 curl_result == HTTP_SERVER_BAD_GATEWAY ||
00963 curl_result == HTTP_SERVER_TEMP_UNAVAILABLE)
00964 {
00965 llwarns << "Re-requesting upload for " << req->getUUID() << ". Received upload error to " << req->mURLBuffer <<
00966 " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl;
00967
00969
00970
00971
00972
00973 }
00974 else
00975 {
00976 llwarns << "Failure uploading " << req->getUUID() << " to " << req->mURLBuffer <<
00977 " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl;
00978
00979 xfer_result = LL_ERR_ASSET_REQUEST_FAILED;
00980 }
00981
00982 if (!(curl_msg->data.result == CURLE_COULDNT_CONNECT ||
00983 curl_msg->data.result == CURLE_OPERATION_TIMEOUTED ||
00984 curl_result == HTTP_SERVER_BAD_GATEWAY ||
00985 curl_result == HTTP_SERVER_TEMP_UNAVAILABLE))
00986 {
00987
00988
00989 _callUploadCallbacks(req->getUUID(), req->getType(), (xfer_result == 0), LL_EXSTAT_CURL_RESULT | curl_result);
00990
00991 }
00992 }
00993 else if (RT_DOWNLOAD == req->mRequestType)
00994 {
00995 if (curl_result == HTTP_OK && curl_msg->data.result == CURLE_OK)
00996 {
00997 if (req->mVFile && req->mVFile->getSize() > 0)
00998 {
00999 llinfos << "Success downloading " << req->mURLBuffer << ", size " << req->mVFile->getSize() << llendl;
01000
01001 req->mVFile->rename(req->getUUID(), req->getType());
01002 }
01003 else
01004 {
01005
01006
01007 llwarns << "Found " << req->mURLBuffer << " to be zero size" << llendl;
01008 xfer_result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
01009 }
01010 }
01011 else
01012 {
01013
01014 llwarns << "Failure downloading " << req->mURLBuffer <<
01015 " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl;
01016
01017 xfer_result = (curl_result == HTTP_MISSING) ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED;
01018
01019 if (req->mVFile)
01020 {
01021 req->mVFile->remove();
01022 }
01023 }
01024
01025
01026
01027 downloadCompleteCallback(
01028 xfer_result,
01029 req->getUUID(),
01030 req->getType(),
01031 (void *)req,
01032 LL_EXSTAT_CURL_RESULT | curl_result);
01033
01034 }
01035 else
01036 {
01037
01038
01039 }
01040
01041
01042 delete req;
01043 req = NULL;
01044 }
01045
01046 } while (curl_msg && queue_length > 0);
01047
01048
01049
01050
01051 bumpTimedOutUploads();
01052
01053 LLAssetStorage::checkForTimeouts();
01054 }
01055
01056 void LLHTTPAssetStorage::bumpTimedOutUploads()
01057 {
01058 bool user_waiting=FALSE;
01059
01060 F64 mt_secs = LLMessageSystem::getMessageTimeSeconds();
01061
01062 if (mPendingUploads.size())
01063 {
01064 request_list_t::iterator it = mPendingUploads.begin();
01065 LLAssetRequest* req = *it;
01066 user_waiting=req->mIsUserWaiting;
01067 }
01068
01069
01070 if (!(mPendingUploads.size() > mRunningUploads.size()) && !user_waiting)
01071 {
01072 return;
01073 }
01074
01075
01076 request_list_t temp_running = mRunningUploads;
01077
01078 request_list_t::iterator it = temp_running.begin();
01079 request_list_t::iterator end = temp_running.end();
01080 for ( ; it != end; ++it)
01081 {
01082
01083 LLAssetRequest* req = *it;
01084
01085 if ( req->mTimeout < (mt_secs - req->mTime) )
01086 {
01087 llwarns << "Asset upload request timed out for "
01088 << req->getUUID() << "."
01089 << LLAssetType::lookup(req->getType())
01090 << ", bumping to the back of the line!" << llendl;
01091
01092 deletePendingRequest(RT_UPLOAD, req->getType(), req->getUUID());
01093 }
01094 }
01095 }
01096
01097
01098 size_t LLHTTPAssetStorage::curlDownCallback(void *data, size_t size, size_t nmemb, void *user_data)
01099 {
01100 if (!gAssetStorage)
01101 {
01102 llwarns << "Missing gAssetStorage, aborting curl download callback!" << llendl;
01103 return 0;
01104 }
01105 S32 bytes = (S32)(size * nmemb);
01106 CURL *curl_handle = (CURL *)user_data;
01107 LLHTTPAssetRequest *req = NULL;
01108 curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, &req);
01109
01110 if (! req->mVFile)
01111 {
01112 req->mVFile = new LLVFile(gAssetStorage->mVFS, req->mTmpUUID, LLAssetType::AT_NONE, LLVFile::APPEND);
01113 }
01114
01115 double content_length = 0.0;
01116 curl_easy_getinfo(curl_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &content_length);
01117
01118
01119 S32 file_length = llmax(0, (S32)llmin(content_length, 20000000.0), bytes + req->mVFile->getSize());
01120
01121 req->mVFile->setMaxSize(file_length);
01122 req->mVFile->write((U8*)data, bytes);
01123
01124 return nmemb;
01125 }
01126
01127
01128 size_t LLHTTPAssetStorage::curlUpCallback(void *data, size_t size, size_t nmemb, void *user_data)
01129 {
01130 if (!gAssetStorage)
01131 {
01132 llwarns << "Missing gAssetStorage, aborting curl download callback!" << llendl;
01133 return 0;
01134 }
01135 CURL *curl_handle = (CURL *)user_data;
01136 LLHTTPAssetRequest *req = NULL;
01137 curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, &req);
01138
01139 if (! req->mVFile)
01140 {
01141 req->mVFile = new LLVFile(gAssetStorage->mVFS, req->getUUID(), req->getType(), LLVFile::READ);
01142 }
01143
01144 S32 bytes = llmin((S32)(size * nmemb), (S32)(req->mVFile->getSize() - req->mVFile->tell()));
01145
01146 req->mVFile->read((U8*)data, bytes);
01147
01148 return req->mVFile->getLastBytesRead();
01149 }
01150
01151
01152 size_t LLHTTPAssetStorage::nullOutputCallback(void *data, size_t size, size_t nmemb, void *user_data)
01153 {
01154
01155
01156 return nmemb;
01157 }
01158
01159
01160
01161
01162
01163 S32 LLHTTPAssetStorage::getURLToFile(const LLUUID& uuid, LLAssetType::EType asset_type, const LLString &url, const char *filename, progress_callback callback, void *userdata)
01164 {
01165
01166
01167 lldebugs << "LLHTTPAssetStorage::getURLToFile() - " << url << llendl;
01168
01169 FILE *fp = LLFile::fopen(filename, "wb");
01170 if (! fp)
01171 {
01172 llwarns << "Failed to open " << filename << " for writing" << llendl;
01173 return LL_ERR_ASSET_REQUEST_FAILED;
01174 }
01175
01176
01177 LLHTTPAssetRequest req(this, uuid, asset_type, RT_DOWNLOAD, url.c_str(), mCurlMultiHandle);
01178 req.mFP = fp;
01179
01180 req.setupCurlHandle();
01181 curl_easy_setopt(req.mCurlHandle, CURLOPT_FOLLOWLOCATION, TRUE);
01182 curl_easy_setopt(req.mCurlHandle, CURLOPT_WRITEFUNCTION, &curlFileDownCallback);
01183 curl_easy_setopt(req.mCurlHandle, CURLOPT_WRITEDATA, req.mCurlHandle);
01184
01185 curl_multi_add_handle(mCurlMultiHandle, req.mCurlHandle);
01186 llinfos << "Requesting as file " << req.mURLBuffer << llendl;
01187
01188
01189 int queue_length;
01190 CURLMsg *curl_msg;
01191 LLTimer timeout;
01192 timeout.setTimerExpirySec(GET_URL_TO_FILE_TIMEOUT);
01193 bool success = false;
01194 S32 xfer_result = 0;
01195 do
01196 {
01197 curl_multi_perform(mCurlMultiHandle, &queue_length);
01198 curl_msg = curl_multi_info_read(mCurlMultiHandle, &queue_length);
01199
01200 if (callback)
01201 {
01202 callback(userdata);
01203 }
01204
01205 if ( curl_msg && (CURLMSG_DONE == curl_msg->msg) )
01206 {
01207 success = true;
01208 }
01209 else if (timeout.hasExpired())
01210 {
01211 llwarns << "Request for " << url << " has timed out." << llendl;
01212 success = false;
01213 xfer_result = LL_ERR_ASSET_REQUEST_FAILED;
01214 break;
01215 }
01216 } while (!success);
01217
01218 if (success)
01219 {
01220 long curl_result = 0;
01221 curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_HTTP_CODE, &curl_result);
01222
01223 if (curl_result == HTTP_OK && curl_msg->data.result == CURLE_OK)
01224 {
01225 S32 size = ftell(req.mFP);
01226 if (size > 0)
01227 {
01228
01229 llinfos << "Success downloading " << req.mURLBuffer << " to file, size " << size << llendl;
01230 }
01231 else
01232 {
01233 llwarns << "Found " << req.mURLBuffer << " to be zero size" << llendl;
01234 xfer_result = LL_ERR_ASSET_REQUEST_FAILED;
01235 }
01236 }
01237 else
01238 {
01239 xfer_result = curl_result == HTTP_MISSING ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED;
01240 llinfos << "Failure downloading " << req.mURLBuffer <<
01241 " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl;
01242 }
01243 }
01244
01245 fclose(fp);
01246 if (xfer_result)
01247 {
01248 LLFile::remove(filename);
01249 }
01250 return xfer_result;
01251 }
01252
01253
01254
01255 size_t LLHTTPAssetStorage::curlFileDownCallback(void *data, size_t size, size_t nmemb, void *user_data)
01256 {
01257 CURL *curl_handle = (CURL *)user_data;
01258 LLHTTPAssetRequest *req = NULL;
01259 curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, &req);
01260
01261 if (! req->mFP)
01262 {
01263 llwarns << "Missing mFP, aborting curl file download callback!" << llendl;
01264 return 0;
01265 }
01266
01267 return fwrite(data, size, nmemb, req->mFP);
01268 }
01269
01270 LLAssetStorage::request_list_t* LLHTTPAssetStorage::getRunningList(LLAssetStorage::ERequestType rt)
01271 {
01272 switch (rt)
01273 {
01274 case RT_DOWNLOAD:
01275 return &mRunningDownloads;
01276 case RT_UPLOAD:
01277 return &mRunningUploads;
01278 case RT_LOCALUPLOAD:
01279 return &mRunningLocalUploads;
01280 default:
01281 return NULL;
01282 }
01283 }
01284
01285 const LLAssetStorage::request_list_t* LLHTTPAssetStorage::getRunningList(LLAssetStorage::ERequestType rt) const
01286 {
01287 switch (rt)
01288 {
01289 case RT_DOWNLOAD:
01290 return &mRunningDownloads;
01291 case RT_UPLOAD:
01292 return &mRunningUploads;
01293 case RT_LOCALUPLOAD:
01294 return &mRunningLocalUploads;
01295 default:
01296 return NULL;
01297 }
01298 }
01299
01300
01301 void LLHTTPAssetStorage::addRunningRequest(ERequestType rt, LLHTTPAssetRequest* request)
01302 {
01303 request_list_t* requests = getRunningList(rt);
01304 if (requests)
01305 {
01306 requests->push_back(request);
01307 }
01308 else
01309 {
01310 llerrs << "LLHTTPAssetStorage::addRunningRequest - Request is not an upload OR download, this is bad!" << llendl;
01311 }
01312 }
01313
01314 void LLHTTPAssetStorage::removeRunningRequest(ERequestType rt, LLHTTPAssetRequest* request)
01315 {
01316 request_list_t* requests = getRunningList(rt);
01317 if (requests)
01318 {
01319 requests->remove(request);
01320 }
01321 else
01322 {
01323 llerrs << "LLHTTPAssetStorage::removeRunningRequest - Destroyed request is not an upload OR download, this is bad!" << llendl;
01324 }
01325 }
01326
01327
01328 void LLHTTPAssetStorage::addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name)
01329 {
01330 if (agent_id.isNull() || asset_id.isNull())
01331 {
01332 llwarns << "TAT: addTempAssetData bad id's asset_id: " << asset_id << " agent_id: " << agent_id << llendl;
01333 return;
01334 }
01335
01336 LLTempAssetData temp_asset_data;
01337 temp_asset_data.mAssetID = asset_id;
01338 temp_asset_data.mAgentID = agent_id;
01339 temp_asset_data.mHostName = host_name;
01340
01341 mTempAssets[asset_id] = temp_asset_data;
01342 }
01343
01344
01345 BOOL LLHTTPAssetStorage::hasTempAssetData(const LLUUID& texture_id) const
01346 {
01347 uuid_tempdata_map::const_iterator citer = mTempAssets.find(texture_id);
01348 BOOL found = (citer != mTempAssets.end());
01349 return found;
01350 }
01351
01352
01353 std::string LLHTTPAssetStorage::getTempAssetHostName(const LLUUID& texture_id) const
01354 {
01355 uuid_tempdata_map::const_iterator citer = mTempAssets.find(texture_id);
01356 if (citer != mTempAssets.end())
01357 {
01358 return citer->second.mHostName;
01359 }
01360 else
01361 {
01362 return std::string();
01363 }
01364 }
01365
01366
01367 LLUUID LLHTTPAssetStorage::getTempAssetAgentID(const LLUUID& texture_id) const
01368 {
01369 uuid_tempdata_map::const_iterator citer = mTempAssets.find(texture_id);
01370 if (citer != mTempAssets.end())
01371 {
01372 return citer->second.mAgentID;
01373 }
01374 else
01375 {
01376 return LLUUID::null;
01377 }
01378 }
01379
01380
01381 void LLHTTPAssetStorage::removeTempAssetData(const LLUUID& asset_id)
01382 {
01383 mTempAssets.erase(asset_id);
01384 }
01385
01386
01387 void LLHTTPAssetStorage::removeTempAssetDataByAgentID(const LLUUID& agent_id)
01388 {
01389 uuid_tempdata_map::iterator it = mTempAssets.begin();
01390 uuid_tempdata_map::iterator end = mTempAssets.end();
01391
01392 while (it != end)
01393 {
01394 const LLTempAssetData& asset_data = it->second;
01395 if (asset_data.mAgentID == agent_id)
01396 {
01397 mTempAssets.erase(it++);
01398 }
01399 else
01400 {
01401 ++it;
01402 }
01403 }
01404 }
01405
01406 std::string LLHTTPAssetStorage::getBaseURL(const LLUUID& asset_id, LLAssetType::EType asset_type)
01407 {
01408 if (LLAssetType::AT_TEXTURE == asset_type)
01409 {
01410 uuid_tempdata_map::const_iterator citer = mTempAssets.find(asset_id);
01411 if (citer != mTempAssets.end())
01412 {
01413 const std::string& host_name = citer->second.mHostName;
01414 std::string url = llformat(LOCAL_ASSET_URL_FORMAT, host_name.c_str());
01415 return url;
01416 }
01417 }
01418
01419 return mBaseURL;
01420 }
01421
01422 void LLHTTPAssetStorage::dumpTempAssetData(const LLUUID& avatar_id) const
01423 {
01424 uuid_tempdata_map::const_iterator it = mTempAssets.begin();
01425 uuid_tempdata_map::const_iterator end = mTempAssets.end();
01426 S32 count = 0;
01427 for ( ; it != end; ++it)
01428 {
01429 const LLTempAssetData& temp_asset_data = it->second;
01430 if (avatar_id.isNull()
01431 || avatar_id == temp_asset_data.mAgentID)
01432 {
01433 llinfos << "TAT: dump agent " << temp_asset_data.mAgentID
01434 << " texture " << temp_asset_data.mAssetID
01435 << " host " << temp_asset_data.mHostName
01436 << llendl;
01437 count++;
01438 }
01439 }
01440
01441 if (avatar_id.isNull())
01442 {
01443 llinfos << "TAT: dumped " << count << " entries for all avatars" << llendl;
01444 }
01445 else
01446 {
01447 llinfos << "TAT: dumped " << count << " entries for avatar " << avatar_id << llendl;
01448 }
01449 }
01450
01451 void LLHTTPAssetStorage::clearTempAssetData()
01452 {
01453 llinfos << "TAT: Clearing temp asset data map" << llendl;
01454 mTempAssets.clear();
01455 }