Пример #1
0
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);
    }
}
Пример #2
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);
}
Пример #3
0
/* 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);
  }
}
Пример #4
0
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;
}
Пример #5
0
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 {
Пример #6
0
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);
    }
Пример #7
0
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);
}
Пример #8
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*/);
}
Пример #9
0
/* 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*/;
}
Пример #10
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");
}