static void s_Resolve(SERV_ITER iter) { struct SDISPD_Data* data = (struct SDISPD_Data*) iter->data; SConnNetInfo* net_info = data->net_info; EIO_Status status = eIO_Success; CONNECTOR c = 0; CONN conn; char* s; assert(!(data->eof | data->fail)); assert(!!net_info->stateless == !!iter->stateless); /* Obtain additional header information */ if ((!(s = SERV_Print(iter, 0, 0)) || ConnNetInfo_OverrideUserHeader(net_info, s)) && ConnNetInfo_OverrideUserHeader(net_info, iter->ok_down && iter->ok_suppressed ? "Dispatch-Mode: PROMISCUOUS\r\n" : iter->ok_down ? "Dispatch-Mode: OK_DOWN\r\n" : iter->ok_suppressed ? "Dispatch-Mode: OK_SUPPRESSED\r\n" : "Dispatch-Mode: INFORMATION_ONLY\r\n") && ConnNetInfo_OverrideUserHeader(net_info, iter->reverse_dns ? "Client-Mode: REVERSE_DNS\r\n" : !net_info->stateless ? "Client-Mode: STATEFUL_CAPABLE\r\n" : "Client-Mode: STATELESS_ONLY\r\n")) { c = HTTP_CreateConnectorEx(net_info, fHTTP_Flushable, s_ParseHeader, iter/*data*/, s_Adjust, 0/*cleanup*/); } if (s) { ConnNetInfo_DeleteUserHeader(net_info, s); free(s); } if (c && (status = CONN_Create(c, &conn)) == eIO_Success) { /* Send all the HTTP data... */ CONN_Flush(conn); /* ...then trigger the header callback */ CONN_Close(conn); } else { CORE_LOGF_X(5, eLOG_Error, ("%s%s%sUnable to create auxiliary HTTP %s: %s", &"["[!*iter->name], iter->name, *iter->name ? "] " : "", c ? "connection" : "connector", IO_StatusStr(c ? status : eIO_Unknown))); if (c && c->destroy) c->destroy(c); assert(0); } }
static CConn_IOStream::TConn_Pair s_ServiceConnectorBuilder(const char* service, TSERV_Type types, const SConnNetInfo* net_info, const char* user_header, const SSERVICE_Extra* params, const STimeout* timeout) { AutoPtr<SConnNetInfo> x_net_info(net_info ? ConnNetInfo_Clone(net_info) : ConnNetInfo_Create(service)); if (!x_net_info.get()) { NCBI_THROW(CIO_Exception, eUnknown, "CConn_ServiceStream::CConn_ServiceStream(): " " Out of memory"); } if (user_header && *user_header) ConnNetInfo_OverrideUserHeader(x_net_info.get(), user_header); x_SetupUserAgent(x_net_info.get()); if (timeout != kDefaultTimeout) x_net_info->timeout = timeout; CONNECTOR c = SERVICE_CreateConnectorEx(service, types, x_net_info.get(), params); return CConn_IOStream::TConn_Pair(c, eIO_Unknown); }
/* Set HTTP user header */ static void x_SetupUserHeader ( SConnNetInfo* net_info, const char* appName, EMIME_Type type, EMIME_SubType subtype, EMIME_Encoding encoding ) { const char* userAgentName = NULL; char user_header [MAX_CONTENT_TYPE_LEN + 80]; /* content-type if specified */ if (type < eMIME_T_Unknown) { VERIFY( MIME_ComposeContentTypeEx (type, subtype, encoding, user_header, MAX_CONTENT_TYPE_LEN) ); ConnNetInfo_OverrideUserHeader (net_info, user_header); } /* allow the user to specify a prog. name, otherwise get it from elsewhere */ if (StringHasNoText (appName)) { const char* progName = GetProgramName(); if (StringHasNoText (progName)) { char path [PATH_MAX]; Nlm_ProgramPath (path, sizeof (path)); userAgentName = StringRChr (path, DIRDELIMCHR); if (userAgentName) ++userAgentName; } else userAgentName = progName; } else userAgentName = appName; if (StringDoesHaveText (userAgentName)) { sprintf (user_header, "User-Agent: %.80s\r\n", userAgentName); ConnNetInfo_ExtendUserHeader (net_info, user_header); } }
static CONNECTOR s_CreateConnector (const SConnNetInfo* net_info, const char* user_header, THCC_Flags flags, FHttpParseHTTPHeader parse_http_hdr, FHttpAdjustNetInfo adjust_net_info, void* adjust_data, FHttpAdjustCleanup adjust_cleanup) { char value[32]; CONNECTOR ccc; SHttpConnector* uuu; SConnNetInfo* xxx; xxx = net_info ? ConnNetInfo_Clone(net_info) : ConnNetInfo_Create(0); if (!xxx) return 0; if ((xxx->scheme != eURL_Unspec && xxx->scheme != eURL_Https && xxx->scheme != eURL_Http) || !ConnNetInfo_AdjustForHttpProxy(xxx)) { ConnNetInfo_Destroy(xxx); return 0; } if (!(ccc = (SConnector *) malloc(sizeof(SConnector ))) || !(uuu = (SHttpConnector*) malloc(sizeof(SHttpConnector)))) { if (ccc) free(ccc); ConnNetInfo_Destroy(xxx); return 0; } if (user_header) ConnNetInfo_OverrideUserHeader(xxx, user_header); s_AddReferer(xxx); ConnNetInfo_GetValue(0, "HTTP_INSECURE_REDIRECT", value, sizeof(value),""); if (*value && (strcmp (value, "1") == 0 || strcasecmp(value, "true") == 0 || strcasecmp(value, "yes") == 0 || strcasecmp(value, "on") == 0)) { flags |= fHCC_InsecureRedirect; } /* initialize internal data structure */ uuu->net_info = xxx; uuu->parse_http_hdr = parse_http_hdr; uuu->adjust_net_info = adjust_net_info; uuu->adjust_cleanup = adjust_cleanup; uuu->adjust_data = adjust_data; uuu->flags = flags; uuu->reserved = 0; uuu->can_connect = eCC_Once; /* will be properly set at open*/ ConnNetInfo_GetValue(0, "HTTP_ERROR_HEADER_ONLY", value, sizeof(value),""); uuu->error_header = (*value && (strcmp (value, "1") == 0 || strcasecmp(value, "true") == 0 || strcasecmp(value, "yes") == 0 || strcasecmp(value, "on") == 0)); uuu->sock = 0; uuu->o_timeout = kDefaultTimeout; /* deliberately bad values -- */ uuu->w_timeout = kDefaultTimeout; /* must be reset prior to use */ uuu->http = 0; uuu->r_buf = 0; uuu->w_buf = 0; /* there are some unintialized fields left -- they are initted later */ /* initialize connector structure */ ccc->handle = uuu; ccc->next = 0; ccc->meta = 0; ccc->setup = s_Setup; ccc->destroy = s_Destroy; return ccc; }
EIO_Status CConnTest::GetFWConnections(string* reason) { SConnNetInfo* net_info = ConnNetInfo_Create(0, m_DebugPrintout); if (net_info) { const char* user_header; net_info->req_method = eReqMethod_Post; if (net_info->firewall) { user_header = "NCBI-RELAY: FALSE"; m_Firewall = true; } else user_header = "NCBI-RELAY: TRUE"; if (net_info->stateless) m_Stateless = true; ConnNetInfo_OverrideUserHeader(net_info, user_header); ConnNetInfo_SetupStandardArgs(net_info, 0/*w/o service*/); } string temp(m_Firewall ? "FIREWALL" : "RELAY (legacy)"); temp += " connection mode has been detected for stateful services\n"; if (m_Firewall) { temp += "This mode requires your firewall to be configured in such a" " way that it allows outbound connections to the port range [" STRINGIFY(CONN_FWD_PORT_MIN) ".." STRINGIFY(CONN_FWD_PORT_MAX) "] (inclusive) at the two fixed NCBI addresses, " NCBI_FWD_BEMD " and " NCBI_FWD_STVA ".\n" "To set that up correctly, please have your network administrator" " read the following (if they have not already done so):" " " NCBI_FWDOC_URL "\n"; } else { temp += "This is an obsolescent mode that requires keeping a wide port" " range [4444..4544] (inclusive) open to let through connections" " to the entire NCBI site (130.14.xxx.xxx/165.112.xxx.xxx) -- this" " mode was designed for unrestricted networks when firewall port" " blocking had not been an issue\n"; } if (m_Firewall) { _ASSERT(net_info); switch (net_info->firewall) { case eFWMode_Adaptive: temp += "Also, there are usually a few additional ports such as " STRINGIFY(CONN_PORT_SSH) " and " STRINGIFY(CONN_PORT_HTTPS) " at " NCBI_FWD_BEMD ", which can be used if connections to" " the ports in the range described above, have failed\n"; break; case eFWMode_Firewall: temp += "Furthermore, your configuration explicitly forbids to use" " any fallback firewall ports that may exist to improve" " reliability of connection experience\n"; break; case eFWMode_Fallback: temp += "There are usually a few backup connection ports such as " STRINGIFY(CONN_PORT_SSH) " and " STRINGIFY(CONN_PORT_HTTPS) " at " NCBI_FWD_BEMD ", which can be used as a failover if" " connections to the port range above fail. However, your " " configuration explicitly requests that only those fallback" " firewall ports (if any exist) are to be used for" " connections: this also implies that no conventional ports" " from the default range will be used\n"; break; default: temp += "Internal program error, please report!\n"; _ASSERT(0); break; } } else { temp += "This mode may not be reliable if your site has a restraining" " firewall imposing a fine-grained control over which hosts and" " ports the outbound connections are allowed to use\n"; } if (m_HttpProxy) { temp += "Connections to the aforementioned ports will be made via an" " HTTP proxy at '"; temp += net_info->http_proxy_host; temp += ':'; temp += NStr::UIntToString(net_info->http_proxy_port); temp += "'"; if (net_info->http_proxy_leak) { temp += ". If that is unsuccessful, a link bypassing the proxy" " will then be attempted"; } } temp += '\n'; PreCheck(eFirewallConnPoints, 0/*main*/, temp); PreCheck(eFirewallConnPoints, 1/*sub*/, "Obtaining current NCBI " + string(m_Firewall ? "firewall settings" : "service entries")); EIO_Status status = x_GetFirewallConfiguration(net_info); if (status == eIO_Interrupt) temp = kCanceled; else if (status == eIO_Success) { if (!m_Fwd.empty() || (!m_FwdFB.empty() && m_Firewall && net_info->firewall == eFWMode_Fallback)) { temp = "OK: "; if (!m_Fwd.empty()) { stable_sort(m_Fwd.begin(), m_Fwd.end()); temp += NStr::UInt8ToString(m_Fwd.size()); } size_t down = 0; if (!m_FwdFB.empty()) { stable_sort(m_FwdFB.begin(), m_FwdFB.end()); if (!m_Fwd.empty()) temp += " + "; temp += NStr::UInt8ToString(m_FwdFB.size()); ITERATE(vector<CConnTest::CFWConnPoint>, cp, m_FwdFB) { if (cp->status != eIO_Success) ++down; } if (down) temp += " - " + NStr::UInt8ToString(down); } temp += m_Fwd.size() + m_FwdFB.size() - down == 1 ? " port" : " ports"; } else {
EIO_Status CConnTest::GetFWConnections(string* reason) { SConnNetInfo* net_info = ConnNetInfo_Create(0); if (net_info) { const char* user_header; net_info->req_method = eReqMethod_Post; if (net_info->firewall) { user_header = "NCBI-RELAY: FALSE"; m_Firewall = true; } else user_header = "NCBI-RELAY: TRUE"; if (net_info->stateless) m_Stateless = true; ConnNetInfo_OverrideUserHeader(net_info, user_header); ConnNetInfo_SetupStandardArgs(net_info, 0/*w/o service*/); } string temp(m_Firewall ? "FIREWALL" : "RELAY (legacy)"); temp += " connection mode has been detected for stateful services\n"; if (m_Firewall) { temp += "This mode requires your firewall to be configured in such a" " way that it allows outbound connections to the port range [" STRINGIFY(CONN_FWD_PORT_MIN) ".." STRINGIFY(CONN_FWD_PORT_MAX) "] (inclusive) at the two fixed NCBI hosts, 130.14.29.112" " and 165.112.7.12\n" "To set that up correctly, please have your network administrator" " read the following (if they have not already done so):" " " NCBI_FW_URL "\n"; } else { temp += "This is an obsolescent mode that requires keeping a wide port" " range [4444..4544] (inclusive) open to let through connections" " to any NCBI host (130.14.2x.xxx/165.112.xx.xxx) -- this mode was" " designed for unrestricted networks when firewall port blocking" " was not an issue\n"; } if (m_Firewall) { _ASSERT(net_info); switch (net_info->firewall) { case eFWMode_Adaptive: temp += "There are also fallback connection ports such as 22 and" " 443 at 130.14.29.112. They will be used if connections to" " the ports in the range described above have failed\n"; break; case eFWMode_Firewall: temp += "Also, your configuration explicitly forbids to use any" " fallback firewall ports that may exist to improve network" " connectivity\n"; break; case eFWMode_Fallback: temp += "However, your configuration explicitly requests that only" " fallback firewall ports (if any exist) are to be used for" " connections: this also implies that no conventional ports" " from the range above will be used\n"; break; default: temp += "Internal program error, please report!\n"; _ASSERT(0); break; } } else { temp += "This mode may not be reliable if your site has a restrictive" " firewall imposing fine-grained control over which hosts and" " ports the outbound connections are allowed to use\n"; } if (m_HttpProxy) { temp += "Connections to the aforementioned ports will be made via an" " HTTP proxy at '"; temp += net_info->http_proxy_host; temp += ':'; temp += NStr::UIntToString(net_info->http_proxy_port); temp += "'"; if (net_info && net_info->http_proxy_leak) { temp += ". If that is unsuccessful, a link bypassing the proxy" " will then be attempted"; } if (m_Firewall && *net_info->proxy_host) temp += ". In addition, your"; } if (m_Firewall && *net_info->proxy_host) { if (!m_HttpProxy) temp += "Your"; temp += " configuration specifies that instead of connecting directly" " to NCBI addresses, a forwarding non-transparent proxy host '"; temp += net_info->proxy_host; temp += "' should be used for all links"; if (m_HttpProxy) temp += " (including those originating from the HTTP proxy)"; } temp += '\n'; PreCheck(eFirewallConnPoints, 0/*main*/, temp); PreCheck(eFirewallConnPoints, 1/*sub*/, "Obtaining current NCBI " + string(m_Firewall ? "firewall settings" : "service entries")); EIO_Status status = x_GetFirewallConfiguration(net_info); if (status == eIO_Interrupt) temp = kCanceled; else if (status == eIO_Success) { if (!m_Fwd.empty() || (!m_FwdFB.empty() && m_Firewall && net_info->firewall == eFWMode_Fallback)) { temp = "OK: "; if (!m_Fwd.empty()) { stable_sort(m_Fwd.begin(), m_Fwd.end()); temp += NStr::UInt8ToString(m_Fwd.size()); } if (!m_FwdFB.empty()) { stable_sort(m_FwdFB.begin(), m_FwdFB.end()); if (!m_Fwd.empty()) temp += " + "; temp += NStr::UInt8ToString(m_FwdFB.size()); } temp += m_Fwd.size() + m_FwdFB.size() == 1 ? " port" : " ports"; } else { status = eIO_Unknown; temp = "No connection ports found, please contact " + HELP_EMAIL; } } else if (status == eIO_Timeout) { temp = x_TimeoutMsg(); if (m_Timeout > kTimeout) temp += "You may want to contact " + HELP_EMAIL; } else temp = "Please contact " + HELP_EMAIL; PostCheck(eFirewallConnPoints, 1/*sub*/, status, temp); ConnNetInfo_Destroy(net_info); if (status == eIO_Success) { PreCheck(eFirewallConnPoints, 2/*sub*/, "Verifying configuration for consistency"); bool firewall = true; // Check primary ports only ITERATE(vector<CConnTest::CFWConnPoint>, cp, m_Fwd) { if (cp->port < CONN_FWD_PORT_MIN || CONN_FWD_PORT_MAX < cp->port) firewall = false; if (cp->status != eIO_Success) { status = cp->status; temp = CSocketAPI::HostPortToString(cp->host, cp->port); temp += " is not operational, please contact " + HELP_EMAIL; break; } } if (status == eIO_Success) { if (!m_Firewall && !m_FwdFB.empty()) { status = eIO_Unknown; temp = "Fallback ports found in non-firewall mode, please" " contact " + HELP_EMAIL; } else if (m_Firewall != firewall) { status = eIO_Unknown; temp = "Firewall "; temp += firewall ? "wrongly" : "not"; temp += " acknowledged, please contact " + HELP_EMAIL; } else temp.resize(2); } PostCheck(eFirewallConnPoints, 2/*sub*/, status, temp); }
static CConn_IOStream::TConn_Pair s_HttpConnectorBuilder(const SConnNetInfo* net_info, const char* url, const char* host, unsigned short port, const char* path, const char* args, const char* user_header, FHTTP_ParseHeader parse_header, void* user_data, FHTTP_Adjust adjust, FHTTP_Cleanup cleanup, THTTP_Flags flags, const STimeout* timeout) { size_t len; AutoPtr<SConnNetInfo> x_net_info(net_info ? ConnNetInfo_Clone(net_info) : ConnNetInfo_Create(0)); if (!x_net_info.get()) { NCBI_THROW(CIO_Exception, eUnknown, "CConn_HttpStream::CConn_HttpStream(): Out of memory"); } if (url && !ConnNetInfo_ParseURL(x_net_info.get(), url)) { NCBI_THROW(CIO_Exception, eInvalidArg, "CConn_HttpStream::CConn_HttpStream(): Bad URL"); } if (host) { if ((len = *host ? strlen(host) : 0) >= sizeof(x_net_info->host)) { NCBI_THROW(CIO_Exception, eInvalidArg, "CConn_HttpStream::CConn_HttpStream(): Host too long"); } memcpy(x_net_info->host, host, ++len); } if (port) x_net_info->port = port; if (path) { if ((len = *path ? strlen(path) : 0) >= sizeof(x_net_info->path)) { NCBI_THROW(CIO_Exception, eInvalidArg, "CConn_HttpStream::CConn_HttpStream(): Path too long"); } memcpy(x_net_info->path, path, ++len); } if (args) { if ((len = *args ? strlen(args) : 0) >= sizeof(x_net_info->args)) { NCBI_THROW(CIO_Exception, eInvalidArg, "CConn_HttpStream::CConn_HttpStream(): Args too long"); } memcpy(x_net_info->args, args, ++len); } if (user_header && *user_header) ConnNetInfo_OverrideUserHeader(x_net_info.get(), user_header); x_SetupUserAgent(x_net_info.get()); if (timeout != kDefaultTimeout) x_net_info->timeout = timeout; CONNECTOR c = HTTP_CreateConnectorEx(x_net_info.get(), flags, parse_header, user_data, adjust, cleanup); return CConn_IOStream::TConn_Pair(c, eIO_Unknown); }
static CONNECTOR s_Open(SServiceConnector* uuu, const STimeout* timeout, const SSERV_Info* info, SConnNetInfo* net_info, int/*bool*/ second_try) { int/*bool*/ but_last = 0/*false*/; const char* user_header; /* either "" or non-empty dynamic string */ char* iter_header; EReqMethod req_method; if (info && info->type != fSERV_Firewall) { /* Not a firewall/relay connection here */ assert(!second_try); /* We know the connection point, let's try to use it! */ if (info->type != fSERV_Standalone || !net_info->stateless) { SOCK_ntoa(info->host, net_info->host, sizeof(net_info->host)); net_info->port = info->port; } switch (info->type) { case fSERV_Ncbid: /* Connection directly to NCBID, add NCBID-specific tags */ if (net_info->stateless) { /* Connection request with data */ user_header = "Connection-Mode: STATELESS\r\n"; /*default*/ req_method = eReqMethod_Post; } else { /* We will be waiting for conn-info back */ user_header = "Connection-Mode: STATEFUL\r\n"; req_method = eReqMethod_Get; } user_header = s_AdjustNetParams(uuu->service, net_info, req_method, NCBID_WEBPATH, SERV_NCBID_ARGS(&info->u.ncbid), 0, user_header, info->mime_t, info->mime_s, info->mime_e, 0); break; case fSERV_Http: case fSERV_HttpGet: case fSERV_HttpPost: /* Connection directly to CGI */ req_method = info->type == fSERV_HttpGet ? eReqMethod_Get : (info->type == fSERV_HttpPost ? eReqMethod_Post : eReqMethod_Any); user_header = "Client-Mode: STATELESS_ONLY\r\n"; /*default*/ user_header = s_AdjustNetParams(uuu->service, net_info, req_method, SERV_HTTP_PATH(&info->u.http), SERV_HTTP_ARGS(&info->u.http), 0, user_header, info->mime_t, info->mime_s, info->mime_e, 0); break; case fSERV_Standalone: if (!net_info->stateless) return s_CreateSocketConnector(net_info, 0, 0); /* Otherwise, it will be a pass-thru connection via dispatcher */ user_header = "Client-Mode: STATELESS_ONLY\r\n"; /*default*/ user_header = s_AdjustNetParams(uuu->service, net_info, eReqMethod_Post, 0, 0, 0, user_header, info->mime_t, info->mime_s, info->mime_e, 0); but_last = 1/*true*/; break; default: user_header = 0; break; } } else { EMIME_Type mime_t; EMIME_SubType mime_s; EMIME_Encoding mime_e; if (net_info->stateless || (info && (info->u.firewall.type & fSERV_Http))) { if (info) { req_method = info->u.firewall.type == fSERV_HttpGet ? eReqMethod_Get : (info->u.firewall.type == fSERV_HttpPost ? eReqMethod_Post : eReqMethod_Any); net_info->stateless = 1/*true*/; } else req_method = eReqMethod_Any; } else req_method = eReqMethod_Get; if (info) { mime_t = info->mime_t; mime_s = info->mime_s; mime_e = info->mime_e; } else { mime_t = eMIME_T_Undefined; mime_s = eMIME_Undefined; mime_e = eENCOD_None; } /* Firewall/relay connection to dispatcher, special tags */ user_header = net_info->stateless ? "Client-Mode: STATELESS_ONLY\r\n" /*default*/ : "Client-Mode: STATEFUL_CAPABLE\r\n"; user_header = s_AdjustNetParams(uuu->service, net_info, req_method, 0, 0, 0, user_header, mime_t, mime_s, mime_e, 0); } if (!user_header) return 0; if ((iter_header = SERV_Print(uuu->iter, net_info, but_last)) != 0) { size_t uh_len; if ((uh_len = strlen(user_header)) > 0) { char* ih; size_t ih_len = strlen(iter_header); if ((ih = (char*) realloc(iter_header, ih_len + uh_len + 1)) != 0){ strcpy(ih + ih_len, user_header); iter_header = ih; } free((char*) user_header); } user_header = iter_header; } else if (!*user_header) user_header = 0; /* special case of assignment of literal "" */ if (uuu->user_header) { ConnNetInfo_DeleteUserHeader(net_info, uuu->user_header); free((void*) uuu->user_header); } uuu->user_header = user_header; if (user_header && !ConnNetInfo_OverrideUserHeader(net_info, user_header)) return 0; if (!second_try) { ConnNetInfo_ExtendUserHeader (net_info, "User-Agent: NCBIServiceConnector/" DISP_PROTOCOL_VERSION #ifdef NCBI_CXX_TOOLKIT " (C++ Toolkit)" #else " (C Toolkit)" #endif "\r\n"); } if (!net_info->stateless && (!info || info->type == fSERV_Firewall || info->type == fSERV_Ncbid)) { /* Auxiliary HTTP connector first */ EIO_Status status = eIO_Success; CONNECTOR c; CONN conn; /* Clear connection info */ uuu->host = 0; uuu->port = 0; uuu->ticket = 0; net_info->max_try = 1; c = HTTP_CreateConnectorEx(net_info, (uuu->params.flags & fHCC_Flushable) | fHCC_SureFlush/*flags*/, s_ParseHeader, 0/*adj.info*/, uuu/*adj.data*/, 0/*cleanup.data*/); /* Wait for connection info back (error-transparent by DISPD.CGI) */ if (c && (status = CONN_Create(c, &conn)) == eIO_Success) { CONN_SetTimeout(conn, eIO_Open, timeout); CONN_SetTimeout(conn, eIO_ReadWrite, timeout); CONN_SetTimeout(conn, eIO_Close, timeout); CONN_Flush(conn); /* This also triggers parse header callback */ CONN_Close(conn); } else { const char* error = c ? IO_StatusStr(status) : 0; CORE_LOGF_X(4, eLOG_Error, ("[%s] Unable to create auxiliary HTTP %s%s%s", uuu->service, c ? "connection" : "connector", error && *error ? ": " : "", error ? error : "")); assert(0); } if (!uuu->host) return 0/*failed, no connection info returned*/; if (uuu->host == (unsigned int)(-1)) { /* Firewall mode only in stateful mode, fallback requested */ assert((!info || info->type == fSERV_Firewall) && !second_try); /* Try to use stateless mode instead */ net_info->stateless = 1/*true*/; return s_Open(uuu, timeout, info, net_info, 1/*second try*/); } SOCK_ntoa(uuu->host, net_info->host, sizeof(net_info->host)); net_info->port = uuu->port; return s_CreateSocketConnector(net_info, &uuu->ticket, uuu->ticket ? sizeof(uuu->ticket) : 0); } return HTTP_CreateConnectorEx(net_info, (uuu->params.flags & (fHCC_Flushable | fHCC_NoAutoRetry)) | fHCC_AutoReconnect, s_ParseHeader, s_AdjustNetInfo, uuu/*adj.data*/, 0/*cleanup.data*/); }
/* This callback is only for services called via direct HTTP */ static int/*bool*/ s_AdjustNetInfo(SConnNetInfo* net_info, void* data, unsigned int n) { SServiceConnector* uuu = (SServiceConnector*) data; const char* user_header; const SSERV_Info* info; assert(n != 0); /* paranoid assertion :-) */ if (uuu->net_info->firewall && !uuu->net_info->stateless) return 0; /*cannot adjust firewall stateful client*/ for (;;) { if (!(info = s_GetNextInfo(uuu))) return 0/*false - not adjusted*/; /* Skip any 'stateful_capable' or unconnectable entries here, * which might have left behind by either a failed stateful * dispatching with a fallback to stateless HTTP mode or * a too relaxed server type selection */ if (!info->sful && info->type != fSERV_Dns) break; } {{ char* iter_header = SERV_Print(uuu->iter, 0, 0); switch (info->type) { case fSERV_Ncbid: user_header = "Connection-Mode: STATELESS\r\n"; /*default*/ user_header = s_AdjustNetParams(uuu->service, net_info, eReqMethod_Post, NCBID_WEBPATH, SERV_NCBID_ARGS(&info->u.ncbid), uuu->net_info->args, user_header, info->mime_t, info->mime_s, info->mime_e, iter_header); break; case fSERV_Http: case fSERV_HttpGet: case fSERV_HttpPost: user_header = "Client-Mode: STATELESS_ONLY\r\n"; /*default*/ user_header = s_AdjustNetParams(uuu->service, net_info, info->type == fSERV_HttpGet ? eReqMethod_Get : (info->type == fSERV_HttpPost ? eReqMethod_Post : eReqMethod_Any), SERV_HTTP_PATH(&info->u.http), SERV_HTTP_ARGS(&info->u.http), uuu->net_info->args, user_header, info->mime_t, info->mime_s, info->mime_e, iter_header); break; case fSERV_Standalone: case fSERV_Firewall: user_header = "Client-Mode: STATELESS_ONLY\r\n"; /*default*/ user_header = s_AdjustNetParams(uuu->service, net_info, eReqMethod_Post, uuu->net_info->path, 0, uuu->net_info->args, user_header, info->mime_t, info->mime_s, info->mime_e, iter_header); break; default: if (iter_header) free(iter_header); user_header = 0; break; } }} if (!user_header) return 0/*false - not adjusted*/; if (uuu->user_header) { assert(*uuu->user_header); ConnNetInfo_DeleteUserHeader(net_info, uuu->user_header); free((void*) uuu->user_header); } if (*user_header) { uuu->user_header = user_header; if (!ConnNetInfo_OverrideUserHeader(net_info, user_header)) return 0/*false - not adjusted*/; } else uuu->user_header = 0; if (info->type == fSERV_Ncbid || (info->type & fSERV_Http)) { SOCK_ntoa(info->host, net_info->host, sizeof(net_info->host)); net_info->port = info->port; } else { strcpy(net_info->host, uuu->net_info->host); net_info->port = uuu->net_info->port; } return 1/*true - adjusted*/; }
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"); }