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 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*/; }