HttpSendRequest завершается с ошибкой 12015
Я создал службу 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 ответа
WinInet предназначен для использования пользователями пространства приложений и связан с местами в реестре для параметров WinInet (на основе зарегистрированной учетной записи пользователя).
Документация MSDN онлайн четко заявляет на каждой странице WinInet:
Примечание. WinINet не поддерживает серверные реализации. Кроме того, он не должен использоваться из службы. Для серверных реализаций или служб используйте Microsoft Windows HTTP Services (WinHTTP).
Разница в API между WinInet и WinHTTP очень мала, вы поймете это очень быстро.
- Функции переименованы (например, HttpOpenRequest -> WinHttpOpenRequest)
- Все методы WinHttp только для Unicode
- использует WinHttp.lib,WinHttp.dll вместо WinInet.lib, WinInet.dll
Есть несколько других тонкостей, но вы не будете бороться.
Я знаю, что ваш вопрос говорит о том, что код работает для людей, которые уже запускают его как сервис. Но тот факт, что в документации конкретно сказано "не делай этого", может указывать на то, что некоторые версии Windows могут не поддерживать его, в частности более поздние версии, и что некоторые пакеты обновления или автоматические обновления могут вызывать сбой текущих рабочих экземпляров.
Я бы предпочел предположить, что могут существовать даже некоторые токены и привилегии безопасности, необходимые WinInet для выполнения задач, и в некоторых установках Windows Server 200x могут быть настройки по умолчанию, чтобы эти маркеры не предоставлялись пользователям, работающим в качестве учетной записи службы.
Я действительно рекомендую попытаться портировать сервис быстрого тестирования на WinHTTP и протестировать реализацию Windows Server вашего клиента, чтобы посмотреть, решит ли это проблему.
С другой стороны... ERROR_INTERNET_LOGIN_FAILURE также может указывать, что брандмауэр заблокировал это соединение.
Возможное решение было описано здесь, в Egg Head Cafe