/* 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, EReadMode read_mode) { EIO_Status status; assert(!uuu->sock); if (uuu->can_connect == eCC_None) { CORE_LOG_X(5, eLOG_Error, "[HTTP] Connector 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; TSOCK_Flags flags; 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; } if (uuu->net_info->debug_printout) ConnNetInfo_Log(uuu->net_info, CORE_GetLOG()); flags = (uuu->net_info->debug_printout == eDebugPrintout_Data ? fSOCK_LogOn : fSOCK_LogDefault); if (uuu->net_info->scheme == eURL_Https) flags |= fSOCK_Secure; if (!(uuu->flags & fHCC_NoUpread)) flags |= fSOCK_ReadOnWrite; /* connect & send HTTP header */ if ((status = URL_ConnectEx (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), flags, &uuu->sock)) != eIO_Success) { uuu->sock = 0; } if (reset_user_header) { ConnNetInfo_SetUserHeader(uuu->net_info, 0); uuu->net_info->http_user_header = http_user_header; } if (uuu->sock) break/*success*/; /* connection failed, no socket was created */ if (!s_Adjust(uuu, &null, read_mode)) break/*closed*/; } return status; }
static CConn_IOStream::TConn_Pair s_SocketConnectorBuilder(const SConnNetInfo* net_info, const STimeout* timeout, const void* data, size_t size, TSOCK_Flags flags) { EIO_Status status = eIO_Success; bool proxy = false; SOCK sock = 0; _ASSERT(net_info); if ((flags & (fSOCK_LogOn | fSOCK_LogDefault)) == fSOCK_LogDefault && net_info->debug_printout == eDebugPrintout_Data) { flags &= ~fSOCK_LogDefault; flags |= fSOCK_LogOn; } if (*net_info->http_proxy_host && net_info->http_proxy_port) { status = HTTP_CreateTunnel(net_info, fHTTP_NoAutoRetry, &sock); _ASSERT(!sock ^ !(status != eIO_Success)); if (status == eIO_Success && ((flags & ~(fSOCK_LogOn | fSOCK_LogDefault)) || size)) { SOCK s; status = SOCK_CreateOnTopEx(sock, 0, &s, data, size, flags); _ASSERT(!s ^ !(status != eIO_Success)); SOCK_Destroy(sock); sock = s; } proxy = true; } if (!sock && (!proxy || net_info->http_proxy_leak)) { const char* host = (net_info->firewall && *net_info->proxy_host ? net_info->proxy_host : net_info->host); if (timeout == kDefaultTimeout) timeout = net_info->timeout; if (!proxy && net_info->debug_printout) { SConnNetInfo* x_net_info = ConnNetInfo_Clone(net_info); if (x_net_info) { x_net_info->req_method = eReqMethod_Any; x_net_info->stateless = 0; x_net_info->lb_disable = 0; x_net_info->http_proxy_host[0] = '\0'; x_net_info->http_proxy_port = 0; x_net_info->http_proxy_user[0] = '\0'; x_net_info->http_proxy_pass[0] = '\0'; x_net_info->proxy_host[0] = '\0'; ConnNetInfo_SetUserHeader(x_net_info, 0); if (x_net_info->http_referer) { free((void*) x_net_info->http_referer); x_net_info->http_referer = 0; } x_net_info->timeout = timeout; } ConnNetInfo_Log(x_net_info, eLOG_Note, CORE_GetLOG()); ConnNetInfo_Destroy(x_net_info); } status = SOCK_CreateEx(host, net_info->port, timeout, &sock, data, size, flags); _ASSERT(!sock ^ !(status != eIO_Success)); } string hostport(net_info->host); hostport += ':'; hostport += NStr::UIntToString(net_info->port); CONNECTOR c = SOCK_CreateConnectorOnTopEx(sock, 1/*own*/, hostport.c_str()); if (!c) { SOCK_Abort(sock); SOCK_Close(sock); status = eIO_Unknown; } return CConn_IOStream::TConn_Pair(c, status); }
int main(int argc, const char* argv[]) { const char* service = argc > 1 && *argv[1] ? argv[1] : "bounce"; static char obuf[8192 + 2]; SConnNetInfo* net_info; CONNECTOR connector; EIO_Status status; char ibuf[1024]; CONN conn; size_t n; setlocale(LC_ALL, ""); g_NCBI_ConnectRandomSeed = (int) time(0) ^ NCBI_CONNECT_SRAND_ADDEND; srand(g_NCBI_ConnectRandomSeed); CORE_SetLOGFormatFlags(fLOG_None | fLOG_Level | fLOG_OmitNoteLevel | fLOG_DateTime); CORE_SetLOGFILE(stderr, 0/*false*/); net_info = ConnNetInfo_Create(service); ConnNetInfo_AppendArg(net_info, "testarg", "val"); ConnNetInfo_AppendArg(net_info, "service", "none"); ConnNetInfo_AppendArg(net_info, "platform", "none"); ConnNetInfo_AppendArg(net_info, "address", "2010"); ConnNetInfo_Log(net_info, eLOG_Note, CORE_GetLOG()); connector = SERVICE_CreateConnectorEx(service, fSERV_Any, net_info, 0); if (!connector) CORE_LOG(eLOG_Fatal, "Failed to create service connector"); if (CONN_Create(connector, &conn) != eIO_Success) CORE_LOG(eLOG_Fatal, "Failed to create connection"); if (argc > 2) { strncpy0(obuf, argv[2], sizeof(obuf) - 2); obuf[n = strlen(obuf)] = '\n'; obuf[++n] = '\0'; if (CONN_Write(conn, obuf, strlen(obuf), &n, eIO_WritePersist) != eIO_Success) { CONN_Close(conn); CORE_LOG(eLOG_Fatal, "Cannot write to connection"); } assert(n == strlen(obuf)); } else { for (n = 0; n < 10; n++) { size_t m; for (m = 0; m < sizeof(obuf) - 2; m++) obuf[m] = "0123456789\n"[rand() % 11]; obuf[m++] = '\n'; obuf[m] = '\0'; if (CONN_Write(conn, obuf, strlen(obuf), &m, eIO_WritePersist) != eIO_Success) { if (!n) { CONN_Close(conn); CORE_LOG(eLOG_Fatal, "Cannot write to connection"); } else break; } assert(m == strlen(obuf)); } } for (;;) { if (CONN_Wait(conn, eIO_Read, net_info->timeout) != eIO_Success) { CONN_Close(conn); CORE_LOG(eLOG_Fatal, "Failed to wait for reading"); } status = CONN_Read(conn, ibuf, sizeof(ibuf), &n, eIO_ReadPersist); if (n) { char* descr = CONN_Description(conn); CORE_DATAF(eLOG_Note, ibuf, n, ("%lu bytes read from service (%s%s%s):", (unsigned long) n, CONN_GetType(conn), descr ? ", " : "", descr ? descr : "")); if (descr) free(descr); } if (status != eIO_Success) { if (status != eIO_Closed) CORE_LOGF(n ? eLOG_Error : eLOG_Fatal, ("Read error: %s", IO_StatusStr(status))); break; } } ConnNetInfo_Destroy(net_info); CONN_Close(conn); #if 0 CORE_LOG(eLOG_Note, "Trying ID1 service"); net_info = ConnNetInfo_Create(service); connector = SERVICE_CreateConnectorEx("ID1", fSERV_Any, net_info); ConnNetInfo_Destroy(net_info); if (!connector) CORE_LOG(eLOG_Fatal, "Service ID1 not available"); if (CONN_Create(connector, &conn) != eIO_Success) CORE_LOG(eLOG_Fatal, "Failed to create connection"); if (CONN_Write(conn, "\xA4\x80\x02\x01\x02\x00", 7, &n, eIO_WritePersist) != eIO_Success) { CONN_Close(conn); CORE_LOG(eLOG_Fatal, "Cannot write to service ID1"); } assert(n == 7); if (CONN_Read(conn, ibuf, sizeof(ibuf), &n, eIO_ReadPlain) != eIO_Success){ CONN_Close(conn); CORE_LOG(eLOG_Fatal, "Cannot read from service ID1"); } CORE_LOGF(eLOG_Note, ("%d bytes read from service ID1", n)); CONN_Close(conn); #endif CORE_LOG(eLOG_Note, "TEST completed successfully"); CORE_SetLOG(0); return 0/*okay*/; }
extern NCBI_XCONNECT_EXPORT // FIXME: To remove once the API is fully official CConn_IOStream* NcbiOpenURL(const string& url, size_t buf_size) { { class CInPlaceConnIniter : protected CConnIniter { } conn_initer; } bool svc = x_IsIdentifier(url); AutoPtr<SConnNetInfo> net_info = ConnNetInfo_Create(svc ? url.c_str() : 0); if (svc) return new CConn_ServiceStream(url, fSERV_Any, net_info.get()); unsigned int host; unsigned short port; if (url.size() == CSocketAPI::StringToHostPort(url, &host, &port) && port && net_info.get()) { net_info->req_method = eReqMethod_Connect; } if (ConnNetInfo_ParseURL(net_info.get(), url.c_str())) { _ASSERT(net_info); // otherwise ConnNetInfo_ParseURL() would fail if (net_info->req_method == eReqMethod_Connect) { return new CConn_SocketStream(*net_info, 0, 0, fSOCK_LogDefault, net_info->timeout, buf_size); } switch (net_info->scheme) { case eURL_Https: case eURL_Http: return new CConn_HttpStream(net_info.get(), kEmptyStr, 0, 0, 0, 0, fHTTP_AutoReconnect, kDefaultTimeout, buf_size); case eURL_File: if (*net_info->host || net_info->port) break; /*not supported*/ _ASSERT(!*net_info->args); if (net_info->debug_printout) { net_info->req_method = eReqMethod_Any; net_info->firewall = 0; net_info->stateless = 0; net_info->lb_disable = 0; net_info->http_proxy_leak = 0; net_info->http_proxy_host[0] = '\0'; net_info->http_proxy_port = 0; net_info->http_proxy_user[0] = '\0'; net_info->http_proxy_pass[0] = '\0'; net_info->proxy_host[0] = '\0'; net_info->max_try = 0; net_info->timeout = kInfiniteTimeout; ConnNetInfo_SetUserHeader(net_info.get(), 0); if (net_info->http_referer) { free((void*) net_info->http_referer); net_info->http_referer = 0; } ConnNetInfo_Log(net_info.get(), eLOG_Note, CORE_GetLOG()); } return new CConn_FileStream(net_info->path); case eURL_Ftp: if (!net_info->user[0]) { strcpy(net_info->user, "ftp"); if (!net_info->pass[0]) strcpy(net_info->pass, "-none@"); } return new CConn_FTPDownloadStream(*net_info, 0, 0, 0, net_info->timeout, buf_size); default: break; } } return 0; }
static void TEST_ConnNetInfo(void) { size_t n; char* str; char buf[80]; SConnNetInfo* net_info; CORE_LOG(eLOG_Note, "ConnNetInfo test started"); net_info = ConnNetInfo_Create(0); assert(net_info); assert(ConnNetInfo_ParseURL(net_info, "ftp://*****:*****@host:8888/ro.t/p@th" "?arg/arg:arg@arg:arg/arg")); assert(net_info->scheme == eURL_Ftp); assert(strcmp(net_info->user, "user") == 0); assert(strcmp(net_info->pass, "pass") == 0); assert(strcmp(net_info->host, "host") == 0); assert( net_info->port == 8888); assert(strcmp(net_info->path, "/ro.t/p@th") == 0); assert(strcmp(net_info->args, "arg/arg:arg@arg:arg/arg") == 0); assert(ConnNetInfo_ParseURL(net_info, "https://www/path" "?arg:arg@arg#frag")); assert( net_info->scheme == eURL_Https); assert( *net_info->user == 0); assert( *net_info->pass == 0); assert(strcmp(net_info->host, "www") == 0); assert( net_info->port == 0); assert(strcmp(net_info->path, "/path") == 0); assert(strcmp(net_info->args, "arg:arg@arg#frag") == 0); assert(ConnNetInfo_ParseURL(net_info, "/path1?arg1#frag2")); assert(strcmp(net_info->args, "arg1#frag2") == 0); assert(ConnNetInfo_ParseURL(net_info, "path0/0")); assert(strcmp(net_info->path, "/path0/0") == 0); assert(strcmp(net_info->args, "#frag2") == 0); assert(ConnNetInfo_ParseURL(net_info, "#frag3")); assert(strcmp(net_info->path, "/path0/0") == 0); assert(strcmp(net_info->args, "#frag3") == 0); assert(ConnNetInfo_ParseURL(net_info, "path2")); assert(strcmp(net_info->path, "/path0/path2") == 0); assert(strcmp(net_info->args, "#frag3") == 0); assert(ConnNetInfo_ParseURL(net_info, "/path3?arg3")); assert(strcmp(net_info->path, "/path3") == 0); assert(strcmp(net_info->args, "arg3#frag3") == 0); strcpy(net_info->user, "user"); strcpy(net_info->pass, "pass"); str = ConnNetInfo_URL(net_info); assert(str); assert(strcmp(str, "https://www/path3?arg3#frag3") == 0); free(str); assert(ConnNetInfo_ParseURL(net_info, "path4/path5?arg4#")); assert(strcmp(net_info->user, "user") == 0); assert(strcmp(net_info->pass, "pass") == 0); assert(strcmp(net_info->path, "/path4/path5") == 0); assert(strcmp(net_info->args, "arg4") == 0); assert(ConnNetInfo_ParseURL(net_info, "../path6")); assert(strcmp(net_info->path, "/path4/../path6") == 0); assert(strcmp(net_info->args, "") == 0); ConnNetInfo_SetUserHeader(net_info, ""); str = UTIL_PrintableString(net_info->http_user_header, 0, buf, 0); printf("HTTP User Header after set:\n%s%s%s\n", "\"" + !str, str ? buf : "NULL", "\"" + !str); assert(!net_info->http_user_header && !str); ConnNetInfo_AppendUserHeader(net_info, "T0: V0\n" "T1:V1\r\n" "T2: V2\r\n" "T3: V3\n" "T4: V4\n" "T1: V6"); str = UTIL_PrintableString(net_info->http_user_header, 0, buf, 0); if (str) *str = '\0'; printf("HTTP User Header after append:\n%s%s%s\n", "\"" + !str, str ? buf : "NULL", "\"" + !str); assert(strcmp(net_info->http_user_header, "T0: V0\n" "T1:V1\r\n" "T2: V2\r\n" "T3: V3\n" "T4: V4\n" "T1: V6\r\n") == 0); ConnNetInfo_OverrideUserHeader(net_info, "T0\r\n" "T5: V5\n" "T1: \t \r\n" "T2:V2.1\r\n" "T3:V3\r\n" "T4: W4"); str = UTIL_PrintableString(net_info->http_user_header, 0, buf, 0); if (str) *str = '\0'; printf("HTTP User Header after override:\n%s%s%s\n", "\"" + !str, str ? buf : "NULL", "\"" + !str); assert(strcmp(net_info->http_user_header, "T0: V0\n" "T2:V2.1\r\n" "T3:V3\n" "T4: W4\r\n" "T5: V5\r\n") == 0); ConnNetInfo_ExtendUserHeader(net_info, "T0: V0\n" "T1:V1\r\n" "T2:V2\n" "T3: T3:V3\n" "T4:\n" "T5"); str = UTIL_PrintableString(net_info->http_user_header, 0, buf, 0); if (str) *str = '\0'; printf("HTTP User Header after extend:\n%s%s%s\n", "\"" + !str, str ? buf : "NULL", "\"" + !str); assert(strcmp(net_info->http_user_header, "T0: V0\n" "T2:V2.1 V2\r\n" "T3:V3 T3:V3\n" "T4: W4\r\n" "T5: V5\r\n" "T1:V1\r\n") == 0); ConnNetInfo_SetUserHeader(net_info, 0); str = UTIL_PrintableString(net_info->http_user_header, 0, buf, 0); if (str) *str = '\0'; printf("HTTP User Header after reset:\n%s%s%s\n", "\"" + !str, str ? buf : "NULL", "\"" + !str); assert(!net_info->http_user_header); for (n = 0; n < sizeof(net_info->args); n++) net_info->args[n] = "0123456789"[rand() % 10]; strncpy0(net_info->args, "a=b&b=c&c=d", sizeof(net_info->args) - 1); printf("HTTP Arg: \"%s\"\n", net_info->args); ConnNetInfo_PrependArg(net_info, "d=e", 0); ConnNetInfo_PrependArg(net_info, "e", "f"); printf("HTTP Arg after prepend: \"%s\"\n", net_info->args); ConnNetInfo_AppendArg(net_info, "f=g", 0); ConnNetInfo_AppendArg(net_info, "g", "h"); printf("HTTP Arg after append: \"%s\"\n", net_info->args); ConnNetInfo_PreOverrideArg(net_info, "a=z&b", "y"); ConnNetInfo_PreOverrideArg(net_info, "c", "x"); printf("HTTP Arg after pre-override: \"%s\"\n", net_info->args); ConnNetInfo_PostOverrideArg(net_info, "d=w&e", "v"); ConnNetInfo_PostOverrideArg(net_info, "f", "u"); printf("HTTP Arg after post-override: \"%s\"\n", net_info->args); ConnNetInfo_DeleteArg(net_info, "g"); ConnNetInfo_DeleteArg(net_info, "h=n"); printf("HTTP Arg after delete: \"%s\"\n", net_info->args); ConnNetInfo_DeleteAllArgs(net_info, "a=b&p=q&f=d"); printf("HTTP Arg after delete-all: \"%s\"\n", net_info->args); ConnNetInfo_LogEx(net_info, eLOG_Note, CORE_GetLOG()); ConnNetInfo_Destroy(net_info); CORE_LOG(eLOG_Note, "ConnNetInfo test completed"); }