HttpSendRequest завершается с ошибкой 12015 - PullRequest
0 голосов
/ 11 марта 2011

Я создал службу Win32, которая использует WinInet для отправки HTTP-запросов на удаленный хост.На моем компьютере (WinXP SP2) на тестовых рабочих станциях в нашей QoS-команде (Win2003 Server) он работает нормально - через прокси и прямой, прокси с аутентификацией и без).

Но некоторые из наших клиентов, которые используюту этой службы and_proxy_with_authorization на Win2003 Server возникла проблема - все вызовы HttpSendRequest завершаются неудачно, а GetLastError возвращает 12015 (ERROR_INTERNET_LOGIN_FAILURE, запрос на подключение и вход на FTP-сервер не выполнен).При этом одинаковый HTTP-запрос, отправленный вручную из адресной строки IE, завершился успешно.

Конфигурация прокси кажется корректной.Вот код инициализации:

m_hNet = InternetOpen(m_strAgent.c_str(),
            INTERNET_OPEN_TYPE_PRECONFIG,
            NULL,
            NULL,
            0);

        // Respect explicit proxy
        if (Cfg::m_bUseProxy)
        {
            char szProxy[MAX_PATH] = {0};
            strncpy(szProxy, m_strProxyServer.c_str(), MAX_PATH - 1);

            INTERNET_PROXY_INFO proxyinfo;
            proxyinfo.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
            proxyinfo.lpszProxy = szProxy;
            proxyinfo.lpszProxyBypass = NULL;

            BOOL B = InternetSetOption(m_hNet, INTERNET_OPTION_PROXY, (LPVOID)(&proxyinfo), sizeof(proxyinfo));
            if (!B)
            {
                devent(TS::LL_HIGH, "[Wrn] InternetSetOption::Proxy failed <proxy=%s><le=%d>",
                    m_strProxyServer.c_str(),
                    GetLastError());
            }
        }


        // Validate handle
        if (NULL == m_hNet)
        {
            devent(TS::LL_CRITICAL, "[Err] InternetOpen failed <le=%d>",
                GetLastError());
            return false;
        }


        // Try to get connection handle
        m_hConnect = InternetConnect(m_hNet,
            m_strHostName.c_str(),
            INTERNET_DEFAULT_HTTP_PORT,
            NULL,
            NULL,
            INTERNET_SERVICE_HTTP,
            0,
            0);


        // Validate handle
        if (NULL == m_hConnect)
        {
            devent(TS::LL_CRITICAL, "[Err] InternetConnect failed <le=%d>",
                GetLastError());
            Cleanup();
            return false;
        }

        // Respect proxy authentication
        if (Cfg::m_bUseAuth)
        {
            BOOL B;
            B = InternetSetOption(m_hConnect, INTERNET_OPTION_PROXY_USERNAME, (LPVOID*)Cfg::m_strProxyLogin.c_str(), Cfg::m_strProxyLogin.length() + 1);
            if (!B)
            {
                devent(TS::LL_HIGH, "[Wrn] InternetSetOption::ProxyUserName failed <login=%s><le=%d>",
                    Cfg::m_strProxyLogin.c_str(),
                    GetLastError());
            }

            B = InternetSetOption(m_hConnect, INTERNET_OPTION_PROXY_PASSWORD, (LPVOID*)Cfg::m_strProxyPassword.c_str(), Cfg::m_strProxyPassword.length() + 1);
            if (!B)
            {
                devent(TS::LL_HIGH, "[Wrn] InternetSetOption::ProxyPassword failed <pass=%s><le=%d>",
                    Cfg::m_strProxyPassword.c_str(),
                    GetLastError());
            }
        }

И это отправка:

// Try to get request handle
        m_hRequest = HttpOpenRequest(m_hConnect,
            "POST",
            m_strReqObject.c_str(),
            NULL,
            NULL,
            NULL,
            INTERNET_FLAG_NO_CACHE_WRITE,
            0);

        // Validate handle
        if (NULL == m_hRequest)
        {
            devent(TS::LL_CRITICAL, "[Err] OpenRequest failed <le=%d>",
                GetLastError());
            return false;
        }

        // Try to get response
        BOOL bOk = HttpSendRequest(m_hRequest,
            strSpecificHeaders.c_str(),
            strSpecificHeaders.length(),
            (LPVOID)strRequest.c_str(),
            (DWORD)strRequest.length());

        if (0 == bOk)
        {
            devent(TS::LL_CRITICAL, "[Err] SendRequest failed <le=%d>",
                GetLastError());

            CloseHandle(m_hRequest);
            return false;
        }

Я два дня гуглил, но не нашел не только решения, но и подобных проблем ни у кого.Также я не могу воспроизвести проблему на аналогичных рабочих станциях.И, наконец, я не могу понять, почему "FTP-сервер" в msdn error desc?

Есть идеи?

Ответы [ 2 ]

1 голос
/ 27 апреля 2011

WinInet предназначен для использования пользователями пространства приложений и связан с расположениями реестра для параметров WinInet (на основе зарегистрированной учетной записи пользователя ).

Онлайн-документация MSDN четко указывается на каждой странице WinInet:

Примечание WinINet не поддерживает реализации сервера.Кроме того, он не должен использоваться из службы.Для серверных реализаций или служб используйте Службы HTTP Microsoft Windows (WinHTTP) .

Разница в API между WinInet и WinHTTP очень мала, вы поймете это очень быстро.

  • Переименованные функции (например, HttpOpenRequest -> WinHttpOpenRequest)
  • Все методы WinHttp доступны только для Unicode
  • использует WinHttp.lib, WinHttp.dll вместо WinInet.lib,WinInet.dll

Есть несколько других тонкостей, но вы не будете бороться.

Я знаю, что ваш вопрос говорит о том, что код работает для людей, уже использующих его в качестве службы,Но тот факт, что в документации конкретно сказано «не делай этого», может указывать на то, что некоторые версии Windows могут не поддерживать его, в частности, более поздние версии, и что некоторые пакеты обновления или автоматические обновления могут вызывать сбой текущих рабочих экземпляров.

Я бы рискнул предположить, что могут даже быть некоторые токены и привилегии безопасности, которые требуются WinInet для скрытого выполнения задач, и в некоторых установках Windows Server 200x может быть настройка по умолчанию, чтобы эти маркеры не предоставлялись пользователям, работающим под управлением.в качестве учетной записи службы.

Я действительно рекомендую попробовать перенести службу быстрого тестирования на WinHTTP и протестировать реализацию Windows Server вашего клиента, чтобы проверить, решит ли это проблему.

0 голосов
/ 27 апреля 2011

По совершенно другому принципу ... ERROR_INTERNET_LOGIN_FAILURE также может указывать, что брандмауэр заблокировал это соединение.

Возможное решение было описано здесь в Egg Head Cafe

...