text: /*****************************************************************
  |
  |   Platinum - HTTP Client Tasks
  |
  | Copyright (c) 2004-2010, Plutinosoft, LLC.
  | All rights reserved.
  | http://www.plutinosoft.com
  |
  | This program is free software; you can redistribute it and/or
  | modify it under the terms of the GNU General Public License
  | as published by the Free Software Foundation; either version 2
  | of the License, or (at your option) any later version.
  |
  | OEMs, ISVs, VARs and other distributors that combine and 
  | distribute commercially licensed software with Platinum software
  | and do not wish to distribute the source code for the commercially
  | licensed software under version 2, or (at your option) any later
  | version, of the GNU General Public License (the "GPL") must enter
  | into a commercial license agreement with Plutinosoft, LLC.
  | licensing@plutinosoft.com
  |  
  | This program is distributed in the hope that it will be useful,
  | but WITHOUT ANY WARRANTY; without even the implied warranty of
  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  | GNU General Public License for more details.
  |
  | You should have received a copy of the GNU General Public License
  | along with this program; see the file LICENSE.txt. If not, write to
  | the Free Software Foundation, Inc., 
  | 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  | http://www.gnu.org/licenses/gpl-2.0.html
  |
  ****************************************************************/
  
  /*----------------------------------------------------------------------
  |   includes
  +---------------------------------------------------------------------*/
  #include "PltHttpClientTask.h"
  #include "PltConstants.h"
  
  NPT_SET_LOCAL_LOGGER("platinum.core.http.clienttask")
  
  /*----------------------------------------------------------------------
  |   PLT_HttpClientSocketTask::PLT_HttpClientSocketTask
  +---------------------------------------------------------------------*/
  PLT_HttpClientSocketTask::PLT_HttpClientSocketTask(NPT_HttpRequest* request /* = NULL */,
                                                     bool             wait_forever /* = false */) :
      m_WaitForever(wait_forever)
  {
      m_Client.SetUserAgent(*PLT_Constants::GetInstance().GetDefaultUserAgent());
      m_Client.SetTimeouts(60000, 60000, 60000);
      if (request) m_Requests.Push(request);
  }
  
  /*----------------------------------------------------------------------
  |   PLT_HttpClientSocketTask::~PLT_HttpClientSocketTask
  +---------------------------------------------------------------------*/
  PLT_HttpClientSocketTask::~PLT_HttpClientSocketTask()
  {
      // delete any outstanding requests
      NPT_HttpRequest* request;
      while (NPT_SUCCEEDED(m_Requests.Pop(request, false))) {
          delete request;
      }
  }
  
  /*----------------------------------------------------------------------
  |   PLT_HttpClientSocketTask::SetHttpClientConfig
  +---------------------------------------------------------------------*/
  NPT_Result 
  PLT_HttpClientSocketTask::SetHttpClientConfig(const NPT_HttpClient::Config& config)
  {
      return m_Client.SetConfig(config);
  }
  
  /*----------------------------------------------------------------------
  |   PLT_HttpClientSocketTask::AddRequest
  +---------------------------------------------------------------------*/
  NPT_Result
  PLT_HttpClientSocketTask::AddRequest(NPT_HttpRequest* request)
  {
      return m_Requests.Push(request);
  }
  
  /*----------------------------------------------------------------------
  |   PLT_HttpClientSocketTask::GetNextRequest
  +---------------------------------------------------------------------*/
  NPT_Result
  PLT_HttpClientSocketTask::GetNextRequest(NPT_HttpRequest*& request, NPT_Timeout timeout_ms)
  {
      return m_Requests.Pop(request, timeout_ms);
  }
  
  /*----------------------------------------------------------------------
  |   PLT_HttpClientSocketTask::DoAbort
  +---------------------------------------------------------------------*/
  void
  PLT_HttpClientSocketTask::DoAbort()
  {
      m_Client.Abort();
  }
  
  /*----------------------------------------------------------------------
  |   PLT_HttpClientSocketTask::DoRun
  +---------------------------------------------------------------------*/
  void
  PLT_HttpClientSocketTask::DoRun()
  {
      NPT_HttpRequest*       request = NULL;
      NPT_HttpResponse*      response = NULL;
      NPT_HttpRequestContext context;
      NPT_Result             res;
      NPT_TimeStamp          watchdog;
  
      NPT_System::GetCurrentTimeStamp(watchdog);
  
      do {
          // pop next request or wait for one for 100ms
          while (NPT_SUCCEEDED(GetNextRequest(request, 100))) {
              response = NULL;
              
              if (IsAborting(0)) goto abort;
  
              // send request
              res = m_Client.SendRequest(*request, response, &context);
  
              NPT_String prefix = NPT_String::Format("PLT_HttpClientSocketTask::DoRun (res = %d):", res);
              PLT_LOG_HTTP_RESPONSE(NPT_LOG_LEVEL_FINER, prefix, response);
  
              // process response
              ProcessResponse(res, *request, context, response);
  
              // cleanup
              delete response;
              response = NULL;
              delete request;
              request = NULL;
          }
  
          // DLNA requires that we abort unanswered/unused sockets after 60 secs
          NPT_TimeStamp now;
          NPT_System::GetCurrentTimeStamp(now);
          if (now > watchdog + NPT_TimeInterval(60.)) {
              NPT_HttpConnectionManager::GetInstance()->Recycle(NULL);
              watchdog = now;
          }
  
      } while (m_WaitForever && !IsAborting(0));
      
  abort:
      if (request) delete request;
      if (response) delete response;
  }
  
  /*----------------------------------------------------------------------
  |   PLT_HttpClientSocketTask::ProcessResponse
  +---------------------------------------------------------------------*/
  NPT_Result 
  PLT_HttpClientSocketTask::ProcessResponse(NPT_Result                    res, 
                                            const NPT_HttpRequest&        request,  
                                            const NPT_HttpRequestContext& context, 
                                            NPT_HttpResponse*             response) 
  {
      NPT_COMPILER_UNUSED(request);
      NPT_COMPILER_UNUSED(context);
  
      NPT_LOG_FINE_1("PLT_HttpClientSocketTask::ProcessResponse (result=%d)", res);
      NPT_CHECK_WARNING(res);
  
      NPT_CHECK_POINTER_WARNING(response);
  
      // check if there's a body to read
      NPT_HttpEntity* entity;
      NPT_InputStreamReference body;
      if (!(entity = response->GetEntity()) || 
          NPT_FAILED(entity->GetInputStream(body)) ||
          body.IsNull()) {
          return NPT_SUCCESS;
      }
  
      // dump body into ether  
      // (if no content-length specified, read until disconnected)
      NPT_NullOutputStream output;
      NPT_CHECK_SEVERE(NPT_StreamToStreamCopy(*body, 
                                              output,
                                              0, 
                                              entity->GetContentLength()));
  
      return NPT_SUCCESS;
  }
  