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();
	}
  }
}