SBinetHttpStream.cpp
上传用户:xqtpzdz
上传日期:2022-05-21
资源大小:1764k
文件大小:52k
源码类别:

xml/soap/webservice

开发平台:

Visual C++

  1. /****************License************************************************
  2.  * Vocalocity OpenVXI
  3.  * Copyright (C) 2004-2005 by Vocalocity, Inc. All Rights Reserved.
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  *  
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  17.  * Vocalocity, the Vocalocity logo, and VocalOS are trademarks or 
  18.  * registered trademarks of Vocalocity, Inc. 
  19.  * OpenVXI is a trademark of Scansoft, Inc. and used under license 
  20.  * by Vocalocity.
  21.  ***********************************************************************/
  22. #ifndef _SB_USE_STD_NAMESPACE
  23. #define _SB_USE_STD_NAMESPACE
  24. #endif
  25. #ifdef WIN32
  26. #ifndef UNICODE
  27. #define UNICODE
  28. #endif
  29. #ifndef _UNICODE
  30. #define _UNICODE
  31. #endif
  32. #ifndef WIN32_LEAN_AND_MEAN
  33. #define WIN32_LEAN_AND_MEAN
  34. #endif
  35. #include <windows.h>
  36. #endif
  37. #include <sys/timeb.h>                  // for _ftime( )/ftime( )
  38. #include <stdio.h>                      // for sprintf
  39. #include "VXIvalue.h"
  40. #include "VXIinet.h"
  41. #include "VXItrd.h"
  42. #include "SBinetLog.h"
  43. #include "SBinetURL.h"
  44. #include "SBinetHttpStream.hpp"
  45. #include "SBinetChannel.h"
  46. #include "SBinetHttpConnection.hpp"
  47. #include "SBinetValidator.h"
  48. #include "SBinetCookie.h"
  49. #include "SBinetUtils.hpp"
  50. #include "SWITimeWatch.hpp"
  51. #include "util_date.h"
  52. #include "ap_ctype.h"
  53. #include "HttpUtils.hpp"
  54. #include <SWIsocket.hpp>
  55. #include <SWIdataOutputStream.hpp>
  56. #include <SWIbufferedInputStream.hpp>
  57. #include <SWIbufferedOutputStream.hpp>
  58. #include <list>
  59. typedef std::basic_string<VXIchar> inetstring;
  60. #define HTTP_UNDEFINED -1234  /* No HTTP error code yet */
  61. #define READ_CHUNK_SIZE 128 * 1024 // Read from socket in 128 Kb chunks
  62. SBinetHttpStream::SBinetHttpStream(SBinetURL* url,
  63.                                    SubmitMethod method,
  64.                                    SBinetChannel* ch,
  65.                                    SBinetValidator* cacheValidator,
  66.                                    VXIlogInterface *log,
  67.                                    VXIunsigned diagLogBase):
  68.   SBinetStoppableStream(url, SBinetStream_HTTP, log, diagLogBase),
  69.   _HttpStatus(HTTP_UNDEFINED), _leftToRead(~0), _chunked(false),
  70.   _method(method), _channel(ch), _connection(NULL),
  71.   _inputStream(NULL), _outputStream(NULL), _closeConnection(TRUE),
  72.   _validator(NULL), _cacheValidator(cacheValidator), _connectionAborted(FALSE)
  73. {}
  74. SBinetHttpStream::~SBinetHttpStream()
  75. {
  76.   delete _validator;
  77.   Close();
  78. }
  79. VXIinetResult SBinetHttpStream::initSocket(SubmitMethod method,
  80.                                            const VXIMap *properties,
  81.                                            VXIMap *streamInfo)
  82. {
  83.   _connection = _channel->getHttpConnection(_url, properties);
  84.   if (_connection == NULL)
  85.   {
  86.     Error(262, L"%s%s", L"URL", _url->getAbsolute());
  87.     return VXIinet_RESULT_FETCH_ERROR;
  88.   }
  89.   SWITimeWatch timeWatch;
  90.   timeWatch.start();
  91.   switch (_connection->connect(getDelay()))
  92.   {
  93.    case SWIstream::TIMED_OUT:
  94.      Error(241, NULL);
  95.      return VXIinet_RESULT_FETCH_TIMEOUT;
  96.      break;
  97.    case SWIstream::SUCCESS:
  98.      break;
  99.    default:
  100.      Error(244, L"%s%s", L"URL", _url->getAbsolute());
  101.      return VXIinet_RESULT_FETCH_ERROR;
  102.   }
  103.   _inputStream = _connection->getInputStream();
  104.   _outputStream = _connection->getOutputStream();
  105.   Diag(MODULE_SBINET_TIMING_TAGID, L"SBinetHttpStream::initSocket",
  106.        L"%i msecs, Connect to socket", timeWatch.getElapsed());
  107.   writeDebugTimeStamp();
  108.   if (method == SBinetHttpStream::GET_METHOD)
  109.     _channel->writeString(_outputStream, "GET ");
  110.   else
  111.     _channel->writeString(_outputStream, "POST ");
  112.   if (_connection->usesProxy())
  113.     _channel->writeString(_outputStream, _url->getNAbsolute());
  114.   else
  115.     _channel->writeString(_outputStream, _url->getNPath());
  116.   _channel->writeString(_outputStream, " HTTP/1.1" CRLF);
  117.   _channel->writeString(_outputStream, "Accept: */*" CRLF);
  118.   // Write HOST header.
  119.   _channel->writeString(_outputStream, "Host: ");
  120.   _channel->writeString(_outputStream, _url->getNHost());
  121.   int defaultPort = _url->getProtocol() == SBinetURL::HTTP_PROTOCOL ? 80 : 443;
  122.   int port = _url->getPort();
  123.   if (port != defaultPort)
  124.   {
  125.     _channel->writeString(_outputStream, ":");
  126.     _channel->writeInt(_outputStream, port);
  127.   }
  128.   _channel->writeString(_outputStream, CRLF);
  129.   // Write USER-AGENT header.
  130.   _channel->writeString(_outputStream, "User-Agent: ");
  131.   _channel->writeString(_outputStream, _channel->getUserAgent());
  132.   _channel->writeString(_outputStream, CRLF);
  133.   // Write REFERER header.
  134.   SBinetNString baseUrl = _url->getNBase();
  135.   if (baseUrl.length() > 0)
  136.   {
  137.     // Cut query arguments, if present
  138.     VXIunsigned queryArgsSeparator = baseUrl.find('?');
  139.     if (queryArgsSeparator < baseUrl.length())
  140.       baseUrl.resize(queryArgsSeparator);
  141.     if (baseUrl.length() > 0)
  142.     {
  143.       _channel->writeString(_outputStream, "Referer: ");
  144.       _channel->writeString(_outputStream, baseUrl.c_str());
  145.       _channel->writeString(_outputStream, CRLF);
  146.     }
  147.   }
  148.   SBinetUtils::getInteger(properties, INET_CLOSE_CONNECTION, _closeConnection);
  149.   if (_closeConnection)
  150.   {
  151.     _channel->writeString(_outputStream, "Connection: close" CRLF);
  152.   }
  153.   VXIint32 maxAge = -1;
  154.   VXIint32 maxStale = -1;
  155.   getCacheInfo(properties, maxAge, maxStale);
  156.   if (maxAge != -1)
  157.   {
  158.     _channel->writeString(_outputStream, "Cache-Control: max-age=");
  159.     _channel->writeInt(_outputStream, maxAge);
  160.     _channel->writeString(_outputStream, CRLF);
  161.   }
  162.   if (maxStale != -1)
  163.   {
  164.     _channel->writeString(_outputStream, "Cache-Control: max-stale=");
  165.     _channel->writeInt(_outputStream, maxStale);
  166.     _channel->writeString(_outputStream, CRLF);
  167.   }
  168.   time_t lastModified = (time_t) -1;
  169.   SBinetNString etag;
  170.   if (_cacheValidator)
  171.   {
  172.     // Otherwise, use the validator that was stored in the cache, if any.
  173.     lastModified = _cacheValidator->getLastModified();
  174.     const VXIchar* eTagStr = _cacheValidator->getETAG();
  175.     if (eTagStr)
  176.       etag = eTagStr;
  177.   }
  178.   if ((method == SBinetHttpStream::GET_METHOD) && (lastModified != (time_t) -1))
  179.   {
  180.     char lastModStr[32];
  181.     ap_gm_timestr_822(lastModStr, lastModified);
  182.     _channel->writeString(_outputStream, "If-Modified-Since: ");
  183.     _channel->writeString(_outputStream, lastModStr);
  184.     _channel->writeString(_outputStream, CRLF);
  185.   }
  186.   if (etag.length() > 0 && etag[0])     
  187.   {
  188.     _channel->writeString(_outputStream, "If-None-Match: ");
  189.     _channel->writeString(_outputStream, etag.c_str());
  190.     _channel->writeString(_outputStream, CRLF);
  191.   }
  192.   if (_channel->cookiesEnabled())
  193.   {
  194.     _channel->collectCookies(_outputStream, _url->getNHost(), _url->getNPath());
  195.   }
  196.   return VXIinet_RESULT_SUCCESS;
  197. }
  198. VXIinetResult SBinetHttpStream::flushAndCheckConnection()
  199. {
  200.   VXIinetResult rc = VXIinet_RESULT_SUCCESS;
  201.   SWIstream::Result src = _outputStream->flush();
  202.   switch( src ) {
  203.     case SWIstream::SUCCESS:
  204.       break;
  205.     case SWIstream::CONNECTION_ABORTED:
  206.     case SWIstream::CONNECTION_RESET:
  207.       _connectionAborted = TRUE;
  208.       // If the server reset the connection 
  209.       // due to keepalive timeout, connection timeout, etc.
  210.       // then retry the connection again without output the error
  211.       // intentional fall through        
  212.     default:
  213.       Diag(MODULE_SBINET_CONNECTION_TAGID, L"SBinetHttpStream::doGet",
  214.            L"_outputStream->flush() error = %d, connection %s", 
  215.            src, (_connectionAborted ? L"aborted" : L"error"));     
  216.       rc = VXIinet_RESULT_IO_ERROR;
  217.   }  
  218.   return rc;
  219. }
  220. VXIinetResult SBinetHttpStream::doGet(VXIint32 flags,
  221.                                       const VXIMap *properties,
  222.                                       VXIMap *streamInfo)
  223. {
  224.   VXIinetResult rc = VXIinet_RESULT_SUCCESS;
  225.   try
  226.   {
  227.     rc = initSocket(GET_METHOD, properties, streamInfo);
  228.     if (rc != VXIinet_RESULT_SUCCESS)
  229.       return rc;
  230.     _channel->writeString(_outputStream, CRLF);
  231.     rc = flushAndCheckConnection();
  232.     
  233.   }
  234.   catch (std::exception& e)
  235.   {
  236.     // An error occurred sending data over the socket.  Abort the connection and
  237.     // try again.
  238.     if (strcmp(e.what(), "CONNECTION_ABORTED") == 0)
  239.       _connectionAborted = TRUE;
  240.     rc = VXIinet_RESULT_IO_ERROR;
  241.     Diag(MODULE_SBINET_CONNECTION_TAGID, L"SBinetHttpStream::doGet",
  242.          L"initSocket caught exception return error = %d, connection aborted", rc);     
  243.   }
  244.   return rc;
  245. }
  246. /*
  247.  * POST simple form data. Don't know how to combine Form data and audio in multipart POST
  248.  */
  249. VXIinetResult SBinetHttpStream::doPost(VXIint32 flags,
  250.                                        const VXIMap *properties,
  251.                                        VXIMap *streamInfo)
  252. {
  253.   const VXIMap *queryArgs =
  254.     (const VXIMap *)VXIMapGetProperty(properties, INET_URL_QUERY_ARGS);
  255.   SBinetNString queryArgsStr;
  256.   VXIint argsLen;
  257.   EncodingType encodingType = getEncodingType(properties);
  258.   const char *encodingStr;
  259.   if (encodingType == TYPE_MULTIPART)
  260.   {
  261.     encodingStr = SB_MULTIPART;
  262.     queryArgsStr = _url->queryArgsToMultipart(queryArgs);
  263.     argsLen = queryArgsStr.length();
  264.     Diag(MODULE_SBINET_STREAM_TAGID, L"SBinetHttpStream::doPost",
  265.          L"Performing multipart POST, data size %i", argsLen);
  266.   }
  267.   else
  268.   {
  269.     encodingStr = SB_URLENCODED;
  270.     queryArgsStr = _url->queryArgsToNString(queryArgs);
  271.     argsLen = queryArgsStr.length();
  272.     Diag(MODULE_SBINET_STREAM_TAGID, L"SBinetHttpStream::doPost",
  273.          L"Performing URL-encoded POST, data size %i", argsLen);
  274.   }
  275.   VXIinetResult rc = VXIinet_RESULT_SUCCESS;
  276.   
  277.   try
  278.   {
  279.     rc = initSocket(POST_METHOD, properties, streamInfo);
  280.     if (rc != VXIinet_RESULT_SUCCESS)
  281.       return rc;
  282.     _channel->writeString(_outputStream, "Expect: 100-continue" CRLF);
  283.     _channel->writeString(_outputStream, "Content-Length: ");
  284.     _channel->writeInt(_outputStream, argsLen);
  285.     _channel->writeString(_outputStream, CRLF);
  286.     _channel->writeString(_outputStream, "Content-Type: ");
  287.     _channel->writeString(_outputStream, encodingStr);
  288.     _channel->writeString(_outputStream, CRLF CRLF);
  289.     rc = flushAndCheckConnection();
  290.     if( rc != VXIinet_RESULT_SUCCESS ) 
  291.       return rc;
  292.     // Wait for input stream to be ready.  If time-out, just send data anyway.
  293.     // If we don't time out, we should be able to get an HTTP_CONTINUE.
  294.     VXIint32 continueTimeout = SBinetChannel::getPostContinueTimeout();
  295.     int maxDelay = getDelay();
  296.     if (continueTimeout < 0 ||
  297.         (maxDelay >=0 && continueTimeout > maxDelay))
  298.       continueTimeout = maxDelay;
  299.     
  300.     SWIstream::Result src = _inputStream->waitReady(continueTimeout);
  301.     switch (src)
  302.     {
  303.      case SWIstream::SUCCESS:
  304.        // Read the HTTP_CONTINUE header
  305.        if ((rc = getHeaderInfo(streamInfo)) != VXIinet_RESULT_SUCCESS)
  306.          return rc;
  307.        if (_HttpStatus != SBinetHttpUtils::HTTP_CONTINUE) {
  308.          Diag(MODULE_SBINET_CONNECTION_TAGID, L"SBinetHttpStream::doPost",
  309.               L"%s%d", L"waitReady epxected HTTP_CONTINUE but got status ", _HttpStatus);     
  310.          return VXIinet_RESULT_FETCH_ERROR;
  311.        }
  312.        
  313.        break;
  314.      case SWIstream::TIMED_OUT:
  315.        // We still have to send the body of the message.  This is done
  316.        // after the switch anyway so we do nothing.
  317.        break;
  318.      default:
  319.       Diag(MODULE_SBINET_CONNECTION_TAGID, L"SBinetHttpStream::doPost",
  320.            L"%s%d", L"waitReady returned IO ERROR ", src);     
  321.        // I/O error on the stream.  Just return an error.
  322.        return VXIinet_RESULT_FETCH_ERROR;
  323.     }
  324.     if (encodingType == TYPE_MULTIPART)
  325.     {
  326.       _channel->writeData(_outputStream, queryArgsStr.data(), argsLen);
  327.     }
  328.     else
  329.     {
  330.       _channel->writeString(_outputStream, queryArgsStr.c_str());
  331.     }
  332.     rc = flushAndCheckConnection();
  333.     if( rc != VXIinet_RESULT_SUCCESS )
  334.       return rc;
  335.   }
  336.   catch (std::exception& e)
  337.   {
  338.     // An error occurred sending data over the socket.  Abort the connection and
  339.     // try again.
  340.     Diag(MODULE_SBINET_CONNECTION_TAGID, L"SBinetHttpStream::doPost",
  341.          L"%s", L"exception caught returned IO ERROR for retry");     
  342.     if( strcmp(e.what(), "CONNECTION_ABORTED") == 0 )
  343.       _connectionAborted = TRUE;
  344.     return VXIinet_RESULT_IO_ERROR;
  345.   }
  346.   return rc;
  347. }
  348. bool SBinetHttpStream::handleRedirect(VXIMap *streamInfo)
  349. {
  350.   const VXIchar *location;
  351.   switch (_HttpStatus)
  352.   {
  353.     case SBinetHttpUtils::HTTP_SEE_OTHER:
  354.      // This return code implies that we change a POST into a GET.
  355.      _method = GET_METHOD;
  356.      // no break: intentional
  357.    case SBinetHttpUtils::HTTP_MULTIPLE_CHOICES:
  358.    case SBinetHttpUtils::HTTP_PERM_REDIRECT:
  359.    case SBinetHttpUtils::HTTP_FOUND:
  360.    case SBinetHttpUtils::HTTP_TEMP_REDIRECT:
  361.      location = SBinetUtils::getString(streamInfo, L"Location");
  362.      if (location == NULL || !*location)
  363.      {
  364.        Error(247, L"%s%s", L"URL", _url->getAbsolute());
  365.        return false;
  366.      }
  367.      if (_url->parse(location, _url->getAbsolute()) != VXIinet_RESULT_SUCCESS)
  368.      {
  369.        Error(248, L"%s%s%s%s", L"URL", _url->getAbsolute(),
  370.              L"Location", location);
  371.        return false;
  372.      }
  373.      return true;
  374.      break;
  375.    default:
  376.      return false;
  377.   }
  378. }
  379. // stupid function required because the people who designed VXIMap, in their
  380. // great wisdom, did not include a VXIMapClear function or the ability for the
  381. // iterator to delete the current entry.
  382. static void clearMap(VXIMap *streamInfo)
  383. {
  384. #if (VXI_CURRENT_VERSION >= 0x00030000)
  385.   VXIMapClear(streamInfo);
  386. #else
  387.   std::list<inetstring> keys;
  388.   const VXIchar *key = NULL;
  389.   const VXIValue *value = NULL;
  390.   int i = 0;
  391.   VXIMapIterator *mapIterator = VXIMapGetFirstProperty(streamInfo,
  392.                                                        &key,
  393.                                                        &value );
  394.   do
  395.   {
  396.     if (key != NULL)
  397.     {
  398.       keys.push_back(key);
  399.     }
  400.   }
  401.   while (VXIMapGetNextProperty(mapIterator, &key, &value) == VXIvalue_RESULT_SUCCESS);
  402.   VXIMapIteratorDestroy(&mapIterator);
  403.   while (!keys.empty())
  404.   {
  405.     VXIMapDeleteProperty(streamInfo, keys.front().c_str());
  406.     keys.pop_front();
  407.   }
  408. #endif  
  409. }
  410. VXIinetResult
  411. SBinetHttpStream::Open(VXIint32                  flags,
  412.        const VXIMap             *properties,
  413.        VXIMap                   *streamInfo)
  414. {
  415.   VXIinetResult rc = VXIinet_RESULT_SUCCESS;
  416.   // Make a copy in case of redirect.
  417.   SBinetString initialUrl = _url->getAbsolute();
  418.   const int maxRetry    = 5;
  419.   int nbRetry           = 0;
  420.   const int maxRedirect = 5;
  421.   int nbRedirect        = 0;
  422.   time_t requestTime = (time_t) -1;
  423.   // If reconnection happens, attempt to retry up to maxRetry
  424.   for (; nbRetry < maxRetry; )
  425.   {
  426.     // Set up request
  427.     rc = VXIinet_RESULT_NON_FATAL_ERROR;
  428.     _HttpStatus = HTTP_UNDEFINED;
  429.     requestTime = time(NULL);
  430.     _chunked = false;
  431.     _leftToRead = ~0;
  432.     _closeConnection = !SBinetChannel::getUsePersistentConnections();
  433.     _connectionAborted = FALSE;
  434.     if (_method == GET_METHOD)
  435.       rc = doGet(flags, properties, streamInfo);
  436.     else if (_method == POST_METHOD)
  437.       rc = doPost(flags, properties, streamInfo);
  438.     if ((rc != VXIinet_RESULT_SUCCESS) ||
  439.        ((rc = getHeaderInfo(streamInfo)) != VXIinet_RESULT_SUCCESS))
  440.     {      
  441.       if (_connectionAborted)
  442.       {
  443.         _closeConnection = TRUE;
  444.         // If the connection was reset by the HTTP server, create a new
  445.         // connection and try again.
  446.         Diag(MODULE_SBINET_CONNECTION_TAGID, L"SBinetHttpStream::Open",
  447.              L"%s%s%d", (_method == GET_METHOD ? L"GET" : L"POST"), 
  448.              L" method: connection is aborted, retry ", nbRetry);     
  449.         Close();
  450.         ++nbRetry;
  451.         continue;
  452.       }
  453.       else
  454.       {
  455.         Diag(MODULE_SBINET_CONNECTION_TAGID, L"SBinetHttpStream::Open",
  456.              L"%s%d", L"(no retry) getHeaderInfo returned error: ", rc); 
  457.         _closeConnection = TRUE;
  458.         break;
  459.       }      
  460.     }       
  461.        
  462.     // Avoid race condition on 100-Continue time-out.  If we got a CONTINUE
  463.     // from previous call to getHeaderInfo, we need to get it again.
  464.     if (_HttpStatus == SBinetHttpUtils::HTTP_CONTINUE &&
  465.         (rc = getHeaderInfo(streamInfo)) != VXIinet_RESULT_SUCCESS)
  466.     {
  467.       Diag(MODULE_SBINET_CONNECTION_TAGID, L"SBinetHttpStream::Open",
  468.            L"%s", L"Unexpected HTTP_CONTINUE"); 
  469.       _closeConnection = TRUE;
  470.       break;
  471.     }
  472.     if (_HttpStatus >= 300 && _HttpStatus <= 399 &&
  473.         handleRedirect(streamInfo))
  474.     {
  475.       // perform a reset on the stream.
  476.       Close();
  477.       if (++nbRedirect > maxRedirect)
  478.       {
  479.         Error(229, L"%s%s", L"URL", initialUrl.c_str());
  480.         return VXIinet_RESULT_FETCH_ERROR;
  481.       }
  482.       // Clear the streamInfo map to avoid previous fetch attribute to remain
  483.       // in the map.
  484.       if (streamInfo != NULL)
  485.         clearMap(streamInfo);
  486.         
  487.       // if redirect happens, reset retry value
  488.       nbRetry = 0;
  489.     }
  490.     else
  491.       break;
  492.   }
  493.   if (streamInfo != NULL && _HttpStatus >= 100 && _HttpStatus <= 999)
  494.   {
  495.     VXIMapSetProperty(streamInfo, INET_INFO_HTTP_STATUS,
  496.                       (VXIValue*) VXIIntegerCreate(_HttpStatus));
  497.     // Set HTTP data source information   
  498.     VXIMapSetProperty(streamInfo, INET_INFO_DATA_SOURCE, 
  499.                      (VXIValue*) VXIIntegerCreate(INET_DATA_SOURCE_HTTP));
  500.   }
  501.   switch (_HttpStatus)
  502.   {
  503.    case SBinetHttpUtils::HTTP_OK:
  504.      if (streamInfo != NULL)
  505.      {
  506.        processHeaderInfo(streamInfo);
  507.        setValidatorInfo(streamInfo, requestTime);
  508.      }
  509.      rc = VXIinet_RESULT_SUCCESS;
  510.      break;
  511.    case SBinetHttpUtils::HTTP_NOT_MODIFIED:
  512.      if (streamInfo != NULL) setValidatorInfo(streamInfo, requestTime, (VXIulong) -1);
  513.      Close();
  514.      rc = VXIinet_RESULT_NOT_MODIFIED;
  515.      break;
  516.    default:
  517.      Close();
  518.      // Map the HTTP error code
  519.      if (_HttpStatus != HTTP_UNDEFINED)
  520.      {
  521.        const VXIchar *errorDesc;
  522.        rc = MapError(_HttpStatus, &errorDesc);
  523.        Error(219, L"%s%s%s%s%s%d%s%s", L"URL", initialUrl.c_str(),
  524.              L"Method", (_method == GET_METHOD) ? L"GET" : L"POST",
  525.              L"HTTPStatus", _HttpStatus, L"HTTPStatusDescription", errorDesc);
  526.      }
  527.      else
  528.      {
  529.        Error(217, L"%s%s", L"URL", initialUrl.c_str());
  530.        if (rc == VXIinet_RESULT_SUCCESS)
  531.          rc = VXIinet_RESULT_NON_FATAL_ERROR;
  532.      }
  533.      break;
  534.   }
  535.   return rc;
  536. }
  537. VXIinetResult SBinetHttpStream::Close()
  538. {
  539.   if (_connection != NULL)
  540.   {
  541.     if (_closeConnection)
  542.       delete _connection;
  543.     else
  544.     {
  545.       // First make sure there is nothing left in the body.
  546.       VXIinetResult rc = skipBody();
  547.       if (rc == VXIinet_RESULT_SUCCESS)
  548.         _channel->putHttpConnection(_connection);
  549.       else
  550.         delete _connection;
  551.     }
  552.     _connection = NULL;
  553.     _inputStream = NULL;
  554.     _outputStream = NULL;
  555.   }
  556.   return(VXIinet_RESULT_SUCCESS);
  557. }
  558. VXIinetResult SBinetHttpStream::skipBody()
  559. {
  560.   // These HTTP status code do not allow for a body.
  561.   if (_HttpStatus == SBinetHttpUtils::HTTP_NOT_MODIFIED ||
  562.       _HttpStatus == SBinetHttpUtils::HTTP_NO_DATA  ||
  563.       (_HttpStatus >= 100 && _HttpStatus <= 199))
  564.     return VXIinet_RESULT_SUCCESS;
  565.   VXIinetResult rc;
  566.   VXIbyte buffer[1024];
  567.   while ((rc = Read(buffer, sizeof(buffer), NULL)) == VXIinet_RESULT_SUCCESS);
  568.   if (rc == VXIinet_RESULT_END_OF_STREAM)
  569.     rc = VXIinet_RESULT_SUCCESS;
  570.   return rc;
  571. }
  572. SBinetHttpStream::EncodingType SBinetHttpStream::getEncodingType(const VXIMap *properties)
  573. {
  574.   SBinetHttpStream::EncodingType encodingType = TYPE_URL_ENCODED;
  575.   // Get the submit MIME type from the properties, if defined
  576.   const VXIchar *strType =
  577.     SBinetUtils::getString(properties, INET_SUBMIT_MIME_TYPE);
  578.   if (strType && *strType)
  579.   {
  580.     // If DEFAULT ever changes, this code will need to be updated
  581.     if (::wcscmp(strType, INET_SUBMIT_MIME_TYPE_DEFAULT) == 0)
  582.       encodingType = TYPE_URL_ENCODED;
  583.     else if (::wcscmp(strType, L"multipart/form-data") == 0)
  584.       encodingType = TYPE_MULTIPART;
  585.     else
  586.       Error(304, L"%s%s%s%s%s%s", L"URL", _url->getAbsolute(),
  587.             L"EncodingType", strType,
  588.             L"DefaultType", INET_SUBMIT_MIME_TYPE_DEFAULT);
  589.   }
  590.   return encodingType;
  591. }
  592. VXIinetResult SBinetHttpStream::getStatus()
  593. {
  594.   _HttpStatus = HTTP_UNDEFINED;
  595.   VXIinetResult rc = waitStreamReady();
  596.   if (rc != VXIinet_RESULT_SUCCESS)
  597.     return rc;
  598.   writeDebugTimeStamp();
  599.   // The HTTP status line should have the following syntax:
  600.   // HTTP/x.x yyy msg CRLF
  601.   //
  602.   // This is buggy if we ever see an HTTP/1.xx in the future
  603.   SWIdataOutputStream line;
  604.   const char *c_line = NULL;
  605.   SWIstream::Result src = _channel->readLine(_inputStream, &line);
  606.   if (src >= 0)
  607.   {
  608.     if (ap_checkmask(c_line = line.getString(), "HTTP/#.# ###*"))
  609.     {
  610.       _HttpStatus = atoi(&c_line[9]);
  611.       int version = (c_line[5] - '0') * 10 + (c_line[7] - '0');
  612.       if (version < 11) _closeConnection = TRUE;
  613.     }
  614.     else
  615.     {
  616.       Error(249, L"%s%s", L"URL", _url->getAbsolute());
  617.     }
  618.   }
  619.   // A return value of END_OF_FILE means the connection was gracefully closed.
  620.   // A return value of CONNECTION_ABORTED means the connection was aborted
  621.   // because of a time out or some other problem.
  622.   else if ((src == SWIstream::CONNECTION_ABORTED) || (src == SWIstream::END_OF_FILE))
  623.   {
  624.     // Return immediately and do not check the _HttpStatus since
  625.     // we don't want to print errors for nothing.
  626.     _connectionAborted = true;
  627.     return VXIinet_RESULT_NON_FATAL_ERROR;
  628.   }
  629.   else
  630.   {
  631.     Error(249, L"%s%s", L"URL", _url->getAbsolute());
  632.   }
  633.   if (_HttpStatus < 100 || _HttpStatus > 999)
  634.   {
  635.     if (_HttpStatus != HTTP_UNDEFINED)
  636.     {
  637.       Error(219, L"%s%s%s%s%s%d",
  638.             L"URL", _url->getAbsolute(),
  639.             L"Method", _method == GET_METHOD ? L"GET" : L"POST",
  640.             L"HTTPStatus", _HttpStatus);
  641.     }
  642.     else
  643.     {
  644.       Error(221, L"%s%s", L"URL", _url->getAbsolute());
  645.     }
  646.     rc = VXIinet_RESULT_NON_FATAL_ERROR;
  647.   }
  648.   return rc;
  649. }
  650. enum HandlerValueType
  651. {
  652.   HANDLER_INT = 0x01,
  653.   HANDLER_DATE = 0x02,
  654.   HANDLER_STRING = 0x04,
  655.   HANDLER_CONTENT = 0x08,
  656.   HANDLER_LIST = 0x10
  657. };
  658. // Currently doing a linear search because of case-insenstivity of
  659. // comparisons.  If the number of entries in this array increases, we should
  660. // consider using a hash implementation instead.
  661. SBinetHttpStream::HeaderInfo SBinetHttpStream::headerInfoMap[] =
  662. {
  663.   { "Age", NULL, HANDLER_INT, NULL },
  664.   { "Cache-Control", NULL, HANDLER_STRING | HANDLER_LIST, NULL },
  665.   { "Content-Length", INET_INFO_SIZE_BYTES, HANDLER_INT, contentLengthHandler },
  666.   { "Content-Type", INET_INFO_MIME_TYPE, HANDLER_STRING, NULL },
  667.   { "Connection", NULL, HANDLER_STRING, connectionHandler },
  668.   { "Date", NULL, HANDLER_DATE, NULL },
  669.   { "ETag", NULL, HANDLER_STRING, NULL },
  670.   { "Expires", NULL, HANDLER_DATE, NULL },
  671.   { "Last-Modified", NULL, HANDLER_DATE, NULL },
  672.   { "Location", NULL, HANDLER_STRING, NULL },
  673.   { "Pragma", NULL, HANDLER_STRING, NULL },
  674.   { "Set-Cookie", NULL, HANDLER_STRING, setCookieHandler },
  675.   { "Set-Cookie2", NULL, HANDLER_STRING, setCookie2Handler },
  676.   { "Transfer-Encoding", NULL, HANDLER_STRING, transferEncodingHandler},
  677.   { NULL, NULL, 0, NULL }
  678. };
  679. void SBinetHttpStream::setCookieHandler(HeaderInfo *headerInfo,
  680.                                         const char *value,
  681.                                         SBinetHttpStream *httpStream,
  682.                                         VXIMap *streamInfo)
  683. {
  684.   if (!httpStream->_channel->cookiesEnabled())
  685.     return;
  686.   const char *p = value;
  687.   while (p != NULL && *p)
  688.   {
  689.     SBinetCookie *cookie = SBinetCookie::parse(httpStream->_url, p, httpStream);
  690.     if (cookie != NULL)
  691.     {
  692.       httpStream->_channel->updateCookie(cookie);
  693.     }
  694.   }
  695.   httpStream->Diag(MODULE_SBINET_STREAM_TAGID,
  696.                    L"SBinetHttpStream::setCookieHandler",
  697.                    L"Set-Cookie: %S", value);
  698. }
  699. void SBinetHttpStream::setCookie2Handler(HeaderInfo *headerInfo,
  700.                                          const char *value,
  701.                                          SBinetHttpStream *httpStream,
  702.                                          VXIMap *streamInfo)
  703. {
  704.   if (!httpStream->_channel->cookiesEnabled())
  705.     return;
  706.   httpStream->Diag(MODULE_SBINET_STREAM_TAGID,
  707.                    L"SBinetHttpStream::setCookie2Handler",
  708.                    L"Not Supported: "Set-Cookie2: %S"", value);
  709. }
  710. void SBinetHttpStream::contentLengthHandler(HeaderInfo *headerInfo,
  711.                                             const char *value,
  712.                                             SBinetHttpStream *httpStream,
  713.                                             VXIMap *streamInfo)
  714. {
  715.   // Ignore content-length if stream is chunked.
  716.   if (!httpStream->_chunked)
  717.   {
  718.     httpStream->_leftToRead = atoi(value);
  719.   }
  720. }
  721. void SBinetHttpStream::connectionHandler(HeaderInfo *headerInfo,
  722.                                          const char *value,
  723.                                          SBinetHttpStream *httpStream,
  724.                                          VXIMap *streamInfo)
  725. {
  726.   SBinetNString attrib;
  727.   for (;;)
  728.   {
  729.     if ((value = SBinetHttpUtils::getValue(value, attrib)) == NULL)
  730.     {
  731.       httpStream->Diag(MODULE_SBINET_STREAM_TAGID,
  732.                        L"SBinetHttpStream::connectionHandler",
  733.                        L"Could not get attribute.");
  734.       break;
  735.     }
  736.     if ((value = SBinetHttpUtils::expectChar(value, ",")) == NULL)
  737.     {
  738.       httpStream->Diag(MODULE_SBINET_STREAM_TAGID,
  739.                        L"SBinetHttpStream::connectionHandler",
  740.                        L"Expecting ','.");
  741.       break;
  742.     }
  743.     if (::strcasecmp(attrib.c_str(), "close") == 0)
  744.     {
  745.       httpStream->_closeConnection = TRUE;
  746.     }
  747.     // Skip comma, or if at end of string, stop parsing.
  748.     if (*value)
  749.       value++;
  750.     else
  751.       break;
  752.   }
  753. }
  754. void SBinetHttpStream::transferEncodingHandler(HeaderInfo *headerInfo,
  755.                                                const char *value,
  756.                                                SBinetHttpStream *httpStream,
  757.                                                VXIMap *streamInfo)
  758. {
  759.   SBinetNString encoding;
  760.   for (;;)
  761.   {
  762.     if ((value = SBinetHttpUtils::getValue(value, encoding)) == NULL)
  763.     {
  764.       httpStream->Diag(MODULE_SBINET_STREAM_TAGID,
  765.                        L"SBinetHttpStream::transferEncodingHandler",
  766.                        L"Could not get encoding.");
  767.       break;
  768.     }
  769.     if ((value = SBinetHttpUtils::expectChar(value, ",")) == NULL)
  770.     {
  771.       httpStream->Diag(MODULE_SBINET_STREAM_TAGID,
  772.                        L"SBinetHttpStream::transferEncodingHandler",
  773.                        L"Expecting ','.");
  774.       break;
  775.     }
  776.     if (::strcasecmp(encoding.c_str(), "chunked") == 0)
  777.     {
  778.       httpStream->_chunked = true;
  779.       httpStream->_leftToRead = 0;
  780.     }
  781.     // Skip comma, or if at end of string, stop parsing.
  782.     if (*value)
  783.       value++;
  784.     else
  785.       break;
  786.   }
  787. }
  788. void SBinetHttpStream::defaultHeaderHandler(HeaderInfo *headerInfo,
  789.                                             const char *value,
  790.                                             SBinetHttpStream *httpStream,
  791.                                             VXIMap *streamInfo)
  792. {
  793.   VXIValue* vxi_value = NULL;
  794.   bool listF = (headerInfo->value_type & HANDLER_LIST) == HANDLER_LIST;
  795.   int value_type = headerInfo->value_type & ~HANDLER_LIST;
  796.   const VXIchar *property = NULL;
  797.   SBinetString *propTmp = NULL;
  798.   if (headerInfo->inet_property != NULL)
  799.   {
  800.     property = headerInfo->inet_property;
  801.   }
  802.   else
  803.   {
  804.     propTmp = new SBinetString(headerInfo->header);
  805.     property = propTmp->c_str();
  806.   }
  807.   switch (value_type)
  808.   {
  809.    case HANDLER_INT:
  810.      vxi_value = (VXIValue *) VXIIntegerCreate(atoi(value));
  811.      break;
  812.    case HANDLER_STRING:
  813.      if (listF)
  814.      {
  815.        const VXIchar *v = SBinetUtils::getString(streamInfo, property);
  816.        if (v != NULL)
  817.        {
  818.          SBinetString tmp = v;
  819.          tmp += L", ";
  820.          tmp += value;
  821.          vxi_value = (VXIValue *) VXIStringCreate(tmp.c_str());
  822.        }
  823.      }
  824.      if (vxi_value == NULL)
  825.      {
  826.        vxi_value = (VXIValue *) VXIStringCreate(SBinetString(value).c_str());
  827.      }
  828.      break;
  829.    case HANDLER_DATE:
  830.      {
  831.        // FIXME: Portability issue. This code assumes that a time_t can be
  832.        // stored in a VXIint32 without losing any information.  Two possible
  833.        // options: extend VXIValue with a VXILong type or use VXIContent.
  834.        time_t timestamp = ap_parseHTTPdate(value);
  835.        vxi_value = (VXIValue *) VXIIntegerCreate(timestamp);
  836.      }
  837.      break;
  838.    case HANDLER_CONTENT:
  839.      if (listF)
  840.      {
  841.        const char *content;
  842.        VXIulong contentLength;
  843.        if (SBinetUtils::getContent(streamInfo, property, content, contentLength))
  844.        {
  845.          SBinetNString tmp = content;
  846.          tmp += ", ";
  847.          tmp += value;
  848.          vxi_value = (VXIValue *) SBinetUtils::createContent(tmp.c_str());
  849.        }
  850.      }
  851.      if (vxi_value == NULL)
  852.      {
  853.        vxi_value = (VXIValue *) SBinetUtils::createContent(value);
  854.      }
  855.      break;
  856.    default:
  857.      break;
  858.   }
  859.   if (vxi_value != NULL)
  860.   {
  861.     VXIMapSetProperty(streamInfo, property, vxi_value);
  862.   }
  863.   else
  864.   {
  865.     httpStream->Diag(MODULE_SBINET_STREAM_TAGID,
  866.                      L"SBinetHttpStream::defaultHeaderHandler",
  867.                      L"Could not create VXI value, header: <%S>, value: <%S>",
  868.                      headerInfo->header,
  869.                      value);
  870.   }
  871.   delete propTmp;
  872. }
  873. SBinetHttpStream::HeaderInfo *SBinetHttpStream::findHeaderInfo(const char *header)
  874. {
  875.   for (int i = 0; headerInfoMap[i].header != NULL; i++)
  876.   {
  877.     if (::strcasecmp(headerInfoMap[i].header, header) == 0)
  878.     {
  879.       return &headerInfoMap[i];
  880.     }
  881.   }
  882.   return NULL;
  883. }
  884. void SBinetHttpStream::processHeader(const char *header,
  885.                                      const char *value,
  886.                                      VXIMap* streamInfo)
  887. {
  888.   HeaderInfo *headerInfo = findHeaderInfo(header);
  889.   // If it is not found, we ignore it.
  890.   if (headerInfo == NULL) return;
  891.   HeaderHandler handler = headerInfo->handler;
  892.   if (handler == NULL) handler = defaultHeaderHandler;
  893.   (*handler)(headerInfo, value, this, streamInfo);
  894. }
  895. static const unsigned long BREAK_AT_INITIAL_NEWLINE = 0x01;
  896. static const unsigned long CONTINUE_AT_NEWLINE = 0x02;
  897. int SBinetHttpStream::getValue(char *&value, unsigned long mask)
  898. {
  899.   char c;
  900.   bool done = false;
  901.   // skip white spaces.
  902.   for (;;)
  903.   {
  904.     if ((c = _channel->readChar(_inputStream)) < 0)
  905.       return -8;
  906.     if (!ap_isspace(c))
  907.       break;
  908.     switch (c)
  909.     {
  910.      case 'r':
  911.        if ((c = _channel->readChar(_inputStream)) != 'n')
  912.          return -5;
  913.        // no break: intentional
  914.      case 'n':
  915.        if (mask & BREAK_AT_INITIAL_NEWLINE)
  916.        {
  917.          if ((c = _inputStream->peek()) < 0) return -6;
  918.          if (!ap_isspace(c)) done = true;
  919.        }
  920.        if (done)
  921.        {
  922.          value = new char[2];
  923.          *value = '';
  924.          Diag(MODULE_SBINET_STREAM_TAGID,
  925.               L"SBinetHttpStream::getValue",
  926.               L"value = '%S'", value);
  927.          return 0;
  928.        }
  929.        break;
  930.      default:
  931.        break;
  932.     }
  933.   }
  934.   int len = 0;
  935.   int bufSize = 32;
  936.   value = new char[bufSize];
  937.   for (;;)
  938.   {
  939.     if (len == bufSize)
  940.     {
  941.       int newBufSize = (bufSize << 1);
  942.       char *new_value = ::strncpy(new char[newBufSize], value, bufSize);
  943.       delete [] value;
  944.       value = new_value;
  945.       bufSize = newBufSize;
  946.     }
  947.     if (c == 'r')
  948.     {
  949.       if ((c = _channel->readChar(_inputStream)) != 'n')
  950.         break;
  951.     }
  952.     // We need to verify if the value continues on the next line.
  953.     if (c == 'n')
  954.     {
  955.       if (mask & CONTINUE_AT_NEWLINE)
  956.       {
  957.         if ((c = _inputStream->peek()) < 0)
  958.           break;
  959.         if (!ap_isspace(c) || c == 'r' || c == 'n')
  960.           done = true;
  961.       }
  962.       else
  963.         done = true;
  964.       if (done)
  965.       {
  966.         // remove trailing blanks and terminate string.
  967.         while (len > 0 && ap_isspace(value[len-1])) len--;
  968.         value[len] = '';
  969.         Diag(MODULE_SBINET_STREAM_TAGID,
  970.              L"SBinetHttpStream::getValue",
  971.              L"value = '%S'", value);
  972.         return 0;
  973.       }
  974.     }
  975.     value[len++] = c;
  976.     if ((c = _channel->readChar(_inputStream)) < 0)
  977.       break;
  978.   }
  979.   // If we get here, we got an error parsing the line.
  980.   delete [] value;
  981.   value = NULL;
  982.   return -7;
  983. }
  984. int SBinetHttpStream::getHeader(char *&header, char delimiter)
  985. {
  986.   int c;
  987.   if ((c = _channel->readChar(_inputStream)) < 0)
  988.     return -1;
  989.   // Check for end of headers.
  990.   if (c == 'r')
  991.   {
  992.     if ((c = _channel->readChar(_inputStream)) != 'n')
  993.       return -2;
  994.     return 1;
  995.   }
  996.   if (c == 'n') return 2;
  997.   if (ap_isspace(c) || c == (unsigned char) delimiter)
  998.     return -3;
  999.   int len = 0;
  1000.   int bufSize = 32;
  1001.   header = new char[bufSize];
  1002.   for (;;)
  1003.   {
  1004.     if (len == bufSize)
  1005.     {
  1006.       int newBufSize = bufSize << 1;
  1007.       char *new_header = ::strncpy(new char[newBufSize], header, bufSize);
  1008.       delete [] header;
  1009.       header = new_header;
  1010.       bufSize = newBufSize;
  1011.     }
  1012.     if (c == (unsigned char) delimiter)
  1013.     {
  1014.       header[len++] = '';
  1015.       Diag(MODULE_SBINET_STREAM_TAGID,
  1016.            L"SBinetHttpStream::getHeader",
  1017.            L"header = '%S'", header);
  1018.       return 0;
  1019.     }
  1020.     header[len++] = c;
  1021.     if ((c = _channel->readChar(_inputStream)) < 0 || ap_isspace(c))
  1022.       break;
  1023.   }
  1024.   delete [] header;
  1025.   header = NULL;
  1026.   return -4;
  1027. }
  1028. int SBinetHttpStream::getHeaderValue(char *&header, char *&value)
  1029. {
  1030.   int rc = getHeader(header, ':');
  1031.   if (rc == 0)
  1032.   {
  1033.     rc = getValue(value, CONTINUE_AT_NEWLINE | BREAK_AT_INITIAL_NEWLINE);
  1034.     if (rc != 0)
  1035.     {
  1036.       Error(250, NULL);
  1037.       delete [] header;
  1038.       header = NULL;
  1039.     }
  1040.   }
  1041.   else if (rc < 0)
  1042.     Error(250, NULL);
  1043.   return rc;
  1044. }
  1045. VXIinetResult SBinetHttpStream::parseHeaders(VXIMap* streamInfo)
  1046. {
  1047.   char *header = NULL;
  1048.   char *value  = NULL;
  1049.   VXIinetResult rc1;
  1050.   int rc2;
  1051.   while (((rc1 = waitStreamReady()) == VXIinet_RESULT_SUCCESS) &&
  1052.          ((rc2 = getHeaderValue(header, value)) == 0))
  1053.   {
  1054.     if (streamInfo) processHeader(header, value, streamInfo);
  1055.     delete [] header;
  1056.     delete [] value;
  1057.   }
  1058.   if (rc1 == VXIinet_RESULT_SUCCESS && rc2 < 0)
  1059.   {
  1060.     Diag(MODULE_SBINET_STREAM_TAGID,
  1061.          L"SBinetHttpStream::parseHeaders",
  1062.          L"Error in parsing header line: URL = <%s>, METHOD = %s, rc2 = %d",
  1063.          _url->getAbsolute(),
  1064.          _method == GET_METHOD ? L"GET" : L"POST",
  1065.          rc2);
  1066.     rc1 = VXIinet_RESULT_NON_FATAL_ERROR;
  1067.   }
  1068.   return rc1;
  1069. }
  1070. void SBinetHttpStream::processHeaderInfo(VXIMap *streamInfo)
  1071. {
  1072.   // Extract the content-length to find out how many bytes are left to be
  1073.   // read from the stream.  If the stream is chunked, ignore
  1074.   // content-length from the server.  If we don't have the content, we
  1075.   // have to set the property to 0.
  1076.   VXIulong contentSize = (_chunked || _leftToRead == ~0) ? 0 : _leftToRead;
  1077.   VXIMapSetProperty(streamInfo, INET_INFO_SIZE_BYTES,
  1078.                     (VXIValue *) VXIIntegerCreate((int) contentSize));
  1079.   const VXIchar *tmp = _url->getAbsolute();
  1080.   if (tmp != NULL)
  1081.   {
  1082.     Diag(MODULE_SBINET_STREAM_TAGID,
  1083.          L"SBinetHttpStream::processHeaderInfo", L"%s%s",
  1084.          L"absolute", tmp);
  1085.     VXIMapSetProperty(streamInfo,
  1086.                       INET_INFO_ABSOLUTE_NAME,
  1087.                       (VXIValue*)VXIStringCreate(tmp));
  1088.   }
  1089.   const VXIString *contentType =
  1090.     (const VXIString *) VXIMapGetProperty(streamInfo, INET_INFO_MIME_TYPE);
  1091.   tmp = contentType != NULL ? VXIStringCStr(contentType) : NULL;
  1092.   if (!tmp || !*tmp
  1093.       || ::wcscmp(tmp, _channel->getDefaultMimeType()) == 0)
  1094.   {
  1095.     VXIString *newContentType = _url->getContentTypeFromUrl();
  1096.     if (newContentType != NULL)
  1097.     {
  1098.       Error (300, L"%s%s%s%s",
  1099.              L"URL", _url->getAbsolute(),
  1100.              L"mime-type", VXIStringCStr(newContentType));
  1101.     }
  1102.     else
  1103.     {
  1104.       newContentType = VXIStringCreate(_channel->getDefaultMimeType());
  1105.       Error (301, L"%s%s", L"URL", _url->getAbsolute());
  1106.     }
  1107.     VXIMapSetProperty(streamInfo, INET_INFO_MIME_TYPE,
  1108.       (VXIValue *) newContentType);
  1109.   }
  1110. }
  1111. void SBinetHttpStream::setValidatorInfo(VXIMap *streamInfo, time_t requestTime)
  1112. {
  1113.   _validator = new SBinetValidator(GetLog(), GetDiagBase());
  1114.   if (_validator->Create(_url->getAbsolute(), requestTime, streamInfo) == VXIinet_RESULT_SUCCESS)
  1115.   {
  1116.     SBinetUtils::setValidatorInfo(streamInfo, _validator);
  1117.   }
  1118. }
  1119. void SBinetHttpStream::setValidatorInfo(VXIMap *streamInfo, time_t requestTime, const VXIulong sizeBytes)
  1120. {
  1121.   _validator = new SBinetValidator(GetLog(), GetDiagBase());
  1122.   if (_validator->Create(_url->getAbsolute(), sizeBytes, requestTime, streamInfo) == VXIinet_RESULT_SUCCESS)
  1123.   {
  1124.     SBinetUtils::setValidatorInfo(streamInfo, _validator);
  1125.   }
  1126. }
  1127. VXIinetResult SBinetHttpStream::getHeaderInfo(VXIMap* streamInfo)
  1128. {
  1129.   SWITimeWatch timeWatch;
  1130.   timeWatch.start();
  1131.   VXIinetResult rc = getStatus();
  1132.   Diag(MODULE_SBINET_TIMING_TAGID, L"SBinetHttpStream::getStatus",
  1133.        L"%i msecs, Wait for HTTP response", timeWatch.getElapsed());
  1134.   if (rc == VXIinet_RESULT_SUCCESS)
  1135.   {
  1136.     rc = parseHeaders(streamInfo);
  1137.   }
  1138.   Diag(MODULE_SBINET_STREAM_TAGID, L"SBinetHttpStream::getHeaderInfo",
  1139.        L"rc = %d, HttpStatus = %d", rc, _HttpStatus);
  1140.   return rc;
  1141. }
  1142. VXIinetResult SBinetHttpStream::getChunkSize(VXIulong& chunk_size)
  1143. {
  1144.   // Read next chunk size.
  1145.   char *chunk_size_str;
  1146.   if (getValue(chunk_size_str, 0) < 0)
  1147.   {
  1148.     Error(245, L"%s%s", L"URL", _url->getAbsolute());
  1149.     return VXIinet_RESULT_FETCH_ERROR;
  1150.   }
  1151.   VXIinetResult rc = VXIinet_RESULT_SUCCESS;
  1152.   bool parseError = false;
  1153.   char *endParse;
  1154.   chunk_size = (VXIulong) strtol(chunk_size_str, &endParse, 16);
  1155.   // If we did not parse a single character, this is an error.
  1156.   if (endParse == chunk_size_str)
  1157.   {
  1158.     parseError = true;
  1159.   }
  1160.   else if (*endParse)
  1161.   {
  1162.     // We did not stop parsing at the end of the string.  If the only
  1163.     // remaining characters are whitespace, this is not an error.
  1164.     while (*endParse && ap_isspace(*endParse));
  1165.     // This is not really an eror as there might be a chunk extension that we
  1166.     // currently ignore.
  1167.     //
  1168.     //if (*endParse) parseError = true;
  1169.   }
  1170.   if (parseError)
  1171.   {
  1172.     // Either an empty string to parse or stopped at non hexadecimal
  1173.     // character.
  1174.     Error(246, L"%s%s%s%S", L"URL", _url->getAbsolute(),
  1175.           L"ChunkSize", chunk_size_str);
  1176.     rc = VXIinet_RESULT_FETCH_ERROR;
  1177.   }
  1178.   delete [] chunk_size_str;
  1179.   return rc;
  1180. }
  1181. static SWIstream::Result inetToStream(VXIinetResult rc)
  1182. {
  1183.   switch (rc)
  1184.   {
  1185.    case VXIinet_RESULT_SUCCESS:
  1186.      return SWIstream::SUCCESS;
  1187.    case VXIinet_RESULT_FETCH_TIMEOUT:
  1188.      return SWIstream::TIMED_OUT;
  1189.    default:
  1190.      return SWIstream::READ_ERROR;
  1191.   }
  1192. }
  1193. int SBinetHttpStream::readChunked(VXIbyte *buffer,
  1194.                                   VXIulong buflen)
  1195. {
  1196.   // Note.  This is not fully compliant as it does not parse chunk extension.
  1197.   // The trailer is parsed but no action is taken.
  1198.   VXIinetResult rc = VXIinet_RESULT_SUCCESS;
  1199.   if (_leftToRead == ~0) return 0;
  1200.   int totalRead = 0;
  1201.   for (;;)
  1202.   {
  1203.     if (_leftToRead == 0)
  1204.     {
  1205.       if ((rc = waitStreamReady()) != VXIinet_RESULT_SUCCESS)
  1206.         return ::inetToStream(rc);
  1207.       if ((rc = getChunkSize(_leftToRead)) != VXIinet_RESULT_SUCCESS)
  1208.         return SWIstream::READ_ERROR;
  1209.       if (_leftToRead == 0)
  1210.       {
  1211.         parseHeaders(NULL);
  1212.         _leftToRead = ~0;
  1213.         break;
  1214.       }
  1215.     }
  1216.     if (buflen == 0) break;
  1217.     VXIulong toRead = (buflen > _leftToRead ? _leftToRead : buflen);
  1218.     VXIulong nbRead = 0;
  1219.     while (toRead > 0)
  1220.     {
  1221.       if ((rc = waitStreamReady()) != VXIinet_RESULT_SUCCESS)
  1222.         return ::inetToStream(rc);
  1223.       int count = _channel->readData(_inputStream, &buffer[nbRead], toRead);
  1224.       // Read error.
  1225.       if (count == 0) count = SWIstream::WOULD_BLOCK;
  1226.       if (count < 0) return count;
  1227.       nbRead += count;
  1228.       toRead -= count;
  1229.     }
  1230.     _leftToRead -= nbRead;
  1231.     totalRead += nbRead;
  1232.     buffer += nbRead;
  1233.     buflen -= nbRead;
  1234.   }
  1235.   return totalRead;
  1236. }
  1237. int SBinetHttpStream::readNormal(VXIbyte *buffer, VXIulong buflen)
  1238. {
  1239.   int totalRead = 0;
  1240.   if (_leftToRead == 0) return totalRead;
  1241.   VXIulong toRead = (buflen > _leftToRead) ? _leftToRead : buflen;
  1242.   VXIulong nbRead = 0;
  1243.   while (toRead > 0)
  1244.   {
  1245.     // Check if fetch timeout has expired
  1246.     VXIinetResult rc = waitStreamReady();
  1247.     if (rc != VXIinet_RESULT_SUCCESS)
  1248.       return inetToStream(rc);
  1249.     int count = _channel->readData(_inputStream, &buffer[nbRead], toRead);
  1250.     // This is not an error if we get END OF FILE.
  1251.     if (count == SWIstream::END_OF_FILE)
  1252.     {
  1253.       _closeConnection = TRUE;
  1254.       _leftToRead = 0;
  1255.       break;
  1256.     }
  1257.     // Read error.
  1258.     if (count == 0) count = SWIstream::WOULD_BLOCK;
  1259.     if (count < 0) return count;
  1260.     nbRead += count;
  1261.     toRead -= count;
  1262.   }
  1263.   totalRead += nbRead;
  1264.   _leftToRead -= nbRead;
  1265.   return totalRead;
  1266. }
  1267. VXIinetResult SBinetHttpStream::Read(VXIbyte *buffer,
  1268.                                      VXIulong buflen,
  1269.                                      VXIulong *nread)
  1270. {
  1271.   VXIinetResult rc = VXIinet_RESULT_SUCCESS;
  1272.   int nbRead;
  1273.   if (_chunked)
  1274.     nbRead = readChunked(buffer, buflen);
  1275.   else
  1276.     nbRead = readNormal(buffer, buflen);
  1277.   if (nbRead >= 0)
  1278.   {
  1279.     if (nread != NULL) *nread = nbRead;
  1280.     if (((unsigned int) nbRead) < buflen ||
  1281.         (!_chunked && _leftToRead == 0))
  1282.       rc = VXIinet_RESULT_END_OF_STREAM;
  1283.   }
  1284.   else
  1285.   {
  1286.     _closeConnection = TRUE;
  1287.     switch (nbRead)
  1288.     {
  1289.      case SWIstream::END_OF_FILE:
  1290.        rc = VXIinet_RESULT_END_OF_STREAM;
  1291.        break;
  1292.      case SWIstream::WOULD_BLOCK:
  1293.        rc = VXIinet_RESULT_WOULD_BLOCK;
  1294.        break;
  1295.      case SWIstream::TIMED_OUT:
  1296.        rc = VXIinet_RESULT_FETCH_TIMEOUT;
  1297.        break;
  1298.      default:
  1299.        rc = VXIinet_RESULT_IO_ERROR;
  1300.     }
  1301.   }
  1302.   return rc;
  1303. }
  1304. VXIinetResult
  1305. SBinetHttpStream::MapError(int ht_error, const VXIchar **errorDesc)
  1306. {
  1307.   VXIinetResult rc;
  1308.   switch(ht_error)
  1309.   {
  1310.    case SBinetHttpUtils::HTTP_NO_ACCESS: /* Unauthorized */
  1311.       *errorDesc = L"Unauthorized";
  1312.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1313.    case SBinetHttpUtils::HTTP_FORBIDDEN: /* Access forbidden */
  1314.       *errorDesc = L"Access forbidden";
  1315.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1316.    case SBinetHttpUtils::HTTP_NOT_ACCEPTABLE:/* Not Acceptable */
  1317.       *errorDesc = L"Not Acceptable";
  1318.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1319.    case SBinetHttpUtils::HTTP_NO_PROXY_ACCESS:    /* Proxy Authentication Failed */
  1320.       *errorDesc = L"Proxy Authentication Failed";
  1321.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1322.    case SBinetHttpUtils::HTTP_CONFLICT:    /* Conflict */
  1323.       *errorDesc = L"Conflict";
  1324.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1325.    case SBinetHttpUtils::HTTP_LENGTH_REQUIRED:    /* Length required */
  1326.       *errorDesc = L"Length required";
  1327.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1328.    case SBinetHttpUtils::HTTP_PRECONDITION_FAILED:    /* Precondition failed */
  1329.       *errorDesc = L"Precondition failed";
  1330.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1331.    case SBinetHttpUtils::HTTP_TOO_BIG:    /* Request entity too large */
  1332.       *errorDesc = L"Request entity too large";
  1333.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1334.    case SBinetHttpUtils::HTTP_URI_TOO_BIG:    /* Request-URI too long */
  1335.       *errorDesc = L"Request-URI too long";
  1336.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1337.    case SBinetHttpUtils::HTTP_UNSUPPORTED:    /* Unsupported */
  1338.       *errorDesc = L"Unsupported";
  1339.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1340.    case SBinetHttpUtils::HTTP_BAD_RANGE:    /* Request Range not satisfiable */
  1341.       *errorDesc = L"Request Range not satisfiable";
  1342.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1343.    case SBinetHttpUtils::HTTP_EXPECTATION_FAILED:    /* Expectation Failed */
  1344.       *errorDesc = L"Expectation Failed";
  1345.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1346.    case SBinetHttpUtils::HTTP_REAUTH:    /* Reauthentication required */
  1347.       *errorDesc = L"Reauthentication required";
  1348.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1349.    case SBinetHttpUtils::HTTP_PROXY_REAUTH:    /* Proxy Reauthentication required */
  1350.       *errorDesc = L"Proxy Reauthentication required";
  1351.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1352.    case SBinetHttpUtils::HTTP_SERVER_ERROR: /* Internal server error */
  1353.       *errorDesc = L"Internal server error";
  1354.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1355.    case SBinetHttpUtils::HTTP_NOT_IMPLEMENTED: /* Not implemented (server error) */
  1356.       *errorDesc = L"Not implemented (server error)";
  1357.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1358.    case SBinetHttpUtils::HTTP_BAD_GATEWAY: /* Bad gateway (server error) */
  1359.       *errorDesc = L"Bad gateway (server error)";
  1360.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1361.    case SBinetHttpUtils::HTTP_RETRY: /* Service not available (server error) */
  1362.       *errorDesc = L"Service not available (server error)";
  1363.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1364.    case SBinetHttpUtils::HTTP_GATEWAY_TIMEOUT: /* Gateway timeout (server error) */
  1365.       *errorDesc = L"Gateway timeout (server error)";
  1366.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1367.    case SBinetHttpUtils::HTTP_BAD_VERSION: /* Bad protocol version (server error) */
  1368.       *errorDesc = L"Bad protocol version (server error)";
  1369.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1370.    case SBinetHttpUtils::HTTP_NO_PARTIAL_UPDATE: /* Partial update not implemented (server error) */
  1371.       *errorDesc = L"Partial update not implemented (server error)";
  1372.       rc = VXIinet_RESULT_FETCH_ERROR; break;
  1373.     case SBinetHttpUtils::HTTP_INTERNAL:    /* Weird -- should never happen. */
  1374.       *errorDesc = L"Internal error";
  1375.       rc = VXIinet_RESULT_NON_FATAL_ERROR; break;
  1376.    case  SBinetHttpUtils::HTTP_WOULD_BLOCK:    /* If we are in a select */
  1377.       *errorDesc = L"Would block; not an error";
  1378.       rc = VXIinet_RESULT_WOULD_BLOCK; break;
  1379.    case SBinetHttpUtils::HTTP_INTERRUPTED:    /* Note the negative value! */
  1380.       *errorDesc = L"Interrupted; not an error";
  1381.       rc = VXIinet_RESULT_SUCCESS; break;
  1382.    case SBinetHttpUtils::HTTP_PAUSE:    /* If we want to pause a stream */
  1383.       *errorDesc = L"Stream paused; not an error";
  1384.       rc = VXIinet_RESULT_SUCCESS; break;
  1385.    case SBinetHttpUtils::HTTP_RECOVER_PIPE:    /* Recover pipe line */
  1386.       *errorDesc = L"Recover pipe line; not an error";
  1387.       rc = VXIinet_RESULT_SUCCESS; break;
  1388.    case SBinetHttpUtils::HTTP_TIMEOUT:    /* Connection timeout */
  1389.       *errorDesc = L"Connection timeout";
  1390.       rc = VXIinet_RESULT_FETCH_TIMEOUT; break;
  1391.    case SBinetHttpUtils::HTTP_NOT_FOUND: /* Not found */
  1392.       *errorDesc = L"Not found";
  1393.       rc = VXIinet_RESULT_NOT_FOUND; break;
  1394.    case SBinetHttpUtils::HTTP_METHOD_NOT_ALLOWED: /* Method not allowed */
  1395.       *errorDesc = L"Method not allowed";
  1396.       rc = VXIinet_RESULT_NON_FATAL_ERROR; break;
  1397.    case SBinetHttpUtils::HTTP_NO_HOST:    /* Can't locate host */
  1398.       *errorDesc = L"Can't locate host";
  1399.       rc = VXIinet_RESULT_NOT_FOUND; break;
  1400.     /* These should not be errors */
  1401.     case SBinetHttpUtils::HTTP_MULTIPLE_CHOICES:
  1402.       *errorDesc = L"Multiple choices";
  1403.       rc = VXIinet_RESULT_NOT_FOUND; break;
  1404.     case SBinetHttpUtils::HTTP_PERM_REDIRECT:
  1405.       *errorDesc = L"Permanent redirection";
  1406.       rc = VXIinet_RESULT_NOT_FOUND; break;
  1407.     case SBinetHttpUtils::HTTP_SEE_OTHER:
  1408.       *errorDesc = L"See other";
  1409.       rc = VXIinet_RESULT_NOT_FOUND; break;
  1410.     case SBinetHttpUtils::HTTP_USE_PROXY:
  1411.       *errorDesc = L"Use Proxy";
  1412.       rc = VXIinet_RESULT_NOT_FOUND; break;
  1413.     case SBinetHttpUtils::HTTP_PROXY_REDIRECT:
  1414.       *errorDesc = L"Proxy Redirect";
  1415.       rc = VXIinet_RESULT_NOT_FOUND; break;
  1416.     case SBinetHttpUtils::HTTP_TEMP_REDIRECT:
  1417.       *errorDesc = L"Temporary Redirect";
  1418.       rc = VXIinet_RESULT_NOT_FOUND; break;
  1419.     case SBinetHttpUtils::HTTP_FOUND:
  1420.       *errorDesc = L"Found";
  1421.       rc = VXIinet_RESULT_NON_FATAL_ERROR; break;
  1422.     default: {
  1423.       switch (ht_error / 100) {
  1424.       case 1: // informational, shouldn't fail due to this!
  1425. *errorDesc = L"Unknown informational status";
  1426. break;
  1427.       case 2: // successful, shouldn't fail due to this!
  1428. *errorDesc = L"Unknown success status";
  1429. break;
  1430.       case 3: // redirection
  1431. *errorDesc = L"Unknown redirection error";
  1432. break;
  1433.       case 4: // client error
  1434. *errorDesc = L"Unknown client error";
  1435. break;
  1436.       case 5: // server error
  1437. *errorDesc = L"Unknown server error";
  1438. break;
  1439.       default:
  1440. *errorDesc = L"Unknown HTTP status code";
  1441.       }
  1442.       rc = VXIinet_RESULT_NON_FATAL_ERROR;
  1443.     }
  1444.   }
  1445.   return rc;
  1446. }
  1447. VXIinetResult SBinetHttpStream::Write(const VXIbyte*   pBuffer,
  1448.                                       VXIulong         nBuflen,
  1449.                                       VXIulong*        pnWritten)
  1450. {
  1451.   return VXIinet_RESULT_UNSUPPORTED;
  1452. }
  1453. VXIinetResult SBinetHttpStream::waitStreamReady()
  1454. {
  1455.   int delay = getDelay();
  1456.   if (delay == 0) {
  1457.     SWITimeStamp tstamp;
  1458.     getTimeOut(&tstamp);
  1459.     Diag(MODULE_SBINET_CONNECTION_TAGID, L"SBinetHttpStream::waitStreamReady",
  1460.        L"%s%d", L"TimeOut occured, delay value ",tstamp.getAddedDelay());    
  1461.     Error(236, L"%s%d", L"waitStreamReady delay", delay);        
  1462.     return VXIinet_RESULT_FETCH_TIMEOUT;
  1463.   }
  1464.   
  1465.   switch (_inputStream->waitReady(delay))
  1466.   {
  1467.    case SWIstream::SUCCESS:
  1468.      return VXIinet_RESULT_SUCCESS;
  1469.      //no break: intentional
  1470.    case SWIstream::TIMED_OUT:
  1471.      Diag(MODULE_SBINET_CONNECTION_TAGID, L"SBinetHttpStream::waitStreamReady",
  1472.           L"%s%d", L"TimeOut occured for waitReady, delay value ", delay);     
  1473.      Error(236, L"%s%s", L"inputStream->waitReady", L"timeout");        
  1474.      return VXIinet_RESULT_FETCH_TIMEOUT;
  1475.      //no break: intentional
  1476.    default:
  1477.      Error(240, NULL);
  1478.      return VXIinet_RESULT_FETCH_ERROR;
  1479.   }
  1480. }
  1481. void SBinetHttpStream::writeDebugTimeStamp()
  1482. {
  1483.   // construct debug string
  1484.   char buffer[1400]; // total bytes needed + extra bytes
  1485.   char connId[200];
  1486.   char timeStamp[40];  
  1487.   // fill with NULL terminator chars
  1488.   memset(buffer, 0, 1400 * sizeof(char));   
  1489.   memset(connId, 0, 200 * sizeof(char));
  1490.   memset(timeStamp, 0, 40 * sizeof(char));  
  1491.   
  1492.   // we are sure the buffer is large enough since timeStamp's length is 40
  1493.   // connection id's is 200 and the buffer itself is 1400
  1494.   SBinetUtils::getTimeStampMsecStr(timeStamp);
  1495.   strncpy(connId, _connection->getId(), 200);
  1496.   sprintf(buffer, "%s, conn = %s, URL = ", timeStamp, connId);  
  1497.   // sprintf will automatically put  to output string, we can
  1498.   // safely call strlen() here.  Also, restrict the abs. uri to 1024 bytes
  1499.   strncpy(&buffer[strlen(buffer)], _url->getNAbsolute(), 1024);  
  1500.   // sprintf(buffer, "%s, URL = %s, conn = %s", timeStamp, absUri, connId);
  1501.   // send debug string          
  1502.   _channel->writeDebugString(CRLF "@ ");
  1503.   _channel->writeDebugString(buffer);
  1504.   _channel->writeDebugString(CRLF);
  1505. }