Обработка универсальных указателей ресурсов
Универсальный указатель ресурсов (URL-адрес) — это компактное представление расположения и метода доступа для ресурса, расположенного в Интернете. Каждый URL-адрес состоит из схемы (HTTP, HTTPS или FTP) и строки для конкретной схемы. Эта строка также может включать сочетание пути к каталогу, строки поиска или имени ресурса. Функции WinINet обеспечивают возможность создания, объединения, разделения и канонизации URL-адресов. Дополнительные сведения о URL-адресах см. в RFC-1738 о единых указателях ресурсов (URL).
Функции URL-адреса работают в зависимости от задач. Содержимое и формат URL-адреса, предоставленного функции, не проверяется. Вызывающее приложение должно отслеживать использование этих функций, чтобы убедиться, что данные хранятся в предполагаемом формате. Например, функция InternetCanonicalizeUrl преобразует символ "%" в управляющую последовательность "%25" при отсутствии флагов. Если InternetCanonicalizeUrl используется в канонизированном URL-адресе, escape-последовательность "%25" будет преобразована в escape-последовательность "%2525", которая не будет работать должным образом.
- Что такое канонизированный URL-адрес?
- Использование функций WinINet для обработки URL-адресов
- канонизация URL-адресов
- объединение базовых и относительных URL-адресов
- Разбор URL-адресов
- создание URL-адресов
- Доступ к URL-адресам напрямую
Что такое канонический URL-адрес?
Формат всех URL-адресов должен соответствовать принятому синтаксису и семантике для доступа к ресурсам через Интернет. Канонизация — это процесс форматирования URL-адреса для выполнения этого принятого синтаксиса и семантики.
Символы, которые должны быть закодированы, включают любые символы, не имеющие соответствующего графического символа US-ASCII в наборе закодированных символов (шестнадцатеричное значение 80-FF, которые не используются в закодированном наборе символов US-ASCII и шестнадцатеричном 00-1F и 7F, которые являются символами управления, пустые пробелы, "%" (который используется для кодирования других символов), а также небезопасные символы (<, >, ", #, {, }, |, \, ^, ~, [, ], и ").
Использование функций WinINet для обработки URL-адресов
В следующей таблице перечислены функции URL-адреса.
Функция | Описание |
---|---|
InternetCanonicalizeUrl | Канонизирует URL-адрес. |
InternetCombineUrl | Объединяет базовые и относительные URL-адреса. |
InternetCrackUrl | Разбирает строку URL-адреса на компоненты. |
InternetCreateUrl | Создает строку URL-адреса из компонентов. |
InternetOpenUrl | Начинает извлечение ресурса FTP, HTTP или HTTPS. |
Канонизация URL-адресов
Канонизация URL-адреса — это процесс, который преобразует URL-адрес, который может содержать небезопасные символы, такие как пустые пробелы, зарезервированные символы и т. д. в принятый формат.
Функцию InternetCanonicalizeUrl можно использовать для канонизации URL-адресов. Эта функция очень ориентирована на задачи, поэтому приложение должно тщательно отслеживать его использование. InternetCanonicalizeUrl не проверяет, что URL-адрес, переданный в него, уже канонизирован и что ВОЗВРАЩАемый URL-адрес является допустимым.
Следующие пять флагов определяют, как InternetCanonicalizeUrl обрабатывает определенный URL-адрес. Флаги можно использовать в сочетании. Если флаги не используются, функция кодирует URL-адрес по умолчанию.
Ценность | Значение |
---|---|
ICU_BROWSER_MODE | Не кодируйте или декодируйте символы после "#" или "?", а не удаляйте конечные пробелы после "?". Если это значение не указано, весь URL-адрес закодирован, а конечный пробел удаляется. |
ICU_DECODE | До анализа URL-адреса преобразуйте все последовательности %XX в символы, включая escape-последовательности. |
ICU_ENCODE_SPACES_ONLY | Кодируйте только пробелы. |
ICU_NO_ENCODE | Не преобразуйте небезопасные символы в escape-последовательности. |
ICU_NO_META | Не удаляйте мета последовательности (например, "." и ".") из URL-адреса. |
Флаг ICU_DECODE следует использовать только в канонизированных URL-адресах, поскольку предполагается, что все последовательности %XX являются escape-кодами и преобразуются в символы, указанные в escape-коде. Если в URL-адресе есть символ "%", который не является частью escape-кода, ICU_DECODE по-прежнему обрабатывает его как один. Эта характеристика может привести к тому, что InternetCanonicalizeUrl создаст недопустимый URL-адрес.
Чтобы использовать InternetCanonicalizeUrl для возврата полностью декодированного URL-адреса, необходимо указать флаги ICU_DECODE и ICU_NO_ENCODE. В этой конфигурации предполагается, что URL-адрес, передаваемый в InternetCanonicalizeUrl, был канонизирован ранее.
Объединение базовых и относительных URL-адресов
Относительный URL-адрес — это компактное представление расположения ресурса относительно абсолютного базового URL-адреса. Базовый URL-адрес должен быть известен средством синтаксического анализа и обычно включает схему, сетевое расположение и части пути URL-адреса. Приложение может вызывать InternetCombineUrl для объединения относительного URL-адреса с базовым URL-адресом. InternetCombineUrl также канонизирует результирующий URL-адрес.
Трещины URL-адресов
Функция InternetCrackUrl разделяет URL на его составные части и возвращает компоненты, указанные структурой URL_COMPONENTS, передаваемой в функцию.
Компоненты, составляющие структуру URL_COMPONENTS, — это номер схемы, имя узла, номер порта, имя пользователя, пароль, URL-путь и дополнительные сведения (например, параметры поиска). Каждый компонент, кроме схемы и номеров портов, имеет строковый элемент, содержащий сведения, и элемент, содержащий длину строкового элемента. Схема и номера портов имеют только одно поле, которое хранит соответствующее значение; оба возвращаются при всех успешных вызовах InternetCrackUrl.
Чтобы получить значение определенного компонента в структуре URL_COMPONENTS, элемент, в который хранится длина строки этого компонента, должен иметь значение, отличное от нуля. Строковый элемент может быть адресом буфера или NULL.
Если элемент указателя содержит адрес буфера, элемент длины строки должен содержать размер этого буфера. InternetCrackUrl возвращает сведения о компоненте в качестве строки в буфере и сохраняет длину строки в элементе длины строки.
Если элемент указателя null, элемент длины строки можно задать для любого ненулевого значения. InternetCrackUrl сохраняет адрес первой строки URL-адреса, содержащей сведения о компоненте, и задает длину строки в оставшейся части строки URL-адреса, относящейся к компоненту.
Все указатели, установленные на NULL, с ненулевой длиной указывают на соответствующую начальную точку в строке URL. Длину, хранящуюся в элементе длины, необходимо использовать для определения конца сведений отдельного компонента.
Чтобы завершить инициализацию структуры URL_COMPONENTS правильно, элемент dwStructSize должен иметь размер структуры URL_COMPONENTS в байтах.
В следующем примере возвращаются компоненты URL-адреса в поле редактирования, IDC_PreOpen1 и возвращаются компоненты в поле списка IDC_PreOpenList. Чтобы отобразить только информацию для отдельного компонента, эта функция копирует символ, находящийся сразу после информации о компоненте в строке, и временно заменяет его на NULL.
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <wininet.h>
#include <stdlib.h>
#pragma comment(lib, "wininet.lib")
#pragma comment(lib, "user32.lib")
#define CRACKER_BUFFER_SIZE MAX_PATH
// For sample source code implementing the InternetErrorOut( )
// function referenced below, see the "Handling Errors" topic
// under "Using WinInet"
extern BOOL WINAPI InternetErrorOut( HWND hWnd, DWORD dwError,
LPCTSTR szFailingFunctionName );
// Forward declaration of listUrlPart helper functions:
BOOL listURLpart( HWND hDlg, int nListBoxID,
LPTSTR szPartName, LPTSTR part, DWORD partLength );
BOOL listURLpart( HWND hDlg, int nListBoxID,
LPTSTR szPartName, int partValue );
// Static list describing the URL Scheme types
// enumerated in INTERNET_SCHEME:
TCHAR* schemeType[] =
{
TEXT( "[Partial URL]" ), // 0
TEXT( "[Unknown scheme]" ), // 1
TEXT( "[Default scheme]" ), // 2
TEXT( "FTP" ), // 3
TEXT( "Gopher" ), // 4
TEXT( "HTTP" ), // 5
TEXT( "HTTPS" ), // 6
TEXT( "File" ), // 7
TEXT( "News" ), // 8
TEXT( "MailTo" ), // 9
TEXT( "Socks" ), // 10
TEXT( "JavaScript" ), // 11
TEXT( "VBScript" ) // 12
};
#define CRACKER_SCHEME_TYPE_ARRAY_SIZE 13
BOOL WINAPI Cracker( HWND hDlg, int nURLtextBoxId, int nListBoxId )
{
int i, j;
TCHAR* failedFunctionName;
TCHAR URL_buffer[CRACKER_BUFFER_SIZE];
URL_COMPONENTS URLparts;
URLparts.dwStructSize = sizeof( URLparts );
// The following elements determine which components are displayed
URLparts.dwSchemeLength = 1;
URLparts.dwHostNameLength = 1;
URLparts.dwUserNameLength = 1;
URLparts.dwPasswordLength = 1;
URLparts.dwUrlPathLength = 1;
URLparts.dwExtraInfoLength = 1;
URLparts.lpszScheme = NULL;
URLparts.lpszHostName = NULL;
URLparts.lpszUserName = NULL;
URLparts.lpszPassword = NULL;
URLparts.lpszUrlPath = NULL;
URLparts.lpszExtraInfo = NULL;
SendDlgItemMessage( hDlg, nListBoxId, LB_RESETCONTENT, 0, 0 );
if( !GetDlgItemText( hDlg, nURLtextBoxId,
URL_buffer, CRACKER_BUFFER_SIZE ) )
{
failedFunctionName = TEXT( "GetDlgItemText" );
goto CrackerError_01;
}
if( FAILED( StringCchLength( URL_buffer, CRACKER_BUFFER_SIZE,
(size_t*) &i ) ) )
{
failedFunctionName = TEXT( "StringCchLength" );
goto CrackerError_01;
}
if( !InternetCrackUrl( URL_buffer, (DWORD)_tcslen( URL_buffer ), 0,
&URLparts ) )
{
failedFunctionName = TEXT( "InternetCrackUrl" );
goto CrackerError_01;
}
failedFunctionName = TEXT( "listURLpart" );
i = URLparts.nScheme + 2;
if( ( i >= 0 ) && ( i < CRACKER_SCHEME_TYPE_ARRAY_SIZE ) )
{
StringCchLength( schemeType[i],
CRACKER_BUFFER_SIZE,
(size_t*) &j );
if( !listURLpart( hDlg, nListBoxId,
TEXT("Scheme type"),
schemeType[i], j ))
goto CrackerError_01;
}
if( !listURLpart( hDlg, nListBoxId, TEXT( "Scheme text" ),
URLparts.lpszScheme,
URLparts.dwSchemeLength ) ||
!listURLpart( hDlg, nListBoxId, TEXT( "Host name" ),
URLparts.lpszHostName,
URLparts.dwHostNameLength) ||
!listURLpart( hDlg, nListBoxId, TEXT( "Port number" ),
(int) URLparts.nPort ) ||
!listURLpart( hDlg, nListBoxId, TEXT( "User name" ),
URLparts.lpszUserName,
URLparts.dwUserNameLength) ||
!listURLpart( hDlg, nListBoxId, TEXT( "Password" ),
URLparts.lpszPassword,
URLparts.dwPasswordLength) ||
!listURLpart( hDlg, nListBoxId, TEXT( "Path" ),
URLparts.lpszUrlPath,
URLparts.dwUrlPathLength) ||
!listURLpart( hDlg, nListBoxId, TEXT( "Extra information"),
URLparts.lpszExtraInfo,
URLparts.dwExtraInfoLength))
goto CrackerError_01;
return( TRUE );
CrackerError_01:
// For sample source code of the InternetErrorOut( ) function
// referenced below, see the "Handling Errors"
// topic under "Using WinInet"
InternetErrorOut( hDlg, GetLastError( ), failedFunctionName );
return FALSE;
}
// listURLpart( ) helper function for string parts
BOOL listURLpart( HWND hDlg, int nListBoxId,
LPTSTR szPartName, LPTSTR part, DWORD partLength )
{
TCHAR outputBuffer[CRACKER_BUFFER_SIZE];
LPTSTR nextStart;
size_t nextSize;
if( partLength == 0 ) // Just skip empty ones
return( TRUE );
if( FAILED( StringCchCopyEx( outputBuffer,
(size_t) CRACKER_BUFFER_SIZE,
szPartName, &nextStart,
&nextSize, 0 ) ) ||
FAILED( StringCchCopyEx( nextStart, nextSize, TEXT( ": " ),
&nextStart, &nextSize, 0 ) ) ||
FAILED( StringCchCopyNEx( nextStart, nextSize, part,
(size_t) partLength,
&nextStart, &nextSize, 0 ) ) )
return( FALSE );
*nextStart = 0;
if( SendDlgItemMessage( hDlg, nListBoxId, LB_ADDSTRING, 0,
(LPARAM)outputBuffer ) < 0 )
return( FALSE );
return( TRUE );
}
// listURLpart( ) helper function for numeric parts
BOOL listURLpart( HWND hDlg, int nListBoxId,
LPTSTR szPartName, int partValue )
{
TCHAR outputBuffer[CRACKER_BUFFER_SIZE];
if( FAILED( StringCchPrintf( outputBuffer,
(size_t) CRACKER_BUFFER_SIZE,
TEXT( "%s: %d" ), szPartName,
partValue ) ) ||
( SendDlgItemMessage( hDlg, nListBoxId, LB_ADDSTRING, 0,
(LPARAM)outputBuffer ) < 0 ) )
return( FALSE );
return( TRUE );
}
Создание URL-адресов
Функция InternetCreateUrl использует сведения в структуре URL_COMPONENTS для создания единого указателя ресурсов.
Компоненты, составляющие структуру URL_COMPONENTS, — это схема, имя узла, номер порта, имя пользователя, пароль, URL-путь и дополнительные сведения (например, параметры поиска). Каждый компонент, кроме номера порта, имеет строковый элемент, содержащий сведения, и элемент, содержащий длину строкового элемента.
Для каждого обязательного компонента элемент указателя должен содержать адрес буфера, в котором хранятся сведения. Элемент длины должен быть равен нулю, если элемент указателя содержит адрес нулевой строки; Элемент длины должен иметь длину строки, если элемент указателя содержит адрес строки, которая не завершается с нуля. Элемент указателя всех компонентов, которые не требуются, должен быть null.
Доступ к URL-адресам напрямую
Доступ к ресурсам FTP и HTTP в Интернете можно получить непосредственно с помощью функций InternetOpenUrl, InternetReadFileи InternetFindNextFile. InternetOpenUrl открывает подключение к ресурсу по URL-адресу, переданном функции. При создании этого подключения можно выполнить два возможных шага. Во-первых, если ресурс является файлом, InternetReadFile может скачать его; во-вторых, если ресурс является каталогом, InternetFindNextFile может перечислять файлы в каталоге (за исключением использования прокси-серверов CERN). Дополнительные сведения о InternetReadFileсм. в разделе Чтение файлов. Дополнительные сведения о InternetFindNextFileсм. в разделе Поиск следующего файла.
Для приложений, которым требуется работать через прокси-сервер CERN, можно использовать InternetOpenUrl для доступа к каталогам и файлам FTP. Запросы FTP упаковываются в виде HTTP-запроса, который будет принимать прокси-сервер CERN.
InternetOpenUrl использует дескрипторHINTERNET, созданный функцией InternetOpen и URL-адресом ресурса. URL-адрес должен содержать схему (http:, ftp:, file: [для локального файла], или https: [для безопасного протокола гипертекста]) и сетевое расположение (например, www.microsoft.com
). URL-адрес также может содержать путь (например, /isapi/gomscom.asp? TARGET=/windows/feature/) и имя ресурса (например, default.htm). Для HTTP-запросов или HTTPS можно включить дополнительные заголовки.
InternetQueryDataAvailable, InternetFindNextFile, InternetReadFileи InternetSetFilePointer (только URL-адреса HTTP или HTTPS) могут использовать дескриптор, созданный InternetOpenUrl для скачивания ресурса.
На следующей схеме показано, какие указатели используются для каждой функции.
Корневой дескриптор HINTERNET, созданный с помощью InternetOpen, используется для InternetOpenUrl. Дескриптор HINTERNET, созданный InternetOpenUrl, можно использовать для InternetQueryDataAvailable, InternetReadFile, InternetFindNextFile (не показано здесь) и InternetSetFilePointer (только HTTP или HTTPS URL-адреса).
Дополнительные сведения см. в разделе HINTERNET Handles.
Заметка
WinINet не поддерживает реализации сервера. Кроме того, его не следует использовать в службе. Для реализации серверов или служб используйте Microsoft Windows HTTP Services (WinHTTP) .