📄 ncbi_http_connector.c
字号:
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 + -