char-fork/llama.cpp

git clone https://git.t4t.associates/char-fork/llama.cpp

Xuan-Son Nguyencli : move to HTTP-based implementation (#24948)c264f65ff

char/aliceai-t5-moe
5.2 KiB191 linesraw
1#pragma once
2
3#include <cpp-httplib/httplib.h>
4
5#ifdef _WIN32
6#include <winsock2.h>
7#include <windows.h>
8#else
9#include <sys/socket.h>
10#include <netinet/in.h>
11#include <arpa/inet.h>
12#include <unistd.h>
13#endif
14
15struct common_http_url {
16    std::string scheme;
17    std::string user;
18    std::string password;
19    std::string host;
20    int port;
21    std::string path;
22};
23
24// bracket an IPv6 literal host for a URL authority (RFC 3986)
25static std::string common_http_format_host(const std::string & host) {
26    return host.find(':') != std::string::npos ? "[" + host + "]" : host;
27}
28
29static common_http_url common_http_parse_url(const std::string & url) {
30    common_http_url parts;
31    auto scheme_end = url.find("://");
32
33    if (scheme_end == std::string::npos) {
34        throw std::runtime_error("invalid URL: no scheme");
35    }
36    parts.scheme = url.substr(0, scheme_end);
37
38    if (parts.scheme != "http" && parts.scheme != "https") {
39        throw std::runtime_error("unsupported URL scheme: " + parts.scheme);
40    }
41
42    auto rest = url.substr(scheme_end + 3);
43    auto at_pos = rest.find('@');
44
45    if (at_pos != std::string::npos) {
46        auto auth = rest.substr(0, at_pos);
47        auto colon_pos = auth.find(':');
48        if (colon_pos != std::string::npos) {
49            parts.user = auth.substr(0, colon_pos);
50            parts.password = auth.substr(colon_pos + 1);
51        } else {
52            parts.user = auth;
53        }
54        rest = rest.substr(at_pos + 1);
55    }
56
57    auto slash_pos = rest.find('/');
58
59    if (slash_pos != std::string::npos) {
60        parts.host = rest.substr(0, slash_pos);
61        parts.path = rest.substr(slash_pos);
62    } else {
63        parts.host = rest;
64        parts.path = "/";
65    }
66
67    // split the authority into host and optional port, a bracketed IPv6 literal keeps its inner colons (RFC 3986)
68    std::string port_str;
69    if (!parts.host.empty() && parts.host.front() == '[') {
70        auto close = parts.host.find(']');
71        if (close == std::string::npos) {
72            throw std::runtime_error("invalid IPv6 URL authority: " + parts.host);
73        }
74        auto after = parts.host.substr(close + 1);
75        if (!after.empty() && after.front() == ':') {
76            port_str = after.substr(1);
77        }
78        parts.host = parts.host.substr(1, close - 1);
79    } else {
80        auto colon_pos = parts.host.find(':');
81        if (colon_pos != std::string::npos) {
82            port_str = parts.host.substr(colon_pos + 1);
83            parts.host = parts.host.substr(0, colon_pos);
84        }
85    }
86
87    if (!port_str.empty()) {
88        parts.port = std::stoi(port_str);
89    } else if (parts.scheme == "http") {
90        parts.port = 80;
91    } else if (parts.scheme == "https") {
92        parts.port = 443;
93    } else {
94        throw std::runtime_error("unsupported URL scheme: " + parts.scheme);
95    }
96
97    return parts;
98}
99
100static std::pair<httplib::Client, common_http_url> common_http_client(const std::string & url) {
101    common_http_url parts = common_http_parse_url(url);
102
103    if (parts.host.empty()) {
104        throw std::runtime_error("error: invalid URL format");
105    }
106
107#ifndef CPPHTTPLIB_OPENSSL_SUPPORT
108    if (parts.scheme == "https") {
109        throw std::runtime_error(
110            "HTTPS is not supported. Please rebuild with one of:\n"
111            "  -DLLAMA_BUILD_BORINGSSL=ON\n"
112            "  -DLLAMA_BUILD_LIBRESSL=ON\n"
113            "  -DLLAMA_OPENSSL=ON (default, requires OpenSSL dev files installed)"
114        );
115    }
116#endif
117
118    httplib::Client cli(parts.scheme + "://" + common_http_format_host(parts.host) + ":" + std::to_string(parts.port));
119
120    if (!parts.user.empty()) {
121        cli.set_basic_auth(parts.user, parts.password);
122    }
123
124    cli.set_follow_location(true);
125
126    return { std::move(cli), std::move(parts) };
127}
128
129static std::string common_http_show_masked_url(const common_http_url & parts) {
130    return parts.scheme + "://" + (parts.user.empty() ? "" : "****:****@") + common_http_format_host(parts.host) + parts.path;
131}
132
133static int common_http_get_free_port() {
134#ifdef _WIN32
135    WSADATA wsaData;
136    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
137        return -1;
138    }
139    typedef SOCKET native_socket_t;
140#define INVALID_SOCKET_VAL INVALID_SOCKET
141#define CLOSE_SOCKET(s) closesocket(s)
142#else
143    typedef int native_socket_t;
144#define INVALID_SOCKET_VAL -1
145#define CLOSE_SOCKET(s) close(s)
146#endif
147
148    native_socket_t sock = socket(AF_INET, SOCK_STREAM, 0);
149    if (sock == INVALID_SOCKET_VAL) {
150#ifdef _WIN32
151        WSACleanup();
152#endif
153        return -1;
154    }
155
156    struct sockaddr_in serv_addr;
157    std::memset(&serv_addr, 0, sizeof(serv_addr));
158    serv_addr.sin_family = AF_INET;
159    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
160    serv_addr.sin_port = htons(0);
161
162    if (bind(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) != 0) {
163        CLOSE_SOCKET(sock);
164#ifdef _WIN32
165        WSACleanup();
166#endif
167        return -1;
168    }
169
170#ifdef _WIN32
171    int namelen = sizeof(serv_addr);
172#else
173    socklen_t namelen = sizeof(serv_addr);
174#endif
175    if (getsockname(sock, (struct sockaddr*)&serv_addr, &namelen) != 0) {
176        CLOSE_SOCKET(sock);
177#ifdef _WIN32
178        WSACleanup();
179#endif
180        return -1;
181    }
182
183    int port = ntohs(serv_addr.sin_port);
184
185    CLOSE_SOCKET(sock);
186#ifdef _WIN32
187    WSACleanup();
188#endif
189
190    return port;
191}