1#pragma once
 2
 3#include <cpp-httplib/httplib.h>
 4
 5struct common_http_url {
 6    std::string scheme;
 7    std::string user;
 8    std::string password;
 9    std::string host;
10    std::string path;
11};
12
13static common_http_url common_http_parse_url(const std::string & url) {
14    common_http_url parts;
15    auto scheme_end = url.find("://");
16
17    if (scheme_end == std::string::npos) {
18        throw std::runtime_error("invalid URL: no scheme");
19    }
20    parts.scheme = url.substr(0, scheme_end);
21
22    if (parts.scheme != "http" && parts.scheme != "https") {
23        throw std::runtime_error("unsupported URL scheme: " + parts.scheme);
24    }
25
26    auto rest = url.substr(scheme_end + 3);
27    auto at_pos = rest.find('@');
28
29    if (at_pos != std::string::npos) {
30        auto auth = rest.substr(0, at_pos);
31        auto colon_pos = auth.find(':');
32        if (colon_pos != std::string::npos) {
33            parts.user = auth.substr(0, colon_pos);
34            parts.password = auth.substr(colon_pos + 1);
35        } else {
36            parts.user = auth;
37        }
38        rest = rest.substr(at_pos + 1);
39    }
40
41    auto slash_pos = rest.find('/');
42
43    if (slash_pos != std::string::npos) {
44        parts.host = rest.substr(0, slash_pos);
45        parts.path = rest.substr(slash_pos);
46    } else {
47        parts.host = rest;
48        parts.path = "/";
49    }
50    return parts;
51}
52
53static std::pair<httplib::Client, common_http_url> common_http_client(const std::string & url) {
54    common_http_url parts = common_http_parse_url(url);
55
56    if (parts.host.empty()) {
57        throw std::runtime_error("error: invalid URL format");
58    }
59
60#ifndef CPPHTTPLIB_OPENSSL_SUPPORT
61    if (parts.scheme == "https") {
62        throw std::runtime_error(
63            "HTTPS is not supported. Please rebuild with one of:\n"
64            "  -DLLAMA_BUILD_BORINGSSL=ON\n"
65            "  -DLLAMA_BUILD_LIBRESSL=ON\n"
66            "  -DLLAMA_OPENSSL=ON (default, requires OpenSSL dev files installed)"
67        );
68    }
69#endif
70
71    httplib::Client cli(parts.scheme + "://" + parts.host);
72
73    if (!parts.user.empty()) {
74        cli.set_basic_auth(parts.user, parts.password);
75    }
76
77    cli.set_follow_location(true);
78
79    return { std::move(cli), std::move(parts) };
80}
81
82static std::string common_http_show_masked_url(const common_http_url & parts) {
83    return parts.scheme + "://" + (parts.user.empty() ? "" : "****:****@") + parts.host + parts.path;
84}