代码之家  ›  专栏  ›  技术社区  ›  Ian Boyd

在winapi中获取url部分

  •  0
  • Ian Boyd  · 技术社区  · 6 年前

    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 (Web套接字)
    • wss://stackoverflow.com (Web套接字安全)
    • sftp://fincen.gov/submit (SSL文件传输)
    • magnet:?xt=urn:btih:c4244b6d0901f71add9a1f9e88013a2fa51a9900
    • stratum+udp://blockchain.info

    WinHttpCrackUrl主动防止用于破解URL:

    如果传入的URL的Internet协议 PWSZURL 不是http或https,那么 WinHttpCrackURL 收益率 错误的 错误信息 指示 ERROR_WINHTTP_UNRECOGNIZED_SCHEME .

    Windows中还有另一个本地API可以获取URL的一部分吗?

    奖金喋喋不休

    以下是在CLR中的操作方法(例如C): ( fiddle )

    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 回复  |  直到 6 年前
        1
  •  1
  •   IInspectable    6 年前

    Windows中有API可以将URL分解成部分吗?

    窗口10中有。这个 Uri windows运行时中的类能够将uri分解为其各个部分。这不是严格意义上的windows api的一部分,但是任何windowsapi应用程序都可以使用它。

    下面的代码演示了它的用法。它是用 C++/WinRT 语言投影,需要C++17编译器。如果不能切换到C++17编译器,可以使用 Windows Runtime C++ Template Library (WRL) 而是使用windows运行时api。

    #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&内部=0鼻子

    产生以下输出:

    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 而是返回值。

        2
  •  0
  •   Ian Boyd    6 年前

    本机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&内部=0鼻子

    分析为:

    • 方案 : stackoverflow
    • 用户名 : iboyd
    • 密码 : password01
    • 宿主 : mail.stackoverflow.com
    • 端口 : 12386
    • 路径 : /questions/SubmitQuestion.aspx
    • 超感官 : ?useLiveData=1&internal=0#nose

    将extrainfo解析为查询和片段

    很遗憾InternetCrackURL没有区分:

    ?query#fragment
    

    把它们混在一起 超感官 :

    • 超感官 : ?UseLiveData=1&内部=0鼻子
    • 查询 : ?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);
    }
    

    给我们最后想要的:

    • 方案 : 栈溢出
    • 用户名 : 伊博伊德
    • 密码 : 密码01
    • 宿主 : mail.stackoverflow.com网站
    • 端口 : 一万二千三百八十六
    • 路径 : /问题/submitquestion.aspx
    • 查询 : ?UseLiveData=1&内部=0
    • 破片 : 鼻孔