Manipulando localizadores de recursos uniformes

Um URL (Uniform Resource Locator) é uma representação compacta do local e do método de acesso para um recurso localizado na Internet. Cada URL consiste em um esquema (HTTP, HTTPS ou FTP) e uma cadeia de caracteres específica do esquema. Essa cadeia de caracteres também pode incluir uma combinação de um caminho de diretório, uma cadeia de caracteres de pesquisa ou um nome do recurso. As funções WinINet fornecem a capacidade de criar, combinar, dividir e canonizar URLs. Para obter mais informações sobre URLs, consulte RFC-1738 em URLs (Uniform Resource Locators).

As funções de URL operam de maneira orientada a tarefas. O conteúdo e o formato da URL que é fornecida à função não são verificados. O aplicativo de chamada deve acompanhar o uso dessas funções para garantir que os dados estão no formato pretendido. Por exemplo, a função InternetCanonicalizeUrl converteria o caractere "%" na sequência de escape "%25" ao usar nenhum sinalizador. Se InternetCanonicalizeUrl for usado na URL canônica, a sequência de escape "%25" será convertida na sequência de escape "%2525", que não funcionaria corretamente.

O que é uma URL canônica?

O formato de todas as URLs deve seguir a sintaxe e a semântica aceitas para acessar recursos por meio da Internet. A canonicalização é o processo de formatação de uma URL para seguir essa sintaxe e semântica aceitas.

Os caracteres que devem ser codificados incluem quaisquer caracteres que não tenham caracteres gráficos correspondentes no conjunto de caracteres codificados US-ASCII (hexadecimal 80-FF, que não são usados no conjunto de caracteres codificados US-ASCII e hexadecimal 00-1F e 7F, que são caracteres de controle), espaços em branco, "%" (que é usado para codificar outros caracteres) e caracteres não seguros (<, >, ", #, {, }, |, \, ^, ~, [, ], e ').

Usando as funções WinINet para manipular URLs

A tabela a seguir resume as funções de URL.

Função Descrição
InternetCanonicalizeUrl Canoniza a URL.
InternetCombineUrl Combina URLs base e relativas.
InternetCrackUrl Analisa uma cadeia de caracteres de URL em componentes.
InternetCreateUrl Cria uma cadeia de caracteres de URL com base em componentes.
Internetopenurl Começa a recuperar um recurso FTP, HTTP ou HTTPS.

 

Canonicalizando URLs

Canonizar uma URL é o processo que converte uma URL, que pode conter caracteres não seguros, como espaços em branco, caracteres reservados e assim por diante, em um formato aceito.

A função InternetCanonicalizeUrl pode ser usada para canonizar URLs. Essa função é muito orientada a tarefas, portanto, o aplicativo deve acompanhar seu uso com cuidado. InternetCanonicalizeUrl não verifica se a URL passada para ela já está canônica e se a URL retornada é válida.

Os cinco sinalizadores a seguir controlam como InternetCanonicalizeUrl manipula uma URL específica. Os sinalizadores podem ser usados em combinação. Se nenhum sinalizador for usado, a função codifica a URL por padrão.

Valor Significado
ICU_BROWSER_MODE Não codifique ou decodifica caracteres após "#" ou "?", e não remova o espaço em branco à direita após "?". Se esse valor não for especificado, toda a URL será codificada e o espaço em branco à direita será removido.
ICU_DECODE Converta todas as sequências %XX em caracteres, incluindo sequências de escape, antes que a URL seja analisada.
ICU_ENCODE_SPACES_ONLY Codificar apenas espaços.
ICU_NO_ENCODE Não converta caracteres não seguros em sequências de escape.
ICU_NO_META Não remova meta sequências (como "." e "..") da URL.

 

O sinalizador ICU_DECODE deve ser usado somente em URLs canônicas, pois pressupõe que todas as sequências %XX são códigos de escape e os converte nos caracteres indicados pelo código. Se a URL tiver um símbolo "%" que não faz parte de um código de escape, ICU_DECODE ainda o tratará como um. Essa característica pode fazer com que InternetCanonicalizeUrl crie uma URL inválida.

Para usar InternetCanonicalizeUrl para retornar uma URL completamente decodificada, os sinalizadores ICU_DECODE e ICU_NO_ENCODE devem ser especificados. Essa configuração pressupõe que a URL que está sendo passada para InternetCanonicalizeUrl foi canônica anteriormente.

Combinando URLs base e relativas

Uma URL relativa é uma representação compacta do local de um recurso em relação a uma URL base absoluta. A URL base deve ser conhecida pelo analisador e geralmente inclui o esquema, o local de rede e as partes do caminho da URL. Um aplicativo pode chamar InternetCombineUrl para combinar a URL relativa com sua URL base. InternetCombineUrl também canoniza a URL resultante.

Urls de quebra

A função InternetCrackUrl separa uma URL em suas partes de componente e retorna os componentes indicados pela estrutura URL_COMPONENTS que é passada para a função.

Os componentes que compõem a estrutura URL_COMPONENTS são o número do esquema, o nome do host, o número da porta, o nome de usuário, a senha, o caminho da URL e informações adicionais (como parâmetros de pesquisa). Cada componente, exceto os números de esquema e porta, tem um membro de cadeia de caracteres que contém as informações e um membro que contém o comprimento do membro da cadeia de caracteres. O esquema e os números de porta têm apenas um membro que armazena o valor correspondente; ambos são retornados em todas as chamadas bem-sucedidas para InternetCrackUrl.

Para obter o valor de um componente específico na estrutura URL_COMPONENTS , o membro que armazena o comprimento da cadeia de caracteres desse componente deve ser definido como um valor diferente de zero. O membro de cadeia de caracteres pode ser o endereço de um buffer ou NULL.

Se o membro do ponteiro contiver o endereço de um buffer, o membro de comprimento da cadeia de caracteres deverá conter o tamanho desse buffer. InternetCrackUrl retorna as informações do componente como uma cadeia de caracteres no buffer e armazena o comprimento da cadeia de caracteres no membro de comprimento da cadeia de caracteres.

Se o membro do ponteiro for NULL, o membro de comprimento da cadeia de caracteres poderá ser definido como qualquer valor diferente de zero. InternetCrackUrl armazena o endereço do primeiro caractere da cadeia de caracteres de URL que contém as informações do componente e define o comprimento da cadeia de caracteres como o número de caracteres na parte restante da cadeia de caracteres de URL que pertence ao componente.

Todos os membros de ponteiro definidos como NULL com um ponto de membro de comprimento diferente de zero para o ponto de partida apropriado na cadeia de caracteres de URL. O comprimento armazenado no membro de comprimento deve ser usado para determinar o final das informações do componente individual.

Para concluir a inicialização correta da estrutura URL_COMPONENTS , o membro dwStructSize deve ser definido como o tamanho da estrutura URL_COMPONENTS , em bytes.

O exemplo a seguir retorna os componentes da URL na caixa de edição, IDC_PreOpen1 e retorna os componentes para a caixa de listagem, IDC_PreOpenList. Para exibir apenas as informações de um componente individual, essa função copia o caractere imediatamente após as informações do componente na cadeia de caracteres e as substitui temporariamente por um 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 );
}

Criando URLs

A função InternetCreateUrl usa as informações na estrutura URL_COMPONENTS para criar um Uniform Resource Locator.

Os componentes que compõem a estrutura URL_COMPONENTS são o esquema, o nome do host, o número da porta, o nome de usuário, a senha, o caminho da URL e informações adicionais (como parâmetros de pesquisa). Cada componente, exceto o número da porta, tem um membro de cadeia de caracteres que contém as informações e um membro que contém o comprimento do membro da cadeia de caracteres.

Para cada componente necessário, o membro do ponteiro deve conter o endereço do buffer que contém as informações. O membro de comprimento deverá ser definido como zero se o membro do ponteiro contiver o endereço de uma cadeia de caracteres terminada em zero; o membro de comprimento deverá ser definido como o comprimento da cadeia de caracteres se o membro do ponteiro contiver o endereço de uma cadeia de caracteres que não seja terminada em zero. O membro ponteiro de todos os componentes que não são necessários deve ser NULL.

Acessando URLs diretamente

Os recursos FTP e HTTP na Internet podem ser acessados diretamente usando as funções InternetOpenUrl, InternetReadFile e InternetFindNextFile . InternetOpenUrl abre uma conexão com o recurso na URL passada para a função. Quando essa conexão é feita, há duas etapas possíveis. Primeiro, se o recurso for um arquivo, o InternetReadFile poderá baixá-lo; segundo, se o recurso for um diretório, InternetFindNextFile poderá enumerar os arquivos dentro do diretório (exceto ao usar proxies CERN). Para obter mais informações sobre InternetReadFile, consulte Lendo arquivos. Para obter mais informações sobre InternetFindNextFile, consulte Localizando o próximo arquivo.

Para aplicativos que precisam operar por meio de um proxy CERN, InternetOpenUrl pode ser usado para acessar diretórios e arquivos FTP. As solicitações ftp são empacotadas para aparecer como uma solicitação HTTP, que o proxy CERN aceitaria.

InternetOpenUrl usa o identificador HINTERNET criado pela função InternetOpen e a URL do recurso. A URL deve incluir o esquema (http:, ftp:, arquivo: [para um arquivo local], ou https: [para o protocolo de hipertexto seguro]) e o local de rede (como www.microsoft.com). A URL também pode incluir um caminho (por exemplo, /isapi/gomscom.asp? TARGET=/windows/feature/) e nome do recurso (por exemplo, default.htm). Para solicitações HTTP ou HTTPS, cabeçalhos adicionais podem ser incluídos.

InternetQueryDataAvailable, InternetFindNextFile, InternetReadFile e InternetSetFilePointer (somente URLs HTTP ou HTTPS) podem usar o identificador criado por InternetOpenUrl para baixar o recurso.

O diagrama a seguir ilustra quais identificadores usar com cada função.

identificadores a serem usados com funções

O identificador HINTERNET raiz criado pela InternetOpen é usado por InternetOpenUrl. O identificador HINTERNET criado por InternetOpenUrl pode ser usado por InternetQueryDataAvailable, InternetReadFile, InternetFindNextFile (não mostrado aqui) e InternetSetFilePointer (somente URLs HTTP ou HTTPS).

Para obter mais informações, consulte Identificadores HINTERNET.

Observação

O WinINet não dá suporte a implementações de servidor. Além disso, ele não deve ser usado de um serviço. Para implementações de servidor ou serviços, use Os Serviços HTTP do Microsoft Windows (WinHTTP).