균일한 리소스 로케이터 처리

URL(Uniform Resource Locator)은 인터넷에 있는 리소스의 위치 및 액세스 방법을 간결하게 표현한 것입니다. 각 URL은 스키마(HTTP, HTTPS 또는 FTP) 및 스키마별 문자열로 구성됩니다. 이 문자열에는 디렉터리 경로, 검색 문자열 또는 리소스 이름의 조합이 포함될 수도 있습니다. WinINet 함수는 URL을 만들고, 결합하고, 세분화하고, 정식화하는 기능을 제공합니다. URL에 대한 자세한 내용은 URL(Uniform Resource Locators)의 RFC-1738 을 참조하세요.

URL 함수는 작업 지향 방식으로 작동합니다. 함수에 지정된 URL의 내용과 형식이 확인되지 않습니다. 호출 애플리케이션은 이러한 함수의 사용을 추적하여 데이터가 의도한 형식인지 확인해야 합니다. 예를 들어 InternetCanonicalizeUrl 함수는 플래그를 사용하지 않을 때 문자 "%"를 이스케이프 시퀀스 "%25"로 변환합니다. 정식화된 URL에서 InternetCanonicalizeUrl 을 사용하는 경우 이스케이프 시퀀스 "%2525"가 제대로 작동하지 않는 이스케이프 시퀀스 "%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에서 메타 시퀀스(예: "." 및 "..")를 제거하지 마세요.

 

모든 %XX 시퀀스가 이스케이프 코드라고 가정하고 코드에서 나타내는 문자로 변환하므로 ICU_DECODE 플래그는 정식화된 URL에서만 사용해야 합니다. URL에 이스케이프 코드의 일부가 아닌 "%" 기호가 있는 경우 ICU_DECODE 여전히 해당 기호를 하나로 처리합니다. 이 특성으로 인해 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 문자열의 적절한 시작점을 가리킵니다. 길이 멤버에 저장된 길이를 사용하여 개별 구성 요소 정보의 끝을 확인해야 합니다.

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 리소스는 InternetOpenUrl, InternetReadFileInternetFindNextFile 함수를 사용하여 직접 액세스할 수 있습니다. InternetOpenUrl 은 함수에 전달된 URL에서 리소스에 대한 연결을 엽니다. 이 연결이 만들어지면 두 가지 가능한 단계가 있습니다. 먼저 리소스가 파일인 경우 InternetReadFile 에서 다운로드할 수 있습니다. 둘째, 리소스가 디렉터리인 경우 InternetFindNextFile 은 디렉터리 내에서 파일을 열거할 수 있습니다(CERN 프록시를 사용하는 경우 제외). InternetReadFile에 대한 자세한 내용은 파일 읽기를 참조하세요. InternetFindNextFile에 대한 자세한 내용은 다음 파일 찾기를 참조하세요.

CERN 프록시를 통해 작동해야 하는 애플리케이션의 경우 InternetOpenUrl 을 사용하여 FTP 디렉터리 및 파일에 액세스할 수 있습니다. FTP 요청은 CERN 프록시가 수락하는 HTTP 요청처럼 표시되도록 패키지됩니다.

InternetOpenUrlInternetOpen 함수에서 만든 HINTERNET 핸들과 리소스의 URL을 사용합니다. URL에는 스키마(http:, ftp:, file: [로컬 파일의 경우] 또는 https: [하이퍼텍스트 프로토콜 보안의 경우]) 및 네트워크 위치(예: www.microsoft.com)가 포함되어야 합니다. URL에는 경로도 포함될 수 있습니다(예: /isapi/gomscom.asp? TARGET=/windows/feature/) 및 리소스 이름(예: default.htm). HTTP 또는 HTTPS 요청의 경우 추가 헤더를 포함할 수 있습니다.

InternetQueryDataAvailable, InternetFindNextFile, InternetReadFileInternetSetFilePointer (HTTP 또는 HTTPS URL만 해당)는 InternetOpenUrl 에서 만든 핸들을 사용하여 리소스를 다운로드할 수 있습니다.

다음 다이어그램에서는 각 함수에 사용할 핸들을 보여 줍니다.

함수와 함께 사용할 핸들

InternetOpen에서 만든 루트 HINTERNET 핸들은 InternetOpenUrl에서 사용됩니다. InternetOpenUrl에서 만든 HINTERNET 핸들은 InternetQueryDataAvailable, InternetReadFile, InternetFindNextFile(여기에 표시되지 않음) 및 InternetSetFilePointer(HTTP 또는 HTTPS URL만 해당)에서 사용할 수 있습니다.

자세한 내용은 HINTERNET 핸들을 참조하세요.

참고

WinINet은 서버 구현을 지원하지 않습니다. 또한 서비스에서 사용하면 안 됩니다. 서버 구현 또는 서비스의 경우 WinHTTP(Microsoft Windows HTTP 서비스)를 사용합니다.