ncbi_http_connector.c
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:41k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbi_http_connector.c,v $
  4.  * PRODUCTION Revision 1000.3  2004/02/12 21:52:44  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [CORE_001] Dev-tree R6.63
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: ncbi_http_connector.c,v 1000.3 2004/02/12 21:52:44 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author:  Anton Lavrentiev, Denis Vakatov
  35.  *
  36.  * File Description:
  37.  *   Implement CONNECTOR for the HTTP-based network connection
  38.  *
  39.  *   See in "ncbi_connector.h" for the detailed specification of the underlying
  40.  *   connector("CONNECTOR", "SConnectorTag") methods and structures.
  41.  *
  42.  */
  43. #include "ncbi_ansi_ext.h"
  44. #include "ncbi_priv.h"
  45. #include <connect/ncbi_http_connector.h>
  46. #include <ctype.h>
  47. #include <stdlib.h>
  48. /***********************************************************************
  49.  *  INTERNAL -- Auxiliary types and static functions
  50.  ***********************************************************************/
  51. /* If the connector is allowed to connect
  52.  */
  53. typedef enum {
  54.     eCC_None,
  55.     eCC_Once,
  56.     eCC_Unlimited
  57. } ECanConnect;
  58. typedef unsigned EBCanConnect;
  59. typedef unsigned TBHCC_Flags;
  60. /* All internal data necessary to perform the (re)connect and I/O
  61.  *
  62.  * The following states are defined:
  63.  *  "sock"  | "read_header" | State description
  64.  * ---------+---------------+--------------------------------------------------
  65.  *   NULL   |  <whatever>   | User "WRITE" mode: accumulate data in buffer
  66.  * non-NULL |   non-zero    | HTTP header is being read
  67.  * non-NULL |     zero      | HTTP body is being read (user "READ" mode)
  68.  * ---------+---------------+--------------------------------------------------
  69.  */
  70. typedef struct {
  71.     SConnNetInfo*        net_info;        /* network configuration parameters*/
  72.     FHttpParseHTTPHeader parse_http_hdr;  /* callback to parse HTTP reply hdr*/
  73.     FHttpAdjustNetInfo   adjust_net_info; /* for on-the-fly net_info adjust  */
  74.     FHttpAdjustCleanup   adjust_cleanup;  /* supplemental user data...       */
  75.     void*                adjust_data;     /* ...and cleanup routine          */
  76.     TBHCC_Flags          flags:10;        /* as passed to constructor        */
  77.     unsigned             reserved:1;
  78.     unsigned             error_header:1;  /* only err.HTTP header on SOME dbg*/
  79.     EBCanConnect         can_connect:2;   /* whether more conns permitted    */
  80.     unsigned             read_header:1;   /* whether reading header          */
  81.     unsigned             shut_down:1;     /* whether shut down for write     */
  82.     unsigned short       failure_count;   /* incr each failure since open    */
  83.     SOCK                 sock;         /* socket;  NULL if not in "READ" mode*/
  84.     const STimeout*      o_timeout;    /* NULL(infinite), dflt or ptr to next*/
  85.     STimeout             oo_timeout;   /* storage for (finite) open timeout  */
  86.     const STimeout*      w_timeout;    /* NULL(infinite), dflt or ptr to next*/
  87.     STimeout             ww_timeout;   /* storage for a (finite) write tmo   */
  88.     BUF                  http;         /* storage for HTTP reply header      */
  89.     BUF                  r_buf;        /* storage to accumulate input data   */
  90.     BUF                  w_buf;        /* storage to accumulate output data  */
  91.     size_t               w_len;        /* pending message body size          */
  92. } SHttpConnector;
  93. /* Try to fix connection parameters (called for an unconnected connector) */
  94. static int/*bool*/ s_Adjust(SHttpConnector* uuu,
  95.                             char**          redirect,
  96.                             int/*bool*/     drop_unread)
  97. {
  98.     assert(!uuu->sock && uuu->can_connect != eCC_None);
  99.     /* we're here because something is going wrong */
  100.     if (++uuu->failure_count >= uuu->net_info->max_try) {
  101.         if (*redirect) {
  102.             free(*redirect);
  103.             *redirect = 0;
  104.         }
  105.         if (!drop_unread && uuu->failure_count > 1) {
  106.             CORE_LOGF(eLOG_Error, ("[HTTP]  Too many failed attempts (%d),"
  107.                                    " giving up", uuu->failure_count));
  108.         }
  109.         uuu->can_connect = eCC_None;
  110.         return 0/*failure*/;
  111.     }
  112.     /* adjust info before yet another connection attempt */
  113.     if (*redirect) {
  114.         int status = ConnNetInfo_ParseURL(uuu->net_info, *redirect);
  115.         free(*redirect);
  116.         *redirect = 0;
  117.         if (!status) {
  118.             CORE_LOG(eLOG_Error, "[HTTP]  Unable to parse redirect");
  119.             uuu->can_connect = eCC_None;
  120.             return 0/*failure*/;
  121.         }
  122.     } else if (!uuu->adjust_net_info ||
  123.                uuu->adjust_net_info(uuu->net_info,
  124.                                     uuu->adjust_data,
  125.                                     uuu->failure_count) == 0) {
  126.         if (!drop_unread && uuu->failure_count > 1) {
  127.             CORE_LOGF(eLOG_Error, ("[HTTP]  Retry attempts (%d) exhausted,"
  128.                                    " giving up", uuu->failure_count));
  129.         }
  130.         uuu->can_connect = eCC_None;
  131.         return 0/*failure*/;
  132.     }
  133.     ConnNetInfo_AdjustForHttpProxy(uuu->net_info);
  134.     if (uuu->net_info->debug_printout)
  135.         ConnNetInfo_Log(uuu->net_info, CORE_GetLOG());
  136.     return 1/*success*/;
  137. }
  138. /* Unconditionally drop the connection; timeout may specify time allowance */
  139. static void s_DropConnection(SHttpConnector* uuu, const STimeout* timeout)
  140. {
  141.     size_t http_size = BUF_Size(uuu->http);
  142.     assert(uuu->sock);
  143.     if (http_size  &&  BUF_Read(uuu->http, 0, http_size) != http_size) {
  144.         CORE_LOG(eLOG_Error, "[HTTP]  Cannot discard HTTP header buffer");
  145.         assert(0);
  146.     }
  147.     SOCK_SetTimeout(uuu->sock, eIO_Close, timeout);
  148.     SOCK_Close(uuu->sock);
  149.     uuu->sock = 0;
  150. }
  151. /* Connect to the HTTP server, specified by uuu->net_info's "port:host".
  152.  * Return eIO_Success only if socket connection has succeeded and uuu->sock
  153.  * is non-zero. If unsuccessful, try to adjust uuu->net_info by s_Adjust(),
  154.  * and then re-try the connection attempt.
  155.  */
  156. static EIO_Status s_Connect(SHttpConnector* uuu, int/*bool*/ drop_unread)
  157. {
  158.     assert(!uuu->sock);
  159.     if (uuu->can_connect == eCC_None) {
  160.         CORE_LOG(eLOG_Error, "[HTTP]  Connector is no longer usable");
  161.         return eIO_Closed;
  162.     }
  163.     /* the re-try loop... */
  164.     for (;;) {
  165.         int/*bool*/ reset_user_header = 0;
  166.         char*       http_user_header = 0;
  167.         char*       null = 0;
  168.         uuu->w_len = BUF_Size(uuu->w_buf);
  169.         if (uuu->net_info->http_user_header)
  170.             http_user_header = strdup(uuu->net_info->http_user_header);
  171.         if (!uuu->net_info->http_user_header == !http_user_header) {
  172.             ConnNetInfo_ExtendUserHeader
  173.                 (uuu->net_info, "User-Agent: NCBIHttpConnector"
  174. #ifdef NCBI_CXX_TOOLKIT
  175.                  " (C++ Toolkit)"
  176. #else
  177.                  " (C Toolkit)"
  178. #endif
  179.                  "rn");
  180.             reset_user_header = 1;
  181.         }
  182.         /* connect & send HTTP header */
  183.         uuu->sock = URL_Connect
  184.             (uuu->net_info->host,       uuu->net_info->port,
  185.              uuu->net_info->path,       uuu->net_info->args,
  186.              uuu->net_info->req_method, uuu->w_len,
  187.              uuu->o_timeout,            uuu->w_timeout,
  188.              uuu->net_info->http_user_header,
  189.              (int/*bool*/) (uuu->flags & fHCC_UrlEncodeArgs),
  190.              uuu->net_info->debug_printout == eDebugPrintout_Data
  191.              ? eOn : (uuu->net_info->debug_printout == eDebugPrintout_None
  192.                       ? eOff : eDefault));
  193.         if (reset_user_header) {
  194.             ConnNetInfo_SetUserHeader(uuu->net_info, 0);
  195.             uuu->net_info->http_user_header = http_user_header;
  196.         }
  197.         if (uuu->sock) {
  198.             if (!(uuu->flags & fHCC_NoUpread))
  199.                 SOCK_SetReadOnWrite(uuu->sock, eOn);
  200.             return eIO_Success;
  201.         }
  202.         /* connection failed, no socket was created */
  203.         if (!s_Adjust(uuu, &null, drop_unread))
  204.             break;
  205.     }
  206.     return eIO_Closed;
  207. }
  208. /* Connect to the server specified by uuu->net_info, then compose and form
  209.  * relevant HTTP header, and flush the accumulated output data(uuu->w_buf)
  210.  * after the HTTP header. If connection/write unsuccessful, retry to reconnect
  211.  * and send the data again until permitted by s_Adjust().
  212.  */
  213. static EIO_Status s_ConnectAndSend(SHttpConnector* uuu,int/*bool*/ drop_unread)
  214. {
  215.     EIO_Status status;
  216.     for (;;) {
  217.         char*  null = 0;
  218.         if (!uuu->sock) {
  219.             if ((status = s_Connect(uuu, drop_unread)) != eIO_Success)
  220.                 break;
  221.             assert(uuu->sock);
  222.             uuu->read_header = 1/*true*/;
  223.             uuu->shut_down = 0/*false*/;
  224.         } else
  225.             status = eIO_Success;
  226.         if (uuu->w_len) {
  227.             size_t off = BUF_Size(uuu->w_buf) - uuu->w_len;
  228.             SOCK_SetTimeout(uuu->sock, eIO_Write, uuu->w_timeout);
  229.             do {
  230.                 char   buf[4096];
  231.                 size_t n_written;
  232.                 size_t n_write = BUF_PeekAt(uuu->w_buf, off, buf, sizeof(buf));
  233.                 status = SOCK_Write(uuu->sock, buf, n_write,
  234.                                     &n_written, eIO_WritePlain);
  235.                 if (status != eIO_Success)
  236.                     break;
  237.                 uuu->w_len -= n_written;
  238.                 off        += n_written;
  239.             } while (uuu->w_len);
  240.         } else if (!uuu->shut_down)
  241.             status = SOCK_Write(uuu->sock, 0, 0, 0, eIO_WritePlain);
  242.         if (status == eIO_Success) {
  243.             assert(uuu->w_len == 0);
  244.             if (!uuu->shut_down) {
  245.                 /* 10/07/03: While this call here is perfectly legal, it could
  246.                  * cause connection severed by a buggy CISCO load-balancer. */
  247.                 /* 10/28/03: CISCO's beta patch for their LB shows that the
  248.                  * problem has been fixed; no more 2'30" drops in connections
  249.                  * that shut down for write.  We still leave this commented
  250.                  * out to allow unpatched clients work seamlessly... */ 
  251.                 /*SOCK_Shutdown(uuu->sock, eIO_Write);*/
  252.                 uuu->shut_down = 1;
  253.             }
  254.             break;
  255.         }
  256.         if (status == eIO_Timeout &&  uuu->w_timeout  &&
  257.             !uuu->w_timeout->sec  &&  !uuu->w_timeout->usec) {
  258.             break;
  259.         }
  260.         CORE_LOGF(eLOG_Error,
  261.                   ("[HTTP]  Error writing body at offset %lu (%s)",
  262.                    (unsigned long) (BUF_Size(uuu->w_buf) - uuu->w_len),
  263.                    IO_StatusStr(status)));
  264.         /* write failed; close and try to use another server */
  265.         SOCK_Abort(uuu->sock);
  266.         s_DropConnection(uuu, 0/*no wait*/);
  267.         if (!s_Adjust(uuu, &null, drop_unread)) {
  268.             status = eIO_Closed;
  269.             break;
  270.         }
  271.     }
  272.     return status;
  273. }
  274. /* Parse HTTP header */
  275. static EIO_Status s_ReadHeader(SHttpConnector* uuu, char** redirect)
  276. {
  277.     int/*bool*/ moved = 0/*false*/;
  278.     int         server_error = 0;
  279.     int         http_status = 0;
  280.     char*       header;
  281.     size_t      size;
  282.     assert(uuu->sock && uuu->read_header);
  283.     *redirect = 0;
  284.     if (uuu->flags & fHCC_KeepHeader) {
  285.         uuu->read_header = 0;
  286.         return eIO_Success;
  287.     }
  288.     /* line by line HTTP header input */
  289.     for (;;) {
  290.         EIO_Status status;
  291.         /* do we have full header yet? */
  292.         size = BUF_Size(uuu->http);
  293.         if (!(header = (char*) malloc(size + 1))) {
  294.             CORE_LOGF(eLOG_Error, ("[HTTP]  Cannot allocate header, %lu bytes",
  295.                                    (unsigned long) size));
  296.             return eIO_Unknown;
  297.         }
  298.         verify(BUF_Peek(uuu->http, header, size) == size);
  299.         header[size] = '';
  300.         if (size >= 4  &&  strcmp(&header[size - 4], "rnrn") == 0)
  301.             break/*full header captured*/;
  302.         free(header);
  303.         status = SOCK_StripToPattern(uuu->sock, "rn", 2, &uuu->http, 0);
  304.         if (status != eIO_Success) {
  305.             const STimeout* tmo = SOCK_GetTimeout(uuu->sock, eIO_Read);
  306.             if (tmo && (tmo->sec || tmo->usec)) {
  307.                 CORE_LOGF(eLOG_Error, ("[HTTP]  Error reading header (%s)",
  308.                                        IO_StatusStr(status)));
  309.             }
  310.             return status;
  311.         }
  312.     }
  313.     uuu->read_header = 0/*false*/; /* the entire header has been read */
  314.     if (BUF_Read(uuu->http, 0, size) != size) {
  315.         CORE_LOG(eLOG_Error, "[HTTP]  Cannot discard HTTP header buffer");
  316.         assert(0);
  317.     }
  318.     /* HTTP status must come on the first line of the reply */
  319.     if (sscanf(header, " HTTP/%*d.%*d %d ", &http_status) != 1  ||
  320.         http_status < 200  ||  299 < http_status) {
  321.         server_error = http_status;
  322.         if (http_status == 301  ||  http_status == 302)
  323.             moved = 1;
  324.         else if (http_status == 403  ||  http_status == 404)
  325.             uuu->net_info->max_try = 0;
  326.     }
  327.     if ((server_error || !uuu->error_header) &&
  328.         uuu->net_info->debug_printout == eDebugPrintout_Some) {
  329.         /* HTTP header gets printed as part of data logging when
  330.            uuu->net_info->debug_printout == eDebugPrintout_Data. */
  331.         const char* header_header;
  332.         if (!server_error) 
  333.             header_header = "HTTP header";
  334.         else if (moved)
  335.             header_header = "HTTP header (moved)";
  336.         else if (!uuu->net_info->max_try)
  337.             header_header = "HTTP header (unrecoverable error)";
  338.         else
  339.             header_header = "HTTP header (server error, can retry)";
  340.         CORE_DATA(header, size, header_header);
  341.     }
  342.     if (uuu->parse_http_hdr) {
  343.         if (!(*uuu->parse_http_hdr)
  344.             (header, uuu->adjust_data, server_error))
  345.             server_error = 1;
  346.     }
  347.     if (moved) {
  348.         /* parsing "Location" pointer */
  349.         const char k_LocationTag[] = "nLocation: ";
  350.         char*      location = strstr(header, k_LocationTag);
  351.         if (location) {
  352.             char* s;
  353.             location += sizeof(k_LocationTag) - 1;
  354.             if (!(s = strchr(location, 'r')))
  355.                 *strchr(location, 'n') = 0;
  356.             else
  357.                 *s = 0;
  358.             while (*location) {
  359.                 if (isspace((unsigned char)(*location)))
  360.                     location++;
  361.                 else
  362.                     break;
  363.             }
  364.             for (s = location; *s; s++)
  365.                 if (isspace((unsigned char)(*s)))
  366.                     break;
  367.             *s = 0;
  368.             if (*location)
  369.                 *redirect = strdup(location);
  370.         }
  371.     }
  372.     if (header)
  373.         free(header);
  374.     /* skip & printout the content, if server error was flagged */
  375.     if (server_error && uuu->net_info->debug_printout == eDebugPrintout_Some) {
  376.         BUF        buf = 0;
  377.         EIO_Status status;
  378.         char*      body;
  379.         SOCK_SetTimeout(uuu->sock, eIO_Read, 0);
  380.         status = SOCK_StripToPattern(uuu->sock, 0, 0, &buf, 0);
  381.         assert(status != eIO_Success); /* because reading until EOF */
  382.         if (!(size = BUF_Size(buf))) {
  383.             CORE_LOG(eLOG_Trace, "[HTTP]  No body received with this error");
  384.         } else if ((body = (char*) malloc(size)) != 0) {
  385.             size_t n = BUF_Read(buf, body, size);
  386.             if (n != size) {
  387.                 CORE_LOGF(eLOG_Error, ("[HTTP]  Cannot read server error "
  388.                                        "body from buffer (%lu out of %lu)",
  389.                                        (unsigned long) n,
  390.                                        (unsigned long) size));
  391.             }
  392.             CORE_DATA(body, n, "HTTP server error body");
  393.             free(body);
  394.         } else {
  395.             CORE_LOGF(eLOG_Error, ("[HTTP]  Cannot allocate server error "
  396.                                    "body, %lu bytes", (unsigned long) size));
  397.         }
  398.         BUF_Destroy(buf);
  399.     }
  400.     return server_error ? eIO_Unknown : eIO_Success;
  401. }
  402. /* Prepare connector for reading. Open socket if necessary and
  403.  * make initial connect and send, re-trying if possible until success.
  404.  * Return codes:
  405.  *   eIO_Success = success, connector is ready for reading (uuu->sock != NULL);
  406.  *   eIO_Timeout = maybe (check uuu->sock) connected and no data yet available;
  407.  *   other code  = error, not connected (uuu->sock == NULL).
  408.  */
  409. static EIO_Status s_PreRead(SHttpConnector* uuu,
  410.                             const STimeout* timeout,
  411.                             int/*bool*/     drop_unread)
  412. {
  413.     char* redirect = 0;
  414.     EIO_Status status;
  415.     for (;;) {
  416.         status = s_ConnectAndSend(uuu, drop_unread);
  417.         if (!uuu->sock) {
  418.             assert(status != eIO_Success);
  419.             break;
  420.         }
  421.         if (status != eIO_Success) {
  422.             if (status != eIO_Timeout ||
  423.                 status == SOCK_Status(uuu->sock, eIO_Read)/*pending*/)
  424.                 break;
  425.         }
  426.         /* set timeout */
  427.         SOCK_SetTimeout(uuu->sock, eIO_Read, timeout);
  428.         if (!uuu->read_header)
  429.             break;
  430.         if ((status = s_ReadHeader(uuu, &redirect)) == eIO_Success) {
  431.             size_t w_size = BUF_Size(uuu->w_buf);
  432.             assert(!uuu->read_header);
  433.             /* pending output data no longer needed */
  434.             if (BUF_Read(uuu->w_buf, 0, w_size) != w_size) {
  435.                 CORE_LOG(eLOG_Error, "[HTTP]  Cannot discard output buffer");
  436.                 assert(0);
  437.             }
  438.             break;
  439.         }
  440.         /* if polling then bail out with eIO_Timeout */
  441.         if(status == eIO_Timeout && timeout && !timeout->sec && !timeout->usec)
  442.             break;
  443.         /* HTTP header read error; disconnect and try to use another server */
  444.         SOCK_Abort(uuu->sock);
  445.         s_DropConnection(uuu, 0/*no wait*/);
  446.         if (!s_Adjust(uuu, &redirect, drop_unread))
  447.             break;
  448.         assert(redirect == 0);
  449.     }
  450.     assert(redirect == 0);
  451.     return status;
  452. }
  453. /* Read non-header data from connection */
  454. static EIO_Status s_Read(SHttpConnector* uuu, void* buf,
  455.                          size_t size, size_t* n_read)
  456. {
  457.     assert(uuu->sock);
  458.     /* just read, with no URL-decoding */
  459.     if (!(uuu->flags & fHCC_UrlDecodeInput))
  460.         return SOCK_Read(uuu->sock, buf, size, n_read, eIO_ReadPlain);
  461.     /* read and URL-decode */
  462.     {{
  463.         EIO_Status status;
  464.         size_t     n_peeked, n_decoded;
  465.         size_t     peek_size = 3 * size;
  466.         void*      peek_buf  = malloc(peek_size);
  467.         /* peek the data */
  468.         status= SOCK_Read(uuu->sock,peek_buf,peek_size,&n_peeked,eIO_ReadPeek);
  469.         if (status != eIO_Success) {
  470.             *n_read = 0;
  471.             free(peek_buf);
  472.             return status;
  473.         }
  474.         /* decode, then discard the successfully decoded data from the input */
  475.         if (URL_Decode(peek_buf, n_peeked, &n_decoded, buf, size, n_read)) {
  476.             if (n_decoded) {
  477.                 size_t x_read;
  478.                 SOCK_Read(uuu->sock,peek_buf,n_decoded,&x_read,eIO_ReadPlain);
  479.                 assert(x_read == n_decoded);
  480.                 status = eIO_Success;
  481.             } else if (SOCK_Status(uuu->sock, eIO_Read) == eIO_Closed)
  482.                 /* we are at EOF, and the remaining data cannot be decoded */
  483.                 status = eIO_Unknown;
  484.         } else
  485.             status = eIO_Unknown;
  486.         if (status != eIO_Success)
  487.             CORE_LOG(eLOG_Error, "[HTTP]  Cannot URL-decode data");
  488.         free(peek_buf);
  489.         return status;
  490.     }}
  491. }
  492. /* Reset/readout input data and close socket */
  493. static EIO_Status s_Disconnect(SHttpConnector* uuu,
  494.                                int/*bool*/     drop_unread,
  495.                                const STimeout* timeout)
  496. {
  497.     EIO_Status status = eIO_Success;
  498.     if (drop_unread) {
  499.         size_t r_size = BUF_Size(uuu->r_buf);
  500.         if (r_size  &&  BUF_Read(uuu->r_buf, 0, r_size) != r_size) {
  501.             CORE_LOG(eLOG_Error, "[HTTP]  Cannot drop input buffer");
  502.             assert(0);
  503.         }
  504.     } else if ((status = s_PreRead(uuu, timeout, 0/*nodrop*/)) == eIO_Success){
  505.         do {
  506.             char     buf[4096];
  507.             size_t   x_read;
  508.             status = s_Read(uuu, buf, sizeof(buf), &x_read);
  509.             if (!BUF_Write(&uuu->r_buf, buf, x_read))
  510.                 status = eIO_Unknown;
  511.         } while (status == eIO_Success);
  512.         if (status == eIO_Closed)
  513.             status = eIO_Success;
  514.     }
  515.     if (uuu->sock) /* s_PreRead() might have dropped the connection already */
  516.         s_DropConnection(uuu, timeout);
  517.     if (uuu->can_connect == eCC_Once)
  518.         uuu->can_connect = eCC_None;
  519.     return status;
  520. }
  521. /* Send the accumulated output data(if any) to server, then close socket.
  522.  * Regardless of the flush, clear both input and output buffer.
  523.  * This function is only called to either re-open or close the connector.
  524.  */
  525. static void s_FlushAndDisconnect(SHttpConnector* uuu,
  526.                                  const STimeout* timeout,
  527.                                  int/*bool*/     close)
  528. {
  529.     size_t w_size = BUF_Size(uuu->w_buf);
  530.     /* store timeouts for later use */
  531.     if (timeout) {
  532.         uuu->oo_timeout = *timeout;
  533.         uuu->o_timeout  = &uuu->oo_timeout;
  534.         uuu->ww_timeout = *timeout;
  535.         uuu->w_timeout  = &uuu->ww_timeout;
  536.     } else {
  537.         uuu->o_timeout  = timeout;
  538.         uuu->w_timeout  = timeout;
  539.     }
  540.     if (close  &&  uuu->can_connect != eCC_None  &&  !uuu->sock  &&
  541.         ((uuu->flags & fHCC_SureFlush)  ||  BUF_Size(uuu->w_buf))) {
  542.         /* "WRITE" mode and data (or just flag) pending */
  543.         s_PreRead(uuu, timeout, 1/*drop_unread*/);
  544.     }
  545.     s_Disconnect(uuu, 1/*drop_unread*/, timeout);
  546.     assert(!uuu->sock);
  547.     /* clear pending output data, if any */
  548.     if (w_size  &&  BUF_Read(uuu->w_buf, 0, w_size) != w_size) {
  549.         CORE_LOG(eLOG_Error, "[HTTP]  Cannot drop output buffer");
  550.         assert(0);
  551.     }
  552. }
  553. /***********************************************************************
  554.  *  INTERNAL -- "s_VT_*" functions for the "virt. table" of connector methods
  555.  ***********************************************************************/
  556. #ifdef __cplusplus
  557. extern "C" {
  558. #endif /* __cplusplus */
  559.     static const char* s_VT_GetType (CONNECTOR       connector);
  560.     static char*       s_VT_Descr   (CONNECTOR       connector);
  561.     static EIO_Status  s_VT_Open    (CONNECTOR       connector,
  562.                                      const STimeout* timeout);
  563.     static EIO_Status  s_VT_Wait    (CONNECTOR       connector,
  564.                                      EIO_Event       event,
  565.                                      const STimeout* timeout);
  566.     static EIO_Status  s_VT_Write   (CONNECTOR       connector,
  567.                                      const void*     buf,
  568.                                      size_t          size,
  569.                                      size_t*         n_written,
  570.                                      const STimeout* timeout);
  571.     static EIO_Status  s_VT_Flush   (CONNECTOR       connector,
  572.                                      const STimeout* timeout);
  573.     static EIO_Status  s_VT_Read    (CONNECTOR       connector,
  574.                                      void*           buf,
  575.                                      size_t          size,
  576.                                      size_t*         n_read,
  577.                                      const STimeout* timeout);
  578.     static EIO_Status  s_VT_Status  (CONNECTOR       connector,
  579.                                      EIO_Event       dir);
  580.     static EIO_Status  s_VT_Close   (CONNECTOR       connector,
  581.                                      const STimeout* timeout);
  582.     static void        s_Setup      (SMetaConnector *meta,
  583.                                      CONNECTOR connector);
  584.     static void        s_Destroy    (CONNECTOR connector);
  585. #  ifdef IMPLEMENTED__CONN_WaitAsync
  586.     static EIO_Status s_VT_WaitAsync(CONNECTOR     connector,
  587.                                      FConnectorAsyncHandler  func,
  588.                                      SConnectorAsyncHandler* data);
  589. #  endif
  590. #ifdef __cplusplus
  591. } /* extern "C" */
  592. #endif /* __cplusplus */
  593. /*ARGSUSED*/
  594. static const char* s_VT_GetType
  595. (CONNECTOR connector)
  596. {
  597.     return "HTTP";
  598. }
  599. static char* s_VT_Descr
  600. (CONNECTOR connector)
  601. {
  602.     SHttpConnector* uuu = (SHttpConnector*) connector->handle;
  603.     size_t len = 7/*"http://"*/ + strlen(uuu->net_info->host) +
  604.         (uuu->net_info->port == 80 ? 0 : 6/*:port*/) +
  605.         strlen(uuu->net_info->path) +
  606.         (*uuu->net_info->args ? 2 + strlen(uuu->net_info->args) : 1);
  607.     char* buf = (char*) malloc(len);
  608.     if (buf) {
  609.         len = sprintf(buf, "http://%s", uuu->net_info->host);
  610.         if (uuu->net_info->port != 80)
  611.             len += sprintf(&buf[len], ":%hu", uuu->net_info->port);
  612.         sprintf(&buf[len], "%s%s%s", uuu->net_info->path,
  613.                 *uuu->net_info->args ? "&" : "", uuu->net_info->args);
  614.     }
  615.     return buf;
  616. }
  617. static EIO_Status s_VT_Open
  618. (CONNECTOR       connector,
  619.  const STimeout* timeout)
  620. {
  621.     SHttpConnector* uuu = (SHttpConnector*) connector->handle;
  622.     /* NOTE: the real connect will be performed on the first "READ", or
  623.      * "CLOSE", or on "WAIT" on read -- see in "s_ConnectAndSend()";
  624.      * we just close underlying socket and prepare to open it later */
  625.     s_FlushAndDisconnect(uuu, timeout, 0/*open*/);
  626.     /* reset the auto-reconnect feature */
  627.     uuu->can_connect = uuu->flags & fHCC_AutoReconnect
  628.         ? eCC_Unlimited : eCC_Once;
  629.     uuu->failure_count = 0;
  630.     return eIO_Success;
  631. }
  632. static EIO_Status s_VT_Wait
  633. (CONNECTOR       connector,
  634.  EIO_Event       event,
  635.  const STimeout* timeout)
  636. {
  637.     SHttpConnector* uuu = (SHttpConnector*) connector->handle;
  638.     switch (event) {
  639.     case eIO_Read:
  640.         if (uuu->can_connect == eCC_None)
  641.             return eIO_Closed;
  642.         if (!uuu->sock || uuu->read_header) {
  643.             EIO_Status status = s_PreRead(uuu, timeout, 0/*no drop unread*/);
  644.             if (status != eIO_Success || BUF_Size(uuu->r_buf))
  645.                 return status;
  646.             assert(uuu->sock);
  647.         }
  648.         return SOCK_Wait(uuu->sock, eIO_Read, timeout);
  649.     case eIO_Write:
  650.         /* Return 'Closed' if no more writes are allowed (and now - reading) */
  651.         return uuu->can_connect == eCC_None ||
  652.             (uuu->sock && uuu->can_connect == eCC_Once)
  653.             ? eIO_Closed : eIO_Success;
  654.     default:
  655.         assert(0);
  656.         return eIO_InvalidArg;
  657.     }
  658. }
  659. static EIO_Status s_VT_Write
  660. (CONNECTOR       connector,
  661.  const void*     buf,
  662.  size_t          size,
  663.  size_t*         n_written,
  664.  const STimeout* timeout)
  665. {
  666.     SHttpConnector* uuu = (SHttpConnector*) connector->handle;
  667.     /* if trying to "WRITE" after "READ" then close the socket,
  668.      * and so switch to "WRITE" mode */
  669.     if (uuu->sock) {
  670.         EIO_Status status = s_Disconnect(uuu,
  671.                                          uuu->flags & fHCC_DropUnread,
  672.                                          timeout);
  673.         if (status != eIO_Success)
  674.             return status;
  675.     }
  676.     if (uuu->can_connect == eCC_None)
  677.         return eIO_Closed; /* no more connects permitted */
  678.     /* accumulate all output in the memory buffer */
  679.     if (uuu->flags & fHCC_UrlEncodeOutput) {
  680.         /* with URL-encoding */
  681.         size_t dst_size = 3 * size;
  682.         void* dst = malloc(dst_size);
  683.         size_t dst_written;
  684.         URL_Encode(buf, size, n_written, dst, dst_size, &dst_written);
  685.         assert(*n_written == size);
  686.         if (!BUF_Write(&uuu->w_buf, dst, dst_written)) {
  687.             free(dst);
  688.             return eIO_Unknown;
  689.         }
  690.         free(dst);
  691.     } else {
  692.         /* "as is" (without URL-encoding) */
  693.         if (!BUF_Write(&uuu->w_buf, buf, size))
  694.             return eIO_Unknown;
  695.         *n_written = size;
  696.     }
  697.     /* store the write timeout */
  698.     if (timeout) {
  699.         uuu->ww_timeout = *timeout;
  700.         uuu->w_timeout  = &uuu->ww_timeout;
  701.     } else
  702.         uuu->w_timeout  = timeout;
  703.     return eIO_Success;
  704. }
  705. static EIO_Status s_VT_Flush
  706. (CONNECTOR       connector,
  707.  const STimeout* timeout)
  708. {
  709.     SHttpConnector* uuu = (SHttpConnector*) connector->handle;
  710.     /* The real flush will be performed on the first "READ" (or "CLOSE"),
  711.      * or on "WAIT". Here, we just store the write timeout, that's all...
  712.      */
  713.     if (timeout) {
  714.         uuu->ww_timeout = *timeout;
  715.         uuu->w_timeout  = &uuu->ww_timeout;
  716.     } else
  717.         uuu->w_timeout  = timeout;
  718.     return eIO_Success;
  719. }
  720. static EIO_Status s_VT_Read
  721. (CONNECTOR       connector,
  722.  void*           buf,
  723.  size_t          size,
  724.  size_t*         n_read,
  725.  const STimeout* timeout)
  726. {
  727.     SHttpConnector* uuu = (SHttpConnector*) connector->handle;
  728.     EIO_Status status = s_PreRead(uuu, timeout, 0/*no drop unread*/);
  729.     size_t x_read = BUF_Read(uuu->r_buf, buf, size);
  730.     *n_read = x_read;
  731.     if (x_read < size) {
  732.         if (status != eIO_Success)
  733.             return status;
  734.         status = s_Read(uuu, (char*) buf + x_read, size - x_read, n_read);
  735.         *n_read += x_read;
  736.     } else
  737.         status = eIO_Success;
  738.     return *n_read ? eIO_Success : status;
  739. }
  740. static EIO_Status s_VT_Status
  741. (CONNECTOR connector,
  742.  EIO_Event dir)
  743. {
  744.     SHttpConnector* uuu = (SHttpConnector*) connector->handle;
  745.     return uuu->sock ? SOCK_Status(uuu->sock, dir) :
  746.         (uuu->can_connect == eCC_None ? eIO_Closed : eIO_Success);
  747. }
  748. static EIO_Status s_VT_Close
  749. (CONNECTOR       connector,
  750.  const STimeout* timeout)
  751. {
  752.     s_FlushAndDisconnect((SHttpConnector*) connector->handle,
  753.                          timeout, 1/*close*/);
  754.     return eIO_Success;
  755. }
  756. #ifdef IMPLEMENTED__CONN_WaitAsync
  757. static EIO_Status s_VT_WaitAsync
  758. (void*                   connector,
  759.  FConnectorAsyncHandler  func,
  760.  SConnectorAsyncHandler* data)
  761. {
  762.     return eIO_NotSupported;
  763. }
  764. #endif
  765. static void s_Setup(SMetaConnector *meta, CONNECTOR connector)
  766. {
  767.     SHttpConnector* uuu = (SHttpConnector*) connector->handle;
  768.     /* initialize virtual table */
  769.     CONN_SET_METHOD(meta, get_type,   s_VT_GetType,   connector);
  770.     CONN_SET_METHOD(meta, descr,      s_VT_Descr,     connector);
  771.     CONN_SET_METHOD(meta, open,       s_VT_Open,      connector);
  772.     CONN_SET_METHOD(meta, wait,       s_VT_Wait,      connector);
  773.     CONN_SET_METHOD(meta, write,      s_VT_Write,     connector);
  774.     CONN_SET_METHOD(meta, flush,      s_VT_Flush,     connector);
  775.     CONN_SET_METHOD(meta, read,       s_VT_Read,      connector);
  776.     CONN_SET_METHOD(meta, status,     s_VT_Status,    connector);
  777.     CONN_SET_METHOD(meta, close,      s_VT_Close,     connector);
  778. #ifdef IMPLEMENTED__CONN_WaitAsync
  779.     CONN_SET_METHOD(meta, wait_async, s_VT_WaitAsync, connector);
  780. #endif
  781.     CONN_SET_DEFAULT_TIMEOUT(meta, uuu->net_info->timeout);
  782. }
  783. static void s_Destroy(CONNECTOR connector)
  784. {
  785.     SHttpConnector* uuu = (SHttpConnector*) connector->handle;
  786.     if (uuu->adjust_cleanup)
  787.         uuu->adjust_cleanup(uuu->adjust_data);
  788.     ConnNetInfo_Destroy(uuu->net_info);
  789.     BUF_Destroy(uuu->http);
  790.     BUF_Destroy(uuu->r_buf);
  791.     BUF_Destroy(uuu->w_buf);
  792.     free(uuu);
  793.     connector->handle = 0;
  794.     free(connector);
  795. }
  796. /***********************************************************************
  797.  *  EXTERNAL -- the connector's "constructor"
  798.  ***********************************************************************/
  799. extern CONNECTOR HTTP_CreateConnector
  800. (const SConnNetInfo* info,
  801.  const char*         user_header,
  802.  THCC_Flags          flags)
  803. {
  804.     SConnNetInfo *net_info;
  805.     CONNECTOR connector;
  806.     net_info = info ? ConnNetInfo_Clone(info) : ConnNetInfo_Create(0);
  807.     if (user_header)
  808.         ConnNetInfo_SetUserHeader(net_info, user_header);
  809.     connector = HTTP_CreateConnectorEx(net_info, flags, 0, 0, 0, 0);
  810.     ConnNetInfo_Destroy(net_info);
  811.     return connector;
  812. }
  813. extern CONNECTOR HTTP_CreateConnectorEx
  814. (const SConnNetInfo*  net_info,
  815.  THCC_Flags           flags,
  816.  FHttpParseHTTPHeader parse_http_hdr,
  817.  FHttpAdjustNetInfo   adjust_net_info,
  818.  void*                adjust_data,
  819.  FHttpAdjustCleanup   adjust_cleanup)
  820. {
  821.     CONNECTOR       ccc = (SConnector    *) malloc(sizeof(SConnector    ));
  822.     SHttpConnector* uuu = (SHttpConnector*) malloc(sizeof(SHttpConnector));
  823.     /* initialize internal data structure */
  824.     uuu->net_info        = net_info ?
  825.         ConnNetInfo_Clone(net_info) : ConnNetInfo_Create(0);
  826.     ConnNetInfo_AdjustForHttpProxy(uuu->net_info);
  827.     if (uuu->net_info->debug_printout)
  828.         ConnNetInfo_Log(uuu->net_info, CORE_GetLOG());
  829.     uuu->parse_http_hdr  = parse_http_hdr;
  830.     uuu->adjust_net_info = adjust_net_info;
  831.     uuu->adjust_cleanup  = adjust_cleanup;
  832.     uuu->adjust_data     = adjust_data;
  833.     uuu->flags           = flags;
  834.     if (flags & fHCC_UrlDecodeInput)
  835.         uuu->flags      &= ~fHCC_KeepHeader;
  836.     uuu->can_connect     = eCC_Once;         /* will be properly set at open */
  837.     uuu->error_header    = getenv("HTTP_ERROR_HEADER_ONLY") ? 1 : 0;
  838.     uuu->sock            = 0;
  839.     uuu->o_timeout       = kDefaultTimeout;  /* deliberately bad values --   */
  840.     uuu->w_timeout       = kDefaultTimeout;  /* will be reset prior to use   */
  841.     uuu->http            = 0;
  842.     uuu->r_buf           = 0;
  843.     uuu->w_buf           = 0;
  844.     /* there are some unintialized fields left -- they are initted later */
  845.     /* initialize connector structure */
  846.     ccc->handle  = uuu;
  847.     ccc->next    = 0;
  848.     ccc->meta    = 0;
  849.     ccc->setup   = s_Setup;
  850.     ccc->destroy = s_Destroy;
  851.     return ccc;
  852. }
  853. /*
  854.  * --------------------------------------------------------------------------
  855.  * $Log: ncbi_http_connector.c,v $
  856.  * Revision 1000.3  2004/02/12 21:52:44  gouriano
  857.  * PRODUCTION: UPGRADED [CORE_001] Dev-tree R6.63
  858.  *
  859.  * Revision 6.63  2004/02/12 16:50:02  lavr
  860.  * Heed warning about uninited variable use
  861.  *
  862.  * Revision 6.62  2003/11/26 12:57:11  lavr
  863.  * s_ReadHeader(): check header size first before looking for end-of-header
  864.  *
  865.  * Revision 6.61  2003/11/03 17:37:42  lavr
  866.  * Fix previous accidental commit and provide corrent change log info:
  867.  * 1. Added more notes about SOCK_Shutdown() being left commented out;
  868.  * 2. Do not print HTTP error body if data trace mode set to "DATA".
  869.  *
  870.  * Revision 6.59  2003/10/29 14:09:08  lavr
  871.  * Log levels and messages changed in some error reports
  872.  *
  873.  * Revision 6.58  2003/10/23 12:27:38  lavr
  874.  * Do not double HTTP header when full data logging is explicitly on
  875.  *
  876.  * Revision 6.57  2003/10/07 20:00:10  lavr
  877.  * Remove SOCK_Shutdown() after sending the HTTP header and request body
  878.  *
  879.  * Revision 6.56  2003/09/30 19:44:08  lavr
  880.  * Fix typos in error messages
  881.  *
  882.  * Revision 6.55  2003/08/25 14:40:29  lavr
  883.  * Employ new k..Timeout constants
  884.  *
  885.  * Revision 6.54  2003/06/09 19:52:42  lavr
  886.  * New env.var. HTTP_ERROR_HEADER_ONLY to control header output on SOME tracing
  887.  *
  888.  * Revision 6.53  2003/06/04 20:58:13  lavr
  889.  * s_Adjust() to return failure if no adjustment callback specified
  890.  * s_VT_Status() to return eIO_Closed if connector failed/closed
  891.  *
  892.  * Revision 6.52  2003/05/31 05:15:15  lavr
  893.  * Add ARGSUSED where args are meant to be unused
  894.  *
  895.  * Revision 6.51  2003/05/21 17:54:16  lavr
  896.  * s_VT_Read() to return eIO_Success if some data have been read
  897.  *
  898.  * Revision 6.50  2003/05/20 23:54:00  lavr
  899.  * Reinstate ConnNetInfo_Destroy() accidently deleted from s_Destroy()
  900.  *
  901.  * Revision 6.49  2003/05/20 21:26:40  lavr
  902.  * Restructure SHttpConnector; add SHttpConnector::shut_down; enable to
  903.  * call SOCK_Shutdown() again (after doing a dummy write of 0 bytes)
  904.  *
  905.  * Revision 6.48  2003/05/19 21:03:50  lavr
  906.  * Remove SOCK_Shutdown() temporarily
  907.  *
  908.  * Revision 6.47  2003/05/19 16:48:39  lavr
  909.  * Pending HTTP body write implemented ({0,0}-timeout tolerant)
  910.  *
  911.  * Revision 6.46  2003/05/14 03:57:48  lavr
  912.  * Better logging; implementation of CONN_Description(); support of
  913.  * {0,0} connect timeouts; bug workaround of MSVC's lame shutdown() is
  914.  * now in ncbi_socket.c and moved away from this module
  915.  *
  916.  * Revision 6.45  2003/04/30 17:01:42  lavr
  917.  * One (unnecessary) variable removed from s_ReadHeader()
  918.  *
  919.  * Revision 6.44  2003/02/04 22:04:11  lavr
  920.  * Minor fix in comment
  921.  *
  922.  * Revision 6.43  2003/01/31 21:18:49  lavr
  923.  * Fullfil max tries even in the absence of connection adjustment routine
  924.  *
  925.  * Revision 6.42  2003/01/17 19:44:46  lavr
  926.  * Reduce dependencies
  927.  *
  928.  * Revision 6.41  2003/01/15 20:27:29  lavr
  929.  * Fix breeding of NCBIHttpConnector token in User-Agent: header tag
  930.  *
  931.  * Revision 6.40  2003/01/10 14:51:29  lavr
  932.  * Revert to R6.37 but properly handle drop of w_buf in s_FlushAndDisconnect()
  933.  *
  934.  * Revision 6.37  2002/12/13 21:19:40  lavr
  935.  * Extend User-Agent: header tag
  936.  *
  937.  * Revision 6.36  2002/11/19 19:20:37  lavr
  938.  * Server error parsing slightly changed
  939.  *
  940.  * Revision 6.35  2002/10/28 15:46:20  lavr
  941.  * Use "ncbi_ansi_ext.h" privately
  942.  *
  943.  * Revision 6.34  2002/10/22 15:11:24  lavr
  944.  * Zero connector's handle to crash if revisited
  945.  *
  946.  * Revision 6.33  2002/09/06 15:46:45  lavr
  947.  * Few bug fixes about corner cases of I/O waiting, flushing and logging
  948.  *
  949.  * Revision 6.32  2002/08/12 15:12:23  lavr
  950.  * Use persistent SOCK_Write()
  951.  *
  952.  * Revision 6.31  2002/08/07 16:33:04  lavr
  953.  * Changed EIO_ReadMethod enums accordingly; log moved to end
  954.  *
  955.  * Revision 6.30  2002/07/25 20:20:43  lavr
  956.  * Do not report header read error on {0, 0} timeout
  957.  *
  958.  * Revision 6.29  2002/07/25 13:59:35  lavr
  959.  * More diagnostic messages added
  960.  *
  961.  * Revision 6.28  2002/06/19 18:08:02  lavr
  962.  * Fixed some wrong assumptions on use of s_PreRead(); more comments added
  963.  *
  964.  * Revision 6.27  2002/06/10 19:51:20  lavr
  965.  * Small prettifying
  966.  *
  967.  * Revision 6.26  2002/05/06 19:13:48  lavr
  968.  * Output to stderr replaced with calls to logger
  969.  *
  970.  * Revision 6.25  2002/04/26 16:36:56  lavr
  971.  * Added setting of default timeout in meta-connector's setup routine
  972.  * Remove all checks for kDefaultTimeout: now supplied good from CONN
  973.  *
  974.  * Revision 6.24  2002/04/22 19:31:33  lavr
  975.  * Reading/waiting redesigned to be more robust in case of network errors
  976.  *
  977.  * Revision 6.23  2002/03/22 19:52:16  lavr
  978.  * Do not include <stdio.h>: included from ncbi_util.h or ncbi_priv.h
  979.  *
  980.  * Revision 6.22  2002/02/11 20:36:44  lavr
  981.  * Use "ncbi_config.h"
  982.  *
  983.  * Revision 6.21  2002/02/05 22:04:12  lavr
  984.  * Included header files rearranged
  985.  *
  986.  * Revision 6.20  2001/12/31 14:53:46  lavr
  987.  * #include <connect/ncbi_ansi_ext.h> for Mac to be happy (noted by J.Kans)
  988.  *
  989.  * Revision 6.19  2001/12/30 20:00:00  lavr
  990.  * Redirect on non-empty location only
  991.  *
  992.  * Revision 6.18  2001/12/30 19:41:07  lavr
  993.  * Process error codes 301 and 302 (document moved) and reissue HTTP request
  994.  *
  995.  * Revision 6.17  2001/09/28 20:48:23  lavr
  996.  * Comments revised; parameter (and SHttpConnector's) names adjusted
  997.  * Retry logic moved entirely into s_Adjust()
  998.  *
  999.  * Revision 6.16  2001/09/10 21:15:56  lavr
  1000.  * Readability issue: FParseHTTPHdr -> FParseHTTPHeader
  1001.  *
  1002.  * Revision 6.15  2001/05/23 21:52:44  lavr
  1003.  * +fHCC_NoUpread
  1004.  *
  1005.  * Revision 6.14  2001/05/17 15:02:51  lavr
  1006.  * Typos corrected
  1007.  *
  1008.  * Revision 6.13  2001/05/08 20:26:27  lavr
  1009.  * Patches in re-try code
  1010.  *
  1011.  * Revision 6.12  2001/04/26 20:21:34  lavr
  1012.  * Reorganized and and made slightly more effective
  1013.  *
  1014.  * Revision 6.11  2001/04/24 21:41:47  lavr
  1015.  * Reorganized code to allow reconnects in case of broken connections at
  1016.  * stage of connection, sending data and receiving HTTP header. Added
  1017.  * code to pull incoming data from connection while sending - stall protection.
  1018.  *
  1019.  * Revision 6.10  2001/03/02 20:08:47  lavr
  1020.  * Typo fixed
  1021.  *
  1022.  * Revision 6.9  2001/01/25 16:53:24  lavr
  1023.  * New flag for HTTP_CreateConnectorEx: fHCC_DropUnread
  1024.  *
  1025.  * Revision 6.8  2001/01/23 23:11:20  lavr
  1026.  * Status virtual method implemented
  1027.  *
  1028.  * Revision 6.7  2001/01/11 16:38:17  lavr
  1029.  * free(connector) removed from s_Destroy function
  1030.  * (now always called from outside, in METACONN_Remove)
  1031.  *
  1032.  * Revision 6.6  2001/01/03 22:32:43  lavr
  1033.  * Redundant calls to 'adjust_info' removed
  1034.  *
  1035.  * Revision 6.5  2000/12/29 17:57:16  lavr
  1036.  * Adapted for use of new connector structure;
  1037.  * parse header callback added; some internal functions renamed.
  1038.  *
  1039.  * Revision 6.4  2000/11/15 18:52:02  vakatov
  1040.  * Call SOCK_Shutdown() after the HTTP request is sent.
  1041.  * Use SOCK_Status() instead of SOCK_Eof().
  1042.  *
  1043.  * Revision 6.3  2000/10/12 21:43:14  vakatov
  1044.  * Minor cosmetic fix...
  1045.  *
  1046.  * Revision 6.2  2000/09/26 22:02:57  lavr
  1047.  * HTTP request method added
  1048.  *
  1049.  * Revision 6.1  2000/04/21 19:41:01  vakatov
  1050.  * Initial revision
  1051.  *
  1052.  * ==========================================================================
  1053.  */