diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llmessage/llhttpassetstorage.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llmessage/llhttpassetstorage.cpp')
-rw-r--r-- | linden/indra/llmessage/llhttpassetstorage.cpp | 1019 |
1 files changed, 1019 insertions, 0 deletions
diff --git a/linden/indra/llmessage/llhttpassetstorage.cpp b/linden/indra/llmessage/llhttpassetstorage.cpp new file mode 100644 index 0000000..2b64385 --- /dev/null +++ b/linden/indra/llmessage/llhttpassetstorage.cpp | |||
@@ -0,0 +1,1019 @@ | |||
1 | /** | ||
2 | * @file llhttpassetstorage.cpp | ||
3 | * @brief Subclass capable of loading asset data to/from an external | ||
4 | * source. Currently, a web server accessed via curl | ||
5 | * | ||
6 | * Copyright (c) 2003-2007, Linden Research, Inc. | ||
7 | * | ||
8 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
9 | * to you under the terms of the GNU General Public License, version 2.0 | ||
10 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
11 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
12 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
13 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
14 | * | ||
15 | * There are special exceptions to the terms and conditions of the GPL as | ||
16 | * it is applied to this Source Code. View the full text of the exception | ||
17 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
18 | * online at http://secondlife.com/developers/opensource/flossexception | ||
19 | * | ||
20 | * By copying, modifying or distributing this software, you acknowledge | ||
21 | * that you have read and understood your obligations described above, | ||
22 | * and agree to abide by those obligations. | ||
23 | * | ||
24 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
25 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
26 | * COMPLETENESS OR PERFORMANCE. | ||
27 | */ | ||
28 | |||
29 | #include "linden_common.h" | ||
30 | |||
31 | #include "llhttpassetstorage.h" | ||
32 | |||
33 | #include "indra_constants.h" | ||
34 | #include "llvfile.h" | ||
35 | #include "llvfs.h" | ||
36 | |||
37 | #include "zlib/zlib.h" | ||
38 | |||
39 | const F32 MAX_PROCESSING_TIME = 0.005f; | ||
40 | const S32 CURL_XFER_BUFFER_SIZE = 65536; | ||
41 | // Try for 30 minutes for now. | ||
42 | const F32 GET_URL_TO_FILE_TIMEOUT = 1800.0f; | ||
43 | |||
44 | const S32 COMPRESSED_INPUT_BUFFER_SIZE = 4096; | ||
45 | |||
46 | const S32 HTTP_OK = 200; | ||
47 | const S32 HTTP_PUT_OK = 201; | ||
48 | const S32 HTTP_NO_CONTENT = 204; | ||
49 | const S32 HTTP_MISSING = 404; | ||
50 | const S32 HTTP_SERVER_BAD_GATEWAY = 502; | ||
51 | const S32 HTTP_SERVER_TEMP_UNAVAILABLE = 503; | ||
52 | |||
53 | ///////////////////////////////////////////////////////////////////////////////// | ||
54 | // LLTempAssetData | ||
55 | // An asset not stored on central asset store, but on a simulator node somewhere. | ||
56 | ///////////////////////////////////////////////////////////////////////////////// | ||
57 | struct LLTempAssetData | ||
58 | { | ||
59 | LLUUID mAssetID; | ||
60 | LLUUID mAgentID; | ||
61 | std::string mHostName; | ||
62 | }; | ||
63 | |||
64 | ///////////////////////////////////////////////////////////////////////////////// | ||
65 | // LLHTTPAssetRequest | ||
66 | ///////////////////////////////////////////////////////////////////////////////// | ||
67 | |||
68 | class LLHTTPAssetRequest : public LLAssetRequest | ||
69 | { | ||
70 | public: | ||
71 | LLHTTPAssetRequest(LLHTTPAssetStorage *asp, const LLUUID &uuid, LLAssetType::EType type, const char *url, CURLM *curl_multi); | ||
72 | virtual ~LLHTTPAssetRequest(); | ||
73 | |||
74 | void setupCurlHandle(); | ||
75 | |||
76 | void prepareCompressedUpload(); | ||
77 | void finishCompressedUpload(); | ||
78 | size_t readCompressedData(void* data, size_t size); | ||
79 | |||
80 | static size_t curlCompressedUploadCallback( | ||
81 | void *data, size_t size, size_t nmemb, void *user_data); | ||
82 | |||
83 | public: | ||
84 | LLHTTPAssetStorage *mAssetStoragep; | ||
85 | |||
86 | CURL *mCurlHandle; | ||
87 | CURLM *mCurlMultiHandle; | ||
88 | char *mURLBuffer; | ||
89 | struct curl_slist *mHTTPHeaders; | ||
90 | LLVFile *mVFile; | ||
91 | LLUUID mTmpUUID; | ||
92 | BOOL mIsUpload; | ||
93 | BOOL mIsLocalUpload; | ||
94 | BOOL mIsDownload; | ||
95 | |||
96 | bool mZInitialized; | ||
97 | z_stream mZStream; | ||
98 | char* mZInputBuffer; | ||
99 | bool mZInputExhausted; | ||
100 | |||
101 | FILE *mFP; | ||
102 | }; | ||
103 | |||
104 | |||
105 | LLHTTPAssetRequest::LLHTTPAssetRequest(LLHTTPAssetStorage *asp, const LLUUID &uuid, LLAssetType::EType type, const char *url, CURLM *curl_multi) | ||
106 | : LLAssetRequest(uuid, type), | ||
107 | mZInitialized(false) | ||
108 | { | ||
109 | mAssetStoragep = asp; | ||
110 | mCurlHandle = NULL; | ||
111 | mCurlMultiHandle = curl_multi; | ||
112 | mVFile = NULL; | ||
113 | mIsUpload = FALSE; | ||
114 | mIsLocalUpload = FALSE; | ||
115 | mIsDownload = FALSE; | ||
116 | mHTTPHeaders = NULL; | ||
117 | |||
118 | mURLBuffer = new char[strlen(url) + 1]; /*Flawfinder: ignore*/ | ||
119 | if (mURLBuffer) | ||
120 | { | ||
121 | strcpy(mURLBuffer, url); | ||
122 | } | ||
123 | } | ||
124 | |||
125 | LLHTTPAssetRequest::~LLHTTPAssetRequest() | ||
126 | { | ||
127 | // Cleanup/cancel the request | ||
128 | if (mCurlHandle) | ||
129 | { | ||
130 | curl_multi_remove_handle(mCurlMultiHandle, mCurlHandle); | ||
131 | curl_easy_cleanup(mCurlHandle); | ||
132 | if (mAssetStoragep) | ||
133 | { | ||
134 | // Terminating a request. Thus upload or download is no longer pending. | ||
135 | if (mIsUpload) | ||
136 | { | ||
137 | mAssetStoragep->clearPendingUpload(); | ||
138 | } | ||
139 | else if (mIsLocalUpload) | ||
140 | { | ||
141 | mAssetStoragep->clearPendingLocalUpload(); | ||
142 | } | ||
143 | else if (mIsDownload) | ||
144 | { | ||
145 | mAssetStoragep->clearPendingDownload(); | ||
146 | } | ||
147 | else | ||
148 | { | ||
149 | llerrs << "LLHTTPAssetRequest::~LLHTTPAssetRequest - Destroyed request is not upload OR download, this is bad!" << llendl; | ||
150 | } | ||
151 | } | ||
152 | else | ||
153 | { | ||
154 | llerrs << "LLHTTPAssetRequest::~LLHTTPAssetRequest - No asset storage associated with this request!" << llendl; | ||
155 | } | ||
156 | } | ||
157 | if (mHTTPHeaders) | ||
158 | { | ||
159 | curl_slist_free_all(mHTTPHeaders); | ||
160 | } | ||
161 | delete[] mURLBuffer; | ||
162 | delete mVFile; | ||
163 | finishCompressedUpload(); | ||
164 | } | ||
165 | |||
166 | void LLHTTPAssetRequest::setupCurlHandle() | ||
167 | { | ||
168 | mCurlHandle = curl_easy_init(); | ||
169 | curl_easy_setopt(mCurlHandle, CURLOPT_NOSIGNAL, 1); | ||
170 | curl_easy_setopt(mCurlHandle, CURLOPT_NOPROGRESS, 1); | ||
171 | curl_easy_setopt(mCurlHandle, CURLOPT_URL, mURLBuffer); | ||
172 | curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, this); | ||
173 | if (mIsDownload) | ||
174 | { | ||
175 | curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, ""); | ||
176 | // only do this on downloads, as uploads | ||
177 | // to some apache configs (like our test grids) | ||
178 | // mistakenly claim the response is gzip'd if the resource | ||
179 | // name ends in .gz, even though in a PUT, the response is | ||
180 | // just plain HTML saying "created" | ||
181 | } | ||
182 | /* Remove the Pragma: no-cache header that libcurl inserts by default; | ||
183 | we want the cached version, if possible. */ | ||
184 | if (mZInitialized) | ||
185 | { | ||
186 | curl_easy_setopt(mCurlHandle, CURLOPT_PROXY, ""); | ||
187 | // disable use of proxy, which can't handle chunked transfers | ||
188 | } | ||
189 | mHTTPHeaders = curl_slist_append(mHTTPHeaders, "Pragma:"); | ||
190 | // resist the temptation to explicitly add the Transfer-Encoding: chunked | ||
191 | // header here - invokes a libCURL bug | ||
192 | curl_easy_setopt(mCurlHandle, CURLOPT_HTTPHEADER, mHTTPHeaders); | ||
193 | if (mAssetStoragep) | ||
194 | { | ||
195 | // Set the appropriate pending upload or download flag | ||
196 | if (mIsUpload) | ||
197 | { | ||
198 | mAssetStoragep->setPendingUpload(); | ||
199 | } | ||
200 | else if (mIsLocalUpload) | ||
201 | { | ||
202 | mAssetStoragep->setPendingLocalUpload(); | ||
203 | } | ||
204 | else if (mIsDownload) | ||
205 | { | ||
206 | mAssetStoragep->setPendingDownload(); | ||
207 | } | ||
208 | else | ||
209 | { | ||
210 | llerrs << "LLHTTPAssetRequest::setupCurlHandle - Request is not upload OR download, this is bad!" << llendl; | ||
211 | } | ||
212 | } | ||
213 | else | ||
214 | { | ||
215 | llerrs << "LLHTTPAssetRequest::setupCurlHandle - No asset storage associated with this request!" << llendl; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | void LLHTTPAssetRequest::prepareCompressedUpload() | ||
220 | { | ||
221 | mZStream.next_in = Z_NULL; | ||
222 | mZStream.avail_in = 0; | ||
223 | mZStream.zalloc = Z_NULL; | ||
224 | mZStream.zfree = Z_NULL; | ||
225 | mZStream.opaque = Z_NULL; | ||
226 | |||
227 | int r = deflateInit2(&mZStream, | ||
228 | 1, // compression level | ||
229 | Z_DEFLATED, // the only method defined | ||
230 | 15 + 16, // the default windowBits + gzip header flag | ||
231 | 8, // the default memLevel | ||
232 | Z_DEFAULT_STRATEGY); | ||
233 | |||
234 | if (r != Z_OK) | ||
235 | { | ||
236 | llerrs << "LLHTTPAssetRequest::prepareCompressedUpload defalateInit2() failed" << llendl; | ||
237 | } | ||
238 | |||
239 | mZInitialized = true; | ||
240 | mZInputBuffer = new char[COMPRESSED_INPUT_BUFFER_SIZE]; | ||
241 | mZInputExhausted = false; | ||
242 | |||
243 | mVFile = new LLVFile(gAssetStorage->mVFS, | ||
244 | getUUID(), getType(), LLVFile::READ); | ||
245 | } | ||
246 | |||
247 | void LLHTTPAssetRequest::finishCompressedUpload() | ||
248 | { | ||
249 | if (mZInitialized) | ||
250 | { | ||
251 | llinfos << "LLHTTPAssetRequest::finishCompressedUpload: " | ||
252 | << "read " << mZStream.total_in << " byte asset file, " | ||
253 | << "uploaded " << mZStream.total_out << " byte compressed asset" | ||
254 | << llendl; | ||
255 | |||
256 | deflateEnd(&mZStream); | ||
257 | delete[] mZInputBuffer; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | size_t LLHTTPAssetRequest::readCompressedData(void* data, size_t size) | ||
262 | { | ||
263 | mZStream.next_out = (Bytef*)data; | ||
264 | mZStream.avail_out = size; | ||
265 | |||
266 | while (mZStream.avail_out > 0) | ||
267 | { | ||
268 | if (mZStream.avail_in == 0 && !mZInputExhausted) | ||
269 | { | ||
270 | S32 to_read = llmin(COMPRESSED_INPUT_BUFFER_SIZE, | ||
271 | (S32)(mVFile->getSize() - mVFile->tell())); | ||
272 | |||
273 | mVFile->read((U8*)mZInputBuffer, to_read); /*Flawfinder: ignore*/ | ||
274 | |||
275 | mZStream.next_in = (Bytef*)mZInputBuffer; | ||
276 | mZStream.avail_in = mVFile->getLastBytesRead(); | ||
277 | |||
278 | mZInputExhausted = mZStream.avail_in == 0; | ||
279 | } | ||
280 | |||
281 | int r = deflate(&mZStream, | ||
282 | mZInputExhausted ? Z_FINISH : Z_NO_FLUSH); | ||
283 | |||
284 | if (r == Z_STREAM_END) | ||
285 | { | ||
286 | break; | ||
287 | } | ||
288 | } | ||
289 | |||
290 | return size - mZStream.avail_out; | ||
291 | } | ||
292 | |||
293 | //static | ||
294 | size_t LLHTTPAssetRequest::curlCompressedUploadCallback( | ||
295 | void *data, size_t size, size_t nmemb, void *user_data) | ||
296 | { | ||
297 | if (!gAssetStorage) | ||
298 | { | ||
299 | return 0; | ||
300 | } | ||
301 | CURL *curl_handle = (CURL *)user_data; | ||
302 | LLHTTPAssetRequest *req = NULL; | ||
303 | curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, &req); | ||
304 | |||
305 | return req->readCompressedData(data, size * nmemb); | ||
306 | } | ||
307 | |||
308 | ///////////////////////////////////////////////////////////////////////////////// | ||
309 | // LLHTTPAssetStorage | ||
310 | ///////////////////////////////////////////////////////////////////////////////// | ||
311 | |||
312 | |||
313 | LLHTTPAssetStorage::LLHTTPAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, | ||
314 | LLVFS *vfs, const LLHost &upstream_host, | ||
315 | const char *web_host, | ||
316 | const char *local_web_host, | ||
317 | const char *host_name) | ||
318 | : LLAssetStorage(msg, xfer, vfs, upstream_host) | ||
319 | { | ||
320 | _init(web_host, local_web_host, host_name); | ||
321 | } | ||
322 | |||
323 | LLHTTPAssetStorage::LLHTTPAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, | ||
324 | LLVFS *vfs, | ||
325 | const char *web_host, | ||
326 | const char *local_web_host, | ||
327 | const char *host_name) | ||
328 | : LLAssetStorage(msg, xfer, vfs) | ||
329 | { | ||
330 | _init(web_host, local_web_host, host_name); | ||
331 | } | ||
332 | |||
333 | void LLHTTPAssetStorage::_init(const char *web_host, const char *local_web_host, const char* host_name) | ||
334 | { | ||
335 | mBaseURL = web_host; | ||
336 | mLocalBaseURL = local_web_host; | ||
337 | mHostName = host_name; | ||
338 | |||
339 | // Do not change this "unless you are familiar with and mean to control | ||
340 | // internal operations of libcurl" | ||
341 | // - http://curl.haxx.se/libcurl/c/curl_global_init.html | ||
342 | curl_global_init(CURL_GLOBAL_ALL); | ||
343 | |||
344 | mCurlMultiHandle = curl_multi_init(); | ||
345 | |||
346 | mPendingDownload = FALSE; | ||
347 | mPendingUpload = FALSE; | ||
348 | mPendingLocalUpload = FALSE; | ||
349 | } | ||
350 | |||
351 | LLHTTPAssetStorage::~LLHTTPAssetStorage() | ||
352 | { | ||
353 | curl_multi_cleanup(mCurlMultiHandle); | ||
354 | mCurlMultiHandle = NULL; | ||
355 | |||
356 | curl_global_cleanup(); | ||
357 | } | ||
358 | |||
359 | // storing data is simpler than getting it, so we just overload the whole method | ||
360 | void LLHTTPAssetStorage::storeAssetData( | ||
361 | const LLUUID& uuid, | ||
362 | LLAssetType::EType type, | ||
363 | LLAssetStorage::LLStoreAssetCallback callback, | ||
364 | void* user_data, | ||
365 | bool temp_file, | ||
366 | bool is_priority, | ||
367 | bool store_local, | ||
368 | const LLUUID& requesting_agent_id) | ||
369 | { | ||
370 | if (mVFS->getExists(uuid, type)) | ||
371 | { | ||
372 | LLAssetRequest *req = new LLAssetRequest(uuid, type); | ||
373 | req->mUpCallback = callback; | ||
374 | req->mUserData = user_data; | ||
375 | req->mRequestingAgentID = requesting_agent_id; | ||
376 | |||
377 | // this will get picked up and transmitted in checkForTimeouts | ||
378 | if(store_local) | ||
379 | { | ||
380 | mPendingLocalUploads.push_back(req); | ||
381 | } | ||
382 | else if(is_priority) | ||
383 | { | ||
384 | mPendingUploads.push_front(req); | ||
385 | } | ||
386 | else | ||
387 | { | ||
388 | mPendingUploads.push_back(req); | ||
389 | } | ||
390 | } | ||
391 | else | ||
392 | { | ||
393 | llwarns << "AssetStorage: attempt to upload non-existent vfile " << uuid << ":" << LLAssetType::lookup(type) << llendl; | ||
394 | if (callback) | ||
395 | { | ||
396 | callback(uuid, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE ); | ||
397 | } | ||
398 | } | ||
399 | } | ||
400 | |||
401 | // virtual | ||
402 | void LLHTTPAssetStorage::storeAssetData( | ||
403 | const char* filename, | ||
404 | const LLUUID& asset_id, | ||
405 | LLAssetType::EType asset_type, | ||
406 | LLStoreAssetCallback callback, | ||
407 | void* user_data, | ||
408 | bool temp_file, | ||
409 | bool is_priority) | ||
410 | { | ||
411 | llinfos << "LLAssetStorage::storeAssetData (legacy)" << asset_id << ":" << LLAssetType::lookup(asset_type) << llendl; | ||
412 | |||
413 | LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest; | ||
414 | |||
415 | legacy->mUpCallback = callback; | ||
416 | legacy->mUserData = user_data; | ||
417 | |||
418 | FILE *fp = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ | ||
419 | if (fp) | ||
420 | { | ||
421 | LLVFile file(mVFS, asset_id, asset_type, LLVFile::WRITE); | ||
422 | |||
423 | fseek(fp, 0, SEEK_END); | ||
424 | S32 size = ftell(fp); | ||
425 | fseek(fp, 0, SEEK_SET); | ||
426 | |||
427 | file.setMaxSize(size); | ||
428 | |||
429 | const S32 buf_size = 65536; | ||
430 | U8 copy_buf[buf_size]; | ||
431 | while ((size = (S32)fread(copy_buf, 1, buf_size, fp))) | ||
432 | { | ||
433 | file.write(copy_buf, size); | ||
434 | } | ||
435 | fclose(fp); | ||
436 | |||
437 | // if this upload fails, the caller needs to setup a new tempfile for us | ||
438 | if (temp_file) | ||
439 | { | ||
440 | LLFile::remove(filename); | ||
441 | } | ||
442 | |||
443 | storeAssetData( | ||
444 | asset_id, | ||
445 | asset_type, | ||
446 | legacyStoreDataCallback, | ||
447 | (void**)legacy, | ||
448 | temp_file, | ||
449 | is_priority); | ||
450 | } | ||
451 | else | ||
452 | { | ||
453 | if (callback) | ||
454 | { | ||
455 | callback(LLUUID::null, user_data, LL_ERR_CANNOT_OPEN_FILE); | ||
456 | } | ||
457 | } | ||
458 | } | ||
459 | |||
460 | // internal requester, used by getAssetData in superclass | ||
461 | void LLHTTPAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType type, | ||
462 | void (*callback)(LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32), | ||
463 | void *user_data, BOOL duplicate, | ||
464 | BOOL is_priority) | ||
465 | { | ||
466 | // stash the callback info so we can find it after we get the response message | ||
467 | LLAssetRequest *req = new LLAssetRequest(uuid, type); | ||
468 | req->mDownCallback = callback; | ||
469 | req->mUserData = user_data; | ||
470 | req->mIsPriority = is_priority; | ||
471 | |||
472 | // this will get picked up and downloaded in checkForTimeouts | ||
473 | |||
474 | // | ||
475 | // HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACK! Asset requests were taking too long and timing out. | ||
476 | // Since texture requests are the LEAST sensitive (on the simulator) to being delayed, add | ||
477 | // non-texture requests to the front, and add texture requests to the back. The theory is | ||
478 | // that we always want them first, even if they're out of order. | ||
479 | // | ||
480 | |||
481 | if (req->getType() == LLAssetType::AT_TEXTURE) | ||
482 | { | ||
483 | mPendingDownloads.push_back(req); | ||
484 | } | ||
485 | else | ||
486 | { | ||
487 | mPendingDownloads.push_front(req); | ||
488 | } | ||
489 | } | ||
490 | |||
491 | // overloaded to additionally move data to/from the webserver | ||
492 | void LLHTTPAssetStorage::checkForTimeouts() | ||
493 | { | ||
494 | LLAssetRequest *req = NULL; | ||
495 | if (mPendingDownloads.size() > 0 && !mPendingDownload) | ||
496 | { | ||
497 | req = mPendingDownloads.front(); | ||
498 | // Setup this curl download request | ||
499 | // We need to generate a new request here | ||
500 | // since the one in the list could go away | ||
501 | char tmp_url[MAX_STRING]; /*Flawfinder: ignore*/ | ||
502 | char uuid_str[UUID_STR_LENGTH]; /*Flawfinder: ignore*/ | ||
503 | req->getUUID().toString(uuid_str); | ||
504 | std::string base_url = getBaseURL(req->getUUID(), req->getType()); | ||
505 | snprintf(tmp_url, sizeof(tmp_url), "%s/%36s.%s", base_url.c_str() , uuid_str, LLAssetType::lookup(req->getType())); /*Flawfinder: ignore*/ | ||
506 | |||
507 | LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(), req->getType(), tmp_url, mCurlMultiHandle); | ||
508 | new_req->mTmpUUID.generate(); | ||
509 | new_req->mIsDownload = TRUE; | ||
510 | |||
511 | // Sets pending download flag internally | ||
512 | new_req->setupCurlHandle(); | ||
513 | curl_easy_setopt(new_req->mCurlHandle, CURLOPT_FOLLOWLOCATION, TRUE); | ||
514 | curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEFUNCTION, &curlDownCallback); | ||
515 | curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEDATA, new_req->mCurlHandle); | ||
516 | |||
517 | curl_multi_add_handle(mCurlMultiHandle, new_req->mCurlHandle); | ||
518 | llinfos << "Requesting " << new_req->mURLBuffer << llendl; | ||
519 | |||
520 | } | ||
521 | |||
522 | |||
523 | if (mPendingUploads.size() > 0 && !mPendingUpload) | ||
524 | { | ||
525 | req = mPendingUploads.front(); | ||
526 | // setup this curl upload request | ||
527 | |||
528 | bool do_compress = req->getType() == LLAssetType::AT_OBJECT; | ||
529 | |||
530 | char tmp_url[MAX_STRING];/*Flawfinder: ignore*/ | ||
531 | char uuid_str[UUID_STR_LENGTH];/*Flawfinder: ignore*/ | ||
532 | req->getUUID().toString(uuid_str); | ||
533 | snprintf(tmp_url, sizeof(tmp_url), /*Flawfinder: ignore*/ | ||
534 | do_compress ? "%s/%s.%s.gz" : "%s/%s.%s", | ||
535 | mBaseURL.c_str(), uuid_str, LLAssetType::lookup(req->getType())); | ||
536 | |||
537 | LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(), req->getType(), tmp_url, mCurlMultiHandle); | ||
538 | new_req->mIsUpload = TRUE; | ||
539 | if (do_compress) | ||
540 | { | ||
541 | new_req->prepareCompressedUpload(); | ||
542 | } | ||
543 | |||
544 | // Sets pending upload flag internally | ||
545 | new_req->setupCurlHandle(); | ||
546 | curl_easy_setopt(new_req->mCurlHandle, CURLOPT_UPLOAD, 1); | ||
547 | curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEFUNCTION, &nullOutputCallback); | ||
548 | |||
549 | if (do_compress) | ||
550 | { | ||
551 | curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READFUNCTION, | ||
552 | &LLHTTPAssetRequest::curlCompressedUploadCallback); | ||
553 | } | ||
554 | else | ||
555 | { | ||
556 | LLVFile file(mVFS, req->getUUID(), req->getType()); | ||
557 | curl_easy_setopt(new_req->mCurlHandle, CURLOPT_INFILESIZE, file.getSize()); | ||
558 | curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READFUNCTION, | ||
559 | &curlUpCallback); | ||
560 | } | ||
561 | curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READDATA, new_req->mCurlHandle); | ||
562 | |||
563 | curl_multi_add_handle(mCurlMultiHandle, new_req->mCurlHandle); | ||
564 | llinfos << "Requesting PUT " << new_req->mURLBuffer << llendl; | ||
565 | // Pending upload will have been flagged by the request | ||
566 | } | ||
567 | |||
568 | |||
569 | if (mPendingLocalUploads.size() > 0 && !mPendingLocalUpload) | ||
570 | { | ||
571 | req = mPendingLocalUploads.front(); | ||
572 | // setup this curl upload request | ||
573 | LLVFile file(mVFS, req->getUUID(), req->getType()); | ||
574 | |||
575 | char tmp_url[MAX_STRING]; /*Flawfinder: ignore*/ | ||
576 | char uuid_str[UUID_STR_LENGTH]; /*Flawfinder: ignore*/ | ||
577 | req->getUUID().toString(uuid_str); | ||
578 | |||
579 | // KLW - All temporary uploads are saved locally "http://localhost:12041/asset" | ||
580 | snprintf(tmp_url, sizeof(tmp_url), "%s/%36s.%s", mLocalBaseURL.c_str(), uuid_str, LLAssetType::lookup(req->getType())); /*Flawfinder: ignore*/ | ||
581 | |||
582 | LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(), req->getType(), tmp_url, mCurlMultiHandle); | ||
583 | new_req->mIsLocalUpload = TRUE; | ||
584 | new_req->mRequestingAgentID = req->mRequestingAgentID; | ||
585 | |||
586 | // Sets pending upload flag internally | ||
587 | new_req->setupCurlHandle(); | ||
588 | curl_easy_setopt(new_req->mCurlHandle, CURLOPT_PUT, 1); | ||
589 | curl_easy_setopt(new_req->mCurlHandle, CURLOPT_INFILESIZE, file.getSize()); | ||
590 | curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEFUNCTION, &nullOutputCallback); | ||
591 | curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READFUNCTION, &curlUpCallback); | ||
592 | curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READDATA, new_req->mCurlHandle); | ||
593 | |||
594 | curl_multi_add_handle(mCurlMultiHandle, new_req->mCurlHandle); | ||
595 | llinfos << "TAT: LLHTTPAssetStorage::checkForTimeouts() : pending local!" | ||
596 | << " Requesting PUT " << new_req->mURLBuffer << llendl; | ||
597 | // Pending upload will have been flagged by the request | ||
598 | } | ||
599 | S32 count = 0; | ||
600 | CURLMcode mcode; | ||
601 | int queue_length; | ||
602 | do | ||
603 | { | ||
604 | mcode = curl_multi_perform(mCurlMultiHandle, &queue_length); | ||
605 | count++; | ||
606 | } while (mcode == CURLM_CALL_MULTI_PERFORM && (count < 5)); | ||
607 | |||
608 | CURLMsg *curl_msg; | ||
609 | do | ||
610 | { | ||
611 | curl_msg = curl_multi_info_read(mCurlMultiHandle, &queue_length); | ||
612 | if (curl_msg && curl_msg->msg == CURLMSG_DONE) | ||
613 | { | ||
614 | long curl_result = 0; | ||
615 | S32 xfer_result = 0; | ||
616 | |||
617 | LLHTTPAssetRequest *req = NULL; | ||
618 | curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_PRIVATE, &req); | ||
619 | |||
620 | curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_HTTP_CODE, &curl_result); | ||
621 | if (req->mIsUpload || req->mIsLocalUpload) | ||
622 | { | ||
623 | if (curl_msg->data.result == CURLE_OK && (curl_result == HTTP_OK || curl_result == HTTP_PUT_OK || curl_result == HTTP_NO_CONTENT)) | ||
624 | { | ||
625 | llinfos << "Success uploading " << req->getUUID() << " to " << req->mURLBuffer << llendl; | ||
626 | if (req->mIsLocalUpload) | ||
627 | { | ||
628 | addTempAssetData(req->getUUID(), req->mRequestingAgentID, mHostName); | ||
629 | } | ||
630 | } | ||
631 | else if (curl_msg->data.result == CURLE_COULDNT_CONNECT || | ||
632 | curl_msg->data.result == CURLE_OPERATION_TIMEOUTED || | ||
633 | curl_result == HTTP_SERVER_BAD_GATEWAY || | ||
634 | curl_result == HTTP_SERVER_TEMP_UNAVAILABLE) | ||
635 | { | ||
636 | llwarns << "Re-requesting upload for " << req->getUUID() << ". Received upload error to " << req->mURLBuffer << | ||
637 | " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl; | ||
638 | } | ||
639 | else | ||
640 | { | ||
641 | llwarns << "Failure uploading " << req->getUUID() << " to " << req->mURLBuffer << | ||
642 | " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl; | ||
643 | |||
644 | xfer_result = LL_ERR_ASSET_REQUEST_FAILED; | ||
645 | } | ||
646 | |||
647 | if (!(curl_msg->data.result == CURLE_COULDNT_CONNECT || | ||
648 | curl_msg->data.result == CURLE_OPERATION_TIMEOUTED || | ||
649 | curl_result == HTTP_SERVER_BAD_GATEWAY || | ||
650 | curl_result == HTTP_SERVER_TEMP_UNAVAILABLE)) | ||
651 | { | ||
652 | // shared upload finished callback | ||
653 | // in the base class, this is called from processUploadComplete | ||
654 | _callUploadCallbacks(req->getUUID(), req->getType(), (xfer_result == 0)); | ||
655 | // Pending upload flag will get cleared when the request is deleted | ||
656 | } | ||
657 | } | ||
658 | else if (req->mIsDownload) | ||
659 | { | ||
660 | if (curl_result == HTTP_OK && curl_msg->data.result == CURLE_OK) | ||
661 | { | ||
662 | if (req->mVFile && req->mVFile->getSize() > 0) | ||
663 | { | ||
664 | llinfos << "Success downloading " << req->mURLBuffer << ", size " << req->mVFile->getSize() << llendl; | ||
665 | |||
666 | req->mVFile->rename(req->getUUID(), req->getType()); | ||
667 | } | ||
668 | else | ||
669 | { | ||
670 | // TODO: if this actually indicates a bad asset on the server | ||
671 | // (not certain at this point), then delete it | ||
672 | llwarns << "Found " << req->mURLBuffer << " to be zero size" << llendl; | ||
673 | xfer_result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; | ||
674 | } | ||
675 | } | ||
676 | else | ||
677 | { | ||
678 | // KLW - TAT See if an avatar owns this texture, and if so request re-upload. | ||
679 | llwarns << "Failure downloading " << req->mURLBuffer << | ||
680 | " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl; | ||
681 | |||
682 | xfer_result = (curl_result == HTTP_MISSING) ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED; | ||
683 | |||
684 | if (req->mVFile) | ||
685 | { | ||
686 | req->mVFile->remove(); | ||
687 | } | ||
688 | } | ||
689 | |||
690 | // call the static callback for transfer completion | ||
691 | // this will cleanup all requests for this asset, including ours | ||
692 | downloadCompleteCallback( | ||
693 | xfer_result, | ||
694 | req->getUUID(), | ||
695 | req->getType(), | ||
696 | (void *)req); | ||
697 | // Pending download flag will get cleared when the request is deleted | ||
698 | } | ||
699 | else | ||
700 | { | ||
701 | // nothing, just axe this request | ||
702 | // currently this can only mean an asset delete | ||
703 | } | ||
704 | |||
705 | // Deleting clears the pending upload/download flag if it's set and the request is transferring | ||
706 | delete req; | ||
707 | req = NULL; | ||
708 | } | ||
709 | |||
710 | } while (curl_msg && queue_length > 0); | ||
711 | |||
712 | |||
713 | LLAssetStorage::checkForTimeouts(); | ||
714 | } | ||
715 | |||
716 | // static | ||
717 | size_t LLHTTPAssetStorage::curlDownCallback(void *data, size_t size, size_t nmemb, void *user_data) | ||
718 | { | ||
719 | if (!gAssetStorage) | ||
720 | { | ||
721 | llwarns << "Missing gAssetStorage, aborting curl download callback!" << llendl; | ||
722 | return 0; | ||
723 | } | ||
724 | S32 bytes = (S32)(size * nmemb); | ||
725 | CURL *curl_handle = (CURL *)user_data; | ||
726 | LLHTTPAssetRequest *req = NULL; | ||
727 | curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, &req); | ||
728 | |||
729 | if (! req->mVFile) | ||
730 | { | ||
731 | req->mVFile = new LLVFile(gAssetStorage->mVFS, req->mTmpUUID, LLAssetType::AT_NONE, LLVFile::APPEND); | ||
732 | } | ||
733 | |||
734 | double content_length = 0.0; | ||
735 | curl_easy_getinfo(curl_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &content_length); | ||
736 | |||
737 | // sanitize content_length, reconcile w/ actual data | ||
738 | S32 file_length = llmax(0, (S32)llmin(content_length, 20000000.0), bytes + req->mVFile->getSize()); | ||
739 | |||
740 | req->mVFile->setMaxSize(file_length); | ||
741 | req->mVFile->write((U8*)data, bytes); | ||
742 | |||
743 | return nmemb; | ||
744 | } | ||
745 | |||
746 | // static | ||
747 | size_t LLHTTPAssetStorage::curlUpCallback(void *data, size_t size, size_t nmemb, void *user_data) | ||
748 | { | ||
749 | if (!gAssetStorage) | ||
750 | { | ||
751 | llwarns << "Missing gAssetStorage, aborting curl download callback!" << llendl; | ||
752 | return 0; | ||
753 | } | ||
754 | CURL *curl_handle = (CURL *)user_data; | ||
755 | LLHTTPAssetRequest *req = NULL; | ||
756 | curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, &req); | ||
757 | |||
758 | if (! req->mVFile) | ||
759 | { | ||
760 | req->mVFile = new LLVFile(gAssetStorage->mVFS, req->getUUID(), req->getType(), LLVFile::READ); | ||
761 | } | ||
762 | |||
763 | S32 bytes = llmin((S32)(size * nmemb), (S32)(req->mVFile->getSize() - req->mVFile->tell())); | ||
764 | |||
765 | req->mVFile->read((U8*)data, bytes);/*Flawfinder: ignore*/ | ||
766 | |||
767 | return req->mVFile->getLastBytesRead(); | ||
768 | } | ||
769 | |||
770 | // static | ||
771 | size_t LLHTTPAssetStorage::nullOutputCallback(void *data, size_t size, size_t nmemb, void *user_data) | ||
772 | { | ||
773 | // do nothing, this is here to soak up script output so it doesn't end up on stdout | ||
774 | |||
775 | return nmemb; | ||
776 | } | ||
777 | |||
778 | |||
779 | |||
780 | // blocking asset fetch which bypasses the VFS | ||
781 | // this is a very limited function for use by the simstate loader and other one-offs | ||
782 | S32 LLHTTPAssetStorage::getURLToFile(const LLUUID& uuid, LLAssetType::EType asset_type, const LLString &url, const char *filename, progress_callback callback, void *userdata) | ||
783 | { | ||
784 | // *NOTE: There is no guarantee that the uuid and the asset_type match | ||
785 | // - not that it matters. - Doug | ||
786 | lldebugs << "LLHTTPAssetStorage::getURLToFile() - " << url << llendl; | ||
787 | |||
788 | FILE *fp = LLFile::fopen(filename, "wb"); /*Flawfinder: ignore*/ | ||
789 | if (! fp) | ||
790 | { | ||
791 | llwarns << "Failed to open " << filename << " for writing" << llendl; | ||
792 | return LL_ERR_ASSET_REQUEST_FAILED; | ||
793 | } | ||
794 | |||
795 | // make sure we use the normal curl setup, even though we don't really need a request object | ||
796 | LLHTTPAssetRequest req(this, uuid, asset_type, url.c_str(), mCurlMultiHandle); | ||
797 | req.mFP = fp; | ||
798 | req.mIsDownload = TRUE; | ||
799 | |||
800 | req.setupCurlHandle(); | ||
801 | curl_easy_setopt(req.mCurlHandle, CURLOPT_FOLLOWLOCATION, TRUE); | ||
802 | curl_easy_setopt(req.mCurlHandle, CURLOPT_WRITEFUNCTION, &curlFileDownCallback); | ||
803 | curl_easy_setopt(req.mCurlHandle, CURLOPT_WRITEDATA, req.mCurlHandle); | ||
804 | |||
805 | curl_multi_add_handle(mCurlMultiHandle, req.mCurlHandle); | ||
806 | llinfos << "Requesting as file " << req.mURLBuffer << llendl; | ||
807 | |||
808 | // braindead curl loop | ||
809 | int queue_length; | ||
810 | CURLMsg *curl_msg; | ||
811 | LLTimer timeout; | ||
812 | timeout.setTimerExpirySec(GET_URL_TO_FILE_TIMEOUT); | ||
813 | bool success = false; | ||
814 | S32 xfer_result = 0; | ||
815 | do | ||
816 | { | ||
817 | curl_multi_perform(mCurlMultiHandle, &queue_length); | ||
818 | curl_msg = curl_multi_info_read(mCurlMultiHandle, &queue_length); | ||
819 | |||
820 | if (callback) | ||
821 | { | ||
822 | callback(userdata); | ||
823 | } | ||
824 | |||
825 | if ( curl_msg && (CURLMSG_DONE == curl_msg->msg) ) | ||
826 | { | ||
827 | success = true; | ||
828 | } | ||
829 | else if (timeout.hasExpired()) | ||
830 | { | ||
831 | llwarns << "Request for " << url << " has timed out." << llendl; | ||
832 | success = false; | ||
833 | xfer_result = LL_ERR_ASSET_REQUEST_FAILED; | ||
834 | break; | ||
835 | } | ||
836 | } while (!success); | ||
837 | |||
838 | if (success) | ||
839 | { | ||
840 | long curl_result = 0; | ||
841 | curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_HTTP_CODE, &curl_result); | ||
842 | |||
843 | if (curl_result == HTTP_OK && curl_msg->data.result == CURLE_OK) | ||
844 | { | ||
845 | S32 size = ftell(req.mFP); | ||
846 | if (size > 0) | ||
847 | { | ||
848 | // everything seems to be in order | ||
849 | llinfos << "Success downloading " << req.mURLBuffer << " to file, size " << size << llendl; | ||
850 | } | ||
851 | else | ||
852 | { | ||
853 | llwarns << "Found " << req.mURLBuffer << " to be zero size" << llendl; | ||
854 | xfer_result = LL_ERR_ASSET_REQUEST_FAILED; | ||
855 | } | ||
856 | } | ||
857 | else | ||
858 | { | ||
859 | xfer_result = curl_result == HTTP_MISSING ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED; | ||
860 | llinfos << "Failure downloading " << req.mURLBuffer << | ||
861 | " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl; | ||
862 | } | ||
863 | } | ||
864 | |||
865 | fclose(fp); | ||
866 | if (xfer_result) | ||
867 | { | ||
868 | LLFile::remove(filename); | ||
869 | } | ||
870 | return xfer_result; | ||
871 | } | ||
872 | |||
873 | |||
874 | // static | ||
875 | size_t LLHTTPAssetStorage::curlFileDownCallback(void *data, size_t size, size_t nmemb, void *user_data) | ||
876 | { | ||
877 | CURL *curl_handle = (CURL *)user_data; | ||
878 | LLHTTPAssetRequest *req = NULL; | ||
879 | curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, &req); | ||
880 | |||
881 | if (! req->mFP) | ||
882 | { | ||
883 | llwarns << "Missing mFP, aborting curl file download callback!" << llendl; | ||
884 | return 0; | ||
885 | } | ||
886 | |||
887 | return fwrite(data, size, nmemb, req->mFP); | ||
888 | } | ||
889 | |||
890 | // virtual | ||
891 | void LLHTTPAssetStorage::addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name) | ||
892 | { | ||
893 | if (agent_id.isNull() || asset_id.isNull()) | ||
894 | { | ||
895 | llwarns << "TAT: addTempAssetData bad id's asset_id: " << asset_id << " agent_id: " << agent_id << llendl; | ||
896 | return; | ||
897 | } | ||
898 | |||
899 | LLTempAssetData temp_asset_data; | ||
900 | temp_asset_data.mAssetID = asset_id; | ||
901 | temp_asset_data.mAgentID = agent_id; | ||
902 | temp_asset_data.mHostName = host_name; | ||
903 | |||
904 | mTempAssets[asset_id] = temp_asset_data; | ||
905 | } | ||
906 | |||
907 | // virtual | ||
908 | BOOL LLHTTPAssetStorage::hasTempAssetData(const LLUUID& texture_id) const | ||
909 | { | ||
910 | uuid_tempdata_map::const_iterator citer = mTempAssets.find(texture_id); | ||
911 | BOOL found = (citer != mTempAssets.end()); | ||
912 | return found; | ||
913 | } | ||
914 | |||
915 | // virtual | ||
916 | std::string LLHTTPAssetStorage::getTempAssetHostName(const LLUUID& texture_id) const | ||
917 | { | ||
918 | uuid_tempdata_map::const_iterator citer = mTempAssets.find(texture_id); | ||
919 | if (citer != mTempAssets.end()) | ||
920 | { | ||
921 | return citer->second.mHostName; | ||
922 | } | ||
923 | else | ||
924 | { | ||
925 | return std::string(); | ||
926 | } | ||
927 | } | ||
928 | |||
929 | // virtual | ||
930 | LLUUID LLHTTPAssetStorage::getTempAssetAgentID(const LLUUID& texture_id) const | ||
931 | { | ||
932 | uuid_tempdata_map::const_iterator citer = mTempAssets.find(texture_id); | ||
933 | if (citer != mTempAssets.end()) | ||
934 | { | ||
935 | return citer->second.mAgentID; | ||
936 | } | ||
937 | else | ||
938 | { | ||
939 | return LLUUID::null; | ||
940 | } | ||
941 | } | ||
942 | |||
943 | // virtual | ||
944 | void LLHTTPAssetStorage::removeTempAssetData(const LLUUID& asset_id) | ||
945 | { | ||
946 | mTempAssets.erase(asset_id); | ||
947 | } | ||
948 | |||
949 | // virtual | ||
950 | void LLHTTPAssetStorage::removeTempAssetDataByAgentID(const LLUUID& agent_id) | ||
951 | { | ||
952 | uuid_tempdata_map::iterator it = mTempAssets.begin(); | ||
953 | uuid_tempdata_map::iterator end = mTempAssets.end(); | ||
954 | |||
955 | while (it != end) | ||
956 | { | ||
957 | const LLTempAssetData& asset_data = it->second; | ||
958 | if (asset_data.mAgentID == agent_id) | ||
959 | { | ||
960 | mTempAssets.erase(it++); | ||
961 | } | ||
962 | else | ||
963 | { | ||
964 | ++it; | ||
965 | } | ||
966 | } | ||
967 | } | ||
968 | |||
969 | std::string LLHTTPAssetStorage::getBaseURL(const LLUUID& asset_id, LLAssetType::EType asset_type) | ||
970 | { | ||
971 | if (LLAssetType::AT_TEXTURE == asset_type) | ||
972 | { | ||
973 | uuid_tempdata_map::const_iterator citer = mTempAssets.find(asset_id); | ||
974 | if (citer != mTempAssets.end()) | ||
975 | { | ||
976 | const std::string& host_name = citer->second.mHostName; | ||
977 | std::string url = llformat(LOCAL_ASSET_URL_FORMAT, host_name.c_str()); | ||
978 | return url; | ||
979 | } | ||
980 | } | ||
981 | |||
982 | return mBaseURL; | ||
983 | } | ||
984 | |||
985 | void LLHTTPAssetStorage::dumpTempAssetData(const LLUUID& avatar_id) const | ||
986 | { | ||
987 | uuid_tempdata_map::const_iterator it = mTempAssets.begin(); | ||
988 | uuid_tempdata_map::const_iterator end = mTempAssets.end(); | ||
989 | S32 count = 0; | ||
990 | for ( ; it != end; ++it) | ||
991 | { | ||
992 | const LLTempAssetData& temp_asset_data = it->second; | ||
993 | if (avatar_id.isNull() | ||
994 | || avatar_id == temp_asset_data.mAgentID) | ||
995 | { | ||
996 | llinfos << "TAT: dump agent " << temp_asset_data.mAgentID | ||
997 | << " texture " << temp_asset_data.mAssetID | ||
998 | << " host " << temp_asset_data.mHostName | ||
999 | << llendl; | ||
1000 | count++; | ||
1001 | } | ||
1002 | } | ||
1003 | |||
1004 | if (avatar_id.isNull()) | ||
1005 | { | ||
1006 | llinfos << "TAT: dumped " << count << " entries for all avatars" << llendl; | ||
1007 | } | ||
1008 | else | ||
1009 | { | ||
1010 | llinfos << "TAT: dumped " << count << " entries for avatar " << avatar_id << llendl; | ||
1011 | } | ||
1012 | } | ||
1013 | |||
1014 | void LLHTTPAssetStorage::clearTempAssetData() | ||
1015 | { | ||
1016 | llinfos << "TAT: Clearing temp asset data map" << llendl; | ||
1017 | mTempAssets.clear(); | ||
1018 | } | ||
1019 | |||