void LLURLRequest::initialize_impl(void) { // If the header is "Pragma" with no value, the caller intends to // force libcurl to drop the Pragma header it so gratuitously inserts. // Before inserting the header, force libcurl to not use the proxy. std::string pragma_value; if (mHeaders.getValue("Pragma", pragma_value) && pragma_value.empty()) { useProxy(false); } if (mAction == LLHTTPClient::HTTP_PUT || mAction == LLHTTPClient::HTTP_POST) { // If the Content-Type header was passed in we defer to the caller's wisdom, // but if they did not specify a Content-Type, then ask the injector. mHeaders.addHeader("Content-Type", mBody->contentType(), AIHTTPHeaders::keep_existing_header); } else if (mAction != LLHTTPClient::HTTP_HEAD) { // Check to see if we have already set Accept or not. If no one // set it, set it to application/llsd+xml since that's what we // almost always want. mHeaders.addHeader("Accept", "application/llsd+xml", AIHTTPHeaders::keep_existing_header); } if (mAction == LLHTTPClient::HTTP_POST && gMessageSystem) { mHeaders.addHeader("X-SecondLife-UDP-Listen-Port", llformat("%d", gMessageSystem->mPort)); } bool success = false; try { AICurlEasyRequest_wat easy_request_w(*mCurlEasyRequest); easy_request_w->prepRequest(easy_request_w, mHeaders, mResponder); if (mBody) { // This might throw AICurlNoBody. mBodySize = mBody->get_body(easy_request_w->sChannels, easy_request_w->getInput()); } success = configure(easy_request_w); } catch (AICurlNoBody const& error) { llwarns << "Injector::get_body() failed: " << error.what() << llendl; } if (success) { // Continue to initialize base class. AICurlEasyRequestStateMachine::initialize_impl(); } else { abort(); } }
void AICurlEasyRequestStateMachine::multiplex_impl(state_type run_state) { switch (run_state) { case AICurlEasyRequestStateMachine_addRequest: { set_state(AICurlEasyRequestStateMachine_waitAdded); idle(); // Wait till AICurlEasyRequestStateMachine::added_to_multi_handle() is called. // This is a work around for the case that this request had a bad url, in order to avoid a crash later on. bool empty_url = AICurlEasyRequest_rat(*mCurlEasyRequest)->getLowercaseServicename().empty(); if (empty_url) { AICurlEasyRequest_wat(*mCurlEasyRequest)->aborted(HTTP_INTERNAL_ERROR_OTHER, "Not a valid URL."); abort(); break; } // Only AFTER going idle, add request to curl thread; this is needed because calls to set_state() are // ignored when the statemachine is not idle, and theoretically the callbacks could be called // immediately after this call. mAdded = true; mCurlEasyRequest.addRequest(); // This causes the state to be changed, now or later, to // AICurlEasyRequestStateMachine_removed_after_finished. // The state at this point is thus one of // 1) AICurlEasyRequestStateMachine_waitAdded (idle) // 2) AICurlEasyRequestStateMachine_removed_after_finished (running) if (mTotalDelayTimeout > 0.f) { // Set an inactivity timer. // This shouldn't really be necessary, except in the case of a bug // in libcurl; but lets be sure and set a timer for inactivity. mTimer = new AITimer; mTimer->setInterval(mTotalDelayTimeout); mTimer->run(this, AICurlEasyRequestStateMachine_timedOut, false, false); } break; } case AICurlEasyRequestStateMachine_waitAdded: { // Nothing to do. idle(); break; } case AICurlEasyRequestStateMachine_timedOut: { // It is possible that exactly at this point the state changes into // AICurlEasyRequestStateMachine_removed_after_finished, with as result that mTimedOut // is set while we will continue with that state. Hence that mTimedOut // is explicitly reset in that state. // Libcurl failed to deliver within a reasonable time... Abort operation in order // to free this curl easy handle and to notify the application that it didn't work. mTimedOut = true; llassert(mAdded); mAdded = false; mCurlEasyRequest.removeRequest(); idle(); // Wait till AICurlEasyRequestStateMachine::removed_from_multi_handle() is called. break; } case AICurlEasyRequestStateMachine_removed_after_finished: { if (!mHandled) { // Only do this once. mHandled = true; if (mTimer) { // Stop the timer. Note that it's the main thread that generates timer events, // so we're certain that there will be no time out anymore if we reach this point. mTimer->abort(); } // The request finished and either data or an error code is available. AICurlEasyRequest_wat easy_request_w(*mCurlEasyRequest); easy_request_w->processOutput(); } // See above. mTimedOut = false; /* Fall-Through */ } case AICurlEasyRequestStateMachine_removed: { // The request was removed from the multi handle. // We're done. If we timed out, abort -- or else the application will // think that getResult() will return a valid error code from libcurl. if (mTimedOut) { AICurlEasyRequest_wat(*mCurlEasyRequest)->aborted(HTTP_INTERNAL_ERROR_CURL_LOCKUP, "Request timeout, aborted."); abort(); } else finish(); break; } case AICurlEasyRequestStateMachine_bad_file_descriptor: { AICurlEasyRequest_wat(*mCurlEasyRequest)->aborted(HTTP_INTERNAL_ERROR_CURL_BADSOCKET, "File descriptor went bad! Aborted."); abort(); } } }