llama-cpp-pro 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +295 -0
- package/LICENSE +21 -0
- package/LlamaCpp.podspec +33 -0
- package/LlamaCppCapacitor.podspec +33 -0
- package/Package.swift +29 -0
- package/README.md +93 -0
- package/android/build.gradle +88 -0
- package/android/src/main/AndroidManifest.xml +4 -0
- package/android/src/main/CMakeLists-arm64.txt +138 -0
- package/android/src/main/CMakeLists-x86_64.txt +141 -0
- package/android/src/main/CMakeLists.txt +138 -0
- package/android/src/main/java/ai/annadata/plugin/capacitor/LlamaCpp.java +1340 -0
- package/android/src/main/java/ai/annadata/plugin/capacitor/LlamaCppPlugin.java +814 -0
- package/android/src/main/java/ai/annadata/plugin/capacitor/ModelAdmissionController.java +214 -0
- package/android/src/main/jni-chat-session.cpp +261 -0
- package/android/src/main/jni-lora.cpp +197 -0
- package/android/src/main/jni-multimodal.cpp +167 -0
- package/android/src/main/jni-tts.cpp +290 -0
- package/android/src/main/jni-utils.h +148 -0
- package/android/src/main/jni.cpp +1808 -0
- package/android/src/main/jniLibs/arm64-v8a/libllama-cpp-arm64.so +0 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/build-native.sh +280 -0
- package/cmake/desktop-metal-embed.cmake +30 -0
- package/cmake/desktop-sources.cmake +100 -0
- package/cmake/ggml-backends.cmake +44 -0
- package/cpp/LICENSE +21 -0
- package/cpp/README.md +15 -0
- package/cpp/anyascii.c +22223 -0
- package/cpp/anyascii.h +42 -0
- package/cpp/cap-completion.cpp +942 -0
- package/cpp/cap-completion.h +127 -0
- package/cpp/cap-embedding.cpp +193 -0
- package/cpp/cap-embedding.h +35 -0
- package/cpp/cap-ios-bridge.cpp +1810 -0
- package/cpp/cap-ios-bridge.h +61 -0
- package/cpp/cap-llama.cpp +412 -0
- package/cpp/cap-llama.h +161 -0
- package/cpp/cap-mtmd.hpp +602 -0
- package/cpp/cap-native-server.cpp +1095 -0
- package/cpp/cap-native-server.h +40 -0
- package/cpp/cap-tts.cpp +591 -0
- package/cpp/cap-tts.h +59 -0
- package/cpp/cap-wasm-fs.cpp +156 -0
- package/cpp/cap-wasm-jspi.cpp +19 -0
- package/cpp/cap-wasm-jspi.h +30 -0
- package/cpp/cap-wasm-vfs.cpp +22 -0
- package/cpp/chat-parser.cpp +393 -0
- package/cpp/chat-parser.h +120 -0
- package/cpp/chat.cpp +2315 -0
- package/cpp/chat.h +221 -0
- package/cpp/common.cpp +1664 -0
- package/cpp/common.h +744 -0
- package/cpp/ggml-alloc.c +1028 -0
- package/cpp/ggml-alloc.h +76 -0
- package/cpp/ggml-backend-impl.h +255 -0
- package/cpp/ggml-backend-reg.cpp +600 -0
- package/cpp/ggml-backend.cpp +2121 -0
- package/cpp/ggml-backend.h +354 -0
- package/cpp/ggml-common.h +1878 -0
- package/cpp/ggml-cpp.h +39 -0
- package/cpp/ggml-cpu/amx/amx.cpp +221 -0
- package/cpp/ggml-cpu/amx/amx.h +8 -0
- package/cpp/ggml-cpu/amx/common.h +91 -0
- package/cpp/ggml-cpu/amx/mmq.cpp +2512 -0
- package/cpp/ggml-cpu/amx/mmq.h +10 -0
- package/cpp/ggml-cpu/arch/arm/cpu-feats.cpp +94 -0
- package/cpp/ggml-cpu/arch/arm/quants.c +3650 -0
- package/cpp/ggml-cpu/arch/arm/repack.cpp +1891 -0
- package/cpp/ggml-cpu/arch/x86/cpu-feats.cpp +327 -0
- package/cpp/ggml-cpu/arch/x86/quants.c +3820 -0
- package/cpp/ggml-cpu/arch/x86/repack.cpp +6307 -0
- package/cpp/ggml-cpu/arch-fallback.h +215 -0
- package/cpp/ggml-cpu/binary-ops.cpp +158 -0
- package/cpp/ggml-cpu/binary-ops.h +16 -0
- package/cpp/ggml-cpu/common.h +73 -0
- package/cpp/ggml-cpu/ggml-cpu-impl.h +559 -0
- package/cpp/ggml-cpu/ggml-cpu.c +3578 -0
- package/cpp/ggml-cpu/ggml-cpu.cpp +672 -0
- package/cpp/ggml-cpu/ops.cpp +10587 -0
- package/cpp/ggml-cpu/ops.h +114 -0
- package/cpp/ggml-cpu/quants.c +1193 -0
- package/cpp/ggml-cpu/quants.h +97 -0
- package/cpp/ggml-cpu/repack.cpp +1982 -0
- package/cpp/ggml-cpu/repack.h +120 -0
- package/cpp/ggml-cpu/simd-mappings.h +1184 -0
- package/cpp/ggml-cpu/traits.cpp +36 -0
- package/cpp/ggml-cpu/traits.h +38 -0
- package/cpp/ggml-cpu/unary-ops.cpp +186 -0
- package/cpp/ggml-cpu/unary-ops.h +28 -0
- package/cpp/ggml-cpu/vec.cpp +348 -0
- package/cpp/ggml-cpu/vec.h +1121 -0
- package/cpp/ggml-cpu.h +145 -0
- package/cpp/ggml-impl.h +622 -0
- package/cpp/ggml-metal-impl.h +688 -0
- package/cpp/ggml-metal.h +66 -0
- package/cpp/ggml-metal.m +6833 -0
- package/cpp/ggml-metal.metal +10754 -0
- package/cpp/ggml-opt.cpp +1093 -0
- package/cpp/ggml-opt.h +256 -0
- package/cpp/ggml-quants.c +5324 -0
- package/cpp/ggml-quants.h +106 -0
- package/cpp/ggml-threading.cpp +12 -0
- package/cpp/ggml-threading.h +14 -0
- package/cpp/ggml.c +7108 -0
- package/cpp/ggml.h +2492 -0
- package/cpp/gguf.cpp +1358 -0
- package/cpp/gguf.h +202 -0
- package/cpp/json-partial.cpp +256 -0
- package/cpp/json-partial.h +38 -0
- package/cpp/json-schema-to-grammar.cpp +985 -0
- package/cpp/json-schema-to-grammar.h +21 -0
- package/cpp/llama-adapter.cpp +388 -0
- package/cpp/llama-adapter.h +76 -0
- package/cpp/llama-arch.cpp +2355 -0
- package/cpp/llama-arch.h +499 -0
- package/cpp/llama-batch.cpp +875 -0
- package/cpp/llama-batch.h +160 -0
- package/cpp/llama-chat.cpp +783 -0
- package/cpp/llama-chat.h +65 -0
- package/cpp/llama-context.cpp +2788 -0
- package/cpp/llama-context.h +306 -0
- package/cpp/llama-cparams.cpp +5 -0
- package/cpp/llama-cparams.h +41 -0
- package/cpp/llama-cpp.h +30 -0
- package/cpp/llama-grammar.cpp +1229 -0
- package/cpp/llama-grammar.h +173 -0
- package/cpp/llama-graph.cpp +1891 -0
- package/cpp/llama-graph.h +810 -0
- package/cpp/llama-hparams.cpp +180 -0
- package/cpp/llama-hparams.h +233 -0
- package/cpp/llama-impl.cpp +167 -0
- package/cpp/llama-impl.h +61 -0
- package/cpp/llama-io.cpp +15 -0
- package/cpp/llama-io.h +35 -0
- package/cpp/llama-kv-cache-iswa.cpp +318 -0
- package/cpp/llama-kv-cache-iswa.h +135 -0
- package/cpp/llama-kv-cache.cpp +2059 -0
- package/cpp/llama-kv-cache.h +374 -0
- package/cpp/llama-kv-cells.h +491 -0
- package/cpp/llama-memory-hybrid.cpp +258 -0
- package/cpp/llama-memory-hybrid.h +137 -0
- package/cpp/llama-memory-recurrent.cpp +1146 -0
- package/cpp/llama-memory-recurrent.h +179 -0
- package/cpp/llama-memory.cpp +59 -0
- package/cpp/llama-memory.h +119 -0
- package/cpp/llama-mmap.cpp +609 -0
- package/cpp/llama-mmap.h +68 -0
- package/cpp/llama-model-loader.cpp +1166 -0
- package/cpp/llama-model-loader.h +170 -0
- package/cpp/llama-model-saver.cpp +282 -0
- package/cpp/llama-model-saver.h +37 -0
- package/cpp/llama-model.cpp +19061 -0
- package/cpp/llama-model.h +491 -0
- package/cpp/llama-sampling.cpp +2575 -0
- package/cpp/llama-sampling.h +32 -0
- package/cpp/llama-vocab.cpp +3792 -0
- package/cpp/llama-vocab.h +176 -0
- package/cpp/llama.cpp +358 -0
- package/cpp/llama.h +1373 -0
- package/cpp/log.cpp +428 -0
- package/cpp/log.h +103 -0
- package/cpp/minja/chat-template.hpp +550 -0
- package/cpp/minja/minja.hpp +3009 -0
- package/cpp/nlohmann/json.hpp +25526 -0
- package/cpp/nlohmann/json_fwd.hpp +187 -0
- package/cpp/regex-partial.cpp +204 -0
- package/cpp/regex-partial.h +56 -0
- package/cpp/sampling.cpp +579 -0
- package/cpp/sampling.h +107 -0
- package/cpp/tools/mtmd/clip-impl.h +473 -0
- package/cpp/tools/mtmd/clip.cpp +4322 -0
- package/cpp/tools/mtmd/clip.h +106 -0
- package/cpp/tools/mtmd/miniaudio/miniaudio.h +93468 -0
- package/cpp/tools/mtmd/mtmd-audio.cpp +769 -0
- package/cpp/tools/mtmd/mtmd-audio.h +47 -0
- package/cpp/tools/mtmd/mtmd-helper.cpp +460 -0
- package/cpp/tools/mtmd/mtmd-helper.h +95 -0
- package/cpp/tools/mtmd/mtmd.cpp +1066 -0
- package/cpp/tools/mtmd/mtmd.h +302 -0
- package/cpp/tools/mtmd/stb/stb_image.h +7988 -0
- package/cpp/unicode-data.cpp +7034 -0
- package/cpp/unicode-data.h +20 -0
- package/cpp/unicode.cpp +1061 -0
- package/cpp/unicode.h +68 -0
- package/cpp/vendor/cpp-httplib/httplib.cpp +16509 -0
- package/cpp/vendor/cpp-httplib/httplib.h +3883 -0
- package/desktop/electron-builder.config.cjs +157 -0
- package/desktop/entitlements.mac.plist +12 -0
- package/desktop/package.json +11 -0
- package/desktop/resolve-package-root.cjs +88 -0
- package/desktop/src/main/backend-selector.cjs +148 -0
- package/desktop/src/main/gpu-probe.cjs +142 -0
- package/desktop/src/main/index.cjs +58 -0
- package/desktop/src/main/ipc-handlers.cjs +212 -0
- package/desktop/src/main/model-store.cjs +50 -0
- package/desktop/src/main/preload.cjs +39 -0
- package/desktop/src/main/sidecar-client.cjs +76 -0
- package/desktop/src/main/sidecar-manager.cjs +364 -0
- package/dist/docs.json +14357 -0
- package/dist/esm/definitions.d.ts +731 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/desktop.d.ts +37 -0
- package/dist/esm/desktop.js +133 -0
- package/dist/esm/desktop.js.map +1 -0
- package/dist/esm/index.d.ts +200 -0
- package/dist/esm/index.js +612 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/isomorphic/desktop.runtime.d.ts +37 -0
- package/dist/esm/isomorphic/desktop.runtime.js +36 -0
- package/dist/esm/isomorphic/desktop.runtime.js.map +1 -0
- package/dist/esm/isomorphic/errors.d.ts +6 -0
- package/dist/esm/isomorphic/errors.js +9 -0
- package/dist/esm/isomorphic/errors.js.map +1 -0
- package/dist/esm/isomorphic/model.admission.d.ts +17 -0
- package/dist/esm/isomorphic/model.admission.js +27 -0
- package/dist/esm/isomorphic/model.admission.js.map +1 -0
- package/dist/esm/isomorphic/model.scheduler.d.ts +31 -0
- package/dist/esm/isomorphic/model.scheduler.js +95 -0
- package/dist/esm/isomorphic/model.scheduler.js.map +1 -0
- package/dist/esm/isomorphic/provider.desktop.d.ts +40 -0
- package/dist/esm/isomorphic/provider.desktop.js +411 -0
- package/dist/esm/isomorphic/provider.desktop.js.map +1 -0
- package/dist/esm/isomorphic/provider.factory.d.ts +2 -0
- package/dist/esm/isomorphic/provider.factory.js +16 -0
- package/dist/esm/isomorphic/provider.factory.js.map +1 -0
- package/dist/esm/isomorphic/provider.interface.d.ts +76 -0
- package/dist/esm/isomorphic/provider.interface.js +2 -0
- package/dist/esm/isomorphic/provider.interface.js.map +1 -0
- package/dist/esm/isomorphic/provider.native.d.ts +18 -0
- package/dist/esm/isomorphic/provider.native.js +173 -0
- package/dist/esm/isomorphic/provider.native.js.map +1 -0
- package/dist/esm/isomorphic/provider.web.d.ts +88 -0
- package/dist/esm/isomorphic/provider.web.js +573 -0
- package/dist/esm/isomorphic/provider.web.js.map +1 -0
- package/dist/esm/isomorphic/sidecar-sse.d.ts +14 -0
- package/dist/esm/isomorphic/sidecar-sse.js +76 -0
- package/dist/esm/isomorphic/sidecar-sse.js.map +1 -0
- package/dist/esm/isomorphic/wasmMemoryCalibration.d.ts +26 -0
- package/dist/esm/isomorphic/wasmMemoryCalibration.js +60 -0
- package/dist/esm/isomorphic/wasmMemoryCalibration.js.map +1 -0
- package/dist/esm/isomorphic/wasmMemoryPolicy.d.ts +55 -0
- package/dist/esm/isomorphic/wasmMemoryPolicy.js +93 -0
- package/dist/esm/isomorphic/wasmMemoryPolicy.js.map +1 -0
- package/dist/esm/storage/manifest.d.ts +13 -0
- package/dist/esm/storage/manifest.js +87 -0
- package/dist/esm/storage/manifest.js.map +1 -0
- package/dist/esm/storage/opfs.store.d.ts +31 -0
- package/dist/esm/storage/opfs.store.js +241 -0
- package/dist/esm/storage/opfs.store.js.map +1 -0
- package/dist/esm/web.d.ts +206 -0
- package/dist/esm/web.js +521 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/esm/workers/async-file.d.ts +13 -0
- package/dist/esm/workers/async-file.js +12 -0
- package/dist/esm/workers/async-file.js.map +1 -0
- package/dist/esm/workers/heapfs.d.ts +55 -0
- package/dist/esm/workers/heapfs.js +115 -0
- package/dist/esm/workers/heapfs.js.map +1 -0
- package/dist/esm/workers/wasm.engine.d.ts +86 -0
- package/dist/esm/workers/wasm.engine.js +504 -0
- package/dist/esm/workers/wasm.engine.js.map +1 -0
- package/dist/esm/workers/worker.protocol.d.ts +160 -0
- package/dist/esm/workers/worker.protocol.js +2 -0
- package/dist/esm/workers/worker.protocol.js.map +1 -0
- package/dist/plugin.cjs +3179 -0
- package/dist/plugin.cjs.map +1 -0
- package/dist/plugin.js +3181 -0
- package/dist/plugin.js.map +1 -0
- package/dist/wasm/llama_engine.d.ts +74 -0
- package/dist/wasm/llama_engine.js +1829 -0
- package/dist/wasm/llama_engine.wasm +0 -0
- package/dist/wasm/llama_engine_emscripten.mjs +2 -0
- package/dist/wasm/package.json +16 -0
- package/dist/workers/llm.worker.js +1226 -0
- package/dist/workers/llm.worker.js.map +7 -0
- package/extraResources/llama-wasm/llama_engine.d.ts +74 -0
- package/extraResources/llama-wasm/llama_engine.js +1829 -0
- package/extraResources/llama-wasm/llama_engine.wasm +0 -0
- package/extraResources/llama-wasm/llama_engine_emscripten.mjs +2 -0
- package/extraResources/llama-wasm/package.json +16 -0
- package/extraResources/sidecar/README.md +11 -0
- package/extraResources/sidecar/darwin-arm64 +0 -0
- package/extraResources/sidecar/darwin-x64 +0 -0
- package/ios/CMakeLists-arm64.txt +161 -0
- package/ios/CMakeLists-x86_64.txt +188 -0
- package/ios/CMakeLists.txt +161 -0
- package/ios/Frameworks/llama-cpp.framework/Info.plist +28 -0
- package/ios/Frameworks/llama-cpp.framework/llama-cpp +0 -0
- package/ios/Sources/LlamaCppCapacitor/LlamaCpp.swift +1365 -0
- package/ios/Sources/LlamaCppCapacitor/LlamaCppPlugin.swift +694 -0
- package/ios/Sources/LlamaCppCapacitor/LlamaNativeBridge.swift +349 -0
- package/ios/Sources/LlamaCppCapacitor/ModelAdmissionController.swift +177 -0
- package/ios/embed-metal-shaders.sh +24 -0
- package/ios/metal-embed.cmake +29 -0
- package/package.json +281 -0
- package/scripts/build-js-preserve-wasm.cjs +53 -0
- package/scripts/build-sidecar-linux.sh +6 -0
- package/scripts/build-sidecar-win.bat +19 -0
- package/scripts/build-sidecar.sh +184 -0
- package/scripts/embed-llama-ios-app-framework.sh +63 -0
- package/scripts/ensure-desktop-sidecar-bundle.cjs +103 -0
- package/scripts/ensure-llama-ios-xcframework.sh +108 -0
- package/scripts/fix-esm-extensions.cjs +45 -0
- package/scripts/prepare-js-dist.cjs +28 -0
- package/scripts/stage-desktop-resources.cjs +116 -0
- package/sidecar/CMakeLists.txt +192 -0
- package/sidecar/cap-sidecar-main.cpp +68 -0
- package/types/llama-cpp-pro.d.ts +441 -0
|
@@ -0,0 +1,3883 @@
|
|
|
1
|
+
//
|
|
2
|
+
// httplib.h
|
|
3
|
+
//
|
|
4
|
+
// Copyright (c) 2026 Yuji Hirose. All rights reserved.
|
|
5
|
+
// MIT License
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#ifndef CPPHTTPLIB_HTTPLIB_H
|
|
9
|
+
#define CPPHTTPLIB_HTTPLIB_H
|
|
10
|
+
|
|
11
|
+
#define CPPHTTPLIB_VERSION "0.40.0"
|
|
12
|
+
#define CPPHTTPLIB_VERSION_NUM "0x002800"
|
|
13
|
+
|
|
14
|
+
#ifdef _WIN32
|
|
15
|
+
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0A00
|
|
16
|
+
#error \
|
|
17
|
+
"cpp-httplib doesn't support Windows 8 or lower. Please use Windows 10 or later."
|
|
18
|
+
#endif
|
|
19
|
+
#endif
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
* Configuration
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
#ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND
|
|
26
|
+
#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND 5
|
|
27
|
+
#endif
|
|
28
|
+
|
|
29
|
+
#ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND
|
|
30
|
+
#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND 10000
|
|
31
|
+
#endif
|
|
32
|
+
|
|
33
|
+
#ifndef CPPHTTPLIB_KEEPALIVE_MAX_COUNT
|
|
34
|
+
#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 100
|
|
35
|
+
#endif
|
|
36
|
+
|
|
37
|
+
#ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND
|
|
38
|
+
#define CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND 300
|
|
39
|
+
#endif
|
|
40
|
+
|
|
41
|
+
#ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND
|
|
42
|
+
#define CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND 0
|
|
43
|
+
#endif
|
|
44
|
+
|
|
45
|
+
#ifndef CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND
|
|
46
|
+
#define CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND 5
|
|
47
|
+
#endif
|
|
48
|
+
|
|
49
|
+
#ifndef CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND
|
|
50
|
+
#define CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND 0
|
|
51
|
+
#endif
|
|
52
|
+
|
|
53
|
+
#ifndef CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND
|
|
54
|
+
#define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND 5
|
|
55
|
+
#endif
|
|
56
|
+
|
|
57
|
+
#ifndef CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND
|
|
58
|
+
#define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND 0
|
|
59
|
+
#endif
|
|
60
|
+
|
|
61
|
+
#ifndef CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND
|
|
62
|
+
#define CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND 300
|
|
63
|
+
#endif
|
|
64
|
+
|
|
65
|
+
#ifndef CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND
|
|
66
|
+
#define CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND 0
|
|
67
|
+
#endif
|
|
68
|
+
|
|
69
|
+
#ifndef CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND
|
|
70
|
+
#define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND 5
|
|
71
|
+
#endif
|
|
72
|
+
|
|
73
|
+
#ifndef CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND
|
|
74
|
+
#define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND 0
|
|
75
|
+
#endif
|
|
76
|
+
|
|
77
|
+
#ifndef CPPHTTPLIB_CLIENT_MAX_TIMEOUT_MSECOND
|
|
78
|
+
#define CPPHTTPLIB_CLIENT_MAX_TIMEOUT_MSECOND 0
|
|
79
|
+
#endif
|
|
80
|
+
|
|
81
|
+
#ifndef CPPHTTPLIB_EXPECT_100_THRESHOLD
|
|
82
|
+
#define CPPHTTPLIB_EXPECT_100_THRESHOLD 1024
|
|
83
|
+
#endif
|
|
84
|
+
|
|
85
|
+
#ifndef CPPHTTPLIB_EXPECT_100_TIMEOUT_MSECOND
|
|
86
|
+
#define CPPHTTPLIB_EXPECT_100_TIMEOUT_MSECOND 1000
|
|
87
|
+
#endif
|
|
88
|
+
|
|
89
|
+
#ifndef CPPHTTPLIB_WAIT_EARLY_SERVER_RESPONSE_THRESHOLD
|
|
90
|
+
#define CPPHTTPLIB_WAIT_EARLY_SERVER_RESPONSE_THRESHOLD (1024 * 1024)
|
|
91
|
+
#endif
|
|
92
|
+
|
|
93
|
+
#ifndef CPPHTTPLIB_WAIT_EARLY_SERVER_RESPONSE_TIMEOUT_MSECOND
|
|
94
|
+
#define CPPHTTPLIB_WAIT_EARLY_SERVER_RESPONSE_TIMEOUT_MSECOND 50
|
|
95
|
+
#endif
|
|
96
|
+
|
|
97
|
+
#ifndef CPPHTTPLIB_IDLE_INTERVAL_SECOND
|
|
98
|
+
#define CPPHTTPLIB_IDLE_INTERVAL_SECOND 0
|
|
99
|
+
#endif
|
|
100
|
+
|
|
101
|
+
#ifndef CPPHTTPLIB_IDLE_INTERVAL_USECOND
|
|
102
|
+
#ifdef _WIN32
|
|
103
|
+
#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 1000
|
|
104
|
+
#else
|
|
105
|
+
#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 0
|
|
106
|
+
#endif
|
|
107
|
+
#endif
|
|
108
|
+
|
|
109
|
+
#ifndef CPPHTTPLIB_REQUEST_URI_MAX_LENGTH
|
|
110
|
+
#define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 8192
|
|
111
|
+
#endif
|
|
112
|
+
|
|
113
|
+
#ifndef CPPHTTPLIB_HEADER_MAX_LENGTH
|
|
114
|
+
#define CPPHTTPLIB_HEADER_MAX_LENGTH 8192
|
|
115
|
+
#endif
|
|
116
|
+
|
|
117
|
+
#ifndef CPPHTTPLIB_HEADER_MAX_COUNT
|
|
118
|
+
#define CPPHTTPLIB_HEADER_MAX_COUNT 100
|
|
119
|
+
#endif
|
|
120
|
+
|
|
121
|
+
#ifndef CPPHTTPLIB_REDIRECT_MAX_COUNT
|
|
122
|
+
#define CPPHTTPLIB_REDIRECT_MAX_COUNT 20
|
|
123
|
+
#endif
|
|
124
|
+
|
|
125
|
+
#ifndef CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT
|
|
126
|
+
#define CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT 1024
|
|
127
|
+
#endif
|
|
128
|
+
|
|
129
|
+
#ifndef CPPHTTPLIB_PAYLOAD_MAX_LENGTH
|
|
130
|
+
#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH (100 * 1024 * 1024) // 100MB
|
|
131
|
+
#endif
|
|
132
|
+
|
|
133
|
+
#ifndef CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH
|
|
134
|
+
#define CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH 8192
|
|
135
|
+
#endif
|
|
136
|
+
|
|
137
|
+
#ifndef CPPHTTPLIB_RANGE_MAX_COUNT
|
|
138
|
+
#define CPPHTTPLIB_RANGE_MAX_COUNT 1024
|
|
139
|
+
#endif
|
|
140
|
+
|
|
141
|
+
#ifndef CPPHTTPLIB_TCP_NODELAY
|
|
142
|
+
#define CPPHTTPLIB_TCP_NODELAY false
|
|
143
|
+
#endif
|
|
144
|
+
|
|
145
|
+
#ifndef CPPHTTPLIB_IPV6_V6ONLY
|
|
146
|
+
#define CPPHTTPLIB_IPV6_V6ONLY false
|
|
147
|
+
#endif
|
|
148
|
+
|
|
149
|
+
#ifndef CPPHTTPLIB_RECV_BUFSIZ
|
|
150
|
+
#define CPPHTTPLIB_RECV_BUFSIZ size_t(16384u)
|
|
151
|
+
#endif
|
|
152
|
+
|
|
153
|
+
#ifndef CPPHTTPLIB_SEND_BUFSIZ
|
|
154
|
+
#define CPPHTTPLIB_SEND_BUFSIZ size_t(16384u)
|
|
155
|
+
#endif
|
|
156
|
+
|
|
157
|
+
#ifndef CPPHTTPLIB_COMPRESSION_BUFSIZ
|
|
158
|
+
#define CPPHTTPLIB_COMPRESSION_BUFSIZ size_t(16384u)
|
|
159
|
+
#endif
|
|
160
|
+
|
|
161
|
+
#ifndef CPPHTTPLIB_THREAD_POOL_COUNT
|
|
162
|
+
#define CPPHTTPLIB_THREAD_POOL_COUNT \
|
|
163
|
+
((std::max)(8u, std::thread::hardware_concurrency() > 0 \
|
|
164
|
+
? std::thread::hardware_concurrency() - 1 \
|
|
165
|
+
: 0))
|
|
166
|
+
#endif
|
|
167
|
+
|
|
168
|
+
#ifndef CPPHTTPLIB_THREAD_POOL_MAX_COUNT
|
|
169
|
+
#define CPPHTTPLIB_THREAD_POOL_MAX_COUNT (CPPHTTPLIB_THREAD_POOL_COUNT * 4)
|
|
170
|
+
#endif
|
|
171
|
+
|
|
172
|
+
#ifndef CPPHTTPLIB_THREAD_POOL_IDLE_TIMEOUT
|
|
173
|
+
#define CPPHTTPLIB_THREAD_POOL_IDLE_TIMEOUT 3 // seconds
|
|
174
|
+
#endif
|
|
175
|
+
|
|
176
|
+
#ifndef CPPHTTPLIB_RECV_FLAGS
|
|
177
|
+
#define CPPHTTPLIB_RECV_FLAGS 0
|
|
178
|
+
#endif
|
|
179
|
+
|
|
180
|
+
#ifndef CPPHTTPLIB_SEND_FLAGS
|
|
181
|
+
#define CPPHTTPLIB_SEND_FLAGS 0
|
|
182
|
+
#endif
|
|
183
|
+
|
|
184
|
+
#ifndef CPPHTTPLIB_LISTEN_BACKLOG
|
|
185
|
+
#define CPPHTTPLIB_LISTEN_BACKLOG 5
|
|
186
|
+
#endif
|
|
187
|
+
|
|
188
|
+
#ifndef CPPHTTPLIB_MAX_LINE_LENGTH
|
|
189
|
+
#define CPPHTTPLIB_MAX_LINE_LENGTH 32768
|
|
190
|
+
#endif
|
|
191
|
+
|
|
192
|
+
#ifndef CPPHTTPLIB_WEBSOCKET_MAX_PAYLOAD_LENGTH
|
|
193
|
+
#define CPPHTTPLIB_WEBSOCKET_MAX_PAYLOAD_LENGTH 16777216
|
|
194
|
+
#endif
|
|
195
|
+
|
|
196
|
+
#ifndef CPPHTTPLIB_WEBSOCKET_READ_TIMEOUT_SECOND
|
|
197
|
+
#define CPPHTTPLIB_WEBSOCKET_READ_TIMEOUT_SECOND 300
|
|
198
|
+
#endif
|
|
199
|
+
|
|
200
|
+
#ifndef CPPHTTPLIB_WEBSOCKET_CLOSE_TIMEOUT_SECOND
|
|
201
|
+
#define CPPHTTPLIB_WEBSOCKET_CLOSE_TIMEOUT_SECOND 5
|
|
202
|
+
#endif
|
|
203
|
+
|
|
204
|
+
#ifndef CPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECOND
|
|
205
|
+
#define CPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECOND 30
|
|
206
|
+
#endif
|
|
207
|
+
|
|
208
|
+
/*
|
|
209
|
+
* Headers
|
|
210
|
+
*/
|
|
211
|
+
|
|
212
|
+
#ifdef _WIN32
|
|
213
|
+
#ifndef _CRT_SECURE_NO_WARNINGS
|
|
214
|
+
#define _CRT_SECURE_NO_WARNINGS
|
|
215
|
+
#endif //_CRT_SECURE_NO_WARNINGS
|
|
216
|
+
|
|
217
|
+
#ifndef _CRT_NONSTDC_NO_DEPRECATE
|
|
218
|
+
#define _CRT_NONSTDC_NO_DEPRECATE
|
|
219
|
+
#endif //_CRT_NONSTDC_NO_DEPRECATE
|
|
220
|
+
|
|
221
|
+
#if defined(_MSC_VER)
|
|
222
|
+
#if _MSC_VER < 1900
|
|
223
|
+
#error Sorry, Visual Studio versions prior to 2015 are not supported
|
|
224
|
+
#endif
|
|
225
|
+
|
|
226
|
+
#pragma comment(lib, "ws2_32.lib")
|
|
227
|
+
|
|
228
|
+
#ifndef _SSIZE_T_DEFINED
|
|
229
|
+
using ssize_t = __int64;
|
|
230
|
+
#define _SSIZE_T_DEFINED
|
|
231
|
+
#endif
|
|
232
|
+
#endif // _MSC_VER
|
|
233
|
+
|
|
234
|
+
#ifndef S_ISREG
|
|
235
|
+
#define S_ISREG(m) (((m) & S_IFREG) == S_IFREG)
|
|
236
|
+
#endif // S_ISREG
|
|
237
|
+
|
|
238
|
+
#ifndef S_ISDIR
|
|
239
|
+
#define S_ISDIR(m) (((m) & S_IFDIR) == S_IFDIR)
|
|
240
|
+
#endif // S_ISDIR
|
|
241
|
+
|
|
242
|
+
#ifndef NOMINMAX
|
|
243
|
+
#define NOMINMAX
|
|
244
|
+
#endif // NOMINMAX
|
|
245
|
+
|
|
246
|
+
#include <io.h>
|
|
247
|
+
#include <winsock2.h>
|
|
248
|
+
#include <ws2tcpip.h>
|
|
249
|
+
|
|
250
|
+
#if defined(__has_include)
|
|
251
|
+
#if __has_include(<afunix.h>)
|
|
252
|
+
// afunix.h uses types declared in winsock2.h, so has to be included after it.
|
|
253
|
+
#include <afunix.h>
|
|
254
|
+
#define CPPHTTPLIB_HAVE_AFUNIX_H 1
|
|
255
|
+
#endif
|
|
256
|
+
#endif
|
|
257
|
+
|
|
258
|
+
#ifndef WSA_FLAG_NO_HANDLE_INHERIT
|
|
259
|
+
#define WSA_FLAG_NO_HANDLE_INHERIT 0x80
|
|
260
|
+
#endif
|
|
261
|
+
|
|
262
|
+
using nfds_t = unsigned long;
|
|
263
|
+
using socket_t = SOCKET;
|
|
264
|
+
using socklen_t = int;
|
|
265
|
+
|
|
266
|
+
#else // not _WIN32
|
|
267
|
+
|
|
268
|
+
#include <arpa/inet.h>
|
|
269
|
+
#if !defined(_AIX) && !defined(__MVS__)
|
|
270
|
+
#include <ifaddrs.h>
|
|
271
|
+
#endif
|
|
272
|
+
#ifdef __MVS__
|
|
273
|
+
#include <strings.h>
|
|
274
|
+
#ifndef NI_MAXHOST
|
|
275
|
+
#define NI_MAXHOST 1025
|
|
276
|
+
#endif
|
|
277
|
+
#endif
|
|
278
|
+
#include <net/if.h>
|
|
279
|
+
#include <netdb.h>
|
|
280
|
+
#include <netinet/in.h>
|
|
281
|
+
#ifdef __linux__
|
|
282
|
+
#include <resolv.h>
|
|
283
|
+
#undef _res // Undefine _res macro to avoid conflicts with user code (#2278)
|
|
284
|
+
#endif
|
|
285
|
+
#include <csignal>
|
|
286
|
+
#include <netinet/tcp.h>
|
|
287
|
+
#include <poll.h>
|
|
288
|
+
#include <pthread.h>
|
|
289
|
+
#include <sys/mman.h>
|
|
290
|
+
#include <sys/socket.h>
|
|
291
|
+
#include <sys/un.h>
|
|
292
|
+
#include <unistd.h>
|
|
293
|
+
|
|
294
|
+
using socket_t = int;
|
|
295
|
+
#ifndef INVALID_SOCKET
|
|
296
|
+
#define INVALID_SOCKET (-1)
|
|
297
|
+
#endif
|
|
298
|
+
#endif //_WIN32
|
|
299
|
+
|
|
300
|
+
#if defined(__APPLE__)
|
|
301
|
+
#include <TargetConditionals.h>
|
|
302
|
+
#endif
|
|
303
|
+
|
|
304
|
+
#include <algorithm>
|
|
305
|
+
#include <array>
|
|
306
|
+
#include <atomic>
|
|
307
|
+
#include <cassert>
|
|
308
|
+
#include <cctype>
|
|
309
|
+
#include <chrono>
|
|
310
|
+
#include <climits>
|
|
311
|
+
#include <condition_variable>
|
|
312
|
+
#include <cstdlib>
|
|
313
|
+
#include <cstring>
|
|
314
|
+
#include <errno.h>
|
|
315
|
+
#include <exception>
|
|
316
|
+
#include <fcntl.h>
|
|
317
|
+
#include <fstream>
|
|
318
|
+
#include <functional>
|
|
319
|
+
#include <iomanip>
|
|
320
|
+
#include <iostream>
|
|
321
|
+
#include <list>
|
|
322
|
+
#include <map>
|
|
323
|
+
#include <memory>
|
|
324
|
+
#include <mutex>
|
|
325
|
+
#include <random>
|
|
326
|
+
#include <regex>
|
|
327
|
+
#include <set>
|
|
328
|
+
#include <sstream>
|
|
329
|
+
#include <string>
|
|
330
|
+
#include <sys/stat.h>
|
|
331
|
+
#include <system_error>
|
|
332
|
+
#include <thread>
|
|
333
|
+
#include <unordered_map>
|
|
334
|
+
#include <unordered_set>
|
|
335
|
+
#include <utility>
|
|
336
|
+
#if __cplusplus >= 201703L
|
|
337
|
+
#include <any>
|
|
338
|
+
#endif
|
|
339
|
+
|
|
340
|
+
// On macOS with a TLS backend, enable Keychain root certificates by default
|
|
341
|
+
// unless the user explicitly opts out.
|
|
342
|
+
#if defined(__APPLE__) && \
|
|
343
|
+
!defined(CPPHTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES) && \
|
|
344
|
+
(defined(CPPHTTPLIB_OPENSSL_SUPPORT) || \
|
|
345
|
+
defined(CPPHTTPLIB_MBEDTLS_SUPPORT) || \
|
|
346
|
+
defined(CPPHTTPLIB_WOLFSSL_SUPPORT))
|
|
347
|
+
#ifndef CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN
|
|
348
|
+
#define CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN
|
|
349
|
+
#endif
|
|
350
|
+
#endif
|
|
351
|
+
|
|
352
|
+
// On Windows, enable Schannel certificate verification by default
|
|
353
|
+
// unless the user explicitly opts out.
|
|
354
|
+
#if defined(_WIN32) && \
|
|
355
|
+
!defined(CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE)
|
|
356
|
+
#define CPPHTTPLIB_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
|
|
357
|
+
#endif
|
|
358
|
+
|
|
359
|
+
#if defined(CPPHTTPLIB_USE_NON_BLOCKING_GETADDRINFO) || \
|
|
360
|
+
defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN)
|
|
361
|
+
#if TARGET_OS_MAC
|
|
362
|
+
#include <CFNetwork/CFHost.h>
|
|
363
|
+
#include <CoreFoundation/CoreFoundation.h>
|
|
364
|
+
#endif
|
|
365
|
+
#endif
|
|
366
|
+
|
|
367
|
+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
|
368
|
+
#ifdef _WIN32
|
|
369
|
+
#include <wincrypt.h>
|
|
370
|
+
|
|
371
|
+
// these are defined in wincrypt.h and it breaks compilation if BoringSSL is
|
|
372
|
+
// used
|
|
373
|
+
#undef X509_NAME
|
|
374
|
+
#undef X509_CERT_PAIR
|
|
375
|
+
#undef X509_EXTENSIONS
|
|
376
|
+
#undef PKCS7_SIGNER_INFO
|
|
377
|
+
|
|
378
|
+
#ifdef _MSC_VER
|
|
379
|
+
#pragma comment(lib, "crypt32.lib")
|
|
380
|
+
#endif
|
|
381
|
+
#endif // _WIN32
|
|
382
|
+
|
|
383
|
+
#ifdef CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN
|
|
384
|
+
#if TARGET_OS_MAC
|
|
385
|
+
#include <Security/Security.h>
|
|
386
|
+
#endif
|
|
387
|
+
#endif
|
|
388
|
+
|
|
389
|
+
#include <openssl/err.h>
|
|
390
|
+
#include <openssl/evp.h>
|
|
391
|
+
#include <openssl/ssl.h>
|
|
392
|
+
#include <openssl/x509v3.h>
|
|
393
|
+
|
|
394
|
+
#if defined(_WIN32) && defined(OPENSSL_USE_APPLINK)
|
|
395
|
+
#include <openssl/applink.c>
|
|
396
|
+
#endif
|
|
397
|
+
|
|
398
|
+
#include <iostream>
|
|
399
|
+
#include <sstream>
|
|
400
|
+
|
|
401
|
+
#if defined(OPENSSL_IS_BORINGSSL) || defined(LIBRESSL_VERSION_NUMBER)
|
|
402
|
+
#if OPENSSL_VERSION_NUMBER < 0x1010107f
|
|
403
|
+
#error Please use OpenSSL or a current version of BoringSSL
|
|
404
|
+
#endif
|
|
405
|
+
#define SSL_get1_peer_certificate SSL_get_peer_certificate
|
|
406
|
+
#elif OPENSSL_VERSION_NUMBER < 0x30000000L
|
|
407
|
+
#error Sorry, OpenSSL versions prior to 3.0.0 are not supported
|
|
408
|
+
#endif
|
|
409
|
+
|
|
410
|
+
#endif // CPPHTTPLIB_OPENSSL_SUPPORT
|
|
411
|
+
|
|
412
|
+
#ifdef CPPHTTPLIB_MBEDTLS_SUPPORT
|
|
413
|
+
#include <mbedtls/ctr_drbg.h>
|
|
414
|
+
#include <mbedtls/entropy.h>
|
|
415
|
+
#include <mbedtls/error.h>
|
|
416
|
+
#include <mbedtls/md5.h>
|
|
417
|
+
#include <mbedtls/net_sockets.h>
|
|
418
|
+
#include <mbedtls/oid.h>
|
|
419
|
+
#include <mbedtls/pk.h>
|
|
420
|
+
#include <mbedtls/sha1.h>
|
|
421
|
+
#include <mbedtls/sha256.h>
|
|
422
|
+
#include <mbedtls/sha512.h>
|
|
423
|
+
#include <mbedtls/ssl.h>
|
|
424
|
+
#include <mbedtls/x509_crt.h>
|
|
425
|
+
#ifdef _WIN32
|
|
426
|
+
#include <wincrypt.h>
|
|
427
|
+
#ifdef _MSC_VER
|
|
428
|
+
#pragma comment(lib, "crypt32.lib")
|
|
429
|
+
#endif
|
|
430
|
+
#endif // _WIN32
|
|
431
|
+
#ifdef CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN
|
|
432
|
+
#if TARGET_OS_MAC
|
|
433
|
+
#include <Security/Security.h>
|
|
434
|
+
#endif
|
|
435
|
+
#endif
|
|
436
|
+
|
|
437
|
+
// Mbed TLS 3.x API compatibility
|
|
438
|
+
#if MBEDTLS_VERSION_MAJOR >= 3
|
|
439
|
+
#define CPPHTTPLIB_MBEDTLS_V3
|
|
440
|
+
#endif
|
|
441
|
+
|
|
442
|
+
#endif // CPPHTTPLIB_MBEDTLS_SUPPORT
|
|
443
|
+
|
|
444
|
+
#ifdef CPPHTTPLIB_WOLFSSL_SUPPORT
|
|
445
|
+
#include <wolfssl/options.h>
|
|
446
|
+
|
|
447
|
+
#include <wolfssl/openssl/x509v3.h>
|
|
448
|
+
|
|
449
|
+
// Fallback definitions for older wolfSSL versions (e.g., 5.6.6)
|
|
450
|
+
#ifndef WOLFSSL_GEN_EMAIL
|
|
451
|
+
#define WOLFSSL_GEN_EMAIL 1
|
|
452
|
+
#endif
|
|
453
|
+
#ifndef WOLFSSL_GEN_DNS
|
|
454
|
+
#define WOLFSSL_GEN_DNS 2
|
|
455
|
+
#endif
|
|
456
|
+
#ifndef WOLFSSL_GEN_URI
|
|
457
|
+
#define WOLFSSL_GEN_URI 6
|
|
458
|
+
#endif
|
|
459
|
+
#ifndef WOLFSSL_GEN_IPADD
|
|
460
|
+
#define WOLFSSL_GEN_IPADD 7
|
|
461
|
+
#endif
|
|
462
|
+
|
|
463
|
+
#include <wolfssl/ssl.h>
|
|
464
|
+
#include <wolfssl/wolfcrypt/hash.h>
|
|
465
|
+
#include <wolfssl/wolfcrypt/md5.h>
|
|
466
|
+
#include <wolfssl/wolfcrypt/sha256.h>
|
|
467
|
+
#include <wolfssl/wolfcrypt/sha512.h>
|
|
468
|
+
#ifdef _WIN32
|
|
469
|
+
#include <wincrypt.h>
|
|
470
|
+
#ifdef _MSC_VER
|
|
471
|
+
#pragma comment(lib, "crypt32.lib")
|
|
472
|
+
#endif
|
|
473
|
+
#endif // _WIN32
|
|
474
|
+
#ifdef CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN
|
|
475
|
+
#if TARGET_OS_MAC
|
|
476
|
+
#include <Security/Security.h>
|
|
477
|
+
#endif
|
|
478
|
+
#endif
|
|
479
|
+
#endif // CPPHTTPLIB_WOLFSSL_SUPPORT
|
|
480
|
+
|
|
481
|
+
// Define CPPHTTPLIB_SSL_ENABLED if any SSL backend is available
|
|
482
|
+
#if defined(CPPHTTPLIB_OPENSSL_SUPPORT) || \
|
|
483
|
+
defined(CPPHTTPLIB_MBEDTLS_SUPPORT) || defined(CPPHTTPLIB_WOLFSSL_SUPPORT)
|
|
484
|
+
#define CPPHTTPLIB_SSL_ENABLED
|
|
485
|
+
#endif
|
|
486
|
+
|
|
487
|
+
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
|
488
|
+
#include <zlib.h>
|
|
489
|
+
#endif
|
|
490
|
+
|
|
491
|
+
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
|
492
|
+
#include <brotli/decode.h>
|
|
493
|
+
#include <brotli/encode.h>
|
|
494
|
+
#endif
|
|
495
|
+
|
|
496
|
+
#ifdef CPPHTTPLIB_ZSTD_SUPPORT
|
|
497
|
+
#include <zstd.h>
|
|
498
|
+
#endif
|
|
499
|
+
|
|
500
|
+
/*
|
|
501
|
+
* Declaration
|
|
502
|
+
*/
|
|
503
|
+
namespace httplib {
|
|
504
|
+
|
|
505
|
+
namespace ws {
|
|
506
|
+
class WebSocket;
|
|
507
|
+
} // namespace ws
|
|
508
|
+
|
|
509
|
+
namespace detail {
|
|
510
|
+
|
|
511
|
+
/*
|
|
512
|
+
* Backport std::make_unique from C++14.
|
|
513
|
+
*
|
|
514
|
+
* NOTE: This code came up with the following stackoverflow post:
|
|
515
|
+
* https://stackoverflow.com/questions/10149840/c-arrays-and-make-unique
|
|
516
|
+
*
|
|
517
|
+
*/
|
|
518
|
+
|
|
519
|
+
template <class T, class... Args>
|
|
520
|
+
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
|
521
|
+
make_unique(Args &&...args) {
|
|
522
|
+
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
template <class T>
|
|
526
|
+
typename std::enable_if<std::is_array<T>::value, std::unique_ptr<T>>::type
|
|
527
|
+
make_unique(std::size_t n) {
|
|
528
|
+
typedef typename std::remove_extent<T>::type RT;
|
|
529
|
+
return std::unique_ptr<T>(new RT[n]);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
namespace case_ignore {
|
|
533
|
+
|
|
534
|
+
inline unsigned char to_lower(int c) {
|
|
535
|
+
const static unsigned char table[256] = {
|
|
536
|
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
|
537
|
+
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
|
538
|
+
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
|
|
539
|
+
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
|
|
540
|
+
60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
|
|
541
|
+
107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
|
|
542
|
+
122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
|
|
543
|
+
105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
|
|
544
|
+
120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
|
|
545
|
+
135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
|
|
546
|
+
150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
|
|
547
|
+
165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
|
|
548
|
+
180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 224, 225, 226,
|
|
549
|
+
227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
|
|
550
|
+
242, 243, 244, 245, 246, 215, 248, 249, 250, 251, 252, 253, 254, 223, 224,
|
|
551
|
+
225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
|
|
552
|
+
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
|
|
553
|
+
255,
|
|
554
|
+
};
|
|
555
|
+
return table[(unsigned char)(char)c];
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
inline std::string to_lower(const std::string &s) {
|
|
559
|
+
std::string result = s;
|
|
560
|
+
std::transform(
|
|
561
|
+
result.begin(), result.end(), result.begin(),
|
|
562
|
+
[](unsigned char c) { return static_cast<char>(to_lower(c)); });
|
|
563
|
+
return result;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
inline bool equal(const std::string &a, const std::string &b) {
|
|
567
|
+
return a.size() == b.size() &&
|
|
568
|
+
std::equal(a.begin(), a.end(), b.begin(), [](char ca, char cb) {
|
|
569
|
+
return to_lower(ca) == to_lower(cb);
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
struct equal_to {
|
|
574
|
+
bool operator()(const std::string &a, const std::string &b) const {
|
|
575
|
+
return equal(a, b);
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
struct hash {
|
|
580
|
+
size_t operator()(const std::string &key) const {
|
|
581
|
+
return hash_core(key.data(), key.size(), 0);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
size_t hash_core(const char *s, size_t l, size_t h) const {
|
|
585
|
+
return (l == 0) ? h
|
|
586
|
+
: hash_core(s + 1, l - 1,
|
|
587
|
+
// Unsets the 6 high bits of h, therefore no
|
|
588
|
+
// overflow happens
|
|
589
|
+
(((std::numeric_limits<size_t>::max)() >> 6) &
|
|
590
|
+
h * 33) ^
|
|
591
|
+
static_cast<unsigned char>(to_lower(*s)));
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
template <typename T>
|
|
596
|
+
using unordered_set = std::unordered_set<T, detail::case_ignore::hash,
|
|
597
|
+
detail::case_ignore::equal_to>;
|
|
598
|
+
|
|
599
|
+
} // namespace case_ignore
|
|
600
|
+
|
|
601
|
+
// This is based on
|
|
602
|
+
// "http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4189".
|
|
603
|
+
|
|
604
|
+
struct scope_exit {
|
|
605
|
+
explicit scope_exit(std::function<void(void)> &&f)
|
|
606
|
+
: exit_function(std::move(f)), execute_on_destruction{true} {}
|
|
607
|
+
|
|
608
|
+
scope_exit(scope_exit &&rhs) noexcept
|
|
609
|
+
: exit_function(std::move(rhs.exit_function)),
|
|
610
|
+
execute_on_destruction{rhs.execute_on_destruction} {
|
|
611
|
+
rhs.release();
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
~scope_exit() {
|
|
615
|
+
if (execute_on_destruction) { this->exit_function(); }
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
void release() { this->execute_on_destruction = false; }
|
|
619
|
+
|
|
620
|
+
private:
|
|
621
|
+
scope_exit(const scope_exit &) = delete;
|
|
622
|
+
void operator=(const scope_exit &) = delete;
|
|
623
|
+
scope_exit &operator=(scope_exit &&) = delete;
|
|
624
|
+
|
|
625
|
+
std::function<void(void)> exit_function;
|
|
626
|
+
bool execute_on_destruction;
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
// Simple from_chars implementation for integer and double types (C++17
|
|
630
|
+
// substitute)
|
|
631
|
+
template <typename T> struct from_chars_result {
|
|
632
|
+
const char *ptr;
|
|
633
|
+
std::errc ec;
|
|
634
|
+
};
|
|
635
|
+
|
|
636
|
+
template <typename T>
|
|
637
|
+
inline from_chars_result<T> from_chars(const char *first, const char *last,
|
|
638
|
+
T &value, int base = 10) {
|
|
639
|
+
value = 0;
|
|
640
|
+
const char *p = first;
|
|
641
|
+
bool negative = false;
|
|
642
|
+
|
|
643
|
+
if (p != last && *p == '-') {
|
|
644
|
+
negative = true;
|
|
645
|
+
++p;
|
|
646
|
+
}
|
|
647
|
+
if (p == last) { return {first, std::errc::invalid_argument}; }
|
|
648
|
+
|
|
649
|
+
T result = 0;
|
|
650
|
+
for (; p != last; ++p) {
|
|
651
|
+
char c = *p;
|
|
652
|
+
int digit = -1;
|
|
653
|
+
if ('0' <= c && c <= '9') {
|
|
654
|
+
digit = c - '0';
|
|
655
|
+
} else if ('a' <= c && c <= 'z') {
|
|
656
|
+
digit = c - 'a' + 10;
|
|
657
|
+
} else if ('A' <= c && c <= 'Z') {
|
|
658
|
+
digit = c - 'A' + 10;
|
|
659
|
+
} else {
|
|
660
|
+
break;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
if (digit < 0 || digit >= base) { break; }
|
|
664
|
+
if (result > ((std::numeric_limits<T>::max)() - digit) / base) {
|
|
665
|
+
return {p, std::errc::result_out_of_range};
|
|
666
|
+
}
|
|
667
|
+
result = result * base + digit;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
if (p == first || (negative && p == first + 1)) {
|
|
671
|
+
return {first, std::errc::invalid_argument};
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
value = negative ? -result : result;
|
|
675
|
+
return {p, std::errc{}};
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// from_chars for double (simple wrapper for strtod)
|
|
679
|
+
inline from_chars_result<double> from_chars(const char *first, const char *last,
|
|
680
|
+
double &value) {
|
|
681
|
+
std::string s(first, last);
|
|
682
|
+
char *endptr = nullptr;
|
|
683
|
+
errno = 0;
|
|
684
|
+
value = std::strtod(s.c_str(), &endptr);
|
|
685
|
+
if (endptr == s.c_str()) { return {first, std::errc::invalid_argument}; }
|
|
686
|
+
if (errno == ERANGE) {
|
|
687
|
+
return {first + (endptr - s.c_str()), std::errc::result_out_of_range};
|
|
688
|
+
}
|
|
689
|
+
return {first + (endptr - s.c_str()), std::errc{}};
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
inline bool parse_port(const char *s, size_t len, int &port) {
|
|
693
|
+
int val = 0;
|
|
694
|
+
auto r = from_chars(s, s + len, val);
|
|
695
|
+
if (r.ec != std::errc{} || val < 1 || val > 65535) { return false; }
|
|
696
|
+
port = val;
|
|
697
|
+
return true;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
inline bool parse_port(const std::string &s, int &port) {
|
|
701
|
+
return parse_port(s.data(), s.size(), port);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
} // namespace detail
|
|
705
|
+
|
|
706
|
+
enum SSLVerifierResponse {
|
|
707
|
+
// no decision has been made, use the built-in certificate verifier
|
|
708
|
+
NoDecisionMade,
|
|
709
|
+
// connection certificate is verified and accepted
|
|
710
|
+
CertificateAccepted,
|
|
711
|
+
// connection certificate was processed but is rejected
|
|
712
|
+
CertificateRejected
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
enum StatusCode {
|
|
716
|
+
// Information responses
|
|
717
|
+
Continue_100 = 100,
|
|
718
|
+
SwitchingProtocol_101 = 101,
|
|
719
|
+
Processing_102 = 102,
|
|
720
|
+
EarlyHints_103 = 103,
|
|
721
|
+
|
|
722
|
+
// Successful responses
|
|
723
|
+
OK_200 = 200,
|
|
724
|
+
Created_201 = 201,
|
|
725
|
+
Accepted_202 = 202,
|
|
726
|
+
NonAuthoritativeInformation_203 = 203,
|
|
727
|
+
NoContent_204 = 204,
|
|
728
|
+
ResetContent_205 = 205,
|
|
729
|
+
PartialContent_206 = 206,
|
|
730
|
+
MultiStatus_207 = 207,
|
|
731
|
+
AlreadyReported_208 = 208,
|
|
732
|
+
IMUsed_226 = 226,
|
|
733
|
+
|
|
734
|
+
// Redirection messages
|
|
735
|
+
MultipleChoices_300 = 300,
|
|
736
|
+
MovedPermanently_301 = 301,
|
|
737
|
+
Found_302 = 302,
|
|
738
|
+
SeeOther_303 = 303,
|
|
739
|
+
NotModified_304 = 304,
|
|
740
|
+
UseProxy_305 = 305,
|
|
741
|
+
unused_306 = 306,
|
|
742
|
+
TemporaryRedirect_307 = 307,
|
|
743
|
+
PermanentRedirect_308 = 308,
|
|
744
|
+
|
|
745
|
+
// Client error responses
|
|
746
|
+
BadRequest_400 = 400,
|
|
747
|
+
Unauthorized_401 = 401,
|
|
748
|
+
PaymentRequired_402 = 402,
|
|
749
|
+
Forbidden_403 = 403,
|
|
750
|
+
NotFound_404 = 404,
|
|
751
|
+
MethodNotAllowed_405 = 405,
|
|
752
|
+
NotAcceptable_406 = 406,
|
|
753
|
+
ProxyAuthenticationRequired_407 = 407,
|
|
754
|
+
RequestTimeout_408 = 408,
|
|
755
|
+
Conflict_409 = 409,
|
|
756
|
+
Gone_410 = 410,
|
|
757
|
+
LengthRequired_411 = 411,
|
|
758
|
+
PreconditionFailed_412 = 412,
|
|
759
|
+
PayloadTooLarge_413 = 413,
|
|
760
|
+
UriTooLong_414 = 414,
|
|
761
|
+
UnsupportedMediaType_415 = 415,
|
|
762
|
+
RangeNotSatisfiable_416 = 416,
|
|
763
|
+
ExpectationFailed_417 = 417,
|
|
764
|
+
ImATeapot_418 = 418,
|
|
765
|
+
MisdirectedRequest_421 = 421,
|
|
766
|
+
UnprocessableContent_422 = 422,
|
|
767
|
+
Locked_423 = 423,
|
|
768
|
+
FailedDependency_424 = 424,
|
|
769
|
+
TooEarly_425 = 425,
|
|
770
|
+
UpgradeRequired_426 = 426,
|
|
771
|
+
PreconditionRequired_428 = 428,
|
|
772
|
+
TooManyRequests_429 = 429,
|
|
773
|
+
RequestHeaderFieldsTooLarge_431 = 431,
|
|
774
|
+
UnavailableForLegalReasons_451 = 451,
|
|
775
|
+
|
|
776
|
+
// Server error responses
|
|
777
|
+
InternalServerError_500 = 500,
|
|
778
|
+
NotImplemented_501 = 501,
|
|
779
|
+
BadGateway_502 = 502,
|
|
780
|
+
ServiceUnavailable_503 = 503,
|
|
781
|
+
GatewayTimeout_504 = 504,
|
|
782
|
+
HttpVersionNotSupported_505 = 505,
|
|
783
|
+
VariantAlsoNegotiates_506 = 506,
|
|
784
|
+
InsufficientStorage_507 = 507,
|
|
785
|
+
LoopDetected_508 = 508,
|
|
786
|
+
NotExtended_510 = 510,
|
|
787
|
+
NetworkAuthenticationRequired_511 = 511,
|
|
788
|
+
};
|
|
789
|
+
|
|
790
|
+
using Headers =
|
|
791
|
+
std::unordered_multimap<std::string, std::string, detail::case_ignore::hash,
|
|
792
|
+
detail::case_ignore::equal_to>;
|
|
793
|
+
|
|
794
|
+
using Params = std::multimap<std::string, std::string>;
|
|
795
|
+
using Match = std::smatch;
|
|
796
|
+
|
|
797
|
+
using DownloadProgress = std::function<bool(size_t current, size_t total)>;
|
|
798
|
+
using UploadProgress = std::function<bool(size_t current, size_t total)>;
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
#if __cplusplus >= 201703L
|
|
802
|
+
|
|
803
|
+
using any = std::any;
|
|
804
|
+
using bad_any_cast = std::bad_any_cast;
|
|
805
|
+
|
|
806
|
+
template <typename T> T any_cast(const any &a) { return std::any_cast<T>(a); }
|
|
807
|
+
template <typename T> T any_cast(any &a) { return std::any_cast<T>(a); }
|
|
808
|
+
template <typename T> T any_cast(any &&a) {
|
|
809
|
+
return std::any_cast<T>(std::move(a));
|
|
810
|
+
}
|
|
811
|
+
template <typename T> const T *any_cast(const any *a) noexcept {
|
|
812
|
+
return std::any_cast<T>(a);
|
|
813
|
+
}
|
|
814
|
+
template <typename T> T *any_cast(any *a) noexcept {
|
|
815
|
+
return std::any_cast<T>(a);
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
#else // C++11/14 implementation
|
|
819
|
+
|
|
820
|
+
class bad_any_cast : public std::bad_cast {
|
|
821
|
+
public:
|
|
822
|
+
const char *what() const noexcept override { return "bad any_cast"; }
|
|
823
|
+
};
|
|
824
|
+
|
|
825
|
+
namespace detail {
|
|
826
|
+
|
|
827
|
+
using any_type_id = const void *;
|
|
828
|
+
|
|
829
|
+
// Returns a unique per-type ID without RTTI.
|
|
830
|
+
// The static address is stable across TUs because function templates are
|
|
831
|
+
// implicitly inline and the ODR merges their statics into one.
|
|
832
|
+
template <typename T> any_type_id any_typeid() noexcept {
|
|
833
|
+
static const char id = 0;
|
|
834
|
+
return &id;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
struct any_storage {
|
|
838
|
+
virtual ~any_storage() = default;
|
|
839
|
+
virtual std::unique_ptr<any_storage> clone() const = 0;
|
|
840
|
+
virtual any_type_id type_id() const noexcept = 0;
|
|
841
|
+
};
|
|
842
|
+
|
|
843
|
+
template <typename T> struct any_value final : any_storage {
|
|
844
|
+
T value;
|
|
845
|
+
template <typename U> explicit any_value(U &&v) : value(std::forward<U>(v)) {}
|
|
846
|
+
std::unique_ptr<any_storage> clone() const override {
|
|
847
|
+
return std::unique_ptr<any_storage>(new any_value<T>(value));
|
|
848
|
+
}
|
|
849
|
+
any_type_id type_id() const noexcept override { return any_typeid<T>(); }
|
|
850
|
+
};
|
|
851
|
+
|
|
852
|
+
} // namespace detail
|
|
853
|
+
|
|
854
|
+
class any {
|
|
855
|
+
std::unique_ptr<detail::any_storage> storage_;
|
|
856
|
+
|
|
857
|
+
public:
|
|
858
|
+
any() noexcept = default;
|
|
859
|
+
any(const any &o) : storage_(o.storage_ ? o.storage_->clone() : nullptr) {}
|
|
860
|
+
any(any &&) noexcept = default;
|
|
861
|
+
any &operator=(const any &o) {
|
|
862
|
+
storage_ = o.storage_ ? o.storage_->clone() : nullptr;
|
|
863
|
+
return *this;
|
|
864
|
+
}
|
|
865
|
+
any &operator=(any &&) noexcept = default;
|
|
866
|
+
|
|
867
|
+
template <
|
|
868
|
+
typename T, typename D = typename std::decay<T>::type,
|
|
869
|
+
typename std::enable_if<!std::is_same<D, any>::value, int>::type = 0>
|
|
870
|
+
any(T &&v) : storage_(new detail::any_value<D>(std::forward<T>(v))) {}
|
|
871
|
+
|
|
872
|
+
template <
|
|
873
|
+
typename T, typename D = typename std::decay<T>::type,
|
|
874
|
+
typename std::enable_if<!std::is_same<D, any>::value, int>::type = 0>
|
|
875
|
+
any &operator=(T &&v) {
|
|
876
|
+
storage_.reset(new detail::any_value<D>(std::forward<T>(v)));
|
|
877
|
+
return *this;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
bool has_value() const noexcept { return storage_ != nullptr; }
|
|
881
|
+
void reset() noexcept { storage_.reset(); }
|
|
882
|
+
|
|
883
|
+
template <typename T> friend T *any_cast(any *a) noexcept;
|
|
884
|
+
template <typename T> friend const T *any_cast(const any *a) noexcept;
|
|
885
|
+
};
|
|
886
|
+
|
|
887
|
+
template <typename T> T *any_cast(any *a) noexcept {
|
|
888
|
+
if (!a || !a->storage_) { return nullptr; }
|
|
889
|
+
if (a->storage_->type_id() != detail::any_typeid<T>()) { return nullptr; }
|
|
890
|
+
return &static_cast<detail::any_value<T> *>(a->storage_.get())->value;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
template <typename T> const T *any_cast(const any *a) noexcept {
|
|
894
|
+
if (!a || !a->storage_) { return nullptr; }
|
|
895
|
+
if (a->storage_->type_id() != detail::any_typeid<T>()) { return nullptr; }
|
|
896
|
+
return &static_cast<const detail::any_value<T> *>(a->storage_.get())->value;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
template <typename T> T any_cast(const any &a) {
|
|
900
|
+
using U =
|
|
901
|
+
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
|
902
|
+
const U *p = any_cast<U>(&a);
|
|
903
|
+
#ifndef CPPHTTPLIB_NO_EXCEPTIONS
|
|
904
|
+
if (!p) { throw bad_any_cast{}; }
|
|
905
|
+
#else
|
|
906
|
+
if (!p) { std::abort(); }
|
|
907
|
+
#endif
|
|
908
|
+
return static_cast<T>(*p);
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
template <typename T> T any_cast(any &a) {
|
|
912
|
+
using U =
|
|
913
|
+
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
|
914
|
+
U *p = any_cast<U>(&a);
|
|
915
|
+
#ifndef CPPHTTPLIB_NO_EXCEPTIONS
|
|
916
|
+
if (!p) { throw bad_any_cast{}; }
|
|
917
|
+
#else
|
|
918
|
+
if (!p) { std::abort(); }
|
|
919
|
+
#endif
|
|
920
|
+
return static_cast<T>(*p);
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
template <typename T> T any_cast(any &&a) {
|
|
924
|
+
using U =
|
|
925
|
+
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
|
926
|
+
U *p = any_cast<U>(&a);
|
|
927
|
+
#ifndef CPPHTTPLIB_NO_EXCEPTIONS
|
|
928
|
+
if (!p) { throw bad_any_cast{}; }
|
|
929
|
+
#else
|
|
930
|
+
if (!p) { std::abort(); }
|
|
931
|
+
#endif
|
|
932
|
+
return static_cast<T>(std::move(*p));
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
#endif // __cplusplus >= 201703L
|
|
936
|
+
|
|
937
|
+
struct Response;
|
|
938
|
+
using ResponseHandler = std::function<bool(const Response &response)>;
|
|
939
|
+
|
|
940
|
+
struct FormData {
|
|
941
|
+
std::string name;
|
|
942
|
+
std::string content;
|
|
943
|
+
std::string filename;
|
|
944
|
+
std::string content_type;
|
|
945
|
+
Headers headers;
|
|
946
|
+
};
|
|
947
|
+
|
|
948
|
+
struct FormField {
|
|
949
|
+
std::string name;
|
|
950
|
+
std::string content;
|
|
951
|
+
Headers headers;
|
|
952
|
+
};
|
|
953
|
+
using FormFields = std::multimap<std::string, FormField>;
|
|
954
|
+
|
|
955
|
+
using FormFiles = std::multimap<std::string, FormData>;
|
|
956
|
+
|
|
957
|
+
struct MultipartFormData {
|
|
958
|
+
FormFields fields; // Text fields from multipart
|
|
959
|
+
FormFiles files; // Files from multipart
|
|
960
|
+
|
|
961
|
+
// Text field access
|
|
962
|
+
std::string get_field(const std::string &key, size_t id = 0) const;
|
|
963
|
+
std::vector<std::string> get_fields(const std::string &key) const;
|
|
964
|
+
bool has_field(const std::string &key) const;
|
|
965
|
+
size_t get_field_count(const std::string &key) const;
|
|
966
|
+
|
|
967
|
+
// File access
|
|
968
|
+
FormData get_file(const std::string &key, size_t id = 0) const;
|
|
969
|
+
std::vector<FormData> get_files(const std::string &key) const;
|
|
970
|
+
bool has_file(const std::string &key) const;
|
|
971
|
+
size_t get_file_count(const std::string &key) const;
|
|
972
|
+
};
|
|
973
|
+
|
|
974
|
+
struct UploadFormData {
|
|
975
|
+
std::string name;
|
|
976
|
+
std::string content;
|
|
977
|
+
std::string filename;
|
|
978
|
+
std::string content_type;
|
|
979
|
+
};
|
|
980
|
+
using UploadFormDataItems = std::vector<UploadFormData>;
|
|
981
|
+
|
|
982
|
+
class DataSink {
|
|
983
|
+
public:
|
|
984
|
+
DataSink() : os(&sb_), sb_(*this) {}
|
|
985
|
+
|
|
986
|
+
DataSink(const DataSink &) = delete;
|
|
987
|
+
DataSink &operator=(const DataSink &) = delete;
|
|
988
|
+
DataSink(DataSink &&) = delete;
|
|
989
|
+
DataSink &operator=(DataSink &&) = delete;
|
|
990
|
+
|
|
991
|
+
std::function<bool(const char *data, size_t data_len)> write;
|
|
992
|
+
std::function<bool()> is_writable;
|
|
993
|
+
std::function<void()> done;
|
|
994
|
+
std::function<void(const Headers &trailer)> done_with_trailer;
|
|
995
|
+
std::ostream os;
|
|
996
|
+
|
|
997
|
+
private:
|
|
998
|
+
class data_sink_streambuf final : public std::streambuf {
|
|
999
|
+
public:
|
|
1000
|
+
explicit data_sink_streambuf(DataSink &sink) : sink_(sink) {}
|
|
1001
|
+
|
|
1002
|
+
protected:
|
|
1003
|
+
std::streamsize xsputn(const char *s, std::streamsize n) override {
|
|
1004
|
+
if (sink_.write(s, static_cast<size_t>(n))) { return n; }
|
|
1005
|
+
return 0;
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
private:
|
|
1009
|
+
DataSink &sink_;
|
|
1010
|
+
};
|
|
1011
|
+
|
|
1012
|
+
data_sink_streambuf sb_;
|
|
1013
|
+
};
|
|
1014
|
+
|
|
1015
|
+
using ContentProvider =
|
|
1016
|
+
std::function<bool(size_t offset, size_t length, DataSink &sink)>;
|
|
1017
|
+
|
|
1018
|
+
using ContentProviderWithoutLength =
|
|
1019
|
+
std::function<bool(size_t offset, DataSink &sink)>;
|
|
1020
|
+
|
|
1021
|
+
using ContentProviderResourceReleaser = std::function<void(bool success)>;
|
|
1022
|
+
|
|
1023
|
+
struct FormDataProvider {
|
|
1024
|
+
std::string name;
|
|
1025
|
+
ContentProviderWithoutLength provider;
|
|
1026
|
+
std::string filename;
|
|
1027
|
+
std::string content_type;
|
|
1028
|
+
};
|
|
1029
|
+
using FormDataProviderItems = std::vector<FormDataProvider>;
|
|
1030
|
+
|
|
1031
|
+
inline FormDataProvider
|
|
1032
|
+
make_file_provider(const std::string &name, const std::string &filepath,
|
|
1033
|
+
const std::string &filename = std::string(),
|
|
1034
|
+
const std::string &content_type = std::string()) {
|
|
1035
|
+
FormDataProvider fdp;
|
|
1036
|
+
fdp.name = name;
|
|
1037
|
+
fdp.filename = filename.empty() ? filepath : filename;
|
|
1038
|
+
fdp.content_type = content_type;
|
|
1039
|
+
fdp.provider = [filepath](size_t offset, DataSink &sink) -> bool {
|
|
1040
|
+
std::ifstream f(filepath, std::ios::binary);
|
|
1041
|
+
if (!f) { return false; }
|
|
1042
|
+
if (offset > 0) {
|
|
1043
|
+
f.seekg(static_cast<std::streamoff>(offset));
|
|
1044
|
+
if (!f.good()) {
|
|
1045
|
+
sink.done();
|
|
1046
|
+
return true;
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
char buf[8192];
|
|
1050
|
+
f.read(buf, sizeof(buf));
|
|
1051
|
+
auto n = static_cast<size_t>(f.gcount());
|
|
1052
|
+
if (n > 0) { return sink.write(buf, n); }
|
|
1053
|
+
sink.done(); // EOF
|
|
1054
|
+
return true;
|
|
1055
|
+
};
|
|
1056
|
+
return fdp;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
inline std::pair<size_t, ContentProvider>
|
|
1060
|
+
make_file_body(const std::string &filepath) {
|
|
1061
|
+
size_t size = 0;
|
|
1062
|
+
{
|
|
1063
|
+
std::ifstream f(filepath, std::ios::binary | std::ios::ate);
|
|
1064
|
+
if (!f) { return {0, ContentProvider{}}; }
|
|
1065
|
+
size = static_cast<size_t>(f.tellg());
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
ContentProvider provider = [filepath](size_t offset, size_t length,
|
|
1069
|
+
DataSink &sink) -> bool {
|
|
1070
|
+
std::ifstream f(filepath, std::ios::binary);
|
|
1071
|
+
if (!f) { return false; }
|
|
1072
|
+
f.seekg(static_cast<std::streamoff>(offset));
|
|
1073
|
+
if (!f.good()) { return false; }
|
|
1074
|
+
char buf[8192];
|
|
1075
|
+
while (length > 0) {
|
|
1076
|
+
auto to_read = (std::min)(sizeof(buf), length);
|
|
1077
|
+
f.read(buf, static_cast<std::streamsize>(to_read));
|
|
1078
|
+
auto n = static_cast<size_t>(f.gcount());
|
|
1079
|
+
if (n == 0) { break; }
|
|
1080
|
+
if (!sink.write(buf, n)) { return false; }
|
|
1081
|
+
length -= n;
|
|
1082
|
+
}
|
|
1083
|
+
return true;
|
|
1084
|
+
};
|
|
1085
|
+
return {size, std::move(provider)};
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
using ContentReceiverWithProgress = std::function<bool(
|
|
1089
|
+
const char *data, size_t data_length, size_t offset, size_t total_length)>;
|
|
1090
|
+
|
|
1091
|
+
using ContentReceiver =
|
|
1092
|
+
std::function<bool(const char *data, size_t data_length)>;
|
|
1093
|
+
|
|
1094
|
+
using FormDataHeader = std::function<bool(const FormData &file)>;
|
|
1095
|
+
|
|
1096
|
+
class ContentReader {
|
|
1097
|
+
public:
|
|
1098
|
+
using Reader = std::function<bool(ContentReceiver receiver)>;
|
|
1099
|
+
using FormDataReader =
|
|
1100
|
+
std::function<bool(FormDataHeader header, ContentReceiver receiver)>;
|
|
1101
|
+
|
|
1102
|
+
ContentReader(Reader reader, FormDataReader multipart_reader)
|
|
1103
|
+
: reader_(std::move(reader)),
|
|
1104
|
+
formdata_reader_(std::move(multipart_reader)) {}
|
|
1105
|
+
|
|
1106
|
+
bool operator()(FormDataHeader header, ContentReceiver receiver) const {
|
|
1107
|
+
return formdata_reader_(std::move(header), std::move(receiver));
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
bool operator()(ContentReceiver receiver) const {
|
|
1111
|
+
return reader_(std::move(receiver));
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
Reader reader_;
|
|
1115
|
+
FormDataReader formdata_reader_;
|
|
1116
|
+
};
|
|
1117
|
+
|
|
1118
|
+
using Range = std::pair<ssize_t, ssize_t>;
|
|
1119
|
+
using Ranges = std::vector<Range>;
|
|
1120
|
+
|
|
1121
|
+
#ifdef CPPHTTPLIB_SSL_ENABLED
|
|
1122
|
+
// TLS abstraction layer - public type definitions and API
|
|
1123
|
+
namespace tls {
|
|
1124
|
+
|
|
1125
|
+
// Opaque handles (defined as void* for abstraction)
|
|
1126
|
+
using ctx_t = void *;
|
|
1127
|
+
using session_t = void *;
|
|
1128
|
+
using const_session_t = const void *; // For read-only session access
|
|
1129
|
+
using cert_t = void *;
|
|
1130
|
+
using ca_store_t = void *;
|
|
1131
|
+
|
|
1132
|
+
// TLS versions
|
|
1133
|
+
enum class Version {
|
|
1134
|
+
TLS1_2 = 0x0303,
|
|
1135
|
+
TLS1_3 = 0x0304,
|
|
1136
|
+
};
|
|
1137
|
+
|
|
1138
|
+
// Subject Alternative Names (SAN) entry types
|
|
1139
|
+
enum class SanType { DNS, IP, EMAIL, URI, OTHER };
|
|
1140
|
+
|
|
1141
|
+
// SAN entry structure
|
|
1142
|
+
struct SanEntry {
|
|
1143
|
+
SanType type;
|
|
1144
|
+
std::string value;
|
|
1145
|
+
};
|
|
1146
|
+
|
|
1147
|
+
// Verification context for certificate verification callback
|
|
1148
|
+
struct VerifyContext {
|
|
1149
|
+
session_t session; // TLS session handle
|
|
1150
|
+
cert_t cert; // Current certificate being verified
|
|
1151
|
+
int depth; // Certificate chain depth (0 = leaf)
|
|
1152
|
+
bool preverify_ok; // OpenSSL/Mbed TLS pre-verification result
|
|
1153
|
+
long error_code; // Backend-specific error code (0 = no error)
|
|
1154
|
+
const char *error_string; // Human-readable error description
|
|
1155
|
+
|
|
1156
|
+
// Certificate introspection methods
|
|
1157
|
+
std::string subject_cn() const;
|
|
1158
|
+
std::string issuer_name() const;
|
|
1159
|
+
bool check_hostname(const char *hostname) const;
|
|
1160
|
+
std::vector<SanEntry> sans() const;
|
|
1161
|
+
bool validity(time_t ¬_before, time_t ¬_after) const;
|
|
1162
|
+
std::string serial() const;
|
|
1163
|
+
};
|
|
1164
|
+
|
|
1165
|
+
using VerifyCallback = std::function<bool(const VerifyContext &ctx)>;
|
|
1166
|
+
|
|
1167
|
+
// TlsError codes for TLS operations (backend-independent)
|
|
1168
|
+
enum class ErrorCode : int {
|
|
1169
|
+
Success = 0,
|
|
1170
|
+
WantRead, // Non-blocking: need to wait for read
|
|
1171
|
+
WantWrite, // Non-blocking: need to wait for write
|
|
1172
|
+
PeerClosed, // Peer closed the connection
|
|
1173
|
+
Fatal, // Unrecoverable error
|
|
1174
|
+
SyscallError, // System call error (check sys_errno)
|
|
1175
|
+
CertVerifyFailed, // Certificate verification failed
|
|
1176
|
+
HostnameMismatch, // Hostname verification failed
|
|
1177
|
+
};
|
|
1178
|
+
|
|
1179
|
+
// TLS error information
|
|
1180
|
+
struct TlsError {
|
|
1181
|
+
ErrorCode code = ErrorCode::Fatal;
|
|
1182
|
+
uint64_t backend_code = 0; // OpenSSL: ERR_get_error(), mbedTLS: return value
|
|
1183
|
+
int sys_errno = 0; // errno when SyscallError
|
|
1184
|
+
|
|
1185
|
+
// Convert verification error code to human-readable string
|
|
1186
|
+
static std::string verify_error_to_string(long error_code);
|
|
1187
|
+
};
|
|
1188
|
+
|
|
1189
|
+
// RAII wrapper for peer certificate
|
|
1190
|
+
class PeerCert {
|
|
1191
|
+
public:
|
|
1192
|
+
PeerCert();
|
|
1193
|
+
PeerCert(PeerCert &&other) noexcept;
|
|
1194
|
+
PeerCert &operator=(PeerCert &&other) noexcept;
|
|
1195
|
+
~PeerCert();
|
|
1196
|
+
|
|
1197
|
+
PeerCert(const PeerCert &) = delete;
|
|
1198
|
+
PeerCert &operator=(const PeerCert &) = delete;
|
|
1199
|
+
|
|
1200
|
+
explicit operator bool() const;
|
|
1201
|
+
std::string subject_cn() const;
|
|
1202
|
+
std::string issuer_name() const;
|
|
1203
|
+
bool check_hostname(const char *hostname) const;
|
|
1204
|
+
std::vector<SanEntry> sans() const;
|
|
1205
|
+
bool validity(time_t ¬_before, time_t ¬_after) const;
|
|
1206
|
+
std::string serial() const;
|
|
1207
|
+
|
|
1208
|
+
private:
|
|
1209
|
+
explicit PeerCert(cert_t cert);
|
|
1210
|
+
cert_t cert_ = nullptr;
|
|
1211
|
+
friend PeerCert get_peer_cert_from_session(const_session_t session);
|
|
1212
|
+
};
|
|
1213
|
+
|
|
1214
|
+
// Callback for TLS context setup (used by SSLServer constructor)
|
|
1215
|
+
using ContextSetupCallback = std::function<bool(ctx_t ctx)>;
|
|
1216
|
+
|
|
1217
|
+
} // namespace tls
|
|
1218
|
+
#endif
|
|
1219
|
+
|
|
1220
|
+
struct Request {
|
|
1221
|
+
std::string method;
|
|
1222
|
+
std::string path;
|
|
1223
|
+
std::string matched_route;
|
|
1224
|
+
Params params;
|
|
1225
|
+
Headers headers;
|
|
1226
|
+
Headers trailers;
|
|
1227
|
+
std::string body;
|
|
1228
|
+
|
|
1229
|
+
std::string remote_addr;
|
|
1230
|
+
int remote_port = -1;
|
|
1231
|
+
std::string local_addr;
|
|
1232
|
+
int local_port = -1;
|
|
1233
|
+
|
|
1234
|
+
// for server
|
|
1235
|
+
std::string version;
|
|
1236
|
+
std::string target;
|
|
1237
|
+
MultipartFormData form;
|
|
1238
|
+
Ranges ranges;
|
|
1239
|
+
Match matches;
|
|
1240
|
+
std::unordered_map<std::string, std::string> path_params;
|
|
1241
|
+
std::function<bool()> is_connection_closed = []() { return true; };
|
|
1242
|
+
|
|
1243
|
+
// for client
|
|
1244
|
+
std::vector<std::string> accept_content_types;
|
|
1245
|
+
ResponseHandler response_handler;
|
|
1246
|
+
ContentReceiverWithProgress content_receiver;
|
|
1247
|
+
DownloadProgress download_progress;
|
|
1248
|
+
UploadProgress upload_progress;
|
|
1249
|
+
|
|
1250
|
+
bool has_header(const std::string &key) const;
|
|
1251
|
+
std::string get_header_value(const std::string &key, const char *def = "",
|
|
1252
|
+
size_t id = 0) const;
|
|
1253
|
+
size_t get_header_value_u64(const std::string &key, size_t def = 0,
|
|
1254
|
+
size_t id = 0) const;
|
|
1255
|
+
size_t get_header_value_count(const std::string &key) const;
|
|
1256
|
+
void set_header(const std::string &key, const std::string &val);
|
|
1257
|
+
|
|
1258
|
+
bool has_trailer(const std::string &key) const;
|
|
1259
|
+
std::string get_trailer_value(const std::string &key, size_t id = 0) const;
|
|
1260
|
+
size_t get_trailer_value_count(const std::string &key) const;
|
|
1261
|
+
|
|
1262
|
+
bool has_param(const std::string &key) const;
|
|
1263
|
+
std::string get_param_value(const std::string &key, size_t id = 0) const;
|
|
1264
|
+
size_t get_param_value_count(const std::string &key) const;
|
|
1265
|
+
|
|
1266
|
+
bool is_multipart_form_data() const;
|
|
1267
|
+
|
|
1268
|
+
// private members...
|
|
1269
|
+
bool body_consumed_ = false;
|
|
1270
|
+
size_t redirect_count_ = CPPHTTPLIB_REDIRECT_MAX_COUNT;
|
|
1271
|
+
size_t content_length_ = 0;
|
|
1272
|
+
ContentProvider content_provider_;
|
|
1273
|
+
bool is_chunked_content_provider_ = false;
|
|
1274
|
+
size_t authorization_count_ = 0;
|
|
1275
|
+
std::chrono::time_point<std::chrono::steady_clock> start_time_ =
|
|
1276
|
+
(std::chrono::steady_clock::time_point::min)();
|
|
1277
|
+
|
|
1278
|
+
#ifdef CPPHTTPLIB_SSL_ENABLED
|
|
1279
|
+
tls::const_session_t ssl = nullptr;
|
|
1280
|
+
tls::PeerCert peer_cert() const;
|
|
1281
|
+
std::string sni() const;
|
|
1282
|
+
#endif
|
|
1283
|
+
};
|
|
1284
|
+
|
|
1285
|
+
struct Response {
|
|
1286
|
+
std::string version;
|
|
1287
|
+
int status = -1;
|
|
1288
|
+
std::string reason;
|
|
1289
|
+
Headers headers;
|
|
1290
|
+
Headers trailers;
|
|
1291
|
+
std::string body;
|
|
1292
|
+
std::string location; // Redirect location
|
|
1293
|
+
|
|
1294
|
+
// User-defined context — set by pre-routing/pre-request handlers and read
|
|
1295
|
+
// by route handlers to pass arbitrary data (e.g. decoded auth tokens).
|
|
1296
|
+
std::map<std::string, any> user_data;
|
|
1297
|
+
|
|
1298
|
+
bool has_header(const std::string &key) const;
|
|
1299
|
+
std::string get_header_value(const std::string &key, const char *def = "",
|
|
1300
|
+
size_t id = 0) const;
|
|
1301
|
+
size_t get_header_value_u64(const std::string &key, size_t def = 0,
|
|
1302
|
+
size_t id = 0) const;
|
|
1303
|
+
size_t get_header_value_count(const std::string &key) const;
|
|
1304
|
+
void set_header(const std::string &key, const std::string &val);
|
|
1305
|
+
|
|
1306
|
+
bool has_trailer(const std::string &key) const;
|
|
1307
|
+
std::string get_trailer_value(const std::string &key, size_t id = 0) const;
|
|
1308
|
+
size_t get_trailer_value_count(const std::string &key) const;
|
|
1309
|
+
|
|
1310
|
+
void set_redirect(const std::string &url, int status = StatusCode::Found_302);
|
|
1311
|
+
void set_content(const char *s, size_t n, const std::string &content_type);
|
|
1312
|
+
void set_content(const std::string &s, const std::string &content_type);
|
|
1313
|
+
void set_content(std::string &&s, const std::string &content_type);
|
|
1314
|
+
|
|
1315
|
+
void set_content_provider(
|
|
1316
|
+
size_t length, const std::string &content_type, ContentProvider provider,
|
|
1317
|
+
ContentProviderResourceReleaser resource_releaser = nullptr);
|
|
1318
|
+
|
|
1319
|
+
void set_content_provider(
|
|
1320
|
+
const std::string &content_type, ContentProviderWithoutLength provider,
|
|
1321
|
+
ContentProviderResourceReleaser resource_releaser = nullptr);
|
|
1322
|
+
|
|
1323
|
+
void set_chunked_content_provider(
|
|
1324
|
+
const std::string &content_type, ContentProviderWithoutLength provider,
|
|
1325
|
+
ContentProviderResourceReleaser resource_releaser = nullptr);
|
|
1326
|
+
|
|
1327
|
+
void set_file_content(const std::string &path,
|
|
1328
|
+
const std::string &content_type);
|
|
1329
|
+
void set_file_content(const std::string &path);
|
|
1330
|
+
|
|
1331
|
+
Response() = default;
|
|
1332
|
+
Response(const Response &) = default;
|
|
1333
|
+
Response &operator=(const Response &) = default;
|
|
1334
|
+
Response(Response &&) = default;
|
|
1335
|
+
Response &operator=(Response &&) = default;
|
|
1336
|
+
~Response() {
|
|
1337
|
+
if (content_provider_resource_releaser_) {
|
|
1338
|
+
content_provider_resource_releaser_(content_provider_success_);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
// private members...
|
|
1343
|
+
size_t content_length_ = 0;
|
|
1344
|
+
ContentProvider content_provider_;
|
|
1345
|
+
ContentProviderResourceReleaser content_provider_resource_releaser_;
|
|
1346
|
+
bool is_chunked_content_provider_ = false;
|
|
1347
|
+
bool content_provider_success_ = false;
|
|
1348
|
+
std::string file_content_path_;
|
|
1349
|
+
std::string file_content_content_type_;
|
|
1350
|
+
};
|
|
1351
|
+
|
|
1352
|
+
enum class Error {
|
|
1353
|
+
Success = 0,
|
|
1354
|
+
Unknown,
|
|
1355
|
+
Connection,
|
|
1356
|
+
BindIPAddress,
|
|
1357
|
+
Read,
|
|
1358
|
+
Write,
|
|
1359
|
+
ExceedRedirectCount,
|
|
1360
|
+
Canceled,
|
|
1361
|
+
SSLConnection,
|
|
1362
|
+
SSLLoadingCerts,
|
|
1363
|
+
SSLServerVerification,
|
|
1364
|
+
SSLServerHostnameVerification,
|
|
1365
|
+
UnsupportedMultipartBoundaryChars,
|
|
1366
|
+
Compression,
|
|
1367
|
+
ConnectionTimeout,
|
|
1368
|
+
ProxyConnection,
|
|
1369
|
+
ConnectionClosed,
|
|
1370
|
+
Timeout,
|
|
1371
|
+
ResourceExhaustion,
|
|
1372
|
+
TooManyFormDataFiles,
|
|
1373
|
+
ExceedMaxPayloadSize,
|
|
1374
|
+
ExceedUriMaxLength,
|
|
1375
|
+
ExceedMaxSocketDescriptorCount,
|
|
1376
|
+
InvalidRequestLine,
|
|
1377
|
+
InvalidHTTPMethod,
|
|
1378
|
+
InvalidHTTPVersion,
|
|
1379
|
+
InvalidHeaders,
|
|
1380
|
+
MultipartParsing,
|
|
1381
|
+
OpenFile,
|
|
1382
|
+
Listen,
|
|
1383
|
+
GetSockName,
|
|
1384
|
+
UnsupportedAddressFamily,
|
|
1385
|
+
HTTPParsing,
|
|
1386
|
+
InvalidRangeHeader,
|
|
1387
|
+
|
|
1388
|
+
// For internal use only
|
|
1389
|
+
SSLPeerCouldBeClosed_,
|
|
1390
|
+
};
|
|
1391
|
+
|
|
1392
|
+
std::string to_string(Error error);
|
|
1393
|
+
|
|
1394
|
+
std::ostream &operator<<(std::ostream &os, const Error &obj);
|
|
1395
|
+
|
|
1396
|
+
class Stream {
|
|
1397
|
+
public:
|
|
1398
|
+
virtual ~Stream() = default;
|
|
1399
|
+
|
|
1400
|
+
virtual bool is_readable() const = 0;
|
|
1401
|
+
virtual bool wait_readable() const = 0;
|
|
1402
|
+
virtual bool wait_writable() const = 0;
|
|
1403
|
+
virtual bool is_peer_alive() const { return wait_writable(); }
|
|
1404
|
+
|
|
1405
|
+
virtual ssize_t read(char *ptr, size_t size) = 0;
|
|
1406
|
+
virtual ssize_t write(const char *ptr, size_t size) = 0;
|
|
1407
|
+
virtual void get_remote_ip_and_port(std::string &ip, int &port) const = 0;
|
|
1408
|
+
virtual void get_local_ip_and_port(std::string &ip, int &port) const = 0;
|
|
1409
|
+
virtual socket_t socket() const = 0;
|
|
1410
|
+
|
|
1411
|
+
virtual time_t duration() const = 0;
|
|
1412
|
+
|
|
1413
|
+
virtual void set_read_timeout(time_t sec, time_t usec = 0) {
|
|
1414
|
+
(void)sec;
|
|
1415
|
+
(void)usec;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
ssize_t write(const char *ptr);
|
|
1419
|
+
ssize_t write(const std::string &s);
|
|
1420
|
+
|
|
1421
|
+
Error get_error() const { return error_; }
|
|
1422
|
+
|
|
1423
|
+
protected:
|
|
1424
|
+
Error error_ = Error::Success;
|
|
1425
|
+
};
|
|
1426
|
+
|
|
1427
|
+
class TaskQueue {
|
|
1428
|
+
public:
|
|
1429
|
+
TaskQueue() = default;
|
|
1430
|
+
virtual ~TaskQueue() = default;
|
|
1431
|
+
|
|
1432
|
+
virtual bool enqueue(std::function<void()> fn) = 0;
|
|
1433
|
+
virtual void shutdown() = 0;
|
|
1434
|
+
|
|
1435
|
+
virtual void on_idle() {}
|
|
1436
|
+
};
|
|
1437
|
+
|
|
1438
|
+
class ThreadPool final : public TaskQueue {
|
|
1439
|
+
public:
|
|
1440
|
+
explicit ThreadPool(size_t n, size_t max_n = 0, size_t mqr = 0);
|
|
1441
|
+
ThreadPool(const ThreadPool &) = delete;
|
|
1442
|
+
~ThreadPool() override = default;
|
|
1443
|
+
|
|
1444
|
+
bool enqueue(std::function<void()> fn) override;
|
|
1445
|
+
void shutdown() override;
|
|
1446
|
+
|
|
1447
|
+
private:
|
|
1448
|
+
void worker(bool is_dynamic);
|
|
1449
|
+
void move_to_finished(std::thread::id id);
|
|
1450
|
+
void cleanup_finished_threads();
|
|
1451
|
+
|
|
1452
|
+
size_t base_thread_count_;
|
|
1453
|
+
size_t max_thread_count_;
|
|
1454
|
+
size_t max_queued_requests_;
|
|
1455
|
+
size_t idle_thread_count_;
|
|
1456
|
+
|
|
1457
|
+
bool shutdown_;
|
|
1458
|
+
|
|
1459
|
+
std::list<std::function<void()>> jobs_;
|
|
1460
|
+
std::vector<std::thread> threads_; // base threads
|
|
1461
|
+
std::list<std::thread> dynamic_threads_; // dynamic threads
|
|
1462
|
+
std::vector<std::thread>
|
|
1463
|
+
finished_threads_; // exited dynamic threads awaiting join
|
|
1464
|
+
|
|
1465
|
+
std::condition_variable cond_;
|
|
1466
|
+
std::mutex mutex_;
|
|
1467
|
+
};
|
|
1468
|
+
|
|
1469
|
+
using Logger = std::function<void(const Request &, const Response &)>;
|
|
1470
|
+
|
|
1471
|
+
// Forward declaration for Error type
|
|
1472
|
+
enum class Error;
|
|
1473
|
+
using ErrorLogger = std::function<void(const Error &, const Request *)>;
|
|
1474
|
+
|
|
1475
|
+
using SocketOptions = std::function<void(socket_t sock)>;
|
|
1476
|
+
|
|
1477
|
+
void default_socket_options(socket_t sock);
|
|
1478
|
+
|
|
1479
|
+
bool set_socket_opt(socket_t sock, int level, int optname, int optval);
|
|
1480
|
+
|
|
1481
|
+
const char *status_message(int status);
|
|
1482
|
+
|
|
1483
|
+
std::string to_string(Error error);
|
|
1484
|
+
|
|
1485
|
+
std::ostream &operator<<(std::ostream &os, const Error &obj);
|
|
1486
|
+
|
|
1487
|
+
std::string get_bearer_token_auth(const Request &req);
|
|
1488
|
+
|
|
1489
|
+
namespace detail {
|
|
1490
|
+
|
|
1491
|
+
class MatcherBase {
|
|
1492
|
+
public:
|
|
1493
|
+
MatcherBase(std::string pattern) : pattern_(std::move(pattern)) {}
|
|
1494
|
+
virtual ~MatcherBase() = default;
|
|
1495
|
+
|
|
1496
|
+
const std::string &pattern() const { return pattern_; }
|
|
1497
|
+
|
|
1498
|
+
// Match request path and populate its matches and
|
|
1499
|
+
virtual bool match(Request &request) const = 0;
|
|
1500
|
+
|
|
1501
|
+
private:
|
|
1502
|
+
std::string pattern_;
|
|
1503
|
+
};
|
|
1504
|
+
|
|
1505
|
+
/**
|
|
1506
|
+
* Captures parameters in request path and stores them in Request::path_params
|
|
1507
|
+
*
|
|
1508
|
+
* Capture name is a substring of a pattern from : to /.
|
|
1509
|
+
* The rest of the pattern is matched against the request path directly
|
|
1510
|
+
* Parameters are captured starting from the next character after
|
|
1511
|
+
* the end of the last matched static pattern fragment until the next /.
|
|
1512
|
+
*
|
|
1513
|
+
* Example pattern:
|
|
1514
|
+
* "/path/fragments/:capture/more/fragments/:second_capture"
|
|
1515
|
+
* Static fragments:
|
|
1516
|
+
* "/path/fragments/", "more/fragments/"
|
|
1517
|
+
*
|
|
1518
|
+
* Given the following request path:
|
|
1519
|
+
* "/path/fragments/:1/more/fragments/:2"
|
|
1520
|
+
* the resulting capture will be
|
|
1521
|
+
* {{"capture", "1"}, {"second_capture", "2"}}
|
|
1522
|
+
*/
|
|
1523
|
+
class PathParamsMatcher final : public MatcherBase {
|
|
1524
|
+
public:
|
|
1525
|
+
PathParamsMatcher(const std::string &pattern);
|
|
1526
|
+
|
|
1527
|
+
bool match(Request &request) const override;
|
|
1528
|
+
|
|
1529
|
+
private:
|
|
1530
|
+
// Treat segment separators as the end of path parameter capture
|
|
1531
|
+
// Does not need to handle query parameters as they are parsed before path
|
|
1532
|
+
// matching
|
|
1533
|
+
static constexpr char separator = '/';
|
|
1534
|
+
|
|
1535
|
+
// Contains static path fragments to match against, excluding the '/' after
|
|
1536
|
+
// path params
|
|
1537
|
+
// Fragments are separated by path params
|
|
1538
|
+
std::vector<std::string> static_fragments_;
|
|
1539
|
+
// Stores the names of the path parameters to be used as keys in the
|
|
1540
|
+
// Request::path_params map
|
|
1541
|
+
std::vector<std::string> param_names_;
|
|
1542
|
+
};
|
|
1543
|
+
|
|
1544
|
+
/**
|
|
1545
|
+
* Performs std::regex_match on request path
|
|
1546
|
+
* and stores the result in Request::matches
|
|
1547
|
+
*
|
|
1548
|
+
* Note that regex match is performed directly on the whole request.
|
|
1549
|
+
* This means that wildcard patterns may match multiple path segments with /:
|
|
1550
|
+
* "/begin/(.*)/end" will match both "/begin/middle/end" and "/begin/1/2/end".
|
|
1551
|
+
*/
|
|
1552
|
+
class RegexMatcher final : public MatcherBase {
|
|
1553
|
+
public:
|
|
1554
|
+
RegexMatcher(const std::string &pattern)
|
|
1555
|
+
: MatcherBase(pattern), regex_(pattern) {}
|
|
1556
|
+
|
|
1557
|
+
bool match(Request &request) const override;
|
|
1558
|
+
|
|
1559
|
+
private:
|
|
1560
|
+
std::regex regex_;
|
|
1561
|
+
};
|
|
1562
|
+
|
|
1563
|
+
int close_socket(socket_t sock);
|
|
1564
|
+
|
|
1565
|
+
ssize_t write_headers(Stream &strm, const Headers &headers);
|
|
1566
|
+
|
|
1567
|
+
bool set_socket_opt_time(socket_t sock, int level, int optname, time_t sec,
|
|
1568
|
+
time_t usec);
|
|
1569
|
+
|
|
1570
|
+
size_t get_multipart_content_length(const UploadFormDataItems &items,
|
|
1571
|
+
const std::string &boundary);
|
|
1572
|
+
|
|
1573
|
+
ContentProvider
|
|
1574
|
+
make_multipart_content_provider(const UploadFormDataItems &items,
|
|
1575
|
+
const std::string &boundary);
|
|
1576
|
+
|
|
1577
|
+
} // namespace detail
|
|
1578
|
+
|
|
1579
|
+
class Server {
|
|
1580
|
+
public:
|
|
1581
|
+
using Handler = std::function<void(const Request &, Response &)>;
|
|
1582
|
+
|
|
1583
|
+
using ExceptionHandler =
|
|
1584
|
+
std::function<void(const Request &, Response &, std::exception_ptr ep)>;
|
|
1585
|
+
|
|
1586
|
+
enum class HandlerResponse {
|
|
1587
|
+
Handled,
|
|
1588
|
+
Unhandled,
|
|
1589
|
+
};
|
|
1590
|
+
using HandlerWithResponse =
|
|
1591
|
+
std::function<HandlerResponse(const Request &, Response &)>;
|
|
1592
|
+
|
|
1593
|
+
using HandlerWithContentReader = std::function<void(
|
|
1594
|
+
const Request &, Response &, const ContentReader &content_reader)>;
|
|
1595
|
+
|
|
1596
|
+
using Expect100ContinueHandler =
|
|
1597
|
+
std::function<int(const Request &, Response &)>;
|
|
1598
|
+
|
|
1599
|
+
using WebSocketHandler =
|
|
1600
|
+
std::function<void(const Request &, ws::WebSocket &)>;
|
|
1601
|
+
using SubProtocolSelector =
|
|
1602
|
+
std::function<std::string(const std::vector<std::string> &protocols)>;
|
|
1603
|
+
|
|
1604
|
+
Server();
|
|
1605
|
+
|
|
1606
|
+
virtual ~Server();
|
|
1607
|
+
|
|
1608
|
+
virtual bool is_valid() const;
|
|
1609
|
+
|
|
1610
|
+
Server &Get(const std::string &pattern, Handler handler);
|
|
1611
|
+
Server &Post(const std::string &pattern, Handler handler);
|
|
1612
|
+
Server &Post(const std::string &pattern, HandlerWithContentReader handler);
|
|
1613
|
+
Server &Put(const std::string &pattern, Handler handler);
|
|
1614
|
+
Server &Put(const std::string &pattern, HandlerWithContentReader handler);
|
|
1615
|
+
Server &Patch(const std::string &pattern, Handler handler);
|
|
1616
|
+
Server &Patch(const std::string &pattern, HandlerWithContentReader handler);
|
|
1617
|
+
Server &Delete(const std::string &pattern, Handler handler);
|
|
1618
|
+
Server &Delete(const std::string &pattern, HandlerWithContentReader handler);
|
|
1619
|
+
Server &Options(const std::string &pattern, Handler handler);
|
|
1620
|
+
|
|
1621
|
+
Server &WebSocket(const std::string &pattern, WebSocketHandler handler);
|
|
1622
|
+
Server &WebSocket(const std::string &pattern, WebSocketHandler handler,
|
|
1623
|
+
SubProtocolSelector sub_protocol_selector);
|
|
1624
|
+
|
|
1625
|
+
bool set_base_dir(const std::string &dir,
|
|
1626
|
+
const std::string &mount_point = std::string());
|
|
1627
|
+
bool set_mount_point(const std::string &mount_point, const std::string &dir,
|
|
1628
|
+
Headers headers = Headers());
|
|
1629
|
+
bool remove_mount_point(const std::string &mount_point);
|
|
1630
|
+
Server &set_file_extension_and_mimetype_mapping(const std::string &ext,
|
|
1631
|
+
const std::string &mime);
|
|
1632
|
+
Server &set_default_file_mimetype(const std::string &mime);
|
|
1633
|
+
Server &set_file_request_handler(Handler handler);
|
|
1634
|
+
|
|
1635
|
+
template <class ErrorHandlerFunc>
|
|
1636
|
+
Server &set_error_handler(ErrorHandlerFunc &&handler) {
|
|
1637
|
+
return set_error_handler_core(
|
|
1638
|
+
std::forward<ErrorHandlerFunc>(handler),
|
|
1639
|
+
std::is_convertible<ErrorHandlerFunc, HandlerWithResponse>{});
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
Server &set_exception_handler(ExceptionHandler handler);
|
|
1643
|
+
|
|
1644
|
+
Server &set_pre_routing_handler(HandlerWithResponse handler);
|
|
1645
|
+
Server &set_post_routing_handler(Handler handler);
|
|
1646
|
+
|
|
1647
|
+
Server &set_pre_request_handler(HandlerWithResponse handler);
|
|
1648
|
+
|
|
1649
|
+
Server &set_expect_100_continue_handler(Expect100ContinueHandler handler);
|
|
1650
|
+
Server &set_logger(Logger logger);
|
|
1651
|
+
Server &set_pre_compression_logger(Logger logger);
|
|
1652
|
+
Server &set_error_logger(ErrorLogger error_logger);
|
|
1653
|
+
|
|
1654
|
+
Server &set_address_family(int family);
|
|
1655
|
+
Server &set_tcp_nodelay(bool on);
|
|
1656
|
+
Server &set_ipv6_v6only(bool on);
|
|
1657
|
+
Server &set_socket_options(SocketOptions socket_options);
|
|
1658
|
+
|
|
1659
|
+
Server &set_default_headers(Headers headers);
|
|
1660
|
+
Server &
|
|
1661
|
+
set_header_writer(std::function<ssize_t(Stream &, Headers &)> const &writer);
|
|
1662
|
+
|
|
1663
|
+
Server &set_trusted_proxies(const std::vector<std::string> &proxies);
|
|
1664
|
+
|
|
1665
|
+
Server &set_keep_alive_max_count(size_t count);
|
|
1666
|
+
Server &set_keep_alive_timeout(time_t sec);
|
|
1667
|
+
|
|
1668
|
+
Server &set_read_timeout(time_t sec, time_t usec = 0);
|
|
1669
|
+
template <class Rep, class Period>
|
|
1670
|
+
Server &set_read_timeout(const std::chrono::duration<Rep, Period> &duration);
|
|
1671
|
+
|
|
1672
|
+
Server &set_write_timeout(time_t sec, time_t usec = 0);
|
|
1673
|
+
template <class Rep, class Period>
|
|
1674
|
+
Server &set_write_timeout(const std::chrono::duration<Rep, Period> &duration);
|
|
1675
|
+
|
|
1676
|
+
Server &set_idle_interval(time_t sec, time_t usec = 0);
|
|
1677
|
+
template <class Rep, class Period>
|
|
1678
|
+
Server &set_idle_interval(const std::chrono::duration<Rep, Period> &duration);
|
|
1679
|
+
|
|
1680
|
+
Server &set_payload_max_length(size_t length);
|
|
1681
|
+
|
|
1682
|
+
Server &set_websocket_ping_interval(time_t sec);
|
|
1683
|
+
template <class Rep, class Period>
|
|
1684
|
+
Server &set_websocket_ping_interval(
|
|
1685
|
+
const std::chrono::duration<Rep, Period> &duration);
|
|
1686
|
+
|
|
1687
|
+
bool bind_to_port(const std::string &host, int port, int socket_flags = 0);
|
|
1688
|
+
int bind_to_any_port(const std::string &host, int socket_flags = 0);
|
|
1689
|
+
bool listen_after_bind();
|
|
1690
|
+
|
|
1691
|
+
bool listen(const std::string &host, int port, int socket_flags = 0);
|
|
1692
|
+
|
|
1693
|
+
bool is_running() const;
|
|
1694
|
+
void wait_until_ready() const;
|
|
1695
|
+
void stop();
|
|
1696
|
+
void decommission();
|
|
1697
|
+
|
|
1698
|
+
std::function<TaskQueue *(void)> new_task_queue;
|
|
1699
|
+
|
|
1700
|
+
protected:
|
|
1701
|
+
bool process_request(Stream &strm, const std::string &remote_addr,
|
|
1702
|
+
int remote_port, const std::string &local_addr,
|
|
1703
|
+
int local_port, bool close_connection,
|
|
1704
|
+
bool &connection_closed,
|
|
1705
|
+
const std::function<void(Request &)> &setup_request,
|
|
1706
|
+
bool *websocket_upgraded = nullptr);
|
|
1707
|
+
|
|
1708
|
+
std::atomic<socket_t> svr_sock_{INVALID_SOCKET};
|
|
1709
|
+
|
|
1710
|
+
std::vector<std::string> trusted_proxies_;
|
|
1711
|
+
|
|
1712
|
+
size_t keep_alive_max_count_ = CPPHTTPLIB_KEEPALIVE_MAX_COUNT;
|
|
1713
|
+
time_t keep_alive_timeout_sec_ = CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND;
|
|
1714
|
+
time_t read_timeout_sec_ = CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND;
|
|
1715
|
+
time_t read_timeout_usec_ = CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND;
|
|
1716
|
+
time_t write_timeout_sec_ = CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND;
|
|
1717
|
+
time_t write_timeout_usec_ = CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND;
|
|
1718
|
+
time_t idle_interval_sec_ = CPPHTTPLIB_IDLE_INTERVAL_SECOND;
|
|
1719
|
+
time_t idle_interval_usec_ = CPPHTTPLIB_IDLE_INTERVAL_USECOND;
|
|
1720
|
+
size_t payload_max_length_ = CPPHTTPLIB_PAYLOAD_MAX_LENGTH;
|
|
1721
|
+
time_t websocket_ping_interval_sec_ =
|
|
1722
|
+
CPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECOND;
|
|
1723
|
+
|
|
1724
|
+
private:
|
|
1725
|
+
using Handlers =
|
|
1726
|
+
std::vector<std::pair<std::unique_ptr<detail::MatcherBase>, Handler>>;
|
|
1727
|
+
using HandlersForContentReader =
|
|
1728
|
+
std::vector<std::pair<std::unique_ptr<detail::MatcherBase>,
|
|
1729
|
+
HandlerWithContentReader>>;
|
|
1730
|
+
|
|
1731
|
+
static std::unique_ptr<detail::MatcherBase>
|
|
1732
|
+
make_matcher(const std::string &pattern);
|
|
1733
|
+
|
|
1734
|
+
Server &set_error_handler_core(HandlerWithResponse handler, std::true_type);
|
|
1735
|
+
Server &set_error_handler_core(Handler handler, std::false_type);
|
|
1736
|
+
|
|
1737
|
+
socket_t create_server_socket(const std::string &host, int port,
|
|
1738
|
+
int socket_flags,
|
|
1739
|
+
SocketOptions socket_options) const;
|
|
1740
|
+
int bind_internal(const std::string &host, int port, int socket_flags);
|
|
1741
|
+
bool listen_internal();
|
|
1742
|
+
|
|
1743
|
+
bool routing(Request &req, Response &res, Stream &strm);
|
|
1744
|
+
bool handle_file_request(Request &req, Response &res);
|
|
1745
|
+
bool check_if_not_modified(const Request &req, Response &res,
|
|
1746
|
+
const std::string &etag, time_t mtime) const;
|
|
1747
|
+
bool check_if_range(Request &req, const std::string &etag,
|
|
1748
|
+
time_t mtime) const;
|
|
1749
|
+
bool dispatch_request(Request &req, Response &res,
|
|
1750
|
+
const Handlers &handlers) const;
|
|
1751
|
+
bool dispatch_request_for_content_reader(
|
|
1752
|
+
Request &req, Response &res, ContentReader content_reader,
|
|
1753
|
+
const HandlersForContentReader &handlers) const;
|
|
1754
|
+
|
|
1755
|
+
bool parse_request_line(const char *s, Request &req) const;
|
|
1756
|
+
void apply_ranges(const Request &req, Response &res,
|
|
1757
|
+
std::string &content_type, std::string &boundary) const;
|
|
1758
|
+
bool write_response(Stream &strm, bool close_connection, Request &req,
|
|
1759
|
+
Response &res);
|
|
1760
|
+
bool write_response_with_content(Stream &strm, bool close_connection,
|
|
1761
|
+
const Request &req, Response &res);
|
|
1762
|
+
bool write_response_core(Stream &strm, bool close_connection,
|
|
1763
|
+
const Request &req, Response &res,
|
|
1764
|
+
bool need_apply_ranges);
|
|
1765
|
+
bool write_content_with_provider(Stream &strm, const Request &req,
|
|
1766
|
+
Response &res, const std::string &boundary,
|
|
1767
|
+
const std::string &content_type);
|
|
1768
|
+
bool read_content(Stream &strm, Request &req, Response &res);
|
|
1769
|
+
bool read_content_with_content_receiver(Stream &strm, Request &req,
|
|
1770
|
+
Response &res,
|
|
1771
|
+
ContentReceiver receiver,
|
|
1772
|
+
FormDataHeader multipart_header,
|
|
1773
|
+
ContentReceiver multipart_receiver);
|
|
1774
|
+
bool read_content_core(Stream &strm, Request &req, Response &res,
|
|
1775
|
+
ContentReceiver receiver,
|
|
1776
|
+
FormDataHeader multipart_header,
|
|
1777
|
+
ContentReceiver multipart_receiver) const;
|
|
1778
|
+
|
|
1779
|
+
virtual bool process_and_close_socket(socket_t sock);
|
|
1780
|
+
|
|
1781
|
+
void output_log(const Request &req, const Response &res) const;
|
|
1782
|
+
void output_pre_compression_log(const Request &req,
|
|
1783
|
+
const Response &res) const;
|
|
1784
|
+
void output_error_log(const Error &err, const Request *req) const;
|
|
1785
|
+
|
|
1786
|
+
std::atomic<bool> is_running_{false};
|
|
1787
|
+
std::atomic<bool> is_decommissioned{false};
|
|
1788
|
+
|
|
1789
|
+
struct MountPointEntry {
|
|
1790
|
+
std::string mount_point;
|
|
1791
|
+
std::string base_dir;
|
|
1792
|
+
std::string resolved_base_dir;
|
|
1793
|
+
Headers headers;
|
|
1794
|
+
};
|
|
1795
|
+
std::vector<MountPointEntry> base_dirs_;
|
|
1796
|
+
std::map<std::string, std::string> file_extension_and_mimetype_map_;
|
|
1797
|
+
std::string default_file_mimetype_ = "application/octet-stream";
|
|
1798
|
+
Handler file_request_handler_;
|
|
1799
|
+
|
|
1800
|
+
Handlers get_handlers_;
|
|
1801
|
+
Handlers post_handlers_;
|
|
1802
|
+
HandlersForContentReader post_handlers_for_content_reader_;
|
|
1803
|
+
Handlers put_handlers_;
|
|
1804
|
+
HandlersForContentReader put_handlers_for_content_reader_;
|
|
1805
|
+
Handlers patch_handlers_;
|
|
1806
|
+
HandlersForContentReader patch_handlers_for_content_reader_;
|
|
1807
|
+
Handlers delete_handlers_;
|
|
1808
|
+
HandlersForContentReader delete_handlers_for_content_reader_;
|
|
1809
|
+
Handlers options_handlers_;
|
|
1810
|
+
|
|
1811
|
+
struct WebSocketHandlerEntry {
|
|
1812
|
+
std::unique_ptr<detail::MatcherBase> matcher;
|
|
1813
|
+
WebSocketHandler handler;
|
|
1814
|
+
SubProtocolSelector sub_protocol_selector;
|
|
1815
|
+
};
|
|
1816
|
+
using WebSocketHandlers = std::vector<WebSocketHandlerEntry>;
|
|
1817
|
+
WebSocketHandlers websocket_handlers_;
|
|
1818
|
+
|
|
1819
|
+
HandlerWithResponse error_handler_;
|
|
1820
|
+
ExceptionHandler exception_handler_;
|
|
1821
|
+
HandlerWithResponse pre_routing_handler_;
|
|
1822
|
+
Handler post_routing_handler_;
|
|
1823
|
+
HandlerWithResponse pre_request_handler_;
|
|
1824
|
+
Expect100ContinueHandler expect_100_continue_handler_;
|
|
1825
|
+
|
|
1826
|
+
mutable std::mutex logger_mutex_;
|
|
1827
|
+
Logger logger_;
|
|
1828
|
+
Logger pre_compression_logger_;
|
|
1829
|
+
ErrorLogger error_logger_;
|
|
1830
|
+
|
|
1831
|
+
int address_family_ = AF_UNSPEC;
|
|
1832
|
+
bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
|
|
1833
|
+
bool ipv6_v6only_ = CPPHTTPLIB_IPV6_V6ONLY;
|
|
1834
|
+
SocketOptions socket_options_ = default_socket_options;
|
|
1835
|
+
|
|
1836
|
+
Headers default_headers_;
|
|
1837
|
+
std::function<ssize_t(Stream &, Headers &)> header_writer_ =
|
|
1838
|
+
detail::write_headers;
|
|
1839
|
+
};
|
|
1840
|
+
|
|
1841
|
+
class Result {
|
|
1842
|
+
public:
|
|
1843
|
+
Result() = default;
|
|
1844
|
+
Result(std::unique_ptr<Response> &&res, Error err,
|
|
1845
|
+
Headers &&request_headers = Headers{})
|
|
1846
|
+
: res_(std::move(res)), err_(err),
|
|
1847
|
+
request_headers_(std::move(request_headers)) {}
|
|
1848
|
+
// Response
|
|
1849
|
+
operator bool() const { return res_ != nullptr; }
|
|
1850
|
+
bool operator==(std::nullptr_t) const { return res_ == nullptr; }
|
|
1851
|
+
bool operator!=(std::nullptr_t) const { return res_ != nullptr; }
|
|
1852
|
+
const Response &value() const { return *res_; }
|
|
1853
|
+
Response &value() { return *res_; }
|
|
1854
|
+
const Response &operator*() const { return *res_; }
|
|
1855
|
+
Response &operator*() { return *res_; }
|
|
1856
|
+
const Response *operator->() const { return res_.get(); }
|
|
1857
|
+
Response *operator->() { return res_.get(); }
|
|
1858
|
+
|
|
1859
|
+
// Error
|
|
1860
|
+
Error error() const { return err_; }
|
|
1861
|
+
|
|
1862
|
+
// Request Headers
|
|
1863
|
+
bool has_request_header(const std::string &key) const;
|
|
1864
|
+
std::string get_request_header_value(const std::string &key,
|
|
1865
|
+
const char *def = "",
|
|
1866
|
+
size_t id = 0) const;
|
|
1867
|
+
size_t get_request_header_value_u64(const std::string &key, size_t def = 0,
|
|
1868
|
+
size_t id = 0) const;
|
|
1869
|
+
size_t get_request_header_value_count(const std::string &key) const;
|
|
1870
|
+
|
|
1871
|
+
private:
|
|
1872
|
+
std::unique_ptr<Response> res_;
|
|
1873
|
+
Error err_ = Error::Unknown;
|
|
1874
|
+
Headers request_headers_;
|
|
1875
|
+
|
|
1876
|
+
#ifdef CPPHTTPLIB_SSL_ENABLED
|
|
1877
|
+
public:
|
|
1878
|
+
Result(std::unique_ptr<Response> &&res, Error err, Headers &&request_headers,
|
|
1879
|
+
int ssl_error)
|
|
1880
|
+
: res_(std::move(res)), err_(err),
|
|
1881
|
+
request_headers_(std::move(request_headers)), ssl_error_(ssl_error) {}
|
|
1882
|
+
Result(std::unique_ptr<Response> &&res, Error err, Headers &&request_headers,
|
|
1883
|
+
int ssl_error, uint64_t ssl_backend_error)
|
|
1884
|
+
: res_(std::move(res)), err_(err),
|
|
1885
|
+
request_headers_(std::move(request_headers)), ssl_error_(ssl_error),
|
|
1886
|
+
ssl_backend_error_(ssl_backend_error) {}
|
|
1887
|
+
|
|
1888
|
+
int ssl_error() const { return ssl_error_; }
|
|
1889
|
+
uint64_t ssl_backend_error() const { return ssl_backend_error_; }
|
|
1890
|
+
|
|
1891
|
+
private:
|
|
1892
|
+
int ssl_error_ = 0;
|
|
1893
|
+
uint64_t ssl_backend_error_ = 0;
|
|
1894
|
+
#endif
|
|
1895
|
+
|
|
1896
|
+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
|
1897
|
+
public:
|
|
1898
|
+
[[deprecated("Use ssl_backend_error() instead. "
|
|
1899
|
+
"This function will be removed by v1.0.0.")]]
|
|
1900
|
+
uint64_t ssl_openssl_error() const {
|
|
1901
|
+
return ssl_backend_error_;
|
|
1902
|
+
}
|
|
1903
|
+
#endif
|
|
1904
|
+
};
|
|
1905
|
+
|
|
1906
|
+
struct ClientConnection {
|
|
1907
|
+
socket_t sock = INVALID_SOCKET;
|
|
1908
|
+
|
|
1909
|
+
bool is_open() const { return sock != INVALID_SOCKET; }
|
|
1910
|
+
|
|
1911
|
+
ClientConnection() = default;
|
|
1912
|
+
|
|
1913
|
+
~ClientConnection();
|
|
1914
|
+
|
|
1915
|
+
ClientConnection(const ClientConnection &) = delete;
|
|
1916
|
+
ClientConnection &operator=(const ClientConnection &) = delete;
|
|
1917
|
+
|
|
1918
|
+
ClientConnection(ClientConnection &&other) noexcept
|
|
1919
|
+
: sock(other.sock)
|
|
1920
|
+
#ifdef CPPHTTPLIB_SSL_ENABLED
|
|
1921
|
+
,
|
|
1922
|
+
session(other.session)
|
|
1923
|
+
#endif
|
|
1924
|
+
{
|
|
1925
|
+
other.sock = INVALID_SOCKET;
|
|
1926
|
+
#ifdef CPPHTTPLIB_SSL_ENABLED
|
|
1927
|
+
other.session = nullptr;
|
|
1928
|
+
#endif
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
ClientConnection &operator=(ClientConnection &&other) noexcept {
|
|
1932
|
+
if (this != &other) {
|
|
1933
|
+
sock = other.sock;
|
|
1934
|
+
other.sock = INVALID_SOCKET;
|
|
1935
|
+
#ifdef CPPHTTPLIB_SSL_ENABLED
|
|
1936
|
+
session = other.session;
|
|
1937
|
+
other.session = nullptr;
|
|
1938
|
+
#endif
|
|
1939
|
+
}
|
|
1940
|
+
return *this;
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1943
|
+
#ifdef CPPHTTPLIB_SSL_ENABLED
|
|
1944
|
+
tls::session_t session = nullptr;
|
|
1945
|
+
#endif
|
|
1946
|
+
};
|
|
1947
|
+
|
|
1948
|
+
namespace detail {
|
|
1949
|
+
|
|
1950
|
+
struct ChunkedDecoder;
|
|
1951
|
+
|
|
1952
|
+
struct BodyReader {
|
|
1953
|
+
Stream *stream = nullptr;
|
|
1954
|
+
bool has_content_length = false;
|
|
1955
|
+
size_t content_length = 0;
|
|
1956
|
+
size_t payload_max_length = CPPHTTPLIB_PAYLOAD_MAX_LENGTH;
|
|
1957
|
+
size_t bytes_read = 0;
|
|
1958
|
+
bool chunked = false;
|
|
1959
|
+
bool eof = false;
|
|
1960
|
+
std::unique_ptr<ChunkedDecoder> chunked_decoder;
|
|
1961
|
+
Error last_error = Error::Success;
|
|
1962
|
+
|
|
1963
|
+
ssize_t read(char *buf, size_t len);
|
|
1964
|
+
bool has_error() const { return last_error != Error::Success; }
|
|
1965
|
+
};
|
|
1966
|
+
|
|
1967
|
+
inline ssize_t read_body_content(Stream *stream, BodyReader &br, char *buf,
|
|
1968
|
+
size_t len) {
|
|
1969
|
+
(void)stream;
|
|
1970
|
+
return br.read(buf, len);
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
class decompressor;
|
|
1974
|
+
|
|
1975
|
+
} // namespace detail
|
|
1976
|
+
|
|
1977
|
+
class ClientImpl {
|
|
1978
|
+
public:
|
|
1979
|
+
explicit ClientImpl(const std::string &host);
|
|
1980
|
+
|
|
1981
|
+
explicit ClientImpl(const std::string &host, int port);
|
|
1982
|
+
|
|
1983
|
+
explicit ClientImpl(const std::string &host, int port,
|
|
1984
|
+
const std::string &client_cert_path,
|
|
1985
|
+
const std::string &client_key_path);
|
|
1986
|
+
|
|
1987
|
+
virtual ~ClientImpl();
|
|
1988
|
+
|
|
1989
|
+
virtual bool is_valid() const;
|
|
1990
|
+
|
|
1991
|
+
struct StreamHandle {
|
|
1992
|
+
std::unique_ptr<Response> response;
|
|
1993
|
+
Error error = Error::Success;
|
|
1994
|
+
|
|
1995
|
+
StreamHandle() = default;
|
|
1996
|
+
StreamHandle(const StreamHandle &) = delete;
|
|
1997
|
+
StreamHandle &operator=(const StreamHandle &) = delete;
|
|
1998
|
+
StreamHandle(StreamHandle &&) = default;
|
|
1999
|
+
StreamHandle &operator=(StreamHandle &&) = default;
|
|
2000
|
+
~StreamHandle() = default;
|
|
2001
|
+
|
|
2002
|
+
bool is_valid() const {
|
|
2003
|
+
return response != nullptr && error == Error::Success;
|
|
2004
|
+
}
|
|
2005
|
+
|
|
2006
|
+
ssize_t read(char *buf, size_t len);
|
|
2007
|
+
void parse_trailers_if_needed();
|
|
2008
|
+
Error get_read_error() const { return body_reader_.last_error; }
|
|
2009
|
+
bool has_read_error() const { return body_reader_.has_error(); }
|
|
2010
|
+
|
|
2011
|
+
bool trailers_parsed_ = false;
|
|
2012
|
+
|
|
2013
|
+
private:
|
|
2014
|
+
friend class ClientImpl;
|
|
2015
|
+
|
|
2016
|
+
ssize_t read_with_decompression(char *buf, size_t len);
|
|
2017
|
+
|
|
2018
|
+
std::unique_ptr<ClientConnection> connection_;
|
|
2019
|
+
std::unique_ptr<Stream> socket_stream_;
|
|
2020
|
+
Stream *stream_ = nullptr;
|
|
2021
|
+
detail::BodyReader body_reader_;
|
|
2022
|
+
|
|
2023
|
+
std::unique_ptr<detail::decompressor> decompressor_;
|
|
2024
|
+
std::string decompress_buffer_;
|
|
2025
|
+
size_t decompress_offset_ = 0;
|
|
2026
|
+
size_t decompressed_bytes_read_ = 0;
|
|
2027
|
+
};
|
|
2028
|
+
|
|
2029
|
+
// clang-format off
|
|
2030
|
+
Result Get(const std::string &path, DownloadProgress progress = nullptr);
|
|
2031
|
+
Result Get(const std::string &path, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2032
|
+
Result Get(const std::string &path, ResponseHandler response_handler, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2033
|
+
Result Get(const std::string &path, const Headers &headers, DownloadProgress progress = nullptr);
|
|
2034
|
+
Result Get(const std::string &path, const Headers &headers, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2035
|
+
Result Get(const std::string &path, const Headers &headers, ResponseHandler response_handler, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2036
|
+
Result Get(const std::string &path, const Params ¶ms, const Headers &headers, DownloadProgress progress = nullptr);
|
|
2037
|
+
Result Get(const std::string &path, const Params ¶ms, const Headers &headers, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2038
|
+
Result Get(const std::string &path, const Params ¶ms, const Headers &headers, ResponseHandler response_handler, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2039
|
+
|
|
2040
|
+
Result Head(const std::string &path);
|
|
2041
|
+
Result Head(const std::string &path, const Headers &headers);
|
|
2042
|
+
|
|
2043
|
+
Result Post(const std::string &path);
|
|
2044
|
+
Result Post(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2045
|
+
Result Post(const std::string &path, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2046
|
+
Result Post(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2047
|
+
Result Post(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2048
|
+
Result Post(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2049
|
+
Result Post(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2050
|
+
Result Post(const std::string &path, const Params ¶ms);
|
|
2051
|
+
Result Post(const std::string &path, const UploadFormDataItems &items, UploadProgress progress = nullptr);
|
|
2052
|
+
Result Post(const std::string &path, const Headers &headers);
|
|
2053
|
+
Result Post(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2054
|
+
Result Post(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2055
|
+
Result Post(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2056
|
+
Result Post(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2057
|
+
Result Post(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2058
|
+
Result Post(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2059
|
+
Result Post(const std::string &path, const Headers &headers, const Params ¶ms);
|
|
2060
|
+
Result Post(const std::string &path, const Headers &headers, const UploadFormDataItems &items, UploadProgress progress = nullptr);
|
|
2061
|
+
Result Post(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const std::string &boundary, UploadProgress progress = nullptr);
|
|
2062
|
+
Result Post(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const FormDataProviderItems &provider_items, UploadProgress progress = nullptr);
|
|
2063
|
+
Result Post(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2064
|
+
|
|
2065
|
+
Result Put(const std::string &path);
|
|
2066
|
+
Result Put(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2067
|
+
Result Put(const std::string &path, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2068
|
+
Result Put(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2069
|
+
Result Put(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2070
|
+
Result Put(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2071
|
+
Result Put(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2072
|
+
Result Put(const std::string &path, const Params ¶ms);
|
|
2073
|
+
Result Put(const std::string &path, const UploadFormDataItems &items, UploadProgress progress = nullptr);
|
|
2074
|
+
Result Put(const std::string &path, const Headers &headers);
|
|
2075
|
+
Result Put(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2076
|
+
Result Put(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2077
|
+
Result Put(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2078
|
+
Result Put(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2079
|
+
Result Put(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2080
|
+
Result Put(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2081
|
+
Result Put(const std::string &path, const Headers &headers, const Params ¶ms);
|
|
2082
|
+
Result Put(const std::string &path, const Headers &headers, const UploadFormDataItems &items, UploadProgress progress = nullptr);
|
|
2083
|
+
Result Put(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const std::string &boundary, UploadProgress progress = nullptr);
|
|
2084
|
+
Result Put(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const FormDataProviderItems &provider_items, UploadProgress progress = nullptr);
|
|
2085
|
+
Result Put(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2086
|
+
|
|
2087
|
+
Result Patch(const std::string &path);
|
|
2088
|
+
Result Patch(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2089
|
+
Result Patch(const std::string &path, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2090
|
+
Result Patch(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2091
|
+
Result Patch(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2092
|
+
Result Patch(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2093
|
+
Result Patch(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2094
|
+
Result Patch(const std::string &path, const Params ¶ms);
|
|
2095
|
+
Result Patch(const std::string &path, const UploadFormDataItems &items, UploadProgress progress = nullptr);
|
|
2096
|
+
Result Patch(const std::string &path, const Headers &headers, UploadProgress progress = nullptr);
|
|
2097
|
+
Result Patch(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2098
|
+
Result Patch(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2099
|
+
Result Patch(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2100
|
+
Result Patch(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2101
|
+
Result Patch(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2102
|
+
Result Patch(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2103
|
+
Result Patch(const std::string &path, const Headers &headers, const Params ¶ms);
|
|
2104
|
+
Result Patch(const std::string &path, const Headers &headers, const UploadFormDataItems &items, UploadProgress progress = nullptr);
|
|
2105
|
+
Result Patch(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const std::string &boundary, UploadProgress progress = nullptr);
|
|
2106
|
+
Result Patch(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const FormDataProviderItems &provider_items, UploadProgress progress = nullptr);
|
|
2107
|
+
Result Patch(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2108
|
+
|
|
2109
|
+
Result Delete(const std::string &path, DownloadProgress progress = nullptr);
|
|
2110
|
+
Result Delete(const std::string &path, const char *body, size_t content_length, const std::string &content_type, DownloadProgress progress = nullptr);
|
|
2111
|
+
Result Delete(const std::string &path, const std::string &body, const std::string &content_type, DownloadProgress progress = nullptr);
|
|
2112
|
+
Result Delete(const std::string &path, const Params ¶ms, DownloadProgress progress = nullptr);
|
|
2113
|
+
Result Delete(const std::string &path, const Headers &headers, DownloadProgress progress = nullptr);
|
|
2114
|
+
Result Delete(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, DownloadProgress progress = nullptr);
|
|
2115
|
+
Result Delete(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, DownloadProgress progress = nullptr);
|
|
2116
|
+
Result Delete(const std::string &path, const Headers &headers, const Params ¶ms, DownloadProgress progress = nullptr);
|
|
2117
|
+
|
|
2118
|
+
Result Options(const std::string &path);
|
|
2119
|
+
Result Options(const std::string &path, const Headers &headers);
|
|
2120
|
+
// clang-format on
|
|
2121
|
+
|
|
2122
|
+
// Streaming API: Open a stream for reading response body incrementally
|
|
2123
|
+
// Socket ownership is transferred to StreamHandle for true streaming
|
|
2124
|
+
// Supports all HTTP methods (GET, POST, PUT, PATCH, DELETE, etc.)
|
|
2125
|
+
StreamHandle open_stream(const std::string &method, const std::string &path,
|
|
2126
|
+
const Params ¶ms = {},
|
|
2127
|
+
const Headers &headers = {},
|
|
2128
|
+
const std::string &body = {},
|
|
2129
|
+
const std::string &content_type = {});
|
|
2130
|
+
|
|
2131
|
+
bool send(Request &req, Response &res, Error &error);
|
|
2132
|
+
Result send(const Request &req);
|
|
2133
|
+
|
|
2134
|
+
void stop();
|
|
2135
|
+
|
|
2136
|
+
std::string host() const;
|
|
2137
|
+
int port() const;
|
|
2138
|
+
|
|
2139
|
+
size_t is_socket_open() const;
|
|
2140
|
+
socket_t socket() const;
|
|
2141
|
+
|
|
2142
|
+
void set_hostname_addr_map(std::map<std::string, std::string> addr_map);
|
|
2143
|
+
|
|
2144
|
+
void set_default_headers(Headers headers);
|
|
2145
|
+
|
|
2146
|
+
void
|
|
2147
|
+
set_header_writer(std::function<ssize_t(Stream &, Headers &)> const &writer);
|
|
2148
|
+
|
|
2149
|
+
void set_address_family(int family);
|
|
2150
|
+
void set_tcp_nodelay(bool on);
|
|
2151
|
+
void set_ipv6_v6only(bool on);
|
|
2152
|
+
void set_socket_options(SocketOptions socket_options);
|
|
2153
|
+
|
|
2154
|
+
void set_connection_timeout(time_t sec, time_t usec = 0);
|
|
2155
|
+
template <class Rep, class Period>
|
|
2156
|
+
void
|
|
2157
|
+
set_connection_timeout(const std::chrono::duration<Rep, Period> &duration);
|
|
2158
|
+
|
|
2159
|
+
void set_read_timeout(time_t sec, time_t usec = 0);
|
|
2160
|
+
template <class Rep, class Period>
|
|
2161
|
+
void set_read_timeout(const std::chrono::duration<Rep, Period> &duration);
|
|
2162
|
+
|
|
2163
|
+
void set_write_timeout(time_t sec, time_t usec = 0);
|
|
2164
|
+
template <class Rep, class Period>
|
|
2165
|
+
void set_write_timeout(const std::chrono::duration<Rep, Period> &duration);
|
|
2166
|
+
|
|
2167
|
+
void set_max_timeout(time_t msec);
|
|
2168
|
+
template <class Rep, class Period>
|
|
2169
|
+
void set_max_timeout(const std::chrono::duration<Rep, Period> &duration);
|
|
2170
|
+
|
|
2171
|
+
void set_basic_auth(const std::string &username, const std::string &password);
|
|
2172
|
+
void set_bearer_token_auth(const std::string &token);
|
|
2173
|
+
|
|
2174
|
+
void set_keep_alive(bool on);
|
|
2175
|
+
void set_follow_location(bool on);
|
|
2176
|
+
|
|
2177
|
+
void set_path_encode(bool on);
|
|
2178
|
+
|
|
2179
|
+
void set_compress(bool on);
|
|
2180
|
+
|
|
2181
|
+
void set_decompress(bool on);
|
|
2182
|
+
|
|
2183
|
+
void set_payload_max_length(size_t length);
|
|
2184
|
+
|
|
2185
|
+
void set_interface(const std::string &intf);
|
|
2186
|
+
|
|
2187
|
+
void set_proxy(const std::string &host, int port);
|
|
2188
|
+
void set_proxy_basic_auth(const std::string &username,
|
|
2189
|
+
const std::string &password);
|
|
2190
|
+
void set_proxy_bearer_token_auth(const std::string &token);
|
|
2191
|
+
|
|
2192
|
+
void set_logger(Logger logger);
|
|
2193
|
+
void set_error_logger(ErrorLogger error_logger);
|
|
2194
|
+
|
|
2195
|
+
protected:
|
|
2196
|
+
struct Socket {
|
|
2197
|
+
socket_t sock = INVALID_SOCKET;
|
|
2198
|
+
|
|
2199
|
+
// For Mbed TLS compatibility: start_time for request timeout tracking
|
|
2200
|
+
std::chrono::time_point<std::chrono::steady_clock> start_time_;
|
|
2201
|
+
|
|
2202
|
+
bool is_open() const { return sock != INVALID_SOCKET; }
|
|
2203
|
+
|
|
2204
|
+
#ifdef CPPHTTPLIB_SSL_ENABLED
|
|
2205
|
+
tls::session_t ssl = nullptr;
|
|
2206
|
+
#endif
|
|
2207
|
+
};
|
|
2208
|
+
|
|
2209
|
+
virtual bool create_and_connect_socket(Socket &socket, Error &error);
|
|
2210
|
+
virtual bool ensure_socket_connection(Socket &socket, Error &error);
|
|
2211
|
+
virtual bool setup_proxy_connection(
|
|
2212
|
+
Socket &socket,
|
|
2213
|
+
std::chrono::time_point<std::chrono::steady_clock> start_time,
|
|
2214
|
+
Response &res, bool &success, Error &error);
|
|
2215
|
+
|
|
2216
|
+
// All of:
|
|
2217
|
+
// shutdown_ssl
|
|
2218
|
+
// shutdown_socket
|
|
2219
|
+
// close_socket
|
|
2220
|
+
// should ONLY be called when socket_mutex_ is locked.
|
|
2221
|
+
// Also, shutdown_ssl and close_socket should also NOT be called concurrently
|
|
2222
|
+
// with a DIFFERENT thread sending requests using that socket.
|
|
2223
|
+
virtual void shutdown_ssl(Socket &socket, bool shutdown_gracefully);
|
|
2224
|
+
void shutdown_socket(Socket &socket) const;
|
|
2225
|
+
void close_socket(Socket &socket);
|
|
2226
|
+
|
|
2227
|
+
bool process_request(Stream &strm, Request &req, Response &res,
|
|
2228
|
+
bool close_connection, Error &error);
|
|
2229
|
+
|
|
2230
|
+
bool write_content_with_provider(Stream &strm, const Request &req,
|
|
2231
|
+
Error &error) const;
|
|
2232
|
+
|
|
2233
|
+
void copy_settings(const ClientImpl &rhs);
|
|
2234
|
+
|
|
2235
|
+
void output_log(const Request &req, const Response &res) const;
|
|
2236
|
+
void output_error_log(const Error &err, const Request *req) const;
|
|
2237
|
+
|
|
2238
|
+
// Socket endpoint information
|
|
2239
|
+
const std::string host_;
|
|
2240
|
+
const int port_;
|
|
2241
|
+
|
|
2242
|
+
// Current open socket
|
|
2243
|
+
Socket socket_;
|
|
2244
|
+
mutable std::mutex socket_mutex_;
|
|
2245
|
+
std::recursive_mutex request_mutex_;
|
|
2246
|
+
|
|
2247
|
+
// These are all protected under socket_mutex
|
|
2248
|
+
size_t socket_requests_in_flight_ = 0;
|
|
2249
|
+
std::thread::id socket_requests_are_from_thread_ = std::thread::id();
|
|
2250
|
+
bool socket_should_be_closed_when_request_is_done_ = false;
|
|
2251
|
+
|
|
2252
|
+
// Hostname-IP map
|
|
2253
|
+
std::map<std::string, std::string> addr_map_;
|
|
2254
|
+
|
|
2255
|
+
// Default headers
|
|
2256
|
+
Headers default_headers_;
|
|
2257
|
+
|
|
2258
|
+
// Header writer
|
|
2259
|
+
std::function<ssize_t(Stream &, Headers &)> header_writer_ =
|
|
2260
|
+
detail::write_headers;
|
|
2261
|
+
|
|
2262
|
+
// Settings
|
|
2263
|
+
std::string client_cert_path_;
|
|
2264
|
+
std::string client_key_path_;
|
|
2265
|
+
|
|
2266
|
+
time_t connection_timeout_sec_ = CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND;
|
|
2267
|
+
time_t connection_timeout_usec_ = CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND;
|
|
2268
|
+
time_t read_timeout_sec_ = CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND;
|
|
2269
|
+
time_t read_timeout_usec_ = CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND;
|
|
2270
|
+
time_t write_timeout_sec_ = CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND;
|
|
2271
|
+
time_t write_timeout_usec_ = CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND;
|
|
2272
|
+
time_t max_timeout_msec_ = CPPHTTPLIB_CLIENT_MAX_TIMEOUT_MSECOND;
|
|
2273
|
+
|
|
2274
|
+
std::string basic_auth_username_;
|
|
2275
|
+
std::string basic_auth_password_;
|
|
2276
|
+
std::string bearer_token_auth_token_;
|
|
2277
|
+
|
|
2278
|
+
bool keep_alive_ = false;
|
|
2279
|
+
bool follow_location_ = false;
|
|
2280
|
+
|
|
2281
|
+
bool path_encode_ = true;
|
|
2282
|
+
|
|
2283
|
+
int address_family_ = AF_UNSPEC;
|
|
2284
|
+
bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
|
|
2285
|
+
bool ipv6_v6only_ = CPPHTTPLIB_IPV6_V6ONLY;
|
|
2286
|
+
SocketOptions socket_options_ = nullptr;
|
|
2287
|
+
|
|
2288
|
+
bool compress_ = false;
|
|
2289
|
+
bool decompress_ = true;
|
|
2290
|
+
|
|
2291
|
+
size_t payload_max_length_ = CPPHTTPLIB_PAYLOAD_MAX_LENGTH;
|
|
2292
|
+
bool has_payload_max_length_ = false;
|
|
2293
|
+
|
|
2294
|
+
std::string interface_;
|
|
2295
|
+
|
|
2296
|
+
std::string proxy_host_;
|
|
2297
|
+
int proxy_port_ = -1;
|
|
2298
|
+
|
|
2299
|
+
std::string proxy_basic_auth_username_;
|
|
2300
|
+
std::string proxy_basic_auth_password_;
|
|
2301
|
+
std::string proxy_bearer_token_auth_token_;
|
|
2302
|
+
|
|
2303
|
+
mutable std::mutex logger_mutex_;
|
|
2304
|
+
Logger logger_;
|
|
2305
|
+
ErrorLogger error_logger_;
|
|
2306
|
+
|
|
2307
|
+
private:
|
|
2308
|
+
bool send_(Request &req, Response &res, Error &error);
|
|
2309
|
+
Result send_(Request &&req);
|
|
2310
|
+
|
|
2311
|
+
socket_t create_client_socket(Error &error) const;
|
|
2312
|
+
bool read_response_line(Stream &strm, const Request &req, Response &res,
|
|
2313
|
+
bool skip_100_continue = true) const;
|
|
2314
|
+
bool write_request(Stream &strm, Request &req, bool close_connection,
|
|
2315
|
+
Error &error, bool skip_body = false);
|
|
2316
|
+
bool write_request_body(Stream &strm, Request &req, Error &error);
|
|
2317
|
+
void prepare_default_headers(Request &r, bool for_stream,
|
|
2318
|
+
const std::string &ct);
|
|
2319
|
+
bool redirect(Request &req, Response &res, Error &error);
|
|
2320
|
+
bool create_redirect_client(const std::string &scheme,
|
|
2321
|
+
const std::string &host, int port, Request &req,
|
|
2322
|
+
Response &res, const std::string &path,
|
|
2323
|
+
const std::string &location, Error &error);
|
|
2324
|
+
template <typename ClientType> void setup_redirect_client(ClientType &client);
|
|
2325
|
+
bool handle_request(Stream &strm, Request &req, Response &res,
|
|
2326
|
+
bool close_connection, Error &error);
|
|
2327
|
+
std::unique_ptr<Response> send_with_content_provider_and_receiver(
|
|
2328
|
+
Request &req, const char *body, size_t content_length,
|
|
2329
|
+
ContentProvider content_provider,
|
|
2330
|
+
ContentProviderWithoutLength content_provider_without_length,
|
|
2331
|
+
const std::string &content_type, ContentReceiver content_receiver,
|
|
2332
|
+
Error &error);
|
|
2333
|
+
Result send_with_content_provider_and_receiver(
|
|
2334
|
+
const std::string &method, const std::string &path,
|
|
2335
|
+
const Headers &headers, const char *body, size_t content_length,
|
|
2336
|
+
ContentProvider content_provider,
|
|
2337
|
+
ContentProviderWithoutLength content_provider_without_length,
|
|
2338
|
+
const std::string &content_type, ContentReceiver content_receiver,
|
|
2339
|
+
UploadProgress progress);
|
|
2340
|
+
ContentProviderWithoutLength get_multipart_content_provider(
|
|
2341
|
+
const std::string &boundary, const UploadFormDataItems &items,
|
|
2342
|
+
const FormDataProviderItems &provider_items) const;
|
|
2343
|
+
|
|
2344
|
+
virtual bool
|
|
2345
|
+
process_socket(const Socket &socket,
|
|
2346
|
+
std::chrono::time_point<std::chrono::steady_clock> start_time,
|
|
2347
|
+
std::function<bool(Stream &strm)> callback);
|
|
2348
|
+
virtual bool is_ssl() const;
|
|
2349
|
+
|
|
2350
|
+
void transfer_socket_ownership_to_handle(StreamHandle &handle);
|
|
2351
|
+
|
|
2352
|
+
#ifdef CPPHTTPLIB_SSL_ENABLED
|
|
2353
|
+
public:
|
|
2354
|
+
void set_digest_auth(const std::string &username,
|
|
2355
|
+
const std::string &password);
|
|
2356
|
+
void set_proxy_digest_auth(const std::string &username,
|
|
2357
|
+
const std::string &password);
|
|
2358
|
+
void set_ca_cert_path(const std::string &ca_cert_file_path,
|
|
2359
|
+
const std::string &ca_cert_dir_path = std::string());
|
|
2360
|
+
void enable_server_certificate_verification(bool enabled);
|
|
2361
|
+
void enable_server_hostname_verification(bool enabled);
|
|
2362
|
+
|
|
2363
|
+
protected:
|
|
2364
|
+
std::string digest_auth_username_;
|
|
2365
|
+
std::string digest_auth_password_;
|
|
2366
|
+
std::string proxy_digest_auth_username_;
|
|
2367
|
+
std::string proxy_digest_auth_password_;
|
|
2368
|
+
std::string ca_cert_file_path_;
|
|
2369
|
+
std::string ca_cert_dir_path_;
|
|
2370
|
+
bool server_certificate_verification_ = true;
|
|
2371
|
+
bool server_hostname_verification_ = true;
|
|
2372
|
+
std::string ca_cert_pem_; // Store CA cert PEM for redirect transfer
|
|
2373
|
+
int last_ssl_error_ = 0;
|
|
2374
|
+
uint64_t last_backend_error_ = 0;
|
|
2375
|
+
#endif
|
|
2376
|
+
|
|
2377
|
+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
|
2378
|
+
public:
|
|
2379
|
+
[[deprecated("Use load_ca_cert_store() instead. "
|
|
2380
|
+
"This function will be removed by v1.0.0.")]]
|
|
2381
|
+
void set_ca_cert_store(X509_STORE *ca_cert_store);
|
|
2382
|
+
|
|
2383
|
+
[[deprecated("Use tls::create_ca_store() instead. "
|
|
2384
|
+
"This function will be removed by v1.0.0.")]]
|
|
2385
|
+
X509_STORE *create_ca_cert_store(const char *ca_cert, std::size_t size) const;
|
|
2386
|
+
|
|
2387
|
+
[[deprecated("Use set_server_certificate_verifier(VerifyCallback) instead. "
|
|
2388
|
+
"This function will be removed by v1.0.0.")]]
|
|
2389
|
+
virtual void set_server_certificate_verifier(
|
|
2390
|
+
std::function<SSLVerifierResponse(SSL *ssl)> verifier);
|
|
2391
|
+
#endif
|
|
2392
|
+
};
|
|
2393
|
+
|
|
2394
|
+
class Client {
|
|
2395
|
+
public:
|
|
2396
|
+
// Universal interface
|
|
2397
|
+
explicit Client(const std::string &scheme_host_port);
|
|
2398
|
+
|
|
2399
|
+
explicit Client(const std::string &scheme_host_port,
|
|
2400
|
+
const std::string &client_cert_path,
|
|
2401
|
+
const std::string &client_key_path);
|
|
2402
|
+
|
|
2403
|
+
// HTTP only interface
|
|
2404
|
+
explicit Client(const std::string &host, int port);
|
|
2405
|
+
|
|
2406
|
+
explicit Client(const std::string &host, int port,
|
|
2407
|
+
const std::string &client_cert_path,
|
|
2408
|
+
const std::string &client_key_path);
|
|
2409
|
+
|
|
2410
|
+
Client(Client &&) = default;
|
|
2411
|
+
Client &operator=(Client &&) = default;
|
|
2412
|
+
|
|
2413
|
+
~Client();
|
|
2414
|
+
|
|
2415
|
+
bool is_valid() const;
|
|
2416
|
+
|
|
2417
|
+
// clang-format off
|
|
2418
|
+
Result Get(const std::string &path, DownloadProgress progress = nullptr);
|
|
2419
|
+
Result Get(const std::string &path, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2420
|
+
Result Get(const std::string &path, ResponseHandler response_handler, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2421
|
+
Result Get(const std::string &path, const Headers &headers, DownloadProgress progress = nullptr);
|
|
2422
|
+
Result Get(const std::string &path, const Headers &headers, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2423
|
+
Result Get(const std::string &path, const Headers &headers, ResponseHandler response_handler, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2424
|
+
Result Get(const std::string &path, const Params ¶ms, const Headers &headers, DownloadProgress progress = nullptr);
|
|
2425
|
+
Result Get(const std::string &path, const Params ¶ms, const Headers &headers, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2426
|
+
Result Get(const std::string &path, const Params ¶ms, const Headers &headers, ResponseHandler response_handler, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2427
|
+
|
|
2428
|
+
Result Head(const std::string &path);
|
|
2429
|
+
Result Head(const std::string &path, const Headers &headers);
|
|
2430
|
+
|
|
2431
|
+
Result Post(const std::string &path);
|
|
2432
|
+
Result Post(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2433
|
+
Result Post(const std::string &path, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2434
|
+
Result Post(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2435
|
+
Result Post(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2436
|
+
Result Post(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2437
|
+
Result Post(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2438
|
+
Result Post(const std::string &path, const Params ¶ms);
|
|
2439
|
+
Result Post(const std::string &path, const UploadFormDataItems &items, UploadProgress progress = nullptr);
|
|
2440
|
+
Result Post(const std::string &path, const Headers &headers);
|
|
2441
|
+
Result Post(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2442
|
+
Result Post(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2443
|
+
Result Post(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2444
|
+
Result Post(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2445
|
+
Result Post(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2446
|
+
Result Post(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2447
|
+
Result Post(const std::string &path, const Headers &headers, const Params ¶ms);
|
|
2448
|
+
Result Post(const std::string &path, const Headers &headers, const UploadFormDataItems &items, UploadProgress progress = nullptr);
|
|
2449
|
+
Result Post(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const std::string &boundary, UploadProgress progress = nullptr);
|
|
2450
|
+
Result Post(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const FormDataProviderItems &provider_items, UploadProgress progress = nullptr);
|
|
2451
|
+
Result Post(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2452
|
+
|
|
2453
|
+
Result Put(const std::string &path);
|
|
2454
|
+
Result Put(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2455
|
+
Result Put(const std::string &path, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2456
|
+
Result Put(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2457
|
+
Result Put(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2458
|
+
Result Put(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2459
|
+
Result Put(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2460
|
+
Result Put(const std::string &path, const Params ¶ms);
|
|
2461
|
+
Result Put(const std::string &path, const UploadFormDataItems &items, UploadProgress progress = nullptr);
|
|
2462
|
+
Result Put(const std::string &path, const Headers &headers);
|
|
2463
|
+
Result Put(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2464
|
+
Result Put(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2465
|
+
Result Put(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2466
|
+
Result Put(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2467
|
+
Result Put(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2468
|
+
Result Put(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2469
|
+
Result Put(const std::string &path, const Headers &headers, const Params ¶ms);
|
|
2470
|
+
Result Put(const std::string &path, const Headers &headers, const UploadFormDataItems &items, UploadProgress progress = nullptr);
|
|
2471
|
+
Result Put(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const std::string &boundary, UploadProgress progress = nullptr);
|
|
2472
|
+
Result Put(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const FormDataProviderItems &provider_items, UploadProgress progress = nullptr);
|
|
2473
|
+
Result Put(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2474
|
+
|
|
2475
|
+
Result Patch(const std::string &path);
|
|
2476
|
+
Result Patch(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2477
|
+
Result Patch(const std::string &path, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2478
|
+
Result Patch(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2479
|
+
Result Patch(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2480
|
+
Result Patch(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2481
|
+
Result Patch(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2482
|
+
Result Patch(const std::string &path, const Params ¶ms);
|
|
2483
|
+
Result Patch(const std::string &path, const UploadFormDataItems &items, UploadProgress progress = nullptr);
|
|
2484
|
+
Result Patch(const std::string &path, const Headers &headers);
|
|
2485
|
+
Result Patch(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2486
|
+
Result Patch(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2487
|
+
Result Patch(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2488
|
+
Result Patch(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2489
|
+
Result Patch(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
|
|
2490
|
+
Result Patch(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
|
|
2491
|
+
Result Patch(const std::string &path, const Headers &headers, const Params ¶ms);
|
|
2492
|
+
Result Patch(const std::string &path, const Headers &headers, const UploadFormDataItems &items, UploadProgress progress = nullptr);
|
|
2493
|
+
Result Patch(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const std::string &boundary, UploadProgress progress = nullptr);
|
|
2494
|
+
Result Patch(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const FormDataProviderItems &provider_items, UploadProgress progress = nullptr);
|
|
2495
|
+
Result Patch(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
|
|
2496
|
+
|
|
2497
|
+
Result Delete(const std::string &path, DownloadProgress progress = nullptr);
|
|
2498
|
+
Result Delete(const std::string &path, const char *body, size_t content_length, const std::string &content_type, DownloadProgress progress = nullptr);
|
|
2499
|
+
Result Delete(const std::string &path, const std::string &body, const std::string &content_type, DownloadProgress progress = nullptr);
|
|
2500
|
+
Result Delete(const std::string &path, const Params ¶ms, DownloadProgress progress = nullptr);
|
|
2501
|
+
Result Delete(const std::string &path, const Headers &headers, DownloadProgress progress = nullptr);
|
|
2502
|
+
Result Delete(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, DownloadProgress progress = nullptr);
|
|
2503
|
+
Result Delete(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, DownloadProgress progress = nullptr);
|
|
2504
|
+
Result Delete(const std::string &path, const Headers &headers, const Params ¶ms, DownloadProgress progress = nullptr);
|
|
2505
|
+
|
|
2506
|
+
Result Options(const std::string &path);
|
|
2507
|
+
Result Options(const std::string &path, const Headers &headers);
|
|
2508
|
+
// clang-format on
|
|
2509
|
+
|
|
2510
|
+
// Streaming API: Open a stream for reading response body incrementally
|
|
2511
|
+
// Socket ownership is transferred to StreamHandle for true streaming
|
|
2512
|
+
// Supports all HTTP methods (GET, POST, PUT, PATCH, DELETE, etc.)
|
|
2513
|
+
ClientImpl::StreamHandle open_stream(const std::string &method,
|
|
2514
|
+
const std::string &path,
|
|
2515
|
+
const Params ¶ms = {},
|
|
2516
|
+
const Headers &headers = {},
|
|
2517
|
+
const std::string &body = {},
|
|
2518
|
+
const std::string &content_type = {});
|
|
2519
|
+
|
|
2520
|
+
bool send(Request &req, Response &res, Error &error);
|
|
2521
|
+
Result send(const Request &req);
|
|
2522
|
+
|
|
2523
|
+
void stop();
|
|
2524
|
+
|
|
2525
|
+
std::string host() const;
|
|
2526
|
+
int port() const;
|
|
2527
|
+
|
|
2528
|
+
size_t is_socket_open() const;
|
|
2529
|
+
socket_t socket() const;
|
|
2530
|
+
|
|
2531
|
+
void set_hostname_addr_map(std::map<std::string, std::string> addr_map);
|
|
2532
|
+
|
|
2533
|
+
void set_default_headers(Headers headers);
|
|
2534
|
+
|
|
2535
|
+
void
|
|
2536
|
+
set_header_writer(std::function<ssize_t(Stream &, Headers &)> const &writer);
|
|
2537
|
+
|
|
2538
|
+
void set_address_family(int family);
|
|
2539
|
+
void set_tcp_nodelay(bool on);
|
|
2540
|
+
void set_socket_options(SocketOptions socket_options);
|
|
2541
|
+
|
|
2542
|
+
void set_connection_timeout(time_t sec, time_t usec = 0);
|
|
2543
|
+
template <class Rep, class Period>
|
|
2544
|
+
void
|
|
2545
|
+
set_connection_timeout(const std::chrono::duration<Rep, Period> &duration);
|
|
2546
|
+
|
|
2547
|
+
void set_read_timeout(time_t sec, time_t usec = 0);
|
|
2548
|
+
template <class Rep, class Period>
|
|
2549
|
+
void set_read_timeout(const std::chrono::duration<Rep, Period> &duration);
|
|
2550
|
+
|
|
2551
|
+
void set_write_timeout(time_t sec, time_t usec = 0);
|
|
2552
|
+
template <class Rep, class Period>
|
|
2553
|
+
void set_write_timeout(const std::chrono::duration<Rep, Period> &duration);
|
|
2554
|
+
|
|
2555
|
+
void set_max_timeout(time_t msec);
|
|
2556
|
+
template <class Rep, class Period>
|
|
2557
|
+
void set_max_timeout(const std::chrono::duration<Rep, Period> &duration);
|
|
2558
|
+
|
|
2559
|
+
void set_basic_auth(const std::string &username, const std::string &password);
|
|
2560
|
+
void set_bearer_token_auth(const std::string &token);
|
|
2561
|
+
|
|
2562
|
+
void set_keep_alive(bool on);
|
|
2563
|
+
void set_follow_location(bool on);
|
|
2564
|
+
|
|
2565
|
+
void set_path_encode(bool on);
|
|
2566
|
+
void set_url_encode(bool on);
|
|
2567
|
+
|
|
2568
|
+
void set_compress(bool on);
|
|
2569
|
+
|
|
2570
|
+
void set_decompress(bool on);
|
|
2571
|
+
|
|
2572
|
+
void set_payload_max_length(size_t length);
|
|
2573
|
+
|
|
2574
|
+
void set_interface(const std::string &intf);
|
|
2575
|
+
|
|
2576
|
+
void set_proxy(const std::string &host, int port);
|
|
2577
|
+
void set_proxy_basic_auth(const std::string &username,
|
|
2578
|
+
const std::string &password);
|
|
2579
|
+
void set_proxy_bearer_token_auth(const std::string &token);
|
|
2580
|
+
void set_logger(Logger logger);
|
|
2581
|
+
void set_error_logger(ErrorLogger error_logger);
|
|
2582
|
+
|
|
2583
|
+
private:
|
|
2584
|
+
std::unique_ptr<ClientImpl> cli_;
|
|
2585
|
+
|
|
2586
|
+
#ifdef CPPHTTPLIB_SSL_ENABLED
|
|
2587
|
+
public:
|
|
2588
|
+
void set_digest_auth(const std::string &username,
|
|
2589
|
+
const std::string &password);
|
|
2590
|
+
void set_proxy_digest_auth(const std::string &username,
|
|
2591
|
+
const std::string &password);
|
|
2592
|
+
void enable_server_certificate_verification(bool enabled);
|
|
2593
|
+
void enable_server_hostname_verification(bool enabled);
|
|
2594
|
+
void set_ca_cert_path(const std::string &ca_cert_file_path,
|
|
2595
|
+
const std::string &ca_cert_dir_path = std::string());
|
|
2596
|
+
|
|
2597
|
+
void set_ca_cert_store(tls::ca_store_t ca_cert_store);
|
|
2598
|
+
void load_ca_cert_store(const char *ca_cert, std::size_t size);
|
|
2599
|
+
|
|
2600
|
+
void set_server_certificate_verifier(tls::VerifyCallback verifier);
|
|
2601
|
+
|
|
2602
|
+
void set_session_verifier(
|
|
2603
|
+
std::function<SSLVerifierResponse(tls::session_t)> verifier);
|
|
2604
|
+
|
|
2605
|
+
tls::ctx_t tls_context() const;
|
|
2606
|
+
|
|
2607
|
+
#ifdef CPPHTTPLIB_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
|
|
2608
|
+
void enable_windows_certificate_verification(bool enabled);
|
|
2609
|
+
#endif
|
|
2610
|
+
|
|
2611
|
+
private:
|
|
2612
|
+
bool is_ssl_ = false;
|
|
2613
|
+
#endif
|
|
2614
|
+
|
|
2615
|
+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
|
2616
|
+
public:
|
|
2617
|
+
[[deprecated("Use tls_context() instead. "
|
|
2618
|
+
"This function will be removed by v1.0.0.")]]
|
|
2619
|
+
SSL_CTX *ssl_context() const;
|
|
2620
|
+
|
|
2621
|
+
[[deprecated("Use set_session_verifier(session_t) instead. "
|
|
2622
|
+
"This function will be removed by v1.0.0.")]]
|
|
2623
|
+
void set_server_certificate_verifier(
|
|
2624
|
+
std::function<SSLVerifierResponse(SSL *ssl)> verifier);
|
|
2625
|
+
|
|
2626
|
+
[[deprecated("Use Result::ssl_backend_error() instead. "
|
|
2627
|
+
"This function will be removed by v1.0.0.")]]
|
|
2628
|
+
long get_verify_result() const;
|
|
2629
|
+
#endif
|
|
2630
|
+
};
|
|
2631
|
+
|
|
2632
|
+
#ifdef CPPHTTPLIB_SSL_ENABLED
|
|
2633
|
+
class SSLServer : public Server {
|
|
2634
|
+
public:
|
|
2635
|
+
SSLServer(const char *cert_path, const char *private_key_path,
|
|
2636
|
+
const char *client_ca_cert_file_path = nullptr,
|
|
2637
|
+
const char *client_ca_cert_dir_path = nullptr,
|
|
2638
|
+
const char *private_key_password = nullptr);
|
|
2639
|
+
|
|
2640
|
+
struct PemMemory {
|
|
2641
|
+
const char *cert_pem;
|
|
2642
|
+
size_t cert_pem_len;
|
|
2643
|
+
const char *key_pem;
|
|
2644
|
+
size_t key_pem_len;
|
|
2645
|
+
const char *client_ca_pem;
|
|
2646
|
+
size_t client_ca_pem_len;
|
|
2647
|
+
const char *private_key_password;
|
|
2648
|
+
};
|
|
2649
|
+
explicit SSLServer(const PemMemory &pem);
|
|
2650
|
+
|
|
2651
|
+
// The callback receives the ctx_t handle which can be cast to the
|
|
2652
|
+
// appropriate backend type (SSL_CTX* for OpenSSL,
|
|
2653
|
+
// tls::impl::MbedTlsContext* for Mbed TLS)
|
|
2654
|
+
explicit SSLServer(const tls::ContextSetupCallback &setup_callback);
|
|
2655
|
+
|
|
2656
|
+
~SSLServer() override;
|
|
2657
|
+
|
|
2658
|
+
bool is_valid() const override;
|
|
2659
|
+
|
|
2660
|
+
bool update_certs_pem(const char *cert_pem, const char *key_pem,
|
|
2661
|
+
const char *client_ca_pem = nullptr,
|
|
2662
|
+
const char *password = nullptr);
|
|
2663
|
+
|
|
2664
|
+
tls::ctx_t tls_context() const { return ctx_; }
|
|
2665
|
+
|
|
2666
|
+
int ssl_last_error() const { return last_ssl_error_; }
|
|
2667
|
+
|
|
2668
|
+
private:
|
|
2669
|
+
bool process_and_close_socket(socket_t sock) override;
|
|
2670
|
+
|
|
2671
|
+
tls::ctx_t ctx_ = nullptr;
|
|
2672
|
+
std::mutex ctx_mutex_;
|
|
2673
|
+
|
|
2674
|
+
int last_ssl_error_ = 0;
|
|
2675
|
+
|
|
2676
|
+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
|
2677
|
+
public:
|
|
2678
|
+
[[deprecated("Use SSLServer(PemMemory) or "
|
|
2679
|
+
"SSLServer(ContextSetupCallback) instead. "
|
|
2680
|
+
"This constructor will be removed by v1.0.0.")]]
|
|
2681
|
+
SSLServer(X509 *cert, EVP_PKEY *private_key,
|
|
2682
|
+
X509_STORE *client_ca_cert_store = nullptr);
|
|
2683
|
+
|
|
2684
|
+
[[deprecated("Use SSLServer(ContextSetupCallback) instead. "
|
|
2685
|
+
"This constructor will be removed by v1.0.0.")]]
|
|
2686
|
+
SSLServer(
|
|
2687
|
+
const std::function<bool(SSL_CTX &ssl_ctx)> &setup_ssl_ctx_callback);
|
|
2688
|
+
|
|
2689
|
+
[[deprecated("Use tls_context() instead. "
|
|
2690
|
+
"This function will be removed by v1.0.0.")]]
|
|
2691
|
+
SSL_CTX *ssl_context() const;
|
|
2692
|
+
|
|
2693
|
+
[[deprecated("Use update_certs_pem() instead. "
|
|
2694
|
+
"This function will be removed by v1.0.0.")]]
|
|
2695
|
+
void update_certs(X509 *cert, EVP_PKEY *private_key,
|
|
2696
|
+
X509_STORE *client_ca_cert_store = nullptr);
|
|
2697
|
+
#endif
|
|
2698
|
+
};
|
|
2699
|
+
|
|
2700
|
+
class SSLClient final : public ClientImpl {
|
|
2701
|
+
public:
|
|
2702
|
+
explicit SSLClient(const std::string &host);
|
|
2703
|
+
|
|
2704
|
+
explicit SSLClient(const std::string &host, int port);
|
|
2705
|
+
|
|
2706
|
+
explicit SSLClient(const std::string &host, int port,
|
|
2707
|
+
const std::string &client_cert_path,
|
|
2708
|
+
const std::string &client_key_path,
|
|
2709
|
+
const std::string &private_key_password = std::string());
|
|
2710
|
+
|
|
2711
|
+
struct PemMemory {
|
|
2712
|
+
const char *cert_pem;
|
|
2713
|
+
size_t cert_pem_len;
|
|
2714
|
+
const char *key_pem;
|
|
2715
|
+
size_t key_pem_len;
|
|
2716
|
+
const char *private_key_password;
|
|
2717
|
+
};
|
|
2718
|
+
explicit SSLClient(const std::string &host, int port, const PemMemory &pem);
|
|
2719
|
+
|
|
2720
|
+
~SSLClient() override;
|
|
2721
|
+
|
|
2722
|
+
bool is_valid() const override;
|
|
2723
|
+
|
|
2724
|
+
void set_ca_cert_store(tls::ca_store_t ca_cert_store);
|
|
2725
|
+
void load_ca_cert_store(const char *ca_cert, std::size_t size);
|
|
2726
|
+
|
|
2727
|
+
void set_server_certificate_verifier(tls::VerifyCallback verifier);
|
|
2728
|
+
|
|
2729
|
+
// Post-handshake session verifier (backend-independent)
|
|
2730
|
+
void set_session_verifier(
|
|
2731
|
+
std::function<SSLVerifierResponse(tls::session_t)> verifier);
|
|
2732
|
+
|
|
2733
|
+
tls::ctx_t tls_context() const { return ctx_; }
|
|
2734
|
+
|
|
2735
|
+
#ifdef CPPHTTPLIB_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
|
|
2736
|
+
void enable_windows_certificate_verification(bool enabled);
|
|
2737
|
+
#endif
|
|
2738
|
+
|
|
2739
|
+
private:
|
|
2740
|
+
bool create_and_connect_socket(Socket &socket, Error &error) override;
|
|
2741
|
+
bool ensure_socket_connection(Socket &socket, Error &error) override;
|
|
2742
|
+
void shutdown_ssl(Socket &socket, bool shutdown_gracefully) override;
|
|
2743
|
+
void shutdown_ssl_impl(Socket &socket, bool shutdown_gracefully);
|
|
2744
|
+
|
|
2745
|
+
bool
|
|
2746
|
+
process_socket(const Socket &socket,
|
|
2747
|
+
std::chrono::time_point<std::chrono::steady_clock> start_time,
|
|
2748
|
+
std::function<bool(Stream &strm)> callback) override;
|
|
2749
|
+
bool is_ssl() const override;
|
|
2750
|
+
|
|
2751
|
+
bool setup_proxy_connection(
|
|
2752
|
+
Socket &socket,
|
|
2753
|
+
std::chrono::time_point<std::chrono::steady_clock> start_time,
|
|
2754
|
+
Response &res, bool &success, Error &error) override;
|
|
2755
|
+
bool connect_with_proxy(
|
|
2756
|
+
Socket &sock,
|
|
2757
|
+
std::chrono::time_point<std::chrono::steady_clock> start_time,
|
|
2758
|
+
Response &res, bool &success, Error &error);
|
|
2759
|
+
bool initialize_ssl(Socket &socket, Error &error);
|
|
2760
|
+
|
|
2761
|
+
bool load_certs();
|
|
2762
|
+
|
|
2763
|
+
tls::ctx_t ctx_ = nullptr;
|
|
2764
|
+
std::mutex ctx_mutex_;
|
|
2765
|
+
std::once_flag initialize_cert_;
|
|
2766
|
+
|
|
2767
|
+
long verify_result_ = 0;
|
|
2768
|
+
|
|
2769
|
+
std::function<SSLVerifierResponse(tls::session_t)> session_verifier_;
|
|
2770
|
+
|
|
2771
|
+
#ifdef CPPHTTPLIB_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
|
|
2772
|
+
bool enable_windows_cert_verification_ = true;
|
|
2773
|
+
#endif
|
|
2774
|
+
|
|
2775
|
+
friend class ClientImpl;
|
|
2776
|
+
|
|
2777
|
+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
|
2778
|
+
public:
|
|
2779
|
+
[[deprecated("Use SSLClient(host, port, PemMemory) instead. "
|
|
2780
|
+
"This constructor will be removed by v1.0.0.")]]
|
|
2781
|
+
explicit SSLClient(const std::string &host, int port, X509 *client_cert,
|
|
2782
|
+
EVP_PKEY *client_key,
|
|
2783
|
+
const std::string &private_key_password = std::string());
|
|
2784
|
+
|
|
2785
|
+
[[deprecated("Use Result::ssl_backend_error() instead. "
|
|
2786
|
+
"This function will be removed by v1.0.0.")]]
|
|
2787
|
+
long get_verify_result() const;
|
|
2788
|
+
|
|
2789
|
+
[[deprecated("Use tls_context() instead. "
|
|
2790
|
+
"This function will be removed by v1.0.0.")]]
|
|
2791
|
+
SSL_CTX *ssl_context() const;
|
|
2792
|
+
|
|
2793
|
+
[[deprecated("Use set_session_verifier(session_t) instead. "
|
|
2794
|
+
"This function will be removed by v1.0.0.")]]
|
|
2795
|
+
void set_server_certificate_verifier(
|
|
2796
|
+
std::function<SSLVerifierResponse(SSL *ssl)> verifier) override;
|
|
2797
|
+
|
|
2798
|
+
private:
|
|
2799
|
+
bool verify_host(X509 *server_cert) const;
|
|
2800
|
+
bool verify_host_with_subject_alt_name(X509 *server_cert) const;
|
|
2801
|
+
bool verify_host_with_common_name(X509 *server_cert) const;
|
|
2802
|
+
#endif
|
|
2803
|
+
};
|
|
2804
|
+
#endif // CPPHTTPLIB_SSL_ENABLED
|
|
2805
|
+
|
|
2806
|
+
namespace detail {
|
|
2807
|
+
|
|
2808
|
+
template <typename T, typename U>
|
|
2809
|
+
inline void duration_to_sec_and_usec(const T &duration, U callback) {
|
|
2810
|
+
auto sec = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
|
|
2811
|
+
auto usec = std::chrono::duration_cast<std::chrono::microseconds>(
|
|
2812
|
+
duration - std::chrono::seconds(sec))
|
|
2813
|
+
.count();
|
|
2814
|
+
callback(static_cast<time_t>(sec), static_cast<time_t>(usec));
|
|
2815
|
+
}
|
|
2816
|
+
|
|
2817
|
+
template <size_t N> inline constexpr size_t str_len(const char (&)[N]) {
|
|
2818
|
+
return N - 1;
|
|
2819
|
+
}
|
|
2820
|
+
|
|
2821
|
+
inline bool is_numeric(const std::string &str) {
|
|
2822
|
+
return !str.empty() &&
|
|
2823
|
+
std::all_of(str.cbegin(), str.cend(),
|
|
2824
|
+
[](unsigned char c) { return std::isdigit(c); });
|
|
2825
|
+
}
|
|
2826
|
+
|
|
2827
|
+
inline size_t get_header_value_u64(const Headers &headers,
|
|
2828
|
+
const std::string &key, size_t def,
|
|
2829
|
+
size_t id, bool &is_invalid_value) {
|
|
2830
|
+
is_invalid_value = false;
|
|
2831
|
+
auto rng = headers.equal_range(key);
|
|
2832
|
+
auto it = rng.first;
|
|
2833
|
+
std::advance(it, static_cast<ssize_t>(id));
|
|
2834
|
+
if (it != rng.second) {
|
|
2835
|
+
if (is_numeric(it->second)) {
|
|
2836
|
+
return static_cast<size_t>(std::strtoull(it->second.data(), nullptr, 10));
|
|
2837
|
+
} else {
|
|
2838
|
+
is_invalid_value = true;
|
|
2839
|
+
}
|
|
2840
|
+
}
|
|
2841
|
+
return def;
|
|
2842
|
+
}
|
|
2843
|
+
|
|
2844
|
+
inline size_t get_header_value_u64(const Headers &headers,
|
|
2845
|
+
const std::string &key, size_t def,
|
|
2846
|
+
size_t id) {
|
|
2847
|
+
auto dummy = false;
|
|
2848
|
+
return get_header_value_u64(headers, key, def, id, dummy);
|
|
2849
|
+
}
|
|
2850
|
+
|
|
2851
|
+
} // namespace detail
|
|
2852
|
+
|
|
2853
|
+
template <class Rep, class Period>
|
|
2854
|
+
inline Server &
|
|
2855
|
+
Server::set_read_timeout(const std::chrono::duration<Rep, Period> &duration) {
|
|
2856
|
+
detail::duration_to_sec_and_usec(
|
|
2857
|
+
duration, [&](time_t sec, time_t usec) { set_read_timeout(sec, usec); });
|
|
2858
|
+
return *this;
|
|
2859
|
+
}
|
|
2860
|
+
|
|
2861
|
+
template <class Rep, class Period>
|
|
2862
|
+
inline Server &
|
|
2863
|
+
Server::set_write_timeout(const std::chrono::duration<Rep, Period> &duration) {
|
|
2864
|
+
detail::duration_to_sec_and_usec(
|
|
2865
|
+
duration, [&](time_t sec, time_t usec) { set_write_timeout(sec, usec); });
|
|
2866
|
+
return *this;
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2869
|
+
template <class Rep, class Period>
|
|
2870
|
+
inline Server &
|
|
2871
|
+
Server::set_idle_interval(const std::chrono::duration<Rep, Period> &duration) {
|
|
2872
|
+
detail::duration_to_sec_and_usec(
|
|
2873
|
+
duration, [&](time_t sec, time_t usec) { set_idle_interval(sec, usec); });
|
|
2874
|
+
return *this;
|
|
2875
|
+
}
|
|
2876
|
+
|
|
2877
|
+
template <class Rep, class Period>
|
|
2878
|
+
inline void ClientImpl::set_connection_timeout(
|
|
2879
|
+
const std::chrono::duration<Rep, Period> &duration) {
|
|
2880
|
+
detail::duration_to_sec_and_usec(duration, [&](time_t sec, time_t usec) {
|
|
2881
|
+
set_connection_timeout(sec, usec);
|
|
2882
|
+
});
|
|
2883
|
+
}
|
|
2884
|
+
|
|
2885
|
+
template <class Rep, class Period>
|
|
2886
|
+
inline void ClientImpl::set_read_timeout(
|
|
2887
|
+
const std::chrono::duration<Rep, Period> &duration) {
|
|
2888
|
+
detail::duration_to_sec_and_usec(
|
|
2889
|
+
duration, [&](time_t sec, time_t usec) { set_read_timeout(sec, usec); });
|
|
2890
|
+
}
|
|
2891
|
+
|
|
2892
|
+
template <class Rep, class Period>
|
|
2893
|
+
inline void ClientImpl::set_write_timeout(
|
|
2894
|
+
const std::chrono::duration<Rep, Period> &duration) {
|
|
2895
|
+
detail::duration_to_sec_and_usec(
|
|
2896
|
+
duration, [&](time_t sec, time_t usec) { set_write_timeout(sec, usec); });
|
|
2897
|
+
}
|
|
2898
|
+
|
|
2899
|
+
template <class Rep, class Period>
|
|
2900
|
+
inline void ClientImpl::set_max_timeout(
|
|
2901
|
+
const std::chrono::duration<Rep, Period> &duration) {
|
|
2902
|
+
auto msec =
|
|
2903
|
+
std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
|
|
2904
|
+
set_max_timeout(msec);
|
|
2905
|
+
}
|
|
2906
|
+
|
|
2907
|
+
template <class Rep, class Period>
|
|
2908
|
+
inline void Client::set_connection_timeout(
|
|
2909
|
+
const std::chrono::duration<Rep, Period> &duration) {
|
|
2910
|
+
cli_->set_connection_timeout(duration);
|
|
2911
|
+
}
|
|
2912
|
+
|
|
2913
|
+
template <class Rep, class Period>
|
|
2914
|
+
inline void
|
|
2915
|
+
Client::set_read_timeout(const std::chrono::duration<Rep, Period> &duration) {
|
|
2916
|
+
cli_->set_read_timeout(duration);
|
|
2917
|
+
}
|
|
2918
|
+
|
|
2919
|
+
template <class Rep, class Period>
|
|
2920
|
+
inline void
|
|
2921
|
+
Client::set_write_timeout(const std::chrono::duration<Rep, Period> &duration) {
|
|
2922
|
+
cli_->set_write_timeout(duration);
|
|
2923
|
+
}
|
|
2924
|
+
|
|
2925
|
+
inline void Client::set_max_timeout(time_t msec) {
|
|
2926
|
+
cli_->set_max_timeout(msec);
|
|
2927
|
+
}
|
|
2928
|
+
|
|
2929
|
+
template <class Rep, class Period>
|
|
2930
|
+
inline void
|
|
2931
|
+
Client::set_max_timeout(const std::chrono::duration<Rep, Period> &duration) {
|
|
2932
|
+
cli_->set_max_timeout(duration);
|
|
2933
|
+
}
|
|
2934
|
+
|
|
2935
|
+
/*
|
|
2936
|
+
* Forward declarations and types that will be part of the .h file if split into
|
|
2937
|
+
* .h + .cc.
|
|
2938
|
+
*/
|
|
2939
|
+
|
|
2940
|
+
std::string hosted_at(const std::string &hostname);
|
|
2941
|
+
|
|
2942
|
+
void hosted_at(const std::string &hostname, std::vector<std::string> &addrs);
|
|
2943
|
+
|
|
2944
|
+
// JavaScript-style URL encoding/decoding functions
|
|
2945
|
+
std::string encode_uri_component(const std::string &value);
|
|
2946
|
+
std::string encode_uri(const std::string &value);
|
|
2947
|
+
std::string decode_uri_component(const std::string &value);
|
|
2948
|
+
std::string decode_uri(const std::string &value);
|
|
2949
|
+
|
|
2950
|
+
// RFC 3986 compliant URL component encoding/decoding functions
|
|
2951
|
+
std::string encode_path_component(const std::string &component);
|
|
2952
|
+
std::string decode_path_component(const std::string &component);
|
|
2953
|
+
std::string encode_query_component(const std::string &component,
|
|
2954
|
+
bool space_as_plus = true);
|
|
2955
|
+
std::string decode_query_component(const std::string &component,
|
|
2956
|
+
bool plus_as_space = true);
|
|
2957
|
+
|
|
2958
|
+
std::string sanitize_filename(const std::string &filename);
|
|
2959
|
+
|
|
2960
|
+
std::string append_query_params(const std::string &path, const Params ¶ms);
|
|
2961
|
+
|
|
2962
|
+
std::pair<std::string, std::string> make_range_header(const Ranges &ranges);
|
|
2963
|
+
|
|
2964
|
+
std::pair<std::string, std::string>
|
|
2965
|
+
make_basic_authentication_header(const std::string &username,
|
|
2966
|
+
const std::string &password,
|
|
2967
|
+
bool is_proxy = false);
|
|
2968
|
+
|
|
2969
|
+
namespace detail {
|
|
2970
|
+
|
|
2971
|
+
#if defined(_WIN32)
|
|
2972
|
+
inline std::wstring u8string_to_wstring(const char *s) {
|
|
2973
|
+
if (!s) { return std::wstring(); }
|
|
2974
|
+
|
|
2975
|
+
auto len = static_cast<int>(strlen(s));
|
|
2976
|
+
if (!len) { return std::wstring(); }
|
|
2977
|
+
|
|
2978
|
+
auto wlen = ::MultiByteToWideChar(CP_UTF8, 0, s, len, nullptr, 0);
|
|
2979
|
+
if (!wlen) { return std::wstring(); }
|
|
2980
|
+
|
|
2981
|
+
std::wstring ws;
|
|
2982
|
+
ws.resize(wlen);
|
|
2983
|
+
wlen = ::MultiByteToWideChar(
|
|
2984
|
+
CP_UTF8, 0, s, len,
|
|
2985
|
+
const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(ws.data())), wlen);
|
|
2986
|
+
if (wlen != static_cast<int>(ws.size())) { ws.clear(); }
|
|
2987
|
+
return ws;
|
|
2988
|
+
}
|
|
2989
|
+
#endif
|
|
2990
|
+
|
|
2991
|
+
struct FileStat {
|
|
2992
|
+
FileStat(const std::string &path);
|
|
2993
|
+
bool is_file() const;
|
|
2994
|
+
bool is_dir() const;
|
|
2995
|
+
time_t mtime() const;
|
|
2996
|
+
size_t size() const;
|
|
2997
|
+
|
|
2998
|
+
private:
|
|
2999
|
+
#if defined(_WIN32)
|
|
3000
|
+
struct _stat st_;
|
|
3001
|
+
#else
|
|
3002
|
+
struct stat st_;
|
|
3003
|
+
#endif
|
|
3004
|
+
int ret_ = -1;
|
|
3005
|
+
};
|
|
3006
|
+
|
|
3007
|
+
std::string make_host_and_port_string(const std::string &host, int port,
|
|
3008
|
+
bool is_ssl);
|
|
3009
|
+
|
|
3010
|
+
std::string trim_copy(const std::string &s);
|
|
3011
|
+
|
|
3012
|
+
void divide(
|
|
3013
|
+
const char *data, std::size_t size, char d,
|
|
3014
|
+
std::function<void(const char *, std::size_t, const char *, std::size_t)>
|
|
3015
|
+
fn);
|
|
3016
|
+
|
|
3017
|
+
void divide(
|
|
3018
|
+
const std::string &str, char d,
|
|
3019
|
+
std::function<void(const char *, std::size_t, const char *, std::size_t)>
|
|
3020
|
+
fn);
|
|
3021
|
+
|
|
3022
|
+
void split(const char *b, const char *e, char d,
|
|
3023
|
+
std::function<void(const char *, const char *)> fn);
|
|
3024
|
+
|
|
3025
|
+
void split(const char *b, const char *e, char d, size_t m,
|
|
3026
|
+
std::function<void(const char *, const char *)> fn);
|
|
3027
|
+
|
|
3028
|
+
bool process_client_socket(
|
|
3029
|
+
socket_t sock, time_t read_timeout_sec, time_t read_timeout_usec,
|
|
3030
|
+
time_t write_timeout_sec, time_t write_timeout_usec,
|
|
3031
|
+
time_t max_timeout_msec,
|
|
3032
|
+
std::chrono::time_point<std::chrono::steady_clock> start_time,
|
|
3033
|
+
std::function<bool(Stream &)> callback);
|
|
3034
|
+
|
|
3035
|
+
socket_t create_client_socket(const std::string &host, const std::string &ip,
|
|
3036
|
+
int port, int address_family, bool tcp_nodelay,
|
|
3037
|
+
bool ipv6_v6only, SocketOptions socket_options,
|
|
3038
|
+
time_t connection_timeout_sec,
|
|
3039
|
+
time_t connection_timeout_usec,
|
|
3040
|
+
time_t read_timeout_sec, time_t read_timeout_usec,
|
|
3041
|
+
time_t write_timeout_sec,
|
|
3042
|
+
time_t write_timeout_usec,
|
|
3043
|
+
const std::string &intf, Error &error);
|
|
3044
|
+
|
|
3045
|
+
const char *get_header_value(const Headers &headers, const std::string &key,
|
|
3046
|
+
const char *def, size_t id);
|
|
3047
|
+
|
|
3048
|
+
std::string params_to_query_str(const Params ¶ms);
|
|
3049
|
+
|
|
3050
|
+
void parse_query_text(const char *data, std::size_t size, Params ¶ms);
|
|
3051
|
+
|
|
3052
|
+
void parse_query_text(const std::string &s, Params ¶ms);
|
|
3053
|
+
|
|
3054
|
+
bool parse_multipart_boundary(const std::string &content_type,
|
|
3055
|
+
std::string &boundary);
|
|
3056
|
+
|
|
3057
|
+
bool parse_range_header(const std::string &s, Ranges &ranges);
|
|
3058
|
+
|
|
3059
|
+
bool parse_accept_header(const std::string &s,
|
|
3060
|
+
std::vector<std::string> &content_types);
|
|
3061
|
+
|
|
3062
|
+
int close_socket(socket_t sock);
|
|
3063
|
+
|
|
3064
|
+
ssize_t send_socket(socket_t sock, const void *ptr, size_t size, int flags);
|
|
3065
|
+
|
|
3066
|
+
ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags);
|
|
3067
|
+
|
|
3068
|
+
enum class EncodingType { None = 0, Gzip, Brotli, Zstd };
|
|
3069
|
+
|
|
3070
|
+
EncodingType encoding_type(const Request &req, const Response &res);
|
|
3071
|
+
|
|
3072
|
+
class BufferStream final : public Stream {
|
|
3073
|
+
public:
|
|
3074
|
+
BufferStream() = default;
|
|
3075
|
+
~BufferStream() override = default;
|
|
3076
|
+
|
|
3077
|
+
bool is_readable() const override;
|
|
3078
|
+
bool wait_readable() const override;
|
|
3079
|
+
bool wait_writable() const override;
|
|
3080
|
+
ssize_t read(char *ptr, size_t size) override;
|
|
3081
|
+
ssize_t write(const char *ptr, size_t size) override;
|
|
3082
|
+
void get_remote_ip_and_port(std::string &ip, int &port) const override;
|
|
3083
|
+
void get_local_ip_and_port(std::string &ip, int &port) const override;
|
|
3084
|
+
socket_t socket() const override;
|
|
3085
|
+
time_t duration() const override;
|
|
3086
|
+
|
|
3087
|
+
const std::string &get_buffer() const;
|
|
3088
|
+
|
|
3089
|
+
private:
|
|
3090
|
+
std::string buffer;
|
|
3091
|
+
size_t position = 0;
|
|
3092
|
+
};
|
|
3093
|
+
|
|
3094
|
+
class compressor {
|
|
3095
|
+
public:
|
|
3096
|
+
virtual ~compressor() = default;
|
|
3097
|
+
|
|
3098
|
+
typedef std::function<bool(const char *data, size_t data_len)> Callback;
|
|
3099
|
+
virtual bool compress(const char *data, size_t data_length, bool last,
|
|
3100
|
+
Callback callback) = 0;
|
|
3101
|
+
};
|
|
3102
|
+
|
|
3103
|
+
class decompressor {
|
|
3104
|
+
public:
|
|
3105
|
+
virtual ~decompressor() = default;
|
|
3106
|
+
|
|
3107
|
+
virtual bool is_valid() const = 0;
|
|
3108
|
+
|
|
3109
|
+
typedef std::function<bool(const char *data, size_t data_len)> Callback;
|
|
3110
|
+
virtual bool decompress(const char *data, size_t data_length,
|
|
3111
|
+
Callback callback) = 0;
|
|
3112
|
+
};
|
|
3113
|
+
|
|
3114
|
+
class nocompressor final : public compressor {
|
|
3115
|
+
public:
|
|
3116
|
+
~nocompressor() override = default;
|
|
3117
|
+
|
|
3118
|
+
bool compress(const char *data, size_t data_length, bool /*last*/,
|
|
3119
|
+
Callback callback) override;
|
|
3120
|
+
};
|
|
3121
|
+
|
|
3122
|
+
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
|
3123
|
+
class gzip_compressor final : public compressor {
|
|
3124
|
+
public:
|
|
3125
|
+
gzip_compressor();
|
|
3126
|
+
~gzip_compressor() override;
|
|
3127
|
+
|
|
3128
|
+
bool compress(const char *data, size_t data_length, bool last,
|
|
3129
|
+
Callback callback) override;
|
|
3130
|
+
|
|
3131
|
+
private:
|
|
3132
|
+
bool is_valid_ = false;
|
|
3133
|
+
z_stream strm_;
|
|
3134
|
+
};
|
|
3135
|
+
|
|
3136
|
+
class gzip_decompressor final : public decompressor {
|
|
3137
|
+
public:
|
|
3138
|
+
gzip_decompressor();
|
|
3139
|
+
~gzip_decompressor() override;
|
|
3140
|
+
|
|
3141
|
+
bool is_valid() const override;
|
|
3142
|
+
|
|
3143
|
+
bool decompress(const char *data, size_t data_length,
|
|
3144
|
+
Callback callback) override;
|
|
3145
|
+
|
|
3146
|
+
private:
|
|
3147
|
+
bool is_valid_ = false;
|
|
3148
|
+
z_stream strm_;
|
|
3149
|
+
};
|
|
3150
|
+
#endif
|
|
3151
|
+
|
|
3152
|
+
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
|
3153
|
+
class brotli_compressor final : public compressor {
|
|
3154
|
+
public:
|
|
3155
|
+
brotli_compressor();
|
|
3156
|
+
~brotli_compressor();
|
|
3157
|
+
|
|
3158
|
+
bool compress(const char *data, size_t data_length, bool last,
|
|
3159
|
+
Callback callback) override;
|
|
3160
|
+
|
|
3161
|
+
private:
|
|
3162
|
+
BrotliEncoderState *state_ = nullptr;
|
|
3163
|
+
};
|
|
3164
|
+
|
|
3165
|
+
class brotli_decompressor final : public decompressor {
|
|
3166
|
+
public:
|
|
3167
|
+
brotli_decompressor();
|
|
3168
|
+
~brotli_decompressor();
|
|
3169
|
+
|
|
3170
|
+
bool is_valid() const override;
|
|
3171
|
+
|
|
3172
|
+
bool decompress(const char *data, size_t data_length,
|
|
3173
|
+
Callback callback) override;
|
|
3174
|
+
|
|
3175
|
+
private:
|
|
3176
|
+
BrotliDecoderResult decoder_r;
|
|
3177
|
+
BrotliDecoderState *decoder_s = nullptr;
|
|
3178
|
+
};
|
|
3179
|
+
#endif
|
|
3180
|
+
|
|
3181
|
+
#ifdef CPPHTTPLIB_ZSTD_SUPPORT
|
|
3182
|
+
class zstd_compressor : public compressor {
|
|
3183
|
+
public:
|
|
3184
|
+
zstd_compressor();
|
|
3185
|
+
~zstd_compressor();
|
|
3186
|
+
|
|
3187
|
+
bool compress(const char *data, size_t data_length, bool last,
|
|
3188
|
+
Callback callback) override;
|
|
3189
|
+
|
|
3190
|
+
private:
|
|
3191
|
+
ZSTD_CCtx *ctx_ = nullptr;
|
|
3192
|
+
};
|
|
3193
|
+
|
|
3194
|
+
class zstd_decompressor : public decompressor {
|
|
3195
|
+
public:
|
|
3196
|
+
zstd_decompressor();
|
|
3197
|
+
~zstd_decompressor();
|
|
3198
|
+
|
|
3199
|
+
bool is_valid() const override;
|
|
3200
|
+
|
|
3201
|
+
bool decompress(const char *data, size_t data_length,
|
|
3202
|
+
Callback callback) override;
|
|
3203
|
+
|
|
3204
|
+
private:
|
|
3205
|
+
ZSTD_DCtx *ctx_ = nullptr;
|
|
3206
|
+
};
|
|
3207
|
+
#endif
|
|
3208
|
+
|
|
3209
|
+
// NOTE: until the read size reaches `fixed_buffer_size`, use `fixed_buffer`
|
|
3210
|
+
// to store data. The call can set memory on stack for performance.
|
|
3211
|
+
class stream_line_reader {
|
|
3212
|
+
public:
|
|
3213
|
+
stream_line_reader(Stream &strm, char *fixed_buffer,
|
|
3214
|
+
size_t fixed_buffer_size);
|
|
3215
|
+
const char *ptr() const;
|
|
3216
|
+
size_t size() const;
|
|
3217
|
+
bool end_with_crlf() const;
|
|
3218
|
+
bool getline();
|
|
3219
|
+
|
|
3220
|
+
private:
|
|
3221
|
+
void append(char c);
|
|
3222
|
+
|
|
3223
|
+
Stream &strm_;
|
|
3224
|
+
char *fixed_buffer_;
|
|
3225
|
+
const size_t fixed_buffer_size_;
|
|
3226
|
+
size_t fixed_buffer_used_size_ = 0;
|
|
3227
|
+
std::string growable_buffer_;
|
|
3228
|
+
};
|
|
3229
|
+
|
|
3230
|
+
bool parse_trailers(stream_line_reader &line_reader, Headers &dest,
|
|
3231
|
+
const Headers &src_headers);
|
|
3232
|
+
|
|
3233
|
+
struct ChunkedDecoder {
|
|
3234
|
+
Stream &strm;
|
|
3235
|
+
size_t chunk_remaining = 0;
|
|
3236
|
+
bool finished = false;
|
|
3237
|
+
char line_buf[64];
|
|
3238
|
+
size_t last_chunk_total = 0;
|
|
3239
|
+
size_t last_chunk_offset = 0;
|
|
3240
|
+
|
|
3241
|
+
explicit ChunkedDecoder(Stream &s);
|
|
3242
|
+
|
|
3243
|
+
ssize_t read_payload(char *buf, size_t len, size_t &out_chunk_offset,
|
|
3244
|
+
size_t &out_chunk_total);
|
|
3245
|
+
|
|
3246
|
+
bool parse_trailers_into(Headers &dest, const Headers &src_headers);
|
|
3247
|
+
};
|
|
3248
|
+
|
|
3249
|
+
class mmap {
|
|
3250
|
+
public:
|
|
3251
|
+
mmap(const char *path);
|
|
3252
|
+
~mmap();
|
|
3253
|
+
|
|
3254
|
+
bool open(const char *path);
|
|
3255
|
+
void close();
|
|
3256
|
+
|
|
3257
|
+
bool is_open() const;
|
|
3258
|
+
size_t size() const;
|
|
3259
|
+
const char *data() const;
|
|
3260
|
+
|
|
3261
|
+
private:
|
|
3262
|
+
#if defined(_WIN32)
|
|
3263
|
+
HANDLE hFile_ = NULL;
|
|
3264
|
+
HANDLE hMapping_ = NULL;
|
|
3265
|
+
#else
|
|
3266
|
+
int fd_ = -1;
|
|
3267
|
+
#endif
|
|
3268
|
+
size_t size_ = 0;
|
|
3269
|
+
void *addr_ = nullptr;
|
|
3270
|
+
bool is_open_empty_file = false;
|
|
3271
|
+
};
|
|
3272
|
+
|
|
3273
|
+
// NOTE: https://www.rfc-editor.org/rfc/rfc9110#section-5
|
|
3274
|
+
namespace fields {
|
|
3275
|
+
|
|
3276
|
+
bool is_token_char(char c);
|
|
3277
|
+
bool is_token(const std::string &s);
|
|
3278
|
+
bool is_field_name(const std::string &s);
|
|
3279
|
+
bool is_vchar(char c);
|
|
3280
|
+
bool is_obs_text(char c);
|
|
3281
|
+
bool is_field_vchar(char c);
|
|
3282
|
+
bool is_field_content(const std::string &s);
|
|
3283
|
+
bool is_field_value(const std::string &s);
|
|
3284
|
+
|
|
3285
|
+
} // namespace fields
|
|
3286
|
+
} // namespace detail
|
|
3287
|
+
|
|
3288
|
+
/*
|
|
3289
|
+
* TLS Abstraction Layer Declarations
|
|
3290
|
+
*/
|
|
3291
|
+
|
|
3292
|
+
#ifdef CPPHTTPLIB_SSL_ENABLED
|
|
3293
|
+
// TLS abstraction layer - backend-specific type declarations
|
|
3294
|
+
#ifdef CPPHTTPLIB_MBEDTLS_SUPPORT
|
|
3295
|
+
namespace tls {
|
|
3296
|
+
namespace impl {
|
|
3297
|
+
|
|
3298
|
+
// Mbed TLS context wrapper (holds config, entropy, DRBG, CA chain, own
|
|
3299
|
+
// cert/key). This struct is accessible via tls::impl for use in SSL context
|
|
3300
|
+
// setup callbacks (cast ctx_t to tls::impl::MbedTlsContext*).
|
|
3301
|
+
struct MbedTlsContext {
|
|
3302
|
+
mbedtls_ssl_config conf;
|
|
3303
|
+
mbedtls_entropy_context entropy;
|
|
3304
|
+
mbedtls_ctr_drbg_context ctr_drbg;
|
|
3305
|
+
mbedtls_x509_crt ca_chain;
|
|
3306
|
+
mbedtls_x509_crt own_cert;
|
|
3307
|
+
mbedtls_pk_context own_key;
|
|
3308
|
+
bool is_server = false;
|
|
3309
|
+
bool verify_client = false;
|
|
3310
|
+
bool has_verify_callback = false;
|
|
3311
|
+
|
|
3312
|
+
MbedTlsContext();
|
|
3313
|
+
~MbedTlsContext();
|
|
3314
|
+
|
|
3315
|
+
MbedTlsContext(const MbedTlsContext &) = delete;
|
|
3316
|
+
MbedTlsContext &operator=(const MbedTlsContext &) = delete;
|
|
3317
|
+
};
|
|
3318
|
+
|
|
3319
|
+
} // namespace impl
|
|
3320
|
+
} // namespace tls
|
|
3321
|
+
#endif
|
|
3322
|
+
|
|
3323
|
+
#ifdef CPPHTTPLIB_WOLFSSL_SUPPORT
|
|
3324
|
+
namespace tls {
|
|
3325
|
+
namespace impl {
|
|
3326
|
+
|
|
3327
|
+
// wolfSSL context wrapper (holds WOLFSSL_CTX and related state).
|
|
3328
|
+
// This struct is accessible via tls::impl for use in SSL context
|
|
3329
|
+
// setup callbacks (cast ctx_t to tls::impl::WolfSSLContext*).
|
|
3330
|
+
struct WolfSSLContext {
|
|
3331
|
+
WOLFSSL_CTX *ctx = nullptr;
|
|
3332
|
+
bool is_server = false;
|
|
3333
|
+
bool verify_client = false;
|
|
3334
|
+
bool has_verify_callback = false;
|
|
3335
|
+
std::string ca_pem_data_; // accumulated PEM for get_ca_names/get_ca_certs
|
|
3336
|
+
|
|
3337
|
+
WolfSSLContext();
|
|
3338
|
+
~WolfSSLContext();
|
|
3339
|
+
|
|
3340
|
+
WolfSSLContext(const WolfSSLContext &) = delete;
|
|
3341
|
+
WolfSSLContext &operator=(const WolfSSLContext &) = delete;
|
|
3342
|
+
};
|
|
3343
|
+
|
|
3344
|
+
// CA store for wolfSSL: holds raw PEM bytes to allow reloading into any ctx
|
|
3345
|
+
struct WolfSSLCAStore {
|
|
3346
|
+
std::string pem_data;
|
|
3347
|
+
};
|
|
3348
|
+
|
|
3349
|
+
} // namespace impl
|
|
3350
|
+
} // namespace tls
|
|
3351
|
+
#endif
|
|
3352
|
+
|
|
3353
|
+
#endif // CPPHTTPLIB_SSL_ENABLED
|
|
3354
|
+
|
|
3355
|
+
namespace stream {
|
|
3356
|
+
|
|
3357
|
+
class Result {
|
|
3358
|
+
public:
|
|
3359
|
+
Result();
|
|
3360
|
+
explicit Result(ClientImpl::StreamHandle &&handle, size_t chunk_size = 8192);
|
|
3361
|
+
Result(Result &&other) noexcept;
|
|
3362
|
+
Result &operator=(Result &&other) noexcept;
|
|
3363
|
+
Result(const Result &) = delete;
|
|
3364
|
+
Result &operator=(const Result &) = delete;
|
|
3365
|
+
|
|
3366
|
+
// Response info
|
|
3367
|
+
bool is_valid() const;
|
|
3368
|
+
explicit operator bool() const;
|
|
3369
|
+
int status() const;
|
|
3370
|
+
const Headers &headers() const;
|
|
3371
|
+
std::string get_header_value(const std::string &key,
|
|
3372
|
+
const char *def = "") const;
|
|
3373
|
+
bool has_header(const std::string &key) const;
|
|
3374
|
+
Error error() const;
|
|
3375
|
+
Error read_error() const;
|
|
3376
|
+
bool has_read_error() const;
|
|
3377
|
+
|
|
3378
|
+
// Stream reading
|
|
3379
|
+
bool next();
|
|
3380
|
+
const char *data() const;
|
|
3381
|
+
size_t size() const;
|
|
3382
|
+
std::string read_all();
|
|
3383
|
+
|
|
3384
|
+
private:
|
|
3385
|
+
ClientImpl::StreamHandle handle_;
|
|
3386
|
+
std::string buffer_;
|
|
3387
|
+
size_t current_size_ = 0;
|
|
3388
|
+
size_t chunk_size_;
|
|
3389
|
+
bool finished_ = false;
|
|
3390
|
+
};
|
|
3391
|
+
|
|
3392
|
+
// GET
|
|
3393
|
+
template <typename ClientType>
|
|
3394
|
+
inline Result Get(ClientType &cli, const std::string &path,
|
|
3395
|
+
size_t chunk_size = 8192) {
|
|
3396
|
+
return Result{cli.open_stream("GET", path), chunk_size};
|
|
3397
|
+
}
|
|
3398
|
+
|
|
3399
|
+
template <typename ClientType>
|
|
3400
|
+
inline Result Get(ClientType &cli, const std::string &path,
|
|
3401
|
+
const Headers &headers, size_t chunk_size = 8192) {
|
|
3402
|
+
return Result{cli.open_stream("GET", path, {}, headers), chunk_size};
|
|
3403
|
+
}
|
|
3404
|
+
|
|
3405
|
+
template <typename ClientType>
|
|
3406
|
+
inline Result Get(ClientType &cli, const std::string &path,
|
|
3407
|
+
const Params ¶ms, size_t chunk_size = 8192) {
|
|
3408
|
+
return Result{cli.open_stream("GET", path, params), chunk_size};
|
|
3409
|
+
}
|
|
3410
|
+
|
|
3411
|
+
template <typename ClientType>
|
|
3412
|
+
inline Result Get(ClientType &cli, const std::string &path,
|
|
3413
|
+
const Params ¶ms, const Headers &headers,
|
|
3414
|
+
size_t chunk_size = 8192) {
|
|
3415
|
+
return Result{cli.open_stream("GET", path, params, headers), chunk_size};
|
|
3416
|
+
}
|
|
3417
|
+
|
|
3418
|
+
// POST
|
|
3419
|
+
template <typename ClientType>
|
|
3420
|
+
inline Result Post(ClientType &cli, const std::string &path,
|
|
3421
|
+
const std::string &body, const std::string &content_type,
|
|
3422
|
+
size_t chunk_size = 8192) {
|
|
3423
|
+
return Result{cli.open_stream("POST", path, {}, {}, body, content_type),
|
|
3424
|
+
chunk_size};
|
|
3425
|
+
}
|
|
3426
|
+
|
|
3427
|
+
template <typename ClientType>
|
|
3428
|
+
inline Result Post(ClientType &cli, const std::string &path,
|
|
3429
|
+
const Headers &headers, const std::string &body,
|
|
3430
|
+
const std::string &content_type, size_t chunk_size = 8192) {
|
|
3431
|
+
return Result{cli.open_stream("POST", path, {}, headers, body, content_type),
|
|
3432
|
+
chunk_size};
|
|
3433
|
+
}
|
|
3434
|
+
|
|
3435
|
+
template <typename ClientType>
|
|
3436
|
+
inline Result Post(ClientType &cli, const std::string &path,
|
|
3437
|
+
const Params ¶ms, const std::string &body,
|
|
3438
|
+
const std::string &content_type, size_t chunk_size = 8192) {
|
|
3439
|
+
return Result{cli.open_stream("POST", path, params, {}, body, content_type),
|
|
3440
|
+
chunk_size};
|
|
3441
|
+
}
|
|
3442
|
+
|
|
3443
|
+
template <typename ClientType>
|
|
3444
|
+
inline Result Post(ClientType &cli, const std::string &path,
|
|
3445
|
+
const Params ¶ms, const Headers &headers,
|
|
3446
|
+
const std::string &body, const std::string &content_type,
|
|
3447
|
+
size_t chunk_size = 8192) {
|
|
3448
|
+
return Result{
|
|
3449
|
+
cli.open_stream("POST", path, params, headers, body, content_type),
|
|
3450
|
+
chunk_size};
|
|
3451
|
+
}
|
|
3452
|
+
|
|
3453
|
+
// PUT
|
|
3454
|
+
template <typename ClientType>
|
|
3455
|
+
inline Result Put(ClientType &cli, const std::string &path,
|
|
3456
|
+
const std::string &body, const std::string &content_type,
|
|
3457
|
+
size_t chunk_size = 8192) {
|
|
3458
|
+
return Result{cli.open_stream("PUT", path, {}, {}, body, content_type),
|
|
3459
|
+
chunk_size};
|
|
3460
|
+
}
|
|
3461
|
+
|
|
3462
|
+
template <typename ClientType>
|
|
3463
|
+
inline Result Put(ClientType &cli, const std::string &path,
|
|
3464
|
+
const Headers &headers, const std::string &body,
|
|
3465
|
+
const std::string &content_type, size_t chunk_size = 8192) {
|
|
3466
|
+
return Result{cli.open_stream("PUT", path, {}, headers, body, content_type),
|
|
3467
|
+
chunk_size};
|
|
3468
|
+
}
|
|
3469
|
+
|
|
3470
|
+
template <typename ClientType>
|
|
3471
|
+
inline Result Put(ClientType &cli, const std::string &path,
|
|
3472
|
+
const Params ¶ms, const std::string &body,
|
|
3473
|
+
const std::string &content_type, size_t chunk_size = 8192) {
|
|
3474
|
+
return Result{cli.open_stream("PUT", path, params, {}, body, content_type),
|
|
3475
|
+
chunk_size};
|
|
3476
|
+
}
|
|
3477
|
+
|
|
3478
|
+
template <typename ClientType>
|
|
3479
|
+
inline Result Put(ClientType &cli, const std::string &path,
|
|
3480
|
+
const Params ¶ms, const Headers &headers,
|
|
3481
|
+
const std::string &body, const std::string &content_type,
|
|
3482
|
+
size_t chunk_size = 8192) {
|
|
3483
|
+
return Result{
|
|
3484
|
+
cli.open_stream("PUT", path, params, headers, body, content_type),
|
|
3485
|
+
chunk_size};
|
|
3486
|
+
}
|
|
3487
|
+
|
|
3488
|
+
// PATCH
|
|
3489
|
+
template <typename ClientType>
|
|
3490
|
+
inline Result Patch(ClientType &cli, const std::string &path,
|
|
3491
|
+
const std::string &body, const std::string &content_type,
|
|
3492
|
+
size_t chunk_size = 8192) {
|
|
3493
|
+
return Result{cli.open_stream("PATCH", path, {}, {}, body, content_type),
|
|
3494
|
+
chunk_size};
|
|
3495
|
+
}
|
|
3496
|
+
|
|
3497
|
+
template <typename ClientType>
|
|
3498
|
+
inline Result Patch(ClientType &cli, const std::string &path,
|
|
3499
|
+
const Headers &headers, const std::string &body,
|
|
3500
|
+
const std::string &content_type, size_t chunk_size = 8192) {
|
|
3501
|
+
return Result{cli.open_stream("PATCH", path, {}, headers, body, content_type),
|
|
3502
|
+
chunk_size};
|
|
3503
|
+
}
|
|
3504
|
+
|
|
3505
|
+
template <typename ClientType>
|
|
3506
|
+
inline Result Patch(ClientType &cli, const std::string &path,
|
|
3507
|
+
const Params ¶ms, const std::string &body,
|
|
3508
|
+
const std::string &content_type, size_t chunk_size = 8192) {
|
|
3509
|
+
return Result{cli.open_stream("PATCH", path, params, {}, body, content_type),
|
|
3510
|
+
chunk_size};
|
|
3511
|
+
}
|
|
3512
|
+
|
|
3513
|
+
template <typename ClientType>
|
|
3514
|
+
inline Result Patch(ClientType &cli, const std::string &path,
|
|
3515
|
+
const Params ¶ms, const Headers &headers,
|
|
3516
|
+
const std::string &body, const std::string &content_type,
|
|
3517
|
+
size_t chunk_size = 8192) {
|
|
3518
|
+
return Result{
|
|
3519
|
+
cli.open_stream("PATCH", path, params, headers, body, content_type),
|
|
3520
|
+
chunk_size};
|
|
3521
|
+
}
|
|
3522
|
+
|
|
3523
|
+
// DELETE
|
|
3524
|
+
template <typename ClientType>
|
|
3525
|
+
inline Result Delete(ClientType &cli, const std::string &path,
|
|
3526
|
+
size_t chunk_size = 8192) {
|
|
3527
|
+
return Result{cli.open_stream("DELETE", path), chunk_size};
|
|
3528
|
+
}
|
|
3529
|
+
|
|
3530
|
+
template <typename ClientType>
|
|
3531
|
+
inline Result Delete(ClientType &cli, const std::string &path,
|
|
3532
|
+
const Headers &headers, size_t chunk_size = 8192) {
|
|
3533
|
+
return Result{cli.open_stream("DELETE", path, {}, headers), chunk_size};
|
|
3534
|
+
}
|
|
3535
|
+
|
|
3536
|
+
template <typename ClientType>
|
|
3537
|
+
inline Result Delete(ClientType &cli, const std::string &path,
|
|
3538
|
+
const std::string &body, const std::string &content_type,
|
|
3539
|
+
size_t chunk_size = 8192) {
|
|
3540
|
+
return Result{cli.open_stream("DELETE", path, {}, {}, body, content_type),
|
|
3541
|
+
chunk_size};
|
|
3542
|
+
}
|
|
3543
|
+
|
|
3544
|
+
template <typename ClientType>
|
|
3545
|
+
inline Result Delete(ClientType &cli, const std::string &path,
|
|
3546
|
+
const Headers &headers, const std::string &body,
|
|
3547
|
+
const std::string &content_type,
|
|
3548
|
+
size_t chunk_size = 8192) {
|
|
3549
|
+
return Result{
|
|
3550
|
+
cli.open_stream("DELETE", path, {}, headers, body, content_type),
|
|
3551
|
+
chunk_size};
|
|
3552
|
+
}
|
|
3553
|
+
|
|
3554
|
+
template <typename ClientType>
|
|
3555
|
+
inline Result Delete(ClientType &cli, const std::string &path,
|
|
3556
|
+
const Params ¶ms, size_t chunk_size = 8192) {
|
|
3557
|
+
return Result{cli.open_stream("DELETE", path, params), chunk_size};
|
|
3558
|
+
}
|
|
3559
|
+
|
|
3560
|
+
template <typename ClientType>
|
|
3561
|
+
inline Result Delete(ClientType &cli, const std::string &path,
|
|
3562
|
+
const Params ¶ms, const Headers &headers,
|
|
3563
|
+
size_t chunk_size = 8192) {
|
|
3564
|
+
return Result{cli.open_stream("DELETE", path, params, headers), chunk_size};
|
|
3565
|
+
}
|
|
3566
|
+
|
|
3567
|
+
template <typename ClientType>
|
|
3568
|
+
inline Result Delete(ClientType &cli, const std::string &path,
|
|
3569
|
+
const Params ¶ms, const std::string &body,
|
|
3570
|
+
const std::string &content_type,
|
|
3571
|
+
size_t chunk_size = 8192) {
|
|
3572
|
+
return Result{cli.open_stream("DELETE", path, params, {}, body, content_type),
|
|
3573
|
+
chunk_size};
|
|
3574
|
+
}
|
|
3575
|
+
|
|
3576
|
+
template <typename ClientType>
|
|
3577
|
+
inline Result Delete(ClientType &cli, const std::string &path,
|
|
3578
|
+
const Params ¶ms, const Headers &headers,
|
|
3579
|
+
const std::string &body, const std::string &content_type,
|
|
3580
|
+
size_t chunk_size = 8192) {
|
|
3581
|
+
return Result{
|
|
3582
|
+
cli.open_stream("DELETE", path, params, headers, body, content_type),
|
|
3583
|
+
chunk_size};
|
|
3584
|
+
}
|
|
3585
|
+
|
|
3586
|
+
// HEAD
|
|
3587
|
+
template <typename ClientType>
|
|
3588
|
+
inline Result Head(ClientType &cli, const std::string &path,
|
|
3589
|
+
size_t chunk_size = 8192) {
|
|
3590
|
+
return Result{cli.open_stream("HEAD", path), chunk_size};
|
|
3591
|
+
}
|
|
3592
|
+
|
|
3593
|
+
template <typename ClientType>
|
|
3594
|
+
inline Result Head(ClientType &cli, const std::string &path,
|
|
3595
|
+
const Headers &headers, size_t chunk_size = 8192) {
|
|
3596
|
+
return Result{cli.open_stream("HEAD", path, {}, headers), chunk_size};
|
|
3597
|
+
}
|
|
3598
|
+
|
|
3599
|
+
template <typename ClientType>
|
|
3600
|
+
inline Result Head(ClientType &cli, const std::string &path,
|
|
3601
|
+
const Params ¶ms, size_t chunk_size = 8192) {
|
|
3602
|
+
return Result{cli.open_stream("HEAD", path, params), chunk_size};
|
|
3603
|
+
}
|
|
3604
|
+
|
|
3605
|
+
template <typename ClientType>
|
|
3606
|
+
inline Result Head(ClientType &cli, const std::string &path,
|
|
3607
|
+
const Params ¶ms, const Headers &headers,
|
|
3608
|
+
size_t chunk_size = 8192) {
|
|
3609
|
+
return Result{cli.open_stream("HEAD", path, params, headers), chunk_size};
|
|
3610
|
+
}
|
|
3611
|
+
|
|
3612
|
+
// OPTIONS
|
|
3613
|
+
template <typename ClientType>
|
|
3614
|
+
inline Result Options(ClientType &cli, const std::string &path,
|
|
3615
|
+
size_t chunk_size = 8192) {
|
|
3616
|
+
return Result{cli.open_stream("OPTIONS", path), chunk_size};
|
|
3617
|
+
}
|
|
3618
|
+
|
|
3619
|
+
template <typename ClientType>
|
|
3620
|
+
inline Result Options(ClientType &cli, const std::string &path,
|
|
3621
|
+
const Headers &headers, size_t chunk_size = 8192) {
|
|
3622
|
+
return Result{cli.open_stream("OPTIONS", path, {}, headers), chunk_size};
|
|
3623
|
+
}
|
|
3624
|
+
|
|
3625
|
+
template <typename ClientType>
|
|
3626
|
+
inline Result Options(ClientType &cli, const std::string &path,
|
|
3627
|
+
const Params ¶ms, size_t chunk_size = 8192) {
|
|
3628
|
+
return Result{cli.open_stream("OPTIONS", path, params), chunk_size};
|
|
3629
|
+
}
|
|
3630
|
+
|
|
3631
|
+
template <typename ClientType>
|
|
3632
|
+
inline Result Options(ClientType &cli, const std::string &path,
|
|
3633
|
+
const Params ¶ms, const Headers &headers,
|
|
3634
|
+
size_t chunk_size = 8192) {
|
|
3635
|
+
return Result{cli.open_stream("OPTIONS", path, params, headers), chunk_size};
|
|
3636
|
+
}
|
|
3637
|
+
|
|
3638
|
+
} // namespace stream
|
|
3639
|
+
|
|
3640
|
+
namespace sse {
|
|
3641
|
+
|
|
3642
|
+
struct SSEMessage {
|
|
3643
|
+
std::string event; // Event type (default: "message")
|
|
3644
|
+
std::string data; // Event payload
|
|
3645
|
+
std::string id; // Event ID for Last-Event-ID header
|
|
3646
|
+
|
|
3647
|
+
SSEMessage();
|
|
3648
|
+
void clear();
|
|
3649
|
+
};
|
|
3650
|
+
|
|
3651
|
+
class SSEClient {
|
|
3652
|
+
public:
|
|
3653
|
+
using MessageHandler = std::function<void(const SSEMessage &)>;
|
|
3654
|
+
using ErrorHandler = std::function<void(Error)>;
|
|
3655
|
+
using OpenHandler = std::function<void()>;
|
|
3656
|
+
|
|
3657
|
+
SSEClient(Client &client, const std::string &path);
|
|
3658
|
+
SSEClient(Client &client, const std::string &path, const Headers &headers);
|
|
3659
|
+
~SSEClient();
|
|
3660
|
+
|
|
3661
|
+
SSEClient(const SSEClient &) = delete;
|
|
3662
|
+
SSEClient &operator=(const SSEClient &) = delete;
|
|
3663
|
+
|
|
3664
|
+
// Event handlers
|
|
3665
|
+
SSEClient &on_message(MessageHandler handler);
|
|
3666
|
+
SSEClient &on_event(const std::string &type, MessageHandler handler);
|
|
3667
|
+
SSEClient &on_open(OpenHandler handler);
|
|
3668
|
+
SSEClient &on_error(ErrorHandler handler);
|
|
3669
|
+
SSEClient &set_reconnect_interval(int ms);
|
|
3670
|
+
SSEClient &set_max_reconnect_attempts(int n);
|
|
3671
|
+
|
|
3672
|
+
// Update headers (thread-safe)
|
|
3673
|
+
SSEClient &set_headers(const Headers &headers);
|
|
3674
|
+
|
|
3675
|
+
// State accessors
|
|
3676
|
+
bool is_connected() const;
|
|
3677
|
+
const std::string &last_event_id() const;
|
|
3678
|
+
|
|
3679
|
+
// Blocking start - runs event loop with auto-reconnect
|
|
3680
|
+
void start();
|
|
3681
|
+
|
|
3682
|
+
// Non-blocking start - runs in background thread
|
|
3683
|
+
void start_async();
|
|
3684
|
+
|
|
3685
|
+
// Stop the client (thread-safe)
|
|
3686
|
+
void stop();
|
|
3687
|
+
|
|
3688
|
+
private:
|
|
3689
|
+
bool parse_sse_line(const std::string &line, SSEMessage &msg, int &retry_ms);
|
|
3690
|
+
void run_event_loop();
|
|
3691
|
+
void dispatch_event(const SSEMessage &msg);
|
|
3692
|
+
bool should_reconnect(int count) const;
|
|
3693
|
+
void wait_for_reconnect();
|
|
3694
|
+
|
|
3695
|
+
// Client and path
|
|
3696
|
+
Client &client_;
|
|
3697
|
+
std::string path_;
|
|
3698
|
+
Headers headers_;
|
|
3699
|
+
mutable std::mutex headers_mutex_;
|
|
3700
|
+
|
|
3701
|
+
// Callbacks
|
|
3702
|
+
MessageHandler on_message_;
|
|
3703
|
+
std::map<std::string, MessageHandler> event_handlers_;
|
|
3704
|
+
OpenHandler on_open_;
|
|
3705
|
+
ErrorHandler on_error_;
|
|
3706
|
+
|
|
3707
|
+
// Configuration
|
|
3708
|
+
int reconnect_interval_ms_ = 3000;
|
|
3709
|
+
int max_reconnect_attempts_ = 0; // 0 = unlimited
|
|
3710
|
+
|
|
3711
|
+
// State
|
|
3712
|
+
std::atomic<bool> running_{false};
|
|
3713
|
+
std::atomic<bool> connected_{false};
|
|
3714
|
+
std::string last_event_id_;
|
|
3715
|
+
|
|
3716
|
+
// Async support
|
|
3717
|
+
std::thread async_thread_;
|
|
3718
|
+
};
|
|
3719
|
+
|
|
3720
|
+
} // namespace sse
|
|
3721
|
+
|
|
3722
|
+
namespace ws {
|
|
3723
|
+
|
|
3724
|
+
enum class Opcode : uint8_t {
|
|
3725
|
+
Continuation = 0x0,
|
|
3726
|
+
Text = 0x1,
|
|
3727
|
+
Binary = 0x2,
|
|
3728
|
+
Close = 0x8,
|
|
3729
|
+
Ping = 0x9,
|
|
3730
|
+
Pong = 0xA,
|
|
3731
|
+
};
|
|
3732
|
+
|
|
3733
|
+
enum class CloseStatus : uint16_t {
|
|
3734
|
+
Normal = 1000,
|
|
3735
|
+
GoingAway = 1001,
|
|
3736
|
+
ProtocolError = 1002,
|
|
3737
|
+
UnsupportedData = 1003,
|
|
3738
|
+
NoStatus = 1005,
|
|
3739
|
+
Abnormal = 1006,
|
|
3740
|
+
InvalidPayload = 1007,
|
|
3741
|
+
PolicyViolation = 1008,
|
|
3742
|
+
MessageTooBig = 1009,
|
|
3743
|
+
MandatoryExtension = 1010,
|
|
3744
|
+
InternalError = 1011,
|
|
3745
|
+
};
|
|
3746
|
+
|
|
3747
|
+
enum ReadResult : int { Fail = 0, Text = 1, Binary = 2 };
|
|
3748
|
+
|
|
3749
|
+
class WebSocket {
|
|
3750
|
+
public:
|
|
3751
|
+
WebSocket(const WebSocket &) = delete;
|
|
3752
|
+
WebSocket &operator=(const WebSocket &) = delete;
|
|
3753
|
+
~WebSocket();
|
|
3754
|
+
|
|
3755
|
+
ReadResult read(std::string &msg);
|
|
3756
|
+
bool send(const std::string &data);
|
|
3757
|
+
bool send(const char *data, size_t len);
|
|
3758
|
+
void close(CloseStatus status = CloseStatus::Normal,
|
|
3759
|
+
const std::string &reason = "");
|
|
3760
|
+
const Request &request() const;
|
|
3761
|
+
bool is_open() const;
|
|
3762
|
+
|
|
3763
|
+
private:
|
|
3764
|
+
friend class httplib::Server;
|
|
3765
|
+
friend class WebSocketClient;
|
|
3766
|
+
|
|
3767
|
+
WebSocket(
|
|
3768
|
+
Stream &strm, const Request &req, bool is_server,
|
|
3769
|
+
time_t ping_interval_sec = CPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECOND)
|
|
3770
|
+
: strm_(strm), req_(req), is_server_(is_server),
|
|
3771
|
+
ping_interval_sec_(ping_interval_sec) {
|
|
3772
|
+
start_heartbeat();
|
|
3773
|
+
}
|
|
3774
|
+
|
|
3775
|
+
WebSocket(
|
|
3776
|
+
std::unique_ptr<Stream> &&owned_strm, const Request &req, bool is_server,
|
|
3777
|
+
time_t ping_interval_sec = CPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECOND)
|
|
3778
|
+
: strm_(*owned_strm), owned_strm_(std::move(owned_strm)), req_(req),
|
|
3779
|
+
is_server_(is_server), ping_interval_sec_(ping_interval_sec) {
|
|
3780
|
+
start_heartbeat();
|
|
3781
|
+
}
|
|
3782
|
+
|
|
3783
|
+
void start_heartbeat();
|
|
3784
|
+
bool send_frame(Opcode op, const char *data, size_t len, bool fin = true);
|
|
3785
|
+
|
|
3786
|
+
Stream &strm_;
|
|
3787
|
+
std::unique_ptr<Stream> owned_strm_;
|
|
3788
|
+
Request req_;
|
|
3789
|
+
bool is_server_;
|
|
3790
|
+
time_t ping_interval_sec_;
|
|
3791
|
+
std::atomic<bool> closed_{false};
|
|
3792
|
+
std::mutex write_mutex_;
|
|
3793
|
+
std::thread ping_thread_;
|
|
3794
|
+
std::mutex ping_mutex_;
|
|
3795
|
+
std::condition_variable ping_cv_;
|
|
3796
|
+
};
|
|
3797
|
+
|
|
3798
|
+
class WebSocketClient {
|
|
3799
|
+
public:
|
|
3800
|
+
explicit WebSocketClient(const std::string &scheme_host_port_path,
|
|
3801
|
+
const Headers &headers = {});
|
|
3802
|
+
|
|
3803
|
+
~WebSocketClient();
|
|
3804
|
+
WebSocketClient(const WebSocketClient &) = delete;
|
|
3805
|
+
WebSocketClient &operator=(const WebSocketClient &) = delete;
|
|
3806
|
+
|
|
3807
|
+
bool is_valid() const;
|
|
3808
|
+
|
|
3809
|
+
bool connect();
|
|
3810
|
+
ReadResult read(std::string &msg);
|
|
3811
|
+
bool send(const std::string &data);
|
|
3812
|
+
bool send(const char *data, size_t len);
|
|
3813
|
+
void close(CloseStatus status = CloseStatus::Normal,
|
|
3814
|
+
const std::string &reason = "");
|
|
3815
|
+
bool is_open() const;
|
|
3816
|
+
const std::string &subprotocol() const;
|
|
3817
|
+
void set_read_timeout(time_t sec, time_t usec = 0);
|
|
3818
|
+
void set_write_timeout(time_t sec, time_t usec = 0);
|
|
3819
|
+
void set_websocket_ping_interval(time_t sec);
|
|
3820
|
+
void set_tcp_nodelay(bool on);
|
|
3821
|
+
void set_address_family(int family);
|
|
3822
|
+
void set_ipv6_v6only(bool on);
|
|
3823
|
+
void set_socket_options(SocketOptions socket_options);
|
|
3824
|
+
void set_connection_timeout(time_t sec, time_t usec = 0);
|
|
3825
|
+
void set_interface(const std::string &intf);
|
|
3826
|
+
|
|
3827
|
+
#ifdef CPPHTTPLIB_SSL_ENABLED
|
|
3828
|
+
void set_ca_cert_path(const std::string &path);
|
|
3829
|
+
void set_ca_cert_store(tls::ca_store_t store);
|
|
3830
|
+
void enable_server_certificate_verification(bool enabled);
|
|
3831
|
+
#endif
|
|
3832
|
+
|
|
3833
|
+
private:
|
|
3834
|
+
void shutdown_and_close();
|
|
3835
|
+
bool create_stream(std::unique_ptr<Stream> &strm);
|
|
3836
|
+
|
|
3837
|
+
std::string host_;
|
|
3838
|
+
int port_;
|
|
3839
|
+
std::string path_;
|
|
3840
|
+
Headers headers_;
|
|
3841
|
+
std::string subprotocol_;
|
|
3842
|
+
bool is_valid_ = false;
|
|
3843
|
+
socket_t sock_ = INVALID_SOCKET;
|
|
3844
|
+
std::unique_ptr<WebSocket> ws_;
|
|
3845
|
+
time_t read_timeout_sec_ = CPPHTTPLIB_WEBSOCKET_READ_TIMEOUT_SECOND;
|
|
3846
|
+
time_t read_timeout_usec_ = 0;
|
|
3847
|
+
time_t write_timeout_sec_ = CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND;
|
|
3848
|
+
time_t write_timeout_usec_ = CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND;
|
|
3849
|
+
time_t websocket_ping_interval_sec_ =
|
|
3850
|
+
CPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECOND;
|
|
3851
|
+
int address_family_ = AF_UNSPEC;
|
|
3852
|
+
bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
|
|
3853
|
+
bool ipv6_v6only_ = CPPHTTPLIB_IPV6_V6ONLY;
|
|
3854
|
+
SocketOptions socket_options_ = nullptr;
|
|
3855
|
+
time_t connection_timeout_sec_ = CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND;
|
|
3856
|
+
time_t connection_timeout_usec_ = CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND;
|
|
3857
|
+
std::string interface_;
|
|
3858
|
+
|
|
3859
|
+
#ifdef CPPHTTPLIB_SSL_ENABLED
|
|
3860
|
+
bool is_ssl_ = false;
|
|
3861
|
+
tls::ctx_t tls_ctx_ = nullptr;
|
|
3862
|
+
tls::session_t tls_session_ = nullptr;
|
|
3863
|
+
std::string ca_cert_file_path_;
|
|
3864
|
+
tls::ca_store_t ca_cert_store_ = nullptr;
|
|
3865
|
+
bool server_certificate_verification_ = true;
|
|
3866
|
+
#endif
|
|
3867
|
+
};
|
|
3868
|
+
|
|
3869
|
+
namespace impl {
|
|
3870
|
+
|
|
3871
|
+
bool is_valid_utf8(const std::string &s);
|
|
3872
|
+
|
|
3873
|
+
bool read_websocket_frame(Stream &strm, Opcode &opcode, std::string &payload,
|
|
3874
|
+
bool &fin, bool expect_masked, size_t max_len);
|
|
3875
|
+
|
|
3876
|
+
} // namespace impl
|
|
3877
|
+
|
|
3878
|
+
} // namespace ws
|
|
3879
|
+
|
|
3880
|
+
|
|
3881
|
+
} // namespace httplib
|
|
3882
|
+
|
|
3883
|
+
#endif // CPPHTTPLIB_HTTPLIB_H
|