Перенос приложений WinINet в WinHTTP

Службы Microsoft Windows HTTP (WinHTTP) предназначены для серверных приложений среднего уровня и серверных приложений, которым требуется доступ к стеку клиентов HTTP. Microsoft Windows Internet (WinINet) предоставляет стек клиента HTTP для клиентских приложений, а также доступ к протоколам FTP, SOCKSv4 и Gopher. Этот обзор поможет определить, будет ли полезным перенос приложений WinINet в WinHTTP. Здесь также описываются конкретные требования к преобразованию.

Что следует учитывать перед переносом приложения WinINet

Рассмотрите возможность переноса приложения WinINet в WinHTTP, если ваше приложение будет пользоваться следующими преимуществами:

  • Стек клиента HTTP, безопасный на сервере.
  • Минимальное использование стека.
  • Масштабируемость серверного приложения.
  • Меньше зависимостей от API, связанных с платформой.
  • Поддержка олицетворения потока.
  • Удобный для службы стек HTTP.
  • Доступ к объекту WinHttpRequest с доступом к скриптам.

Не рекомендуется переносить приложение WinINet в WinHTTP, если оно должно поддерживать одно или несколько из следующих компонентов:

  • Протокол FTP или Gopher из стека HTTP.
  • Поддержка протокола SOCKSv4 для взаимодействия с прокси-серверами SOCKS.
  • Автоматические коммутируемые службы.

Если вы решили перенести приложение в WinHTTP, в следующих разделах описан процесс преобразования.

Для примера приложения для WinINet и WinHTTP сравните пример AsyncDemo для WinINet с примером AsyncDemo для WinHTTP.

Эквиваленты WinHTTP функциям WinINet

В следующей таблице перечислены функции WinINet, связанные со стеком клиентов HTTP, а также эквиваленты WinHTTP.

Если приложению требуются функции WinINet, которых нет в списке, не переносите приложение в WinHTTP.

Функция WinINet Эквивалент WinHTTP Важные изменения
HttpAddRequestHeaders WinHttpAddRequestHeaders Нет.
HttpEndRequest WinHttpReceiveResponse Значение контекста задается с помощью WinHttpSendRequest или WinHttpSetOption. Параметры запроса задаются с помощью WinHttpOpenRequest. После отправки запроса необходимо вызвать WinHttpReceiveResponse.
HttpOpenRequest WinHttpOpenRequest Значение контекста задается с помощью WinHttpSendRequest или WinHttpSetOption.
HttpQueryInfo WinHttpQueryHeaders Нет.
HttpSendRequest WinHttpSendRequest Значение контекста можно задать с помощью WinHttpSendRequest.
HttpSendRequestEx WinHttpSendRequest Невозможно предоставить буферы.
InternetCanonicalizeUrl Эквивалент отсутствует URL-адреса теперь помещаются в каноническую форму в WinHttpOpenRequest.
InternetCheckConnection Эквивалент отсутствует Не реализовано в WinHTTP.
InternetCloseHandle WinHttpCloseHandle Закрытие родительского дескриптора в WinHTTP не приводит к рекурсивному закрытию дочерних дескрипторов.
InternetCombineUrl Эквивалент отсутствует URL-адреса можно собрать с помощью функции WinHttpCreateUrl .
InternetConfirmZoneCrossing Эквивалент отсутствует Не реализовано в WinHTTP.
InternetConnect WinHttpConnect Значение контекста задается с помощью WinHttpSendRequest или WinHttpSetOption. Параметры запроса задаются с помощью WinHttpOpenRequest. Учетные данные пользователя задаются с помощью WinHttpSetCredentials.
InternetCrackUrl WinHttpCrackUrl Поведение флага ICU_ESCAPE противоположное: в InternetCrackUrl этот флаг приводит к преобразованию escape-последовательностей (%xx) в символы, но при использовании WinHttpCrackUrl символы, которые должны быть экранированы в HTTP-запросе, преобразуются в escape-последовательности.
InternetCreateUrl WinHttpCreateUrl Нет.
InternetErrorDlg Эквивалент отсутствует Так как WinHTTP предназначен для приложений на стороне сервера, он не реализует пользовательский интерфейс.
InternetGetCookie Эквивалент отсутствует WinHTTP не сохраняет данные между сеансами и не может получить доступ к файлам cookie WinINet.
ИнтернетОткрыть WinHttpOpen Нет.
InternetOpenUrl WinHttpConnect, WinHttpOpenRequest, WinHttpSendRequest, WinHttpReceiveResponse Эта функция доступна в перечисленных функциях WinHTTP.
InternetQueryDataAvailable WinHttpQueryDataAvailable Нет зарезервированных параметров.
InternetQueryOption WinHttpQueryOption WinHTTP предлагает набор параметров, отличный от WinINet. Дополнительные сведения и параметры, предлагаемые WinHTTP, см. в разделе Флаги параметров.
InternetReadFile WinHttpReadData Нет.
InternetReadFileEx WinHttpReadData Вместо структуры буфер представляет собой область памяти, к которым обращается указатель.
InternetSetOption WinHttpSetOption Нет.
InternetSetStatusCallback WinHttpSetStatusCallback Дополнительные сведения см. в разделе "Различная обработка асинхронных запросов" этой статьи.
InternetTimeFromSystemTime WinHttpTimeFromSystemTime Нет.
InternetTimeToSystemTime WinHttpTimeToSystemTime Нет.
InternetWriteFile WinHttpWriteData Нет.

 

Различная обработка асинхронных запросов

Имейте в виду, что в WinINet и WinHTTP некоторые функции могут выполнять асинхронные запросы как синхронно, так и асинхронно. Приложение должно обрабатывать обе ситуации. Существуют значительные различия в том, как WinINet и WinHTTP обрабатывают эти потенциально асинхронные функции.

Wininet

  • Синхронное завершение. Если потенциально асинхронный вызов функции WinINet завершается синхронно, параметры OUT функции возвращают результаты операции. При возникновении ошибки получите код ошибки, вызвав Метод GetLastError после вызова функции WinINet.

  • Асинхронное завершение. Если потенциально асинхронный вызов функции завершается асинхронно, результаты операции и все ошибки доступны в функции обратного вызова. Функция обратного вызова выполняется в рабочем потоке, а не в потоке, который выполнил первоначальный вызов функции.

Другими словами, приложение должно дублировать логику для обработки результатов таких операций в двух местах: как сразу после вызова функции, так и в функции обратного вызова.

WinHTTP упрощает эту модель, позволяя реализовать рабочая логику только в функции обратного вызова, которая получает уведомление о завершении независимо от того, была ли операция выполнена синхронно или асинхронно. Если включена асинхронная операция, параметры OUT функций WinHTTP не возвращают значимые данные и должны иметь значение NULL.

Единственное существенное различие между асинхронным и синхронным завершением в WinHTTP с точки зрения приложения заключается в том, где выполняется функция обратного вызова.

WinHTTP

  • Синхронное завершение. Когда операция завершается синхронно, результаты возвращаются в функции обратного вызова, которая выполняется в том же потоке, что и исходный вызов функции.

  • Асинхронное завершение. Когда операция завершается асинхронно, результаты возвращаются в функции обратного вызова, которая выполняется в рабочем потоке.

Хотя большинство ошибок также можно обрабатывать полностью в функции обратного вызова, приложения WinHTTP по-прежнему должны быть подготовлены к возврату функции FALSE из-за ERROR_INVALID_PARAMETER или другой аналогичной ошибки, полученной путем вызова GetLastError.

В отличие от WinINet, которая может выполнять несколько асинхронных операций одновременно, WinHTTP применяет политику одной ожидающей асинхронной операции на дескриптор запроса. Если одна операция находится в состоянии ожидания и вызывается другая функция WinHTTP, вторая функция завершается сбоем и GetLastError возвращает ERROR_INVALID_OPERATION.

WinHTTP упрощает эту модель, позволяя реализовать рабочая логику только в функции обратного вызова, которая получает уведомление о завершении независимо от того, была ли операция выполнена синхронно или асинхронно. Если включена асинхронная операция, параметры OUT функций WinHTTP не возвращают значимые данные и должны иметь значение NULL.

Различия в уведомлениях обратного вызова WinHTTP

Функция обратного вызова состояния получает обновления о состоянии операций с помощью флагов уведомлений. В WinHTTP уведомления выбираются с помощью параметра dwNotificationFlags функции WinHttpSetStatusCallback . Используйте флаг WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS , чтобы получать уведомления обо всех обновлениях состояния.

Уведомления, указывающие, что определенная операция завершена, называются уведомлениями о завершении или просто завершениями. В WinINet каждый раз, когда функция обратного вызова получает завершение, параметр lpvStatusInformation содержит INTERNET_ASYNC_RESULT структуру. В WinHTTP эта структура доступна не для всех завершений. Важно просмотреть справочную страницу для WINHTTP_STATUS_CALLBACK, на которой содержатся сведения об уведомлениях и типе данных, которые можно ожидать для каждого из них.

В WinHTTP одно завершение WINHTTP_CALLBACK_STATUS_REQUEST_ERROR указывает на сбой операции. Все остальные завершения указывают на успешное выполнение операции.

Как WinINet, так и WinHTTP используют определяемое пользователем контекстное значение для передачи сведений из потока main функции обратного вызова состояния, которая может выполняться в рабочем потоке. В WinINet значение контекста, используемое функцией обратного вызова состояния, задается путем вызова одной из нескольких функций. В WinHTTP значение контекста задается только с помощью WinHttpSendRequest или WinHttpSetOption. Из-за этого в WinHTTP может появиться уведомление до установки значения контекста. Если функция обратного вызова получает уведомление до установки значения контекста, приложение должно быть подготовлено к получению null в параметре dwContext функции обратного вызова.

Различия в проверке подлинности

В WinINet учетные данные пользователя задаются путем вызова функции InternetSetOption с помощью кода, аналогичного приведенному в следующем примере кода.

// Use the WinINet InternetSetOption function to set the 
// user credentials to the user name contained in strUsername 
// and the password to the contents of strPassword.
       
InternetSetOption( hRequest, INTERNET_OPTION_PROXY_USERNAME, 
                   strUsername, strlen(strUsername) + 1 );

InternetSetOption( hRequest, INTERNET_OPTION_PROXY_PASSWORD, 
                   strPassword, strlen(strPassword) + 1 );

Для обеспечения совместимости учетные данные пользователя также можно задать в WinHTTP с помощью функции WinHttpSetOption , но это не рекомендуется, так как это может представлять уязвимость системы безопасности.

Вместо этого, когда приложение получает код состояния 401 в WinHTTP, рекомендуется сначала определить схему проверки подлинности с помощью WinHttpQueryAuthSchemes , а затем задать учетные данные с помощью WinHttpSetCredentials. В следующем примере кода показано, как это сделать.

DWORD dwSupportedSchemes;
DWORD dwPrefered;
DWORD dwTarget;

// Obtain the supported and first schemes.
WinHttpQueryAuthSchemes( hRequest, &dwSupportedSchemes, &dwPrefered, &dwTarget );

// Set the credentials before resending the request.
WinHttpSetCredentials( hRequest, dwTarget, dwPrefered, strUsername, strPassword, NULL );

Так как в WinHTTP нет эквивалента InternetErrorDlg , приложения, получающие учетные данные через пользовательский интерфейс, должны предоставлять собственный интерфейс.

В отличие от WinINet, WinHTTP не кэширует пароли. Для каждого запроса должны быть предоставлены допустимые учетные данные пользователя.

WinHTTP не поддерживает схему распределенной проверки подлинности паролей (DPA), поддерживаемую WinINet. Однако WinHTTP поддерживает Microsoft Passport 1.4. Дополнительные сведения об использовании проверки подлинности Passport в WinHTTP см. в статье Проверка подлинности passport в WinHTTP.

WinHTTP не использует параметры интернет-Обозреватель для определения политики автоматического входа. Вместо этого политика автоматического входа задается с помощью WinHttpSetOption. Дополнительные сведения о проверке подлинности в WinHTTP, включая политику автоматического входа, см. в разделе Проверка подлинности в WinHTTP.

Различия в безопасных транзакциях HTTP

В WinINet инициируйте безопасный сеанс с помощью HttpOpenRequest или InternetConnect, но в WinHTTP необходимо вызвать WinHttpOpenRequest с помощью флага WINHTTP_FLAG_SECURE .

В безопасной транзакции HTTP сертификаты сервера можно использовать для проверки подлинности сервера для клиента. В WinINet, если сертификат сервера содержит ошибки, HttpSendRequest завершается ошибкой и предоставляет сведения об ошибках сертификата.

В WinHttp ошибки сертификата сервера обрабатываются в соответствии с версией следующим образом:

  • Начиная с WinHttp 5.1, если сертификат сервера завершается сбоем или содержит ошибки, вызов WinHttpSendRequest сообщает о WINHTTP_CALLBACK_STATUS_SECURE_FAILURE в функции обратного вызова. Если ошибка, созданная WinHttpSendRequest , игнорируется, последующие вызовы WinHttpReceiveResponse завершаются ошибкой ERROR_WINHTTP_OPERATION_CANCELLED.
  • В WinHTTP 5.0 ошибки в сертификатах сервера по умолчанию не приводят к сбою запроса. Вместо этого об ошибках сообщается в функции обратного вызова с уведомлением WINHTTP_CALLBACK_STATUS_SECURE_FAILURE .

На некоторых более ранних платформах WinINet поддерживал протоколы Технологии частной коммуникации (PCT) и (или) Fortezza, хотя и не в Windows XP.

WinHTTP не поддерживает протоколы PCT и Fortezza на любой платформе и использует протокол SSL 2.0, SSL 3.0 или TLS 1.0.