Merge branch 'master' of git://github.com/AlericInglewood/SingularityViewer

This commit is contained in:
Siana Gearz
2013-01-03 02:17:20 +01:00
58 changed files with 3575 additions and 1462 deletions

View File

@@ -4,9 +4,9 @@ include(Prebuilt)
set(OpenSSL_FIND_QUIETLY ON) set(OpenSSL_FIND_QUIETLY ON)
set(OpenSSL_FIND_REQUIRED ON) set(OpenSSL_FIND_REQUIRED ON)
if (STANDALONE) if (STANDALONE OR USE_SYSTEM_OPENSSL)
include(FindOpenSSL) include(FindOpenSSL)
else (STANDALONE) else (STANDALONE OR USE_SYSTEM_OPENSSL)
use_prebuilt_binary(openSSL) use_prebuilt_binary(openSSL)
if (WINDOWS) if (WINDOWS)
set(OPENSSL_LIBRARIES ssleay32 libeay32) set(OPENSSL_LIBRARIES ssleay32 libeay32)
@@ -14,7 +14,7 @@ else (STANDALONE)
set(OPENSSL_LIBRARIES ssl) set(OPENSSL_LIBRARIES ssl)
endif (WINDOWS) endif (WINDOWS)
set(OPENSSL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include) set(OPENSSL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include)
endif (STANDALONE) endif (STANDALONE OR USE_SYSTEM_OPENSSL)
if (LINUX OR DARWIN) if (LINUX OR DARWIN)
set(CRYPTO_LIBRARIES crypto) set(CRYPTO_LIBRARIES crypto)

View File

@@ -236,8 +236,9 @@ void stop_recording_backtraces(void)
channel_ct backtrace DDCN("BACKTRACE"); //!< This debug channel is used for backtraces. channel_ct backtrace DDCN("BACKTRACE"); //!< This debug channel is used for backtraces.
channel_ct statemachine DDCN("STATEMACHINE"); //!< This debug channel is used for output related to class AIStateMachine. channel_ct statemachine DDCN("STATEMACHINE"); //!< This debug channel is used for output related to class AIStateMachine.
channel_ct caps DDCN("CAPS"); //!< This debug channel is used for output related to Capabilities. channel_ct caps DDCN("CAPS"); //!< This debug channel is used for output related to Capabilities.
channel_ct curl DDCN("CURL"); //!< This debug channel is used for output related to Curl. channel_ct curl DDCN("CURL"); //!< This debug channel is used for output related to AICurl.
channel_ct curlio DDCN("CURLIO"); //!< This debug channel is used to print debug output of libcurl. channel_ct curlio DDCN("CURLIO"); //!< This debug channel is used to print debug output of libcurl. This includes all HTTP network traffic.
channel_ct curltr DDCN("CURLTR"); //!< This debug channel is used to print libcurl API calls.
} // namespace dc } // namespace dc
} // namespace DEBUGCHANNELS } // namespace DEBUGCHANNELS

View File

@@ -207,6 +207,7 @@ extern CWD_API channel_ct statemachine;
extern CWD_API channel_ct caps; extern CWD_API channel_ct caps;
extern CWD_API channel_ct curl; extern CWD_API channel_ct curl;
extern CWD_API channel_ct curlio; extern CWD_API channel_ct curlio;
extern CWD_API channel_ct curltr;
#endif #endif

View File

@@ -206,6 +206,19 @@ U8* LLImageBase::allocateData(S32 size)
// virtual // virtual
U8* LLImageBase::reallocateData(S32 size) U8* LLImageBase::reallocateData(S32 size)
{ {
if (size == -1)
{
size = mWidth * mHeight * mComponents;
if (size <= 0)
{
llerrs << llformat("LLImageBase::reallocateData called with bad dimensions: %dx%dx%d", mWidth, mHeight, (S32)mComponents) << llendl;
}
}
else if (size <= 0 || (size > 4096 * 4096 * 16 && !mAllowOverSize))
{
llerrs << "LLImageBase::reallocateData: bad size: " << size << llendl;
}
if(mData && (mDataSize == size)) if(mData && (mDataSize == size))
return mData; return mData;
@@ -300,6 +313,32 @@ LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components)
++sRawImageCount; ++sRawImageCount;
} }
LLImageRaw::LLImageRaw(LLImageRaw const* src, U16 width, U16 height, U16 crop_offset, bool crop_vertically) : mCacheEntries(0)
{
mMemType = LLMemType::MTYPE_IMAGERAW;
llassert_always(src);
S8 const components = src->getComponents();
U8 const* const data = src->getData();
if (allocateDataSize(width, height, components))
{
if (crop_vertically)
{
llassert_always(width == src->getWidth());
memcpy(getData(), data + width * crop_offset * components, width * height * components);
}
else
{
llassert_always(height == src->getHeight());
U16 const src_width = src->getWidth();
for (U16 row = 0; row < height; ++row)
{
memcpy(getData() + width * row * components, data + (src_width * row + crop_offset) * components, width * components);
}
}
}
++sRawImageCount;
}
/*LLImageRaw::LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only) /*LLImageRaw::LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only)
: LLImageBase(), mCacheEntries(0) : LLImageBase(), mCacheEntries(0)
{ {
@@ -516,7 +555,7 @@ void LLImageRaw::contractToPowerOfTwo(S32 max_dim, BOOL scale_image)
scale( new_width, new_height, scale_image ); scale( new_width, new_height, scale_image );
} }
void LLImageRaw::biasedScaleToPowerOfTwo(S32 max_dim) void LLImageRaw::biasedScaleToPowerOfTwo(S32 target_width, S32 target_height, S32 max_dim)
{ {
// Strong bias towards rounding down (to save bandwidth) // Strong bias towards rounding down (to save bandwidth)
// No bias would mean THRESHOLD == 1.5f; // No bias would mean THRESHOLD == 1.5f;
@@ -525,22 +564,22 @@ void LLImageRaw::biasedScaleToPowerOfTwo(S32 max_dim)
// Find new sizes // Find new sizes
S32 larger_w = max_dim; // 2^n >= mWidth S32 larger_w = max_dim; // 2^n >= mWidth
S32 smaller_w = max_dim; // 2^(n-1) <= mWidth S32 smaller_w = max_dim; // 2^(n-1) <= mWidth
while( (smaller_w > getWidth()) && (smaller_w > MIN_IMAGE_SIZE) ) while( (smaller_w > target_width) && (smaller_w > MIN_IMAGE_SIZE) )
{ {
larger_w = smaller_w; larger_w = smaller_w;
smaller_w >>= 1; smaller_w >>= 1;
} }
S32 new_width = ( (F32)getWidth() / smaller_w > THRESHOLD ) ? larger_w : smaller_w; S32 new_width = ( (F32)target_width / smaller_w > THRESHOLD ) ? larger_w : smaller_w;
S32 larger_h = max_dim; // 2^m >= mHeight S32 larger_h = max_dim; // 2^m >= mHeight
S32 smaller_h = max_dim; // 2^(m-1) <= mHeight S32 smaller_h = max_dim; // 2^(m-1) <= mHeight
while( (smaller_h > getHeight()) && (smaller_h > MIN_IMAGE_SIZE) ) while( (smaller_h > target_height) && (smaller_h > MIN_IMAGE_SIZE) )
{ {
larger_h = smaller_h; larger_h = smaller_h;
smaller_h >>= 1; smaller_h >>= 1;
} }
S32 new_height = ( (F32)getHeight() / smaller_h > THRESHOLD ) ? larger_h : smaller_h; S32 new_height = ( (F32)target_height / smaller_h > THRESHOLD ) ? larger_h : smaller_h;
scale( new_width, new_height ); scale( new_width, new_height );
@@ -943,76 +982,66 @@ BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )
return TRUE; // Nothing to do. return TRUE; // Nothing to do.
} }
// Reallocate the data buffer. U8* old_buffer = NULL;
U8* new_buffer;
S32 const old_width_bytes = old_width * getComponents();
S32 const new_width_bytes = new_width * getComponents();
S32 const min_height = llmin(old_height, new_height);
S32 const min_width_bytes = llmin(old_width_bytes, new_width_bytes);
if (scale_image_data) if (scale_image_data)
{ {
// Vertical if (new_height != old_height)
S32 temp_data_size = old_width * new_height * getComponents();
llassert_always(temp_data_size > 0);
U8* temp_buffer = new (std::nothrow) U8[ temp_data_size ];
if (!temp_buffer )
{ {
llerrs << "Out of memory in LLImageRaw::scale()" << llendl; // Resize vertically.
return FALSE; old_buffer = LLImageBase::release();
new_buffer = allocateDataSize(old_width, new_height, getComponents());
for (S32 col = 0; col < old_width; ++col)
{
copyLineScaled(old_buffer + getComponents() * col, new_buffer + getComponents() * col, old_height, new_height, old_width, old_width);
}
LLImageBase::deleteData(old_buffer);
} }
for( S32 col = 0; col < old_width; col++ ) if (new_width != old_width)
{ {
copyLineScaled( getData() + (getComponents() * col), temp_buffer + (getComponents() * col), old_height, new_height, old_width, old_width ); // Resize horizontally.
old_buffer = LLImageBase::release();
new_buffer = allocateDataSize(new_width, new_height, getComponents());
for (S32 row = 0; row < new_height; ++row)
{
copyLineScaled(old_buffer + old_width_bytes * row, new_buffer + new_width_bytes * row, old_width, new_width, 1, 1);
}
LLImageBase::deleteData(old_buffer);
} }
deleteData();
U8* new_buffer = allocateDataSize(new_width, new_height, getComponents());
// Horizontal
for( S32 row = 0; row < new_height; row++ )
{
copyLineScaled( temp_buffer + (getComponents() * old_width * row), new_buffer + (getComponents() * new_width * row), old_width, new_width, 1, 1 );
}
// Clean up
delete[] temp_buffer;
} }
else else
{ {
// copy out existing image data if (new_width == old_width)
S32 temp_data_size = old_width * old_height * getComponents();
U8* temp_buffer = new (std::nothrow) U8[ temp_data_size ];
if (!temp_buffer)
{ {
llwarns << "Out of memory in LLImageRaw::scale: old (w, h, c) = (" << old_width << ", " << old_height << ", " << (S32)getComponents() << setSize(new_width, new_height, getComponents());
") ; new (w, h, c) = (" << new_width << ", " << new_height << ", " << (S32)getComponents() << ")" << llendl; new_buffer = reallocateData();
return FALSE ;
} }
memcpy(temp_buffer, getData(), temp_data_size); /* Flawfinder: ignore */ else
// allocate new image data, will delete old data
U8* new_buffer = allocateDataSize(new_width, new_height, getComponents());
for( S32 row = 0; row < new_height; row++ )
{ {
if (row < old_height) old_buffer = LLImageBase::release();
new_buffer = allocateDataSize(new_width, new_height, getComponents());
for (S32 row = 0; row < min_height; ++row)
{ {
memcpy(new_buffer + (new_width * row * getComponents()), temp_buffer + (old_width * row * getComponents()), getComponents() * llmin(old_width, new_width)); /* Flawfinder: ignore */ memcpy(new_buffer + row * new_width_bytes, old_buffer + row * old_width_bytes, min_width_bytes);
if (old_width < new_width) if (new_width_bytes > old_width_bytes)
{ {
// pad out rest of row with black // Pad out rest of row with black.
memset(new_buffer + (getComponents() * ((new_width * row) + old_width)), 0, getComponents() * (new_width - old_width)); memset(new_buffer + new_width_bytes * row + old_width_bytes, 0, new_width_bytes - old_width_bytes);
} }
} }
else LLImageBase::deleteData(old_buffer);
{ }
// pad remaining rows with black if (new_height > old_height)
memset(new_buffer + (new_width * row * getComponents()), 0, new_width * getComponents()); {
} // Pad remaining rows with black.
memset(new_buffer + new_width_bytes * min_height, 0, new_width_bytes * (new_height - old_height));
} }
// Clean up
delete[] temp_buffer;
} }
return TRUE ; return TRUE ;
} }

View File

@@ -114,6 +114,8 @@ public:
virtual void deleteData(); virtual void deleteData();
virtual U8* allocateData(S32 size = -1); virtual U8* allocateData(S32 size = -1);
virtual U8* reallocateData(S32 size = -1); virtual U8* reallocateData(S32 size = -1);
static void deleteData(U8* data) { FREE_MEM(sPrivatePoolp, data); }
U8* release() { U8* data = mData; mData = NULL; mDataSize = 0; return data; } // Same as deleteData(), but returns old data. Call deleteData(old_data) to free it.
virtual void dump(); virtual void dump();
virtual void sanityCheck(); virtual void sanityCheck();
@@ -175,12 +177,13 @@ public:
LLImageRaw(); LLImageRaw();
LLImageRaw(U16 width, U16 height, S8 components); LLImageRaw(U16 width, U16 height, S8 components);
LLImageRaw(U8 *data, U16 width, U16 height, S8 components); LLImageRaw(U8 *data, U16 width, U16 height, S8 components);
LLImageRaw(LLImageRaw const* src, U16 width, U16 height, U16 crop_offset, bool crop_vertically);
// Construct using createFromFile (used by tools) // Construct using createFromFile (used by tools)
//LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false); //LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false);
/*virtual*/ void deleteData(); /*virtual*/ void deleteData();
/*virtual*/ U8* allocateData(S32 size = -1); /*virtual*/ U8* allocateData(S32 size = -1);
/*virtual*/ U8* reallocateData(S32 size); /*virtual*/ U8* reallocateData(S32 size = -1);
BOOL resize(U16 width, U16 height, S8 components); BOOL resize(U16 width, U16 height, S8 components);
@@ -194,7 +197,8 @@ public:
void expandToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE); void expandToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE);
void contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE); void contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE);
void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE); void biasedScaleToPowerOfTwo(S32 target_width, S32 target_height, S32 max_dim = MAX_IMAGE_SIZE);
void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE) { biasedScaleToPowerOfTwo(getWidth(), getHeight(), max_dim); }
BOOL scale( S32 new_width, S32 new_height, BOOL scale_image = TRUE ); BOOL scale( S32 new_width, S32 new_height, BOOL scale_image = TRUE );
//BOOL scaleDownWithoutBlending( S32 new_width, S32 new_height) ; //BOOL scaleDownWithoutBlending( S32 new_width, S32 new_height) ;
@@ -287,7 +291,7 @@ public:
// LLImageBase // LLImageBase
/*virtual*/ void deleteData(); /*virtual*/ void deleteData();
/*virtual*/ U8* allocateData(S32 size = -1); /*virtual*/ U8* allocateData(S32 size = -1);
/*virtual*/ U8* reallocateData(S32 size); /*virtual*/ U8* reallocateData(S32 size = -1);
/*virtual*/ void dump(); /*virtual*/ void dump();
/*virtual*/ void sanityCheck(); /*virtual*/ void sanityCheck();

View File

@@ -545,6 +545,9 @@ void CurlEasyHandle::handle_easy_error(CURLcode code)
// Throws AICurlNoEasyHandle. // Throws AICurlNoEasyHandle.
CurlEasyHandle::CurlEasyHandle(void) : mActiveMultiHandle(NULL), mErrorBuffer(NULL), mQueuedForRemoval(false) CurlEasyHandle::CurlEasyHandle(void) : mActiveMultiHandle(NULL), mErrorBuffer(NULL), mQueuedForRemoval(false)
#ifdef DEBUG_CURLIO
, mDebug(false)
#endif
#ifdef SHOW_ASSERT #ifdef SHOW_ASSERT
, mRemovedPerCommand(true) , mRemovedPerCommand(true)
#endif #endif
@@ -588,6 +591,12 @@ CurlEasyHandle::~CurlEasyHandle()
llassert(!mActiveMultiHandle); llassert(!mActiveMultiHandle);
curl_easy_cleanup(mEasyHandle); curl_easy_cleanup(mEasyHandle);
Stats::easy_cleanup_calls++; Stats::easy_cleanup_calls++;
#ifdef DEBUG_CURLIO
if (mDebug)
{
debug_curl_remove_easy(mEasyHandle);
}
#endif
} }
//static //static
@@ -760,17 +769,17 @@ void CurlEasyRequest::setoptString(CURLoption option, std::string const& value)
setopt(option, value.c_str()); setopt(option, value.c_str());
} }
void CurlEasyRequest::setPost(AIPostFieldPtr const& postdata, U32 size) void CurlEasyRequest::setPost(AIPostFieldPtr const& postdata, U32 size, bool keepalive)
{ {
llassert_always(postdata->data()); llassert_always(postdata->data());
DoutCurl("POST size is " << size << " bytes: \"" << libcwd::buf2str(postdata->data(), size) << "\"."); DoutCurl("POST size is " << size << " bytes: \"" << libcwd::buf2str(postdata->data(), size) << "\".");
setPostField(postdata); // Make sure the data stays around until we don't need it anymore. setPostField(postdata); // Make sure the data stays around until we don't need it anymore.
setPost_raw(size, postdata->data()); setPost_raw(size, postdata->data(), keepalive);
} }
void CurlEasyRequest::setPost_raw(U32 size, char const* data) void CurlEasyRequest::setPost_raw(U32 size, char const* data, bool keepalive)
{ {
if (!data) if (!data)
{ {
@@ -780,7 +789,7 @@ void CurlEasyRequest::setPost_raw(U32 size, char const* data)
// The server never replies with 100-continue, so suppress the "Expect: 100-continue" header that libcurl adds by default. // The server never replies with 100-continue, so suppress the "Expect: 100-continue" header that libcurl adds by default.
addHeader("Expect:"); addHeader("Expect:");
if (size > 0) if (size > 0 && keepalive)
{ {
addHeader("Connection: keep-alive"); addHeader("Connection: keep-alive");
addHeader("Keep-alive: 300"); addHeader("Keep-alive: 300");
@@ -1005,6 +1014,8 @@ CURLcode CurlEasyRequest::curlCtxCallback(CURL* curl, void* sslctx, void* parm)
options |= SSL_OP_NO_TLSv1_1; options |= SSL_OP_NO_TLSv1_1;
} }
#else #else
// This is expected when you compile against the headers of a version < 1.0.1 and then link at runtime with version >= 1.0.1.
// Don't do that.
llassert_always(!need_renegotiation_hack); llassert_always(!need_renegotiation_hack);
#endif #endif
SSL_CTX_set_options(ctx, options); SSL_CTX_set_options(ctx, options);
@@ -1225,6 +1236,20 @@ void CurlEasyRequest::removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy
mHandleEventsTarget->removed_from_multi_handle(curl_easy_request_w); mHandleEventsTarget->removed_from_multi_handle(curl_easy_request_w);
} }
void CurlEasyRequest::bad_file_descriptor(AICurlEasyRequest_wat& curl_easy_request_w)
{
if (mHandleEventsTarget)
mHandleEventsTarget->bad_file_descriptor(curl_easy_request_w);
}
#ifdef SHOW_ASSERT
void CurlEasyRequest::queued_for_removal(AICurlEasyRequest_wat& curl_easy_request_w)
{
if (mHandleEventsTarget)
mHandleEventsTarget->queued_for_removal(curl_easy_request_w);
}
#endif
PerHostRequestQueuePtr CurlEasyRequest::getPerHostPtr(void) PerHostRequestQueuePtr CurlEasyRequest::getPerHostPtr(void)
{ {
if (!mPerHostPtr) if (!mPerHostPtr)
@@ -1288,7 +1313,17 @@ void BufferedCurlEasyRequest::timed_out(void)
mResponder->finished(CURLE_OK, HTTP_INTERNAL_ERROR, "Request timeout, aborted.", sChannels, mOutput); mResponder->finished(CURLE_OK, HTTP_INTERNAL_ERROR, "Request timeout, aborted.", sChannels, mOutput);
if (mResponder->needsHeaders()) if (mResponder->needsHeaders())
{ {
send_buffer_events_to(NULL); // Revoke buffer events: we sent them to the responder. send_buffer_events_to(NULL); // Revoke buffer events: we send them to the responder.
}
mResponder = NULL;
}
void BufferedCurlEasyRequest::bad_socket(void)
{
mResponder->finished(CURLE_OK, HTTP_INTERNAL_ERROR, "File descriptor went bad! Aborted.", sChannels, mOutput);
if (mResponder->needsHeaders())
{
send_buffer_events_to(NULL); // Revoke buffer events: we send them to the responder.
} }
mResponder = NULL; mResponder = NULL;
} }
@@ -1408,3 +1443,16 @@ CurlMultiHandle::~CurlMultiHandle()
} }
} // namespace AICurlPrivate } // namespace AICurlPrivate
extern "C" {
// Keep linker happy.
SSL_METHOD *SSLv2_client_method(void)
{
// Never used.
llassert_always(false);
return NULL;
}
}

View File

@@ -208,6 +208,10 @@ struct AICurlEasyHandleEvents {
virtual void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) = 0; virtual void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
virtual void finished(AICurlEasyRequest_wat& curl_easy_request_w) = 0; virtual void finished(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
virtual void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) = 0; virtual void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
virtual void bad_file_descriptor(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
#ifdef SHOW_ASSERT
virtual void queued_for_removal(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
#endif
// Avoid compiler warning. // Avoid compiler warning.
virtual ~AICurlEasyHandleEvents() { } virtual ~AICurlEasyHandleEvents() { }
}; };
@@ -271,6 +275,11 @@ class AICurlEasyRequest {
// Queue a command to remove this request from the multi session (or cancel a queued command to add it). // Queue a command to remove this request from the multi session (or cancel a queued command to add it).
void removeRequest(void); void removeRequest(void);
#ifdef DEBUG_CURLIO
// Turn on/off debug output.
void debug(bool debug) { AICurlEasyRequest_wat(*mBufferedCurlEasyRequest)->debug(debug); }
#endif
private: private:
// The actual pointer to the ThreadSafeBufferedCurlEasyRequest instance. // The actual pointer to the ThreadSafeBufferedCurlEasyRequest instance.
AICurlPrivate::BufferedCurlEasyRequestPtr mBufferedCurlEasyRequest; AICurlPrivate::BufferedCurlEasyRequestPtr mBufferedCurlEasyRequest;

View File

@@ -40,7 +40,8 @@ enum curleasyrequeststatemachine_state_type {
AICurlEasyRequestStateMachine_timedOut, // This must be smaller than the rest, so they always overrule. AICurlEasyRequestStateMachine_timedOut, // This must be smaller than the rest, so they always overrule.
AICurlEasyRequestStateMachine_finished, AICurlEasyRequestStateMachine_finished,
AICurlEasyRequestStateMachine_removed, // The removed states must be largest two, so they are never ignored. AICurlEasyRequestStateMachine_removed, // The removed states must be largest two, so they are never ignored.
AICurlEasyRequestStateMachine_removed_after_finished AICurlEasyRequestStateMachine_removed_after_finished,
AICurlEasyRequestStateMachine_bad_file_descriptor
}; };
char const* AICurlEasyRequestStateMachine::state_str_impl(state_type run_state) const char const* AICurlEasyRequestStateMachine::state_str_impl(state_type run_state) const
@@ -54,6 +55,7 @@ char const* AICurlEasyRequestStateMachine::state_str_impl(state_type run_state)
AI_CASE_RETURN(AICurlEasyRequestStateMachine_finished); AI_CASE_RETURN(AICurlEasyRequestStateMachine_finished);
AI_CASE_RETURN(AICurlEasyRequestStateMachine_removed); AI_CASE_RETURN(AICurlEasyRequestStateMachine_removed);
AI_CASE_RETURN(AICurlEasyRequestStateMachine_removed_after_finished); AI_CASE_RETURN(AICurlEasyRequestStateMachine_removed_after_finished);
AI_CASE_RETURN(AICurlEasyRequestStateMachine_bad_file_descriptor);
} }
return "UNKNOWN STATE"; return "UNKNOWN STATE";
} }
@@ -94,6 +96,24 @@ void AICurlEasyRequestStateMachine::removed_from_multi_handle(AICurlEasyRequest_
set_state(mFinished ? AICurlEasyRequestStateMachine_removed_after_finished : AICurlEasyRequestStateMachine_removed); set_state(mFinished ? AICurlEasyRequestStateMachine_removed_after_finished : AICurlEasyRequestStateMachine_removed);
} }
// CURL-THREAD
void AICurlEasyRequestStateMachine::bad_file_descriptor(AICurlEasyRequest_wat&)
{
if (!mFinished)
{
mFinished = true;
set_state(AICurlEasyRequestStateMachine_bad_file_descriptor);
}
}
#ifdef SHOW_ASSERT
// CURL-THREAD
void AICurlEasyRequestStateMachine::queued_for_removal(AICurlEasyRequest_wat&)
{
llassert(mFinished || mTimedOut); // See AICurlEasyRequestStateMachine::removed_from_multi_handle
}
#endif
void AICurlEasyRequestStateMachine::multiplex_impl(void) void AICurlEasyRequestStateMachine::multiplex_impl(void)
{ {
mSetStateLock.lock(); mSetStateLock.lock();
@@ -207,6 +227,11 @@ void AICurlEasyRequestStateMachine::multiplex_impl(void)
break; break;
} }
case AICurlEasyRequestStateMachine_bad_file_descriptor:
{
AICurlEasyRequest_wat(*mCurlEasyRequest)->bad_socket();
abort();
}
} }
} }

View File

@@ -81,6 +81,14 @@ class AICurlEasyRequestStateMachine : public AIStateMachine, public AICurlEasyHa
// Called after this curl easy handle was removed from a multi handle. // Called after this curl easy handle was removed from a multi handle.
/*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat&); /*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat&);
// Called when the curl thread detected that the socket of this handle has become unusable.
/*virtual*/ void bad_file_descriptor(AICurlEasyRequest_wat&);
#ifdef SHOW_ASSERT
// Called when a command was added to remove this easy handle.
/*virtual*/ void queued_for_removal(AICurlEasyRequest_wat&);
#endif
protected: protected:
// AIStateMachine implementations. // AIStateMachine implementations.

View File

@@ -201,12 +201,19 @@ class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEven
// In case it's added after being removed. // In case it's added after being removed.
void add_queued(void) { mQueuedForRemoval = false; } void add_queued(void) { mQueuedForRemoval = false; }
#ifdef DEBUG_CURLIO
void debug(bool debug) { if (mDebug) debug_curl_remove_easy(mEasyHandle); if (debug) debug_curl_add_easy(mEasyHandle); mDebug = debug; }
#endif
private: private:
CURL* mEasyHandle; CURL* mEasyHandle;
CURLM* mActiveMultiHandle; CURLM* mActiveMultiHandle;
mutable char* mErrorBuffer; mutable char* mErrorBuffer;
AIPostFieldPtr mPostField; // This keeps the POSTFIELD data alive for as long as the easy handle exists. AIPostFieldPtr mPostField; // This keeps the POSTFIELD data alive for as long as the easy handle exists.
bool mQueuedForRemoval; // Set if the easy handle is (probably) added to the multi handle, but is queued for removal. bool mQueuedForRemoval; // Set if the easy handle is (probably) added to the multi handle, but is queued for removal.
#ifdef DEBUG_CURLIO
bool mDebug;
#endif
#ifdef SHOW_ASSERT #ifdef SHOW_ASSERT
public: public:
bool mRemovedPerCommand; // Set if mActiveMultiHandle was reset as per command from the main thread. bool mRemovedPerCommand; // Set if mActiveMultiHandle was reset as per command from the main thread.
@@ -270,11 +277,11 @@ class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEven
// and the CurlEasyRequest destructed. // and the CurlEasyRequest destructed.
class CurlEasyRequest : public CurlEasyHandle { class CurlEasyRequest : public CurlEasyHandle {
private: private:
void setPost_raw(U32 size, char const* data); void setPost_raw(U32 size, char const* data, bool keepalive);
public: public:
void setPost(U32 size) { setPost_raw(size, NULL); } void setPost(U32 size, bool keepalive = true) { setPost_raw(size, NULL, keepalive); }
void setPost(AIPostFieldPtr const& postdata, U32 size); void setPost(AIPostFieldPtr const& postdata, U32 size, bool keepalive = true);
void setPost(char const* data, U32 size) { setPost(new AIPostField(data), size); } void setPost(char const* data, U32 size, bool keepalive = true) { setPost(new AIPostField(data), size, keepalive); }
void setoptString(CURLoption option, std::string const& value); void setoptString(CURLoption option, std::string const& value);
void addHeader(char const* str); void addHeader(char const* str);
void addHeaders(AIHTTPHeaders const& headers); void addHeaders(AIHTTPHeaders const& headers);
@@ -413,6 +420,11 @@ class CurlEasyRequest : public CurlEasyHandle {
/*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w); /*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
/*virtual*/ void finished(AICurlEasyRequest_wat& curl_easy_request_w); /*virtual*/ void finished(AICurlEasyRequest_wat& curl_easy_request_w);
/*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w); /*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
public:
/*virtual*/ void bad_file_descriptor(AICurlEasyRequest_wat& curl_easy_request_w);
#ifdef SHOW_ASSERT
/*virtual*/ void queued_for_removal(AICurlEasyRequest_wat& curl_easy_request_w);
#endif
}; };
// This class adds input/output buffers to the request and hooks up the libcurl callbacks to use those buffers. // This class adds input/output buffers to the request and hooks up the libcurl callbacks to use those buffers.
@@ -431,6 +443,9 @@ class BufferedCurlEasyRequest : public CurlEasyRequest {
// Called if libcurl doesn't deliver within AIHTTPTimeoutPolicy::mMaximumTotalDelay seconds. // Called if libcurl doesn't deliver within AIHTTPTimeoutPolicy::mMaximumTotalDelay seconds.
void timed_out(void); void timed_out(void);
// Called if the underlaying socket went bad (ie, when accidently closed by a buggy library).
void bad_socket(void);
// Called after removed_from_multi_handle was called. // Called after removed_from_multi_handle was called.
void processOutput(void); void processOutput(void);

View File

@@ -286,14 +286,36 @@ enum refresh_t {
empty_and_complete = complete|empty empty_and_complete = complete|empty
}; };
// A class with info for each socket that is in use by curl.
class CurlSocketInfo
{
public:
CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socket_t s, int action, ThreadSafeBufferedCurlEasyRequest* lockobj);
~CurlSocketInfo();
void set_action(int action);
void mark_dead(void) { set_action(CURL_POLL_NONE); mDead = true; }
curl_socket_t getSocketFd(void) const { return mSocketFd; }
AICurlEasyRequest& getEasyRequest(void) { return mEasyRequest; }
private:
MultiHandle& mMultiHandle;
CURL const* mEasy;
curl_socket_t mSocketFd;
int mAction;
bool mDead;
AICurlEasyRequest mEasyRequest;
LLPointer<HTTPTimeout> mTimeout;
};
class PollSet class PollSet
{ {
public: public:
PollSet(void); PollSet(void);
// Add/remove a filedescriptor to/from mFileDescriptors. // Add/remove a filedescriptor to/from mFileDescriptors.
void add(curl_socket_t s); void add(CurlSocketInfo* sp);
void remove(curl_socket_t s); void remove(CurlSocketInfo* sp);
// Copy mFileDescriptors to an internal fd_set that is returned by access(). // Copy mFileDescriptors to an internal fd_set that is returned by access().
// Returns if all fds could be copied (complete) and/or if the resulting fd_set is empty. // Returns if all fds could be copied (complete) and/or if the resulting fd_set is empty.
@@ -307,8 +329,8 @@ class PollSet
curl_socket_t get_max_fd(void) const { return mMaxFdSet; } curl_socket_t get_max_fd(void) const { return mMaxFdSet; }
#endif #endif
// Return true if a filedescriptor is set in mFileDescriptors (used for debugging). // Return a pointer to the corresponding CurlSocketInfo if a filedescriptor is set in mFileDescriptors, or NULL if s is not set.
bool contains(curl_socket_t s) const; CurlSocketInfo* contains(curl_socket_t s) const;
// Return true if a filedescriptor is set in mFdSet. // Return true if a filedescriptor is set in mFdSet.
bool is_set(curl_socket_t s) const; bool is_set(curl_socket_t s) const;
@@ -323,7 +345,7 @@ class PollSet
void next(void); // Advance to next filedescriptor. void next(void); // Advance to next filedescriptor.
private: private:
curl_socket_t* mFileDescriptors; CurlSocketInfo** mFileDescriptors;
int mNrFds; // The number of filedescriptors in the array. int mNrFds; // The number of filedescriptors in the array.
int mNext; // The index of the first file descriptor to start copying, the next call to refresh(). int mNext; // The index of the first file descriptor to start copying, the next call to refresh().
@@ -332,8 +354,8 @@ class PollSet
#if !WINDOWS_CODE #if !WINDOWS_CODE
curl_socket_t mMaxFd; // The largest filedescriptor in the array, or CURL_SOCKET_BAD when it is empty. curl_socket_t mMaxFd; // The largest filedescriptor in the array, or CURL_SOCKET_BAD when it is empty.
curl_socket_t mMaxFdSet; // The largest filedescriptor set in mFdSet by refresh(), or CURL_SOCKET_BAD when it was empty. curl_socket_t mMaxFdSet; // The largest filedescriptor set in mFdSet by refresh(), or CURL_SOCKET_BAD when it was empty.
std::vector<curl_socket_t> mCopiedFileDescriptors; // Filedescriptors copied by refresh to mFdSet. std::vector<CurlSocketInfo*> mCopiedFileDescriptors; // Filedescriptors copied by refresh to mFdSet.
std::vector<curl_socket_t>::iterator mIter; // Index into mCopiedFileDescriptors for next(); loop variable. std::vector<CurlSocketInfo*>::iterator mIter; // Index into mCopiedFileDescriptors for next(); loop variable.
#else #else
unsigned int mIter; // Index into fd_set::fd_array. unsigned int mIter; // Index into fd_set::fd_array.
#endif #endif
@@ -359,7 +381,7 @@ class PollSet
static size_t const MAXSIZE = llmax(1024, FD_SETSIZE); static size_t const MAXSIZE = llmax(1024, FD_SETSIZE);
// Create an empty PollSet. // Create an empty PollSet.
PollSet::PollSet(void) : mFileDescriptors(new curl_socket_t [MAXSIZE]), PollSet::PollSet(void) : mFileDescriptors(new CurlSocketInfo* [MAXSIZE]),
mNrFds(0), mNext(0) mNrFds(0), mNext(0)
#if !WINDOWS_CODE #if !WINDOWS_CODE
, mMaxFd(-1), mMaxFdSet(-1) , mMaxFd(-1), mMaxFdSet(-1)
@@ -369,17 +391,17 @@ PollSet::PollSet(void) : mFileDescriptors(new curl_socket_t [MAXSIZE]),
} }
// Add filedescriptor s to the PollSet. // Add filedescriptor s to the PollSet.
void PollSet::add(curl_socket_t s) void PollSet::add(CurlSocketInfo* sp)
{ {
llassert_always(mNrFds < (int)MAXSIZE); llassert_always(mNrFds < (int)MAXSIZE);
mFileDescriptors[mNrFds++] = s; mFileDescriptors[mNrFds++] = sp;
#if !WINDOWS_CODE #if !WINDOWS_CODE
mMaxFd = llmax(mMaxFd, s); mMaxFd = llmax(mMaxFd, sp->getSocketFd());
#endif #endif
} }
// Remove filedescriptor s from the PollSet. // Remove filedescriptor s from the PollSet.
void PollSet::remove(curl_socket_t s) void PollSet::remove(CurlSocketInfo* sp)
{ {
// The number of open filedescriptors is relatively small, // The number of open filedescriptors is relatively small,
// and on top of that we rather do something CPU intensive // and on top of that we rather do something CPU intensive
@@ -391,15 +413,15 @@ void PollSet::remove(curl_socket_t s)
// back, keeping it compact and keeping the filedescriptors // back, keeping it compact and keeping the filedescriptors
// in the same order (which is supposedly their priority). // in the same order (which is supposedly their priority).
// //
// The general case is where mFileDescriptors contains s at an index // The general case is where mFileDescriptors contains sp at an index
// between 0 and mNrFds: // between 0 and mNrFds:
// mNrFds = 6 // mNrFds = 6
// v // v
// index: 0 1 2 3 4 5 // index: 0 1 2 3 4 5
// a b c s d e // a b c s d e
// This function should never be called unless s is actually in mFileDescriptors, // This function should never be called unless sp is actually in mFileDescriptors,
// as a result of a previous call to PollSet::add(). // as a result of a previous call to PollSet::add(sp).
llassert(mNrFds > 0); llassert(mNrFds > 0);
// Correct mNrFds for when the descriptor is removed. // Correct mNrFds for when the descriptor is removed.
@@ -409,17 +431,18 @@ void PollSet::remove(curl_socket_t s)
// v // v
// index: 0 1 2 3 4 5 // index: 0 1 2 3 4 5
// a b c s d e // a b c s d e
curl_socket_t cur = mFileDescriptors[i]; // cur = 'e' curl_socket_t const s = sp->getSocketFd();
CurlSocketInfo* cur = mFileDescriptors[i]; // cur = 'e'
#if !WINDOWS_CODE #if !WINDOWS_CODE
curl_socket_t max = -1; curl_socket_t max = -1;
#endif #endif
while (cur != s) while (cur != sp)
{ {
llassert(i > 0); llassert(i > 0);
curl_socket_t next = mFileDescriptors[--i]; // next = 'd' CurlSocketInfo* next = mFileDescriptors[--i]; // next = 'd'
mFileDescriptors[i] = cur; // Overwrite 'd' with 'e'. mFileDescriptors[i] = cur; // Overwrite 'd' with 'e'.
#if !WINDOWS_CODE #if !WINDOWS_CODE
max = llmax(max, cur); // max is the maximum value in 'i' or higher. max = llmax(max, cur->getSocketFd()); // max is the maximum value in 'i' or higher.
#endif #endif
cur = next; // cur = 'd' cur = next; // cur = 'd'
// i NrFds = 5 // i NrFds = 5
@@ -427,21 +450,21 @@ void PollSet::remove(curl_socket_t s)
// index: 0 1 2 3 4 // index: 0 1 2 3 4
// a b c s e // cur = 'd' // a b c s e // cur = 'd'
// //
// Next loop iteration: next = 's', overwrite 's' with 'd', cur = 's'; loop terminates. // Next loop iteration: next = 'sp', overwrite 'sp' with 'd', cur = 'sp'; loop terminates.
// i NrFds = 5 // i NrFds = 5
// v v // v v
// index: 0 1 2 3 4 // index: 0 1 2 3 4
// a b c d e // cur = 's' // a b c d e // cur = 'sp'
} }
llassert(cur == s); llassert(cur == sp);
// At this point i was decremented once more and points to the element before the old s. // At this point i was decremented once more and points to the element before the old s.
// i NrFds = 5 // i NrFds = 5
// v v // v v
// index: 0 1 2 3 4 // index: 0 1 2 3 4
// a b c d e // max = llmax('d', 'e') // a b c d e // max = llmax('d', 'e')
// If mNext pointed to an element before s, it should be left alone. Otherwise, if mNext pointed // If mNext pointed to an element before sp, it should be left alone. Otherwise, if mNext pointed
// to s it must now point to 'd', or if it pointed beyond 's' it must be decremented by 1. // to sp it must now point to 'd', or if it pointed beyond 'sp' it must be decremented by 1.
if (mNext > i) // i is where s was. if (mNext > i) // i is where s was.
--mNext; --mNext;
@@ -451,8 +474,8 @@ void PollSet::remove(curl_socket_t s)
{ {
while (i > 0) while (i > 0)
{ {
curl_socket_t next = mFileDescriptors[--i]; CurlSocketInfo* next = mFileDescriptors[--i];
max = llmax(max, next); max = llmax(max, next->getSocketFd());
} }
mMaxFd = max; mMaxFd = max;
llassert(mMaxFd < s); llassert(mMaxFd < s);
@@ -487,12 +510,12 @@ void PollSet::remove(curl_socket_t s)
#endif #endif
} }
bool PollSet::contains(curl_socket_t fd) const CurlSocketInfo* PollSet::contains(curl_socket_t fd) const
{ {
for (int i = 0; i < mNrFds; ++i) for (int i = 0; i < mNrFds; ++i)
if (mFileDescriptors[i] == fd) if (mFileDescriptors[i]->getSocketFd() == fd)
return true; return mFileDescriptors[i];
return false; return NULL;
} }
inline bool PollSet::is_set(curl_socket_t fd) const inline bool PollSet::is_set(curl_socket_t fd) const
@@ -536,7 +559,7 @@ refresh_t PollSet::refresh(void)
// Calculate mMaxFdSet. // Calculate mMaxFdSet.
// Run over FD_SETSIZE - 1 elements, starting at mNext, wrapping to 0 when we reach the end. // Run over FD_SETSIZE - 1 elements, starting at mNext, wrapping to 0 when we reach the end.
int max = -1, i = mNext, count = 0; int max = -1, i = mNext, count = 0;
while (++count < FD_SETSIZE) { max = llmax(max, mFileDescriptors[i]); if (++i == mNrFds) i = 0; } while (++count < FD_SETSIZE) { max = llmax(max, mFileDescriptors[i]->getSocketFd()); if (++i == mNrFds) i = 0; }
mMaxFdSet = max; mMaxFdSet = max;
#endif #endif
} }
@@ -556,7 +579,7 @@ refresh_t PollSet::refresh(void)
mNext = i; mNext = i;
return not_complete_not_empty; return not_complete_not_empty;
} }
FD_SET(mFileDescriptors[i], &mFdSet); FD_SET(mFileDescriptors[i]->getSocketFd(), &mFdSet);
#if !WINDOWS_CODE #if !WINDOWS_CODE
mCopiedFileDescriptors.push_back(mFileDescriptors[i]); mCopiedFileDescriptors.push_back(mFileDescriptors[i]);
#endif #endif
@@ -603,7 +626,7 @@ void PollSet::reset(void)
else else
{ {
mIter = mCopiedFileDescriptors.begin(); mIter = mCopiedFileDescriptors.begin();
if (!FD_ISSET(*mIter, &mFdSet)) if (!FD_ISSET((*mIter)->getSocketFd(), &mFdSet))
next(); next();
} }
#endif #endif
@@ -614,7 +637,7 @@ inline curl_socket_t PollSet::get(void) const
#if WINDOWS_CODE #if WINDOWS_CODE
return (mIter >= mFdSet.fd_count) ? CURL_SOCKET_BAD : mFdSet.fd_array[mIter]; return (mIter >= mFdSet.fd_count) ? CURL_SOCKET_BAD : mFdSet.fd_array[mIter];
#else #else
return (mIter == mCopiedFileDescriptors.end()) ? CURL_SOCKET_BAD : *mIter; return (mIter == mCopiedFileDescriptors.end()) ? CURL_SOCKET_BAD : (*mIter)->getSocketFd();
#endif #endif
} }
@@ -625,7 +648,7 @@ void PollSet::next(void)
++mIter; ++mIter;
#else #else
llassert(mIter != mCopiedFileDescriptors.end()); // Only call next() if the last call to get() didn't return -1. llassert(mIter != mCopiedFileDescriptors.end()); // Only call next() if the last call to get() didn't return -1.
while (++mIter != mCopiedFileDescriptors.end() && !FD_ISSET(*mIter, &mFdSet)); while (++mIter != mCopiedFileDescriptors.end() && !FD_ISSET((*mIter)->getSocketFd(), &mFdSet));
#endif #endif
} }
@@ -743,26 +766,8 @@ std::ostream& operator<<(std::ostream& os, DebugFdSet const& s)
} }
#endif #endif
// A class with info for each socket that is in use by curl.
class CurlSocketInfo
{
public:
CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socket_t s, int action, ThreadSafeBufferedCurlEasyRequest* lockobj);
~CurlSocketInfo();
void set_action(int action);
private:
MultiHandle& mMultiHandle;
CURL const* mEasy;
curl_socket_t mSocketFd;
int mAction;
AICurlEasyRequest mEasyRequest;
LLPointer<HTTPTimeout> mTimeout;
};
CurlSocketInfo::CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socket_t s, int action, ThreadSafeBufferedCurlEasyRequest* lockobj) : CurlSocketInfo::CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socket_t s, int action, ThreadSafeBufferedCurlEasyRequest* lockobj) :
mMultiHandle(multi_handle), mEasy(easy), mSocketFd(s), mAction(CURL_POLL_NONE), mEasyRequest(lockobj) mMultiHandle(multi_handle), mEasy(easy), mSocketFd(s), mAction(CURL_POLL_NONE), mDead(false), mEasyRequest(lockobj)
{ {
llassert(*AICurlEasyRequest_wat(*mEasyRequest) == easy); llassert(*AICurlEasyRequest_wat(*mEasyRequest) == easy);
mMultiHandle.assign(s, this); mMultiHandle.assign(s, this);
@@ -785,23 +790,28 @@ CurlSocketInfo::~CurlSocketInfo()
void CurlSocketInfo::set_action(int action) void CurlSocketInfo::set_action(int action)
{ {
if (mDead)
{
return;
}
Dout(dc::curl, "CurlSocketInfo::set_action(" << action_str(mAction) << " --> " << action_str(action) << ") [" << (void*)mEasyRequest.get_ptr().get() << "]"); Dout(dc::curl, "CurlSocketInfo::set_action(" << action_str(mAction) << " --> " << action_str(action) << ") [" << (void*)mEasyRequest.get_ptr().get() << "]");
int toggle_action = mAction ^ action; int toggle_action = mAction ^ action;
mAction = action; mAction = action;
if ((toggle_action & CURL_POLL_IN)) if ((toggle_action & CURL_POLL_IN))
{ {
if ((action & CURL_POLL_IN)) if ((action & CURL_POLL_IN))
mMultiHandle.mReadPollSet->add(mSocketFd); mMultiHandle.mReadPollSet->add(this);
else else
mMultiHandle.mReadPollSet->remove(mSocketFd); mMultiHandle.mReadPollSet->remove(this);
} }
if ((toggle_action & CURL_POLL_OUT)) if ((toggle_action & CURL_POLL_OUT))
{ {
if ((action & CURL_POLL_OUT)) if ((action & CURL_POLL_OUT))
mMultiHandle.mWritePollSet->add(mSocketFd); mMultiHandle.mWritePollSet->add(this);
else else
{ {
mMultiHandle.mWritePollSet->remove(mSocketFd); mMultiHandle.mWritePollSet->remove(this);
// The following is a bit of a hack, needed because of the lack of proper timeout callbacks in libcurl. // The following is a bit of a hack, needed because of the lack of proper timeout callbacks in libcurl.
// The removal of CURL_POLL_OUT could be part of the SSL handshake, therefore check if we're already connected: // The removal of CURL_POLL_OUT could be part of the SSL handshake, therefore check if we're already connected:
@@ -838,6 +848,9 @@ class AICurlThread : public LLThread
// MAIN-THREAD // MAIN-THREAD
void stop_thread(void) { mRunning = false; wakeup_thread(); } void stop_thread(void) { mRunning = false; wakeup_thread(); }
// MAIN-THREAD
apr_status_t join_thread(void);
protected: protected:
virtual void run(void); virtual void run(void);
void wakeup(AICurlMultiHandle_wat const& multi_handle_w); void wakeup(AICurlMultiHandle_wat const& multi_handle_w);
@@ -1110,6 +1123,17 @@ void AICurlThread::wakeup_thread(void)
#endif #endif
} }
apr_status_t AICurlThread::join_thread(void)
{
apr_status_t retval = APR_SUCCESS;
if (sInstance)
{
apr_thread_join(&retval, sInstance->mAPRThreadp);
delete sInstance;
}
return retval;
}
void AICurlThread::wakeup(AICurlMultiHandle_wat const& multi_handle_w) void AICurlThread::wakeup(AICurlMultiHandle_wat const& multi_handle_w)
{ {
DoutEntering(dc::curl, "AICurlThread::wakeup"); DoutEntering(dc::curl, "AICurlThread::wakeup");
@@ -1255,6 +1279,26 @@ void AICurlThread::process_commands(AICurlMultiHandle_wat const& multi_handle_w)
} }
} }
// Return true if fd is a 'bad' socket.
static bool is_bad(curl_socket_t fd, bool for_writing)
{
fd_set tmp;
FD_ZERO(&tmp);
FD_SET(fd, &tmp);
fd_set* readfds = for_writing ? NULL : &tmp;
fd_set* writefds = for_writing ? &tmp : NULL;
#if !WINDOWS_CODE
int nfds = fd + 1;
#else
int nfds = 64;
#endif
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 10;
int ret = select(nfds, readfds, writefds, NULL, &timeout);
return ret == -1;
}
// The main loop of the curl thread. // The main loop of the curl thread.
void AICurlThread::run(void) void AICurlThread::run(void)
{ {
@@ -1266,7 +1310,7 @@ void AICurlThread::run(void)
{ {
// If mRunning is true then we can only get here if mWakeUpFd != CURL_SOCKET_BAD. // If mRunning is true then we can only get here if mWakeUpFd != CURL_SOCKET_BAD.
llassert(mWakeUpFd != CURL_SOCKET_BAD); llassert(mWakeUpFd != CURL_SOCKET_BAD);
// Copy the next batch of file descriptors from the PollSets mFiledescriptors into their mFdSet. // Copy the next batch of file descriptors from the PollSets mFileDescriptors into their mFdSet.
multi_handle_w->mReadPollSet->refresh(); multi_handle_w->mReadPollSet->refresh();
refresh_t wres = multi_handle_w->mWritePollSet->refresh(); refresh_t wres = multi_handle_w->mWritePollSet->refresh();
// Add wake up fd if any, and pass NULL to select() if a set is empty. // Add wake up fd if any, and pass NULL to select() if a set is empty.
@@ -1383,6 +1427,51 @@ void AICurlThread::run(void)
if (ready == -1) if (ready == -1)
{ {
llwarns << "select() failed: " << errno << ", " << strerror(errno) << llendl; llwarns << "select() failed: " << errno << ", " << strerror(errno) << llendl;
if (errno == EBADF)
{
// Somewhere (fmodex?) one of our file descriptors was closed. Try to recover by finding out which.
llassert_always(!is_bad(mWakeUpFd, false)); // We can't recover from this.
PollSet* found = NULL;
// Run over all read file descriptors.
multi_handle_w->mReadPollSet->refresh();
multi_handle_w->mReadPollSet->reset();
curl_socket_t fd;
while ((fd = multi_handle_w->mReadPollSet->get()) != CURL_SOCKET_BAD)
{
if (is_bad(fd, false))
{
found = multi_handle_w->mReadPollSet;
break;
}
multi_handle_w->mReadPollSet->next();
}
if (!found)
{
// Try all write file descriptors.
refresh_t wres = multi_handle_w->mWritePollSet->refresh();
if (!(wres & empty))
{
multi_handle_w->mWritePollSet->reset();
while ((fd = multi_handle_w->mWritePollSet->get()) != CURL_SOCKET_BAD)
{
if (is_bad(fd, true))
{
found = multi_handle_w->mWritePollSet;
break;
}
multi_handle_w->mWritePollSet->next();
}
}
}
llassert_always(found); // It makes no sense to continue if we can't recover.
// Find the corresponding CurlSocketInfo
CurlSocketInfo* sp = found->contains(fd);
llassert_always(sp); // fd was just *read* from this sp.
sp->mark_dead(); // Make sure it's never used again.
AICurlEasyRequest_wat curl_easy_request_w(*sp->getEasyRequest());
curl_easy_request_w->pause(CURLPAUSE_ALL); // Keep libcurl at bay.
curl_easy_request_w->bad_file_descriptor(curl_easy_request_w); // Make the main thread cleanly terminate this transaction.
}
continue; continue;
} }
// Clock count used for timeouts. // Clock count used for timeouts.
@@ -1822,7 +1911,7 @@ bool HTTPTimeout::data_received(size_t n)
// | | | | | | | | | | | | | | // | | | | | | | | | | | | | |
bool HTTPTimeout::lowspeed(size_t bytes) bool HTTPTimeout::lowspeed(size_t bytes)
{ {
DoutCurlEntering("HTTPTimeout::lowspeed(" << bytes << ")"); //DoutCurlEntering("HTTPTimeout::lowspeed(" << bytes << ")"); commented out... too spammy for normal use.
// The algorithm to determine if we timed out if different from how libcurls CURLOPT_LOW_SPEED_TIME works. // The algorithm to determine if we timed out if different from how libcurls CURLOPT_LOW_SPEED_TIME works.
// //
@@ -2000,12 +2089,11 @@ void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, ch
#if LOWRESTIMER #if LOWRESTIMER
llinfos << "Hostname seems to have been still in the DNS cache." << llendl; llinfos << "Hostname seems to have been still in the DNS cache." << llendl;
#else #else
llwarns << "Huh? Curl returned CURLE_OPERATION_TIMEDOUT, but DNS lookup did not occur according to timings. Expected CURLE_COULDNT_RESOLVE_PROXY or CURLE_COULDNT_RESOLVE_HOST!" << llendl; llwarns << "Curl returned CURLE_OPERATION_TIMEDOUT and DNS lookup did not occur according to timings. Apparently the resolve attempt timed out (bad network?)" << llendl;
llassert(connect_time == 0); llassert(connect_time == 0);
llassert(appconnect_time == 0); llassert(appconnect_time == 0);
llassert(pretransfer_time == 0); llassert(pretransfer_time == 0);
llassert(starttransfer_time == 0); llassert(starttransfer_time == 0);
// Fatal error for diagnostics.
return; return;
#endif #endif
} }
@@ -2028,11 +2116,10 @@ void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, ch
#endif #endif
) )
{ {
llwarns << "Huh? Curl returned CURLE_OPERATION_TIMEDOUT, but connection did not occur according to timings. Expected CURLE_COULDNT_CONNECT!" << llendl; llwarns << "Curl returned CURLE_OPERATION_TIMEDOUT and connection did not occur according to timings: apparently the connect attempt timed out (bad network?)" << llendl;
llassert(appconnect_time == 0); llassert(appconnect_time == 0);
llassert(pretransfer_time == 0); llassert(pretransfer_time == 0);
llassert(starttransfer_time == 0); llassert(starttransfer_time == 0);
// Fatal error for diagnostics.
return; return;
} }
// If connect_time is almost equal to namelookup_time, then it was just set because it was already connected. // If connect_time is almost equal to namelookup_time, then it was just set because it was already connected.
@@ -2148,12 +2235,22 @@ void stopCurlThread(void)
if (AICurlThread::sInstance) if (AICurlThread::sInstance)
{ {
AICurlThread::sInstance->stop_thread(); AICurlThread::sInstance->stop_thread();
int count = 101; int count = 401;
while(--count && !AICurlThread::sInstance->isStopped()) while(--count && !AICurlThread::sInstance->isStopped())
{ {
ms_sleep(10); ms_sleep(10);
} }
Dout(dc::curl, "Curl thread" << (curlThreadIsRunning() ? " not" : "") << " stopped after " << ((100 - count) * 10) << "ms."); if (AICurlThread::sInstance->isStopped())
{
// isStopped() returns true somewhere at the end of run(),
// but that doesn't mean the thread really stopped: it still
// needs to destroy it's static variables.
// If we don't join here, then there is a chance that the
// curl thread will crash when using globals that we (the
// main thread) will have destroyed before it REALLY finished.
AICurlThread::sInstance->join_thread(); // Wait till it is REALLY done.
}
llinfos << "Curl thread" << (curlThreadIsRunning() ? " not" : "") << " stopped after " << ((400 - count) * 10) << "ms." << llendl;
} }
} }
@@ -2174,7 +2271,7 @@ void BufferedCurlEasyRequest::setStatusAndReason(U32 status, std::string const&
AICurlInterface::Stats::status_count[AICurlInterface::Stats::status2index(mStatus)]++; AICurlInterface::Stats::status_count[AICurlInterface::Stats::status2index(mStatus)]++;
// Sanity check. If the server replies with a redirect status then we better have that option turned on! // Sanity check. If the server replies with a redirect status then we better have that option turned on!
if ((status >= 300 && status < 400) && mResponder && !mResponder->followRedir()) if ((status >= 300 && status < 400) && mResponder && !mResponder->redirect_status_ok())
{ {
llerrs << "Received " << status << " (" << reason << ") for responder \"" << mTimeoutPolicy->name() << "\" which has no followRedir()!" << llendl; llerrs << "Received " << status << " (" << reason << ") for responder \"" << mTimeoutPolicy->name() << "\" which has no followRedir()!" << llendl;
} }
@@ -2188,7 +2285,7 @@ void BufferedCurlEasyRequest::processOutput(void)
CURLcode code; CURLcode code;
AITransferInfo info; AITransferInfo info;
getResult(&code, &info); getResult(&code, &info);
if (code == CURLE_OK) if (code == CURLE_OK && mStatus != HTTP_INTERNAL_ERROR)
{ {
getinfo(CURLINFO_RESPONSE_CODE, &responseCode); getinfo(CURLINFO_RESPONSE_CODE, &responseCode);
// If getResult code is CURLE_OK then we should have decoded the first header line ourselves. // If getResult code is CURLE_OK then we should have decoded the first header line ourselves.
@@ -2201,7 +2298,7 @@ void BufferedCurlEasyRequest::processOutput(void)
else else
{ {
responseCode = HTTP_INTERNAL_ERROR; responseCode = HTTP_INTERNAL_ERROR;
responseReason = curl_easy_strerror(code); responseReason = (code == CURLE_OK) ? mReason : std::string(curl_easy_strerror(code));
setopt(CURLOPT_FRESH_CONNECT, TRUE); setopt(CURLOPT_FRESH_CONNECT, TRUE);
} }
@@ -2367,14 +2464,25 @@ size_t BufferedCurlEasyRequest::curlHeaderCallback(char* data, size_t size, size
} }
#if defined(CWDEBUG) || defined(DEBUG_CURLIO) #if defined(CWDEBUG) || defined(DEBUG_CURLIO)
int debug_callback(CURL*, curl_infotype infotype, char* buf, size_t size, void* user_ptr) int debug_callback(CURL* handle, curl_infotype infotype, char* buf, size_t size, void* user_ptr)
{ {
BufferedCurlEasyRequest* request = (BufferedCurlEasyRequest*)user_ptr; BufferedCurlEasyRequest* request = (BufferedCurlEasyRequest*)user_ptr;
if (infotype == CURLINFO_HEADER_OUT && size >= 5 && (strncmp(buf, "GET ", 4) == 0 || strncmp(buf, "HEAD ", 5) == 0))
{
request->mDebugIsHeadOrGetMethod = true;
}
#ifdef DEBUG_CURLIO
if (!debug_curl_print_debug(handle))
{
return 0;
}
#endif
#ifdef CWDEBUG #ifdef CWDEBUG
using namespace ::libcwd; using namespace ::libcwd;
std::ostringstream marker; std::ostringstream marker;
marker << (void*)request->get_lockobj(); marker << (void*)request->get_lockobj() << ' ';
libcw_do.push_marker(); libcw_do.push_marker();
libcw_do.marker().assign(marker.str().data(), marker.str().size()); libcw_do.marker().assign(marker.str().data(), marker.str().size());
if (!debug::channels::dc::curlio.is_on()) if (!debug::channels::dc::curlio.is_on())
@@ -2398,8 +2506,6 @@ int debug_callback(CURL*, curl_infotype infotype, char* buf, size_t size, void*
break; break;
case CURLINFO_HEADER_OUT: case CURLINFO_HEADER_OUT:
LibcwDoutStream << "H< "; LibcwDoutStream << "H< ";
if (size >= 5 && (strncmp(buf, "GET ", 4) == 0 || strncmp(buf, "HEAD ", 5) == 0))
request->mDebugIsHeadOrGetMethod = true;
break; break;
case CURLINFO_DATA_IN: case CURLINFO_DATA_IN:
LibcwDoutStream << "D> "; LibcwDoutStream << "D> ";
@@ -2573,6 +2679,14 @@ void AICurlEasyRequest::removeRequest(void)
} }
} }
} }
{
AICurlEasyRequest_wat curl_easy_request_w(*get());
// As soon as the lock on the command queue is released, it could be picked up by
// the curl thread and executed. At that point it (already) demands that the easy
// request either timed out or is finished. So, to avoid race conditions that already
// has to be true right now. The call to queued_for_removal() checks this.
curl_easy_request_w->queued_for_removal(curl_easy_request_w);
}
#endif #endif
// Add a command to remove this request from the multi session to the command queue. // Add a command to remove this request from the multi session to the command queue.
command_queue_w->push_back(Command(*this, cmd_remove)); command_queue_w->push_back(Command(*this, cmd_remove));

View File

@@ -107,6 +107,20 @@ void AIHTTPReceivedHeaders::addHeader(std::string const& key, std::string const&
{ {
mContainer = new Container; mContainer = new Container;
} }
else if (equal(key, "set-cookie"))
{
// If a cookie with this name already exists, replace it.
std::string const name = value.substr(0, value.find('='));
container_t::iterator const end = mContainer->mKeyValuePairs.end();
for (container_t::iterator header = mContainer->mKeyValuePairs.begin(); header != end; ++header)
{
if (equal(header->first, "set-cookie") && header->second.substr(0, header->second.find('=')) == name)
{
header->second = value;
return;
}
}
}
mContainer->mKeyValuePairs.insert(container_t::value_type(key, value)); mContainer->mKeyValuePairs.insert(container_t::value_type(key, value));
} }
@@ -151,3 +165,20 @@ std::ostream& operator<<(std::ostream& os, AIHTTPReceivedHeaders const& headers)
return os; return os;
} }
//static
bool AIHTTPReceivedHeaders::equal(std::string const& key1, std::string const& key2)
{
if (key1.length() != key2.length())
{
return false;
}
for (std::string::const_iterator i1 = key1.begin(), i2 = key2.begin(); i1 != key1.end(); ++i1, ++i2)
{
if ((*i1 ^ *i2) & 0xdf != 0)
{
return false;
}
}
return true;
}

View File

@@ -132,6 +132,9 @@ class AIHTTPReceivedHeaders {
// Add a header. // Add a header.
void addHeader(std::string const& key, std::string const& value); void addHeader(std::string const& key, std::string const& value);
// Swap headers with another container.
void swap(AIHTTPReceivedHeaders& headers) { LLPointer<Container>::swap(mContainer, headers.mContainer); }
// Return true if there are no headers associated with this object. // Return true if there are no headers associated with this object.
bool empty(void) const { return !mContainer || mContainer->mKeyValuePairs.empty(); } bool empty(void) const { return !mContainer || mContainer->mKeyValuePairs.empty(); }
@@ -147,6 +150,9 @@ class AIHTTPReceivedHeaders {
// For debug purposes. // For debug purposes.
friend std::ostream& operator<<(std::ostream& os, AIHTTPReceivedHeaders const& headers); friend std::ostream& operator<<(std::ostream& os, AIHTTPReceivedHeaders const& headers);
// Returns true if the two keys compare equal (ie, "Set-Cookie" == "set-cookie").
static bool equal(std::string const& key1, std::string const& key2);
private: private:
struct Container : public LLThreadSafeRefCount { struct Container : public LLThreadSafeRefCount {
container_t mKeyValuePairs; container_t mKeyValuePairs;

View File

@@ -6,6 +6,7 @@
#include <cstdlib> #include <cstdlib>
#include <stdarg.h> #include <stdarg.h>
#include <cstring> #include <cstring>
#include <algorithm>
#include "llpreprocessor.h" #include "llpreprocessor.h"
#include <curl/curl.h> #include <curl/curl.h>
#define COMPILING_DEBUG_LIBCURL_CC #define COMPILING_DEBUG_LIBCURL_CC
@@ -528,19 +529,66 @@ std::ostream& operator<<(std::ostream& os, EvBitmask const& bitmask)
return os; return os;
} }
// Set this to limit the curl debug output to specific easy handles.
bool gDebugCurlTerse = false;
namespace {
std::vector<CURL*> handles;
inline bool print_debug(CURL* handle)
{
if (!gDebugCurlTerse)
return true;
return std::find(handles.begin(), handles.end(), handle) != handles.end();
}
} // namespace
void debug_curl_add_easy(CURL* handle)
{
std::vector<CURL*>::iterator iter = std::find(handles.begin(), handles.end(), handle);
if (iter == handles.end())
{
handles.push_back(handle);
Dout(dc::warning, "debug_curl_add_easy(" << (void*)handle << "): added");
}
llassert(print_debug(handle));
}
void debug_curl_remove_easy(CURL* handle)
{
std::vector<CURL*>::iterator iter = std::find(handles.begin(), handles.end(), handle);
if (iter != handles.end())
{
handles.erase(iter);
Dout(dc::warning, "debug_curl_remove_easy(" << (void*)handle << "): removed");
}
llassert(!print_debug(handle));
}
bool debug_curl_print_debug(CURL* handle)
{
return print_debug(handle);
}
extern "C" { extern "C" {
void debug_curl_easy_cleanup(CURL* handle) void debug_curl_easy_cleanup(CURL* handle)
{ {
curl_easy_cleanup(handle); curl_easy_cleanup(handle);
Dout(dc::curl, "curl_easy_cleanup(" << (AICURL*)handle << ")"); if (print_debug(handle))
{
Dout(dc::curltr, "curl_easy_cleanup(" << (AICURL*)handle << ")");
}
} }
CURL* debug_curl_easy_duphandle(CURL* handle) CURL* debug_curl_easy_duphandle(CURL* handle)
{ {
CURL* ret; CURL* ret;
ret = curl_easy_duphandle(handle); ret = curl_easy_duphandle(handle);
Dout(dc::curl, "curl_easy_duphandle(" << (AICURL*)handle << ") = " << (AICURL*)ret); if (!print_debug(handle)) return ret;
Dout(dc::curltr, "curl_easy_duphandle(" << (AICURL*)handle << ") = " << (AICURL*)ret);
return ret; return ret;
} }
@@ -548,11 +596,12 @@ char* debug_curl_easy_escape(CURL* curl, char* url, int length)
{ {
char* ret; char* ret;
ret = curl_easy_escape(curl, url, length); ret = curl_easy_escape(curl, url, length);
Dout(dc::curl, "curl_easy_escape(" << (AICURL*)curl << ", \"" << url << "\", " << length << ") = \"" << ret << '"'); if (!print_debug(curl)) return ret;
Dout(dc::curltr, "curl_easy_escape(" << (AICURL*)curl << ", \"" << url << "\", " << length << ") = \"" << ret << '"');
return ret; return ret;
} }
CURLcode debug_curl_easy_getinfo(CURL* curl, CURLINFO info, ...) CURLcode debug_curl_easy_getinfo(CURL* handle, CURLINFO info, ...)
{ {
CURLcode ret; CURLcode ret;
va_list ap; va_list ap;
@@ -566,26 +615,27 @@ CURLcode debug_curl_easy_getinfo(CURL* curl, CURLINFO info, ...)
va_start(ap, info); va_start(ap, info);
param.some_ptr = va_arg(ap, void*); param.some_ptr = va_arg(ap, void*);
va_end(ap); va_end(ap);
ret = curl_easy_getinfo(curl, info, param.some_ptr); ret = curl_easy_getinfo(handle, info, param.some_ptr);
if (!print_debug(handle)) return ret;
if (info == CURLINFO_PRIVATE) if (info == CURLINFO_PRIVATE)
{ {
Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", 0x" << std::hex << (size_t)param.some_ptr << std::dec << ") = " << ret); Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", 0x" << std::hex << (size_t)param.some_ptr << std::dec << ") = " << ret);
} }
else else
{ {
switch((info & CURLINFO_TYPEMASK)) switch((info & CURLINFO_TYPEMASK))
{ {
case CURLINFO_STRING: case CURLINFO_STRING:
Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", (char**){ \"" << (ret == CURLE_OK ? *param.char_ptr : " <unchanged> ") << "\" }) = " << ret); Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", (char**){ \"" << (ret == CURLE_OK ? *param.char_ptr : " <unchanged> ") << "\" }) = " << ret);
break; break;
case CURLINFO_LONG: case CURLINFO_LONG:
Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", (long*){ " << (ret == CURLE_OK ? *param.long_ptr : 0L) << "L }) = " << ret); Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", (long*){ " << (ret == CURLE_OK ? *param.long_ptr : 0L) << "L }) = " << ret);
break; break;
case CURLINFO_DOUBLE: case CURLINFO_DOUBLE:
Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", (double*){" << (ret == CURLE_OK ? *param.double_ptr : 0.) << "}) = " << ret); Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", (double*){" << (ret == CURLE_OK ? *param.double_ptr : 0.) << "}) = " << ret);
break; break;
case CURLINFO_SLIST: case CURLINFO_SLIST:
Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", (curl_slist**){ " << (ret == CURLE_OK ? **param.curl_slist_ptr : unchanged_slist) << " }) = " << ret); Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", (curl_slist**){ " << (ret == CURLE_OK ? **param.curl_slist_ptr : unchanged_slist) << " }) = " << ret);
break; break;
} }
} }
@@ -596,7 +646,8 @@ CURL* debug_curl_easy_init(void)
{ {
CURL* ret; CURL* ret;
ret = curl_easy_init(); ret = curl_easy_init();
Dout(dc::curl, "curl_easy_init() = " << (AICURL*)ret); if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_easy_init() = " << (AICURL*)ret);
return ret; return ret;
} }
@@ -604,7 +655,8 @@ CURLcode debug_curl_easy_pause(CURL* handle, int bitmask)
{ {
CURLcode ret; CURLcode ret;
ret = curl_easy_pause(handle, bitmask); ret = curl_easy_pause(handle, bitmask);
Dout(dc::curl, "curl_easy_pause(" << (AICURL*)handle << ", 0x" << std::hex << bitmask << std::dec << ") = " << ret); if (!print_debug(handle)) return ret;
Dout(dc::curltr, "curl_easy_pause(" << (AICURL*)handle << ", 0x" << std::hex << bitmask << std::dec << ") = " << ret);
return ret; return ret;
} }
@@ -612,19 +664,21 @@ CURLcode debug_curl_easy_perform(CURL* handle)
{ {
CURLcode ret; CURLcode ret;
ret = curl_easy_perform(handle); ret = curl_easy_perform(handle);
Dout(dc::curl, "curl_easy_perform(" << (AICURL*)handle << ") = " << ret); if (!print_debug(handle)) return ret;
Dout(dc::curltr, "curl_easy_perform(" << (AICURL*)handle << ") = " << ret);
return ret; return ret;
} }
void debug_curl_easy_reset(CURL* handle) void debug_curl_easy_reset(CURL* handle)
{ {
curl_easy_reset(handle); curl_easy_reset(handle);
Dout(dc::curl, "curl_easy_reset(" << (AICURL*)handle << ")"); if (!print_debug(handle)) return;
Dout(dc::curltr, "curl_easy_reset(" << (AICURL*)handle << ")");
} }
CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...) CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...)
{ {
CURLcode ret = CURLE_UNKNOWN_OPTION; // Suppress compiler warning. CURLcode ret = CURLE_OBSOLETE50; // Suppress compiler warning.
va_list ap; va_list ap;
union param_type { union param_type {
long along; long along;
@@ -656,7 +710,10 @@ CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...)
case CURLOPTTYPE_LONG: case CURLOPTTYPE_LONG:
{ {
ret = curl_easy_setopt(handle, option, param.along); ret = curl_easy_setopt(handle, option, param.along);
Dout(dc::curl, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", " << param.along << "L) = " << ret); if (print_debug(handle))
{
Dout(dc::curltr, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", " << param.along << "L) = " << ret);
}
if (option == CURLOPT_POSTFIELDSIZE) if (option == CURLOPT_POSTFIELDSIZE)
{ {
postfieldsize = param.along; postfieldsize = param.along;
@@ -666,7 +723,8 @@ CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...)
case CURLOPTTYPE_OBJECTPOINT: case CURLOPTTYPE_OBJECTPOINT:
{ {
ret = curl_easy_setopt(handle, option, param.ptr); ret = curl_easy_setopt(handle, option, param.ptr);
LibcwDoutScopeBegin(LIBCWD_DEBUGCHANNELS, libcwd::libcw_do, dc::curl) if (!print_debug(handle)) break;
LibcwDoutScopeBegin(LIBCWD_DEBUGCHANNELS, libcwd::libcw_do, dc::curltr)
LibcwDoutStream << "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", "; LibcwDoutStream << "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", ";
// For a subset of all options that take a char*, print the string passed. // For a subset of all options that take a char*, print the string passed.
if (option == CURLOPT_PROXY || // Set HTTP proxy to use. The parameter should be a char* to a zero terminated string holding the host name or dotted IP address. if (option == CURLOPT_PROXY || // Set HTTP proxy to use. The parameter should be a char* to a zero terminated string holding the host name or dotted IP address.
@@ -717,11 +775,11 @@ CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...)
if (option == CURLOPT_HTTPHEADER && param.ptr) if (option == CURLOPT_HTTPHEADER && param.ptr)
{ {
debug::Indent indent(2); debug::Indent indent(2);
Dout(dc::curl, "HTTP Headers:"); Dout(dc::curltr, "HTTP Headers:");
struct curl_slist* list = (struct curl_slist*)param.ptr; struct curl_slist* list = (struct curl_slist*)param.ptr;
while (list) while (list)
{ {
Dout(dc::curl, '"' << list->data << '"'); Dout(dc::curltr, '"' << list->data << '"');
list = list->next; list = list->next;
} }
} }
@@ -729,12 +787,18 @@ CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...)
} }
case CURLOPTTYPE_FUNCTIONPOINT: case CURLOPTTYPE_FUNCTIONPOINT:
ret = curl_easy_setopt(handle, option, param.ptr); ret = curl_easy_setopt(handle, option, param.ptr);
Dout(dc::curl, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", (function*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret); if (print_debug(handle))
{
Dout(dc::curltr, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", (function*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret);
}
break; break;
case CURLOPTTYPE_OFF_T: case CURLOPTTYPE_OFF_T:
{ {
ret = curl_easy_setopt(handle, option, param.offset); ret = curl_easy_setopt(handle, option, param.offset);
Dout(dc::curl, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", (curl_off_t)" << param.offset << ") = " << ret); if (print_debug(handle))
{
Dout(dc::curltr, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", (curl_off_t)" << param.offset << ") = " << ret);
}
if (option == CURLOPT_POSTFIELDSIZE_LARGE) if (option == CURLOPT_POSTFIELDSIZE_LARGE)
{ {
postfieldsize = (long)param.offset; postfieldsize = (long)param.offset;
@@ -751,7 +815,8 @@ char const* debug_curl_easy_strerror(CURLcode errornum)
{ {
char const* ret; char const* ret;
ret = curl_easy_strerror(errornum); ret = curl_easy_strerror(errornum);
Dout(dc::curl, "curl_easy_strerror(" << errornum << ") = \"" << ret << '"'); if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_easy_strerror(" << errornum << ") = \"" << ret << '"');
return ret; return ret;
} }
@@ -759,35 +824,38 @@ char* debug_curl_easy_unescape(CURL* curl, char* url, int inlength, int* outleng
{ {
char* ret; char* ret;
ret = curl_easy_unescape(curl, url, inlength, outlength); ret = curl_easy_unescape(curl, url, inlength, outlength);
Dout(dc::curl, "curl_easy_unescape(" << (AICURL*)curl << ", \"" << url << "\", " << inlength << ", " << ((ret && outlength) ? *outlength : 1) << ") = \"" << ret << '"'); if (!print_debug(curl)) return ret;
Dout(dc::curltr, "curl_easy_unescape(" << (AICURL*)curl << ", \"" << url << "\", " << inlength << ", " << ((ret && outlength) ? *outlength : 1) << ") = \"" << ret << '"');
return ret; return ret;
} }
void debug_curl_free(char* ptr) void debug_curl_free(char* ptr)
{ {
curl_free(ptr); curl_free(ptr);
Dout(dc::curl, "curl_free(0x" << std::hex << (size_t)ptr << std::dec << ")"); if (gDebugCurlTerse) return;
Dout(dc::curltr, "curl_free(0x" << std::hex << (size_t)ptr << std::dec << ")");
} }
time_t debug_curl_getdate(char const* datestring, time_t* now) time_t debug_curl_getdate(char const* datestring, time_t* now)
{ {
time_t ret; time_t ret;
ret = curl_getdate(datestring, now); ret = curl_getdate(datestring, now);
Dout(dc::curl, "curl_getdate(\"" << datestring << "\", " << (now == NULL ? "NULL" : "<erroneous non-NULL value for 'now'>") << ") = " << ret); if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_getdate(\"" << datestring << "\", " << (now == NULL ? "NULL" : "<erroneous non-NULL value for 'now'>") << ") = " << ret);
return ret; return ret;
} }
void debug_curl_global_cleanup(void) void debug_curl_global_cleanup(void)
{ {
curl_global_cleanup(); curl_global_cleanup();
Dout(dc::curl, "curl_global_cleanup()"); Dout(dc::curltr, "curl_global_cleanup()");
} }
CURLcode debug_curl_global_init(long flags) CURLcode debug_curl_global_init(long flags)
{ {
CURLcode ret; CURLcode ret;
ret = curl_global_init(flags); ret = curl_global_init(flags);
Dout(dc::curl, "curl_global_init(0x" << std::hex << flags << std::dec << ") = " << ret); Dout(dc::curltr, "curl_global_init(0x" << std::hex << flags << std::dec << ") = " << ret);
return ret; return ret;
} }
@@ -795,7 +863,8 @@ CURLMcode debug_curl_multi_add_handle(CURLM* multi_handle, CURL* easy_handle)
{ {
CURLMcode ret; CURLMcode ret;
ret = curl_multi_add_handle(multi_handle, easy_handle); ret = curl_multi_add_handle(multi_handle, easy_handle);
Dout(dc::curl, "curl_multi_add_handle(" << (AICURLM*)multi_handle << ", " << (AICURL*)easy_handle << ") = " << ret); if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_multi_add_handle(" << (AICURLM*)multi_handle << ", " << (AICURL*)easy_handle << ") = " << ret);
return ret; return ret;
} }
@@ -803,7 +872,8 @@ CURLMcode debug_curl_multi_assign(CURLM* multi_handle, curl_socket_t sockfd, voi
{ {
CURLMcode ret; CURLMcode ret;
ret = curl_multi_assign(multi_handle, sockfd, sockptr); ret = curl_multi_assign(multi_handle, sockfd, sockptr);
Dout(dc::curl, "curl_multi_assign(" << (AICURLM*)multi_handle << ", " << Socket(sockfd) << ", " << sockptr << ") = " << ret); if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_multi_assign(" << (AICURLM*)multi_handle << ", " << Socket(sockfd) << ", " << sockptr << ") = " << ret);
return ret; return ret;
} }
@@ -811,7 +881,8 @@ CURLMcode debug_curl_multi_cleanup(CURLM* multi_handle)
{ {
CURLMcode ret; CURLMcode ret;
ret = curl_multi_cleanup(multi_handle); ret = curl_multi_cleanup(multi_handle);
Dout(dc::curl, "curl_multi_cleanup(" << (AICURLM*)multi_handle << ") = " << ret); if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_multi_cleanup(" << (AICURLM*)multi_handle << ") = " << ret);
return ret; return ret;
} }
@@ -819,7 +890,8 @@ CURLMsg* debug_curl_multi_info_read(CURLM* multi_handle, int* msgs_in_queue)
{ {
CURLMsg* ret; CURLMsg* ret;
ret = curl_multi_info_read(multi_handle, msgs_in_queue); ret = curl_multi_info_read(multi_handle, msgs_in_queue);
Dout(dc::curl, "curl_multi_info_read(" << (AICURLM*)multi_handle << ", {" << *msgs_in_queue << "}) = " << ret); if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_multi_info_read(" << (AICURLM*)multi_handle << ", {" << *msgs_in_queue << "}) = " << ret);
return ret; return ret;
} }
@@ -827,7 +899,8 @@ CURLM* debug_curl_multi_init(void)
{ {
CURLM* ret; CURLM* ret;
ret = curl_multi_init(); ret = curl_multi_init();
Dout(dc::curl, "curl_multi_init() = " << (AICURLM*)ret); if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_multi_init() = " << (AICURLM*)ret);
return ret; return ret;
} }
@@ -835,7 +908,8 @@ CURLMcode debug_curl_multi_remove_handle(CURLM* multi_handle, CURL* easy_handle)
{ {
CURLMcode ret; CURLMcode ret;
ret = curl_multi_remove_handle(multi_handle, easy_handle); ret = curl_multi_remove_handle(multi_handle, easy_handle);
Dout(dc::curl, "curl_multi_remove_handle(" << (AICURLM*)multi_handle << ", " << (AICURL*)easy_handle << ") = " << ret); if (!print_debug(easy_handle)) return ret;
Dout(dc::curltr, "curl_multi_remove_handle(" << (AICURLM*)multi_handle << ", " << (AICURL*)easy_handle << ") = " << ret);
return ret; return ret;
} }
@@ -871,19 +945,23 @@ CURLMcode debug_curl_multi_setopt(CURLM* multi_handle, CURLMoption option, ...)
{ {
case CURLOPTTYPE_LONG: case CURLOPTTYPE_LONG:
ret = curl_multi_setopt(multi_handle, option, param.along); ret = curl_multi_setopt(multi_handle, option, param.along);
Dout(dc::curl, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", " << param.along << "L) = " << ret); if (gDebugCurlTerse) break;
Dout(dc::curltr, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", " << param.along << "L) = " << ret);
break; break;
case CURLOPTTYPE_OBJECTPOINT: case CURLOPTTYPE_OBJECTPOINT:
ret = curl_multi_setopt(multi_handle, option, param.ptr); ret = curl_multi_setopt(multi_handle, option, param.ptr);
Dout(dc::curl, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (object*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret); if (gDebugCurlTerse) break;
Dout(dc::curltr, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (object*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret);
break; break;
case CURLOPTTYPE_FUNCTIONPOINT: case CURLOPTTYPE_FUNCTIONPOINT:
ret = curl_multi_setopt(multi_handle, option, param.ptr); ret = curl_multi_setopt(multi_handle, option, param.ptr);
Dout(dc::curl, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (function*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret); if (gDebugCurlTerse) break;
Dout(dc::curltr, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (function*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret);
break; break;
case CURLOPTTYPE_OFF_T: case CURLOPTTYPE_OFF_T:
ret = curl_multi_setopt(multi_handle, option, param.offset); ret = curl_multi_setopt(multi_handle, option, param.offset);
Dout(dc::curl, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (curl_off_t)" << param.offset << ") = " << ret); if (gDebugCurlTerse) break;
Dout(dc::curltr, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (curl_off_t)" << param.offset << ") = " << ret);
break; break;
default: // Stop compiler complaining about no default. default: // Stop compiler complaining about no default.
break; break;
@@ -895,7 +973,8 @@ CURLMcode debug_curl_multi_socket_action(CURLM* multi_handle, curl_socket_t sock
{ {
CURLMcode ret; CURLMcode ret;
ret = curl_multi_socket_action(multi_handle, sockfd, ev_bitmask, running_handles); ret = curl_multi_socket_action(multi_handle, sockfd, ev_bitmask, running_handles);
Dout(dc::curl, "curl_multi_socket_action(" << (AICURLM*)multi_handle << ", " << Socket(sockfd) << if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_multi_socket_action(" << (AICURLM*)multi_handle << ", " << Socket(sockfd) <<
", " << EvBitmask(ev_bitmask) << ", {" << (ret == CURLM_OK ? *running_handles : 0) << "}) = " << ret); ", " << EvBitmask(ev_bitmask) << ", {" << (ret == CURLM_OK ? *running_handles : 0) << "}) = " << ret);
return ret; return ret;
} }
@@ -904,7 +983,8 @@ char const* debug_curl_multi_strerror(CURLMcode errornum)
{ {
char const* ret; char const* ret;
ret = curl_multi_strerror(errornum); ret = curl_multi_strerror(errornum);
Dout(dc::curl, "curl_multi_strerror(" << errornum << ") = \"" << ret << '"'); if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_multi_strerror(" << errornum << ") = \"" << ret << '"');
return ret; return ret;
} }
@@ -912,21 +992,24 @@ struct curl_slist* debug_curl_slist_append(struct curl_slist* list, char const*
{ {
struct curl_slist* ret; struct curl_slist* ret;
ret = curl_slist_append(list, string); ret = curl_slist_append(list, string);
Dout(dc::curl, "curl_slist_append((curl_slist)@0x" << std::hex << (size_t)list << std::dec << ", \"" << string << "\") = " << *ret); if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_slist_append((curl_slist)@0x" << std::hex << (size_t)list << std::dec << ", \"" << string << "\") = " << *ret);
return ret; return ret;
} }
void debug_curl_slist_free_all(struct curl_slist* list) void debug_curl_slist_free_all(struct curl_slist* list)
{ {
curl_slist_free_all(list); curl_slist_free_all(list);
Dout(dc::curl, "curl_slist_free_all((curl_slist)@0x" << std::hex << (size_t)list << std::dec << ")"); if (gDebugCurlTerse) return;
Dout(dc::curltr, "curl_slist_free_all((curl_slist)@0x" << std::hex << (size_t)list << std::dec << ")");
} }
char* debug_curl_unescape(char const* url, int length) char* debug_curl_unescape(char const* url, int length)
{ {
char* ret; char* ret;
ret = curl_unescape(url, length); ret = curl_unescape(url, length);
Dout(dc::curl, "curl_unescape(\"" << url << "\", " << length << ") = \"" << ret << '"'); if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_unescape(\"" << url << "\", " << length << ") = \"" << ret << '"');
return ret; return ret;
} }
@@ -934,7 +1017,8 @@ char* debug_curl_version(void)
{ {
char* ret; char* ret;
ret = curl_version(); ret = curl_version();
Dout(dc::curl, "curl_version() = \"" << ret << '"'); if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_version() = \"" << ret << '"');
return ret; return ret;
} }

View File

@@ -86,4 +86,9 @@ extern char* debug_curl_version(void);
#endif // !COMPILING_DEBUG_LIBCURL_CC #endif // !COMPILING_DEBUG_LIBCURL_CC
extern bool gDebugCurlTerse; // With this set,
void debug_curl_add_easy(CURL* handle); // only output debug output for easy handles added with this function.
void debug_curl_remove_easy(CURL* handle);
bool debug_curl_print_debug(CURL* handle);
#endif // DEBUG_LIBCURL #endif // DEBUG_LIBCURL

View File

@@ -200,7 +200,9 @@ static void request(
LLURLRequest::ERequestAction method, LLURLRequest::ERequestAction method,
Injector* body_injector, Injector* body_injector,
LLHTTPClient::ResponderPtr responder, LLHTTPClient::ResponderPtr responder,
AIHTTPHeaders& headers, AIHTTPHeaders& headers/*,*/
DEBUG_CURLIO_PARAM(EDebugCurl debug),
EKeepAlive keepalive = keep_alive,
bool is_auth = false, bool is_auth = false,
bool no_compression = false) bool no_compression = false)
{ {
@@ -213,7 +215,10 @@ static void request(
LLURLRequest* req; LLURLRequest* req;
try try
{ {
req = new LLURLRequest(method, url, body_injector, responder, headers, is_auth, no_compression); req = new LLURLRequest(method, url, body_injector, responder, headers, keepalive, is_auth, no_compression);
#ifdef DEBUG_CURLIO
req->mCurlEasyRequest.debug(debug);
#endif
} }
catch(AICurlNoEasyHandle& error) catch(AICurlNoEasyHandle& error)
{ {
@@ -225,36 +230,36 @@ static void request(
req->run(); req->run();
} }
void LLHTTPClient::getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers) void LLHTTPClient::getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{ {
if(offset > 0 || bytes > 0) if(offset > 0 || bytes > 0)
{ {
headers.addHeader("Range", llformat("bytes=%d-%d", offset, offset + bytes - 1)); headers.addHeader("Range", llformat("bytes=%d-%d", offset, offset + bytes - 1));
} }
request(url, LLURLRequest::HTTP_GET, NULL, responder, headers); request(url, LLURLRequest::HTTP_GET, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
} }
void LLHTTPClient::head(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers) void LLHTTPClient::head(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{ {
request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers); request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
} }
void LLHTTPClient::get(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers) void LLHTTPClient::get(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{ {
request(url, LLURLRequest::HTTP_GET, NULL, responder, headers); request(url, LLURLRequest::HTTP_GET, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
} }
void LLHTTPClient::getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers) void LLHTTPClient::getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{ {
request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers); request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
} }
void LLHTTPClient::get(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers) void LLHTTPClient::get(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{ {
LLURI uri; LLURI uri;
uri = LLURI::buildHTTP(url, LLSD::emptyArray(), query); uri = LLURI::buildHTTP(url, LLSD::emptyArray(), query);
get(uri.asString(), responder, headers); get(uri.asString(), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
} }
//============================================================================= //=============================================================================
@@ -362,6 +367,22 @@ void LLHTTPClient::ResponderBase::decode_raw_body(U32 status, std::string const&
} }
} }
std::string const& LLHTTPClient::ResponderBase::get_cookie(std::string const& key)
{
AIHTTPReceivedHeaders::range_type cookies;
mReceivedHeaders.getValues("set-cookie", cookies);
for (AIHTTPReceivedHeaders::iterator_type cookie = cookies.first; cookie != cookies.second; ++cookie)
{
if (key == cookie->second.substr(0, cookie->second.find('=')))
{
return cookie->second;
}
}
// Not found.
static std::string empty_dummy;
return empty_dummy;
}
// Called with HTML body. // Called with HTML body.
// virtual // virtual
void LLHTTPClient::ResponderWithCompleted::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) void LLHTTPClient::ResponderWithCompleted::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer)
@@ -554,7 +575,8 @@ enum EBlockingRequestAction {
static LLSD blocking_request( static LLSD blocking_request(
std::string const& url, std::string const& url,
EBlockingRequestAction method, EBlockingRequestAction method,
LLSD const& body) // Only used for HTTP_LLSD_POST LLSD const& body/*,*/ // Only used for HTTP_LLSD_POST
DEBUG_CURLIO_PARAM(EDebugCurl debug))
{ {
lldebugs << "blockingRequest of " << url << llendl; lldebugs << "blockingRequest of " << url << llendl;
@@ -563,17 +585,17 @@ static LLSD blocking_request(
if (method == HTTP_LLSD_POST) if (method == HTTP_LLSD_POST)
{ {
responder = new BlockingLLSDPostResponder; responder = new BlockingLLSDPostResponder;
LLHTTPClient::post(url, body, responder, headers); LLHTTPClient::post(url, body, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
} }
else if (method == HTTP_LLSD_GET) else if (method == HTTP_LLSD_GET)
{ {
responder = new BlockingLLSDGetResponder; responder = new BlockingLLSDGetResponder;
LLHTTPClient::get(url, responder, headers); LLHTTPClient::get(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
} }
else // method == HTTP_RAW_GET else // method == HTTP_RAW_GET
{ {
responder = new BlockingRawGetResponder; responder = new BlockingRawGetResponder;
LLHTTPClient::get(url, responder, headers); LLHTTPClient::get(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
} }
responder->wait(); responder->wait();
@@ -635,39 +657,39 @@ static LLSD blocking_request(
return response; return response;
} }
LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body) LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{ {
return blocking_request(url, HTTP_LLSD_POST, body); return blocking_request(url, HTTP_LLSD_POST, body/*,*/ DEBUG_CURLIO_PARAM(debug));
} }
LLSD LLHTTPClient::blockingGet(const std::string& url) LLSD LLHTTPClient::blockingGet(const std::string& url/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{ {
return blocking_request(url, HTTP_LLSD_GET, LLSD()); return blocking_request(url, HTTP_LLSD_GET, LLSD()/*,*/ DEBUG_CURLIO_PARAM(debug));
} }
U32 LLHTTPClient::blockingGetRaw(const std::string& url, std::string& body) U32 LLHTTPClient::blockingGetRaw(const std::string& url, std::string& body/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{ {
LLSD result = blocking_request(url, HTTP_RAW_GET, LLSD()); LLSD result = blocking_request(url, HTTP_RAW_GET, LLSD()/*,*/ DEBUG_CURLIO_PARAM(debug));
body = result["body"].asString(); body = result["body"].asString();
return result["status"].asInteger(); return result["status"].asInteger();
} }
void LLHTTPClient::put(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers) void LLHTTPClient::put(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{ {
request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, headers); request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
} }
void LLHTTPClient::post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers) void LLHTTPClient::post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
{ {
request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, headers); request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive);
} }
void LLHTTPClient::postXMLRPC(std::string const& url, XMLRPC_REQUEST xmlrpc_request, ResponderPtr responder, AIHTTPHeaders& headers) void LLHTTPClient::postXMLRPC(std::string const& url, XMLRPC_REQUEST xmlrpc_request, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
{ {
request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers, true, false); // Does use compression. request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, true, false); // Does use compression.
} }
void LLHTTPClient::postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers) void LLHTTPClient::postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
{ {
XMLRPC_REQUEST xmlrpc_request = XMLRPC_RequestNew(); XMLRPC_REQUEST xmlrpc_request = XMLRPC_RequestNew();
XMLRPC_RequestSetMethodName(xmlrpc_request, method); XMLRPC_RequestSetMethodName(xmlrpc_request, method);
@@ -675,33 +697,33 @@ void LLHTTPClient::postXMLRPC(std::string const& url, char const* method, XMLRPC
XMLRPC_RequestSetData(xmlrpc_request, value); XMLRPC_RequestSetData(xmlrpc_request, value);
// XMLRPCInjector takes ownership of xmlrpc_request and will free it when done. // XMLRPCInjector takes ownership of xmlrpc_request and will free it when done.
// LLURLRequest takes ownership of the XMLRPCInjector object and will free it when done. // LLURLRequest takes ownership of the XMLRPCInjector object and will free it when done.
request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers, true, true); // Does not use compression. request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, true, true); // Does not use compression.
} }
void LLHTTPClient::postRaw(std::string const& url, char const* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers) void LLHTTPClient::postRaw(std::string const& url, char const* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
{ {
request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, headers); request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive);
} }
void LLHTTPClient::postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers) void LLHTTPClient::postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
{ {
request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, headers); request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive);
} }
void LLHTTPClient::postFile(std::string const& url, LLUUID const& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers) void LLHTTPClient::postFile(std::string const& url, LLUUID const& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
{ {
request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, headers); request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive);
} }
// static // static
void LLHTTPClient::del(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers) void LLHTTPClient::del(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{ {
request(url, LLURLRequest::HTTP_DELETE, NULL, responder, headers); request(url, LLURLRequest::HTTP_DELETE, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
} }
// static // static
void LLHTTPClient::move(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers) void LLHTTPClient::move(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{ {
headers.addHeader("Destination", destination); headers.addHeader("Destination", destination);
request(url, LLURLRequest::HTTP_MOVE, NULL, responder, headers); request(url, LLURLRequest::HTTP_MOVE, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
} }

View File

@@ -66,6 +66,21 @@ struct AIBufferedCurlEasyRequestEvents {
virtual void completed_headers(U32 status, std::string const& reason, AITransferInfo* info) = 0; // Transaction completed. virtual void completed_headers(U32 status, std::string const& reason, AITransferInfo* info) = 0; // Transaction completed.
}; };
enum EKeepAlive {
no_keep_alive = 0,
keep_alive
};
#ifdef DEBUG_CURLIO
enum EDebugCurl {
debug_off = 0,
debug_on
};
#define DEBUG_CURLIO_PARAM(p) ,p
#else
#define DEBUG_CURLIO_PARAM(p)
#endif
class LLHTTPClient { class LLHTTPClient {
public: public:
@@ -140,7 +155,16 @@ public:
{ {
// It's possible that this page was moved (302), so we already saw headers // It's possible that this page was moved (302), so we already saw headers
// from the 302 page and are starting over on the new page now. // from the 302 page and are starting over on the new page now.
mReceivedHeaders.clear(); // Erase all headers EXCEPT the cookies.
AIHTTPReceivedHeaders set_cookie_headers;
AIHTTPReceivedHeaders::range_type cookies;
mReceivedHeaders.getValues("set-cookie", cookies);
for (AIHTTPReceivedHeaders::iterator_type cookie = cookies.first; cookie != cookies.second; ++cookie)
{
set_cookie_headers.addHeader(cookie->first, cookie->second);
}
// Replace headers with just the cookie headers.
mReceivedHeaders.swap(set_cookie_headers);
} }
// Called for all remaining headers. // Called for all remaining headers.
@@ -155,6 +179,9 @@ public:
completedHeaders(status, reason, mReceivedHeaders); completedHeaders(status, reason, mReceivedHeaders);
} }
// Extract cookie 'key' from mReceivedHeaders and return the string 'key=value', or an empty string if key does not exists.
std::string const& get_cookie(std::string const& key);
public: public:
// Derived classes that implement completed_headers()/completedHeaders() should return true here. // Derived classes that implement completed_headers()/completedHeaders() should return true here.
virtual bool needsHeaders(void) const { return false; } virtual bool needsHeaders(void) const { return false; }
@@ -163,6 +190,9 @@ public:
// The default is not to follow redirections. // The default is not to follow redirections.
virtual bool followRedir(void) const { return false; } virtual bool followRedir(void) const { return false; }
// If this function returns false then we generate an error when a redirect status (300..399) is received.
virtual bool redirect_status_ok(void) const { return followRedir(); }
// Timeout policy to use. // Timeout policy to use.
virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const = 0; virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const = 0;
@@ -358,59 +388,59 @@ public:
/** @name non-blocking API */ /** @name non-blocking API */
//@{ //@{
static void head(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers); static void head(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
static void head(std::string const& url, ResponderHeadersOnly* responder) static void head(std::string const& url, ResponderHeadersOnly* responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
{ AIHTTPHeaders headers; head(url, responder, headers); } { AIHTTPHeaders headers; head(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
static void getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers); static void getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
static void getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder) static void getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
{ AIHTTPHeaders headers; getByteRange(url, offset, bytes, responder, headers); } { AIHTTPHeaders headers; getByteRange(url, offset, bytes, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
static void get(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers); static void get(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
static void get(std::string const& url, ResponderPtr responder) static void get(std::string const& url, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
{ AIHTTPHeaders headers; get(url, responder, headers); } { AIHTTPHeaders headers; get(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
static void get(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers); static void get(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
static void get(std::string const& url, LLSD const& query, ResponderPtr responder) static void get(std::string const& url, LLSD const& query, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
{ AIHTTPHeaders headers; get(url, query, responder, headers); } { AIHTTPHeaders headers; get(url, query, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
static void put(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers); static void put(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
static void put(std::string const& url, LLSD const& body, ResponderPtr responder) static void put(std::string const& url, LLSD const& body, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
{ AIHTTPHeaders headers; put(url, body, responder, headers); } { AIHTTPHeaders headers; put(url, body, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
static void getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers); static void getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
static void getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder) static void getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
{ AIHTTPHeaders headers; getHeaderOnly(url, responder, headers); } { AIHTTPHeaders headers; getHeaderOnly(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
static void post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers); static void post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
static void post(std::string const& url, LLSD const& body, ResponderPtr responder) static void post(std::string const& url, LLSD const& body, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
{ AIHTTPHeaders headers; post(url, body, responder, headers); } { AIHTTPHeaders headers; post(url, body, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); }
/** Takes ownership of request and deletes it when sent */ /** Takes ownership of request and deletes it when sent */
static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder, AIHTTPHeaders& headers); static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder) static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
{ AIHTTPHeaders headers; postXMLRPC(url, request, responder, headers); } { AIHTTPHeaders headers; postXMLRPC(url, request, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); }
static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers); static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder) static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
{ AIHTTPHeaders headers; postXMLRPC(url, method, value, responder, headers); } { AIHTTPHeaders headers; postXMLRPC(url, method, value, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); }
/** Takes ownership of data and deletes it when sent */ /** Takes ownership of data and deletes it when sent */
static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers); static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder) static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
{ AIHTTPHeaders headers; postRaw(url, data, size, responder, headers); } { AIHTTPHeaders headers; postRaw(url, data, size, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); }
static void postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers); static void postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
static void postFile(std::string const& url, std::string const& filename, ResponderPtr responder) static void postFile(std::string const& url, std::string const& filename, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
{ AIHTTPHeaders headers; postFile(url, filename, responder, headers); } { AIHTTPHeaders headers; postFile(url, filename, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); }
static void postFile(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers); static void postFile(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
static void postFile(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder) static void postFile(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
{ AIHTTPHeaders headers; postFile(url, uuid, asset_type, responder, headers); } { AIHTTPHeaders headers; postFile(url, uuid, asset_type, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); }
static void del(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers); static void del(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
static void del(std::string const& url, ResponderPtr responder) static void del(std::string const& url, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
{ AIHTTPHeaders headers; del(url, responder, headers); } { AIHTTPHeaders headers; del(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
///< sends a DELETE method, but we can't call it delete in c++ ///< sends a DELETE method, but we can't call it delete in c++
@@ -423,9 +453,9 @@ public:
* @param headers A map of key:value headers to pass to the request * @param headers A map of key:value headers to pass to the request
* @param timeout The number of seconds to give the server to respond. * @param timeout The number of seconds to give the server to respond.
*/ */
static void move(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers); static void move(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
static void move(std::string const& url, std::string const& destination, ResponderPtr responder) static void move(std::string const& url, std::string const& destination, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
{ AIHTTPHeaders headers; move(url, destination, responder, headers); } { AIHTTPHeaders headers; move(url, destination, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
//@} //@}
@@ -435,7 +465,7 @@ public:
* @param url the complete serialized (and escaped) url to get * @param url the complete serialized (and escaped) url to get
* @return An LLSD of { 'status':status, 'body':payload } * @return An LLSD of { 'status':status, 'body':payload }
*/ */
static LLSD blockingGet(std::string const& url); static LLSD blockingGet(std::string const& url/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
/** /**
* @brief Blocking HTTP GET that returns the raw body. * @brief Blocking HTTP GET that returns the raw body.
@@ -444,7 +474,7 @@ public:
* @param result the target string to write the body to * @param result the target string to write the body to
* @return HTTP status * @return HTTP status
*/ */
static U32 blockingGetRaw(const std::string& url, std::string& result); static U32 blockingGetRaw(const std::string& url, std::string& result/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
/** /**
* @brief Blocking HTTP POST that returns an LLSD map of status and body. * @brief Blocking HTTP POST that returns an LLSD map of status and body.
@@ -453,7 +483,7 @@ public:
* @param body the LLSD post body * @param body the LLSD post body
* @return An LLSD of { 'status':status (an int), 'body':payload (an LLSD) } * @return An LLSD of { 'status':status (an int), 'body':payload (an LLSD) }
*/ */
static LLSD blockingPost(std::string const& url, LLSD const& body); static LLSD blockingPost(std::string const& url, LLSD const& body/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
}; };
#endif // LL_LLHTTPCLIENT_H #endif // LL_LLHTTPCLIENT_H

View File

@@ -77,8 +77,8 @@ std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action)
// This might throw AICurlNoEasyHandle. // This might throw AICurlNoEasyHandle.
LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string const& url, Injector* body, LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string const& url, Injector* body,
LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool is_auth, bool no_compression) : LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool keepalive, bool is_auth, bool no_compression) :
mAction(action), mURL(url), mIsAuth(is_auth), mNoCompression(no_compression), mAction(action), mURL(url), mKeepAlive(keepalive), mIsAuth(is_auth), mNoCompression(no_compression),
mBody(body), mResponder(responder), mHeaders(headers) mBody(body), mResponder(responder), mHeaders(headers)
{ {
} }
@@ -226,7 +226,7 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w)
case HTTP_POST: case HTTP_POST:
{ {
// Set the handle for an http post // Set the handle for an http post
curlEasyRequest_w->setPost(mBodySize); curlEasyRequest_w->setPost(mBodySize, mKeepAlive);
// Set Accept-Encoding to allow response compression // Set Accept-Encoding to allow response compression
curlEasyRequest_w->setoptString(CURLOPT_ENCODING, mNoCompression ? "identity" : ""); curlEasyRequest_w->setoptString(CURLOPT_ENCODING, mNoCompression ? "identity" : "");

View File

@@ -77,7 +77,7 @@ class LLURLRequest : public AICurlEasyRequestStateMachine {
* @param action One of the ERequestAction enumerations. * @param action One of the ERequestAction enumerations.
* @param url The url of the request. It should already be encoded. * @param url The url of the request. It should already be encoded.
*/ */
LLURLRequest(ERequestAction action, std::string const& url, Injector* body, LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool is_auth, bool no_compression); LLURLRequest(ERequestAction action, std::string const& url, Injector* body, LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool keepalive, bool is_auth, bool no_compression);
protected: protected:
// Call abort(), not delete. // Call abort(), not delete.
@@ -111,6 +111,7 @@ class LLURLRequest : public AICurlEasyRequestStateMachine {
private: private:
ERequestAction mAction; ERequestAction mAction;
std::string mURL; std::string mURL;
bool mKeepAlive; // Set to false only when explicitely requested.
bool mIsAuth; // Set for authentication messages (login, buy land, buy currency). bool mIsAuth; // Set for authentication messages (login, buy land, buy currency).
bool mNoCompression; // Set to disable using gzip. bool mNoCompression; // Set to disable using gzip.
Injector* mBody; // Non-zero iff the action is HTTP_POST and HTTP_PUT. Injector* mBody; // Non-zero iff the action is HTTP_POST and HTTP_PUT.

View File

@@ -201,15 +201,13 @@ void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled )
gGL.begin( LLRender::LINES ); gGL.begin( LLRender::LINES );
// Verticals // Verticals
gGL.vertex2i(left + 1, top); gGL.vertex2i(left + 1, top + 1);
gGL.vertex2i(left + 1, bottom); gGL.vertex2i(left + 1, bottom + 1);
gGL.vertex2i(right, bottom); gGL.vertex2i(right + 1, bottom + 1);
gGL.vertex2i(right, top); gGL.vertex2i(right + 1, top + 1);
// Horizontals // Horizontals
top--;
right--;
gGL.vertex2i(left, bottom); gGL.vertex2i(left, bottom);
gGL.vertex2i(right, bottom); gGL.vertex2i(right, bottom);
@@ -219,8 +217,6 @@ void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled )
} }
else else
{ {
top--;
right--;
gGL.begin( LLRender::LINE_STRIP ); gGL.begin( LLRender::LINE_STRIP );
gGL.vertex2i(left, top); gGL.vertex2i(left, top);
gGL.vertex2i(left, bottom); gGL.vertex2i(left, bottom);

View File

@@ -196,8 +196,9 @@ set(viewer_SOURCE_FILES
llfloaterevent.cpp llfloaterevent.cpp
llfloaterexploreanimations.cpp llfloaterexploreanimations.cpp
llfloaterexploresounds.cpp llfloaterexploresounds.cpp
llfloaterfriends.cpp llfloaterfeed.cpp
llfloaterfonttest.cpp llfloaterfonttest.cpp
llfloaterfriends.cpp
llfloatergesture.cpp llfloatergesture.cpp
llfloatergodtools.cpp llfloatergodtools.cpp
llfloatergroupinfo.cpp llfloatergroupinfo.cpp
@@ -704,6 +705,7 @@ set(viewer_HEADER_FILES
llfloaterexploreanimations.h llfloaterexploreanimations.h
llfloaterexploresounds.h llfloaterexploresounds.h
llfloaterevent.h llfloaterevent.h
llfloaterfeed.h
llfloaterfonttest.h llfloaterfonttest.h
llfloaterfriends.h llfloaterfriends.h
llfloatergesture.h llfloatergesture.h

View File

@@ -6776,6 +6776,22 @@ This should be as low as possible, but too low may break functionality</string>
<integer>0</integer> <integer>0</integer>
</array> </array>
</map> </map>
<key>FloaterOutboxRect</key>
<map>
<key>Comment</key>
<string>Rectangle for merchant outbox window</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Rect</string>
<key>Value</key>
<array>
<integer>0</integer>
<integer>342</integer>
<integer>310</integer>
<integer>52</integer>
</array>
</map>
<key>FloaterPayRectB</key> <key>FloaterPayRectB</key>
<map> <map>
<key>Comment</key> <key>Comment</key>
@@ -6856,6 +6872,38 @@ This should be as low as possible, but too low may break functionality</string>
<integer>400</integer> <integer>400</integer>
</array> </array>
</map> </map>
<key>FloaterSnapshotFeedRect</key>
<map>
<key>Comment</key>
<string>Rectangle for snapshot feed window</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Rect</string>
<key>Value</key>
<array>
<integer>0</integer>
<integer>200</integer>
<integer>200</integer>
<integer>400</integer>
</array>
</map>
<key>FloaterSnapshotPostcardRect</key>
<map>
<key>Comment</key>
<string>Rectangle for snapshot postcard window</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Rect</string>
<key>Value</key>
<array>
<integer>0</integer>
<integer>346</integer>
<integer>450</integer>
<integer>400</integer>
</array>
</map>
<key>FloaterSoundsRect</key> <key>FloaterSoundsRect</key>
<map> <map>
<key>Comment</key> <key>Comment</key>
@@ -8163,17 +8211,6 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key> <key>Value</key>
<integer>64</integer> <integer>64</integer>
</map> </map>
<key>KeepAspectForSnapshot</key>
<map>
<key>Comment</key>
<string>Use full window when taking snapshot, regardless of requested image size</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>LandBrushSize</key> <key>LandBrushSize</key>
<map> <map>
<key>Comment</key> <key>Comment</key>
@@ -8344,6 +8381,50 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key> <key>Value</key>
<string>0.0.0</string> <string>0.0.0</string>
</map> </map>
<key>LastSnapshotToFeedAspect</key>
<map>
<key>Comment</key>
<string>The aspect ratio spinner value for snapshots uploaded to my.secondlife.com</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<integer>1.33333</integer>
</map>
<key>LastSnapshotToFeedHeight</key>
<map>
<key>Comment</key>
<string>The height of the last my.secondlife.com feed snapshot, in px</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>525</integer>
</map>
<key>LastSnapshotToFeedWidth</key>
<map>
<key>Comment</key>
<string>The width of the last my.secondlife.com feed snapshot, in px</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>700</integer>
</map>
<key>LastSnapshotToEmailAspect</key>
<map>
<key>Comment</key>
<string>The aspect ratio spinner value for snapshots sent by email</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>LastSnapshotToEmailHeight</key> <key>LastSnapshotToEmailHeight</key>
<map> <map>
<key>Comment</key> <key>Comment</key>
@@ -8366,6 +8447,17 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key> <key>Value</key>
<integer>1024</integer> <integer>1024</integer>
</map> </map>
<key>LastSnapshotToDiskAspect</key>
<map>
<key>Comment</key>
<string>The aspect ratio spinner value for snapshots written to disk</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>LastSnapshotToDiskHeight</key> <key>LastSnapshotToDiskHeight</key>
<map> <map>
<key>Comment</key> <key>Comment</key>
@@ -8388,6 +8480,17 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key> <key>Value</key>
<integer>1024</integer> <integer>1024</integer>
</map> </map>
<key>LastSnapshotToInventoryAspect</key>
<map>
<key>Comment</key>
<string>The aspect ratio spinner value for snapshots uploaded to inventory</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>LastSnapshotToInventoryHeight</key> <key>LastSnapshotToInventoryHeight</key>
<map> <map>
<key>Comment</key> <key>Comment</key>
@@ -8421,6 +8524,17 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key> <key>Value</key>
<integer>0</integer> <integer>0</integer>
</map> </map>
<key>SnapshotFeedAddLocation</key>
<map>
<key>Comment</key>
<string>Include your location in your uploads to profile feed.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>LeftClickShowMenu</key> <key>LeftClickShowMenu</key>
<map> <map>
<key>Comment</key> <key>Comment</key>
@@ -13686,6 +13800,28 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key> <key>Value</key>
<integer>0</integer> <integer>0</integer>
</map> </map>
<key>SnapshotFeedLastAspect</key>
<map>
<key>Comment</key>
<string>Take next feed snapshot at this aspect</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>SnapshotFeedLastResolution</key>
<map>
<key>Comment</key>
<string>Take next feed snapshot at this resolution</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>SnapshotFormat</key> <key>SnapshotFormat</key>
<map> <map>
<key>Comment</key> <key>Comment</key>
@@ -13697,6 +13833,28 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key> <key>Value</key>
<integer>0</integer> <integer>0</integer>
</map> </map>
<key>SnapshotLayerType</key>
<map>
<key>Comment</key>
<string>Save snapshots in this format (0 = Colors, 1 = Depth)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>SnapshotLocalLastAspect</key>
<map>
<key>Comment</key>
<string>Take next local snapshot at this aspect</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>SnapshotLocalLastResolution</key> <key>SnapshotLocalLastResolution</key>
<map> <map>
<key>Comment</key> <key>Comment</key>
@@ -13708,6 +13866,17 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key> <key>Value</key>
<integer>0</integer> <integer>0</integer>
</map> </map>
<key>SnapshotPostcardLastAspect</key>
<map>
<key>Comment</key>
<string>Take next postcard snapshot at this aspect</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>SnapshotPostcardLastResolution</key> <key>SnapshotPostcardLastResolution</key>
<map> <map>
<key>Comment</key> <key>Comment</key>
@@ -13730,6 +13899,17 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key> <key>Value</key>
<integer>75</integer> <integer>75</integer>
</map> </map>
<key>SnapshotTextureLastAspect</key>
<map>
<key>Comment</key>
<string>Take next texture snapshot at this aspect</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>SnapshotTextureLastResolution</key> <key>SnapshotTextureLastResolution</key>
<map> <map>
<key>Comment</key> <key>Comment</key>
@@ -13741,6 +13921,17 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key> <key>Value</key>
<integer>0</integer> <integer>0</integer>
</map> </map>
<key>SnapshotOpenFreezeTime</key>
<map>
<key>Comment</key>
<string>When opening the snapshot floater, immediately freeze time.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>SpeakingColor</key> <key>SpeakingColor</key>
<map> <map>
<key>Comment</key> <key>Comment</key>
@@ -14453,12 +14644,12 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key> <key>Value</key>
<integer>0</integer> <integer>0</integer>
</map> </map>
<key>UseFreezeFrame</key> <key>UseFreezeTime</key>
<map> <map>
<key>Comment</key> <key>Comment</key>
<string>Freeze time when taking snapshots.</string> <string>Freeze time when taking snapshots.</string>
<key>Persist</key> <key>Persist</key>
<integer>1</integer> <integer>0</integer>
<key>Type</key> <key>Type</key>
<string>Boolean</string> <string>Boolean</string>
<key>Value</key> <key>Value</key>

View File

@@ -2514,9 +2514,10 @@ void LLAgentCamera::setFocusObject(LLViewerObject* object)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void LLAgentCamera::setFocusGlobal(const LLPickInfo& pick) void LLAgentCamera::setFocusGlobal(const LLPickInfo& pick)
{ {
static const LLCachedControl<bool> freeze_time("FreezeTime",false);
LLViewerObject* objectp = gObjectList.findObject(pick.mObjectID); LLViewerObject* objectp = gObjectList.findObject(pick.mObjectID);
if (objectp) if (objectp && !freeze_time)
{ {
// focus on object plus designated offset // focus on object plus designated offset
// which may or may not be same as pick.mPosGlobal // which may or may not be same as pick.mPosGlobal

View File

@@ -237,7 +237,10 @@ void LLDrawPoolWater::render(S32 pass)
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
// Slowly move over time. // Slowly move over time.
F32 offset = fmod(gFrameTimeSeconds*2.f, 100.f); static const LLCachedControl<bool> freeze_time("FreezeTime",false);
static F32 frame_time;
if (!freeze_time) frame_time = gFrameTimeSeconds;
F32 offset = fmod(frame_time*2.f, 100.f);
F32 tp0[4] = {16.f/256.f, 0.0f, 0.0f, offset*0.01f}; F32 tp0[4] = {16.f/256.f, 0.0f, 0.0f, offset*0.01f};
F32 tp1[4] = {0.0f, 16.f/256.f, 0.0f, offset*0.01f}; F32 tp1[4] = {0.0f, 16.f/256.f, 0.0f, offset*0.01f};
glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0); glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0);
@@ -418,11 +421,14 @@ void LLDrawPoolWater::renderOpaqueLegacyWater()
// Use the fact that we know all water faces are the same size // Use the fact that we know all water faces are the same size
// to save some computation // to save some computation
// Slowly move texture coordinates over time so the watter appears // Slowly move texture coordinates over time so the water appears
// to be moving. // to be moving.
F32 movement_period_secs = 50.f; F32 movement_period_secs = 50.f;
F32 offset = fmod(gFrameTimeSeconds, movement_period_secs); static const LLCachedControl<bool> freeze_time("FreezeTime",false);
static F32 frame_time;
if (!freeze_time) frame_time = gFrameTimeSeconds;
F32 offset = fmod(frame_time, movement_period_secs);
if (movement_period_secs != 0) if (movement_period_secs != 0)
{ {
@@ -580,7 +586,11 @@ void LLDrawPoolWater::shade()
shader->bind(); shader->bind();
} }
sTime = (F32)LLFrameTimer::getElapsedSeconds()*0.5f; static const LLCachedControl<bool> freeze_time("FreezeTime",false);
if (!freeze_time)
{
sTime = (F32)LLFrameTimer::getElapsedSeconds()*0.5f;
}
S32 reftex = shader->enableTexture(LLViewerShaderMgr::WATER_REFTEX); S32 reftex = shader->enableTexture(LLViewerShaderMgr::WATER_REFTEX);

View File

@@ -180,7 +180,7 @@ void LLFloaterAuction::onClickSnapshot(void* data)
BOOL success = gViewerWindow->rawSnapshot(raw, BOOL success = gViewerWindow->rawSnapshot(raw,
gViewerWindow->getWindowWidth(), gViewerWindow->getWindowWidth(),
gViewerWindow->getWindowHeight(), gViewerWindow->getWindowHeight(),
TRUE, FALSE, (F32)gViewerWindow->getWindowWidth() / gViewerWindow->getWindowHeight(),
FALSE, FALSE); FALSE, FALSE);
gForceRenderLandFence = FALSE; gForceRenderLandFence = FALSE;

View File

@@ -0,0 +1,177 @@
/**
* @file llfloaterfeed.cpp
* @brief Feed send floater, allows setting caption and whether or to add location, etc.
*
* $LicenseInfo:firstyear=2012&license=viewergpl$
*
* Copyright (c) 2004-2009, Linden Research, Inc.
* Copyright (c) 2012, Aleric Ingelwood.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "llfloaterfeed.h"
#include "llfloatersnapshot.h"
#include "llimagepng.h"
#include "llnotificationsutil.h"
#include "lluictrlfactory.h"
#include "llviewertexture.h"
#include "llviewerwindow.h"
#include "llwebprofile.h"
#include <boost/bind.hpp>
///----------------------------------------------------------------------------
/// Class LLFloaterFeed
///----------------------------------------------------------------------------
LLFloaterFeed::LLFloaterFeed(LLImagePNG* png, LLViewerTexture* img, LLVector2 const& img_scale, int index) :
LLFloater(std::string("Feed Floater")),
mPNGImage(png), mViewerImage(img), mImageScale(img_scale), mSnapshotIndex(index)
{
}
// Destroys the object
LLFloaterFeed::~LLFloaterFeed()
{
mPNGImage = NULL;
}
BOOL LLFloaterFeed::postBuild()
{
getChild<LLUICtrl>("cancel_btn")->setCommitCallback(boost::bind(&LLFloaterFeed::onClickCancel, this));
getChild<LLUICtrl>("post_btn")->setCommitCallback(boost::bind(&LLFloaterFeed::onClickPost, this));
return true;
}
// static
LLFloaterFeed* LLFloaterFeed::showFromSnapshot(LLImagePNG* png, LLViewerTexture* img, LLVector2 const& image_scale, int index)
{
// Take the images from the caller
// It's now our job to clean them up
LLFloaterFeed* instance = new LLFloaterFeed(png, img, image_scale, index);
LLUICtrlFactory::getInstance()->buildFloater(instance, "floater_snapshot_feed.xml");
S32 left, top;
gFloaterView->getNewFloaterPosition(&left, &top);
instance->setOrigin(left, top - instance->getRect().getHeight());
instance->open();
return instance;
}
void LLFloaterFeed::draw(void)
{
LLGLSUIDefault gls_ui;
LLFloater::draw();
if (!isMinimized() && mViewerImage.notNull() && mPNGImage.notNull())
{
LLRect rect(getRect());
// First set the max extents of our preview.
rect.translate(-rect.mLeft, -rect.mBottom);
rect.mLeft += 10;
rect.mRight -= 10;
rect.mTop -= 25;
rect.mBottom = rect.mTop - 150;
// Then fix the aspect ratio.
F32 ratio = (F32)mPNGImage->getWidth() / (F32)mPNGImage->getHeight();
if ((F32)rect.getWidth() / (F32)rect.getHeight() >= ratio)
{
rect.mRight = (S32)((F32)rect.mLeft + ((F32)rect.getHeight() * ratio));
}
else
{
rect.mBottom = (S32)((F32)rect.mTop - ((F32)rect.getWidth() / ratio));
}
{
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gl_rect_2d(rect, LLColor4(0.f, 0.f, 0.f, 1.f));
rect.stretch(-1);
}
{
gGL.matrixMode(LLRender::MM_TEXTURE);
gGL.pushMatrix();
{
gGL.scalef(mImageScale.mV[VX], mImageScale.mV[VY], 1.f);
gGL.matrixMode(LLRender::MM_MODELVIEW);
gl_draw_scaled_image(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), mViewerImage, LLColor4::white);
}
gGL.matrixMode(LLRender::MM_TEXTURE);
gGL.popMatrix();
gGL.matrixMode(LLRender::MM_MODELVIEW);
}
}
}
void LLFloaterFeed::onClickCancel()
{
// Return false on cancel, to enable the upload button again.
LLFloaterSnapshot::saveFeedDone(false, mSnapshotIndex);
close(false);
}
void LLFloaterFeed::onClose(bool app_quitting)
{
LLFloaterSnapshot::saveFeedDone(false, mSnapshotIndex);
destroy();
}
void LLFloaterFeed::onClickPost()
{
if (mPNGImage.notNull())
{
static LLCachedControl<bool> add_location("SnapshotFeedAddLocation");
const std::string caption = childGetValue("caption").asString();
LLWebProfile::setImageUploadResultCallback(boost::bind(&LLFloaterSnapshot::saveFeedDone, _1, mPNGImage));
LLWebProfile::uploadImage(mPNGImage, caption, add_location);
// give user feedback of the event
gViewerWindow->playSnapshotAnimAndSound();
// don't destroy the window until the upload is done
// this way we keep the information in the form
setVisible(FALSE);
// remove any dependency on snapshot floater
// so we outlive it during the upload.
LLFloater* dependee = getDependee();
if (dependee)
{
dependee->removeDependentFloater(this);
}
}
else
{
LLNotificationsUtil::add("ErrorProcessingSnapshot");
}
}

View File

@@ -0,0 +1,64 @@
/**
* @file llfloaterfeed.h
* @brief Feed send floater, allows setting caption and whether or not to include location.
*
* Copyright (c) 2004-2009, Linden Research, Inc.
* Copyright (c) 2012, Aleric Inglewood.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_LLFLOATERFEED_H
#define LL_LLFLOATERFEED_H
#include "llfloater.h" // LLFloater
#include "v2math.h" // LLVector2
#include "llpointer.h" // LLPointer
class LLImagePNG;
class LLViewerTexture;
class LLFloaterFeed : public LLFloater
{
public:
LLFloaterFeed(LLImagePNG* png, LLViewerTexture* img, LLVector2 const& img_scale, int index);
virtual ~LLFloaterFeed();
/*virtual*/ void onClose(bool app_quitting);
/*virtual*/ BOOL postBuild();
/*virtual*/ void draw();
static LLFloaterFeed* showFromSnapshot(LLImagePNG* png, LLViewerTexture* img, LLVector2 const& img_scale, int index);
void onClickCancel();
void onClickPost();
protected:
LLPointer<LLImagePNG> mPNGImage;
LLPointer<LLViewerTexture> mViewerImage;
LLVector2 const mImageScale;
int mSnapshotIndex;
};
#endif // LL_LLFLOATERFEED_H

View File

@@ -67,6 +67,7 @@
#include "llassetuploadresponders.h" #include "llassetuploadresponders.h"
#include "hippogridmanager.h" #include "hippogridmanager.h"
#include "llfloatersnapshot.h"
#if LL_MSVC #if LL_MSVC
#pragma warning( disable : 4265 ) // "class has virtual functions, but destructor is not virtual" #pragma warning( disable : 4265 ) // "class has virtual functions, but destructor is not virtual"
@@ -84,13 +85,14 @@ LLFloaterPostcard::instance_list_t LLFloaterPostcard::sInstances;
/// Class LLFloaterPostcard /// Class LLFloaterPostcard
///---------------------------------------------------------------------------- ///----------------------------------------------------------------------------
LLFloaterPostcard::LLFloaterPostcard(LLImageJPEG* jpeg, LLViewerTexture *img, const LLVector2& img_scale, const LLVector3d& pos_taken_global) LLFloaterPostcard::LLFloaterPostcard(LLImageJPEG* jpeg, LLViewerTexture *img, const LLVector2& img_scale, const LLVector3d& pos_taken_global, int index)
: LLFloater(std::string("Postcard Floater")), : LLFloater(std::string("Postcard Floater")),
mJPEGImage(jpeg), mJPEGImage(jpeg),
mViewerImage(img), mViewerImage(img),
mImageScale(img_scale), mImageScale(img_scale),
mPosTakenGlobal(pos_taken_global), mPosTakenGlobal(pos_taken_global),
mHasFirstMsgFocus(false) mHasFirstMsgFocus(false),
mSnapshotIndex(index)
{ {
init(); init();
} }
@@ -146,11 +148,11 @@ BOOL LLFloaterPostcard::postBuild()
// static // static
LLFloaterPostcard* LLFloaterPostcard::showFromSnapshot(LLImageJPEG *jpeg, LLViewerTexture *img, const LLVector2 &image_scale, const LLVector3d& pos_taken_global) LLFloaterPostcard* LLFloaterPostcard::showFromSnapshot(LLImageJPEG *jpeg, LLViewerTexture *img, const LLVector2 &image_scale, const LLVector3d& pos_taken_global, int index)
{ {
// Take the images from the caller // Take the images from the caller
// It's now our job to clean them up // It's now our job to clean them up
LLFloaterPostcard *instance = new LLFloaterPostcard(jpeg, img, image_scale, pos_taken_global); LLFloaterPostcard *instance = new LLFloaterPostcard(jpeg, img, image_scale, pos_taken_global, index);
LLUICtrlFactory::getInstance()->buildFloater(instance, "floater_postcard.xml"); LLUICtrlFactory::getInstance()->buildFloater(instance, "floater_postcard.xml");
@@ -221,25 +223,47 @@ void LLFloaterPostcard::onClickCancel(void* data)
if (data) if (data)
{ {
LLFloaterPostcard *self = (LLFloaterPostcard *)data; LLFloaterPostcard *self = (LLFloaterPostcard *)data;
LLFloaterSnapshot::savePostcardDone(false, self->mSnapshotIndex);
self->close(false); self->close(false);
} }
} }
void LLFloaterPostcard::onClose(bool app_quitting)
{
LLFloaterSnapshot::savePostcardDone(false, mSnapshotIndex);
destroy();
}
class LLSendPostcardResponder : public LLAssetUploadResponder class LLSendPostcardResponder : public LLAssetUploadResponder
{ {
private:
int mSnapshotIndex;
public: public:
LLSendPostcardResponder(const LLSD &post_data, LLSendPostcardResponder(const LLSD &post_data,
const LLUUID& vfile_id, const LLUUID& vfile_id,
LLAssetType::EType asset_type): LLAssetType::EType asset_type,
LLAssetUploadResponder(post_data, vfile_id, asset_type) int index) :
LLAssetUploadResponder(post_data, vfile_id, asset_type),
mSnapshotIndex(index)
{ {
} }
// *TODO define custom uploadFailed here so it's not such a generic message // *TODO define custom uploadFailed here so it's not such a generic message
void uploadComplete(const LLSD& content) /*virtual*/ void uploadComplete(const LLSD& content)
{ {
// we don't care about what the server returns from this post, just clean up the UI // we don't care about what the server returns from this post, just clean up the UI
LLUploadDialog::modalUploadFinished(); LLUploadDialog::modalUploadFinished();
LLFloaterSnapshot::savePostcardDone(true, mSnapshotIndex);
}
/*virtual*/ void uploadFailure(const LLSD& content)
{
LLAssetUploadResponder::uploadFailure(content);
LLFloaterSnapshot::savePostcardDone(false, mSnapshotIndex);
}
/*virtual*/ void error(U32 statusNum, const std::string& reason)
{
LLAssetUploadResponder::error(statusNum, reason);
LLFloaterSnapshot::savePostcardDone(false, mSnapshotIndex);
} }
}; };
@@ -292,6 +316,8 @@ void LLFloaterPostcard::uploadCallback(const LLUUID& asset_id, void *user_data,
LLUploadDialog::modalUploadFinished(); LLUploadDialog::modalUploadFinished();
LLFloaterSnapshot::savePostcardDone(!result, self->mSnapshotIndex);
if (result) if (result)
{ {
LLSD args; LLSD args;
@@ -396,7 +422,7 @@ void LLFloaterPostcard::sendPostcard()
body["name"] = childGetValue("name_form").asString(); body["name"] = childGetValue("name_form").asString();
body["subject"] = childGetValue("subject_form").asString(); body["subject"] = childGetValue("subject_form").asString();
body["msg"] = childGetValue("msg_form").asString(); body["msg"] = childGetValue("msg_form").asString();
LLHTTPClient::post(url, body, new LLSendPostcardResponder(body, mAssetID, LLAssetType::AT_IMAGE_JPEG)); LLHTTPClient::post(url, body, new LLSendPostcardResponder(body, mAssetID, LLAssetType::AT_IMAGE_JPEG, mSnapshotIndex));
} }
else else
{ {

View File

@@ -50,14 +50,15 @@ class LLFloaterPostcard
: public LLFloater : public LLFloater
{ {
public: public:
LLFloaterPostcard(LLImageJPEG* jpeg, LLViewerTexture *img, const LLVector2& img_scale, const LLVector3d& pos_taken_global); LLFloaterPostcard(LLImageJPEG* jpeg, LLViewerTexture *img, const LLVector2& img_scale, const LLVector3d& pos_taken_global, int index);
virtual ~LLFloaterPostcard(); /*virtual*/ ~LLFloaterPostcard();
virtual void init(); /*virtual*/ void init();
virtual BOOL postBuild(); /*virtual*/ BOOL postBuild();
virtual void draw(); /*virtual*/ void draw();
/*virtual*/ void onClose(bool app_quitting);
static LLFloaterPostcard* showFromSnapshot(LLImageJPEG *jpeg, LLViewerTexture *img, const LLVector2& img_scale, const LLVector3d& pos_taken_global); static LLFloaterPostcard* showFromSnapshot(LLImageJPEG *jpeg, LLViewerTexture *img, const LLVector2& img_scale, const LLVector3d& pos_taken_global, int index);
static void onClickCancel(void* data); static void onClickCancel(void* data);
static void onClickSend(void* data); static void onClickSend(void* data);
@@ -82,6 +83,7 @@ protected:
LLVector2 mImageScale; LLVector2 mImageScale;
LLVector3d mPosTakenGlobal; LLVector3d mPosTakenGlobal;
bool mHasFirstMsgFocus; bool mHasFirstMsgFocus;
int mSnapshotIndex;
typedef std::set<LLFloaterPostcard*> instance_list_t; typedef std::set<LLFloaterPostcard*> instance_list_t;
static instance_list_t sInstances; static instance_list_t sInstances;

View File

@@ -898,7 +898,8 @@ void LLFloaterReporter::takeScreenshot()
const S32 IMAGE_HEIGHT = 768; const S32 IMAGE_HEIGHT = 768;
LLPointer<LLImageRaw> raw = new LLImageRaw; LLPointer<LLImageRaw> raw = new LLImageRaw;
if( !gViewerWindow->rawSnapshot(raw, IMAGE_WIDTH, IMAGE_HEIGHT, TRUE, FALSE, TRUE, FALSE)) // Warning: This crops left and right in case of wide-screen monitor:
if( !gViewerWindow->rawSnapshot(raw, IMAGE_WIDTH, IMAGE_HEIGHT, (F32)IMAGE_WIDTH / IMAGE_HEIGHT, TRUE, FALSE))
{ {
llwarns << "Unable to take screenshot" << llendl; llwarns << "Unable to take screenshot" << llendl;
return; return;

File diff suppressed because it is too large Load Diff

View File

@@ -47,16 +47,22 @@ public:
{ {
SNAPSHOT_FORMAT_PNG, SNAPSHOT_FORMAT_PNG,
SNAPSHOT_FORMAT_JPEG, SNAPSHOT_FORMAT_JPEG,
SNAPSHOT_FORMAT_BMP SNAPSHOT_FORMAT_BMP,
SNAPSHOT_FORMAT_J2C
} ESnapshotFormat; } ESnapshotFormat;
LLFloaterSnapshot(); LLFloaterSnapshot();
virtual ~LLFloaterSnapshot(); virtual ~LLFloaterSnapshot();
LLRect getThumbnailAreaRect();
/*virtual*/ BOOL postBuild(); /*virtual*/ BOOL postBuild();
/*virtual*/ void draw(); /*virtual*/ void draw();
/*virtual*/ void onClose(bool app_quitting); /*virtual*/ void onClose(bool app_quitting);
/*virtual*/ void onOpen(); /*virtual*/ void onOpen();
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
static void show(void*); static void show(void*);
static void hide(void*); static void hide(void*);
@@ -66,6 +72,13 @@ public:
static S32 getUIWinHeightShort() {return sUIWinHeightShort ;} static S32 getUIWinHeightShort() {return sUIWinHeightShort ;}
static S32 getUIWinWidth() {return sUIWinWidth ;} static S32 getUIWinWidth() {return sUIWinWidth ;}
static void saveLocalDone(bool success, int index);
static void saveFeedDone(bool success, int index);
static void savePostcardDone(bool success, int index);
static void updateControls();
static void resetFeedAndPostcardAspect();
private: private:
class Impl; class Impl;
Impl& impl; Impl& impl;

View File

@@ -199,12 +199,19 @@ namespace LLMarketplaceImport
/*virtual*/ bool followRedir(void) const { return true; } /*virtual*/ bool followRedir(void) const { return true; }
/*virtual*/ bool needsHeaders(void) const { return true; } /*virtual*/ bool needsHeaders(void) const { return true; }
void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers)
{ {
std::string set_cookie_string; if (status == HTTP_OK)
if (headers.getFirstValue("set-cookie", set_cookie_string) && !set_cookie_string.empty())
{ {
sMarketplaceCookie = set_cookie_string; std::string value = get_cookie("_slm_session");
if (!value.empty())
{
sMarketplaceCookie = value;
}
else if (sMarketplaceCookie.empty())
{
llwarns << "No such cookie \"_slm_session\" received!" << llendl;
}
} }
} }
@@ -226,7 +233,7 @@ namespace LLMarketplaceImport
{ {
if (gSavedSettings.getBOOL("InventoryOutboxLogging")) if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
{ {
llinfos << " SLM GET clearing marketplace cookie due to authentication failure or timeout" << llendl; llinfos << " SLM GET clearing marketplace cookie due to authentication failure or timeout (" << status << " / " << reason << ")." << llendl;
} }
sMarketplaceCookie.clear(); sMarketplaceCookie.clear();
@@ -372,7 +379,7 @@ namespace LLMarketplaceImport
// Interface class // Interface class
// //
//static const F32 MARKET_IMPORTER_UPDATE_FREQUENCY = 300.0f; //1.0f; static const F32 MARKET_IMPORTER_UPDATE_FREQUENCY = 1.0f;
//static //static
void LLMarketplaceInventoryImporter::update() void LLMarketplaceInventoryImporter::update()
@@ -383,7 +390,7 @@ void LLMarketplaceInventoryImporter::update()
if (update_timer.hasExpired()) if (update_timer.hasExpired())
{ {
LLMarketplaceInventoryImporter::instance().updateImport(); LLMarketplaceInventoryImporter::instance().updateImport();
static LLCachedControl<F32> MARKET_IMPORTER_UPDATE_FREQUENCY("MarketImporterUpdateFreq", 10.0f); //static LLCachedControl<F32> MARKET_IMPORTER_UPDATE_FREQUENCY("MarketImporterUpdateFreq", 1.0f);
update_timer.setTimerExpirySec(MARKET_IMPORTER_UPDATE_FREQUENCY); update_timer.setTimerExpirySec(MARKET_IMPORTER_UPDATE_FREQUENCY);
} }
} }

View File

@@ -70,7 +70,6 @@ LLMenuOptionPathfindingRebakeNavmesh::~LLMenuOptionPathfindingRebakeNavmesh()
void LLMenuOptionPathfindingRebakeNavmesh::initialize() void LLMenuOptionPathfindingRebakeNavmesh::initialize()
{ {
llassert(!mIsInitialized);
if (!mIsInitialized) if (!mIsInitialized)
{ {
mIsInitialized = true; mIsInitialized = true;

View File

@@ -162,10 +162,6 @@ public:
LLLoginRefreshHandler gLoginRefreshHandler; LLLoginRefreshHandler gLoginRefreshHandler;
// <edit>
std::string gFullName;
// </edit>
// helper class that trys to download a URL from a web site and calls a method // helper class that trys to download a URL from a web site and calls a method
// on parent class indicating if the web server is working or not // on parent class indicating if the web server is working or not
class LLIamHereLogin : public LLHTTPClient::ResponderHeadersOnly class LLIamHereLogin : public LLHTTPClient::ResponderHeadersOnly

View File

@@ -41,10 +41,6 @@
class LLUIImage; class LLUIImage;
class LLComboBox; class LLComboBox;
// <edit>
extern std::string gFullName;
// </edit>
class LLPanelLogin: class LLPanelLogin:
public LLPanel, public LLPanel,
public LLViewerMediaObserver public LLViewerMediaObserver
@@ -165,8 +161,4 @@ private:
std::string load_password_from_disk(void); std::string load_password_from_disk(void);
void save_password_to_disk(const char* hashed_password); void save_password_to_disk(const char* hashed_password);
// <edit>
extern std::string gFullName;
// </edit>
#endif #endif

View File

@@ -4421,6 +4421,10 @@ public:
} }
} }
else if (avatar->isLangolier())
{
skip_check = true;
}
} }
if (!skip_check && vobj->lineSegmentIntersect(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mBinormal)) if (!skip_check && vobj->lineSegmentIntersect(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mBinormal))

View File

@@ -757,9 +757,6 @@ bool idle_startup()
// We have at least some login information on a SLURL // We have at least some login information on a SLURL
firstname = gLoginHandler.getFirstName(); firstname = gLoginHandler.getFirstName();
lastname = gLoginHandler.getLastName(); lastname = gLoginHandler.getLastName();
// <edit>
gFullName = utf8str_tolower(firstname + " " + lastname);
// </edit>
web_login_key = gLoginHandler.getWebLoginKey(); web_login_key = gLoginHandler.getWebLoginKey();
// Show the login screen if we don't have everything // Show the login screen if we don't have everything
@@ -771,9 +768,6 @@ bool idle_startup()
LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo"); LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo");
firstname = cmd_line_login[0].asString(); firstname = cmd_line_login[0].asString();
lastname = cmd_line_login[1].asString(); lastname = cmd_line_login[1].asString();
// <edit>
gFullName = utf8str_tolower(firstname + " " + lastname);
// </edit>
LLMD5 pass((unsigned char*)cmd_line_login[2].asString().c_str()); LLMD5 pass((unsigned char*)cmd_line_login[2].asString().c_str());
char md5pass[33]; /* Flawfinder: ignore */ char md5pass[33]; /* Flawfinder: ignore */
@@ -791,9 +785,6 @@ bool idle_startup()
{ {
firstname = gSavedSettings.getString("FirstName"); firstname = gSavedSettings.getString("FirstName");
lastname = gSavedSettings.getString("LastName"); lastname = gSavedSettings.getString("LastName");
// <edit>
gFullName = utf8str_tolower(firstname + " " + lastname);
// </edit>
password = LLStartUp::loadPasswordFromDisk(); password = LLStartUp::loadPasswordFromDisk();
gSavedSettings.setBOOL("RememberPassword", TRUE); gSavedSettings.setBOOL("RememberPassword", TRUE);
@@ -809,9 +800,6 @@ bool idle_startup()
// a valid grid is selected // a valid grid is selected
firstname = gSavedSettings.getString("FirstName"); firstname = gSavedSettings.getString("FirstName");
lastname = gSavedSettings.getString("LastName"); lastname = gSavedSettings.getString("LastName");
// <edit>
gFullName = utf8str_tolower(firstname + " " + lastname);
// </edit>
password = LLStartUp::loadPasswordFromDisk(); password = LLStartUp::loadPasswordFromDisk();
show_connect_box = true; show_connect_box = true;
} }
@@ -895,9 +883,6 @@ bool idle_startup()
else else
{ {
LLPanelLogin::setFields(firstname, lastname, password); LLPanelLogin::setFields(firstname, lastname, password);
// <edit>
gFullName = utf8str_tolower(firstname + " " + lastname);
// </edit>
LLPanelLogin::giveFocus(); LLPanelLogin::giveFocus();
} }
display_startup(); display_startup();
@@ -969,9 +954,6 @@ bool idle_startup()
{ {
firstname = gLoginHandler.getFirstName(); firstname = gLoginHandler.getFirstName();
lastname = gLoginHandler.getLastName(); lastname = gLoginHandler.getLastName();
// <edit>
gFullName = utf8str_tolower(firstname + " " + lastname);
// </edit>
web_login_key = gLoginHandler.getWebLoginKey(); web_login_key = gLoginHandler.getWebLoginKey();
} }
@@ -990,15 +972,21 @@ bool idle_startup()
{ {
gSavedSettings.setString("FirstName", firstname); gSavedSettings.setString("FirstName", firstname);
gSavedSettings.setString("LastName", lastname); gSavedSettings.setString("LastName", lastname);
// <edit>
gFullName = utf8str_tolower(firstname + " " + lastname);
// </edit>
if (!gSavedSettings.controlExists("RememberLogin")) gSavedSettings.declareBOOL("RememberLogin", false, "Remember login", false); if (!gSavedSettings.controlExists("RememberLogin")) gSavedSettings.declareBOOL("RememberLogin", false, "Remember login", false);
gSavedSettings.setBOOL("RememberLogin", LLPanelLogin::getRememberLogin()); gSavedSettings.setBOOL("RememberLogin", LLPanelLogin::getRememberLogin());
LL_INFOS("AppInit") << "Attempting login as: " << firstname << " " << lastname << LL_ENDL; LL_INFOS("AppInit") << "Attempting login as: " << firstname << " " << lastname << LL_ENDL;
gDebugInfo["LoginName"] = firstname + " " + lastname; gDebugInfo["LoginName"] = firstname + " " + lastname;
} }
else
{
// User tried to login on a non-SecondLife grid with an empty lastname.
LLSD subs;
subs["GRIDNAME"] = gHippoGridManager->getConnectedGrid()->getGridName();
LLNotificationsUtil::add(firstname.empty() ? "EmptyFirstNameMessage" : "EmptyLastNameMessage", subs);
LLStartUp::setStartupState(STATE_LOGIN_SHOW);
return FALSE;
}
LLScriptEdCore::parseFunctions("lsl_functions_sl.xml"); //Singu Note: This parsing function essentially replaces the entirety of the lscript_library library LLScriptEdCore::parseFunctions("lsl_functions_sl.xml"); //Singu Note: This parsing function essentially replaces the entirety of the lscript_library library
@@ -4099,9 +4087,6 @@ bool process_login_success_response(std::string& password)
if(!text.empty()) lastname.assign(text); if(!text.empty()) lastname.assign(text);
gSavedSettings.setString("FirstName", firstname); gSavedSettings.setString("FirstName", firstname);
gSavedSettings.setString("LastName", lastname); gSavedSettings.setString("LastName", lastname);
// <edit>
gFullName = utf8str_tolower(firstname + " " + lastname);
// </edit>
if (gSavedSettings.getBOOL("RememberPassword")) if (gSavedSettings.getBOOL("RememberPassword"))
{ {

View File

@@ -188,7 +188,8 @@ void display_update_camera(bool tiling=false)
// Cut draw distance in half when customizing avatar, // Cut draw distance in half when customizing avatar,
// but on the viewer only. // but on the viewer only.
F32 final_far = gAgentCamera.mDrawDistance; F32 final_far = gAgentCamera.mDrawDistance;
if(tiling) //Don't animate clouds and water if tiling! static const LLCachedControl<bool> freeze_time("FreezeTime",false);
if(freeze_time || tiling) //Don't animate clouds and water if tiling!
{ {
LLViewerCamera::getInstance()->setFar(final_far); LLViewerCamera::getInstance()->setFar(final_far);
gViewerWindow->setup3DRender(); gViewerWindow->setup3DRender();

View File

@@ -55,6 +55,7 @@
#include "llwindow.h" #include "llwindow.h"
#include "llvieweraudio.h" #include "llvieweraudio.h"
#include "llweb.h" #include "llweb.h"
#include "llwebprofile.h"
#include "llfloateravatarinfo.h" // for getProfileURL() function #include "llfloateravatarinfo.h" // for getProfileURL() function
//#include "viewerversion.h" //#include "viewerversion.h"
@@ -140,12 +141,7 @@ public:
{ {
LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL;
LL_DEBUGS("MediaAuth") << headers << LL_ENDL; LL_DEBUGS("MediaAuth") << headers << LL_ENDL;
AIHTTPReceivedHeaders::range_type cookies; LLViewerMedia::openIDCookieResponse(get_cookie("agni_sl_session_id"));
if (headers.getValues("set-cookie", cookies))
{
for (AIHTTPReceivedHeaders::iterator_type cookie = cookies.first; cookie != cookies.second; ++cookie)
LLViewerMedia::openIDCookieResponse(cookie->second);
}
} }
/* virtual */ void completedRaw( /* virtual */ void completedRaw(
@@ -182,11 +178,29 @@ public:
LL_INFOS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; LL_INFOS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL;
LL_INFOS("MediaAuth") << headers << LL_ENDL; LL_INFOS("MediaAuth") << headers << LL_ENDL;
bool found = false;
AIHTTPReceivedHeaders::range_type cookies; AIHTTPReceivedHeaders::range_type cookies;
if (headers.getValues("set-cookie", cookies)) if (headers.getValues("set-cookie", cookies))
{ {
for (AIHTTPReceivedHeaders::iterator_type cookie = cookies.first; cookie != cookies.second; ++cookie) for (AIHTTPReceivedHeaders::iterator_type cookie = cookies.first; cookie != cookies.second; ++cookie)
{
LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie->second, mHost); LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie->second, mHost);
std::string key = cookie->second.substr(0, cookie->second.find('='));
if (key == "_my_secondlife_session")
{
// Set cookie for snapshot publishing.
std::string auth_cookie = cookie->second.substr(0, cookie->second.find(";")); // strip path
LL_INFOS("MediaAuth") << "Setting openID auth cookie \"" << auth_cookie << "\"." << LL_ENDL;
LLWebProfile::setAuthCookie(auth_cookie);
found = true;
break;
}
}
}
if (!found)
{
llwarns << "LLViewerMediaWebProfileResponder did not receive a session ID cookie \"_my_secondlife_session\"! OpenID authentications will fail!" << llendl;
} }
} }

View File

@@ -527,6 +527,7 @@ class LLFileTakeSnapshotToDisk : public view_listener_t
S32 width = gViewerWindow->getWindowDisplayWidth(); S32 width = gViewerWindow->getWindowDisplayWidth();
S32 height = gViewerWindow->getWindowDisplayHeight(); S32 height = gViewerWindow->getWindowDisplayHeight();
F32 ratio = (F32)width / height;
F32 supersample = 1.f; F32 supersample = 1.f;
if (gSavedSettings.getBOOL("HighResSnapshot")) if (gSavedSettings.getBOOL("HighResSnapshot"))
@@ -546,8 +547,7 @@ class LLFileTakeSnapshotToDisk : public view_listener_t
if (gViewerWindow->rawSnapshot(raw, if (gViewerWindow->rawSnapshot(raw,
width, width,
height, height,
TRUE, ratio,
FALSE,
gSavedSettings.getBOOL("RenderUIInSnapshot"), gSavedSettings.getBOOL("RenderUIInSnapshot"),
FALSE, FALSE,
LLViewerWindow::SNAPSHOT_TYPE_COLOR, LLViewerWindow::SNAPSHOT_TYPE_COLOR,
@@ -574,7 +574,7 @@ class LLFileTakeSnapshotToDisk : public view_listener_t
formatted->enableOverSize() ; formatted->enableOverSize() ;
formatted->encode(raw, 0); formatted->encode(raw, 0);
formatted->disableOverSize(); formatted->disableOverSize();
gViewerWindow->saveImageNumbered(formatted); gViewerWindow->saveImageNumbered(formatted, -1);
} }
return true; return true;
} }

View File

@@ -1340,7 +1340,7 @@ void LLViewerObjectList::killAllObjects()
killObject(objectp); killObject(objectp);
// Object must be dead, or it's the LLVOAvatarSelf which never dies. // Object must be dead, or it's the LLVOAvatarSelf which never dies.
llassert((objectp == gAgentAvatarp) || objectp->isDead()); llassert((objectp == gAgentAvatarp) || objectp->isDead() || (objectp->asAvatar() && objectp->asAvatar()->isFrozenDead()));
} }
cleanDeadObjects(FALSE); cleanDeadObjects(FALSE);

View File

@@ -3990,10 +3990,11 @@ BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d
} }
// Saves an image to the harddrive as "SnapshotX" where X >= 1. // Saves an image to the harddrive as "SnapshotX" where X >= 1.
void LLViewerWindow::saveImageNumbered(LLPointer<LLImageFormatted> image) void LLViewerWindow::saveImageNumbered(LLPointer<LLImageFormatted> image, int index)
{ {
if (!image) if (!image)
{ {
LLFloaterSnapshot::saveLocalDone(false, index);
return; return;
} }
@@ -4022,15 +4023,15 @@ void LLViewerWindow::saveImageNumbered(LLPointer<LLImageFormatted> image)
// pick a directory in which to save // pick a directory in which to save
AIFilePicker* filepicker = AIFilePicker::create(); // Deleted in LLViewerWindow::saveImageNumbered_continued1 AIFilePicker* filepicker = AIFilePicker::create(); // Deleted in LLViewerWindow::saveImageNumbered_continued1
filepicker->open(proposed_name, pick_type, "", "snapshot"); filepicker->open(proposed_name, pick_type, "", "snapshot");
filepicker->run(boost::bind(&LLViewerWindow::saveImageNumbered_continued1, this, image, extension, filepicker)); filepicker->run(boost::bind(&LLViewerWindow::saveImageNumbered_continued1, this, image, extension, filepicker, index));
return; return;
} }
// LLViewerWindow::sSnapshotBaseName and LLViewerWindow::sSnapshotDir already known. Go straight to saveImageNumbered_continued2. // LLViewerWindow::sSnapshotBaseName and LLViewerWindow::sSnapshotDir already known. Go straight to saveImageNumbered_continued2.
saveImageNumbered_continued2(image, extension); saveImageNumbered_continued2(image, extension, index);
} }
void LLViewerWindow::saveImageNumbered_continued1(LLPointer<LLImageFormatted> image, std::string const& extension, AIFilePicker* filepicker) void LLViewerWindow::saveImageNumbered_continued1(LLPointer<LLImageFormatted> image, std::string const& extension, AIFilePicker* filepicker, int index)
{ {
if (filepicker->hasFilename()) if (filepicker->hasFilename())
{ {
@@ -4040,11 +4041,15 @@ void LLViewerWindow::saveImageNumbered_continued1(LLPointer<LLImageFormatted> im
LLViewerWindow::sSnapshotBaseName = gDirUtilp->getBaseFileName(filepath, true); LLViewerWindow::sSnapshotBaseName = gDirUtilp->getBaseFileName(filepath, true);
LLViewerWindow::sSnapshotDir = gDirUtilp->getDirName(filepath); LLViewerWindow::sSnapshotDir = gDirUtilp->getDirName(filepath);
saveImageNumbered_continued2(image, extension); saveImageNumbered_continued2(image, extension, index);
}
else
{
LLFloaterSnapshot::saveLocalDone(false, index);
} }
} }
void LLViewerWindow::saveImageNumbered_continued2(LLPointer<LLImageFormatted> image, std::string const& extension) void LLViewerWindow::saveImageNumbered_continued2(LLPointer<LLImageFormatted> image, std::string const& extension, int index)
{ {
// Look for an unused file name // Look for an unused file name
std::string filepath; std::string filepath;
@@ -4068,6 +4073,11 @@ void LLViewerWindow::saveImageNumbered_continued2(LLPointer<LLImageFormatted> im
if (image->save(filepath)) if (image->save(filepath))
{ {
playSnapshotAnimAndSound(); playSnapshotAnimAndSound();
LLFloaterSnapshot::saveLocalDone(true, index);
}
else
{
LLFloaterSnapshot::saveLocalDone(false, index);
} }
} }
@@ -4118,7 +4128,7 @@ BOOL LLViewerWindow::saveSnapshot( const std::string& filepath, S32 image_width,
llinfos << "Saving snapshot to: " << filepath << llendl; llinfos << "Saving snapshot to: " << filepath << llendl;
LLPointer<LLImageRaw> raw = new LLImageRaw; LLPointer<LLImageRaw> raw = new LLImageRaw;
BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, FALSE, show_ui, do_rebuild); BOOL success = rawSnapshot(raw, image_width, image_height, (F32)image_width / image_height, show_ui, do_rebuild);
if (success) if (success)
{ {
@@ -4154,7 +4164,7 @@ void LLViewerWindow::playSnapshotAnimAndSound()
BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type)
{ {
return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, do_rebuild, type); return rawSnapshot(raw, preview_width, preview_height, (F32)gViewerWindow->getWindowWidthRaw() / gViewerWindow->getWindowHeightRaw(), show_ui, do_rebuild, type);
// *TODO below code was broken in deferred pipeline // *TODO below code was broken in deferred pipeline
/* /*
@@ -4293,25 +4303,29 @@ BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 p
return TRUE;*/ return TRUE;*/
} }
// Saves the image from the screen to the specified filename and path. // Saves the image from the screen to the image pointed to by raw.
BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, // This function does NOT yet scale the snapshot down to the requested size
BOOL keep_window_aspect, BOOL is_texture, BOOL show_ui, BOOL do_rebuild, ESnapshotType type, S32 max_size, F32 supersample) // if that is smaller than the current window (scale_factor < 1) or if
// the aspect of the snapshot is unequal to the aspect of requested image.
bool LLViewerWindow::rawRawSnapshot(LLImageRaw *raw,
S32 image_width, S32 image_height, F32 snapshot_aspect, BOOL show_ui,
BOOL do_rebuild, ESnapshotType type, S32 max_size, F32 supersample)
{ {
if (!raw) if (!raw)
{ {
return FALSE; return false;
} }
//check if there is enough memory for the snapshot image //check if there is enough memory for the snapshot image
if(LLPipeline::sMemAllocationThrottled) if(LLPipeline::sMemAllocationThrottled)
{ {
return FALSE ; //snapshot taking is disabled due to memory restriction. return false; //snapshot taking is disabled due to memory restriction.
} }
if(image_width * image_height > (1 << 22)) //if snapshot image is larger than 2K by 2K if(image_width * image_height > (1 << 22)) //if snapshot image is larger than 2K by 2K
{ {
if(!LLMemory::tryToAlloc(NULL, image_width * image_height * 3)) if(!LLMemory::tryToAlloc(NULL, image_width * image_height * 3))
{ {
llwarns << "No enough memory to take the snapshot with size (w : h): " << image_width << " : " << image_height << llendl ; llwarns << "No enough memory to take the snapshot with size (w : h): " << image_width << " : " << image_height << llendl ;
return FALSE ; //there is no enough memory for taking this snapshot. return false; //there is no enough memory for taking this snapshot.
} }
} }
@@ -4335,27 +4349,13 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
LLPipeline::sShowHUDAttachments = FALSE; LLPipeline::sShowHUDAttachments = FALSE;
} }
// Copy screen to a buffer // Copy screen to a buffer
// crop sides or top and bottom, if taking a snapshot of different aspect ratio
// from window
LLRect window_rect = show_ui ? getWindowRectRaw() : getWorldViewRectRaw();
S32 snapshot_width = window_rect.getWidth(); LLRect const window_rect = show_ui ? getWindowRectRaw() : getWorldViewRectRaw();
S32 snapshot_height = window_rect.getHeight(); S32 const window_width = window_rect.getWidth();
S32 const window_height = window_rect.getHeight();
// SNAPSHOT // SNAPSHOT
S32 window_width = snapshot_width;
S32 window_height = snapshot_height;
F32 scale_factor = 1.0f ;
bool is_tiling = false;
//fbo method no longer supported. Good riddance
/*LLRenderTarget target;
bool use_fbo = false;
static const LLCachedControl<bool> force_tile("SHHighResSnapshotForceTile",false);*/
#if 1//SHY_MOD // screenshot improvement #if 1//SHY_MOD // screenshot improvement
F32 internal_scale = llmin(llmax(supersample,1.f),3.f); F32 internal_scale = llmin(llmax(supersample,1.f),3.f);
@@ -4379,86 +4379,79 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
} }
} }
if(!keep_window_aspect) //image cropping S32 buffer_x_offset = 0;
{ S32 buffer_y_offset = 0;
F32 ratio = llmin( (F32)window_width / image_width , (F32)window_height / image_height) ; F32 scale_factor;
snapshot_width = (S32)(ratio * image_width) ; S32 image_buffer_x;
snapshot_height = (S32)(ratio * image_height) ; S32 image_buffer_y;
scale_factor = llmax(1.0f, 1.0f / ratio) ;
} F32 const window_aspect = (F32)window_width / window_height;
else //the scene(window) proportion needs to be maintained. // snapshot fits precisely inside window, it is the portion of the window with the correct aspect.
F32 snapshot_width = (snapshot_aspect > window_aspect) ? (F32)window_width : window_height * snapshot_aspect;
F32 snapshot_height = (snapshot_aspect < window_aspect) ? (F32)window_height : window_width / snapshot_aspect;
// ratio is the ratio snapshot/image', where image' is a rectangle with aspect snapshot_aspect that precisely contains image.
// Thus image_width' / image_height' == aspect ==> snapshot_width / image_width' == snapshot_height / image_height'.
// Since image' precisely contains image, one of them is equal (ie, image_height' = image_height) and the other is larger
// (or equal) (ie, image_width' >= image_width), and therefore one of snapshot_width / image_width and
// snapshot_height / image_height is correct, and the other is larger. Therefore, the smallest value of the
// following equals the ratio we're looking for.
F32 ratio = llmin(snapshot_width / image_width, snapshot_height / image_height);
// buffer equals the largest of image' and snapshot. This is because in the first case we need the higher
// resolution because of the size of the target image, and in the second case there is no reason to go
// smaller because it takes the same amount of time (and a slightly better quality should result after
// the final scaling). Thus, if ratio < 1 then buffer equals image', otherwise it equals snapshot.
// scale_factor is the ratio buffer/snapshot, and is initiallly equal to the ratio between buffer
// and snapshot (which have the same aspect).
for(scale_factor = llmax(1.0f, 1.0f / ratio);; // Initial attempt.
// However, if the buffer turns out to be too large, then clamp it to max_size.
scale_factor = llmin(max_size / snapshot_width, max_size / snapshot_height)) // Clamp
{ {
if(image_width > window_width || image_height > window_height) //need to enlarge the scene image_buffer_x = llround(snapshot_width * scale_factor);
image_buffer_y = llround(snapshot_height * scale_factor);
if (llmax(image_buffer_x, image_buffer_y) > max_size && // Boundary check to avoid memory overflow.
internal_scale <= 1.f) // SHY_MOD: If supersampling... Don't care about max_size.
{ {
//Unsupported // Too big, clamp.
/*if (!force_tile && gGLManager.mHasFramebufferObject && !show_ui) continue;
{
GLint max_size = 0;
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &max_size);
if (image_width <= max_size && image_height <= max_size) //re-project the scene
{
use_fbo = TRUE;
snapshot_width = image_width;
snapshot_height = image_height;
target.allocate(snapshot_width, snapshot_height, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, TRUE);
window_width = snapshot_width;
window_height = snapshot_height;
scale_factor = 1.f;
mWindowRectRaw.set(0, snapshot_height, snapshot_width, 0);
target.bindTarget();
}
}
if(!use_fbo) //no re-projection, so tiling the scene*/
{
F32 ratio = llmin( (F32)window_width / image_width , (F32)window_height / image_height) ;
snapshot_width = (S32)(ratio * image_width) ;
snapshot_height = (S32)(ratio * image_height) ;
scale_factor = llmax(1.0f, 1.0f / ratio) ;
is_tiling = true;
}
} }
//else: keep the current scene scale, re-scale it if necessary after reading out. // Done.
break;
} }
// Center the buffer.
S32 buffer_x_offset = llfloor(((window_width - snapshot_width) * scale_factor) / 2.f); buffer_x_offset = llfloor(((window_width - snapshot_width) * scale_factor) / 2.f);
S32 buffer_y_offset = llfloor(((window_height - snapshot_height) * scale_factor) / 2.f); buffer_y_offset = llfloor(((window_height - snapshot_height) * scale_factor) / 2.f);
Dout(dc::notice, "rawSnapshot(" << image_width << ", " << image_height << ", " << snapshot_aspect << "): image_buffer_x = " << image_buffer_x << "; image_buffer_y = " << image_buffer_y);
S32 image_buffer_x = llfloor(snapshot_width*scale_factor) ; bool error = !(image_buffer_x > 0 && image_buffer_y > 0);
S32 image_buffer_y = llfloor(snapshot_height*scale_factor) ; if (!error)
#if 1//SHY_MOD // screenshot improvement
if(internal_scale <= 1.f) //If supersampling... Don't care about max_size.
#endif //shy_mod
if(image_buffer_x > max_size || image_buffer_y > max_size) //boundary check to avoid memory overflow
{ {
scale_factor *= llmin((F32)max_size / image_buffer_x, (F32)max_size / image_buffer_y) ; raw->resize(image_buffer_x, image_buffer_y, 3);
image_buffer_x = llfloor(snapshot_width*scale_factor) ; error = raw->isBufferInvalid();
image_buffer_y = llfloor(snapshot_height *scale_factor) ;
} }
if (image_buffer_x > 0 && image_buffer_y > 0) if (error)
{ {
raw->resize(image_buffer_x, image_buffer_y, 3); if (prev_draw_ui != gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
} {
else LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
{ }
return FALSE ; if (hide_hud)
} {
if(raw->isBufferInvalid()) LLPipeline::sShowHUDAttachments = TRUE;
{ }
return FALSE ; setCursor(UI_CURSOR_ARROW);
return false;
} }
BOOL high_res = scale_factor > 1.f; BOOL is_tiling = scale_factor > 1.f;
if (high_res) if (is_tiling)
{ {
Dout(dc::warning, "USING TILING FOR SNAPSHOT!");
send_agent_pause(); send_agent_pause();
if (show_ui || !hide_hud) if (show_ui || !hide_hud)
{ {
//rescale fonts //rescale fonts
initFonts(scale_factor); initFonts(scale_factor);
LLHUDObject::reshapeAll(); LLHUDObject::reshapeAll();
} }
} }
@@ -4471,7 +4464,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
for (int subimage_y = 0; subimage_y < scale_factor; ++subimage_y) for (int subimage_y = 0; subimage_y < scale_factor; ++subimage_y)
{ {
S32 subimage_y_offset = llclamp(buffer_y_offset - (subimage_y * window_height), 0, window_height);; S32 subimage_y_offset = llclamp(buffer_y_offset - (subimage_y * window_height), 0, window_height);
// handle fractional columns // handle fractional columns
U32 read_height = llmax(0, (window_height - subimage_y_offset) - U32 read_height = llmax(0, (window_height - subimage_y_offset) -
llmax(0, (window_height * (subimage_y + 1)) - (buffer_y_offset + raw->getHeight()))); llmax(0, (window_height * (subimage_y + 1)) - (buffer_y_offset + raw->getHeight())));
@@ -4513,7 +4506,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
// Ping the watchdog thread every 100 lines to keep us alive (arbitrary number, feel free to change) // Ping the watchdog thread every 100 lines to keep us alive (arbitrary number, feel free to change)
if (out_y % 100 == 0) if (out_y % 100 == 0)
{ {
LLAppViewer::instance()->pingMainloopTimeout("LLViewerWindow::rawSnapshot"); LLAppViewer::instance()->pingMainloopTimeout("LLViewerWindow::rawRawSnapshot");
} }
if (type == SNAPSHOT_TYPE_COLOR) if (type == SNAPSHOT_TYPE_COLOR)
@@ -4556,12 +4549,6 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
output_buffer_offset_y += subimage_y_offset; output_buffer_offset_y += subimage_y_offset;
} }
/*if (use_fbo)
{
mWindowRect = window_rect;
target.flush();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}*/
gDisplaySwapBuffers = FALSE; gDisplaySwapBuffers = FALSE;
gDepthDirty = TRUE; gDepthDirty = TRUE;
@@ -4576,36 +4563,12 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
LLPipeline::sShowHUDAttachments = TRUE; LLPipeline::sShowHUDAttachments = TRUE;
} }
if (high_res && (show_ui || !hide_hud)) if (is_tiling && (show_ui || !hide_hud))
{ {
initFonts(1.f); initFonts(1.f);
LLHUDObject::reshapeAll(); LLHUDObject::reshapeAll();
} }
// Pre-pad image to number of pixels such that the line length is a multiple of 4 bytes (for BMP encoding)
// Note: this formula depends on the number of components being 3. Not obvious, but it's correct.
image_width += (image_width * 3) % 4;
BOOL ret = TRUE ;
// Resize image
if(llabs(image_width - image_buffer_x) > 4 || llabs(image_height - image_buffer_y) > 4)
{
ret = raw->scale( image_width, image_height );
}
else if(image_width != image_buffer_x || image_height != image_buffer_y)
{
ret = raw->scale( image_width, image_height, FALSE );
}
#if 1//SHY_MOD // screenshot improvement
if(raw->isBufferInvalid()) //Just checking!
return FALSE;
if(internal_scale != 1.f) //Scale down our render to the desired dimensions.
raw->scale( image_width/internal_scale, image_height/internal_scale );
if(raw->isBufferInvalid()) //Just checking!
return FALSE;
#endif //shy_mod
setCursor(UI_CURSOR_ARROW); setCursor(UI_CURSOR_ARROW);
if (do_rebuild) if (do_rebuild)
@@ -4618,11 +4581,50 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
gPipeline.resetDrawOrders(); gPipeline.resetDrawOrders();
} }
if (high_res) if (is_tiling)
{ {
send_agent_resume(); send_agent_resume();
} }
return true;
}
// Same as the above, but does the resizing.
bool LLViewerWindow::rawSnapshot(LLImageRaw *raw,
S32 image_width, S32 image_height, F32 snapshot_aspect, BOOL show_ui,
BOOL do_rebuild, ESnapshotType type, S32 max_size, F32 supersample)
{
bool ret = rawRawSnapshot(raw, image_width, image_height, snapshot_aspect, show_ui, do_rebuild, type, max_size, supersample);
#if 1
if (ret && !raw->scale(image_width, image_height))
{
ret = false; // Failure.
}
#else // This was the old behavior.. but I don't think this is needed here.
if (ret)
{
// Pad image width such that the line length is a multiple of 4 bytes (for BMP encoding).
int n = 4;
for (int c = raw->getComponents(); c % 2 == 0 && n > 1; c /= 2) { n /= 2; } // n /= gcd(n, components)
image_width += (image_width * (n - 1)) % n; // Now n divides image_width, and thus four divides image_width * components, the line length.
// Resize image
if (llabs(image_width - image_buffer_x) > 4 || llabs(image_height - image_buffer_y) > 4)
{
ret = raw->scale( image_width, image_height );
}
else if (image_width != image_buffer_x || image_height != image_buffer_y)
{
ret = raw->scale( image_width, image_height, FALSE );
}
}
#endif
return ret; return ret;
} }

View File

@@ -308,17 +308,21 @@ public:
enum ESnapshotType enum ESnapshotType
{ {
SNAPSHOT_TYPE_COLOR, SNAPSHOT_TYPE_COLOR,
SNAPSHOT_TYPE_DEPTH, SNAPSHOT_TYPE_DEPTH
}; };
BOOL saveSnapshot(const std::string& filename, S32 image_width, S32 image_height, BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR); BOOL saveSnapshot(const std::string& filename, S32 image_width, S32 image_height, BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR);
BOOL rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, BOOL keep_window_aspect = TRUE, BOOL is_texture = FALSE, bool rawRawSnapshot(LLImageRaw* raw, S32 image_width, S32 image_height, F32 aspect,
BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_SNAPSHOT_IMAGE_SIZE, F32 supersample = 1.f ); BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR,
S32 max_size = MAX_SNAPSHOT_IMAGE_SIZE, F32 supersample = 1.f);
bool rawSnapshot(LLImageRaw* raw, S32 image_width, S32 image_height, F32 aspect,
BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR,
S32 max_size = MAX_SNAPSHOT_IMAGE_SIZE, F32 supersample = 1.f);
BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) ; BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) ;
BOOL isSnapshotLocSet() const { return ! sSnapshotDir.empty(); } BOOL isSnapshotLocSet() const { return ! sSnapshotDir.empty(); }
void resetSnapshotLoc() const { sSnapshotDir.clear(); } void resetSnapshotLoc() const { sSnapshotDir.clear(); }
void saveImageNumbered(LLPointer<LLImageFormatted> image); void saveImageNumbered(LLPointer<LLImageFormatted> image, int index);
void saveImageNumbered_continued1(LLPointer<LLImageFormatted> image, std::string const& extension, AIFilePicker* filepicker); void saveImageNumbered_continued1(LLPointer<LLImageFormatted> image, std::string const& extension, AIFilePicker* filepicker, int index);
void saveImageNumbered_continued2(LLPointer<LLImageFormatted> image, std::string const& extension); void saveImageNumbered_continued2(LLPointer<LLImageFormatted> image, std::string const& extension, int index);
// Reset the directory where snapshots are saved. // Reset the directory where snapshots are saved.
// Client will open directory picker on next snapshot save. // Client will open directory picker on next snapshot save.

View File

@@ -993,6 +993,12 @@ EmeraldGlobalBoobConfig LLVOAvatar::sBoobConfig;
static F32 calc_bouncy_animation(F32 x); static F32 calc_bouncy_animation(F32 x);
static U32 calc_shame(LLVOVolume* volume, std::set<LLUUID> &textures); static U32 calc_shame(LLVOVolume* volume, std::set<LLUUID> &textures);
//-----------------------------------------------------------------------------
// Debug setting caches.
//-----------------------------------------------------------------------------
static LLCachedControl<bool> const freeze_time("FreezeTime", false);
static LLCachedControl<bool> const render_unloaded_avatar("RenderUnloadedAvatar", false);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// LLVOAvatar() // LLVOAvatar()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@@ -1005,6 +1011,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mAttachmentGeometryBytes(0), mAttachmentGeometryBytes(0),
mAttachmentSurfaceArea(0.f), mAttachmentSurfaceArea(0.f),
mTurning(FALSE), mTurning(FALSE),
mFreezeTimeLangolier(freeze_time),
mFreezeTimeDead(false),
mPelvisToFoot(0.f), mPelvisToFoot(0.f),
mLastSkeletonSerialNum( 0 ), mLastSkeletonSerialNum( 0 ),
mHeadOffset(), mHeadOffset(),
@@ -1045,7 +1053,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mSupportsAlphaLayers(FALSE), mSupportsAlphaLayers(FALSE),
mLoadedCallbacksPaused(FALSE), mLoadedCallbacksPaused(FALSE),
mHasPelvisOffset( FALSE ), mHasPelvisOffset( FALSE ),
mRenderUnloadedAvatar(LLCachedControl<bool>(gSavedSettings, "RenderUnloadedAvatar")), mRenderUnloadedAvatar(render_unloaded_avatar),
mLastRezzedStatus(-1), mLastRezzedStatus(-1),
mFirstSetActualBoobGravRan( false ), mFirstSetActualBoobGravRan( false ),
mSupportsPhysics( false ), mSupportsPhysics( false ),
@@ -1229,6 +1237,13 @@ LLVOAvatar::~LLVOAvatar()
void LLVOAvatar::markDead() void LLVOAvatar::markDead()
{ {
static const LLCachedControl<bool> freeze_time("FreezeTime", false);
if (freeze_time && !mFreezeTimeLangolier)
{
// Delay the call to this function until FreezeTime is reset, otherwise avatars disappear from the frozen scene.
mFreezeTimeDead = true;
return;
}
if (mNameText) if (mNameText)
{ {
mNameText->markDead(); mNameText->markDead();
@@ -3662,6 +3677,7 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name)
} }
bool is_friend = LLAvatarTracker::instance().isBuddy(getID()); bool is_friend = LLAvatarTracker::instance().isBuddy(getID());
bool is_cloud = getIsCloud(); bool is_cloud = getIsCloud();
bool is_langolier = isLangolier();
if (is_appearance != mNameAppearance) if (is_appearance != mNameAppearance)
{ {
@@ -3687,7 +3703,8 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name)
|| is_muted != mNameMute || is_muted != mNameMute
|| is_appearance != mNameAppearance || is_appearance != mNameAppearance
|| is_friend != mNameFriend || is_friend != mNameFriend
|| is_cloud != mNameCloud) || is_cloud != mNameCloud
|| is_langolier != mNameLangolier)
{ {
LLColor4 name_tag_color = getNameTagColor(is_friend); LLColor4 name_tag_color = getNameTagColor(is_friend);
@@ -3697,7 +3714,7 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name)
std::string firstnameText; std::string firstnameText;
std::string lastnameText; std::string lastnameText;
if (is_away || is_muted || is_busy || is_appearance || !idle_string.empty()) if (is_away || is_muted || is_busy || is_appearance || is_langolier || !idle_string.empty())
{ {
std::string line; std::string line;
if (is_away) if (is_away)
@@ -3720,7 +3737,12 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name)
line += LLTrans::getString("AvatarEditingAppearance"); //"(Editing Appearance)" line += LLTrans::getString("AvatarEditingAppearance"); //"(Editing Appearance)"
line += ", "; line += ", ";
} }
if (is_cloud) if (is_langolier)
{
line += LLTrans::getString("AvatarLangolier"); //"Langolier"
line += ", ";
}
else if (is_cloud)
{ {
line += LLTrans::getString("LoadingData"); //"Loading..." line += LLTrans::getString("LoadingData"); //"Loading..."
line += ", "; line += ", ";
@@ -3847,6 +3869,7 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name)
mNameAppearance = is_appearance; mNameAppearance = is_appearance;
mNameFriend = is_friend; mNameFriend = is_friend;
mNameCloud = is_cloud; mNameCloud = is_cloud;
mNameLangolier = is_langolier;
mTitle = title ? title->getString() : ""; mTitle = title ? title->getString() : "";
LLStringFn::replace_ascii_controlchars(mTitle,LL_UNKNOWN_CHAR); LLStringFn::replace_ascii_controlchars(mTitle,LL_UNKNOWN_CHAR);
new_name = TRUE; new_name = TRUE;
@@ -4084,7 +4107,18 @@ bool LLVOAvatar::isVisuallyMuted() const
return LLMuteList::getInstance()->isMuted(getID()) || return LLMuteList::getInstance()->isMuted(getID()) ||
(mAttachmentGeometryBytes > max_attachment_bytes && max_attachment_bytes > 0) || (mAttachmentGeometryBytes > max_attachment_bytes && max_attachment_bytes > 0) ||
(mAttachmentSurfaceArea > max_attachment_area && max_attachment_area > 0.f); (mAttachmentSurfaceArea > max_attachment_area && max_attachment_area > 0.f) ||
isLangolier();
}
void LLVOAvatar::resetFreezeTime()
{
bool dead = mFreezeTimeDead;
mFreezeTimeLangolier = mFreezeTimeDead = false;
if (dead)
{
markDead();
}
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
@@ -4095,6 +4129,13 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
{ {
LLMemType mt(LLMemType::MTYPE_AVATAR); LLMemType mt(LLMemType::MTYPE_AVATAR);
// Frozen!
if (areAnimationsPaused())
{
updateMotions(LLCharacter::NORMAL_UPDATE); // This is necessary to get unpaused again.
return FALSE;
}
// clear debug text // clear debug text
mDebugText.clear(); mDebugText.clear();
if (LLVOAvatar::sShowAnimationDebug) if (LLVOAvatar::sShowAnimationDebug)

View File

@@ -341,6 +341,8 @@ public:
BOOL hasGray() const; BOOL hasGray() const;
S32 getRezzedStatus() const; // 0 = cloud, 1 = gray, 2 = fully textured. S32 getRezzedStatus() const; // 0 = cloud, 1 = gray, 2 = fully textured.
void updateRezzedStatusTimers(); void updateRezzedStatusTimers();
bool isLangolier() const { return mFreezeTimeLangolier; }
bool isFrozenDead() const { return mFreezeTimeDead; }
S32 mLastRezzedStatus; S32 mLastRezzedStatus;
protected: protected:
@@ -358,6 +360,8 @@ private:
S32 mVisualComplexity; S32 mVisualComplexity;
LLFrameTimer mFullyLoadedTimer; LLFrameTimer mFullyLoadedTimer;
LLFrameTimer mRuthTimer; LLFrameTimer mRuthTimer;
bool mFreezeTimeLangolier; // True when this avatar was created during snapshot FreezeTime mode, and that mode is still active.
bool mFreezeTimeDead; // True when the avatar was marked dead (ie, TP-ed away) while in FreezeTime mode.
protected: protected:
LLFrameTimer mInvisibleTimer; LLFrameTimer mInvisibleTimer;
@@ -453,6 +457,7 @@ private:
public: public:
U32 renderImpostor(LLColor4U color = LLColor4U(255,255,255,255), S32 diffuse_channel = 0); U32 renderImpostor(LLColor4U color = LLColor4U(255,255,255,255), S32 diffuse_channel = 0);
bool isVisuallyMuted() const; bool isVisuallyMuted() const;
void resetFreezeTime();
U32 renderRigid(); U32 renderRigid();
U32 renderSkinned(EAvatarRenderPass pass); U32 renderSkinned(EAvatarRenderPass pass);
@@ -1012,6 +1017,7 @@ private:
bool mNameAppearance; bool mNameAppearance;
bool mNameFriend; bool mNameFriend;
bool mNameCloud; bool mNameCloud;
bool mNameLangolier;
F32 mNameAlpha; F32 mNameAlpha;
BOOL mRenderGroupTitles; BOOL mRenderGroupTitles;

View File

@@ -374,7 +374,7 @@ void LLWaterParamManager::updateShaderLinks()
void LLWaterParamManager::update(LLViewerCamera * cam) void LLWaterParamManager::update(LLViewerCamera * cam)
{ {
LLFastTimer ftm(FTM_UPDATE_WATERPARAM); LLFastTimer ftm(FTM_UPDATE_WATERPARAM);
// update the shaders and the menu // update the shaders and the menu
propagateParameters(); propagateParameters();

View File

@@ -114,12 +114,13 @@ public:
config["caption"] = data.get("caption", "").asString(); config["caption"] = data.get("caption", "").asString();
// Do the actual image upload using the configuration. // Do the actual image upload using the configuration.
LL_DEBUGS("Snapshots") << "Got upload config, POSTing image to " << upload_url << ", config=[" << config << "]" << llendl; LL_DEBUGS("Snapshots") << "Got upload config, POSTing image to " << upload_url << ", config=[" << config << "]" << LL_ENDL;
LLWebProfile::post(mImagep, config, upload_url); LLWebProfile::post(mImagep, config, upload_url);
} }
protected: protected:
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return webProfileResponders_timeout; } /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return webProfileResponders_timeout; }
/*virtual*/ bool followRedir(void) const { return true; }
private: private:
LLPointer<LLImageFormatted> mImagep; LLPointer<LLImageFormatted> mImagep;
@@ -150,12 +151,13 @@ public:
strstrm << istr.rdbuf(); strstrm << istr.rdbuf();
const std::string body = strstrm.str(); const std::string body = strstrm.str();
llinfos << "Image uploaded." << llendl; llinfos << "Image uploaded." << llendl;
LL_DEBUGS("Snapshots") << "Uploading image succeeded. Response: [" << body << "]" << llendl; LL_DEBUGS("Snapshots") << "Uploading image succeeded. Response: [" << body << "]" << LL_ENDL;
LLWebProfile::reportImageUploadStatus(true); LLWebProfile::reportImageUploadStatus(true);
} }
protected: protected:
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return webProfileResponders_timeout; } /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return webProfileResponders_timeout; }
/*virtual*/ bool followRedir(void) const { return true; }
private: private:
LLPointer<LLImageFormatted> mImagep; LLPointer<LLImageFormatted> mImagep;
@@ -171,10 +173,11 @@ class LLWebProfileResponders::PostImageResponder : public LLHTTPClient::Responde
public: public:
/*virtual*/ bool needsHeaders(void) const { return true; } /*virtual*/ bool needsHeaders(void) const { return true; }
/*virtual*/ void completedHeader(U32 status, const std::string& reason, const LLSD& content) /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& received_headers)
{ {
// Viewer seems to fail to follow a 303 redirect on POST request // Server abuses 303 status; Curl can't handle it because it tries to resent
// (URLRequest Error: 65, Send failed since rewinding of the data stream failed). // the just uploaded data, which fails
// (CURLE_SEND_FAIL_REWIND: Send failed since rewinding of the data stream failed).
// Handle it manually. // Handle it manually.
if (status == 303) if (status == 303)
{ {
@@ -182,14 +185,15 @@ public:
headers.addHeader("Accept", "*/*"); headers.addHeader("Accept", "*/*");
headers.addHeader("Cookie", LLWebProfile::getAuthCookie()); headers.addHeader("Cookie", LLWebProfile::getAuthCookie());
headers.addHeader("User-Agent", LLViewerMedia::getCurrentUserAgent()); headers.addHeader("User-Agent", LLViewerMedia::getCurrentUserAgent());
const std::string& redir_url = content["location"]; std::string redir_url;
LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << llendl; received_headers.getFirstValue("location", redir_url);
LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << LL_ENDL;
LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder, headers); LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder, headers);
} }
else else
{ {
llwarns << "Unexpected POST status: " << status << " " << reason << llendl; llwarns << "Unexpected POST status: " << status << " " << reason << llendl;
LL_DEBUGS("Snapshots") << "headers: [" << content << "]" << llendl; LL_DEBUGS("Snapshots") << "received_headers: [" << received_headers << "]" << LL_ENDL;
LLWebProfile::reportImageUploadStatus(false); LLWebProfile::reportImageUploadStatus(false);
} }
} }
@@ -203,6 +207,7 @@ public:
protected: protected:
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return webProfileResponders_timeout; } /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return webProfileResponders_timeout; }
/*virtual*/ bool redirect_status_ok(void) const { return true; }
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@@ -219,7 +224,7 @@ void LLWebProfile::uploadImage(LLPointer<LLImageFormatted> image, const std::str
config_url += "?caption=" + LLURI::escape(caption); config_url += "?caption=" + LLURI::escape(caption);
config_url += "&add_loc=" + std::string(add_location ? "1" : "0"); config_url += "&add_loc=" + std::string(add_location ? "1" : "0");
LL_DEBUGS("Snapshots") << "Requesting " << config_url << llendl; LL_DEBUGS("Snapshots") << "Requesting " << config_url << LL_ENDL;
AIHTTPHeaders headers; AIHTTPHeaders headers;
headers.addHeader("Accept", "*/*"); headers.addHeader("Accept", "*/*");
headers.addHeader("Cookie", LLWebProfile::getAuthCookie()); headers.addHeader("Cookie", LLWebProfile::getAuthCookie());
@@ -230,7 +235,7 @@ void LLWebProfile::uploadImage(LLPointer<LLImageFormatted> image, const std::str
// static // static
void LLWebProfile::setAuthCookie(const std::string& cookie) void LLWebProfile::setAuthCookie(const std::string& cookie)
{ {
LL_DEBUGS("Snapshots") << "Setting auth cookie: " << cookie << llendl; LL_DEBUGS("Snapshots") << "Setting auth cookie: " << cookie << LL_ENDL;
sAuthCookie = cookie; sAuthCookie = cookie;
} }
@@ -286,24 +291,22 @@ void LLWebProfile::post(LLPointer<LLImageFormatted> image, const LLSD& config, c
body << "--" << boundary << "\r\n" body << "--" << boundary << "\r\n"
<< "Content-Disposition: form-data; name=\"file\"; filename=\"snapshot.png\"\r\n" << "Content-Disposition: form-data; name=\"file\"; filename=\"snapshot.png\"\r\n"
<< "Content-Type: image/png\r\n\r\n"; << "Content-Type: image/png\r\n\r\n";
size_t const body_size = body.str().size();
// Insert the image data. std::ostringstream footer;
// *FIX: Treating this as a string will probably screw it up ... footer << "\r\n--" << boundary << "--\r\n";
U8* image_data = image->getData(); size_t const footer_size = footer.str().size();
for (S32 i = 0; i < image->getDataSize(); ++i)
{
body << image_data[i];
}
body << "\r\n--" << boundary << "--\r\n";
size_t size = body_size + image->getDataSize() + footer_size;
// postRaw() takes ownership of the buffer and releases it later. // postRaw() takes ownership of the buffer and releases it later.
size_t size = body.str().size();
char* data = new char [size]; char* data = new char [size];
memcpy(data, body.str().data(), size); memcpy(data, body.str().data(), body_size);
// Insert the image data.
memcpy(data + body_size, image->getData(), image->getDataSize());
memcpy(data + body_size + image->getDataSize(), footer.str().data(), footer_size);
// Send request, successful upload will trigger posting metadata. // Send request, successful upload will trigger posting metadata.
LLHTTPClient::postRaw(url, data, size, new LLWebProfileResponders::PostImageResponder(), headers); LLHTTPClient::postRaw(url, data, size, new LLWebProfileResponders::PostImageResponder(), headers/*,*/ DEBUG_CURLIO_PARAM(debug_off), no_keep_alive);
} }
// static // static

View File

@@ -475,7 +475,7 @@ void LLWLParamManager::propagateParameters(void)
void LLWLParamManager::update(LLViewerCamera * cam) void LLWLParamManager::update(LLViewerCamera * cam)
{ {
LLFastTimer ftm(FTM_UPDATE_WLPARAM); LLFastTimer ftm(FTM_UPDATE_WLPARAM);
// update clouds, sun, and general // update clouds, sun, and general
mCurParams.updateCloudScrolling(); mCurParams.updateCloudScrolling();

View File

@@ -682,6 +682,12 @@ void LLWorld::updateRegions(F32 max_update_time)
void LLWorld::updateParticles() void LLWorld::updateParticles()
{ {
static const LLCachedControl<bool> freeze_time("FreezeTime",false);
if (freeze_time)
{
// don't move particles in snapshot mode
return;
}
LLViewerPartSim::getInstance()->updateSimulation(); LLViewerPartSim::getInstance()->updateSimulation();
} }

View File

@@ -10,6 +10,7 @@
name="floater_merchant_outbox" name="floater_merchant_outbox"
save_rect="true" save_rect="true"
save_visibility="false" save_visibility="false"
rect_control="FloaterOutboxRect"
reuse_instance="true" reuse_instance="true"
title="Merchant Outbox" title="Merchant Outbox"
width="333"> width="333">

View File

@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?> <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<floater can_close="true" can_drag_on_left="false" can_minimize="false" <floater can_close="true" can_drag_on_left="false" can_minimize="false"
can_resize="true" height="380" min_height="380" min_width="450" can_resize="true" height="346" min_height="346" min_width="450"
name="Postcard" title="Email Snapshot" width="450"> name="Postcard" title="Email Snapshot" width="450"
rect_control="FloaterSnapshotPostcardRect">
<text bottom="-35" follows="top|left" font="SansSerif" left="12" name="to_label"> <text bottom="-35" follows="top|left" font="SansSerif" left="12" name="to_label">
Recipient&apos;s Email: Recipient&apos;s Email:
</text> </text>
@@ -34,10 +35,6 @@
max_length="700" name="msg_form" width="420" spell_check="true"> max_length="700" name="msg_form" width="420" spell_check="true">
Type your message here. Type your message here.
</text_editor> </text_editor>
<text bottom_delta="-37" follows="left|bottom" font="SansSerifSmall" left="12"
name="fine_print">
If your recipient joins our universe, you&apos;ll get a referral bonus.
</text>
<button bottom_delta="-32" follows="right|bottom" height="20" label="Cancel" <button bottom_delta="-32" follows="right|bottom" height="20" label="Cancel"
name="cancel_btn" right="-10" width="100" /> name="cancel_btn" right="-10" width="100" />
<button bottom_delta="0" follows="right|bottom" height="20" label="Send" <button bottom_delta="0" follows="right|bottom" height="20" label="Send"

View File

@@ -1,58 +1,97 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?> <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<floater bottom="-300" can_close="true" can_drag_on_left="false" can_minimize="false" <floater bottom="-300" can_close="true" can_drag_on_left="false" can_minimize="false"
can_resize="false" follows="left|top" height="566" name="Snapshot" can_resize="false" follows="left|top" height="629" name="Snapshot"
rect_control="FloaterSnapshotRect" title="Snapshot Preview" width="215"> rect_control="FloaterSnapshotRect" title="Snapshot Preview" width="219">
<text bottom_delta="-40" follows="top|left" height="15" left="10" name="type_label" <text bottom="-201" right="-6" height="25" name="file_size_label" halign="right" width="120">
width="195">
Snapshot destination
</text>
<radio_group bottom_delta="-65" follows="left|top" height="60" label="Snapshot type"
left="10" name="snapshot_type_radio" width="195">
<radio_item bottom="-19" height="16" name="postcard">
Send via email
</radio_item>
<radio_item bottom="-38" height="16" name="texture">
Save to your inventory ([UPLOADFEE])
</radio_item>
<radio_item bottom="-57" height="16" name="local">
Save to your hard drive
</radio_item>
</radio_group>
<text bottom="-236" follows="left|top" height="25" left="10" name="file_size_label"
width="195">
File size: [SIZE] KB File size: [SIZE] KB
</text> </text>
<button bottom="-246" follows="left|top" height="20" label="Refresh Snapshot" left="10" <text bottom="-195" height="15" left="10" name="type_label" halign="left">
name="new_snapshot_btn" width="195" /> Target
<button bottom_delta="-22" follows="left|top" height="20" label="Send" left="10" </text>
<radio_group bottom_delta="-79" follows="left|top" height="79" label="Snapshot type"
left="10" name="snapshot_type_radio" width="200">
<radio_item bottom="-19" height="16" name="feed">
Post to my.secondlife.com feed
</radio_item>
<radio_item bottom="-38" height="16" name="postcard">
Send via email
</radio_item>
<radio_item bottom="-57" height="16" name="texture">
Save to my inventory ([UPLOADFEE])
</radio_item>
<radio_item bottom="-76" height="16" name="local">
Save to my hard drive
</radio_item>
</radio_group>
<button bottom_delta="-28" follows="left|top" height="20" label="Refresh snapshot" left="10"
name="new_snapshot_btn" width="115" tool_tip="Make a snapshot of the current view. Use the save and/or upload button to actually save it. The latest snapshot is shown in the thumbnail. In Freeze Time mode a preview of the new snapshot is also shown full screen (note that this has NOT the same quality as the real thing that will be saved: it is downscaled from the actual formatted image to a power of two with a max. resolution of 1024x1024, in order to be displayed in openGL and then probably stretched again to fill your screen). Press ESC to go back to Freeze Time." />
<button bottom_delta="0" follows="left|top" height="20" label="Freeze time" left="129"
name="freeze_time_btn" width="80" tool_tip="Freeze time and show a fullscreen preview. Allows to cam around as if time is frozen and make multiple snapshots of the same scene. Press ESC to undo!" />
<button bottom_delta="-22" follows="left|top" height="20" label="Upload" left="10"
name="feed_btn" width="105" />
<button bottom_delta="0" follows="left|top" height="20" label="Send" left="10"
name="send_btn" width="105" /> name="send_btn" width="105" />
<button bottom_delta="0" follows="left|top" height="20" label="Save ([UPLOADFEE])" left="10" <button bottom_delta="0" follows="left|top" height="20" label="Upload ([UPLOADFEE])" left="10"
name="upload_btn" width="105" /> name="upload_btn" width="105" />
<flyout_button bottom_delta="0" follows="left|top" height="20" label="Save" left="10" <flyout_button bottom_delta="-2" follows="left|top" height="20" label="Save" left="10"
list_position="below" mouse_opaque="true" name="save_btn" tool_tip="Save image to a file" list_position="below" mouse_opaque="true" name="save_btn" tool_tip="Save image to a file" width="105">
width="105">
<flyout_button_item value="save" name="save_item">Save</flyout_button_item> <flyout_button_item value="save" name="save_item">Save</flyout_button_item>
<flyout_button_item value="saveas" name="saveas_item">Save As...</flyout_button_item> <flyout_button_item value="saveas" name="saveas_item">Save As...</flyout_button_item>
</flyout_button> </flyout_button>
<button bottom_delta="0" follows="left|top" height="20" label="Cancel" left="120" <combo_box bottom_delta="-4" follows="left|top" height="20" label="Format" left="139"
name="discard_btn" width="85" /> name="local_format_combo" width="70">
<button bottom="-290" follows="left|top" font="SansSerifSmall" halign="center" <combo_item name="PNG">
height="20" label="More &gt;&gt;" left="10" PNG
</combo_item>
<combo_item name="JPEG">
JPEG
</combo_item>
<combo_item name="BMP">
BMP
</combo_item>
</combo_box>
<button bottom_delta="-22" follows="left|top" font="SansSerifSmall" halign="center"
height="20" label="Advanced&gt;&gt;" left="10"
mouse_opaque="true" name="more_btn" scale_image="TRUE" mouse_opaque="true" name="more_btn" scale_image="TRUE"
tool_tip="Advanced Options" width="80" /> tool_tip="Advanced Options. Default uses current window size (500x375 for profile feed)." width="72" />
<button bottom_delta="0" follows="left|top" font="SansSerifSmall" halign="center" <button bottom_delta="0" follows="left|top" font="SansSerifSmall" halign="center"
height="20" label="&lt;&lt; Less" left_delta="0" height="20" label="&lt;&lt;Default" left_delta="0"
mouse_opaque="true" name="less_btn" scale_image="TRUE" mouse_opaque="true" name="less_btn" scale_image="TRUE"
tool_tip="Advanced Options" width="80" /> tool_tip="Advanced Options. Default uses current window size (500x375 for profile feed)." width="72" />
<text bottom_delta="-20" follows="top|left" height="15" left="10" name="type_label2" <slider bottom_delta="0" decimal_digits="0" follows="left|top" height="15"
width="115"> increment="1" initial_val="75" left="80"
Size max_val="100" min_val="0" name="image_quality_slider" width="150" />
</text> <text bottom_delta="-20" follows="top|left" height="15" left="10" name="type_label2" width="115">
<text bottom_delta="0" follows="top|left" height="15" left="130" name="format_label" Target size
width="70"> </text>
Format
</text>
<combo_box bottom_delta="-22" follows="left|top" height="20" label="Resolution" left="10" <combo_box bottom_delta="-22" follows="left|top" height="20" label="Resolution" left="10"
name="feed_size_combo" width="125">
<combo_item name="CurrentWindow" value="[i0,i0]">
Current Window
</combo_item>
<combo_item name="500x500" value="[i500,i500]">
500x500 (1:1)
</combo_item>
<combo_item name="500x375" value="[i500,i375]">
500x375 (4:3)
</combo_item>
<combo_item name="500x350" value="[i500,i350]">
500x350 (10:7)
</combo_item>
<combo_item name="500x313" value="[i500,i313]">
500x313 (16:10)
</combo_item>
<combo_item name="500x281" value="[i500,i281]">
500x281 (16:9)
</combo_item>
<combo_item name="500x250" value="[i500,i250]">
500x250 (2:1)
</combo_item>
<combo_item name="Custom" value="[i-1,i-1]">
Custom
</combo_item>
</combo_box>
<combo_box bottom_delta="0" follows="left|top" height="20" label="Resolution" left="10"
name="postcard_size_combo" width="115"> name="postcard_size_combo" width="115">
<combo_item name="CurrentWindow" value="[i0,i0]"> <combo_item name="CurrentWindow" value="[i0,i0]">
Current Window Current Window
@@ -60,6 +99,9 @@
<combo_item name="640x480" value="[i640,i480]"> <combo_item name="640x480" value="[i640,i480]">
640x480 640x480
</combo_item> </combo_item>
<combo_item name="700x525" value="[i700,i525]">
700x525
</combo_item>
<combo_item name="800x600" value="[i800,i600]"> <combo_item name="800x600" value="[i800,i600]">
800x600 800x600
</combo_item> </combo_item>
@@ -72,20 +114,32 @@
</combo_box> </combo_box>
<combo_box bottom_delta="0" follows="left|top" height="20" label="Resolution" left="10" <combo_box bottom_delta="0" follows="left|top" height="20" label="Resolution" left="10"
name="texture_size_combo" width="115"> name="texture_size_combo" width="115">
<combo_item name="CurrentWindow" value="[i0,i0]"> <combo_item name="512x512" value="[i512,i512]">
Current Window 512x512 (1:1)
</combo_item> </combo_item>
<combo_item name="Small(128x128)" value="[i128,i128]"> <combo_item name="256x256" value="[i256,i256]">
Small (128x128) 256x256 (1:1)
</combo_item> </combo_item>
<combo_item name="Medium(256x256)" value="[i256,i256]"> <combo_item name="128x128" value="[i128,i128]">
Medium (256x256) 128x128 (1:1)
</combo_item> </combo_item>
<combo_item name="Large(512x512)" value="[i512,i512]"> <combo_item name="512x256" value="[i512,i256]">
Large (512x512) 512x256 (2:1)
</combo_item> </combo_item>
<combo_item name="Custom" value="[i-1,i-1]"> <combo_item name="256x128" value="[i256,i128]">
Custom 256x128 (2:1)
</combo_item>
<combo_item name="256x512" value="[i256,i512]">
256x512 (1:2)
</combo_item>
<combo_item name="128x256" value="[i128,i256]">
128x256 (1:2)
</combo_item>
<combo_item name="512x128" value="[i512,i128]">
512x128 (4:1)
</combo_item>
<combo_item name="128x512" value="[i128,i512]">
128x512 (1:4)
</combo_item> </combo_item>
</combo_box> </combo_box>
<combo_box bottom_delta="0" follows="left|top" height="20" label="Resolution" left="10" <combo_box bottom_delta="0" follows="left|top" height="20" label="Resolution" left="10"
@@ -105,45 +159,122 @@
<combo_item name="1024x768" value="[i1024,i768]"> <combo_item name="1024x768" value="[i1024,i768]">
1024x768 1024x768
</combo_item> </combo_item>
<combo_item name="1280x960" value="[i1280,i960]">
1280x960
</combo_item>
<combo_item name="1280x1024" value="[i1280,i1024]"> <combo_item name="1280x1024" value="[i1280,i1024]">
1280x1024 1280x1024
</combo_item> </combo_item>
<combo_item name="1600x1200" value="[i1600,i1200]"> <combo_item name="1600x1200" value="[i1600,i1200]">
1600x1200 1600x1200
</combo_item> </combo_item>
<combo_item name="1680x1050" value="[i1680,i1050]">
1680x1050
</combo_item>
<combo_item name="Custom" value="[i-1,i-1]"> <combo_item name="Custom" value="[i-1,i-1]">
Custom Custom
</combo_item> </combo_item>
</combo_box> </combo_box>
<combo_box bottom_delta="0" follows="left|top" height="20" label="Format" left="130"
name="local_format_combo" width="70">
<combo_item name="PNG">
PNG
</combo_item>
<combo_item name="JPEG">
JPEG
</combo_item>
<combo_item name="BMP">
BMP
</combo_item>
</combo_box>
<spinner bottom_delta="-25" decimal_digits="0" follows="left|top" height="20" <spinner bottom_delta="-25" decimal_digits="0" follows="left|top" height="20"
increment="32" label="Width" label_width="30" left="10" max_val="6016" increment="32" label="Width" label_width="30" left="10" max_val="6016"
min_val="32" name="snapshot_width" width="95" allow_text_entry="false"/> min_val="32" name="snapshot_width" width="95" allow_text_entry="false"/>
<spinner bottom_delta="0" decimal_digits="0" follows="left|top" height="20" <spinner bottom_delta="0" decimal_digits="0" follows="left|top" height="20"
increment="32" label="Height" label_width="35" left="110" max_val="6016" increment="32" label="Height" label_width="35" left="110" max_val="6016"
min_val="32" name="snapshot_height" width="95" allow_text_entry="false"/> min_val="32" name="snapshot_height" width="95" allow_text_entry="false"/>
<check_box bottom_delta="-20" follows="left|top" label="Constrain Proportions" left="10" <text bottom_delta="-18" follows="top|left" height="15" left="10" name="type_label3"
name="keep_aspect_check" /> width="115">
<slider bottom_delta="-20" decimal_digits="0" follows="left|top" height="15" Target aspect ratio
increment="1" initial_val="75" label="Image Quality" left="10" </text>
max_val="100" min_val="0" name="image_quality_slider" width="210" /> <combo_box bottom_delta="-22" follows="left|top" height="20" label="Aspect" left="10"
<text bottom_delta="-28" follows="left|top" height="20" left="10" name="feed_aspect_combo" width="115">
<combo_item name="Default" value="-2">
Default
</combo_item>
<combo_item name="Custom" value="-1">
Custom
</combo_item>
</combo_box>
<combo_box bottom_delta="0" follows="left|top" height="20" label="Aspect" left="10"
name="postcard_aspect_combo" width="115">
<combo_item name="Default" value="-2">
Default
</combo_item>
<combo_item name="Custom" value="-1">
Custom
</combo_item>
</combo_box>
<combo_box bottom_delta="0" follows="left|top" height="20" label="Aspect" left="10"
name="texture_aspect_combo" width="115">
<combo_item name="CurrentWindow" value="0">
Current Window
</combo_item>
<combo_item name="1:1" value="1">
1:1
</combo_item>
<combo_item name="4:3" value="1.33333">
4:3 (profile)
</combo_item>
<combo_item name="10:7" value="1.42857">
10:7
</combo_item>
<combo_item name="3:2" value="1.5">
3:2
</combo_item>
<combo_item name="16:10" value="1.6">
16:10
</combo_item>
<combo_item name="16:9" value="1.77778">
16:9
</combo_item>
<combo_item name="2:1" value="2">
2:1
</combo_item>
<combo_item name="Custom" value="-1">
Custom
</combo_item>
</combo_box>
<combo_box bottom_delta="0" follows="left|top" height="20" label="Aspect" left="10"
name="local_aspect_combo" width="115">
<combo_item name="Default" value="-2">
Default
</combo_item>
<combo_item name="CurrentWindow" value="0">
Current Window
</combo_item>
<combo_item name="1:1" value="1">
1:1
</combo_item>
<combo_item name="4:3" value="1.33333">
4:3 (profile)
</combo_item>
<combo_item name="10:7" value="1.42857">
10:7
</combo_item>
<combo_item name="3:2" value="1.5">
3:2
</combo_item>
<combo_item name="16:10" value="1.6">
16:10
</combo_item>
<combo_item name="16:9" value="1.77778">
16:9
</combo_item>
<combo_item name="2:1" value="2">
2:1
</combo_item>
<combo_item name="Custom" value="-1">
Custom
</combo_item>
</combo_box>
<spinner bottom_delta="0" decimal_digits="5" follows="left|top" height="20"
increment="0.01" label="" left="130" max_val="32"
min_val="0.03125" name="aspect_ratio" width="64" allow_text_entry="false"/>
<text bottom_delta="-10" height="20" left="196" name="aspect_one_label">:1</text>
<text bottom_delta="-20" follows="left|top" height="20" left="15"
name="layer_type_label" width="50"> name="layer_type_label" width="50">
Capture: Capture:
</text> </text>
<combo_box bottom_delta="3" follows="left|top" height="20" label="Image Layers" left="60" <combo_box bottom_delta="3" follows="left|top" height="20" label="Image Layers" left="61"
name="layer_types" width="145"> name="layer_types" width="145">
<combo_item name="Colors" value="colors"> <combo_item name="Colors" value="colors">
Colors Colors
@@ -152,19 +283,19 @@
Depth Depth
</combo_item> </combo_item>
</combo_box> </combo_box>
<check_box bottom_delta="-20" follows="left|top" label="Show interface in snapshot" <check_box bottom_delta="-18" follows="left|top" label="Show interface in snapshot"
left="10" name="ui_check" /> left="10" name="ui_check" tool_tip="Show the UI in the snapshot. This enforces the resolution of the snapshot to that of your current window." />
<check_box bottom_delta="-20" follows="left|top" label="Show HUD objects in snapshot" <check_box bottom_delta="-20" follows="left|top" label="Show HUD objects in snapshot"
left="10" name="hud_check" /> left="10" name="hud_check" tool_tip="Show your HUD objects in the snapshot. This enforces the resolution of the snapshot to that of your current window." />
<check_box bottom_delta="-20" follows="left|top" label="Keep open after saving" left="10" <check_box bottom_delta="-20" follows="left|top" label="Keep open after saving" left="10"
name="keep_open_check" /> name="keep_open_check" tool_tip="Do not close the snapshot floater after saving or uploading. This allows you to save, upload or send the SAME snapshot again with different formats and/or to a different destination." />
<check_box bottom_delta="-20" follows="left|top" label="Freeze frame (fullscreen preview)" <check_box bottom_delta="-20" follows="left|top" label="Open floater in Freeze Time mode"
left="10" name="freeze_frame_check" /> left="10" name="freeze_time_check" tool_tip="This allows one to quickly press cntrl-shift-S and then take your time to choose the camera position and even make multiple shots of the frozen scene." />
<check_box bottom_delta="-20" follows="left|top" label="Auto-refresh" left="10" <check_box bottom_delta="-20" follows="left|top" label="Auto-refresh" left="10"
name="auto_snapshot_check" /> name="auto_snapshot_check" tool_tip="Handy in conjunction with Freeze Time: creates a new fullscreen preview whenever you stop camming." />
<check_box bottom_delta="-20" follows="left|top" control_name="TemporaryUpload" enabled="true" <check_box bottom_delta="-20" follows="left|top" control_name="TemporaryUpload" enabled="true"
initial_value="false" label="Temporary Image (Free)" left="10" initial_value="false" label="Temporary Image (Free)" left="10"
name="temp_check" tooltip="Sets the asset to be temporary, meaning it's free, but in return, only good for a short time before it ceases to exist." /> name="temp_check" tool_tip="Uploads the texture to the sim instead of the asset server, meaning it's free but only visible in the current sim and deleted when you leave the sim." />
<string name="unknown"> <string name="unknown">
unknown unknown
</string> </string>

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<floater
can_minimize="false"
title="Post to My Profile Feed"
height="380"
width="370"
layout="topleft"
name="floater_snapshot_profile"
rect_control="FloaterSnapshotFeedRect">
<text_editor
follows="bottom|left"
bottom="40"
hide_scrollbar="true"
length="1"
max_length="700"
name="caption"
top="-180"
left="10"
right="-10"
type="string"
word_wrap="true"/>
<check_box
follows="left|bottom"
initial_value="true"
label="Include location"
layout="topleft"
left_delta="0"
name="add_location_cb"
control_name="SnapshotFeedAddLocation"
bottom_delta="-25" />
<button
follows="right|bottom"
height="23"
label="Cancel"
layout="topleft"
name="cancel_btn"
right="-10"
bottom="10"
width="100"/>
<button
follows="right|bottom"
height="23"
label="Post"
layout="topleft"
left_delta="-106"
name="post_btn"
bottom_delta="0"
width="100"/>
</floater>

View File

@@ -264,6 +264,22 @@ An error occurred while updating [APP_NAME]. Please download the latest version
yestext="Ok"/> yestext="Ok"/>
</notification> </notification>
<notification
icon="alertmodal.tga"
name="EmptyFirstNameMessage"
type="alertmodal">
[GRIDNAME] requires a non-empty first name to login.
Please try again.
</notification>
<notification
icon="alertmodal.tga"
name="EmptyLastNameMessage"
type="alertmodal">
[GRIDNAME] requires a non-empty last name to login.
Please try again.
</notification>
<notification <notification
icon="alertmodal.tga" icon="alertmodal.tga"
name="LoginFailedNoNetwork" name="LoginFailedNoNetwork"
@@ -309,9 +325,9 @@ You don't have permission to copy one or more of these items to the Merchant Out
</notification> </notification>
<notification <notification
icon="OutboxStatus_Success" icon="alert.tga"
name="OutboxFolderCreated" name="OutboxFolderCreated"
type="outbox"> type="alert">
<unique/> <unique/>
A new folder has been created for each item you have transferred into the top level of your Merchant Outbox. A new folder has been created for each item you have transferred into the top level of your Merchant Outbox.
@@ -322,9 +338,9 @@ A new folder has been created for each item you have transferred into the top le
</notification> </notification>
<notification <notification
icon="OutboxStatus_Success" icon="alert.tga"
name="OutboxImportComplete" name="OutboxImportComplete"
type="outbox"> type="alert">
Success Success
All folders were successfully sent to the Marketplace. All folders were successfully sent to the Marketplace.
@@ -336,9 +352,9 @@ All folders were successfully sent to the Marketplace.
</notification> </notification>
<notification <notification
icon="OutboxStatus_Warning" icon="alert.tga"
name="OutboxImportHadErrors" name="OutboxImportHadErrors"
type="outbox"> type="alert">
Some folders did not transfer Some folders did not transfer
Errors occurred when some folders were sent to the Marketplace. Those folders are still in your Merchant Outbox. Errors occurred when some folders were sent to the Marketplace. Those folders are still in your Merchant Outbox.
@@ -351,9 +367,9 @@ See the [[MARKETPLACE_IMPORTS_URL] error log] for more information.
</notification> </notification>
<notification <notification
icon="OutboxStatus_Error" icon="alertmodal.tga"
name="OutboxImportFailed" name="OutboxImportFailed"
type="outbox"> type="alertmodal">
Transfer failed Transfer failed
No folders were sent to the Marketplace because of a system or network error. Try again later. No folders were sent to the Marketplace because of a system or network error. Try again later.
@@ -364,9 +380,9 @@ No folders were sent to the Marketplace because of a system or network error. T
</notification> </notification>
<notification <notification
icon="OutboxStatus_Error" icon="alertmodal.tga"
name="OutboxInitFailed" name="OutboxInitFailed"
type="outbox"> type="alertmodal">
Marketplace initialization failed Marketplace initialization failed
Initialization with the Marketplace failed because of a system or network error. Try again later. Initialization with the Marketplace failed because of a system or network error. Try again later.
@@ -405,6 +421,13 @@ There was a problem writing animation data. Please try again later.
There was a problem uploading the auction snapshot due to the following reason: [REASON] There was a problem uploading the auction snapshot due to the following reason: [REASON]
</notification> </notification>
<notification
icon="alertmodal.tga"
name="UploadSnapshotFail"
type="alertmodal">
There was a problem uploading the snapshot due to the following reason: [REASON]
</notification>
<notification <notification
icon="alertmodal.tga" icon="alertmodal.tga"
name="UnableToViewContentsMoreThanOne" name="UnableToViewContentsMoreThanOne"
@@ -937,6 +960,14 @@ Error processing snapshot data
Error encoding snapshot. Error encoding snapshot.
</notification> </notification>
<notification
icon="alertmodal.tga"
name="ErrorSizeAspectSnapshot"
type="alertmodal">
It is not possible to make a snapshot with this size and aspect.
Try a smaller size or a less stretched aspect.
</notification>
<notification <notification
icon="alertmodal.tga" icon="alertmodal.tga"
name="ErrorUploadingPostcard" name="ErrorUploadingPostcard"

View File

@@ -196,6 +196,7 @@
<string name="AvatarAway">Away</string> <string name="AvatarAway">Away</string>
<string name="AvatarBusy">Busy</string> <string name="AvatarBusy">Busy</string>
<string name="AvatarMuted">Muted</string> <string name="AvatarMuted">Muted</string>
<string name="AvatarLangolier">Langolier</string>
<!-- animations --> <!-- animations -->
<string name="anim_express_afraid">Afraid</string> <string name="anim_express_afraid">Afraid</string>

View File

@@ -163,14 +163,14 @@ Asegurate que tu conexión a internet funciona correctamente.
<usetemplate name="okcancelbuttons" notext="No mover ítem(s)" yestext="Mover ítem(s)"/> <usetemplate name="okcancelbuttons" notext="No mover ítem(s)" yestext="Mover ítem(s)"/>
</notification> </notification>
<notification name="OutboxFolderCreated" type="outbox"> <notification name="OutboxFolderCreated" type="alert">
<unique/> <unique/>
Una nueva carpeta ha sido creada por cada ítem que has transferido en el nivel superior de tu Merchant Outbox. Una nueva carpeta ha sido creada por cada ítem que has transferido en el nivel superior de tu Merchant Outbox.
<usetemplate ignoretext="Una nueva carpeta ha sido creada en el Merchant Outbox" name="okignore" yestext="OK"/> <usetemplate ignoretext="Una nueva carpeta ha sido creada en el Merchant Outbox" name="okignore" yestext="OK"/>
</notification> </notification>
<notification name="OutboxImportComplete" type="outbox"> <notification name="OutboxImportComplete" type="alert">
Completado Completado
Todas las carpetas ha sido enviadas satisfactoriamente al Marketplace. Todas las carpetas ha sido enviadas satisfactoriamente al Marketplace.
@@ -178,7 +178,7 @@ Todas las carpetas ha sido enviadas satisfactoriamente al Marketplace.
<usetemplate ignoretext="Todas las carpetas se han enviado al Marketplace" name="okignore" yestext="OK"/> <usetemplate ignoretext="Todas las carpetas se han enviado al Marketplace" name="okignore" yestext="OK"/>
</notification> </notification>
<notification name="OutboxImportHadErrors" type="outbox"> <notification name="OutboxImportHadErrors" type="alert">
Algunas carpetas no fueron transferidas Algunas carpetas no fueron transferidas
Ha habido errores al enviar algunas carpetas al Markeplace. Estas carpetas aún están en tu Merchant Outbox. Ha habido errores al enviar algunas carpetas al Markeplace. Estas carpetas aún están en tu Merchant Outbox.
@@ -188,7 +188,7 @@ Mira en el [log de errores [[MARKETPLACE_IMPORTS_URL]] para mayor información.
<usetemplate name="okbutton" yestext="OK"/> <usetemplate name="okbutton" yestext="OK"/>
</notification> </notification>
<notification name="OutboxImportFailed" type="outbox"> <notification name="OutboxImportFailed" type="alertmodal">
La transferencia ha fallado La transferencia ha fallado
No se han enviado carpetas al Marketplace debido a un error de sistema o de red. Inténtalo nuevamente más tarde. No se han enviado carpetas al Marketplace debido a un error de sistema o de red. Inténtalo nuevamente más tarde.
@@ -196,7 +196,7 @@ No se han enviado carpetas al Marketplace debido a un error de sistema o de red.
<usetemplate name="okbutton" yestext="OK"/> <usetemplate name="okbutton" yestext="OK"/>
</notification> </notification>
<notification name="OutboxInitFailed" type="outbox"> <notification name="OutboxInitFailed" type="alertmodal">
Ha fallado la inicialización del Marketplace Ha fallado la inicialización del Marketplace
La inicialización con el Marketplace ha fallado debido a un error de sistema o de red. Inténtalo nuevamente más tarde. La inicialización con el Marketplace ha fallado debido a un error de sistema o de red. Inténtalo nuevamente más tarde.

View File

@@ -869,16 +869,16 @@ class Linux_x86_64Manifest(LinuxManifest):
self.end_prefix("lib64") self.end_prefix("lib64")
# Vivox runtimes and libs # Vivox runtimes and libs
if self.prefix(src="vivox-runtime/i686-linux", dst="bin"): if self.prefix(src="vivox-runtime/i686-linux", dst="bin"):
self.path("SLVoice") self.path("SLVoice")
self.end_prefix("bin") self.end_prefix("bin")
if self.prefix(src="vivox-runtime/i686-linux", dst="lib32"): if self.prefix(src="vivox-runtime/i686-linux", dst="lib32"):
#self.path("libalut.so") #self.path("libalut.so")
self.path("libortp.so") self.path("libortp.so")
self.path("libvivoxsdk.so") self.path("libvivoxsdk.so")
self.end_prefix("lib32") self.end_prefix("lib32")
# 32bit libs needed for voice # 32bit libs needed for voice
if self.prefix("../../libraries/x86_64-linux/lib/release/32bit-compat", dst="lib32"): if self.prefix("../../libraries/x86_64-linux/lib/release/32bit-compat", dst="lib32"):