Skip to content

Commit a03a7c8

Browse files
authored
Add HTTPS support via cpp-httplib's mbedtls backend (#1011)
1 parent 18aee94 commit a03a7c8

25 files changed

Lines changed: 442 additions & 11 deletions

llama.cpp.patches/README.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,29 @@ Cosmopolitan libc has specific behaviors with condition variables and signals th
8686
| `common_log.cpp.patch` | Adds `#include <csignal>`; blocks `SIGINT`/`SIGTERM` on logger thread via `pthread_sigmask` to prevent `EINTR` exceptions; replaces `cv.wait()` with `wait_for(30s)` loop to work around XNU futex timeout bug (~72 minute expiry) |
8787
| `tools_server_server-models.cpp.patch` | Adds `#include <csignal>`; blocks signals on the stopping thread via `pthread_sigmask`; replaces untimed `cv.wait()` with `wait_for(30s)` loops on every model-lifecycle wait (`unload_lru`, the reload-drain wait, `stopping_thread`, the `is_reloading` guard in `load`, and the generic `wait()` predicate helper) to work around the XNU futex timeout bug |
8888
| `tools_server_server-queue.cpp.patch` | Adds missing includes (`<cerrno>`, `<system_error>`, `<csignal>`); blocks `SIGINT`/`SIGTERM` on queue thread; replaces `wait()` with `wait_for()` loops in three locations (`wait_until_no_sleep`, main loop, `recv`) |
89-
| `vendor_cpp-httplib_httplib.cpp.patch` | Fixes httplib thread pool with `wait_for()` instead of `wait()` for XNU futex compatibility |
89+
| `vendor_cpp-httplib_httplib.cpp.patch` | Fixes httplib thread pool with `wait_for()` instead of `wait()` for XNU futex compatibility; also see HTTPS / TLS Support below |
90+
91+
### HTTPS / TLS Support
92+
93+
Upstream llama.cpp gets TLS from cpp-httplib's OpenSSL backend
94+
(`CPPHTTPLIB_OPENSSL_SUPPORT`, satisfied by system OpenSSL or vendored
95+
BoringSSL/LibreSSL at cmake time). None of those is available in the
96+
cosmocc make build, so llamafile instead enables cpp-httplib's **Mbed TLS
97+
backend** (`CPPHTTPLIB_MBEDTLS_SUPPORT`) against the mbedtls fork already
98+
vendored in `third_party/mbedtls` — the same TLS stack llamafile <= 0.9.3
99+
used. `third_party/mbedtls/include/` maps the canonical `<mbedtls/*.h>`
100+
include paths onto the fork's headers, and `BUILD.mk` sets the macro on
101+
every object that can reach `httplib.h` (the macro changes httplib class
102+
layouts, so all TUs must agree) and links `mbedtls.a` into `llama-server`.
103+
This enables HTTPS model downloads (`-hf`, `--model-url`), https clients
104+
in server-models, and TLS serving via `--ssl-cert-file`/`--ssl-key-file`.
105+
106+
| Patch | Description |
107+
|-------|-------------|
108+
| `common_http.h.patch` | `#ifndef CPPHTTPLIB_OPENSSL_SUPPORT` -> `#ifndef CPPHTTPLIB_SSL_ENABLED` for the "HTTPS is not supported" guard, so any cpp-httplib TLS backend counts (candidate for upstreaming) |
109+
| `tools_server_server-http.cpp.patch` | Same macro fix for the `httplib::SSLServer` (`--ssl-cert-file`/`--ssl-key-file`) guard (candidate for upstreaming) |
110+
| `tools_server_server-models.cpp.patch` | Same macro fix for the direct `httplib::SSLClient` construction in `server_http_proxy` (candidate for upstreaming) |
111+
| `vendor_cpp-httplib_httplib.cpp.patch` | Under `__COSMOPOLITAN__`: appends `/zip/third_party/mbedtls/sslroot` to `system_ca_dirs()` as the trust-store fallback (essential on Windows hosts, where the `_WIN32` cert-store branches are not compiled into an APE), and `__static_yoink("ssl_root_support")` so the Mozilla root PEMs bundled by `third_party/mbedtls/BUILD.mk` are pulled into the executable's zip |
90112

91113
### TinyBLAS Integration
92114

llama.cpp.patches/llamafile-files/BUILD.mk

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,19 @@ $(TOOL_PERPLEXITY_OBJS) $(TOOL_BENCH_OBJS) $(TOOL_SERVER_OBJS) $(MTMD_OBJS): \
460460
-iquote $(UI_GEN_DIR) \
461461
-isystem llama.cpp/vendor
462462

463+
# HTTPS support: build cpp-httplib with its Mbed TLS backend against the
464+
# mbedtls vendored in third_party/mbedtls (the same TLS stack llamafile
465+
# <= 0.9.3 used); third_party/mbedtls/include maps the canonical
466+
# <mbedtls/*.h> include paths onto it. The macro changes httplib class
467+
# layouts, so every object that includes httplib.h (directly or via
468+
# common/http.h, server-http.h, server-cors-proxy.h) must see it.
469+
$(LLAMA_CPP_OBJS) $(TOOL_QUANTIZE_OBJS) $(TOOL_IMATRIX_OBJS) \
470+
$(TOOL_PERPLEXITY_OBJS) $(TOOL_BENCH_OBJS) $(TOOL_SERVER_OBJS) $(MTMD_OBJS) \
471+
$(HTTPLIB_OBJS): \
472+
private CPPFLAGS += \
473+
-DCPPHTTPLIB_MBEDTLS_SUPPORT \
474+
-isystem third_party/mbedtls/include
475+
463476
# Server needs llamafile headers for Metal support.
464477
# The generated ui.h sits in $(UI_GEN_DIR); the -iquote above lets every
465478
# server source resolve `#include "ui.h"`.
@@ -576,9 +589,10 @@ o/$(MODE)/llama.cpp/server/llama-server: \
576589
$(HTTPLIB_OBJS) \
577590
$(TOOL_LLAMAFILE_OBJS) \
578591
$$(TINYBLAS_CPU_OBJS) \
579-
o/$(MODE)/llama.cpp/llama.cpp.a
592+
o/$(MODE)/llama.cpp/llama.cpp.a \
593+
o/$(MODE)/third_party/mbedtls/mbedtls.a
580594
@mkdir -p $(dir $@)
581-
$(LINK.o) $(TOOL_SERVER_OBJS) $(UI_GEN_OBJ) $(MTMD_OBJS) $(HTTPLIB_OBJS) $(TOOL_LLAMAFILE_OBJS) $(TINYBLAS_CPU_OBJS) o/$(MODE)/llama.cpp/llama.cpp.a $(LOADLIBES) $(LDLIBS) -o $@
595+
$(LINK.o) $(TOOL_SERVER_OBJS) $(UI_GEN_OBJ) $(MTMD_OBJS) $(HTTPLIB_OBJS) $(TOOL_LLAMAFILE_OBJS) $(TINYBLAS_CPU_OBJS) o/$(MODE)/llama.cpp/llama.cpp.a o/$(MODE)/third_party/mbedtls/mbedtls.a $(LOADLIBES) $(LDLIBS) -o $@
582596

583597
# ==============================================================================
584598
# Dependencies
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
diff --git a/common/http.h b/common/http.h
2+
--- a/llama.cpp/common/http.h
3+
+++ b/llama.cpp/common/http.h
4+
@@ -72,7 +72,7 @@ static std::pair<httplib::Client, common_http_url> common_http_client(const std:
5+
throw std::runtime_error("error: invalid URL format");
6+
}
7+
8+
-#ifndef CPPHTTPLIB_OPENSSL_SUPPORT
9+
+#ifndef CPPHTTPLIB_SSL_ENABLED
10+
if (parts.scheme == "https") {
11+
throw std::runtime_error(
12+
"HTTPS is not supported. Please rebuild with one of:\n"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
diff --git a/tools/server/server-http.cpp b/tools/server/server-http.cpp
2+
--- a/llama.cpp/tools/server/server-http.cpp
3+
+++ b/llama.cpp/tools/server/server-http.cpp
4+
@@ -93,7 +93,7 @@ bool server_http_context::init(const common_params & params) {
5+
6+
auto & srv = pimpl->srv;
7+
8+
-#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
9+
+#ifdef CPPHTTPLIB_SSL_ENABLED
10+
if (!params.ssl_file_key.empty() && !params.ssl_file_cert.empty()) {
11+
SRV_INF("running with SSL: key = %s, cert = %s\n", params.ssl_file_key.c_str(), params.ssl_file_cert.c_str());
12+
srv = std::make_unique<httplib::SSLServer>(

llama.cpp.patches/patches/tools_server_server-models.cpp.patch

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,16 @@ diff --git a/tools/server/server-models.cpp b/tools/server/server-models.cpp
120120
}
121121

122122
bool server_models::ensure_model_ready(const std::string & name) {
123+
@@ -1894,10 +1928,10 @@ server_http_proxy::server_http_proxy(
124+
auto pipe = std::make_shared<pipe_t<msg_t>>();
125+
126+
if (scheme == "https") {
127+
-#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
128+
+#ifdef CPPHTTPLIB_SSL_ENABLED
129+
cli.reset(new httplib::SSLClient(host, port));
130+
#else
131+
- throw std::runtime_error("HTTPS requested but CPPHTTPLIB_OPENSSL_SUPPORT is not defined");
132+
+ throw std::runtime_error("HTTPS requested but the server is built without SSL support");
133+
#endif
134+
}
135+

llama.cpp.patches/patches/vendor_cpp-httplib_httplib.cpp.patch

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,28 @@ diff --git a/vendor/cpp-httplib/httplib.cpp b/vendor/cpp-httplib/httplib.cpp
3939
}
4040

4141
idle_thread_count_--;
42+
@@ -12625,6 +12647,13 @@ bool enumerate_macos_keychain_certs(Callback cb) {
43+
44+
#if !defined(_WIN32) && !(defined(__APPLE__) && \
45+
defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN))
46+
+#ifdef __COSMOPOLITAN__
47+
+// Reference the Mozilla CA roots zipped into the APE (see llamafile's
48+
+// third_party/mbedtls/sslroot) so the linker keeps them; they serve as
49+
+// the trust-store fallback below on hosts without a system CA store
50+
+// (notably Windows, where the _WIN32 branches above are not compiled).
51+
+__static_yoink("ssl_root_support");
52+
+#endif
53+
// Common CA certificate file paths on Linux/Unix
54+
const char **system_ca_paths() {
55+
static const char *paths[] = {
56+
@@ -12642,6 +12671,10 @@ const char **system_ca_dirs() {
57+
static const char *dirs[] = {"/etc/ssl/certs", // Debian/Ubuntu
58+
"/etc/pki/tls/certs", // RHEL/CentOS
59+
"/usr/share/ca-certificates", // Other
60+
+#ifdef __COSMOPOLITAN__
61+
+ // CA bundle zipped into the APE (llamafile)
62+
+ "/zip/third_party/mbedtls/sslroot",
63+
+#endif
64+
nullptr};
65+
return dirs;
66+
}

llamafile/BUILD.mk

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,20 @@ LLAMAFILE_CPPFLAGS := \
6262
-DLLAMAFILE_TUI \
6363
-DCOSMOCC=1
6464

65+
# Flags for every TU that includes httplib.h: cpp-httplib is built with its
66+
# Mbed TLS backend (see llama.cpp/BUILD.mk), and CPPHTTPLIB_MBEDTLS_SUPPORT
67+
# changes httplib class layouts (e.g. httplib::Result, httplib::Client), so
68+
# an includer compiled without it corrupts memory when it exchanges those
69+
# types with httplib.cpp. If you add an httplib include to a llamafile
70+
# source, add its object below next to the chatbot ones.
71+
# -iquote . and -mcosmo are for the vendored mbedtls headers themselves
72+
# (repo-rooted internal includes, cosmo-extension macros).
73+
LLAMAFILE_HTTPLIB_TLS_FLAGS := \
74+
-DCPPHTTPLIB_MBEDTLS_SUPPORT \
75+
-isystem third_party/mbedtls/include \
76+
-iquote . \
77+
-mcosmo
78+
6579
# ==============================================================================
6680
# Source files - Highlight library
6781
# ==============================================================================
@@ -285,17 +299,21 @@ LLAMAFILE_DEPS = \
285299
$(LLAMAFILE_HIGHLIGHT_KEYWORDS) \
286300
$(LLAMAFILE_METAL_SOURCES) \
287301
$(TINYBLAS_CPU_OBJS) \
288-
o/$(MODE)/third_party/stb/stb_image_resize2.o
302+
o/$(MODE)/third_party/stb/stb_image_resize2.o \
303+
o/$(MODE)/third_party/mbedtls/mbedtls.a
289304

290305
# ==============================================================================
291306
# Server integration
292307
# ==============================================================================
293308

294-
# Include paths needed for server compilation
309+
# Include paths needed for server compilation. server.cpp reaches
310+
# httplib.h via server-cors-proxy.h, so it needs the httplib TLS flags
311+
# (see LLAMAFILE_HTTPLIB_TLS_FLAGS above).
295312
LLAMAFILE_SERVER_INCS := \
296313
$(LLAMAFILE_INCLUDES) \
297314
-iquote llama.cpp/tools/server \
298-
-iquote o/$(MODE)/llama.cpp/tools/server
315+
-iquote o/$(MODE)/llama.cpp/tools/server \
316+
$(LLAMAFILE_HTTPLIB_TLS_FLAGS)
299317

300318
# Compile server.cpp
301319
o/$(MODE)/llamafile/server.cpp.o: llama.cpp/tools/server/server.cpp
@@ -317,7 +335,7 @@ o/$(MODE)/llamafile/llamafile: \
317335
$(LLAMAFILE_OBJS) \
318336
$(LLAMAFILE_DEPS)
319337
@mkdir -p $(@D)
320-
$(CXX) $(LDFLAGS) -o $@ $(filter %.o,$^) $(LDLIBS)
338+
$(CXX) $(LDFLAGS) -o $@ $(filter %.o %.a,$^) $(LDLIBS)
321339

322340
# ==============================================================================
323341
# Pattern rules for llamafile sources
@@ -354,6 +372,13 @@ LLAMAFILE_GPU_OBJS := \
354372

355373
o/$(MODE)/llamafile/gpu.a: $(LLAMAFILE_GPU_OBJS)
356374

375+
# The TUI chatbot talks to the server through httplib as an HTTP client,
376+
# so its objects must agree with httplib.cpp on the httplib class layouts
377+
# (see LLAMAFILE_HTTPLIB_TLS_FLAGS).
378+
o/$(MODE)/llamafile/chatbot_api.o \
379+
o/$(MODE)/llamafile/chatbot_main.o: private \
380+
LLAMAFILE_CPPFLAGS += $(LLAMAFILE_HTTPLIB_TLS_FLAGS)
381+
357382
o/$(MODE)/llamafile/%.o: llamafile/%.cpp
358383
@mkdir -p $(@D)
359384
$(CXX) $(CXXFLAGS) $(LLAMAFILE_CPPFLAGS) -c -o $@ $<

llamafile/args.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ LlamafileArgs parse_llamafile_args(int argc, char** argv) {
5757
if ((strcmp(argv[i], "-m") == 0 || strcmp(argv[i], "--model") == 0) && i + 1 < argc) {
5858
args.model_path = argv[i + 1];
5959
}
60+
if ((strcmp(argv[i], "-hf") == 0 || strcmp(argv[i], "-hfr") == 0 ||
61+
strcmp(argv[i], "--hf-repo") == 0 || strcmp(argv[i], "-mu") == 0 ||
62+
strcmp(argv[i], "--model-url") == 0) && i + 1 < argc) {
63+
args.remote_model = argv[i + 1];
64+
}
6065
}
6166

6267
// Determine execution mode from flags

llamafile/args.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ struct LlamafileArgs {
4545
// Model path captured from -m (for display in combined mode TUI)
4646
std::string model_path;
4747

48+
// Remote model reference captured from -hf/--hf-repo/-mu/--model-url.
49+
// llama.cpp downloads it over HTTPS at load time, so -m is not required
50+
// when one of these is present; also used as the TUI display fallback.
51+
std::string remote_model;
52+
4853
// Note: Llamafile-specific flags are stored in FLAG_* globals (llamafile.h):
4954
// --verbose -> FLAG_verbose
5055
// --nothink -> FLAG_nothink

llamafile/main.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,8 @@ static int combined_main(const LlamafileArgs &args) {
240240
// stack is too small for the httplib + SSE + JSON parsing call chain)
241241
auto *ctx = new TuiThreadCtx{
242242
&shutdown_fn, &mu, &cv, &shutdown_ready,
243-
listen_addr, args.system_prompt, args.model_path
243+
listen_addr, args.system_prompt,
244+
args.model_path.empty() ? args.remote_model : args.model_path
244245
};
245246

246247
pthread_attr_t attr;
@@ -314,8 +315,10 @@ int main(int argc, char **argv) {
314315
}
315316
}
316317

317-
// All modes require a model file (but let --server --help pass through).
318-
if (args.model_path.empty() &&
318+
// All modes require a model: either a local file (-m) or a remote
319+
// reference (-hf/--model-url) that llama.cpp downloads over HTTPS.
320+
// --server --help still passes through.
321+
if (args.model_path.empty() && args.remote_model.empty() &&
319322
!llamafile_has(argv, "--help") && !llamafile_has(argv, "-h")) {
320323
fprintf(stderr, "error: missing required -m MODEL.gguf\n\n");
321324
switch (args.mode) {

0 commit comments

Comments
 (0)