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

📄 ncbi_http_connector.c

📁 ncbi源码
💻 C
📖 第 1 页 / 共 3 页
字号:
        if (location) {            char* s;            location += sizeof(k_LocationTag) - 1;            if (!(s = strchr(location, '\r')))                *strchr(location, '\n') = 0;            else                *s = 0;            while (*location) {                if (isspace((unsigned char)(*location)))                    location++;                else                    break;            }            for (s = location; *s; s++)                if (isspace((unsigned char)(*s)))                    break;            *s = 0;            if (*location)                *redirect = strdup(location);        }    }    if (header)        free(header);    /* skip & printout the content, if server error was flagged */    if (server_error && uuu->net_info->debug_printout == eDebugPrintout_Some) {        BUF        buf = 0;        EIO_Status status;        char*      body;        SOCK_SetTimeout(uuu->sock, eIO_Read, 0);        status = SOCK_StripToPattern(uuu->sock, 0, 0, &buf, 0);        assert(status != eIO_Success); /* because reading until EOF */        if (!(size = BUF_Size(buf))) {            CORE_LOG(eLOG_Trace, "[HTTP]  No body received with this error");        } else if ((body = (char*) malloc(size)) != 0) {            size_t n = BUF_Read(buf, body, size);            if (n != size) {                CORE_LOGF(eLOG_Error, ("[HTTP]  Cannot read server error "                                       "body from buffer (%lu out of %lu)",                                       (unsigned long) n,                                       (unsigned long) size));            }            CORE_DATA(body, n, "HTTP server error body");            free(body);        } else {            CORE_LOGF(eLOG_Error, ("[HTTP]  Cannot allocate server error "                                   "body, %lu bytes", (unsigned long) size));        }        BUF_Destroy(buf);    }    return server_error ? eIO_Unknown : eIO_Success;}/* Prepare connector for reading. Open socket if necessary and * make initial connect and send, re-trying if possible until success. * Return codes: *   eIO_Success = success, connector is ready for reading (uuu->sock != NULL); *   eIO_Timeout = maybe (check uuu->sock) connected and no data yet available; *   other code  = error, not connected (uuu->sock == NULL). */static EIO_Status s_PreRead(SHttpConnector* uuu,                            const STimeout* timeout,                            int/*bool*/     drop_unread){    char* redirect = 0;    EIO_Status status;    for (;;) {        status = s_ConnectAndSend(uuu, drop_unread);        if (!uuu->sock) {            assert(status != eIO_Success);            break;        }        if (status != eIO_Success) {            if (status != eIO_Timeout ||                status == SOCK_Status(uuu->sock, eIO_Read)/*pending*/)                break;        }        /* set timeout */        SOCK_SetTimeout(uuu->sock, eIO_Read, timeout);        if (!uuu->read_header)            break;        if ((status = s_ReadHeader(uuu, &redirect)) == eIO_Success) {            size_t w_size = BUF_Size(uuu->w_buf);            assert(!uuu->read_header);            /* pending output data no longer needed */            if (BUF_Read(uuu->w_buf, 0, w_size) != w_size) {                CORE_LOG(eLOG_Error, "[HTTP]  Cannot discard output buffer");                assert(0);            }            break;        }        /* if polling then bail out with eIO_Timeout */        if(status == eIO_Timeout && timeout && !timeout->sec && !timeout->usec)            break;        /* HTTP header read error; disconnect and try to use another server */        SOCK_Abort(uuu->sock);        s_DropConnection(uuu, 0/*no wait*/);        if (!s_Adjust(uuu, &redirect, drop_unread))            break;        assert(redirect == 0);    }    assert(redirect == 0);    return status;}/* Read non-header data from connection */static EIO_Status s_Read(SHttpConnector* uuu, void* buf,                         size_t size, size_t* n_read){    assert(uuu->sock);    /* just read, with no URL-decoding */    if (!(uuu->flags & fHCC_UrlDecodeInput))        return SOCK_Read(uuu->sock, buf, size, n_read, eIO_ReadPlain);    /* read and URL-decode */    {{        EIO_Status status;        size_t     n_peeked, n_decoded;        size_t     peek_size = 3 * size;        void*      peek_buf  = malloc(peek_size);        /* peek the data */        status= SOCK_Read(uuu->sock,peek_buf,peek_size,&n_peeked,eIO_ReadPeek);        if (status != eIO_Success) {            *n_read = 0;            free(peek_buf);            return status;        }        /* decode, then discard the successfully decoded data from the input */        if (URL_Decode(peek_buf, n_peeked, &n_decoded, buf, size, n_read)) {            if (n_decoded) {                size_t x_read;                SOCK_Read(uuu->sock,peek_buf,n_decoded,&x_read,eIO_ReadPlain);                assert(x_read == n_decoded);                status = eIO_Success;            } else if (SOCK_Status(uuu->sock, eIO_Read) == eIO_Closed)                /* we are at EOF, and the remaining data cannot be decoded */                status = eIO_Unknown;        } else            status = eIO_Unknown;        if (status != eIO_Success)            CORE_LOG(eLOG_Error, "[HTTP]  Cannot URL-decode data");        free(peek_buf);        return status;    }}}/* Reset/readout input data and close socket */static EIO_Status s_Disconnect(SHttpConnector* uuu,                               int/*bool*/     drop_unread,                               const STimeout* timeout){    EIO_Status status = eIO_Success;    if (drop_unread) {        size_t r_size = BUF_Size(uuu->r_buf);        if (r_size  &&  BUF_Read(uuu->r_buf, 0, r_size) != r_size) {            CORE_LOG(eLOG_Error, "[HTTP]  Cannot drop input buffer");            assert(0);        }    } else if ((status = s_PreRead(uuu, timeout, 0/*nodrop*/)) == eIO_Success){        do {            char     buf[4096];            size_t   x_read;            status = s_Read(uuu, buf, sizeof(buf), &x_read);            if (!BUF_Write(&uuu->r_buf, buf, x_read))                status = eIO_Unknown;        } while (status == eIO_Success);        if (status == eIO_Closed)            status = eIO_Success;    }    if (uuu->sock) /* s_PreRead() might have dropped the connection already */        s_DropConnection(uuu, timeout);    if (uuu->can_connect == eCC_Once)        uuu->can_connect = eCC_None;    return status;}/* Send the accumulated output data(if any) to server, then close socket. * Regardless of the flush, clear both input and output buffer. * This function is only called to either re-open or close the connector. */static void s_FlushAndDisconnect(SHttpConnector* uuu,                                 const STimeout* timeout,                                 int/*bool*/     close){    size_t w_size = BUF_Size(uuu->w_buf);    /* store timeouts for later use */    if (timeout) {        uuu->oo_timeout = *timeout;        uuu->o_timeout  = &uuu->oo_timeout;        uuu->ww_timeout = *timeout;        uuu->w_timeout  = &uuu->ww_timeout;    } else {        uuu->o_timeout  = timeout;        uuu->w_timeout  = timeout;    }    if (close  &&  uuu->can_connect != eCC_None  &&  !uuu->sock  &&        ((uuu->flags & fHCC_SureFlush)  ||  BUF_Size(uuu->w_buf))) {        /* "WRITE" mode and data (or just flag) pending */        s_PreRead(uuu, timeout, 1/*drop_unread*/);    }    s_Disconnect(uuu, 1/*drop_unread*/, timeout);    assert(!uuu->sock);    /* clear pending output data, if any */    if (w_size  &&  BUF_Read(uuu->w_buf, 0, w_size) != w_size) {        CORE_LOG(eLOG_Error, "[HTTP]  Cannot drop output buffer");        assert(0);    }}/*********************************************************************** *  INTERNAL -- "s_VT_*" functions for the "virt. table" of connector methods ***********************************************************************/#ifdef __cplusplusextern "C" {#endif /* __cplusplus */    static const char* s_VT_GetType (CONNECTOR       connector);    static char*       s_VT_Descr   (CONNECTOR       connector);    static EIO_Status  s_VT_Open    (CONNECTOR       connector,                                     const STimeout* timeout);    static EIO_Status  s_VT_Wait    (CONNECTOR       connector,                                     EIO_Event       event,                                     const STimeout* timeout);    static EIO_Status  s_VT_Write   (CONNECTOR       connector,                                     const void*     buf,                                     size_t          size,                                     size_t*         n_written,                                     const STimeout* timeout);    static EIO_Status  s_VT_Flush   (CONNECTOR       connector,                                     const STimeout* timeout);    static EIO_Status  s_VT_Read    (CONNECTOR       connector,                                     void*           buf,                                     size_t          size,                                     size_t*         n_read,                                     const STimeout* timeout);    static EIO_Status  s_VT_Status  (CONNECTOR       connector,                                     EIO_Event       dir);    static EIO_Status  s_VT_Close   (CONNECTOR       connector,                                     const STimeout* timeout);    static void        s_Setup      (SMetaConnector *meta,                                     CONNECTOR connector);    static void        s_Destroy    (CONNECTOR connector);#  ifdef IMPLEMENTED__CONN_WaitAsync    static EIO_Status s_VT_WaitAsync(CONNECTOR     connector,                                     FConnectorAsyncHandler  func,                                     SConnectorAsyncHandler* data);#  endif#ifdef __cplusplus} /* extern "C" */#endif /* __cplusplus *//*ARGSUSED*/static const char* s_VT_GetType(CONNECTOR connector){    return "HTTP";}static char* s_VT_Descr(CONNECTOR connector){    SHttpConnector* uuu = (SHttpConnector*) connector->handle;    size_t len = 7/*"http://"*/ + strlen(uuu->net_info->host) +        (uuu->net_info->port == 80 ? 0 : 6/*:port*/) +        strlen(uuu->net_info->path) +        (*uuu->net_info->args ? 2 + strlen(uuu->net_info->args) : 1);    char* buf = (char*) malloc(len);    if (buf) {        len = sprintf(buf, "http://%s", uuu->net_info->host);        if (uuu->net_info->port != 80)            len += sprintf(&buf[len], ":%hu", uuu->net_info->port);        sprintf(&buf[len], "%s%s%s", uuu->net_info->path,                *uuu->net_info->args ? "&" : "", uuu->net_info->args);    }    return buf;}static EIO_Status s_VT_Open(CONNECTOR       connector, const STimeout* timeout){    SHttpConnector* uuu = (SHttpConnector*) connector->handle;    /* NOTE: the real connect will be performed on the first "READ", or     * "CLOSE", or on "WAIT" on read -- see in "s_ConnectAndSend()";     * we just close underlying socket and prepare to open it later */    s_FlushAndDisconnect(uuu, timeout, 0/*open*/);    /* reset the auto-reconnect feature */    uuu->can_connect = uuu->flags & fHCC_AutoReconnect        ? eCC_Unlimited : eCC_Once;    uuu->failure_count = 0;    return eIO_Success;}static EIO_Status s_VT_Wait(CONNECTOR       connector, EIO_Event       event, const STimeout* timeout){    SHttpConnector* uuu = (SHttpConnector*) connector->handle;    switch (event) {    case eIO_Read:        if (uuu->can_connect == eCC_None)            return eIO_Closed;        if (!uuu->sock || uuu->read_header) {            EIO_Status status = s_PreRead(uuu, timeout, 0/*no drop unread*/);            if (status != eIO_Success || BUF_Size(uuu->r_buf))                return status;            assert(uuu->sock);        }        return SOCK_Wait(uuu->sock, eIO_Read, timeout);    case eIO_Write:        /* Return 'Closed' if no more writes are allowed (and now - reading) */        return uuu->can_connect == eCC_None ||            (uuu->sock && uuu->can_connect == eCC_Once)            ? eIO_Closed : eIO_Success;    default:        assert(0);        return eIO_InvalidArg;    }}static EIO_Status s_VT_Write(CONNECTOR       connector, const void*     buf, size_t          size, size_t*         n_written, const STimeout* timeout){    SHttpConnector* uuu = (SHttpConnector*) connector->handle;    /* if trying to "WRITE" after "READ" then close the socket,     * and so switch to "WRITE" mode */    if (uuu->sock) {        EIO_Status status = s_Disconnect(uuu,                                         uuu->flags & fHCC_DropUnread,                                         timeout);        if (status != eIO_Success)            return status;    }    if (uuu->can_connect == eCC_None)        return eIO_Closed; /* no more connects permitted */    /* accumulate all output in the memory buffer */    if (uuu->flags & fHCC_UrlEncodeOutput) {        /* with URL-encoding */        size_t dst_size = 3 * size;        void* dst = malloc(dst_size);        size_t dst_written;        URL_Encode(buf, size, n_written, dst, dst_size, &dst_written);        assert(*n_written == size);        if (!BUF_Write(&uuu->w_buf, dst, dst_written)) {            free(dst);            return eIO_Unknown;        }        free(dst);    } else {        /* "as is" (without URL-encoding) */        if (!BUF_Write(&uuu->w_buf, buf, size))            return eIO_Unknown;        *n_written = size;    }

⌨️ 快捷键说明

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