Получить части URL в winapi - PullRequest
0 голосов
/ 11 июня 2018

Есть ли в Windows API, который может разбить URL на части?

Фон

Формат URL:

stackoverflow://iboyd:password01@mail.stackoverflow.com:12386/questions/SubmitQuestion.aspx?useLiveData=1&internal=0#nose
\___________/   \___/ \________/ \____________________/ \___/ \___________________________/\_______________________/ \__/
     |            |       |               |               |                |                          |                |
   scheme     username password        hostname          port             path                      query           fragment

Есть ли функцияв (родном) Win32 API, который может взломать URL на части:

  • Схема : stackoverflow
  • Имя пользователя : iboyd
  • Пароль: password01
  • Имя хоста: mail.stackoverflow.com
  • Порт :12386
  • Путь : questions/SubmitQuestion.aspx
  • Запрос : ?useLiveData=1&internal=0
  • Фрагмент : nose

Некоторые функции не работают

В WinApi есть некоторые функции, но они не справляются с этой задачей, потому что не понимают схемы, кроме тех, которыеWinHttp можно использовать:

оба не понимают URL, таких как:

  • ws://stackoverflow.com (веб-носокet)
  • wss://stackoverflow.com (защита веб-сокета)
  • sftp://fincen.gov/submit (передача файлов SSL)
  • magnet:?xt=urn:btih:c4244b6d0901f71add9a1f9e88013a2fa51a9900
  • stratum+udp://blockchain.info

WinHttpCrackUrl активно предотвращает использование для взлома URL:

Если интернет-протокол URL передан вдля pwszUrl не является HTTP или HTTPS, тогда WinHttpCrackUrl возвращает FALSE и GetLastError указывает ERROR_WINHTTP_UNRECOGNIZED 11SCH1112 *.

Есть ли в Windows еще один собственный API, который может получать части URL-адреса?

Bonus Chatter

Вот как это делается в CLR (например,C #): ( скрипка )

using System;

public class Program
{
    public static void Main()
    {
        var uri = new Uri("stackoverflow://iboyd:password01@mail.stackoverflow.com:12386/questions/SubmitQuestion.aspx?useLiveData=1&internal=0#nose");

        Console.WriteLine("Uri.Scheme: "+uri.Scheme);
        Console.WriteLine("Uri.UserInfo: "+uri.UserInfo);
        Console.WriteLine("Uri.Host: "+uri.Host);
        Console.WriteLine("Uri.Port: "+uri.Port);
        Console.WriteLine("Uri.AbsolutePath: "+uri.AbsolutePath);
        Console.WriteLine("Uri.Query: "+uri.Query);
        Console.WriteLine("Uri.Fragment: "+uri.Fragment);
    }
}

Выходы

Uri.Scheme: stackoverflow
Uri.UserInfo: iboyd:password01
Uri.Host: mail.stackoverflow.com
Uri.Port: 12386
Uri.AbsolutePath: /questions/SubmitQuestion.aspx
Uri.Query: ?useLiveData=1&internal=0
Uri.Fragment: #nose

Ответы [ 2 ]

0 голосов
/ 12 июня 2018

Есть ли в Windows API, который может разбить URL на части?

Есть в Windows 10. Класс Uri в среде выполнения Windows способенразложить URI на отдельные части.Это не является строго частью API Windows, но может использоваться любым приложением Windows API.

Следующий код иллюстрирует его использование.Он написан с использованием языковой проекции C ++ / WinRT и требует компилятора C ++ 17.Если вы не можете переключиться на компилятор C ++ 17, вы можете вместо этого использовать Библиотека шаблонов C ++ (WRL) среды выполнения Windows , чтобы использовать API среды выполнения Windows.

#include <iostream>
#include <string>
#include <winrt/Windows.Foundation.h>

#pragma comment(lib, "WindowsApp.lib")

using namespace winrt;
using namespace Windows::Foundation;

int wmain(int argc, wchar_t* wargv[])
{
    if (argc != 2)
    {
        std::wcout << L"Usage:\n  UrlCracker <url>" << std::endl;
        return 1;
    }

    init_apartment();

    Uri const uri{ wargv[1] };
    std::wcout << L"Scheme: " << uri.SchemeName().c_str() << std::endl;
    std::wcout << L"Username: " << uri.UserName().c_str() << std::endl;
    std::wcout << L"Password: " << uri.Password().c_str() << std::endl;
    std::wcout << L"Host: " << uri.Host().c_str() << std::endl;
    std::wcout << L"Port: " << std::to_wstring(uri.Port()) << std::endl;
    std::wcout << L"Path: " << uri.Path().c_str() << std::endl;
    std::wcout << L"Query: " << uri.Query().c_str() << std::endl;
    std::wcout << L"Fragment: " << uri.Fragment().c_str() << std::endl;
}

Эта программа перевариваетлюбой URI прописан в вопросе.Используя ввод

stackoverflow: // iboyd: password01@mail.stackoverflow.com: 12386 / questions / SubmitQuestion.aspx? UseLiveData = 1 & internal = 0 # nose

производит следующий вывод:

Scheme: stackoverflow
Username: iboyd
Password: password01
Host: mail.stackoverflow.com
Port: 12386
Path: /questions/SubmitQuestion.aspx
Query: ?useLiveData=1&internal=0
Fragment: #nose

Обработка ошибок была опущена.Если в Uri c'tor передана недопустимая строка, он генерирует исключение типа winrt :: hresult_error .Если вы не можете использовать исключения в своем коде, вы можете активировать тип вручную (например, с помощью WRL) и проверить вместо него возвращаемые значения HRESULT.

0 голосов
/ 12 июня 2018

Существует ряд функций, доступных родным разработчикам Windows:

Из них InternetCrackUrl работает.

URL_COMPONENTS components;
components.dwStructSize      = sizeof(URL_COMPONENTS);
components.dwSchemeLength    = DWORD(-1);
components.dwHostNameLength  = DWORD(-1);
components.dwUserNameLength  = DWORD(-1);
components.dwPasswordLength  = DWORD(-1);
components.dwUrlPathLength   = DWORD(-1);
components.dwExtraInfoLength = DWORD(-1);

if (!InternetCrackUrl(url, url.Length, 0, ref components)
    RaiseLastOSError();

String scheme   = StrLCopy(components.lpszScheme, components.dwSchemeLength);
String username = StrLCopy(components.lpszUserName, components.dwUserNameLength);
String password = StrLCopy(components.lpszPassword, components.dwPasswordLength);
String host     = StrLCopy(components.lpszHostName, components.dwHostNameLength);
Int32  port     = components.nPort;
String path     = StrLCopy(components.lpszUrlPath, components.dwUrlPathLength);
String extra    = StrLCopy(components.lpszExtraInfo, components.dwExtraInfoLength);

Это означает, что

stackoverflow: // iboyd: password01@mail.stackoverflow.com: 12386 / questions / SubmitQuestion.aspx? useLiveData = 1 & internal = 0 # nose

анализируется в:

  • Схема : stackoverflow
  • Имя пользователя : iboyd
  • Пароль : password01
  • Host : mail.stackoverflow.com
  • Порт : 12386
  • Path : /questions/SubmitQuestion.aspx
  • ExtraInfo : ?useLiveData=1&internal=0#nose

Разбор ExtraInfo в запрос и фрагмент

Это отстойв InternetCrackUrl не делает различий между:

?query#fragment

и просто объединяет их как ExtraInfo :

  • ExtraInfo :?useLiveData=1&internal=0#nose
  • Запрос : ?useLiveData=1&internal=0
  • Фрагмент : #nose

Итак, мы должнысделайте некоторое разбиение, если мы хотим, чтобы ?query или #fragment:

/*
   InternetCrackUrl returns ?query#fragment in a single combined extraInfo field.
   Split that into separate
      ?query
      #fragment
*/
String query = extraInfo;
String fragment = "";

Int32 n = StrPos("#", extraInfo);
if (n >= 1) //one-based string indexes
{
   query = extraInfo.SubString(1, n-1);
   fragment = extraInfo.SubString(n, MaxInt);
}

, давая нам желаемый финал:

  • Схема : stackoverflow
  • Имя пользователя : iboyd
  • Пароль : password01
  • Хост : mail.stackoverflow.com
  • Порт : 12386
  • Путь : /questions/SubmitQuestion.aspx
  • Запрос :?useLiveData=1&internal=0
  • Фрагмент : #nose
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...