Uniform Resource Locator の処理

Uniform Resource Locator (URL) は、インターネット上にあるリソースの場所とアクセス方法をコンパクトに表現したものです。 各 URL は、スキーム (HTTP、HTTPS、または FTP) とスキーム固有の文字列で構成されます。 この文字列には、ディレクトリ パス、検索文字列、またはリソースの名前の組み合わせを含めることもできます。 WinINet 関数は、URL の作成、結合、分割、正規化を行う機能を提供します。 URL の詳細については、UNIFORM Resource Locators (URL) に関する RFC-1738 を参照してください。

URL 関数は、タスク指向の方法で動作します。 関数に指定された URL の内容と形式は検証されません。 呼び出し元のアプリケーションは、これらの関数の使用を追跡して、データが意図した形式であることを確認する必要があります。 たとえば、 InternetCanonicalizeUrl 関数は、フラグを使用しない場合、文字 "%" をエスケープ シーケンス "%25" に変換します。 正規化された URL で InternetCanonicalizeUrl が使用されている場合、エスケープ シーケンス "%25" はエスケープ シーケンス "%2525" に変換され、正しく機能しません。

正規化された URL とは

すべての URL の形式は、インターネット経由でリソースにアクセスするために、受け入れられる構文とセマンティクスに従う必要があります。 正規化は、この受け入れ可能な構文とセマンティクスに従って URL を書式設定するプロセスです。

エンコードする必要がある文字には、US-ASCII コード化文字セットに対応するグラフィック文字を持たない文字 (16 進数 80-FF、 US-ASCII コード化文字セットでは使用されず、制御文字である 16 進数の 00-1F と 7F、空白スペース、"%" (他の文字のエンコードに使用されます)、安全でない文字 (<、、 >、"、#、{、}、|、\、^、~、[、]、および ')。

WinINet 関数を使用した URL の処理

次の表に、URL 関数の概要を示します。

機能 説明
InternetCanonicalizeUrl URL を正規化します。
InternetCombineUrl ベース URL と相対 URL を組み合わせます。
InternetCrackUrl URL 文字列をコンポーネントに解析します。
InternetCreateUrl コンポーネントから URL 文字列を作成します。
InternetOpenUrl FTP、HTTP、または HTTPS リソースの取得を開始します。

 

URL の正規化

URL の正規化は、空白や予約文字などの安全でない文字を含む可能性がある URL を受け入れ可能な形式に変換するプロセスです。

InternetCanonicalizeUrl 関数を使用して、URL を正規化できます。 この関数は非常にタスク指向であるため、アプリケーションはその使用を慎重に追跡する必要があります。 InternetCanonicalizeUrl は、渡された URL が既に正規化されていること、および返される URL が有効であることを確認しません。

次の 5 つのフラグは 、InternetCanonicalizeUrl が 特定の URL を処理する方法を制御します。 フラグは組み合わせて使用できます。 フラグが使用されていない場合、関数は既定で URL をエンコードします。

説明
ICU_BROWSER_MODE "#" または "?"の後に文字をエンコードまたはデコードしないでください。また、末尾の空白は "?"" の後に削除しないでください。 この値を指定しない場合、URL 全体がエンコードされ、末尾の空白が削除されます。
ICU_DECODE URL が解析される前に、すべての %XX シーケンスをエスケープ シーケンスを含む文字に変換します。
ICU_ENCODE_SPACES_ONLY スペースのみをエンコードします。
ICU_NO_ENCODE 安全でない文字をエスケープ シーケンスに変換しないでください。
ICU_NO_META URL からメタ シーケンス ("." や ".." など) を削除しないでください。

 

ICU_DECODE フラグは、正規化された URL でのみ使用する必要があります。これは、すべての %XX シーケンスがエスケープ コードであると想定し、コードで示される文字に変換するためです。 URL にエスケープ コードの一部ではない "%" 記号が含まれている場合でも、ICU_DECODEはそれを 1 として扱います。 この特性により 、InternetCanonicalizeUrl が 無効な URL を作成する可能性があります。

InternetCanonicalizeUrl を使用して完全にデコードされた URL を返すには、ICU_DECODEフラグと ICU_NO_ENCODE フラグを指定する必要があります。 このセットアップでは、 InternetCanonicalizeUrl に渡される URL が以前に正規化されていることを前提としています。

ベース URL と相対 URL の組み合わせ

相対 URL は、絶対ベース URL に対するリソースの場所をコンパクトに表現するものです。 ベース URL はパーサーに認識されている必要があり、通常はスキーム、ネットワークの場所、URL パスの一部が含まれます。 アプリケーションは InternetCombineUrl を 呼び出して、相対 URL とそのベース URL を組み合わせることができます。 InternetCombineUrl は、結果の URL も正規化します。

クラッキング URL

InternetCrackUrl 関数は、URL をコンポーネント部分に分割し、関数に渡されるURL_COMPONENTS構造体によって示されるコンポーネントを返します。

URL_COMPONENTS構造を構成するコンポーネントは、スキーム番号、ホスト名、ポート番号、ユーザー名、パスワード、URL パス、追加情報 (検索パラメーターなど) です。 スキームとポート番号を除く各コンポーネントには、情報を保持する文字列メンバーと、文字列メンバーの長さを保持するメンバーがあります。 スキームとポート番号には、対応する値を格納するメンバーのみが含まれます。これらはどちらも 、InternetCrackUrl への正常な呼び出しで返されます。

URL_COMPONENTS構造体内の特定のコンポーネントの値を取得するには、そのコンポーネントの文字列長を格納するメンバーを 0 以外の値に設定する必要があります。 文字列メンバーには、バッファーのアドレスまたは NULL を指定できます。

ポインター メンバーにバッファーのアドレスが含まれている場合、文字列の長さのメンバーには、そのバッファーのサイズが含まれている必要があります。 InternetCrackUrl は 、コンポーネント情報をバッファー内の文字列として返し、文字列の長さを文字列長メンバーに格納します。

ポインター メンバーが NULL の場合、文字列長メンバーは 0 以外の値に設定できます。 InternetCrackUrl は 、コンポーネント情報を含む URL 文字列の最初の文字のアドレスを格納し、文字列の長さを、コンポーネントに関連する URL 文字列の残りの部分の文字数に設定します。

すべてのポインター メンバーが NULL に設定され、長さ 0 以外のメンバーが URL 文字列内の適切な開始点を指します。 length メンバーに格納されている長さは、個々のコンポーネントの情報の末尾を決定するために使用する必要があります。

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 構造の情報を使用して、Uniform Resource Locator を作成します。

URL_COMPONENTS構造を構成するコンポーネントは、スキーム、ホスト名、ポート番号、ユーザー名、パスワード、URL パス、追加情報 (検索パラメーターなど) です。 ポート番号を除く各コンポーネントには、情報を保持する文字列メンバーと、文字列メンバーの長さを保持するメンバーがあります。

必要なコンポーネントごとに、ポインター メンバーには、情報を保持するバッファーのアドレスが含まれている必要があります。 ポインター メンバーに 0 で終わる文字列のアドレスが含まれている場合は、長さメンバーを 0 に設定する必要があります。ポインター メンバーに 0 で終わる文字列ではない文字列のアドレスが含まれている場合は、長さメンバーを文字列の長さに設定する必要があります。 必須ではないコンポーネントのポインター メンバーは NULL である必要があります。

URL への直接アクセス

インターネット上の FTP および HTTP リソースには、 InternetOpenUrlInternetReadFileおよび InternetFindNextFile 関数を使用して直接アクセスできます。 InternetOpenUrl は、関数に渡された URL でリソースへの接続を開きます。 この接続が確立されると、2 つの手順が考えられます。 まず、リソースがファイルの場合、 InternetReadFile はそれをダウンロードできます。次に、リソースがディレクトリの場合、 InternetFindNextFile はディレクトリ内のファイルを列挙できます (CERN プロキシを使用する場合を除く)。 InternetReadFile の詳細については、「ファイルの読み取り」を参照してください。 InternetFindNextFile の詳細については、「次のファイルの検索」を参照してください。

CERN プロキシを介して操作する必要があるアプリケーションの場合は、 InternetOpenUrl を 使用して FTP ディレクトリとファイルにアクセスできます。 FTP 要求は、CERN プロキシが受け入れる HTTP 要求のように表示されるようにパッケージ化されます。

InternetOpenUrl は、InternetOpen 関数によって作成された HINTERNET ハンドルとリソースの URL を使用します。 URL には、スキーム (http:、ftp:、file: [ローカル ファイルの場合]、または https: [hypertext protocol secure]) とネットワークの場所 (など www.microsoft.com) を含める必要があります。 URL にはパス (/isapi/gomscom.asp など) を含めることもできます。TARGET=/windows/feature/) とリソース名 (たとえば、default.htm)。 HTTP または HTTPS 要求の場合は、追加のヘッダーを含めることができます。

InternetQueryDataAvailableInternetFindNextFileInternetReadFileおよび InternetSetFilePointer (HTTP または HTTPS URL のみ) は、 InternetOpenUrl によって作成されたハンドルを使用してリソースをダウンロードできます。

次の図は、各関数で使用するハンドルを示しています。

関数で使用するハンドル

InternetOpen によって作成されたルート HINTERNET ハンドルは、InternetOpenUrl によって使用されます。 InternetOpenUrl によって作成された HINTERNET ハンドルは、InternetQueryDataAvailableInternetReadFileInternetFindNextFile (ここでは示されていません)、InternetSetFilePointer (HTTP または HTTPS URL のみ) で使用できます。

詳細については、「 HINTERNET ハンドル」を参照してください。

注意

WinINet では、サーバーの実装はサポートされていません。 また、サービスから使用しないでください。 サーバーの実装またはサービスの場合は、 Microsoft Windows HTTP サービス (WinHTTP) を使用します。