⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ncbi_http_connector.c

📁 ncbi源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * =========================================================================== * PRODUCTION $Log: ncbi_http_connector.c,v $ * PRODUCTION Revision 1000.3  2004/02/12 21:52:44  gouriano * PRODUCTION PRODUCTION: UPGRADED [CORE_001] Dev-tree R6.63 * PRODUCTION * =========================================================================== *//*  $Id: ncbi_http_connector.c,v 1000.3 2004/02/12 21:52:44 gouriano Exp $ * =========================================================================== * *                            PUBLIC DOMAIN NOTICE *               National Center for Biotechnology Information * *  This software/database is a "United States Government Work" under the *  terms of the United States Copyright Act.  It was written as part of *  the author's official duties as a United States Government employee and *  thus cannot be copyrighted.  This software/database is freely available *  to the public for use. The National Library of Medicine and the U.S. *  Government have not placed any restriction on its use or reproduction. * *  Although all reasonable efforts have been taken to ensure the accuracy *  and reliability of the software and data, the NLM and the U.S. *  Government do not and cannot warrant the performance or results that *  may be obtained by using this software or data. The NLM and the U.S. *  Government disclaim all warranties, express or implied, including *  warranties of performance, merchantability or fitness for any particular *  purpose. * *  Please cite the author in any work or product based on this material. * * =========================================================================== * * Author:  Anton Lavrentiev, Denis Vakatov * * File Description: *   Implement CONNECTOR for the HTTP-based network connection * *   See in "ncbi_connector.h" for the detailed specification of the underlying *   connector("CONNECTOR", "SConnectorTag") methods and structures. * */#include "ncbi_ansi_ext.h"#include "ncbi_priv.h"#include <connect/ncbi_http_connector.h>#include <ctype.h>#include <stdlib.h>/*********************************************************************** *  INTERNAL -- Auxiliary types and static functions ***********************************************************************//* If the connector is allowed to connect */typedef enum {    eCC_None,    eCC_Once,    eCC_Unlimited} ECanConnect;typedef unsigned EBCanConnect;typedef unsigned TBHCC_Flags;/* All internal data necessary to perform the (re)connect and I/O * * The following states are defined: *  "sock"  | "read_header" | State description * ---------+---------------+-------------------------------------------------- *   NULL   |  <whatever>   | User "WRITE" mode: accumulate data in buffer * non-NULL |   non-zero    | HTTP header is being read * non-NULL |     zero      | HTTP body is being read (user "READ" mode) * ---------+---------------+-------------------------------------------------- */typedef struct {    SConnNetInfo*        net_info;        /* network configuration parameters*/    FHttpParseHTTPHeader parse_http_hdr;  /* callback to parse HTTP reply hdr*/    FHttpAdjustNetInfo   adjust_net_info; /* for on-the-fly net_info adjust  */    FHttpAdjustCleanup   adjust_cleanup;  /* supplemental user data...       */    void*                adjust_data;     /* ...and cleanup routine          */    TBHCC_Flags          flags:10;        /* as passed to constructor        */    unsigned             reserved:1;    unsigned             error_header:1;  /* only err.HTTP header on SOME dbg*/    EBCanConnect         can_connect:2;   /* whether more conns permitted    */    unsigned             read_header:1;   /* whether reading header          */    unsigned             shut_down:1;     /* whether shut down for write     */    unsigned short       failure_count;   /* incr each failure since open    */    SOCK                 sock;         /* socket;  NULL if not in "READ" mode*/    const STimeout*      o_timeout;    /* NULL(infinite), dflt or ptr to next*/    STimeout             oo_timeout;   /* storage for (finite) open timeout  */    const STimeout*      w_timeout;    /* NULL(infinite), dflt or ptr to next*/    STimeout             ww_timeout;   /* storage for a (finite) write tmo   */    BUF                  http;         /* storage for HTTP reply header      */    BUF                  r_buf;        /* storage to accumulate input data   */    BUF                  w_buf;        /* storage to accumulate output data  */    size_t               w_len;        /* pending message body size          */} SHttpConnector;/* Try to fix connection parameters (called for an unconnected connector) */static int/*bool*/ s_Adjust(SHttpConnector* uuu,                            char**          redirect,                            int/*bool*/     drop_unread){    assert(!uuu->sock && uuu->can_connect != eCC_None);    /* we're here because something is going wrong */    if (++uuu->failure_count >= uuu->net_info->max_try) {        if (*redirect) {            free(*redirect);            *redirect = 0;        }        if (!drop_unread && uuu->failure_count > 1) {            CORE_LOGF(eLOG_Error, ("[HTTP]  Too many failed attempts (%d),"                                   " giving up", uuu->failure_count));        }        uuu->can_connect = eCC_None;        return 0/*failure*/;    }    /* adjust info before yet another connection attempt */    if (*redirect) {        int status = ConnNetInfo_ParseURL(uuu->net_info, *redirect);        free(*redirect);        *redirect = 0;        if (!status) {            CORE_LOG(eLOG_Error, "[HTTP]  Unable to parse redirect");            uuu->can_connect = eCC_None;            return 0/*failure*/;        }    } else if (!uuu->adjust_net_info ||               uuu->adjust_net_info(uuu->net_info,                                    uuu->adjust_data,                                    uuu->failure_count) == 0) {        if (!drop_unread && uuu->failure_count > 1) {            CORE_LOGF(eLOG_Error, ("[HTTP]  Retry attempts (%d) exhausted,"                                   " giving up", uuu->failure_count));        }        uuu->can_connect = eCC_None;        return 0/*failure*/;    }    ConnNetInfo_AdjustForHttpProxy(uuu->net_info);    if (uuu->net_info->debug_printout)        ConnNetInfo_Log(uuu->net_info, CORE_GetLOG());    return 1/*success*/;}/* Unconditionally drop the connection; timeout may specify time allowance */static void s_DropConnection(SHttpConnector* uuu, const STimeout* timeout){    size_t http_size = BUF_Size(uuu->http);    assert(uuu->sock);    if (http_size  &&  BUF_Read(uuu->http, 0, http_size) != http_size) {        CORE_LOG(eLOG_Error, "[HTTP]  Cannot discard HTTP header buffer");        assert(0);    }    SOCK_SetTimeout(uuu->sock, eIO_Close, timeout);    SOCK_Close(uuu->sock);    uuu->sock = 0;}/* Connect to the HTTP server, specified by uuu->net_info's "port:host". * Return eIO_Success only if socket connection has succeeded and uuu->sock * is non-zero. If unsuccessful, try to adjust uuu->net_info by s_Adjust(), * and then re-try the connection attempt. */static EIO_Status s_Connect(SHttpConnector* uuu, int/*bool*/ drop_unread){    assert(!uuu->sock);    if (uuu->can_connect == eCC_None) {        CORE_LOG(eLOG_Error, "[HTTP]  Connector is no longer usable");        return eIO_Closed;    }    /* the re-try loop... */    for (;;) {        int/*bool*/ reset_user_header = 0;        char*       http_user_header = 0;        char*       null = 0;        uuu->w_len = BUF_Size(uuu->w_buf);        if (uuu->net_info->http_user_header)            http_user_header = strdup(uuu->net_info->http_user_header);        if (!uuu->net_info->http_user_header == !http_user_header) {            ConnNetInfo_ExtendUserHeader                (uuu->net_info, "User-Agent: NCBIHttpConnector"#ifdef NCBI_CXX_TOOLKIT                 " (C++ Toolkit)"#else                 " (C Toolkit)"#endif                 "\r\n");            reset_user_header = 1;        }        /* connect & send HTTP header */        uuu->sock = URL_Connect            (uuu->net_info->host,       uuu->net_info->port,             uuu->net_info->path,       uuu->net_info->args,             uuu->net_info->req_method, uuu->w_len,             uuu->o_timeout,            uuu->w_timeout,             uuu->net_info->http_user_header,             (int/*bool*/) (uuu->flags & fHCC_UrlEncodeArgs),             uuu->net_info->debug_printout == eDebugPrintout_Data             ? eOn : (uuu->net_info->debug_printout == eDebugPrintout_None                      ? eOff : eDefault));        if (reset_user_header) {            ConnNetInfo_SetUserHeader(uuu->net_info, 0);            uuu->net_info->http_user_header = http_user_header;        }        if (uuu->sock) {            if (!(uuu->flags & fHCC_NoUpread))                SOCK_SetReadOnWrite(uuu->sock, eOn);            return eIO_Success;        }        /* connection failed, no socket was created */        if (!s_Adjust(uuu, &null, drop_unread))            break;    }    return eIO_Closed;}/* Connect to the server specified by uuu->net_info, then compose and form * relevant HTTP header, and flush the accumulated output data(uuu->w_buf) * after the HTTP header. If connection/write unsuccessful, retry to reconnect * and send the data again until permitted by s_Adjust(). */static EIO_Status s_ConnectAndSend(SHttpConnector* uuu,int/*bool*/ drop_unread){    EIO_Status status;    for (;;) {        char*  null = 0;        if (!uuu->sock) {            if ((status = s_Connect(uuu, drop_unread)) != eIO_Success)                break;            assert(uuu->sock);            uuu->read_header = 1/*true*/;            uuu->shut_down = 0/*false*/;        } else            status = eIO_Success;        if (uuu->w_len) {            size_t off = BUF_Size(uuu->w_buf) - uuu->w_len;            SOCK_SetTimeout(uuu->sock, eIO_Write, uuu->w_timeout);            do {                char   buf[4096];                size_t n_written;                size_t n_write = BUF_PeekAt(uuu->w_buf, off, buf, sizeof(buf));                status = SOCK_Write(uuu->sock, buf, n_write,                                    &n_written, eIO_WritePlain);                if (status != eIO_Success)                    break;                uuu->w_len -= n_written;                off        += n_written;            } while (uuu->w_len);        } else if (!uuu->shut_down)            status = SOCK_Write(uuu->sock, 0, 0, 0, eIO_WritePlain);        if (status == eIO_Success) {            assert(uuu->w_len == 0);            if (!uuu->shut_down) {                /* 10/07/03: While this call here is perfectly legal, it could                 * cause connection severed by a buggy CISCO load-balancer. */                /* 10/28/03: CISCO's beta patch for their LB shows that the                 * problem has been fixed; no more 2'30" drops in connections                 * that shut down for write.  We still leave this commented                 * out to allow unpatched clients work seamlessly... */                 /*SOCK_Shutdown(uuu->sock, eIO_Write);*/                uuu->shut_down = 1;            }            break;        }        if (status == eIO_Timeout &&  uuu->w_timeout  &&            !uuu->w_timeout->sec  &&  !uuu->w_timeout->usec) {            break;        }        CORE_LOGF(eLOG_Error,                  ("[HTTP]  Error writing body at offset %lu (%s)",                   (unsigned long) (BUF_Size(uuu->w_buf) - uuu->w_len),                   IO_StatusStr(status)));        /* write failed; close and try to use another server */        SOCK_Abort(uuu->sock);        s_DropConnection(uuu, 0/*no wait*/);        if (!s_Adjust(uuu, &null, drop_unread)) {            status = eIO_Closed;            break;        }    }    return status;}/* Parse HTTP header */static EIO_Status s_ReadHeader(SHttpConnector* uuu, char** redirect){    int/*bool*/ moved = 0/*false*/;    int         server_error = 0;    int         http_status = 0;    char*       header;    size_t      size;    assert(uuu->sock && uuu->read_header);    *redirect = 0;    if (uuu->flags & fHCC_KeepHeader) {        uuu->read_header = 0;        return eIO_Success;    }    /* line by line HTTP header input */    for (;;) {        EIO_Status status;        /* do we have full header yet? */        size = BUF_Size(uuu->http);        if (!(header = (char*) malloc(size + 1))) {            CORE_LOGF(eLOG_Error, ("[HTTP]  Cannot allocate header, %lu bytes",                                   (unsigned long) size));            return eIO_Unknown;        }        verify(BUF_Peek(uuu->http, header, size) == size);        header[size] = '\0';        if (size >= 4  &&  strcmp(&header[size - 4], "\r\n\r\n") == 0)            break/*full header captured*/;        free(header);        status = SOCK_StripToPattern(uuu->sock, "\r\n", 2, &uuu->http, 0);        if (status != eIO_Success) {            const STimeout* tmo = SOCK_GetTimeout(uuu->sock, eIO_Read);            if (tmo && (tmo->sec || tmo->usec)) {                CORE_LOGF(eLOG_Error, ("[HTTP]  Error reading header (%s)",                                       IO_StatusStr(status)));            }            return status;        }    }    uuu->read_header = 0/*false*/; /* the entire header has been read */    if (BUF_Read(uuu->http, 0, size) != size) {        CORE_LOG(eLOG_Error, "[HTTP]  Cannot discard HTTP header buffer");        assert(0);    }    /* HTTP status must come on the first line of the reply */    if (sscanf(header, " HTTP/%*d.%*d %d ", &http_status) != 1  ||        http_status < 200  ||  299 < http_status) {        server_error = http_status;        if (http_status == 301  ||  http_status == 302)            moved = 1;        else if (http_status == 403  ||  http_status == 404)            uuu->net_info->max_try = 0;    }    if ((server_error || !uuu->error_header) &&        uuu->net_info->debug_printout == eDebugPrintout_Some) {        /* HTTP header gets printed as part of data logging when           uuu->net_info->debug_printout == eDebugPrintout_Data. */        const char* header_header;        if (!server_error)             header_header = "HTTP header";        else if (moved)            header_header = "HTTP header (moved)";        else if (!uuu->net_info->max_try)            header_header = "HTTP header (unrecoverable error)";        else            header_header = "HTTP header (server error, can retry)";        CORE_DATA(header, size, header_header);    }    if (uuu->parse_http_hdr) {        if (!(*uuu->parse_http_hdr)            (header, uuu->adjust_data, server_error))            server_error = 1;    }    if (moved) {        /* parsing "Location" pointer */        const char k_LocationTag[] = "\nLocation: ";        char*      location = strstr(header, k_LocationTag);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -