@fugood/llama.node 0.3.6 → 0.3.8
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/README.md +17 -2
- package/bin/darwin/arm64/llama-node.node +0 -0
- package/bin/darwin/x64/llama-node.node +0 -0
- package/bin/linux/arm64/llama-node.node +0 -0
- package/bin/linux/x64/llama-node.node +0 -0
- package/bin/linux-cuda/arm64/llama-node.node +0 -0
- package/bin/linux-cuda/x64/llama-node.node +0 -0
- package/bin/linux-vulkan/arm64/llama-node.node +0 -0
- package/bin/linux-vulkan/x64/llama-node.node +0 -0
- package/bin/win32/arm64/llama-node.node +0 -0
- package/bin/win32/arm64/node.lib +0 -0
- package/bin/win32/x64/llama-node.node +0 -0
- package/bin/win32/x64/node.lib +0 -0
- package/bin/win32-vulkan/arm64/llama-node.node +0 -0
- package/bin/win32-vulkan/arm64/node.lib +0 -0
- package/bin/win32-vulkan/x64/llama-node.node +0 -0
- package/bin/win32-vulkan/x64/node.lib +0 -0
- package/lib/binding.ts +3 -1
- package/lib/index.js +16 -1
- package/lib/index.ts +16 -0
- package/package.json +1 -1
- package/src/EmbeddingWorker.cpp +4 -3
- package/src/LlamaCompletionWorker.cpp +4 -2
- package/src/LlamaContext.cpp +61 -6
- package/src/LlamaContext.h +1 -0
- package/src/common.hpp +6 -11
- package/src/llama.cpp/.github/workflows/build.yml +19 -17
- package/src/llama.cpp/.github/workflows/docker.yml +77 -30
- package/src/llama.cpp/.github/workflows/editorconfig.yml +3 -1
- package/src/llama.cpp/.github/workflows/server.yml +22 -3
- package/src/llama.cpp/CMakeLists.txt +49 -24
- package/src/llama.cpp/common/arg.cpp +82 -26
- package/src/llama.cpp/common/arg.h +3 -0
- package/src/llama.cpp/common/common.cpp +192 -72
- package/src/llama.cpp/common/common.h +51 -18
- package/src/llama.cpp/common/ngram-cache.cpp +12 -12
- package/src/llama.cpp/common/ngram-cache.h +2 -2
- package/src/llama.cpp/common/sampling.cpp +11 -6
- package/src/llama.cpp/common/speculative.cpp +18 -15
- package/src/llama.cpp/docs/build.md +2 -0
- package/src/llama.cpp/examples/batched/batched.cpp +9 -7
- package/src/llama.cpp/examples/batched-bench/batched-bench.cpp +3 -3
- package/src/llama.cpp/examples/convert-llama2c-to-ggml/convert-llama2c-to-ggml.cpp +10 -8
- package/src/llama.cpp/examples/cvector-generator/cvector-generator.cpp +11 -8
- package/src/llama.cpp/examples/cvector-generator/mean.hpp +1 -1
- package/src/llama.cpp/examples/cvector-generator/pca.hpp +1 -1
- package/src/llama.cpp/examples/embedding/embedding.cpp +8 -7
- package/src/llama.cpp/examples/eval-callback/eval-callback.cpp +7 -6
- package/src/llama.cpp/examples/export-lora/export-lora.cpp +8 -7
- package/src/llama.cpp/examples/gguf/gguf.cpp +10 -6
- package/src/llama.cpp/examples/gguf-hash/gguf-hash.cpp +1 -0
- package/src/llama.cpp/examples/gguf-split/gguf-split.cpp +8 -7
- package/src/llama.cpp/examples/gritlm/gritlm.cpp +13 -10
- package/src/llama.cpp/examples/imatrix/imatrix.cpp +13 -12
- package/src/llama.cpp/examples/infill/infill.cpp +23 -24
- package/src/llama.cpp/examples/llama-bench/llama-bench.cpp +44 -13
- package/src/llama.cpp/examples/llama.android/llama/src/main/cpp/llama-android.cpp +11 -6
- package/src/llama.cpp/examples/llava/clip.cpp +4 -2
- package/src/llama.cpp/examples/llava/llava-cli.cpp +9 -6
- package/src/llama.cpp/examples/llava/llava.cpp +2 -2
- package/src/llama.cpp/examples/llava/minicpmv-cli.cpp +8 -4
- package/src/llama.cpp/examples/llava/qwen2vl-cli.cpp +11 -8
- package/src/llama.cpp/examples/lookahead/lookahead.cpp +6 -7
- package/src/llama.cpp/examples/lookup/lookup-create.cpp +4 -9
- package/src/llama.cpp/examples/lookup/lookup-stats.cpp +3 -7
- package/src/llama.cpp/examples/lookup/lookup.cpp +5 -6
- package/src/llama.cpp/examples/main/main.cpp +51 -29
- package/src/llama.cpp/examples/parallel/parallel.cpp +5 -6
- package/src/llama.cpp/examples/passkey/passkey.cpp +7 -5
- package/src/llama.cpp/examples/perplexity/perplexity.cpp +37 -23
- package/src/llama.cpp/examples/quantize-stats/quantize-stats.cpp +12 -14
- package/src/llama.cpp/examples/retrieval/retrieval.cpp +8 -8
- package/src/llama.cpp/examples/rpc/rpc-server.cpp +12 -0
- package/src/llama.cpp/examples/run/CMakeLists.txt +1 -1
- package/src/llama.cpp/examples/run/linenoise.cpp/linenoise.cpp +1351 -0
- package/src/llama.cpp/examples/run/linenoise.cpp/linenoise.h +114 -0
- package/src/llama.cpp/examples/run/run.cpp +175 -61
- package/src/llama.cpp/examples/save-load-state/save-load-state.cpp +4 -25
- package/src/llama.cpp/examples/server/CMakeLists.txt +1 -0
- package/src/llama.cpp/examples/server/httplib.h +1295 -409
- package/src/llama.cpp/examples/server/server.cpp +387 -181
- package/src/llama.cpp/examples/server/tests/requirements.txt +1 -0
- package/src/llama.cpp/examples/server/utils.hpp +170 -58
- package/src/llama.cpp/examples/simple/simple.cpp +9 -8
- package/src/llama.cpp/examples/simple-chat/simple-chat.cpp +16 -12
- package/src/llama.cpp/examples/speculative/speculative.cpp +22 -23
- package/src/llama.cpp/examples/speculative-simple/speculative-simple.cpp +8 -12
- package/src/llama.cpp/examples/tokenize/tokenize.cpp +17 -5
- package/src/llama.cpp/examples/tts/tts.cpp +64 -23
- package/src/llama.cpp/ggml/CMakeLists.txt +5 -21
- package/src/llama.cpp/ggml/include/ggml-backend.h +2 -0
- package/src/llama.cpp/ggml/include/ggml-cpp.h +1 -0
- package/src/llama.cpp/ggml/include/ggml.h +36 -145
- package/src/llama.cpp/ggml/include/gguf.h +202 -0
- package/src/llama.cpp/ggml/src/CMakeLists.txt +6 -3
- package/src/llama.cpp/ggml/src/ggml-alloc.c +5 -0
- package/src/llama.cpp/ggml/src/ggml-backend-impl.h +0 -1
- package/src/llama.cpp/ggml/src/ggml-backend-reg.cpp +79 -49
- package/src/llama.cpp/ggml/src/ggml-backend.cpp +5 -2
- package/src/llama.cpp/ggml/src/ggml-cpu/CMakeLists.txt +33 -23
- package/src/llama.cpp/ggml/src/ggml-cpu/ggml-cpu-aarch64.cpp +57 -72
- package/src/llama.cpp/ggml/src/ggml-cpu/ggml-cpu-quants.c +87 -2
- package/src/llama.cpp/ggml/src/ggml-cpu/ggml-cpu.c +335 -66
- package/src/llama.cpp/ggml/src/ggml-cpu/ggml-cpu.cpp +10 -2
- package/src/llama.cpp/ggml/src/ggml-cpu/llamafile/sgemm.cpp +1090 -378
- package/src/llama.cpp/ggml/src/ggml-cpu/llamafile/sgemm.h +2 -2
- package/src/llama.cpp/ggml/src/ggml-cuda/vendors/cuda.h +1 -0
- package/src/llama.cpp/ggml/src/ggml-cuda/vendors/hip.h +3 -0
- package/src/llama.cpp/ggml/src/ggml-cuda/vendors/musa.h +3 -0
- package/src/llama.cpp/ggml/src/ggml-hip/CMakeLists.txt +3 -1
- package/src/llama.cpp/ggml/src/ggml-impl.h +11 -16
- package/src/llama.cpp/ggml/src/ggml-metal/CMakeLists.txt +16 -0
- package/src/llama.cpp/ggml/src/ggml-opencl/ggml-opencl.cpp +6 -6
- package/src/llama.cpp/ggml/src/ggml-rpc/ggml-rpc.cpp +154 -35
- package/src/llama.cpp/ggml/src/ggml-sycl/backend.hpp +1 -0
- package/src/llama.cpp/ggml/src/ggml-sycl/common.cpp +9 -3
- package/src/llama.cpp/ggml/src/ggml-sycl/common.hpp +18 -0
- package/src/llama.cpp/ggml/src/ggml-sycl/concat.cpp +3 -2
- package/src/llama.cpp/ggml/src/ggml-sycl/concat.hpp +1 -2
- package/src/llama.cpp/ggml/src/ggml-sycl/conv.cpp +3 -2
- package/src/llama.cpp/ggml/src/ggml-sycl/conv.hpp +1 -2
- package/src/llama.cpp/ggml/src/ggml-sycl/dpct/helper.hpp +40 -95
- package/src/llama.cpp/ggml/src/ggml-sycl/element_wise.cpp +48 -48
- package/src/llama.cpp/ggml/src/ggml-sycl/element_wise.hpp +24 -24
- package/src/llama.cpp/ggml/src/ggml-sycl/ggml-sycl.cpp +238 -164
- package/src/llama.cpp/ggml/src/ggml-sycl/gla.cpp +105 -0
- package/src/llama.cpp/ggml/src/ggml-sycl/gla.hpp +8 -0
- package/src/llama.cpp/ggml/src/ggml-sycl/outprod.cpp +3 -3
- package/src/llama.cpp/ggml/src/ggml-sycl/outprod.hpp +1 -2
- package/src/llama.cpp/ggml/src/ggml-sycl/tsembd.cpp +3 -2
- package/src/llama.cpp/ggml/src/ggml-sycl/tsembd.hpp +1 -2
- package/src/llama.cpp/ggml/src/ggml-sycl/wkv6.cpp +7 -5
- package/src/llama.cpp/ggml/src/ggml-sycl/wkv6.hpp +1 -2
- package/src/llama.cpp/ggml/src/ggml-vulkan/CMakeLists.txt +74 -4
- package/src/llama.cpp/ggml/src/ggml-vulkan/ggml-vulkan.cpp +314 -116
- package/src/llama.cpp/ggml/src/ggml-vulkan/vulkan-shaders/CMakeLists.txt +4 -2
- package/src/llama.cpp/ggml/src/ggml-vulkan/vulkan-shaders/vulkan-shaders-gen.cpp +9 -3
- package/src/llama.cpp/ggml/src/ggml.c +117 -1327
- package/src/llama.cpp/ggml/src/gguf.cpp +1329 -0
- package/src/llama.cpp/include/llama-cpp.h +6 -1
- package/src/llama.cpp/include/llama.h +138 -75
- package/src/llama.cpp/src/CMakeLists.txt +13 -1
- package/src/llama.cpp/src/llama-adapter.cpp +347 -0
- package/src/llama.cpp/src/llama-adapter.h +74 -0
- package/src/llama.cpp/src/llama-arch.cpp +1487 -0
- package/src/llama.cpp/src/llama-arch.h +400 -0
- package/src/llama.cpp/src/llama-batch.cpp +368 -0
- package/src/llama.cpp/src/llama-batch.h +88 -0
- package/src/llama.cpp/src/llama-chat.cpp +578 -0
- package/src/llama.cpp/src/llama-chat.h +52 -0
- package/src/llama.cpp/src/llama-context.cpp +1775 -0
- package/src/llama.cpp/src/llama-context.h +128 -0
- package/src/llama.cpp/src/llama-cparams.cpp +1 -0
- package/src/llama.cpp/src/llama-cparams.h +37 -0
- package/src/llama.cpp/src/llama-grammar.cpp +5 -4
- package/src/llama.cpp/src/llama-grammar.h +3 -1
- package/src/llama.cpp/src/llama-hparams.cpp +71 -0
- package/src/llama.cpp/src/llama-hparams.h +139 -0
- package/src/llama.cpp/src/llama-impl.cpp +167 -0
- package/src/llama.cpp/src/llama-impl.h +16 -136
- package/src/llama.cpp/src/llama-kv-cache.cpp +718 -0
- package/src/llama.cpp/src/llama-kv-cache.h +218 -0
- package/src/llama.cpp/src/llama-mmap.cpp +589 -0
- package/src/llama.cpp/src/llama-mmap.h +67 -0
- package/src/llama.cpp/src/llama-model-loader.cpp +1124 -0
- package/src/llama.cpp/src/llama-model-loader.h +167 -0
- package/src/llama.cpp/src/llama-model.cpp +3953 -0
- package/src/llama.cpp/src/llama-model.h +370 -0
- package/src/llama.cpp/src/llama-quant.cpp +934 -0
- package/src/llama.cpp/src/llama-quant.h +1 -0
- package/src/llama.cpp/src/llama-sampling.cpp +147 -32
- package/src/llama.cpp/src/llama-sampling.h +3 -19
- package/src/llama.cpp/src/llama-vocab.cpp +1832 -575
- package/src/llama.cpp/src/llama-vocab.h +97 -142
- package/src/llama.cpp/src/llama.cpp +7160 -20314
- package/src/llama.cpp/src/unicode.cpp +8 -3
- package/src/llama.cpp/tests/CMakeLists.txt +2 -0
- package/src/llama.cpp/tests/test-autorelease.cpp +3 -3
- package/src/llama.cpp/tests/test-backend-ops.cpp +370 -59
- package/src/llama.cpp/tests/test-chat-template.cpp +162 -125
- package/src/llama.cpp/tests/test-gguf.cpp +222 -187
- package/src/llama.cpp/tests/test-model-load-cancel.cpp +1 -1
- package/src/llama.cpp/tests/test-sampling.cpp +0 -1
- package/src/llama.cpp/tests/test-tokenizer-0.cpp +4 -4
- package/src/llama.cpp/tests/test-tokenizer-1-bpe.cpp +9 -7
- package/src/llama.cpp/tests/test-tokenizer-1-spm.cpp +8 -6
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
#ifndef CPPHTTPLIB_HTTPLIB_H
|
|
9
9
|
#define CPPHTTPLIB_HTTPLIB_H
|
|
10
10
|
|
|
11
|
-
#define CPPHTTPLIB_VERSION "0.
|
|
11
|
+
#define CPPHTTPLIB_VERSION "0.18.5"
|
|
12
12
|
|
|
13
13
|
/*
|
|
14
14
|
* Configuration
|
|
@@ -18,8 +18,12 @@
|
|
|
18
18
|
#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND 5
|
|
19
19
|
#endif
|
|
20
20
|
|
|
21
|
+
#ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND
|
|
22
|
+
#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND 10000
|
|
23
|
+
#endif
|
|
24
|
+
|
|
21
25
|
#ifndef CPPHTTPLIB_KEEPALIVE_MAX_COUNT
|
|
22
|
-
#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT
|
|
26
|
+
#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 100
|
|
23
27
|
#endif
|
|
24
28
|
|
|
25
29
|
#ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND
|
|
@@ -30,20 +34,36 @@
|
|
|
30
34
|
#define CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND 0
|
|
31
35
|
#endif
|
|
32
36
|
|
|
33
|
-
#ifndef
|
|
34
|
-
#define
|
|
37
|
+
#ifndef CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND
|
|
38
|
+
#define CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND 5
|
|
39
|
+
#endif
|
|
40
|
+
|
|
41
|
+
#ifndef CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND
|
|
42
|
+
#define CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND 0
|
|
43
|
+
#endif
|
|
44
|
+
|
|
45
|
+
#ifndef CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND
|
|
46
|
+
#define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND 5
|
|
47
|
+
#endif
|
|
48
|
+
|
|
49
|
+
#ifndef CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND
|
|
50
|
+
#define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND 0
|
|
51
|
+
#endif
|
|
52
|
+
|
|
53
|
+
#ifndef CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND
|
|
54
|
+
#define CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND 300
|
|
35
55
|
#endif
|
|
36
56
|
|
|
37
|
-
#ifndef
|
|
38
|
-
#define
|
|
57
|
+
#ifndef CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND
|
|
58
|
+
#define CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND 0
|
|
39
59
|
#endif
|
|
40
60
|
|
|
41
|
-
#ifndef
|
|
42
|
-
#define
|
|
61
|
+
#ifndef CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND
|
|
62
|
+
#define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND 5
|
|
43
63
|
#endif
|
|
44
64
|
|
|
45
|
-
#ifndef
|
|
46
|
-
#define
|
|
65
|
+
#ifndef CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND
|
|
66
|
+
#define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND 0
|
|
47
67
|
#endif
|
|
48
68
|
|
|
49
69
|
#ifndef CPPHTTPLIB_IDLE_INTERVAL_SECOND
|
|
@@ -90,8 +110,12 @@
|
|
|
90
110
|
#define CPPHTTPLIB_TCP_NODELAY false
|
|
91
111
|
#endif
|
|
92
112
|
|
|
113
|
+
#ifndef CPPHTTPLIB_IPV6_V6ONLY
|
|
114
|
+
#define CPPHTTPLIB_IPV6_V6ONLY false
|
|
115
|
+
#endif
|
|
116
|
+
|
|
93
117
|
#ifndef CPPHTTPLIB_RECV_BUFSIZ
|
|
94
|
-
#define CPPHTTPLIB_RECV_BUFSIZ size_t(
|
|
118
|
+
#define CPPHTTPLIB_RECV_BUFSIZ size_t(16384u)
|
|
95
119
|
#endif
|
|
96
120
|
|
|
97
121
|
#ifndef CPPHTTPLIB_COMPRESSION_BUFSIZ
|
|
@@ -145,11 +169,11 @@ using ssize_t = long;
|
|
|
145
169
|
#endif // _MSC_VER
|
|
146
170
|
|
|
147
171
|
#ifndef S_ISREG
|
|
148
|
-
#define S_ISREG(m) (((m)&S_IFREG) == S_IFREG)
|
|
172
|
+
#define S_ISREG(m) (((m) & S_IFREG) == S_IFREG)
|
|
149
173
|
#endif // S_ISREG
|
|
150
174
|
|
|
151
175
|
#ifndef S_ISDIR
|
|
152
|
-
#define S_ISDIR(m) (((m)&S_IFDIR) == S_IFDIR)
|
|
176
|
+
#define S_ISDIR(m) (((m) & S_IFDIR) == S_IFDIR)
|
|
153
177
|
#endif // S_ISDIR
|
|
154
178
|
|
|
155
179
|
#ifndef NOMINMAX
|
|
@@ -269,7 +293,12 @@ using socket_t = int;
|
|
|
269
293
|
#include <iostream>
|
|
270
294
|
#include <sstream>
|
|
271
295
|
|
|
272
|
-
#if
|
|
296
|
+
#if defined(OPENSSL_IS_BORINGSSL) || defined(LIBRESSL_VERSION_NUMBER)
|
|
297
|
+
#if OPENSSL_VERSION_NUMBER < 0x1010107f
|
|
298
|
+
#error Please use OpenSSL or a current version of BoringSSL
|
|
299
|
+
#endif
|
|
300
|
+
#define SSL_get1_peer_certificate SSL_get_peer_certificate
|
|
301
|
+
#elif OPENSSL_VERSION_NUMBER < 0x30000000L
|
|
273
302
|
#error Sorry, OpenSSL versions prior to 3.0.0 are not supported
|
|
274
303
|
#endif
|
|
275
304
|
|
|
@@ -312,16 +341,63 @@ make_unique(std::size_t n) {
|
|
|
312
341
|
return std::unique_ptr<T>(new RT[n]);
|
|
313
342
|
}
|
|
314
343
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
344
|
+
namespace case_ignore {
|
|
345
|
+
|
|
346
|
+
inline unsigned char to_lower(int c) {
|
|
347
|
+
const static unsigned char table[256] = {
|
|
348
|
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
|
349
|
+
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
|
350
|
+
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
|
|
351
|
+
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
|
|
352
|
+
60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
|
|
353
|
+
107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
|
|
354
|
+
122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
|
|
355
|
+
105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
|
|
356
|
+
120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
|
|
357
|
+
135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
|
|
358
|
+
150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
|
|
359
|
+
165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
|
|
360
|
+
180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 224, 225, 226,
|
|
361
|
+
227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
|
|
362
|
+
242, 243, 244, 245, 246, 215, 248, 249, 250, 251, 252, 253, 254, 223, 224,
|
|
363
|
+
225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
|
|
364
|
+
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
|
|
365
|
+
255,
|
|
366
|
+
};
|
|
367
|
+
return table[(unsigned char)(char)c];
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
inline bool equal(const std::string &a, const std::string &b) {
|
|
371
|
+
return a.size() == b.size() &&
|
|
372
|
+
std::equal(a.begin(), a.end(), b.begin(), [](char ca, char cb) {
|
|
373
|
+
return to_lower(ca) == to_lower(cb);
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
struct equal_to {
|
|
378
|
+
bool operator()(const std::string &a, const std::string &b) const {
|
|
379
|
+
return equal(a, b);
|
|
322
380
|
}
|
|
323
381
|
};
|
|
324
382
|
|
|
383
|
+
struct hash {
|
|
384
|
+
size_t operator()(const std::string &key) const {
|
|
385
|
+
return hash_core(key.data(), key.size(), 0);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
size_t hash_core(const char *s, size_t l, size_t h) const {
|
|
389
|
+
return (l == 0) ? h
|
|
390
|
+
: hash_core(s + 1, l - 1,
|
|
391
|
+
// Unsets the 6 high bits of h, therefore no
|
|
392
|
+
// overflow happens
|
|
393
|
+
(((std::numeric_limits<size_t>::max)() >> 6) &
|
|
394
|
+
h * 33) ^
|
|
395
|
+
static_cast<unsigned char>(to_lower(*s)));
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
} // namespace case_ignore
|
|
400
|
+
|
|
325
401
|
// This is based on
|
|
326
402
|
// "http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4189".
|
|
327
403
|
|
|
@@ -427,7 +503,9 @@ enum StatusCode {
|
|
|
427
503
|
NetworkAuthenticationRequired_511 = 511,
|
|
428
504
|
};
|
|
429
505
|
|
|
430
|
-
using Headers =
|
|
506
|
+
using Headers =
|
|
507
|
+
std::unordered_multimap<std::string, std::string, detail::case_ignore::hash,
|
|
508
|
+
detail::case_ignore::equal_to>;
|
|
431
509
|
|
|
432
510
|
using Params = std::multimap<std::string, std::string>;
|
|
433
511
|
using Match = std::smatch;
|
|
@@ -534,6 +612,7 @@ using Ranges = std::vector<Range>;
|
|
|
534
612
|
struct Request {
|
|
535
613
|
std::string method;
|
|
536
614
|
std::string path;
|
|
615
|
+
Params params;
|
|
537
616
|
Headers headers;
|
|
538
617
|
std::string body;
|
|
539
618
|
|
|
@@ -545,11 +624,11 @@ struct Request {
|
|
|
545
624
|
// for server
|
|
546
625
|
std::string version;
|
|
547
626
|
std::string target;
|
|
548
|
-
Params params;
|
|
549
627
|
MultipartFormDataMap files;
|
|
550
628
|
Ranges ranges;
|
|
551
629
|
Match matches;
|
|
552
630
|
std::unordered_map<std::string, std::string> path_params;
|
|
631
|
+
std::function<bool()> is_connection_closed = []() { return true; };
|
|
553
632
|
|
|
554
633
|
// for client
|
|
555
634
|
ResponseHandler response_handler;
|
|
@@ -560,8 +639,10 @@ struct Request {
|
|
|
560
639
|
#endif
|
|
561
640
|
|
|
562
641
|
bool has_header(const std::string &key) const;
|
|
563
|
-
std::string get_header_value(const std::string &key,
|
|
564
|
-
|
|
642
|
+
std::string get_header_value(const std::string &key, const char *def = "",
|
|
643
|
+
size_t id = 0) const;
|
|
644
|
+
uint64_t get_header_value_u64(const std::string &key, uint64_t def = 0,
|
|
645
|
+
size_t id = 0) const;
|
|
565
646
|
size_t get_header_value_count(const std::string &key) const;
|
|
566
647
|
void set_header(const std::string &key, const std::string &val);
|
|
567
648
|
|
|
@@ -592,8 +673,10 @@ struct Response {
|
|
|
592
673
|
std::string location; // Redirect location
|
|
593
674
|
|
|
594
675
|
bool has_header(const std::string &key) const;
|
|
595
|
-
std::string get_header_value(const std::string &key,
|
|
596
|
-
|
|
676
|
+
std::string get_header_value(const std::string &key, const char *def = "",
|
|
677
|
+
size_t id = 0) const;
|
|
678
|
+
uint64_t get_header_value_u64(const std::string &key, uint64_t def = 0,
|
|
679
|
+
size_t id = 0) const;
|
|
597
680
|
size_t get_header_value_count(const std::string &key) const;
|
|
598
681
|
void set_header(const std::string &key, const std::string &val);
|
|
599
682
|
|
|
@@ -614,6 +697,10 @@ struct Response {
|
|
|
614
697
|
const std::string &content_type, ContentProviderWithoutLength provider,
|
|
615
698
|
ContentProviderResourceReleaser resource_releaser = nullptr);
|
|
616
699
|
|
|
700
|
+
void set_file_content(const std::string &path,
|
|
701
|
+
const std::string &content_type);
|
|
702
|
+
void set_file_content(const std::string &path);
|
|
703
|
+
|
|
617
704
|
Response() = default;
|
|
618
705
|
Response(const Response &) = default;
|
|
619
706
|
Response &operator=(const Response &) = default;
|
|
@@ -631,6 +718,8 @@ struct Response {
|
|
|
631
718
|
ContentProviderResourceReleaser content_provider_resource_releaser_;
|
|
632
719
|
bool is_chunked_content_provider_ = false;
|
|
633
720
|
bool content_provider_success_ = false;
|
|
721
|
+
std::string file_content_path_;
|
|
722
|
+
std::string file_content_content_type_;
|
|
634
723
|
};
|
|
635
724
|
|
|
636
725
|
class Stream {
|
|
@@ -646,8 +735,6 @@ public:
|
|
|
646
735
|
virtual void get_local_ip_and_port(std::string &ip, int &port) const = 0;
|
|
647
736
|
virtual socket_t socket() const = 0;
|
|
648
737
|
|
|
649
|
-
template <typename... Args>
|
|
650
|
-
ssize_t write_format(const char *fmt, const Args &...args);
|
|
651
738
|
ssize_t write(const char *ptr);
|
|
652
739
|
ssize_t write(const std::string &s);
|
|
653
740
|
};
|
|
@@ -719,13 +806,18 @@ private:
|
|
|
719
806
|
|
|
720
807
|
if (pool_.shutdown_ && pool_.jobs_.empty()) { break; }
|
|
721
808
|
|
|
722
|
-
fn =
|
|
809
|
+
fn = pool_.jobs_.front();
|
|
723
810
|
pool_.jobs_.pop_front();
|
|
724
811
|
}
|
|
725
812
|
|
|
726
813
|
assert(true == static_cast<bool>(fn));
|
|
727
814
|
fn();
|
|
728
815
|
}
|
|
816
|
+
|
|
817
|
+
#if defined(CPPHTTPLIB_OPENSSL_SUPPORT) && !defined(OPENSSL_IS_BORINGSSL) && \
|
|
818
|
+
!defined(LIBRESSL_VERSION_NUMBER)
|
|
819
|
+
OPENSSL_thread_stop();
|
|
820
|
+
#endif
|
|
729
821
|
}
|
|
730
822
|
|
|
731
823
|
ThreadPool &pool_;
|
|
@@ -787,7 +879,6 @@ public:
|
|
|
787
879
|
bool match(Request &request) const override;
|
|
788
880
|
|
|
789
881
|
private:
|
|
790
|
-
static constexpr char marker = ':';
|
|
791
882
|
// Treat segment separators as the end of path parameter capture
|
|
792
883
|
// Does not need to handle query parameters as they are parsed before path
|
|
793
884
|
// matching
|
|
@@ -871,8 +962,13 @@ public:
|
|
|
871
962
|
Server &set_default_file_mimetype(const std::string &mime);
|
|
872
963
|
Server &set_file_request_handler(Handler handler);
|
|
873
964
|
|
|
874
|
-
|
|
875
|
-
Server &set_error_handler(
|
|
965
|
+
template <class ErrorHandlerFunc>
|
|
966
|
+
Server &set_error_handler(ErrorHandlerFunc &&handler) {
|
|
967
|
+
return set_error_handler_core(
|
|
968
|
+
std::forward<ErrorHandlerFunc>(handler),
|
|
969
|
+
std::is_convertible<ErrorHandlerFunc, HandlerWithResponse>{});
|
|
970
|
+
}
|
|
971
|
+
|
|
876
972
|
Server &set_exception_handler(ExceptionHandler handler);
|
|
877
973
|
Server &set_pre_routing_handler(HandlerWithResponse handler);
|
|
878
974
|
Server &set_post_routing_handler(Handler handler);
|
|
@@ -882,6 +978,7 @@ public:
|
|
|
882
978
|
|
|
883
979
|
Server &set_address_family(int family);
|
|
884
980
|
Server &set_tcp_nodelay(bool on);
|
|
981
|
+
Server &set_ipv6_v6only(bool on);
|
|
885
982
|
Server &set_socket_options(SocketOptions socket_options);
|
|
886
983
|
|
|
887
984
|
Server &set_default_headers(Headers headers);
|
|
@@ -914,21 +1011,24 @@ public:
|
|
|
914
1011
|
bool is_running() const;
|
|
915
1012
|
void wait_until_ready() const;
|
|
916
1013
|
void stop();
|
|
1014
|
+
void decommission();
|
|
917
1015
|
|
|
918
1016
|
std::function<TaskQueue *(void)> new_task_queue;
|
|
919
1017
|
|
|
920
1018
|
protected:
|
|
921
|
-
bool process_request(Stream &strm,
|
|
1019
|
+
bool process_request(Stream &strm, const std::string &remote_addr,
|
|
1020
|
+
int remote_port, const std::string &local_addr,
|
|
1021
|
+
int local_port, bool close_connection,
|
|
922
1022
|
bool &connection_closed,
|
|
923
1023
|
const std::function<void(Request &)> &setup_request);
|
|
924
1024
|
|
|
925
1025
|
std::atomic<socket_t> svr_sock_{INVALID_SOCKET};
|
|
926
1026
|
size_t keep_alive_max_count_ = CPPHTTPLIB_KEEPALIVE_MAX_COUNT;
|
|
927
1027
|
time_t keep_alive_timeout_sec_ = CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND;
|
|
928
|
-
time_t read_timeout_sec_ =
|
|
929
|
-
time_t read_timeout_usec_ =
|
|
930
|
-
time_t write_timeout_sec_ =
|
|
931
|
-
time_t write_timeout_usec_ =
|
|
1028
|
+
time_t read_timeout_sec_ = CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND;
|
|
1029
|
+
time_t read_timeout_usec_ = CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND;
|
|
1030
|
+
time_t write_timeout_sec_ = CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND;
|
|
1031
|
+
time_t write_timeout_usec_ = CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND;
|
|
932
1032
|
time_t idle_interval_sec_ = CPPHTTPLIB_IDLE_INTERVAL_SECOND;
|
|
933
1033
|
time_t idle_interval_usec_ = CPPHTTPLIB_IDLE_INTERVAL_USECOND;
|
|
934
1034
|
size_t payload_max_length_ = CPPHTTPLIB_PAYLOAD_MAX_LENGTH;
|
|
@@ -943,6 +1043,9 @@ private:
|
|
|
943
1043
|
static std::unique_ptr<detail::MatcherBase>
|
|
944
1044
|
make_matcher(const std::string &pattern);
|
|
945
1045
|
|
|
1046
|
+
Server &set_error_handler_core(HandlerWithResponse handler, std::true_type);
|
|
1047
|
+
Server &set_error_handler_core(Handler handler, std::false_type);
|
|
1048
|
+
|
|
946
1049
|
socket_t create_server_socket(const std::string &host, int port,
|
|
947
1050
|
int socket_flags,
|
|
948
1051
|
SocketOptions socket_options) const;
|
|
@@ -985,7 +1088,7 @@ private:
|
|
|
985
1088
|
virtual bool process_and_close_socket(socket_t sock);
|
|
986
1089
|
|
|
987
1090
|
std::atomic<bool> is_running_{false};
|
|
988
|
-
std::atomic<bool>
|
|
1091
|
+
std::atomic<bool> is_decommisioned{false};
|
|
989
1092
|
|
|
990
1093
|
struct MountPointEntry {
|
|
991
1094
|
std::string mount_point;
|
|
@@ -1018,6 +1121,7 @@ private:
|
|
|
1018
1121
|
|
|
1019
1122
|
int address_family_ = AF_UNSPEC;
|
|
1020
1123
|
bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
|
|
1124
|
+
bool ipv6_v6only_ = CPPHTTPLIB_IPV6_V6ONLY;
|
|
1021
1125
|
SocketOptions socket_options_ = default_socket_options;
|
|
1022
1126
|
|
|
1023
1127
|
Headers default_headers_;
|
|
@@ -1037,6 +1141,7 @@ enum class Error {
|
|
|
1037
1141
|
SSLConnection,
|
|
1038
1142
|
SSLLoadingCerts,
|
|
1039
1143
|
SSLServerVerification,
|
|
1144
|
+
SSLServerHostnameVerification,
|
|
1040
1145
|
UnsupportedMultipartBoundaryChars,
|
|
1041
1146
|
Compression,
|
|
1042
1147
|
ConnectionTimeout,
|
|
@@ -1074,9 +1179,10 @@ public:
|
|
|
1074
1179
|
// Request Headers
|
|
1075
1180
|
bool has_request_header(const std::string &key) const;
|
|
1076
1181
|
std::string get_request_header_value(const std::string &key,
|
|
1182
|
+
const char *def = "",
|
|
1077
1183
|
size_t id = 0) const;
|
|
1078
1184
|
uint64_t get_request_header_value_u64(const std::string &key,
|
|
1079
|
-
size_t id = 0) const;
|
|
1185
|
+
uint64_t def = 0, size_t id = 0) const;
|
|
1080
1186
|
size_t get_request_header_value_count(const std::string &key) const;
|
|
1081
1187
|
|
|
1082
1188
|
private:
|
|
@@ -1140,10 +1246,18 @@ public:
|
|
|
1140
1246
|
const std::string &content_type);
|
|
1141
1247
|
Result Post(const std::string &path, const Headers &headers, const char *body,
|
|
1142
1248
|
size_t content_length, const std::string &content_type);
|
|
1249
|
+
Result Post(const std::string &path, const Headers &headers, const char *body,
|
|
1250
|
+
size_t content_length, const std::string &content_type,
|
|
1251
|
+
Progress progress);
|
|
1143
1252
|
Result Post(const std::string &path, const std::string &body,
|
|
1144
1253
|
const std::string &content_type);
|
|
1254
|
+
Result Post(const std::string &path, const std::string &body,
|
|
1255
|
+
const std::string &content_type, Progress progress);
|
|
1145
1256
|
Result Post(const std::string &path, const Headers &headers,
|
|
1146
1257
|
const std::string &body, const std::string &content_type);
|
|
1258
|
+
Result Post(const std::string &path, const Headers &headers,
|
|
1259
|
+
const std::string &body, const std::string &content_type,
|
|
1260
|
+
Progress progress);
|
|
1147
1261
|
Result Post(const std::string &path, size_t content_length,
|
|
1148
1262
|
ContentProvider content_provider,
|
|
1149
1263
|
const std::string &content_type);
|
|
@@ -1159,6 +1273,8 @@ public:
|
|
|
1159
1273
|
Result Post(const std::string &path, const Params ¶ms);
|
|
1160
1274
|
Result Post(const std::string &path, const Headers &headers,
|
|
1161
1275
|
const Params ¶ms);
|
|
1276
|
+
Result Post(const std::string &path, const Headers &headers,
|
|
1277
|
+
const Params ¶ms, Progress progress);
|
|
1162
1278
|
Result Post(const std::string &path, const MultipartFormDataItems &items);
|
|
1163
1279
|
Result Post(const std::string &path, const Headers &headers,
|
|
1164
1280
|
const MultipartFormDataItems &items);
|
|
@@ -1173,10 +1289,18 @@ public:
|
|
|
1173
1289
|
const std::string &content_type);
|
|
1174
1290
|
Result Put(const std::string &path, const Headers &headers, const char *body,
|
|
1175
1291
|
size_t content_length, const std::string &content_type);
|
|
1292
|
+
Result Put(const std::string &path, const Headers &headers, const char *body,
|
|
1293
|
+
size_t content_length, const std::string &content_type,
|
|
1294
|
+
Progress progress);
|
|
1176
1295
|
Result Put(const std::string &path, const std::string &body,
|
|
1177
1296
|
const std::string &content_type);
|
|
1297
|
+
Result Put(const std::string &path, const std::string &body,
|
|
1298
|
+
const std::string &content_type, Progress progress);
|
|
1178
1299
|
Result Put(const std::string &path, const Headers &headers,
|
|
1179
1300
|
const std::string &body, const std::string &content_type);
|
|
1301
|
+
Result Put(const std::string &path, const Headers &headers,
|
|
1302
|
+
const std::string &body, const std::string &content_type,
|
|
1303
|
+
Progress progress);
|
|
1180
1304
|
Result Put(const std::string &path, size_t content_length,
|
|
1181
1305
|
ContentProvider content_provider, const std::string &content_type);
|
|
1182
1306
|
Result Put(const std::string &path,
|
|
@@ -1191,6 +1315,8 @@ public:
|
|
|
1191
1315
|
Result Put(const std::string &path, const Params ¶ms);
|
|
1192
1316
|
Result Put(const std::string &path, const Headers &headers,
|
|
1193
1317
|
const Params ¶ms);
|
|
1318
|
+
Result Put(const std::string &path, const Headers &headers,
|
|
1319
|
+
const Params ¶ms, Progress progress);
|
|
1194
1320
|
Result Put(const std::string &path, const MultipartFormDataItems &items);
|
|
1195
1321
|
Result Put(const std::string &path, const Headers &headers,
|
|
1196
1322
|
const MultipartFormDataItems &items);
|
|
@@ -1203,13 +1329,23 @@ public:
|
|
|
1203
1329
|
Result Patch(const std::string &path);
|
|
1204
1330
|
Result Patch(const std::string &path, const char *body, size_t content_length,
|
|
1205
1331
|
const std::string &content_type);
|
|
1332
|
+
Result Patch(const std::string &path, const char *body, size_t content_length,
|
|
1333
|
+
const std::string &content_type, Progress progress);
|
|
1206
1334
|
Result Patch(const std::string &path, const Headers &headers,
|
|
1207
1335
|
const char *body, size_t content_length,
|
|
1208
1336
|
const std::string &content_type);
|
|
1337
|
+
Result Patch(const std::string &path, const Headers &headers,
|
|
1338
|
+
const char *body, size_t content_length,
|
|
1339
|
+
const std::string &content_type, Progress progress);
|
|
1209
1340
|
Result Patch(const std::string &path, const std::string &body,
|
|
1210
1341
|
const std::string &content_type);
|
|
1342
|
+
Result Patch(const std::string &path, const std::string &body,
|
|
1343
|
+
const std::string &content_type, Progress progress);
|
|
1211
1344
|
Result Patch(const std::string &path, const Headers &headers,
|
|
1212
1345
|
const std::string &body, const std::string &content_type);
|
|
1346
|
+
Result Patch(const std::string &path, const Headers &headers,
|
|
1347
|
+
const std::string &body, const std::string &content_type,
|
|
1348
|
+
Progress progress);
|
|
1213
1349
|
Result Patch(const std::string &path, size_t content_length,
|
|
1214
1350
|
ContentProvider content_provider,
|
|
1215
1351
|
const std::string &content_type);
|
|
@@ -1227,13 +1363,24 @@ public:
|
|
|
1227
1363
|
Result Delete(const std::string &path, const Headers &headers);
|
|
1228
1364
|
Result Delete(const std::string &path, const char *body,
|
|
1229
1365
|
size_t content_length, const std::string &content_type);
|
|
1366
|
+
Result Delete(const std::string &path, const char *body,
|
|
1367
|
+
size_t content_length, const std::string &content_type,
|
|
1368
|
+
Progress progress);
|
|
1230
1369
|
Result Delete(const std::string &path, const Headers &headers,
|
|
1231
1370
|
const char *body, size_t content_length,
|
|
1232
1371
|
const std::string &content_type);
|
|
1372
|
+
Result Delete(const std::string &path, const Headers &headers,
|
|
1373
|
+
const char *body, size_t content_length,
|
|
1374
|
+
const std::string &content_type, Progress progress);
|
|
1233
1375
|
Result Delete(const std::string &path, const std::string &body,
|
|
1234
1376
|
const std::string &content_type);
|
|
1377
|
+
Result Delete(const std::string &path, const std::string &body,
|
|
1378
|
+
const std::string &content_type, Progress progress);
|
|
1235
1379
|
Result Delete(const std::string &path, const Headers &headers,
|
|
1236
1380
|
const std::string &body, const std::string &content_type);
|
|
1381
|
+
Result Delete(const std::string &path, const Headers &headers,
|
|
1382
|
+
const std::string &body, const std::string &content_type,
|
|
1383
|
+
Progress progress);
|
|
1237
1384
|
|
|
1238
1385
|
Result Options(const std::string &path);
|
|
1239
1386
|
Result Options(const std::string &path, const Headers &headers);
|
|
@@ -1258,6 +1405,7 @@ public:
|
|
|
1258
1405
|
|
|
1259
1406
|
void set_address_family(int family);
|
|
1260
1407
|
void set_tcp_nodelay(bool on);
|
|
1408
|
+
void set_ipv6_v6only(bool on);
|
|
1261
1409
|
void set_socket_options(SocketOptions socket_options);
|
|
1262
1410
|
|
|
1263
1411
|
void set_connection_timeout(time_t sec, time_t usec = 0);
|
|
@@ -1309,6 +1457,8 @@ public:
|
|
|
1309
1457
|
|
|
1310
1458
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
|
1311
1459
|
void enable_server_certificate_verification(bool enabled);
|
|
1460
|
+
void enable_server_hostname_verification(bool enabled);
|
|
1461
|
+
void set_server_certificate_verifier(std::function<bool(SSL *ssl)> verifier);
|
|
1312
1462
|
#endif
|
|
1313
1463
|
|
|
1314
1464
|
void set_logger(Logger logger);
|
|
@@ -1375,10 +1525,10 @@ protected:
|
|
|
1375
1525
|
|
|
1376
1526
|
time_t connection_timeout_sec_ = CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND;
|
|
1377
1527
|
time_t connection_timeout_usec_ = CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND;
|
|
1378
|
-
time_t read_timeout_sec_ =
|
|
1379
|
-
time_t read_timeout_usec_ =
|
|
1380
|
-
time_t write_timeout_sec_ =
|
|
1381
|
-
time_t write_timeout_usec_ =
|
|
1528
|
+
time_t read_timeout_sec_ = CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND;
|
|
1529
|
+
time_t read_timeout_usec_ = CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND;
|
|
1530
|
+
time_t write_timeout_sec_ = CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND;
|
|
1531
|
+
time_t write_timeout_usec_ = CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND;
|
|
1382
1532
|
|
|
1383
1533
|
std::string basic_auth_username_;
|
|
1384
1534
|
std::string basic_auth_password_;
|
|
@@ -1395,6 +1545,7 @@ protected:
|
|
|
1395
1545
|
|
|
1396
1546
|
int address_family_ = AF_UNSPEC;
|
|
1397
1547
|
bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
|
|
1548
|
+
bool ipv6_v6only_ = CPPHTTPLIB_IPV6_V6ONLY;
|
|
1398
1549
|
SocketOptions socket_options_ = nullptr;
|
|
1399
1550
|
|
|
1400
1551
|
bool compress_ = false;
|
|
@@ -1422,6 +1573,8 @@ protected:
|
|
|
1422
1573
|
|
|
1423
1574
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
|
1424
1575
|
bool server_certificate_verification_ = true;
|
|
1576
|
+
bool server_hostname_verification_ = true;
|
|
1577
|
+
std::function<bool(SSL *ssl)> server_certificate_verifier_;
|
|
1425
1578
|
#endif
|
|
1426
1579
|
|
|
1427
1580
|
Logger logger_;
|
|
@@ -1430,6 +1583,9 @@ private:
|
|
|
1430
1583
|
bool send_(Request &req, Response &res, Error &error);
|
|
1431
1584
|
Result send_(Request &&req);
|
|
1432
1585
|
|
|
1586
|
+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
|
1587
|
+
bool is_ssl_peer_could_be_closed(SSL *ssl) const;
|
|
1588
|
+
#endif
|
|
1433
1589
|
socket_t create_client_socket(Error &error) const;
|
|
1434
1590
|
bool read_response_line(Stream &strm, const Request &req,
|
|
1435
1591
|
Response &res) const;
|
|
@@ -1448,7 +1604,7 @@ private:
|
|
|
1448
1604
|
const Headers &headers, const char *body, size_t content_length,
|
|
1449
1605
|
ContentProvider content_provider,
|
|
1450
1606
|
ContentProviderWithoutLength content_provider_without_length,
|
|
1451
|
-
const std::string &content_type);
|
|
1607
|
+
const std::string &content_type, Progress progress);
|
|
1452
1608
|
ContentProviderWithoutLength get_multipart_content_provider(
|
|
1453
1609
|
const std::string &boundary, const MultipartFormDataItems &items,
|
|
1454
1610
|
const MultipartFormDataProviderItems &provider_items) const;
|
|
@@ -1477,6 +1633,7 @@ public:
|
|
|
1477
1633
|
const std::string &client_key_path);
|
|
1478
1634
|
|
|
1479
1635
|
Client(Client &&) = default;
|
|
1636
|
+
Client &operator=(Client &&) = default;
|
|
1480
1637
|
|
|
1481
1638
|
~Client();
|
|
1482
1639
|
|
|
@@ -1523,10 +1680,18 @@ public:
|
|
|
1523
1680
|
const std::string &content_type);
|
|
1524
1681
|
Result Post(const std::string &path, const Headers &headers, const char *body,
|
|
1525
1682
|
size_t content_length, const std::string &content_type);
|
|
1683
|
+
Result Post(const std::string &path, const Headers &headers, const char *body,
|
|
1684
|
+
size_t content_length, const std::string &content_type,
|
|
1685
|
+
Progress progress);
|
|
1526
1686
|
Result Post(const std::string &path, const std::string &body,
|
|
1527
1687
|
const std::string &content_type);
|
|
1688
|
+
Result Post(const std::string &path, const std::string &body,
|
|
1689
|
+
const std::string &content_type, Progress progress);
|
|
1528
1690
|
Result Post(const std::string &path, const Headers &headers,
|
|
1529
1691
|
const std::string &body, const std::string &content_type);
|
|
1692
|
+
Result Post(const std::string &path, const Headers &headers,
|
|
1693
|
+
const std::string &body, const std::string &content_type,
|
|
1694
|
+
Progress progress);
|
|
1530
1695
|
Result Post(const std::string &path, size_t content_length,
|
|
1531
1696
|
ContentProvider content_provider,
|
|
1532
1697
|
const std::string &content_type);
|
|
@@ -1542,6 +1707,8 @@ public:
|
|
|
1542
1707
|
Result Post(const std::string &path, const Params ¶ms);
|
|
1543
1708
|
Result Post(const std::string &path, const Headers &headers,
|
|
1544
1709
|
const Params ¶ms);
|
|
1710
|
+
Result Post(const std::string &path, const Headers &headers,
|
|
1711
|
+
const Params ¶ms, Progress progress);
|
|
1545
1712
|
Result Post(const std::string &path, const MultipartFormDataItems &items);
|
|
1546
1713
|
Result Post(const std::string &path, const Headers &headers,
|
|
1547
1714
|
const MultipartFormDataItems &items);
|
|
@@ -1556,10 +1723,18 @@ public:
|
|
|
1556
1723
|
const std::string &content_type);
|
|
1557
1724
|
Result Put(const std::string &path, const Headers &headers, const char *body,
|
|
1558
1725
|
size_t content_length, const std::string &content_type);
|
|
1726
|
+
Result Put(const std::string &path, const Headers &headers, const char *body,
|
|
1727
|
+
size_t content_length, const std::string &content_type,
|
|
1728
|
+
Progress progress);
|
|
1559
1729
|
Result Put(const std::string &path, const std::string &body,
|
|
1560
1730
|
const std::string &content_type);
|
|
1731
|
+
Result Put(const std::string &path, const std::string &body,
|
|
1732
|
+
const std::string &content_type, Progress progress);
|
|
1561
1733
|
Result Put(const std::string &path, const Headers &headers,
|
|
1562
1734
|
const std::string &body, const std::string &content_type);
|
|
1735
|
+
Result Put(const std::string &path, const Headers &headers,
|
|
1736
|
+
const std::string &body, const std::string &content_type,
|
|
1737
|
+
Progress progress);
|
|
1563
1738
|
Result Put(const std::string &path, size_t content_length,
|
|
1564
1739
|
ContentProvider content_provider, const std::string &content_type);
|
|
1565
1740
|
Result Put(const std::string &path,
|
|
@@ -1574,6 +1749,8 @@ public:
|
|
|
1574
1749
|
Result Put(const std::string &path, const Params ¶ms);
|
|
1575
1750
|
Result Put(const std::string &path, const Headers &headers,
|
|
1576
1751
|
const Params ¶ms);
|
|
1752
|
+
Result Put(const std::string &path, const Headers &headers,
|
|
1753
|
+
const Params ¶ms, Progress progress);
|
|
1577
1754
|
Result Put(const std::string &path, const MultipartFormDataItems &items);
|
|
1578
1755
|
Result Put(const std::string &path, const Headers &headers,
|
|
1579
1756
|
const MultipartFormDataItems &items);
|
|
@@ -1586,13 +1763,23 @@ public:
|
|
|
1586
1763
|
Result Patch(const std::string &path);
|
|
1587
1764
|
Result Patch(const std::string &path, const char *body, size_t content_length,
|
|
1588
1765
|
const std::string &content_type);
|
|
1766
|
+
Result Patch(const std::string &path, const char *body, size_t content_length,
|
|
1767
|
+
const std::string &content_type, Progress progress);
|
|
1589
1768
|
Result Patch(const std::string &path, const Headers &headers,
|
|
1590
1769
|
const char *body, size_t content_length,
|
|
1591
1770
|
const std::string &content_type);
|
|
1771
|
+
Result Patch(const std::string &path, const Headers &headers,
|
|
1772
|
+
const char *body, size_t content_length,
|
|
1773
|
+
const std::string &content_type, Progress progress);
|
|
1592
1774
|
Result Patch(const std::string &path, const std::string &body,
|
|
1593
1775
|
const std::string &content_type);
|
|
1776
|
+
Result Patch(const std::string &path, const std::string &body,
|
|
1777
|
+
const std::string &content_type, Progress progress);
|
|
1594
1778
|
Result Patch(const std::string &path, const Headers &headers,
|
|
1595
1779
|
const std::string &body, const std::string &content_type);
|
|
1780
|
+
Result Patch(const std::string &path, const Headers &headers,
|
|
1781
|
+
const std::string &body, const std::string &content_type,
|
|
1782
|
+
Progress progress);
|
|
1596
1783
|
Result Patch(const std::string &path, size_t content_length,
|
|
1597
1784
|
ContentProvider content_provider,
|
|
1598
1785
|
const std::string &content_type);
|
|
@@ -1610,13 +1797,24 @@ public:
|
|
|
1610
1797
|
Result Delete(const std::string &path, const Headers &headers);
|
|
1611
1798
|
Result Delete(const std::string &path, const char *body,
|
|
1612
1799
|
size_t content_length, const std::string &content_type);
|
|
1800
|
+
Result Delete(const std::string &path, const char *body,
|
|
1801
|
+
size_t content_length, const std::string &content_type,
|
|
1802
|
+
Progress progress);
|
|
1613
1803
|
Result Delete(const std::string &path, const Headers &headers,
|
|
1614
1804
|
const char *body, size_t content_length,
|
|
1615
1805
|
const std::string &content_type);
|
|
1806
|
+
Result Delete(const std::string &path, const Headers &headers,
|
|
1807
|
+
const char *body, size_t content_length,
|
|
1808
|
+
const std::string &content_type, Progress progress);
|
|
1616
1809
|
Result Delete(const std::string &path, const std::string &body,
|
|
1617
1810
|
const std::string &content_type);
|
|
1811
|
+
Result Delete(const std::string &path, const std::string &body,
|
|
1812
|
+
const std::string &content_type, Progress progress);
|
|
1618
1813
|
Result Delete(const std::string &path, const Headers &headers,
|
|
1619
1814
|
const std::string &body, const std::string &content_type);
|
|
1815
|
+
Result Delete(const std::string &path, const Headers &headers,
|
|
1816
|
+
const std::string &body, const std::string &content_type,
|
|
1817
|
+
Progress progress);
|
|
1620
1818
|
|
|
1621
1819
|
Result Options(const std::string &path);
|
|
1622
1820
|
Result Options(const std::string &path, const Headers &headers);
|
|
@@ -1685,6 +1883,8 @@ public:
|
|
|
1685
1883
|
|
|
1686
1884
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
|
1687
1885
|
void enable_server_certificate_verification(bool enabled);
|
|
1886
|
+
void enable_server_hostname_verification(bool enabled);
|
|
1887
|
+
void set_server_certificate_verifier(std::function<bool(SSL *ssl)> verifier);
|
|
1688
1888
|
#endif
|
|
1689
1889
|
|
|
1690
1890
|
void set_logger(Logger logger);
|
|
@@ -1730,6 +1930,9 @@ public:
|
|
|
1730
1930
|
|
|
1731
1931
|
SSL_CTX *ssl_context() const;
|
|
1732
1932
|
|
|
1933
|
+
void update_certs(X509 *cert, EVP_PKEY *private_key,
|
|
1934
|
+
X509_STORE *client_ca_cert_store = nullptr);
|
|
1935
|
+
|
|
1733
1936
|
private:
|
|
1734
1937
|
bool process_and_close_socket(socket_t sock) override;
|
|
1735
1938
|
|
|
@@ -1810,68 +2013,58 @@ inline void duration_to_sec_and_usec(const T &duration, U callback) {
|
|
|
1810
2013
|
callback(static_cast<time_t>(sec), static_cast<time_t>(usec));
|
|
1811
2014
|
}
|
|
1812
2015
|
|
|
2016
|
+
inline bool is_numeric(const std::string &str) {
|
|
2017
|
+
return !str.empty() && std::all_of(str.begin(), str.end(), ::isdigit);
|
|
2018
|
+
}
|
|
2019
|
+
|
|
1813
2020
|
inline uint64_t get_header_value_u64(const Headers &headers,
|
|
1814
|
-
const std::string &key,
|
|
1815
|
-
|
|
2021
|
+
const std::string &key, uint64_t def,
|
|
2022
|
+
size_t id, bool &is_invalid_value) {
|
|
2023
|
+
is_invalid_value = false;
|
|
1816
2024
|
auto rng = headers.equal_range(key);
|
|
1817
2025
|
auto it = rng.first;
|
|
1818
2026
|
std::advance(it, static_cast<ssize_t>(id));
|
|
1819
2027
|
if (it != rng.second) {
|
|
1820
|
-
|
|
2028
|
+
if (is_numeric(it->second)) {
|
|
2029
|
+
return std::strtoull(it->second.data(), nullptr, 10);
|
|
2030
|
+
} else {
|
|
2031
|
+
is_invalid_value = true;
|
|
2032
|
+
}
|
|
1821
2033
|
}
|
|
1822
2034
|
return def;
|
|
1823
2035
|
}
|
|
1824
2036
|
|
|
2037
|
+
inline uint64_t get_header_value_u64(const Headers &headers,
|
|
2038
|
+
const std::string &key, uint64_t def,
|
|
2039
|
+
size_t id) {
|
|
2040
|
+
bool dummy = false;
|
|
2041
|
+
return get_header_value_u64(headers, key, def, id, dummy);
|
|
2042
|
+
}
|
|
2043
|
+
|
|
1825
2044
|
} // namespace detail
|
|
1826
2045
|
|
|
1827
2046
|
inline uint64_t Request::get_header_value_u64(const std::string &key,
|
|
1828
|
-
size_t id) const {
|
|
1829
|
-
return detail::get_header_value_u64(headers, key,
|
|
2047
|
+
uint64_t def, size_t id) const {
|
|
2048
|
+
return detail::get_header_value_u64(headers, key, def, id);
|
|
1830
2049
|
}
|
|
1831
2050
|
|
|
1832
2051
|
inline uint64_t Response::get_header_value_u64(const std::string &key,
|
|
1833
|
-
size_t id) const {
|
|
1834
|
-
return detail::get_header_value_u64(headers, key,
|
|
1835
|
-
}
|
|
1836
|
-
|
|
1837
|
-
template <typename... Args>
|
|
1838
|
-
inline ssize_t Stream::write_format(const char *fmt, const Args &...args) {
|
|
1839
|
-
const auto bufsiz = 2048;
|
|
1840
|
-
std::array<char, bufsiz> buf{};
|
|
1841
|
-
|
|
1842
|
-
auto sn = snprintf(buf.data(), buf.size() - 1, fmt, args...);
|
|
1843
|
-
if (sn <= 0) { return sn; }
|
|
1844
|
-
|
|
1845
|
-
auto n = static_cast<size_t>(sn);
|
|
1846
|
-
|
|
1847
|
-
if (n >= buf.size() - 1) {
|
|
1848
|
-
std::vector<char> glowable_buf(buf.size());
|
|
1849
|
-
|
|
1850
|
-
while (n >= glowable_buf.size() - 1) {
|
|
1851
|
-
glowable_buf.resize(glowable_buf.size() * 2);
|
|
1852
|
-
n = static_cast<size_t>(
|
|
1853
|
-
snprintf(&glowable_buf[0], glowable_buf.size() - 1, fmt, args...));
|
|
1854
|
-
}
|
|
1855
|
-
return write(&glowable_buf[0], n);
|
|
1856
|
-
} else {
|
|
1857
|
-
return write(buf.data(), n);
|
|
1858
|
-
}
|
|
2052
|
+
uint64_t def, size_t id) const {
|
|
2053
|
+
return detail::get_header_value_u64(headers, key, def, id);
|
|
1859
2054
|
}
|
|
1860
2055
|
|
|
1861
2056
|
inline void default_socket_options(socket_t sock) {
|
|
1862
|
-
int
|
|
2057
|
+
int opt = 1;
|
|
1863
2058
|
#ifdef _WIN32
|
|
1864
2059
|
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
|
|
1865
|
-
reinterpret_cast<const char *>(&
|
|
1866
|
-
setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
|
|
1867
|
-
reinterpret_cast<const char *>(&yes), sizeof(yes));
|
|
2060
|
+
reinterpret_cast<const char *>(&opt), sizeof(opt));
|
|
1868
2061
|
#else
|
|
1869
2062
|
#ifdef SO_REUSEPORT
|
|
1870
2063
|
setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
|
|
1871
|
-
reinterpret_cast<const void *>(&
|
|
2064
|
+
reinterpret_cast<const void *>(&opt), sizeof(opt));
|
|
1872
2065
|
#else
|
|
1873
2066
|
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
|
|
1874
|
-
reinterpret_cast<const void *>(&
|
|
2067
|
+
reinterpret_cast<const void *>(&opt), sizeof(opt));
|
|
1875
2068
|
#endif
|
|
1876
2069
|
#endif
|
|
1877
2070
|
}
|
|
@@ -1997,6 +2190,8 @@ inline std::string to_string(const Error error) {
|
|
|
1997
2190
|
case Error::SSLConnection: return "SSL connection failed";
|
|
1998
2191
|
case Error::SSLLoadingCerts: return "SSL certificate loading failed";
|
|
1999
2192
|
case Error::SSLServerVerification: return "SSL server verification failed";
|
|
2193
|
+
case Error::SSLServerHostnameVerification:
|
|
2194
|
+
return "SSL server hostname verification failed";
|
|
2000
2195
|
case Error::UnsupportedMultipartBoundaryChars:
|
|
2001
2196
|
return "Unsupported HTTP multipart boundary characters";
|
|
2002
2197
|
case Error::Compression: return "Compression failed";
|
|
@@ -2016,8 +2211,9 @@ inline std::ostream &operator<<(std::ostream &os, const Error &obj) {
|
|
|
2016
2211
|
}
|
|
2017
2212
|
|
|
2018
2213
|
inline uint64_t Result::get_request_header_value_u64(const std::string &key,
|
|
2214
|
+
uint64_t def,
|
|
2019
2215
|
size_t id) const {
|
|
2020
|
-
return detail::get_header_value_u64(request_headers_, key,
|
|
2216
|
+
return detail::get_header_value_u64(request_headers_, key, def, id);
|
|
2021
2217
|
}
|
|
2022
2218
|
|
|
2023
2219
|
template <class Rep, class Period>
|
|
@@ -2080,6 +2276,36 @@ make_basic_authentication_header(const std::string &username,
|
|
|
2080
2276
|
|
|
2081
2277
|
namespace detail {
|
|
2082
2278
|
|
|
2279
|
+
#if defined(_WIN32)
|
|
2280
|
+
inline std::wstring u8string_to_wstring(const char *s) {
|
|
2281
|
+
std::wstring ws;
|
|
2282
|
+
auto len = static_cast<int>(strlen(s));
|
|
2283
|
+
auto wlen = ::MultiByteToWideChar(CP_UTF8, 0, s, len, nullptr, 0);
|
|
2284
|
+
if (wlen > 0) {
|
|
2285
|
+
ws.resize(wlen);
|
|
2286
|
+
wlen = ::MultiByteToWideChar(
|
|
2287
|
+
CP_UTF8, 0, s, len,
|
|
2288
|
+
const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(ws.data())), wlen);
|
|
2289
|
+
if (wlen != static_cast<int>(ws.size())) { ws.clear(); }
|
|
2290
|
+
}
|
|
2291
|
+
return ws;
|
|
2292
|
+
}
|
|
2293
|
+
#endif
|
|
2294
|
+
|
|
2295
|
+
struct FileStat {
|
|
2296
|
+
FileStat(const std::string &path);
|
|
2297
|
+
bool is_file() const;
|
|
2298
|
+
bool is_dir() const;
|
|
2299
|
+
|
|
2300
|
+
private:
|
|
2301
|
+
#if defined(_WIN32)
|
|
2302
|
+
struct _stat st_;
|
|
2303
|
+
#else
|
|
2304
|
+
struct stat st_;
|
|
2305
|
+
#endif
|
|
2306
|
+
int ret_ = -1;
|
|
2307
|
+
};
|
|
2308
|
+
|
|
2083
2309
|
std::string encode_query_param(const std::string &value);
|
|
2084
2310
|
|
|
2085
2311
|
std::string decode_url(const std::string &s, bool convert_plus_to_space);
|
|
@@ -2088,6 +2314,16 @@ void read_file(const std::string &path, std::string &out);
|
|
|
2088
2314
|
|
|
2089
2315
|
std::string trim_copy(const std::string &s);
|
|
2090
2316
|
|
|
2317
|
+
void divide(
|
|
2318
|
+
const char *data, std::size_t size, char d,
|
|
2319
|
+
std::function<void(const char *, std::size_t, const char *, std::size_t)>
|
|
2320
|
+
fn);
|
|
2321
|
+
|
|
2322
|
+
void divide(
|
|
2323
|
+
const std::string &str, char d,
|
|
2324
|
+
std::function<void(const char *, std::size_t, const char *, std::size_t)>
|
|
2325
|
+
fn);
|
|
2326
|
+
|
|
2091
2327
|
void split(const char *b, const char *e, char d,
|
|
2092
2328
|
std::function<void(const char *, const char *)> fn);
|
|
2093
2329
|
|
|
@@ -2099,18 +2335,23 @@ bool process_client_socket(socket_t sock, time_t read_timeout_sec,
|
|
|
2099
2335
|
time_t write_timeout_usec,
|
|
2100
2336
|
std::function<bool(Stream &)> callback);
|
|
2101
2337
|
|
|
2102
|
-
socket_t create_client_socket(
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2338
|
+
socket_t create_client_socket(const std::string &host, const std::string &ip,
|
|
2339
|
+
int port, int address_family, bool tcp_nodelay,
|
|
2340
|
+
bool ipv6_v6only, SocketOptions socket_options,
|
|
2341
|
+
time_t connection_timeout_sec,
|
|
2342
|
+
time_t connection_timeout_usec,
|
|
2343
|
+
time_t read_timeout_sec, time_t read_timeout_usec,
|
|
2344
|
+
time_t write_timeout_sec,
|
|
2345
|
+
time_t write_timeout_usec,
|
|
2346
|
+
const std::string &intf, Error &error);
|
|
2108
2347
|
|
|
2109
2348
|
const char *get_header_value(const Headers &headers, const std::string &key,
|
|
2110
|
-
|
|
2349
|
+
const char *def, size_t id);
|
|
2111
2350
|
|
|
2112
2351
|
std::string params_to_query_str(const Params ¶ms);
|
|
2113
2352
|
|
|
2353
|
+
void parse_query_text(const char *data, std::size_t size, Params ¶ms);
|
|
2354
|
+
|
|
2114
2355
|
void parse_query_text(const std::string &s, Params ¶ms);
|
|
2115
2356
|
|
|
2116
2357
|
bool parse_multipart_boundary(const std::string &content_type,
|
|
@@ -2270,15 +2511,70 @@ public:
|
|
|
2270
2511
|
|
|
2271
2512
|
private:
|
|
2272
2513
|
#if defined(_WIN32)
|
|
2273
|
-
HANDLE hFile_;
|
|
2274
|
-
HANDLE hMapping_;
|
|
2514
|
+
HANDLE hFile_ = NULL;
|
|
2515
|
+
HANDLE hMapping_ = NULL;
|
|
2275
2516
|
#else
|
|
2276
|
-
int fd_;
|
|
2517
|
+
int fd_ = -1;
|
|
2277
2518
|
#endif
|
|
2278
|
-
size_t size_;
|
|
2279
|
-
void *addr_;
|
|
2519
|
+
size_t size_ = 0;
|
|
2520
|
+
void *addr_ = nullptr;
|
|
2521
|
+
bool is_open_empty_file = false;
|
|
2280
2522
|
};
|
|
2281
2523
|
|
|
2524
|
+
// NOTE: https://www.rfc-editor.org/rfc/rfc9110#section-5
|
|
2525
|
+
namespace fields {
|
|
2526
|
+
|
|
2527
|
+
inline bool is_token_char(char c) {
|
|
2528
|
+
return std::isalnum(c) || c == '!' || c == '#' || c == '$' || c == '%' ||
|
|
2529
|
+
c == '&' || c == '\'' || c == '*' || c == '+' || c == '-' ||
|
|
2530
|
+
c == '.' || c == '^' || c == '_' || c == '`' || c == '|' || c == '~';
|
|
2531
|
+
}
|
|
2532
|
+
|
|
2533
|
+
inline bool is_token(const std::string &s) {
|
|
2534
|
+
if (s.empty()) { return false; }
|
|
2535
|
+
for (auto c : s) {
|
|
2536
|
+
if (!is_token_char(c)) { return false; }
|
|
2537
|
+
}
|
|
2538
|
+
return true;
|
|
2539
|
+
}
|
|
2540
|
+
|
|
2541
|
+
inline bool is_field_name(const std::string &s) { return is_token(s); }
|
|
2542
|
+
|
|
2543
|
+
inline bool is_vchar(char c) { return c >= 33 && c <= 126; }
|
|
2544
|
+
|
|
2545
|
+
inline bool is_obs_text(char c) { return 128 <= static_cast<unsigned char>(c); }
|
|
2546
|
+
|
|
2547
|
+
inline bool is_field_vchar(char c) { return is_vchar(c) || is_obs_text(c); }
|
|
2548
|
+
|
|
2549
|
+
inline bool is_field_content(const std::string &s) {
|
|
2550
|
+
if (s.empty()) { return false; }
|
|
2551
|
+
|
|
2552
|
+
if (s.size() == 1) {
|
|
2553
|
+
return is_field_vchar(s[0]);
|
|
2554
|
+
} else if (s.size() == 2) {
|
|
2555
|
+
return is_field_vchar(s[0]) && is_field_vchar(s[1]);
|
|
2556
|
+
} else {
|
|
2557
|
+
size_t i = 0;
|
|
2558
|
+
|
|
2559
|
+
if (!is_field_vchar(s[i])) { return false; }
|
|
2560
|
+
i++;
|
|
2561
|
+
|
|
2562
|
+
while (i < s.size() - 1) {
|
|
2563
|
+
auto c = s[i++];
|
|
2564
|
+
if (c == ' ' || c == '\t' || is_field_vchar(c)) {
|
|
2565
|
+
} else {
|
|
2566
|
+
return false;
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
return is_field_vchar(s[i]);
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
|
|
2574
|
+
inline bool is_field_value(const std::string &s) { return is_field_content(s); }
|
|
2575
|
+
|
|
2576
|
+
} // namespace fields
|
|
2577
|
+
|
|
2282
2578
|
} // namespace detail
|
|
2283
2579
|
|
|
2284
2580
|
// ----------------------------------------------------------------------------
|
|
@@ -2392,20 +2688,6 @@ inline std::string base64_encode(const std::string &in) {
|
|
|
2392
2688
|
return out;
|
|
2393
2689
|
}
|
|
2394
2690
|
|
|
2395
|
-
inline bool is_file(const std::string &path) {
|
|
2396
|
-
#ifdef _WIN32
|
|
2397
|
-
return _access_s(path.c_str(), 0) == 0;
|
|
2398
|
-
#else
|
|
2399
|
-
struct stat st;
|
|
2400
|
-
return stat(path.c_str(), &st) >= 0 && S_ISREG(st.st_mode);
|
|
2401
|
-
#endif
|
|
2402
|
-
}
|
|
2403
|
-
|
|
2404
|
-
inline bool is_dir(const std::string &path) {
|
|
2405
|
-
struct stat st;
|
|
2406
|
-
return stat(path.c_str(), &st) >= 0 && S_ISDIR(st.st_mode);
|
|
2407
|
-
}
|
|
2408
|
-
|
|
2409
2691
|
inline bool is_valid_path(const std::string &path) {
|
|
2410
2692
|
size_t level = 0;
|
|
2411
2693
|
size_t i = 0;
|
|
@@ -2448,6 +2730,21 @@ inline bool is_valid_path(const std::string &path) {
|
|
|
2448
2730
|
return true;
|
|
2449
2731
|
}
|
|
2450
2732
|
|
|
2733
|
+
inline FileStat::FileStat(const std::string &path) {
|
|
2734
|
+
#if defined(_WIN32)
|
|
2735
|
+
auto wpath = u8string_to_wstring(path.c_str());
|
|
2736
|
+
ret_ = _wstat(wpath.c_str(), &st_);
|
|
2737
|
+
#else
|
|
2738
|
+
ret_ = stat(path.c_str(), &st_);
|
|
2739
|
+
#endif
|
|
2740
|
+
}
|
|
2741
|
+
inline bool FileStat::is_file() const {
|
|
2742
|
+
return ret_ >= 0 && S_ISREG(st_.st_mode);
|
|
2743
|
+
}
|
|
2744
|
+
inline bool FileStat::is_dir() const {
|
|
2745
|
+
return ret_ >= 0 && S_ISDIR(st_.st_mode);
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2451
2748
|
inline std::string encode_query_param(const std::string &value) {
|
|
2452
2749
|
std::ostringstream escaped;
|
|
2453
2750
|
escaped.fill('0');
|
|
@@ -2579,6 +2876,27 @@ inline std::string trim_double_quotes_copy(const std::string &s) {
|
|
|
2579
2876
|
return s;
|
|
2580
2877
|
}
|
|
2581
2878
|
|
|
2879
|
+
inline void
|
|
2880
|
+
divide(const char *data, std::size_t size, char d,
|
|
2881
|
+
std::function<void(const char *, std::size_t, const char *, std::size_t)>
|
|
2882
|
+
fn) {
|
|
2883
|
+
const auto it = std::find(data, data + size, d);
|
|
2884
|
+
const auto found = static_cast<std::size_t>(it != data + size);
|
|
2885
|
+
const auto lhs_data = data;
|
|
2886
|
+
const auto lhs_size = static_cast<std::size_t>(it - data);
|
|
2887
|
+
const auto rhs_data = it + found;
|
|
2888
|
+
const auto rhs_size = size - lhs_size - found;
|
|
2889
|
+
|
|
2890
|
+
fn(lhs_data, lhs_size, rhs_data, rhs_size);
|
|
2891
|
+
}
|
|
2892
|
+
|
|
2893
|
+
inline void
|
|
2894
|
+
divide(const std::string &str, char d,
|
|
2895
|
+
std::function<void(const char *, std::size_t, const char *, std::size_t)>
|
|
2896
|
+
fn) {
|
|
2897
|
+
divide(str.data(), str.size(), d, std::move(fn));
|
|
2898
|
+
}
|
|
2899
|
+
|
|
2582
2900
|
inline void split(const char *b, const char *e, char d,
|
|
2583
2901
|
std::function<void(const char *, const char *)> fn) {
|
|
2584
2902
|
return split(b, e, d, (std::numeric_limits<size_t>::max)(), std::move(fn));
|
|
@@ -2636,6 +2954,10 @@ inline bool stream_line_reader::getline() {
|
|
|
2636
2954
|
fixed_buffer_used_size_ = 0;
|
|
2637
2955
|
glowable_buffer_.clear();
|
|
2638
2956
|
|
|
2957
|
+
#ifndef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
|
|
2958
|
+
char prev_byte = 0;
|
|
2959
|
+
#endif
|
|
2960
|
+
|
|
2639
2961
|
for (size_t i = 0;; i++) {
|
|
2640
2962
|
char byte;
|
|
2641
2963
|
auto n = strm_.read(&byte, 1);
|
|
@@ -2652,7 +2974,12 @@ inline bool stream_line_reader::getline() {
|
|
|
2652
2974
|
|
|
2653
2975
|
append(byte);
|
|
2654
2976
|
|
|
2977
|
+
#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
|
|
2655
2978
|
if (byte == '\n') { break; }
|
|
2979
|
+
#else
|
|
2980
|
+
if (prev_byte == '\r' && byte == '\n') { break; }
|
|
2981
|
+
prev_byte = byte;
|
|
2982
|
+
#endif
|
|
2656
2983
|
}
|
|
2657
2984
|
|
|
2658
2985
|
return true;
|
|
@@ -2671,16 +2998,7 @@ inline void stream_line_reader::append(char c) {
|
|
|
2671
2998
|
}
|
|
2672
2999
|
}
|
|
2673
3000
|
|
|
2674
|
-
inline mmap::mmap(const char *path)
|
|
2675
|
-
#if defined(_WIN32)
|
|
2676
|
-
: hFile_(NULL), hMapping_(NULL)
|
|
2677
|
-
#else
|
|
2678
|
-
: fd_(-1)
|
|
2679
|
-
#endif
|
|
2680
|
-
,
|
|
2681
|
-
size_(0), addr_(nullptr) {
|
|
2682
|
-
open(path);
|
|
2683
|
-
}
|
|
3001
|
+
inline mmap::mmap(const char *path) { open(path); }
|
|
2684
3002
|
|
|
2685
3003
|
inline mmap::~mmap() { close(); }
|
|
2686
3004
|
|
|
@@ -2688,29 +3006,60 @@ inline bool mmap::open(const char *path) {
|
|
|
2688
3006
|
close();
|
|
2689
3007
|
|
|
2690
3008
|
#if defined(_WIN32)
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
wpath += path[i];
|
|
2694
|
-
}
|
|
3009
|
+
auto wpath = u8string_to_wstring(path);
|
|
3010
|
+
if (wpath.empty()) { return false; }
|
|
2695
3011
|
|
|
3012
|
+
#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
|
|
2696
3013
|
hFile_ = ::CreateFile2(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ,
|
|
2697
3014
|
OPEN_EXISTING, NULL);
|
|
3015
|
+
#else
|
|
3016
|
+
hFile_ = ::CreateFileW(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
3017
|
+
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
3018
|
+
#endif
|
|
2698
3019
|
|
|
2699
3020
|
if (hFile_ == INVALID_HANDLE_VALUE) { return false; }
|
|
2700
3021
|
|
|
2701
3022
|
LARGE_INTEGER size{};
|
|
2702
3023
|
if (!::GetFileSizeEx(hFile_, &size)) { return false; }
|
|
3024
|
+
// If the following line doesn't compile due to QuadPart, update Windows SDK.
|
|
3025
|
+
// See:
|
|
3026
|
+
// https://github.com/yhirose/cpp-httplib/issues/1903#issuecomment-2316520721
|
|
3027
|
+
if (static_cast<ULONGLONG>(size.QuadPart) >
|
|
3028
|
+
(std::numeric_limits<decltype(size_)>::max)()) {
|
|
3029
|
+
// `size_t` might be 32-bits, on 32-bits Windows.
|
|
3030
|
+
return false;
|
|
3031
|
+
}
|
|
2703
3032
|
size_ = static_cast<size_t>(size.QuadPart);
|
|
2704
3033
|
|
|
3034
|
+
#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
|
|
2705
3035
|
hMapping_ =
|
|
2706
3036
|
::CreateFileMappingFromApp(hFile_, NULL, PAGE_READONLY, size_, NULL);
|
|
3037
|
+
#else
|
|
3038
|
+
hMapping_ = ::CreateFileMappingW(hFile_, NULL, PAGE_READONLY, 0, 0, NULL);
|
|
3039
|
+
#endif
|
|
3040
|
+
|
|
3041
|
+
// Special treatment for an empty file...
|
|
3042
|
+
if (hMapping_ == NULL && size_ == 0) {
|
|
3043
|
+
close();
|
|
3044
|
+
is_open_empty_file = true;
|
|
3045
|
+
return true;
|
|
3046
|
+
}
|
|
2707
3047
|
|
|
2708
3048
|
if (hMapping_ == NULL) {
|
|
2709
3049
|
close();
|
|
2710
3050
|
return false;
|
|
2711
3051
|
}
|
|
2712
3052
|
|
|
3053
|
+
#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
|
|
2713
3054
|
addr_ = ::MapViewOfFileFromApp(hMapping_, FILE_MAP_READ, 0, 0);
|
|
3055
|
+
#else
|
|
3056
|
+
addr_ = ::MapViewOfFile(hMapping_, FILE_MAP_READ, 0, 0, 0);
|
|
3057
|
+
#endif
|
|
3058
|
+
|
|
3059
|
+
if (addr_ == nullptr) {
|
|
3060
|
+
close();
|
|
3061
|
+
return false;
|
|
3062
|
+
}
|
|
2714
3063
|
#else
|
|
2715
3064
|
fd_ = ::open(path, O_RDONLY);
|
|
2716
3065
|
if (fd_ == -1) { return false; }
|
|
@@ -2723,22 +3072,26 @@ inline bool mmap::open(const char *path) {
|
|
|
2723
3072
|
size_ = static_cast<size_t>(sb.st_size);
|
|
2724
3073
|
|
|
2725
3074
|
addr_ = ::mmap(NULL, size_, PROT_READ, MAP_PRIVATE, fd_, 0);
|
|
2726
|
-
#endif
|
|
2727
3075
|
|
|
2728
|
-
|
|
3076
|
+
// Special treatment for an empty file...
|
|
3077
|
+
if (addr_ == MAP_FAILED && size_ == 0) {
|
|
2729
3078
|
close();
|
|
3079
|
+
is_open_empty_file = true;
|
|
2730
3080
|
return false;
|
|
2731
3081
|
}
|
|
3082
|
+
#endif
|
|
2732
3083
|
|
|
2733
3084
|
return true;
|
|
2734
3085
|
}
|
|
2735
3086
|
|
|
2736
|
-
inline bool mmap::is_open() const {
|
|
3087
|
+
inline bool mmap::is_open() const {
|
|
3088
|
+
return is_open_empty_file ? true : addr_ != nullptr;
|
|
3089
|
+
}
|
|
2737
3090
|
|
|
2738
3091
|
inline size_t mmap::size() const { return size_; }
|
|
2739
3092
|
|
|
2740
3093
|
inline const char *mmap::data() const {
|
|
2741
|
-
return static_cast<const char *>(addr_);
|
|
3094
|
+
return is_open_empty_file ? "" : static_cast<const char *>(addr_);
|
|
2742
3095
|
}
|
|
2743
3096
|
|
|
2744
3097
|
inline void mmap::close() {
|
|
@@ -2757,6 +3110,8 @@ inline void mmap::close() {
|
|
|
2757
3110
|
::CloseHandle(hFile_);
|
|
2758
3111
|
hFile_ = INVALID_HANDLE_VALUE;
|
|
2759
3112
|
}
|
|
3113
|
+
|
|
3114
|
+
is_open_empty_file = false;
|
|
2760
3115
|
#else
|
|
2761
3116
|
if (addr_ != nullptr) {
|
|
2762
3117
|
munmap(addr_, size_);
|
|
@@ -2782,7 +3137,10 @@ template <typename T> inline ssize_t handle_EINTR(T fn) {
|
|
|
2782
3137
|
ssize_t res = 0;
|
|
2783
3138
|
while (true) {
|
|
2784
3139
|
res = fn();
|
|
2785
|
-
if (res < 0 && errno == EINTR) {
|
|
3140
|
+
if (res < 0 && errno == EINTR) {
|
|
3141
|
+
std::this_thread::sleep_for(std::chrono::microseconds{1});
|
|
3142
|
+
continue;
|
|
3143
|
+
}
|
|
2786
3144
|
break;
|
|
2787
3145
|
}
|
|
2788
3146
|
return res;
|
|
@@ -2991,23 +3349,37 @@ private:
|
|
|
2991
3349
|
};
|
|
2992
3350
|
#endif
|
|
2993
3351
|
|
|
2994
|
-
inline bool keep_alive(socket_t
|
|
3352
|
+
inline bool keep_alive(const std::atomic<socket_t> &svr_sock, socket_t sock,
|
|
3353
|
+
time_t keep_alive_timeout_sec) {
|
|
2995
3354
|
using namespace std::chrono;
|
|
2996
|
-
|
|
3355
|
+
|
|
3356
|
+
const auto interval_usec =
|
|
3357
|
+
CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND;
|
|
3358
|
+
|
|
3359
|
+
// Avoid expensive `steady_clock::now()` call for the first time
|
|
3360
|
+
if (select_read(sock, 0, interval_usec) > 0) { return true; }
|
|
3361
|
+
|
|
3362
|
+
const auto start = steady_clock::now() - microseconds{interval_usec};
|
|
3363
|
+
const auto timeout = seconds{keep_alive_timeout_sec};
|
|
3364
|
+
|
|
2997
3365
|
while (true) {
|
|
2998
|
-
|
|
3366
|
+
if (svr_sock == INVALID_SOCKET) {
|
|
3367
|
+
break; // Server socket is closed
|
|
3368
|
+
}
|
|
3369
|
+
|
|
3370
|
+
auto val = select_read(sock, 0, interval_usec);
|
|
2999
3371
|
if (val < 0) {
|
|
3000
|
-
|
|
3372
|
+
break; // Ssocket error
|
|
3001
3373
|
} else if (val == 0) {
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
if (duration.count() > timeout) { return false; }
|
|
3006
|
-
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
3374
|
+
if (steady_clock::now() - start > timeout) {
|
|
3375
|
+
break; // Timeout
|
|
3376
|
+
}
|
|
3007
3377
|
} else {
|
|
3008
|
-
return true;
|
|
3378
|
+
return true; // Ready for read
|
|
3009
3379
|
}
|
|
3010
3380
|
}
|
|
3381
|
+
|
|
3382
|
+
return false;
|
|
3011
3383
|
}
|
|
3012
3384
|
|
|
3013
3385
|
template <typename T>
|
|
@@ -3018,8 +3390,7 @@ process_server_socket_core(const std::atomic<socket_t> &svr_sock, socket_t sock,
|
|
|
3018
3390
|
assert(keep_alive_max_count > 0);
|
|
3019
3391
|
auto ret = false;
|
|
3020
3392
|
auto count = keep_alive_max_count;
|
|
3021
|
-
while (
|
|
3022
|
-
keep_alive(sock, keep_alive_timeout_sec)) {
|
|
3393
|
+
while (count > 0 && keep_alive(svr_sock, sock, keep_alive_timeout_sec)) {
|
|
3023
3394
|
auto close_connection = count == 1;
|
|
3024
3395
|
auto connection_closed = false;
|
|
3025
3396
|
ret = callback(close_connection, connection_closed);
|
|
@@ -3063,10 +3434,29 @@ inline int shutdown_socket(socket_t sock) {
|
|
|
3063
3434
|
#endif
|
|
3064
3435
|
}
|
|
3065
3436
|
|
|
3437
|
+
inline std::string escape_abstract_namespace_unix_domain(const std::string &s) {
|
|
3438
|
+
if (s.size() > 1 && s[0] == '\0') {
|
|
3439
|
+
auto ret = s;
|
|
3440
|
+
ret[0] = '@';
|
|
3441
|
+
return ret;
|
|
3442
|
+
}
|
|
3443
|
+
return s;
|
|
3444
|
+
}
|
|
3445
|
+
|
|
3446
|
+
inline std::string
|
|
3447
|
+
unescape_abstract_namespace_unix_domain(const std::string &s) {
|
|
3448
|
+
if (s.size() > 1 && s[0] == '@') {
|
|
3449
|
+
auto ret = s;
|
|
3450
|
+
ret[0] = '\0';
|
|
3451
|
+
return ret;
|
|
3452
|
+
}
|
|
3453
|
+
return s;
|
|
3454
|
+
}
|
|
3455
|
+
|
|
3066
3456
|
template <typename BindOrConnect>
|
|
3067
3457
|
socket_t create_socket(const std::string &host, const std::string &ip, int port,
|
|
3068
3458
|
int address_family, int socket_flags, bool tcp_nodelay,
|
|
3069
|
-
SocketOptions socket_options,
|
|
3459
|
+
bool ipv6_v6only, SocketOptions socket_options,
|
|
3070
3460
|
BindOrConnect bind_or_connect) {
|
|
3071
3461
|
// Get address info
|
|
3072
3462
|
const char *node = nullptr;
|
|
@@ -3075,7 +3465,7 @@ socket_t create_socket(const std::string &host, const std::string &ip, int port,
|
|
|
3075
3465
|
|
|
3076
3466
|
memset(&hints, 0, sizeof(struct addrinfo));
|
|
3077
3467
|
hints.ai_socktype = SOCK_STREAM;
|
|
3078
|
-
hints.ai_protocol =
|
|
3468
|
+
hints.ai_protocol = IPPROTO_IP;
|
|
3079
3469
|
|
|
3080
3470
|
if (!ip.empty()) {
|
|
3081
3471
|
node = ip.c_str();
|
|
@@ -3093,20 +3483,32 @@ socket_t create_socket(const std::string &host, const std::string &ip, int port,
|
|
|
3093
3483
|
const auto addrlen = host.length();
|
|
3094
3484
|
if (addrlen > sizeof(sockaddr_un::sun_path)) { return INVALID_SOCKET; }
|
|
3095
3485
|
|
|
3486
|
+
#ifdef SOCK_CLOEXEC
|
|
3487
|
+
auto sock = socket(hints.ai_family, hints.ai_socktype | SOCK_CLOEXEC,
|
|
3488
|
+
hints.ai_protocol);
|
|
3489
|
+
#else
|
|
3096
3490
|
auto sock = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol);
|
|
3491
|
+
#endif
|
|
3492
|
+
|
|
3097
3493
|
if (sock != INVALID_SOCKET) {
|
|
3098
3494
|
sockaddr_un addr{};
|
|
3099
3495
|
addr.sun_family = AF_UNIX;
|
|
3100
|
-
|
|
3496
|
+
|
|
3497
|
+
auto unescaped_host = unescape_abstract_namespace_unix_domain(host);
|
|
3498
|
+
std::copy(unescaped_host.begin(), unescaped_host.end(), addr.sun_path);
|
|
3101
3499
|
|
|
3102
3500
|
hints.ai_addr = reinterpret_cast<sockaddr *>(&addr);
|
|
3103
3501
|
hints.ai_addrlen = static_cast<socklen_t>(
|
|
3104
3502
|
sizeof(addr) - sizeof(addr.sun_path) + addrlen);
|
|
3105
3503
|
|
|
3504
|
+
#ifndef SOCK_CLOEXEC
|
|
3106
3505
|
fcntl(sock, F_SETFD, FD_CLOEXEC);
|
|
3506
|
+
#endif
|
|
3507
|
+
|
|
3107
3508
|
if (socket_options) { socket_options(sock); }
|
|
3108
3509
|
|
|
3109
|
-
|
|
3510
|
+
bool dummy;
|
|
3511
|
+
if (!bind_or_connect(sock, hints, dummy)) {
|
|
3110
3512
|
close_socket(sock);
|
|
3111
3513
|
sock = INVALID_SOCKET;
|
|
3112
3514
|
}
|
|
@@ -3123,6 +3525,7 @@ socket_t create_socket(const std::string &host, const std::string &ip, int port,
|
|
|
3123
3525
|
#endif
|
|
3124
3526
|
return INVALID_SOCKET;
|
|
3125
3527
|
}
|
|
3528
|
+
auto se = detail::scope_exit([&] { freeaddrinfo(result); });
|
|
3126
3529
|
|
|
3127
3530
|
for (auto rp = result; rp; rp = rp->ai_next) {
|
|
3128
3531
|
// Create a socket
|
|
@@ -3148,11 +3551,18 @@ socket_t create_socket(const std::string &host, const std::string &ip, int port,
|
|
|
3148
3551
|
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
|
3149
3552
|
}
|
|
3150
3553
|
#else
|
|
3554
|
+
|
|
3555
|
+
#ifdef SOCK_CLOEXEC
|
|
3556
|
+
auto sock =
|
|
3557
|
+
socket(rp->ai_family, rp->ai_socktype | SOCK_CLOEXEC, rp->ai_protocol);
|
|
3558
|
+
#else
|
|
3151
3559
|
auto sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
|
3560
|
+
#endif
|
|
3561
|
+
|
|
3152
3562
|
#endif
|
|
3153
3563
|
if (sock == INVALID_SOCKET) { continue; }
|
|
3154
3564
|
|
|
3155
|
-
#
|
|
3565
|
+
#if !defined _WIN32 && !defined SOCK_CLOEXEC
|
|
3156
3566
|
if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) {
|
|
3157
3567
|
close_socket(sock);
|
|
3158
3568
|
continue;
|
|
@@ -3160,39 +3570,38 @@ socket_t create_socket(const std::string &host, const std::string &ip, int port,
|
|
|
3160
3570
|
#endif
|
|
3161
3571
|
|
|
3162
3572
|
if (tcp_nodelay) {
|
|
3163
|
-
auto
|
|
3573
|
+
auto opt = 1;
|
|
3164
3574
|
#ifdef _WIN32
|
|
3165
3575
|
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
|
|
3166
|
-
reinterpret_cast<const char *>(&
|
|
3576
|
+
reinterpret_cast<const char *>(&opt), sizeof(opt));
|
|
3167
3577
|
#else
|
|
3168
3578
|
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
|
|
3169
|
-
reinterpret_cast<const void *>(&
|
|
3579
|
+
reinterpret_cast<const void *>(&opt), sizeof(opt));
|
|
3170
3580
|
#endif
|
|
3171
3581
|
}
|
|
3172
3582
|
|
|
3173
|
-
if (socket_options) { socket_options(sock); }
|
|
3174
|
-
|
|
3175
3583
|
if (rp->ai_family == AF_INET6) {
|
|
3176
|
-
auto
|
|
3584
|
+
auto opt = ipv6_v6only ? 1 : 0;
|
|
3177
3585
|
#ifdef _WIN32
|
|
3178
3586
|
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
|
|
3179
|
-
reinterpret_cast<const char *>(&
|
|
3587
|
+
reinterpret_cast<const char *>(&opt), sizeof(opt));
|
|
3180
3588
|
#else
|
|
3181
3589
|
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
|
|
3182
|
-
reinterpret_cast<const void *>(&
|
|
3590
|
+
reinterpret_cast<const void *>(&opt), sizeof(opt));
|
|
3183
3591
|
#endif
|
|
3184
3592
|
}
|
|
3185
3593
|
|
|
3594
|
+
if (socket_options) { socket_options(sock); }
|
|
3595
|
+
|
|
3186
3596
|
// bind or connect
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
return sock;
|
|
3190
|
-
}
|
|
3597
|
+
auto quit = false;
|
|
3598
|
+
if (bind_or_connect(sock, *rp, quit)) { return sock; }
|
|
3191
3599
|
|
|
3192
3600
|
close_socket(sock);
|
|
3601
|
+
|
|
3602
|
+
if (quit) { break; }
|
|
3193
3603
|
}
|
|
3194
3604
|
|
|
3195
|
-
freeaddrinfo(result);
|
|
3196
3605
|
return INVALID_SOCKET;
|
|
3197
3606
|
}
|
|
3198
3607
|
|
|
@@ -3225,6 +3634,7 @@ inline bool bind_ip_address(socket_t sock, const std::string &host) {
|
|
|
3225
3634
|
hints.ai_protocol = 0;
|
|
3226
3635
|
|
|
3227
3636
|
if (getaddrinfo(host.c_str(), "0", &hints, &result)) { return false; }
|
|
3637
|
+
auto se = detail::scope_exit([&] { freeaddrinfo(result); });
|
|
3228
3638
|
|
|
3229
3639
|
auto ret = false;
|
|
3230
3640
|
for (auto rp = result; rp; rp = rp->ai_next) {
|
|
@@ -3235,7 +3645,6 @@ inline bool bind_ip_address(socket_t sock, const std::string &host) {
|
|
|
3235
3645
|
}
|
|
3236
3646
|
}
|
|
3237
3647
|
|
|
3238
|
-
freeaddrinfo(result);
|
|
3239
3648
|
return ret;
|
|
3240
3649
|
}
|
|
3241
3650
|
|
|
@@ -3247,6 +3656,8 @@ inline bool bind_ip_address(socket_t sock, const std::string &host) {
|
|
|
3247
3656
|
inline std::string if2ip(int address_family, const std::string &ifn) {
|
|
3248
3657
|
struct ifaddrs *ifap;
|
|
3249
3658
|
getifaddrs(&ifap);
|
|
3659
|
+
auto se = detail::scope_exit([&] { freeifaddrs(ifap); });
|
|
3660
|
+
|
|
3250
3661
|
std::string addr_candidate;
|
|
3251
3662
|
for (auto ifa = ifap; ifa; ifa = ifa->ifa_next) {
|
|
3252
3663
|
if (ifa->ifa_addr && ifn == ifa->ifa_name &&
|
|
@@ -3256,7 +3667,6 @@ inline std::string if2ip(int address_family, const std::string &ifn) {
|
|
|
3256
3667
|
auto sa = reinterpret_cast<struct sockaddr_in *>(ifa->ifa_addr);
|
|
3257
3668
|
char buf[INET_ADDRSTRLEN];
|
|
3258
3669
|
if (inet_ntop(AF_INET, &sa->sin_addr, buf, INET_ADDRSTRLEN)) {
|
|
3259
|
-
freeifaddrs(ifap);
|
|
3260
3670
|
return std::string(buf, INET_ADDRSTRLEN);
|
|
3261
3671
|
}
|
|
3262
3672
|
} else if (ifa->ifa_addr->sa_family == AF_INET6) {
|
|
@@ -3269,7 +3679,6 @@ inline std::string if2ip(int address_family, const std::string &ifn) {
|
|
|
3269
3679
|
if (s6_addr_head == 0xfc || s6_addr_head == 0xfd) {
|
|
3270
3680
|
addr_candidate = std::string(buf, INET6_ADDRSTRLEN);
|
|
3271
3681
|
} else {
|
|
3272
|
-
freeifaddrs(ifap);
|
|
3273
3682
|
return std::string(buf, INET6_ADDRSTRLEN);
|
|
3274
3683
|
}
|
|
3275
3684
|
}
|
|
@@ -3277,20 +3686,21 @@ inline std::string if2ip(int address_family, const std::string &ifn) {
|
|
|
3277
3686
|
}
|
|
3278
3687
|
}
|
|
3279
3688
|
}
|
|
3280
|
-
freeifaddrs(ifap);
|
|
3281
3689
|
return addr_candidate;
|
|
3282
3690
|
}
|
|
3283
3691
|
#endif
|
|
3284
3692
|
|
|
3285
3693
|
inline socket_t create_client_socket(
|
|
3286
3694
|
const std::string &host, const std::string &ip, int port,
|
|
3287
|
-
int address_family, bool tcp_nodelay,
|
|
3288
|
-
|
|
3289
|
-
time_t
|
|
3695
|
+
int address_family, bool tcp_nodelay, bool ipv6_v6only,
|
|
3696
|
+
SocketOptions socket_options, time_t connection_timeout_sec,
|
|
3697
|
+
time_t connection_timeout_usec, time_t read_timeout_sec,
|
|
3698
|
+
time_t read_timeout_usec, time_t write_timeout_sec,
|
|
3290
3699
|
time_t write_timeout_usec, const std::string &intf, Error &error) {
|
|
3291
3700
|
auto sock = create_socket(
|
|
3292
|
-
host, ip, port, address_family, 0, tcp_nodelay,
|
|
3293
|
-
|
|
3701
|
+
host, ip, port, address_family, 0, tcp_nodelay, ipv6_v6only,
|
|
3702
|
+
std::move(socket_options),
|
|
3703
|
+
[&](socket_t sock2, struct addrinfo &ai, bool &quit) -> bool {
|
|
3294
3704
|
if (!intf.empty()) {
|
|
3295
3705
|
#ifdef USE_IF2IP
|
|
3296
3706
|
auto ip_from_if = if2ip(address_family, intf);
|
|
@@ -3314,7 +3724,10 @@ inline socket_t create_client_socket(
|
|
|
3314
3724
|
}
|
|
3315
3725
|
error = wait_until_socket_is_ready(sock2, connection_timeout_sec,
|
|
3316
3726
|
connection_timeout_usec);
|
|
3317
|
-
if (error != Error::Success) {
|
|
3727
|
+
if (error != Error::Success) {
|
|
3728
|
+
if (error == Error::ConnectionTimeout) { quit = true; }
|
|
3729
|
+
return false;
|
|
3730
|
+
}
|
|
3318
3731
|
}
|
|
3319
3732
|
|
|
3320
3733
|
set_nonblocking(sock2, false);
|
|
@@ -3439,7 +3852,7 @@ inline unsigned int str2tag(const std::string &s) {
|
|
|
3439
3852
|
|
|
3440
3853
|
namespace udl {
|
|
3441
3854
|
|
|
3442
|
-
inline constexpr unsigned int operator""
|
|
3855
|
+
inline constexpr unsigned int operator""_t(const char *s, size_t l) {
|
|
3443
3856
|
return str2tag_core(s, l, 0);
|
|
3444
3857
|
}
|
|
3445
3858
|
|
|
@@ -3524,8 +3937,9 @@ inline bool can_compress_content_type(const std::string &content_type) {
|
|
|
3524
3937
|
case "application/protobuf"_t:
|
|
3525
3938
|
case "application/xhtml+xml"_t: return true;
|
|
3526
3939
|
|
|
3527
|
-
|
|
3528
|
-
|
|
3940
|
+
case "text/event-stream"_t: return false;
|
|
3941
|
+
|
|
3942
|
+
default: return !content_type.rfind("text/", 0);
|
|
3529
3943
|
}
|
|
3530
3944
|
}
|
|
3531
3945
|
|
|
@@ -3762,8 +4176,8 @@ inline bool has_header(const Headers &headers, const std::string &key) {
|
|
|
3762
4176
|
}
|
|
3763
4177
|
|
|
3764
4178
|
inline const char *get_header_value(const Headers &headers,
|
|
3765
|
-
const std::string &key,
|
|
3766
|
-
|
|
4179
|
+
const std::string &key, const char *def,
|
|
4180
|
+
size_t id) {
|
|
3767
4181
|
auto rng = headers.equal_range(key);
|
|
3768
4182
|
auto it = rng.first;
|
|
3769
4183
|
std::advance(it, static_cast<ssize_t>(id));
|
|
@@ -3771,14 +4185,6 @@ inline const char *get_header_value(const Headers &headers,
|
|
|
3771
4185
|
return def;
|
|
3772
4186
|
}
|
|
3773
4187
|
|
|
3774
|
-
inline bool compare_case_ignore(const std::string &a, const std::string &b) {
|
|
3775
|
-
if (a.size() != b.size()) { return false; }
|
|
3776
|
-
for (size_t i = 0; i < b.size(); i++) {
|
|
3777
|
-
if (::tolower(a[i]) != ::tolower(b[i])) { return false; }
|
|
3778
|
-
}
|
|
3779
|
-
return true;
|
|
3780
|
-
}
|
|
3781
|
-
|
|
3782
4188
|
template <typename T>
|
|
3783
4189
|
inline bool parse_header(const char *beg, const char *end, T fn) {
|
|
3784
4190
|
// Skip trailing spaces and tabs.
|
|
@@ -3801,15 +4207,27 @@ inline bool parse_header(const char *beg, const char *end, T fn) {
|
|
|
3801
4207
|
p++;
|
|
3802
4208
|
}
|
|
3803
4209
|
|
|
3804
|
-
if (p
|
|
4210
|
+
if (p <= end) {
|
|
3805
4211
|
auto key_len = key_end - beg;
|
|
3806
4212
|
if (!key_len) { return false; }
|
|
3807
4213
|
|
|
3808
4214
|
auto key = std::string(beg, key_end);
|
|
3809
|
-
auto val =
|
|
4215
|
+
auto val = case_ignore::equal(key, "Location")
|
|
3810
4216
|
? std::string(p, end)
|
|
3811
4217
|
: decode_url(std::string(p, end), false);
|
|
3812
|
-
|
|
4218
|
+
|
|
4219
|
+
// NOTE: From RFC 9110:
|
|
4220
|
+
// Field values containing CR, LF, or NUL characters are
|
|
4221
|
+
// invalid and dangerous, due to the varying ways that
|
|
4222
|
+
// implementations might parse and interpret those
|
|
4223
|
+
// characters; a recipient of CR, LF, or NUL within a field
|
|
4224
|
+
// value MUST either reject the message or replace each of
|
|
4225
|
+
// those characters with SP before further processing or
|
|
4226
|
+
// forwarding of that message.
|
|
4227
|
+
static const std::string CR_LF_NUL("\r\n\0", 3);
|
|
4228
|
+
if (val.find_first_of(CR_LF_NUL) != std::string::npos) { return false; }
|
|
4229
|
+
|
|
4230
|
+
fn(key, val);
|
|
3813
4231
|
return true;
|
|
3814
4232
|
}
|
|
3815
4233
|
|
|
@@ -3829,27 +4247,27 @@ inline bool read_headers(Stream &strm, Headers &headers) {
|
|
|
3829
4247
|
if (line_reader.end_with_crlf()) {
|
|
3830
4248
|
// Blank line indicates end of headers.
|
|
3831
4249
|
if (line_reader.size() == 2) { break; }
|
|
3832
|
-
#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
|
|
3833
4250
|
} else {
|
|
4251
|
+
#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
|
|
3834
4252
|
// Blank line indicates end of headers.
|
|
3835
4253
|
if (line_reader.size() == 1) { break; }
|
|
3836
4254
|
line_terminator_len = 1;
|
|
3837
|
-
}
|
|
3838
4255
|
#else
|
|
3839
|
-
} else {
|
|
3840
4256
|
continue; // Skip invalid line.
|
|
3841
|
-
}
|
|
3842
4257
|
#endif
|
|
4258
|
+
}
|
|
3843
4259
|
|
|
3844
4260
|
if (line_reader.size() > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; }
|
|
3845
4261
|
|
|
3846
4262
|
// Exclude line terminator
|
|
3847
4263
|
auto end = line_reader.ptr() + line_reader.size() - line_terminator_len;
|
|
3848
4264
|
|
|
3849
|
-
parse_header(line_reader.ptr(), end,
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
4265
|
+
if (!parse_header(line_reader.ptr(), end,
|
|
4266
|
+
[&](const std::string &key, std::string &val) {
|
|
4267
|
+
headers.emplace(key, val);
|
|
4268
|
+
})) {
|
|
4269
|
+
return false;
|
|
4270
|
+
}
|
|
3853
4271
|
}
|
|
3854
4272
|
|
|
3855
4273
|
return true;
|
|
@@ -3937,8 +4355,19 @@ inline bool read_content_chunked(Stream &strm, T &x,
|
|
|
3937
4355
|
|
|
3938
4356
|
assert(chunk_len == 0);
|
|
3939
4357
|
|
|
3940
|
-
//
|
|
3941
|
-
|
|
4358
|
+
// NOTE: In RFC 9112, '7.1 Chunked Transfer Coding' mentiones "The chunked
|
|
4359
|
+
// transfer coding is complete when a chunk with a chunk-size of zero is
|
|
4360
|
+
// received, possibly followed by a trailer section, and finally terminated by
|
|
4361
|
+
// an empty line". https://www.rfc-editor.org/rfc/rfc9112.html#section-7.1
|
|
4362
|
+
//
|
|
4363
|
+
// In '7.1.3. Decoding Chunked', however, the pseudo-code in the section
|
|
4364
|
+
// does't care for the existence of the final CRLF. In other words, it seems
|
|
4365
|
+
// to be ok whether the final CRLF exists or not in the chunked data.
|
|
4366
|
+
// https://www.rfc-editor.org/rfc/rfc9112.html#section-7.1.3
|
|
4367
|
+
//
|
|
4368
|
+
// According to the reference code in RFC 9112, cpp-htpplib now allows
|
|
4369
|
+
// chuncked transfer coding data without the final CRLF.
|
|
4370
|
+
if (!line_reader.getline()) { return true; }
|
|
3942
4371
|
|
|
3943
4372
|
while (strcmp(line_reader.ptr(), "\r\n") != 0) {
|
|
3944
4373
|
if (line_reader.size() > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; }
|
|
@@ -3948,8 +4377,8 @@ inline bool read_content_chunked(Stream &strm, T &x,
|
|
|
3948
4377
|
auto end = line_reader.ptr() + line_reader.size() - line_terminator_len;
|
|
3949
4378
|
|
|
3950
4379
|
parse_header(line_reader.ptr(), end,
|
|
3951
|
-
[&](std::string
|
|
3952
|
-
x.headers.emplace(
|
|
4380
|
+
[&](const std::string &key, const std::string &val) {
|
|
4381
|
+
x.headers.emplace(key, val);
|
|
3953
4382
|
});
|
|
3954
4383
|
|
|
3955
4384
|
if (!line_reader.getline()) { return false; }
|
|
@@ -3959,8 +4388,8 @@ inline bool read_content_chunked(Stream &strm, T &x,
|
|
|
3959
4388
|
}
|
|
3960
4389
|
|
|
3961
4390
|
inline bool is_chunked_transfer_encoding(const Headers &headers) {
|
|
3962
|
-
return
|
|
3963
|
-
get_header_value(headers, "Transfer-Encoding",
|
|
4391
|
+
return case_ignore::equal(
|
|
4392
|
+
get_header_value(headers, "Transfer-Encoding", "", 0), "chunked");
|
|
3964
4393
|
}
|
|
3965
4394
|
|
|
3966
4395
|
template <typename T, typename U>
|
|
@@ -4026,8 +4455,14 @@ bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status,
|
|
|
4026
4455
|
} else if (!has_header(x.headers, "Content-Length")) {
|
|
4027
4456
|
ret = read_content_without_length(strm, out);
|
|
4028
4457
|
} else {
|
|
4029
|
-
auto
|
|
4030
|
-
|
|
4458
|
+
auto is_invalid_value = false;
|
|
4459
|
+
auto len = get_header_value_u64(x.headers, "Content-Length",
|
|
4460
|
+
std::numeric_limits<uint64_t>::max(),
|
|
4461
|
+
0, is_invalid_value);
|
|
4462
|
+
|
|
4463
|
+
if (is_invalid_value) {
|
|
4464
|
+
ret = false;
|
|
4465
|
+
} else if (len > payload_max_length) {
|
|
4031
4466
|
exceed_payload_max_length = true;
|
|
4032
4467
|
skip_content_with_length(strm, len);
|
|
4033
4468
|
ret = false;
|
|
@@ -4042,13 +4477,36 @@ bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status,
|
|
|
4042
4477
|
}
|
|
4043
4478
|
return ret;
|
|
4044
4479
|
});
|
|
4045
|
-
}
|
|
4480
|
+
}
|
|
4481
|
+
|
|
4482
|
+
inline ssize_t write_request_line(Stream &strm, const std::string &method,
|
|
4483
|
+
const std::string &path) {
|
|
4484
|
+
std::string s = method;
|
|
4485
|
+
s += " ";
|
|
4486
|
+
s += path;
|
|
4487
|
+
s += " HTTP/1.1\r\n";
|
|
4488
|
+
return strm.write(s.data(), s.size());
|
|
4489
|
+
}
|
|
4490
|
+
|
|
4491
|
+
inline ssize_t write_response_line(Stream &strm, int status) {
|
|
4492
|
+
std::string s = "HTTP/1.1 ";
|
|
4493
|
+
s += std::to_string(status);
|
|
4494
|
+
s += " ";
|
|
4495
|
+
s += httplib::status_message(status);
|
|
4496
|
+
s += "\r\n";
|
|
4497
|
+
return strm.write(s.data(), s.size());
|
|
4498
|
+
}
|
|
4046
4499
|
|
|
4047
4500
|
inline ssize_t write_headers(Stream &strm, const Headers &headers) {
|
|
4048
4501
|
ssize_t write_len = 0;
|
|
4049
4502
|
for (const auto &x : headers) {
|
|
4050
|
-
|
|
4051
|
-
|
|
4503
|
+
std::string s;
|
|
4504
|
+
s = x.first;
|
|
4505
|
+
s += ": ";
|
|
4506
|
+
s += x.second;
|
|
4507
|
+
s += "\r\n";
|
|
4508
|
+
|
|
4509
|
+
auto len = strm.write(s.data(), s.size());
|
|
4052
4510
|
if (len < 0) { return len; }
|
|
4053
4511
|
write_len += len;
|
|
4054
4512
|
}
|
|
@@ -4302,22 +4760,22 @@ inline std::string params_to_query_str(const Params ¶ms) {
|
|
|
4302
4760
|
return query;
|
|
4303
4761
|
}
|
|
4304
4762
|
|
|
4305
|
-
inline void parse_query_text(const std::
|
|
4763
|
+
inline void parse_query_text(const char *data, std::size_t size,
|
|
4764
|
+
Params ¶ms) {
|
|
4306
4765
|
std::set<std::string> cache;
|
|
4307
|
-
split(
|
|
4766
|
+
split(data, data + size, '&', [&](const char *b, const char *e) {
|
|
4308
4767
|
std::string kv(b, e);
|
|
4309
4768
|
if (cache.find(kv) != cache.end()) { return; }
|
|
4310
|
-
cache.insert(kv);
|
|
4769
|
+
cache.insert(std::move(kv));
|
|
4311
4770
|
|
|
4312
4771
|
std::string key;
|
|
4313
4772
|
std::string val;
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
});
|
|
4773
|
+
divide(b, static_cast<std::size_t>(e - b), '=',
|
|
4774
|
+
[&](const char *lhs_data, std::size_t lhs_size, const char *rhs_data,
|
|
4775
|
+
std::size_t rhs_size) {
|
|
4776
|
+
key.assign(lhs_data, lhs_size);
|
|
4777
|
+
val.assign(rhs_data, rhs_size);
|
|
4778
|
+
});
|
|
4321
4779
|
|
|
4322
4780
|
if (!key.empty()) {
|
|
4323
4781
|
params.emplace(decode_url(key, true), decode_url(val, true));
|
|
@@ -4325,6 +4783,10 @@ inline void parse_query_text(const std::string &s, Params ¶ms) {
|
|
|
4325
4783
|
});
|
|
4326
4784
|
}
|
|
4327
4785
|
|
|
4786
|
+
inline void parse_query_text(const std::string &s, Params ¶ms) {
|
|
4787
|
+
parse_query_text(s.data(), s.size(), params);
|
|
4788
|
+
}
|
|
4789
|
+
|
|
4328
4790
|
inline bool parse_multipart_boundary(const std::string &content_type,
|
|
4329
4791
|
std::string &boundary) {
|
|
4330
4792
|
auto boundary_keyword = "boundary=";
|
|
@@ -4365,35 +4827,44 @@ inline bool parse_range_header(const std::string &s, Ranges &ranges) {
|
|
|
4365
4827
|
#else
|
|
4366
4828
|
inline bool parse_range_header(const std::string &s, Ranges &ranges) try {
|
|
4367
4829
|
#endif
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4830
|
+
auto is_valid = [](const std::string &str) {
|
|
4831
|
+
return std::all_of(str.cbegin(), str.cend(),
|
|
4832
|
+
[](unsigned char c) { return std::isdigit(c); });
|
|
4833
|
+
};
|
|
4834
|
+
|
|
4835
|
+
if (s.size() > 7 && s.compare(0, 6, "bytes=") == 0) {
|
|
4836
|
+
const auto pos = static_cast<size_t>(6);
|
|
4837
|
+
const auto len = static_cast<size_t>(s.size() - 6);
|
|
4373
4838
|
auto all_valid_ranges = true;
|
|
4374
4839
|
split(&s[pos], &s[pos + len], ',', [&](const char *b, const char *e) {
|
|
4375
4840
|
if (!all_valid_ranges) { return; }
|
|
4376
|
-
static auto re_another_range = std::regex(R"(\s*(\d*)-(\d*))");
|
|
4377
|
-
std::cmatch cm;
|
|
4378
|
-
if (std::regex_match(b, e, cm, re_another_range)) {
|
|
4379
|
-
ssize_t first = -1;
|
|
4380
|
-
if (!cm.str(1).empty()) {
|
|
4381
|
-
first = static_cast<ssize_t>(std::stoll(cm.str(1)));
|
|
4382
|
-
}
|
|
4383
4841
|
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4842
|
+
const auto it = std::find(b, e, '-');
|
|
4843
|
+
if (it == e) {
|
|
4844
|
+
all_valid_ranges = false;
|
|
4845
|
+
return;
|
|
4846
|
+
}
|
|
4847
|
+
|
|
4848
|
+
const auto lhs = std::string(b, it);
|
|
4849
|
+
const auto rhs = std::string(it + 1, e);
|
|
4850
|
+
if (!is_valid(lhs) || !is_valid(rhs)) {
|
|
4851
|
+
all_valid_ranges = false;
|
|
4852
|
+
return;
|
|
4853
|
+
}
|
|
4388
4854
|
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4855
|
+
const auto first =
|
|
4856
|
+
static_cast<ssize_t>(lhs.empty() ? -1 : std::stoll(lhs));
|
|
4857
|
+
const auto last =
|
|
4858
|
+
static_cast<ssize_t>(rhs.empty() ? -1 : std::stoll(rhs));
|
|
4859
|
+
if ((first == -1 && last == -1) ||
|
|
4860
|
+
(first != -1 && last != -1 && first > last)) {
|
|
4861
|
+
all_valid_ranges = false;
|
|
4862
|
+
return;
|
|
4394
4863
|
}
|
|
4864
|
+
|
|
4865
|
+
ranges.emplace_back(first, last);
|
|
4395
4866
|
});
|
|
4396
|
-
return all_valid_ranges;
|
|
4867
|
+
return all_valid_ranges && !ranges.empty();
|
|
4397
4868
|
}
|
|
4398
4869
|
return false;
|
|
4399
4870
|
#ifdef CPPHTTPLIB_NO_EXCEPTIONS
|
|
@@ -4452,7 +4923,7 @@ public:
|
|
|
4452
4923
|
const auto header = buf_head(pos);
|
|
4453
4924
|
|
|
4454
4925
|
if (!parse_header(header.data(), header.data() + header.size(),
|
|
4455
|
-
[&](std::string
|
|
4926
|
+
[&](const std::string &, const std::string &) {})) {
|
|
4456
4927
|
is_valid_ = false;
|
|
4457
4928
|
return false;
|
|
4458
4929
|
}
|
|
@@ -4562,7 +5033,9 @@ private:
|
|
|
4562
5033
|
const std::string &b) const {
|
|
4563
5034
|
if (a.size() < b.size()) { return false; }
|
|
4564
5035
|
for (size_t i = 0; i < b.size(); i++) {
|
|
4565
|
-
if (::
|
|
5036
|
+
if (case_ignore::to_lower(a[i]) != case_ignore::to_lower(b[i])) {
|
|
5037
|
+
return false;
|
|
5038
|
+
}
|
|
4566
5039
|
}
|
|
4567
5040
|
return true;
|
|
4568
5041
|
}
|
|
@@ -4645,16 +5118,6 @@ private:
|
|
|
4645
5118
|
size_t buf_epos_ = 0;
|
|
4646
5119
|
};
|
|
4647
5120
|
|
|
4648
|
-
inline std::string to_lower(const char *beg, const char *end) {
|
|
4649
|
-
std::string out;
|
|
4650
|
-
auto it = beg;
|
|
4651
|
-
while (it != end) {
|
|
4652
|
-
out += static_cast<char>(::tolower(*it));
|
|
4653
|
-
it++;
|
|
4654
|
-
}
|
|
4655
|
-
return out;
|
|
4656
|
-
}
|
|
4657
|
-
|
|
4658
5121
|
inline std::string random_string(size_t length) {
|
|
4659
5122
|
static const char data[] =
|
|
4660
5123
|
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
@@ -4768,7 +5231,18 @@ inline bool range_error(Request &req, Response &res) {
|
|
|
4768
5231
|
last_pos = contant_len - 1;
|
|
4769
5232
|
}
|
|
4770
5233
|
|
|
4771
|
-
|
|
5234
|
+
// NOTE: RFC-9110 '14.1.2. Byte Ranges':
|
|
5235
|
+
// A client can limit the number of bytes requested without knowing the
|
|
5236
|
+
// size of the selected representation. If the last-pos value is absent,
|
|
5237
|
+
// or if the value is greater than or equal to the current length of the
|
|
5238
|
+
// representation data, the byte range is interpreted as the remainder of
|
|
5239
|
+
// the representation (i.e., the server replaces the value of last-pos
|
|
5240
|
+
// with a value that is one less than the current length of the selected
|
|
5241
|
+
// representation).
|
|
5242
|
+
// https://www.rfc-editor.org/rfc/rfc9110.html#section-14.1.2-6
|
|
5243
|
+
if (last_pos == -1 || last_pos >= contant_len) {
|
|
5244
|
+
last_pos = contant_len - 1;
|
|
5245
|
+
}
|
|
4772
5246
|
|
|
4773
5247
|
// Range must be within content length
|
|
4774
5248
|
if (!(0 <= first_pos && first_pos <= last_pos &&
|
|
@@ -4795,12 +5269,11 @@ inline bool range_error(Request &req, Response &res) {
|
|
|
4795
5269
|
|
|
4796
5270
|
inline std::pair<size_t, size_t>
|
|
4797
5271
|
get_range_offset_and_length(Range r, size_t content_length) {
|
|
4798
|
-
(void)(content_length); // patch to get rid of "unused parameter" on release build
|
|
4799
5272
|
assert(r.first != -1 && r.second != -1);
|
|
4800
5273
|
assert(0 <= r.first && r.first < static_cast<ssize_t>(content_length));
|
|
4801
5274
|
assert(r.first <= r.second &&
|
|
4802
5275
|
r.second < static_cast<ssize_t>(content_length));
|
|
4803
|
-
|
|
5276
|
+
(void)(content_length);
|
|
4804
5277
|
return std::make_pair(r.first, static_cast<size_t>(r.second - r.first) + 1);
|
|
4805
5278
|
}
|
|
4806
5279
|
|
|
@@ -5230,6 +5703,7 @@ inline void hosted_at(const std::string &hostname,
|
|
|
5230
5703
|
#endif
|
|
5231
5704
|
return;
|
|
5232
5705
|
}
|
|
5706
|
+
auto se = detail::scope_exit([&] { freeaddrinfo(result); });
|
|
5233
5707
|
|
|
5234
5708
|
for (auto rp = result; rp; rp = rp->ai_next) {
|
|
5235
5709
|
const auto &addr =
|
|
@@ -5241,8 +5715,6 @@ inline void hosted_at(const std::string &hostname,
|
|
|
5241
5715
|
addrs.push_back(ip);
|
|
5242
5716
|
}
|
|
5243
5717
|
}
|
|
5244
|
-
|
|
5245
|
-
freeaddrinfo(result);
|
|
5246
5718
|
}
|
|
5247
5719
|
|
|
5248
5720
|
inline std::string append_query_params(const std::string &path,
|
|
@@ -5291,8 +5763,8 @@ inline bool Request::has_header(const std::string &key) const {
|
|
|
5291
5763
|
}
|
|
5292
5764
|
|
|
5293
5765
|
inline std::string Request::get_header_value(const std::string &key,
|
|
5294
|
-
size_t id) const {
|
|
5295
|
-
return detail::get_header_value(headers, key,
|
|
5766
|
+
const char *def, size_t id) const {
|
|
5767
|
+
return detail::get_header_value(headers, key, def, id);
|
|
5296
5768
|
}
|
|
5297
5769
|
|
|
5298
5770
|
inline size_t Request::get_header_value_count(const std::string &key) const {
|
|
@@ -5302,7 +5774,8 @@ inline size_t Request::get_header_value_count(const std::string &key) const {
|
|
|
5302
5774
|
|
|
5303
5775
|
inline void Request::set_header(const std::string &key,
|
|
5304
5776
|
const std::string &val) {
|
|
5305
|
-
if (
|
|
5777
|
+
if (detail::fields::is_field_name(key) &&
|
|
5778
|
+
detail::fields::is_field_value(val)) {
|
|
5306
5779
|
headers.emplace(key, val);
|
|
5307
5780
|
}
|
|
5308
5781
|
}
|
|
@@ -5356,8 +5829,9 @@ inline bool Response::has_header(const std::string &key) const {
|
|
|
5356
5829
|
}
|
|
5357
5830
|
|
|
5358
5831
|
inline std::string Response::get_header_value(const std::string &key,
|
|
5832
|
+
const char *def,
|
|
5359
5833
|
size_t id) const {
|
|
5360
|
-
return detail::get_header_value(headers, key,
|
|
5834
|
+
return detail::get_header_value(headers, key, def, id);
|
|
5361
5835
|
}
|
|
5362
5836
|
|
|
5363
5837
|
inline size_t Response::get_header_value_count(const std::string &key) const {
|
|
@@ -5367,13 +5841,14 @@ inline size_t Response::get_header_value_count(const std::string &key) const {
|
|
|
5367
5841
|
|
|
5368
5842
|
inline void Response::set_header(const std::string &key,
|
|
5369
5843
|
const std::string &val) {
|
|
5370
|
-
if (
|
|
5844
|
+
if (detail::fields::is_field_name(key) &&
|
|
5845
|
+
detail::fields::is_field_value(val)) {
|
|
5371
5846
|
headers.emplace(key, val);
|
|
5372
5847
|
}
|
|
5373
5848
|
}
|
|
5374
5849
|
|
|
5375
5850
|
inline void Response::set_redirect(const std::string &url, int stat) {
|
|
5376
|
-
if (
|
|
5851
|
+
if (detail::fields::is_field_value(url)) {
|
|
5377
5852
|
set_header("Location", url);
|
|
5378
5853
|
if (300 <= stat && stat < 400) {
|
|
5379
5854
|
this->status = stat;
|
|
@@ -5436,14 +5911,25 @@ inline void Response::set_chunked_content_provider(
|
|
|
5436
5911
|
is_chunked_content_provider_ = true;
|
|
5437
5912
|
}
|
|
5438
5913
|
|
|
5914
|
+
inline void Response::set_file_content(const std::string &path,
|
|
5915
|
+
const std::string &content_type) {
|
|
5916
|
+
file_content_path_ = path;
|
|
5917
|
+
file_content_content_type_ = content_type;
|
|
5918
|
+
}
|
|
5919
|
+
|
|
5920
|
+
inline void Response::set_file_content(const std::string &path) {
|
|
5921
|
+
file_content_path_ = path;
|
|
5922
|
+
}
|
|
5923
|
+
|
|
5439
5924
|
// Result implementation
|
|
5440
5925
|
inline bool Result::has_request_header(const std::string &key) const {
|
|
5441
5926
|
return request_headers_.find(key) != request_headers_.end();
|
|
5442
5927
|
}
|
|
5443
5928
|
|
|
5444
5929
|
inline std::string Result::get_request_header_value(const std::string &key,
|
|
5930
|
+
const char *def,
|
|
5445
5931
|
size_t id) const {
|
|
5446
|
-
return detail::get_header_value(request_headers_, key,
|
|
5932
|
+
return detail::get_header_value(request_headers_, key, def, id);
|
|
5447
5933
|
}
|
|
5448
5934
|
|
|
5449
5935
|
inline size_t
|
|
@@ -5584,6 +6070,8 @@ inline socket_t BufferStream::socket() const { return 0; }
|
|
|
5584
6070
|
inline const std::string &BufferStream::get_buffer() const { return buffer; }
|
|
5585
6071
|
|
|
5586
6072
|
inline PathParamsMatcher::PathParamsMatcher(const std::string &pattern) {
|
|
6073
|
+
static constexpr char marker[] = "/:";
|
|
6074
|
+
|
|
5587
6075
|
// One past the last ending position of a path param substring
|
|
5588
6076
|
std::size_t last_param_end = 0;
|
|
5589
6077
|
|
|
@@ -5596,13 +6084,14 @@ inline PathParamsMatcher::PathParamsMatcher(const std::string &pattern) {
|
|
|
5596
6084
|
#endif
|
|
5597
6085
|
|
|
5598
6086
|
while (true) {
|
|
5599
|
-
const auto marker_pos = pattern.find(
|
|
6087
|
+
const auto marker_pos = pattern.find(
|
|
6088
|
+
marker, last_param_end == 0 ? last_param_end : last_param_end - 1);
|
|
5600
6089
|
if (marker_pos == std::string::npos) { break; }
|
|
5601
6090
|
|
|
5602
6091
|
static_fragments_.push_back(
|
|
5603
|
-
pattern.substr(last_param_end, marker_pos - last_param_end));
|
|
6092
|
+
pattern.substr(last_param_end, marker_pos - last_param_end + 1));
|
|
5604
6093
|
|
|
5605
|
-
const auto param_name_start = marker_pos +
|
|
6094
|
+
const auto param_name_start = marker_pos + 2;
|
|
5606
6095
|
|
|
5607
6096
|
auto sep_pos = pattern.find(separator, param_name_start);
|
|
5608
6097
|
if (sep_pos == std::string::npos) { sep_pos = pattern.length(); }
|
|
@@ -5664,7 +6153,7 @@ inline bool PathParamsMatcher::match(Request &request) const {
|
|
|
5664
6153
|
request.path_params.emplace(
|
|
5665
6154
|
param_name, request.path.substr(starting_pos, sep_pos - starting_pos));
|
|
5666
6155
|
|
|
5667
|
-
// Mark
|
|
6156
|
+
// Mark everything up to '/' as matched
|
|
5668
6157
|
starting_pos = sep_pos + 1;
|
|
5669
6158
|
}
|
|
5670
6159
|
// Returns false if the path is longer than the pattern
|
|
@@ -5763,7 +6252,8 @@ inline bool Server::set_base_dir(const std::string &dir,
|
|
|
5763
6252
|
|
|
5764
6253
|
inline bool Server::set_mount_point(const std::string &mount_point,
|
|
5765
6254
|
const std::string &dir, Headers headers) {
|
|
5766
|
-
|
|
6255
|
+
detail::FileStat stat(dir);
|
|
6256
|
+
if (stat.is_dir()) {
|
|
5767
6257
|
std::string mnt = !mount_point.empty() ? mount_point : "/";
|
|
5768
6258
|
if (!mnt.empty() && mnt[0] == '/') {
|
|
5769
6259
|
base_dirs_.push_back({mnt, dir, std::move(headers)});
|
|
@@ -5800,12 +6290,14 @@ inline Server &Server::set_file_request_handler(Handler handler) {
|
|
|
5800
6290
|
return *this;
|
|
5801
6291
|
}
|
|
5802
6292
|
|
|
5803
|
-
inline Server &Server::
|
|
6293
|
+
inline Server &Server::set_error_handler_core(HandlerWithResponse handler,
|
|
6294
|
+
std::true_type) {
|
|
5804
6295
|
error_handler_ = std::move(handler);
|
|
5805
6296
|
return *this;
|
|
5806
6297
|
}
|
|
5807
6298
|
|
|
5808
|
-
inline Server &Server::
|
|
6299
|
+
inline Server &Server::set_error_handler_core(Handler handler,
|
|
6300
|
+
std::false_type) {
|
|
5809
6301
|
error_handler_ = [handler](const Request &req, Response &res) {
|
|
5810
6302
|
handler(req, res);
|
|
5811
6303
|
return HandlerResponse::Handled;
|
|
@@ -5849,6 +6341,11 @@ inline Server &Server::set_tcp_nodelay(bool on) {
|
|
|
5849
6341
|
return *this;
|
|
5850
6342
|
}
|
|
5851
6343
|
|
|
6344
|
+
inline Server &Server::set_ipv6_v6only(bool on) {
|
|
6345
|
+
ipv6_v6only_ = on;
|
|
6346
|
+
return *this;
|
|
6347
|
+
}
|
|
6348
|
+
|
|
5852
6349
|
inline Server &Server::set_socket_options(SocketOptions socket_options) {
|
|
5853
6350
|
socket_options_ = std::move(socket_options);
|
|
5854
6351
|
return *this;
|
|
@@ -5900,27 +6397,27 @@ inline Server &Server::set_payload_max_length(size_t length) {
|
|
|
5900
6397
|
|
|
5901
6398
|
inline bool Server::bind_to_port(const std::string &host, int port,
|
|
5902
6399
|
int socket_flags) {
|
|
5903
|
-
|
|
6400
|
+
auto ret = bind_internal(host, port, socket_flags);
|
|
6401
|
+
if (ret == -1) { is_decommisioned = true; }
|
|
6402
|
+
return ret >= 0;
|
|
5904
6403
|
}
|
|
5905
6404
|
inline int Server::bind_to_any_port(const std::string &host, int socket_flags) {
|
|
5906
|
-
|
|
6405
|
+
auto ret = bind_internal(host, 0, socket_flags);
|
|
6406
|
+
if (ret == -1) { is_decommisioned = true; }
|
|
6407
|
+
return ret;
|
|
5907
6408
|
}
|
|
5908
6409
|
|
|
5909
|
-
inline bool Server::listen_after_bind() {
|
|
5910
|
-
auto se = detail::scope_exit([&]() { done_ = true; });
|
|
5911
|
-
return listen_internal();
|
|
5912
|
-
}
|
|
6410
|
+
inline bool Server::listen_after_bind() { return listen_internal(); }
|
|
5913
6411
|
|
|
5914
6412
|
inline bool Server::listen(const std::string &host, int port,
|
|
5915
6413
|
int socket_flags) {
|
|
5916
|
-
auto se = detail::scope_exit([&]() { done_ = true; });
|
|
5917
6414
|
return bind_to_port(host, port, socket_flags) && listen_internal();
|
|
5918
6415
|
}
|
|
5919
6416
|
|
|
5920
6417
|
inline bool Server::is_running() const { return is_running_; }
|
|
5921
6418
|
|
|
5922
6419
|
inline void Server::wait_until_ready() const {
|
|
5923
|
-
while (!
|
|
6420
|
+
while (!is_running_ && !is_decommisioned) {
|
|
5924
6421
|
std::this_thread::sleep_for(std::chrono::milliseconds{1});
|
|
5925
6422
|
}
|
|
5926
6423
|
}
|
|
@@ -5932,8 +6429,11 @@ inline void Server::stop() {
|
|
|
5932
6429
|
detail::shutdown_socket(sock);
|
|
5933
6430
|
detail::close_socket(sock);
|
|
5934
6431
|
}
|
|
6432
|
+
is_decommisioned = false;
|
|
5935
6433
|
}
|
|
5936
6434
|
|
|
6435
|
+
inline void Server::decommission() { is_decommisioned = true; }
|
|
6436
|
+
|
|
5937
6437
|
inline bool Server::parse_request_line(const char *s, Request &req) const {
|
|
5938
6438
|
auto len = strlen(s);
|
|
5939
6439
|
if (len < 2 || s[len - 2] != '\r' || s[len - 1] != '\n') { return false; }
|
|
@@ -5972,26 +6472,13 @@ inline bool Server::parse_request_line(const char *s, Request &req) const {
|
|
|
5972
6472
|
}
|
|
5973
6473
|
}
|
|
5974
6474
|
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
break;
|
|
5983
|
-
case 1: {
|
|
5984
|
-
if (e - b > 0) {
|
|
5985
|
-
detail::parse_query_text(std::string(b, e), req.params);
|
|
5986
|
-
}
|
|
5987
|
-
break;
|
|
5988
|
-
}
|
|
5989
|
-
default: break;
|
|
5990
|
-
}
|
|
5991
|
-
count++;
|
|
5992
|
-
});
|
|
5993
|
-
|
|
5994
|
-
if (count > 2) { return false; }
|
|
6475
|
+
detail::divide(req.target, '?',
|
|
6476
|
+
[&](const char *lhs_data, std::size_t lhs_size,
|
|
6477
|
+
const char *rhs_data, std::size_t rhs_size) {
|
|
6478
|
+
req.path = detail::decode_url(
|
|
6479
|
+
std::string(lhs_data, lhs_size), false);
|
|
6480
|
+
detail::parse_query_text(rhs_data, rhs_size, req.params);
|
|
6481
|
+
});
|
|
5995
6482
|
}
|
|
5996
6483
|
|
|
5997
6484
|
return true;
|
|
@@ -6030,23 +6517,24 @@ inline bool Server::write_response_core(Stream &strm, bool close_connection,
|
|
|
6030
6517
|
if (close_connection || req.get_header_value("Connection") == "close") {
|
|
6031
6518
|
res.set_header("Connection", "close");
|
|
6032
6519
|
} else {
|
|
6033
|
-
std::
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6520
|
+
std::string s = "timeout=";
|
|
6521
|
+
s += std::to_string(keep_alive_timeout_sec_);
|
|
6522
|
+
s += ", max=";
|
|
6523
|
+
s += std::to_string(keep_alive_max_count_);
|
|
6524
|
+
res.set_header("Keep-Alive", s);
|
|
6037
6525
|
}
|
|
6038
6526
|
|
|
6039
|
-
if (!res.
|
|
6040
|
-
|
|
6527
|
+
if ((!res.body.empty() || res.content_length_ > 0 || res.content_provider_) &&
|
|
6528
|
+
!res.has_header("Content-Type")) {
|
|
6041
6529
|
res.set_header("Content-Type", "text/plain");
|
|
6042
6530
|
}
|
|
6043
6531
|
|
|
6044
|
-
if (
|
|
6045
|
-
!res.
|
|
6532
|
+
if (res.body.empty() && !res.content_length_ && !res.content_provider_ &&
|
|
6533
|
+
!res.has_header("Content-Length")) {
|
|
6046
6534
|
res.set_header("Content-Length", "0");
|
|
6047
6535
|
}
|
|
6048
6536
|
|
|
6049
|
-
if (!res.has_header("Accept-Ranges")
|
|
6537
|
+
if (req.method == "HEAD" && !res.has_header("Accept-Ranges")) {
|
|
6050
6538
|
res.set_header("Accept-Ranges", "bytes");
|
|
6051
6539
|
}
|
|
6052
6540
|
|
|
@@ -6055,12 +6543,7 @@ inline bool Server::write_response_core(Stream &strm, bool close_connection,
|
|
|
6055
6543
|
// Response line and headers
|
|
6056
6544
|
{
|
|
6057
6545
|
detail::BufferStream bstrm;
|
|
6058
|
-
|
|
6059
|
-
if (!bstrm.write_format("HTTP/1.1 %d %s\r\n", res.status,
|
|
6060
|
-
status_message(res.status))) {
|
|
6061
|
-
return false;
|
|
6062
|
-
}
|
|
6063
|
-
|
|
6546
|
+
if (!detail::write_response_line(bstrm, res.status)) { return false; }
|
|
6064
6547
|
if (!header_writer_(bstrm, res.headers)) { return false; }
|
|
6065
6548
|
|
|
6066
6549
|
// Flush buffer
|
|
@@ -6254,7 +6737,14 @@ inline bool Server::handle_file_request(const Request &req, Response &res,
|
|
|
6254
6737
|
auto path = entry.base_dir + sub_path;
|
|
6255
6738
|
if (path.back() == '/') { path += "index.html"; }
|
|
6256
6739
|
|
|
6257
|
-
|
|
6740
|
+
detail::FileStat stat(path);
|
|
6741
|
+
|
|
6742
|
+
if (stat.is_dir()) {
|
|
6743
|
+
res.set_redirect(sub_path + "/", StatusCode::MovedPermanently_301);
|
|
6744
|
+
return true;
|
|
6745
|
+
}
|
|
6746
|
+
|
|
6747
|
+
if (stat.is_file()) {
|
|
6258
6748
|
for (const auto &kv : entry.headers) {
|
|
6259
6749
|
res.set_header(kv.first, kv.second);
|
|
6260
6750
|
}
|
|
@@ -6289,8 +6779,8 @@ Server::create_server_socket(const std::string &host, int port,
|
|
|
6289
6779
|
SocketOptions socket_options) const {
|
|
6290
6780
|
return detail::create_socket(
|
|
6291
6781
|
host, std::string(), port, address_family_, socket_flags, tcp_nodelay_,
|
|
6292
|
-
std::move(socket_options),
|
|
6293
|
-
[](socket_t sock, struct addrinfo &ai) -> bool {
|
|
6782
|
+
ipv6_v6only_, std::move(socket_options),
|
|
6783
|
+
[](socket_t sock, struct addrinfo &ai, bool & /*quit*/) -> bool {
|
|
6294
6784
|
if (::bind(sock, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen))) {
|
|
6295
6785
|
return false;
|
|
6296
6786
|
}
|
|
@@ -6301,6 +6791,8 @@ Server::create_server_socket(const std::string &host, int port,
|
|
|
6301
6791
|
|
|
6302
6792
|
inline int Server::bind_internal(const std::string &host, int port,
|
|
6303
6793
|
int socket_flags) {
|
|
6794
|
+
if (is_decommisioned) { return -1; }
|
|
6795
|
+
|
|
6304
6796
|
if (!is_valid()) { return -1; }
|
|
6305
6797
|
|
|
6306
6798
|
svr_sock_ = create_server_socket(host, port, socket_flags, socket_options_);
|
|
@@ -6326,6 +6818,8 @@ inline int Server::bind_internal(const std::string &host, int port,
|
|
|
6326
6818
|
}
|
|
6327
6819
|
|
|
6328
6820
|
inline bool Server::listen_internal() {
|
|
6821
|
+
if (is_decommisioned) { return false; }
|
|
6822
|
+
|
|
6329
6823
|
auto ret = true;
|
|
6330
6824
|
is_running_ = true;
|
|
6331
6825
|
auto se = detail::scope_exit([&]() { is_running_ = false; });
|
|
@@ -6346,13 +6840,22 @@ inline bool Server::listen_internal() {
|
|
|
6346
6840
|
#ifndef _WIN32
|
|
6347
6841
|
}
|
|
6348
6842
|
#endif
|
|
6843
|
+
|
|
6844
|
+
#if defined _WIN32
|
|
6845
|
+
// sockets conneced via WASAccept inherit flags NO_HANDLE_INHERIT,
|
|
6846
|
+
// OVERLAPPED
|
|
6847
|
+
socket_t sock = WSAAccept(svr_sock_, nullptr, nullptr, nullptr, 0);
|
|
6848
|
+
#elif defined SOCK_CLOEXEC
|
|
6849
|
+
socket_t sock = accept4(svr_sock_, nullptr, nullptr, SOCK_CLOEXEC);
|
|
6850
|
+
#else
|
|
6349
6851
|
socket_t sock = accept(svr_sock_, nullptr, nullptr);
|
|
6852
|
+
#endif
|
|
6350
6853
|
|
|
6351
6854
|
if (sock == INVALID_SOCKET) {
|
|
6352
6855
|
if (errno == EMFILE) {
|
|
6353
6856
|
// The per-process limit of open file descriptors has been reached.
|
|
6354
6857
|
// Try to accept new connections after a short sleep.
|
|
6355
|
-
std::this_thread::sleep_for(std::chrono::
|
|
6858
|
+
std::this_thread::sleep_for(std::chrono::microseconds{1});
|
|
6356
6859
|
continue;
|
|
6357
6860
|
} else if (errno == EINTR || errno == EAGAIN) {
|
|
6358
6861
|
continue;
|
|
@@ -6406,6 +6909,7 @@ inline bool Server::listen_internal() {
|
|
|
6406
6909
|
task_queue->shutdown();
|
|
6407
6910
|
}
|
|
6408
6911
|
|
|
6912
|
+
is_decommisioned = !ret;
|
|
6409
6913
|
return ret;
|
|
6410
6914
|
}
|
|
6411
6915
|
|
|
@@ -6503,7 +7007,7 @@ inline bool Server::dispatch_request(Request &req, Response &res,
|
|
|
6503
7007
|
inline void Server::apply_ranges(const Request &req, Response &res,
|
|
6504
7008
|
std::string &content_type,
|
|
6505
7009
|
std::string &boundary) const {
|
|
6506
|
-
if (req.ranges.size() > 1) {
|
|
7010
|
+
if (req.ranges.size() > 1 && res.status == StatusCode::PartialContent_206) {
|
|
6507
7011
|
auto it = res.headers.find("Content-Type");
|
|
6508
7012
|
if (it != res.headers.end()) {
|
|
6509
7013
|
content_type = it->second;
|
|
@@ -6521,7 +7025,7 @@ inline void Server::apply_ranges(const Request &req, Response &res,
|
|
|
6521
7025
|
if (res.body.empty()) {
|
|
6522
7026
|
if (res.content_length_ > 0) {
|
|
6523
7027
|
size_t length = 0;
|
|
6524
|
-
if (req.ranges.empty()) {
|
|
7028
|
+
if (req.ranges.empty() || res.status != StatusCode::PartialContent_206) {
|
|
6525
7029
|
length = res.content_length_;
|
|
6526
7030
|
} else if (req.ranges.size() == 1) {
|
|
6527
7031
|
auto offset_and_length = detail::get_range_offset_and_length(
|
|
@@ -6550,7 +7054,7 @@ inline void Server::apply_ranges(const Request &req, Response &res,
|
|
|
6550
7054
|
}
|
|
6551
7055
|
}
|
|
6552
7056
|
} else {
|
|
6553
|
-
if (req.ranges.empty()) {
|
|
7057
|
+
if (req.ranges.empty() || res.status != StatusCode::PartialContent_206) {
|
|
6554
7058
|
;
|
|
6555
7059
|
} else if (req.ranges.size() == 1) {
|
|
6556
7060
|
auto offset_and_length =
|
|
@@ -6621,7 +7125,9 @@ inline bool Server::dispatch_request_for_content_reader(
|
|
|
6621
7125
|
}
|
|
6622
7126
|
|
|
6623
7127
|
inline bool
|
|
6624
|
-
Server::process_request(Stream &strm,
|
|
7128
|
+
Server::process_request(Stream &strm, const std::string &remote_addr,
|
|
7129
|
+
int remote_port, const std::string &local_addr,
|
|
7130
|
+
int local_port, bool close_connection,
|
|
6625
7131
|
bool &connection_closed,
|
|
6626
7132
|
const std::function<void(Request &)> &setup_request) {
|
|
6627
7133
|
std::array<char, 2048> buf{};
|
|
@@ -6675,11 +7181,13 @@ Server::process_request(Stream &strm, bool close_connection,
|
|
|
6675
7181
|
connection_closed = true;
|
|
6676
7182
|
}
|
|
6677
7183
|
|
|
6678
|
-
|
|
7184
|
+
req.remote_addr = remote_addr;
|
|
7185
|
+
req.remote_port = remote_port;
|
|
6679
7186
|
req.set_header("REMOTE_ADDR", req.remote_addr);
|
|
6680
7187
|
req.set_header("REMOTE_PORT", std::to_string(req.remote_port));
|
|
6681
7188
|
|
|
6682
|
-
|
|
7189
|
+
req.local_addr = local_addr;
|
|
7190
|
+
req.local_port = local_port;
|
|
6683
7191
|
req.set_header("LOCAL_ADDR", req.local_addr);
|
|
6684
7192
|
req.set_header("LOCAL_PORT", std::to_string(req.local_port));
|
|
6685
7193
|
|
|
@@ -6701,13 +7209,20 @@ Server::process_request(Stream &strm, bool close_connection,
|
|
|
6701
7209
|
switch (status) {
|
|
6702
7210
|
case StatusCode::Continue_100:
|
|
6703
7211
|
case StatusCode::ExpectationFailed_417:
|
|
6704
|
-
strm
|
|
6705
|
-
|
|
7212
|
+
detail::write_response_line(strm, status);
|
|
7213
|
+
strm.write("\r\n");
|
|
6706
7214
|
break;
|
|
6707
|
-
default:
|
|
7215
|
+
default:
|
|
7216
|
+
connection_closed = true;
|
|
7217
|
+
return write_response(strm, true, req, res);
|
|
6708
7218
|
}
|
|
6709
7219
|
}
|
|
6710
7220
|
|
|
7221
|
+
// Setup `is_connection_closed` method
|
|
7222
|
+
req.is_connection_closed = [&]() {
|
|
7223
|
+
return !detail::is_socket_alive(strm.socket());
|
|
7224
|
+
};
|
|
7225
|
+
|
|
6711
7226
|
// Routing
|
|
6712
7227
|
auto routed = false;
|
|
6713
7228
|
#ifdef CPPHTTPLIB_NO_EXCEPTIONS
|
|
@@ -6750,6 +7265,32 @@ Server::process_request(Stream &strm, bool close_connection,
|
|
|
6750
7265
|
: StatusCode::PartialContent_206;
|
|
6751
7266
|
}
|
|
6752
7267
|
|
|
7268
|
+
// Serve file content by using a content provider
|
|
7269
|
+
if (!res.file_content_path_.empty()) {
|
|
7270
|
+
const auto &path = res.file_content_path_;
|
|
7271
|
+
auto mm = std::make_shared<detail::mmap>(path.c_str());
|
|
7272
|
+
if (!mm->is_open()) {
|
|
7273
|
+
res.body.clear();
|
|
7274
|
+
res.content_length_ = 0;
|
|
7275
|
+
res.content_provider_ = nullptr;
|
|
7276
|
+
res.status = StatusCode::NotFound_404;
|
|
7277
|
+
return write_response(strm, close_connection, req, res);
|
|
7278
|
+
}
|
|
7279
|
+
|
|
7280
|
+
auto content_type = res.file_content_content_type_;
|
|
7281
|
+
if (content_type.empty()) {
|
|
7282
|
+
content_type = detail::find_content_type(
|
|
7283
|
+
path, file_extension_and_mimetype_map_, default_file_mimetype_);
|
|
7284
|
+
}
|
|
7285
|
+
|
|
7286
|
+
res.set_content_provider(
|
|
7287
|
+
mm->size(), content_type,
|
|
7288
|
+
[mm](size_t offset, size_t length, DataSink &sink) -> bool {
|
|
7289
|
+
sink.write(mm->data() + offset, length);
|
|
7290
|
+
return true;
|
|
7291
|
+
});
|
|
7292
|
+
}
|
|
7293
|
+
|
|
6753
7294
|
if (detail::range_error(req, res)) {
|
|
6754
7295
|
res.body.clear();
|
|
6755
7296
|
res.content_length_ = 0;
|
|
@@ -6769,12 +7310,21 @@ Server::process_request(Stream &strm, bool close_connection,
|
|
|
6769
7310
|
inline bool Server::is_valid() const { return true; }
|
|
6770
7311
|
|
|
6771
7312
|
inline bool Server::process_and_close_socket(socket_t sock) {
|
|
7313
|
+
std::string remote_addr;
|
|
7314
|
+
int remote_port = 0;
|
|
7315
|
+
detail::get_remote_ip_and_port(sock, remote_addr, remote_port);
|
|
7316
|
+
|
|
7317
|
+
std::string local_addr;
|
|
7318
|
+
int local_port = 0;
|
|
7319
|
+
detail::get_local_ip_and_port(sock, local_addr, local_port);
|
|
7320
|
+
|
|
6772
7321
|
auto ret = detail::process_server_socket(
|
|
6773
7322
|
svr_sock_, sock, keep_alive_max_count_, keep_alive_timeout_sec_,
|
|
6774
7323
|
read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
|
|
6775
7324
|
write_timeout_usec_,
|
|
6776
|
-
[
|
|
6777
|
-
return process_request(strm,
|
|
7325
|
+
[&](Stream &strm, bool close_connection, bool &connection_closed) {
|
|
7326
|
+
return process_request(strm, remote_addr, remote_port, local_addr,
|
|
7327
|
+
local_port, close_connection, connection_closed,
|
|
6778
7328
|
nullptr);
|
|
6779
7329
|
});
|
|
6780
7330
|
|
|
@@ -6793,8 +7343,8 @@ inline ClientImpl::ClientImpl(const std::string &host, int port)
|
|
|
6793
7343
|
inline ClientImpl::ClientImpl(const std::string &host, int port,
|
|
6794
7344
|
const std::string &client_cert_path,
|
|
6795
7345
|
const std::string &client_key_path)
|
|
6796
|
-
: host_(host), port_(port),
|
|
6797
|
-
host_and_port_(adjust_host_string(
|
|
7346
|
+
: host_(detail::escape_abstract_namespace_unix_domain(host)), port_(port),
|
|
7347
|
+
host_and_port_(adjust_host_string(host_) + ":" + std::to_string(port)),
|
|
6798
7348
|
client_cert_path_(client_cert_path), client_key_path_(client_key_path) {}
|
|
6799
7349
|
|
|
6800
7350
|
inline ClientImpl::~ClientImpl() {
|
|
@@ -6825,6 +7375,7 @@ inline void ClientImpl::copy_settings(const ClientImpl &rhs) {
|
|
|
6825
7375
|
url_encode_ = rhs.url_encode_;
|
|
6826
7376
|
address_family_ = rhs.address_family_;
|
|
6827
7377
|
tcp_nodelay_ = rhs.tcp_nodelay_;
|
|
7378
|
+
ipv6_v6only_ = rhs.ipv6_v6only_;
|
|
6828
7379
|
socket_options_ = rhs.socket_options_;
|
|
6829
7380
|
compress_ = rhs.compress_;
|
|
6830
7381
|
decompress_ = rhs.decompress_;
|
|
@@ -6845,6 +7396,8 @@ inline void ClientImpl::copy_settings(const ClientImpl &rhs) {
|
|
|
6845
7396
|
#endif
|
|
6846
7397
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
|
6847
7398
|
server_certificate_verification_ = rhs.server_certificate_verification_;
|
|
7399
|
+
server_hostname_verification_ = rhs.server_hostname_verification_;
|
|
7400
|
+
server_certificate_verifier_ = rhs.server_certificate_verifier_;
|
|
6848
7401
|
#endif
|
|
6849
7402
|
logger_ = rhs.logger_;
|
|
6850
7403
|
}
|
|
@@ -6853,9 +7406,9 @@ inline socket_t ClientImpl::create_client_socket(Error &error) const {
|
|
|
6853
7406
|
if (!proxy_host_.empty() && proxy_port_ != -1) {
|
|
6854
7407
|
return detail::create_client_socket(
|
|
6855
7408
|
proxy_host_, std::string(), proxy_port_, address_family_, tcp_nodelay_,
|
|
6856
|
-
socket_options_, connection_timeout_sec_,
|
|
6857
|
-
read_timeout_sec_, read_timeout_usec_,
|
|
6858
|
-
write_timeout_usec_, interface_, error);
|
|
7409
|
+
ipv6_v6only_, socket_options_, connection_timeout_sec_,
|
|
7410
|
+
connection_timeout_usec_, read_timeout_sec_, read_timeout_usec_,
|
|
7411
|
+
write_timeout_sec_, write_timeout_usec_, interface_, error);
|
|
6859
7412
|
}
|
|
6860
7413
|
|
|
6861
7414
|
// Check is custom IP specified for host_
|
|
@@ -6864,10 +7417,10 @@ inline socket_t ClientImpl::create_client_socket(Error &error) const {
|
|
|
6864
7417
|
if (it != addr_map_.end()) { ip = it->second; }
|
|
6865
7418
|
|
|
6866
7419
|
return detail::create_client_socket(
|
|
6867
|
-
host_, ip, port_, address_family_, tcp_nodelay_,
|
|
6868
|
-
connection_timeout_sec_, connection_timeout_usec_,
|
|
6869
|
-
read_timeout_usec_, write_timeout_sec_,
|
|
6870
|
-
error);
|
|
7420
|
+
host_, ip, port_, address_family_, tcp_nodelay_, ipv6_v6only_,
|
|
7421
|
+
socket_options_, connection_timeout_sec_, connection_timeout_usec_,
|
|
7422
|
+
read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
|
|
7423
|
+
write_timeout_usec_, interface_, error);
|
|
6871
7424
|
}
|
|
6872
7425
|
|
|
6873
7426
|
inline bool ClientImpl::create_and_connect_socket(Socket &socket,
|
|
@@ -6956,6 +7509,18 @@ inline bool ClientImpl::send(Request &req, Response &res, Error &error) {
|
|
|
6956
7509
|
return ret;
|
|
6957
7510
|
}
|
|
6958
7511
|
|
|
7512
|
+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
|
7513
|
+
inline bool ClientImpl::is_ssl_peer_could_be_closed(SSL *ssl) const {
|
|
7514
|
+
detail::set_nonblocking(socket_.sock, true);
|
|
7515
|
+
auto se = detail::scope_exit(
|
|
7516
|
+
[&]() { detail::set_nonblocking(socket_.sock, false); });
|
|
7517
|
+
|
|
7518
|
+
char buf[1];
|
|
7519
|
+
return !SSL_peek(ssl, buf, 1) &&
|
|
7520
|
+
SSL_get_error(ssl, 0) == SSL_ERROR_ZERO_RETURN;
|
|
7521
|
+
}
|
|
7522
|
+
#endif
|
|
7523
|
+
|
|
6959
7524
|
inline bool ClientImpl::send_(Request &req, Response &res, Error &error) {
|
|
6960
7525
|
{
|
|
6961
7526
|
std::lock_guard<std::mutex> guard(socket_mutex_);
|
|
@@ -6967,6 +7532,13 @@ inline bool ClientImpl::send_(Request &req, Response &res, Error &error) {
|
|
|
6967
7532
|
auto is_alive = false;
|
|
6968
7533
|
if (socket_.is_open()) {
|
|
6969
7534
|
is_alive = detail::is_socket_alive(socket_.sock);
|
|
7535
|
+
|
|
7536
|
+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
|
7537
|
+
if (is_alive && is_ssl()) {
|
|
7538
|
+
if (is_ssl_peer_could_be_closed(socket_.ssl)) { is_alive = false; }
|
|
7539
|
+
}
|
|
7540
|
+
#endif
|
|
7541
|
+
|
|
6970
7542
|
if (!is_alive) {
|
|
6971
7543
|
// Attempt to avoid sigpipe by shutting down nongracefully if it seems
|
|
6972
7544
|
// like the other side has already closed the connection Also, there
|
|
@@ -7144,7 +7716,7 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
|
|
|
7144
7716
|
if (location.empty()) { return false; }
|
|
7145
7717
|
|
|
7146
7718
|
const static std::regex re(
|
|
7147
|
-
R"((?:(https?):)?(?://(?:\[([\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)");
|
|
7719
|
+
R"((?:(https?):)?(?://(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)");
|
|
7148
7720
|
|
|
7149
7721
|
std::smatch m;
|
|
7150
7722
|
if (!std::regex_match(location, m, re)) { return false; }
|
|
@@ -7243,12 +7815,26 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req,
|
|
|
7243
7815
|
|
|
7244
7816
|
if (!req.has_header("Accept")) { req.set_header("Accept", "*/*"); }
|
|
7245
7817
|
|
|
7818
|
+
if (!req.content_receiver) {
|
|
7819
|
+
if (!req.has_header("Accept-Encoding")) {
|
|
7820
|
+
std::string accept_encoding;
|
|
7821
|
+
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
|
7822
|
+
accept_encoding = "br";
|
|
7823
|
+
#endif
|
|
7824
|
+
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
|
7825
|
+
if (!accept_encoding.empty()) { accept_encoding += ", "; }
|
|
7826
|
+
accept_encoding += "gzip, deflate";
|
|
7827
|
+
#endif
|
|
7828
|
+
req.set_header("Accept-Encoding", accept_encoding);
|
|
7829
|
+
}
|
|
7830
|
+
|
|
7246
7831
|
#ifndef CPPHTTPLIB_NO_DEFAULT_USER_AGENT
|
|
7247
|
-
|
|
7248
|
-
|
|
7249
|
-
|
|
7250
|
-
|
|
7832
|
+
if (!req.has_header("User-Agent")) {
|
|
7833
|
+
auto agent = std::string("cpp-httplib/") + CPPHTTPLIB_VERSION;
|
|
7834
|
+
req.set_header("User-Agent", agent);
|
|
7835
|
+
}
|
|
7251
7836
|
#endif
|
|
7837
|
+
};
|
|
7252
7838
|
|
|
7253
7839
|
if (req.body.empty()) {
|
|
7254
7840
|
if (req.content_provider_) {
|
|
@@ -7308,8 +7894,14 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req,
|
|
|
7308
7894
|
{
|
|
7309
7895
|
detail::BufferStream bstrm;
|
|
7310
7896
|
|
|
7311
|
-
const auto &
|
|
7312
|
-
|
|
7897
|
+
const auto &path_with_query =
|
|
7898
|
+
req.params.empty() ? req.path
|
|
7899
|
+
: append_query_params(req.path, req.params);
|
|
7900
|
+
|
|
7901
|
+
const auto &path =
|
|
7902
|
+
url_encode_ ? detail::encode_url(path_with_query) : path_with_query;
|
|
7903
|
+
|
|
7904
|
+
detail::write_request_line(bstrm, req.method, path);
|
|
7313
7905
|
|
|
7314
7906
|
header_writer_(bstrm, req.headers);
|
|
7315
7907
|
|
|
@@ -7417,11 +8009,12 @@ inline Result ClientImpl::send_with_content_provider(
|
|
|
7417
8009
|
const std::string &method, const std::string &path, const Headers &headers,
|
|
7418
8010
|
const char *body, size_t content_length, ContentProvider content_provider,
|
|
7419
8011
|
ContentProviderWithoutLength content_provider_without_length,
|
|
7420
|
-
const std::string &content_type) {
|
|
8012
|
+
const std::string &content_type, Progress progress) {
|
|
7421
8013
|
Request req;
|
|
7422
8014
|
req.method = method;
|
|
7423
8015
|
req.headers = headers;
|
|
7424
8016
|
req.path = path;
|
|
8017
|
+
req.progress = progress;
|
|
7425
8018
|
|
|
7426
8019
|
auto error = Error::Success;
|
|
7427
8020
|
|
|
@@ -7448,9 +8041,7 @@ inline bool ClientImpl::process_request(Stream &strm, Request &req,
|
|
|
7448
8041
|
if (is_ssl()) {
|
|
7449
8042
|
auto is_proxy_enabled = !proxy_host_.empty() && proxy_port_ != -1;
|
|
7450
8043
|
if (!is_proxy_enabled) {
|
|
7451
|
-
|
|
7452
|
-
if (SSL_peek(socket_.ssl, buf, 1) == 0 &&
|
|
7453
|
-
SSL_get_error(socket_.ssl, 0) == SSL_ERROR_ZERO_RETURN) {
|
|
8044
|
+
if (is_ssl_peer_could_be_closed(socket_.ssl)) {
|
|
7454
8045
|
error = Error::SSLPeerCouldBeClosed_;
|
|
7455
8046
|
return false;
|
|
7456
8047
|
}
|
|
@@ -7468,7 +8059,9 @@ inline bool ClientImpl::process_request(Stream &strm, Request &req,
|
|
|
7468
8059
|
// Body
|
|
7469
8060
|
if ((res.status != StatusCode::NoContent_204) && req.method != "HEAD" &&
|
|
7470
8061
|
req.method != "CONNECT") {
|
|
7471
|
-
auto redirect = 300 < res.status && res.status < 400 &&
|
|
8062
|
+
auto redirect = 300 < res.status && res.status < 400 &&
|
|
8063
|
+
res.status != StatusCode::NotModified_304 &&
|
|
8064
|
+
follow_location_;
|
|
7472
8065
|
|
|
7473
8066
|
if (req.response_handler && !redirect) {
|
|
7474
8067
|
if (!req.response_handler(res)) {
|
|
@@ -7489,9 +8082,7 @@ inline bool ClientImpl::process_request(Stream &strm, Request &req,
|
|
|
7489
8082
|
: static_cast<ContentReceiverWithProgress>(
|
|
7490
8083
|
[&](const char *buf, size_t n, uint64_t /*off*/,
|
|
7491
8084
|
uint64_t /*len*/) {
|
|
7492
|
-
|
|
7493
|
-
return false;
|
|
7494
|
-
}
|
|
8085
|
+
assert(res.body.size() + n <= res.body.max_size());
|
|
7495
8086
|
res.body.append(buf, n);
|
|
7496
8087
|
return true;
|
|
7497
8088
|
});
|
|
@@ -7503,12 +8094,25 @@ inline bool ClientImpl::process_request(Stream &strm, Request &req,
|
|
|
7503
8094
|
return ret;
|
|
7504
8095
|
};
|
|
7505
8096
|
|
|
7506
|
-
|
|
7507
|
-
|
|
7508
|
-
|
|
7509
|
-
|
|
7510
|
-
|
|
7511
|
-
|
|
8097
|
+
if (res.has_header("Content-Length")) {
|
|
8098
|
+
if (!req.content_receiver) {
|
|
8099
|
+
auto len = res.get_header_value_u64("Content-Length");
|
|
8100
|
+
if (len > res.body.max_size()) {
|
|
8101
|
+
error = Error::Read;
|
|
8102
|
+
return false;
|
|
8103
|
+
}
|
|
8104
|
+
res.body.reserve(static_cast<size_t>(len));
|
|
8105
|
+
}
|
|
8106
|
+
}
|
|
8107
|
+
|
|
8108
|
+
if (res.status != StatusCode::NotModified_304) {
|
|
8109
|
+
int dummy_status;
|
|
8110
|
+
if (!detail::read_content(strm, res, (std::numeric_limits<size_t>::max)(),
|
|
8111
|
+
dummy_status, std::move(progress),
|
|
8112
|
+
std::move(out), decompress_)) {
|
|
8113
|
+
if (error != Error::Canceled) { error = Error::Read; }
|
|
8114
|
+
return false;
|
|
8115
|
+
}
|
|
7512
8116
|
}
|
|
7513
8117
|
}
|
|
7514
8118
|
|
|
@@ -7717,14 +8321,22 @@ inline Result ClientImpl::Post(const std::string &path,
|
|
|
7717
8321
|
inline Result ClientImpl::Post(const std::string &path, const char *body,
|
|
7718
8322
|
size_t content_length,
|
|
7719
8323
|
const std::string &content_type) {
|
|
7720
|
-
return Post(path, Headers(), body, content_length, content_type);
|
|
8324
|
+
return Post(path, Headers(), body, content_length, content_type, nullptr);
|
|
7721
8325
|
}
|
|
7722
8326
|
|
|
7723
8327
|
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
|
|
7724
8328
|
const char *body, size_t content_length,
|
|
7725
8329
|
const std::string &content_type) {
|
|
7726
8330
|
return send_with_content_provider("POST", path, headers, body, content_length,
|
|
7727
|
-
nullptr, nullptr, content_type);
|
|
8331
|
+
nullptr, nullptr, content_type, nullptr);
|
|
8332
|
+
}
|
|
8333
|
+
|
|
8334
|
+
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
|
|
8335
|
+
const char *body, size_t content_length,
|
|
8336
|
+
const std::string &content_type,
|
|
8337
|
+
Progress progress) {
|
|
8338
|
+
return send_with_content_provider("POST", path, headers, body, content_length,
|
|
8339
|
+
nullptr, nullptr, content_type, progress);
|
|
7728
8340
|
}
|
|
7729
8341
|
|
|
7730
8342
|
inline Result ClientImpl::Post(const std::string &path, const std::string &body,
|
|
@@ -7732,12 +8344,27 @@ inline Result ClientImpl::Post(const std::string &path, const std::string &body,
|
|
|
7732
8344
|
return Post(path, Headers(), body, content_type);
|
|
7733
8345
|
}
|
|
7734
8346
|
|
|
8347
|
+
inline Result ClientImpl::Post(const std::string &path, const std::string &body,
|
|
8348
|
+
const std::string &content_type,
|
|
8349
|
+
Progress progress) {
|
|
8350
|
+
return Post(path, Headers(), body, content_type, progress);
|
|
8351
|
+
}
|
|
8352
|
+
|
|
7735
8353
|
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
|
|
7736
8354
|
const std::string &body,
|
|
7737
8355
|
const std::string &content_type) {
|
|
7738
8356
|
return send_with_content_provider("POST", path, headers, body.data(),
|
|
7739
|
-
body.size(), nullptr, nullptr,
|
|
7740
|
-
|
|
8357
|
+
body.size(), nullptr, nullptr, content_type,
|
|
8358
|
+
nullptr);
|
|
8359
|
+
}
|
|
8360
|
+
|
|
8361
|
+
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
|
|
8362
|
+
const std::string &body,
|
|
8363
|
+
const std::string &content_type,
|
|
8364
|
+
Progress progress) {
|
|
8365
|
+
return send_with_content_provider("POST", path, headers, body.data(),
|
|
8366
|
+
body.size(), nullptr, nullptr, content_type,
|
|
8367
|
+
progress);
|
|
7741
8368
|
}
|
|
7742
8369
|
|
|
7743
8370
|
inline Result ClientImpl::Post(const std::string &path, const Params ¶ms) {
|
|
@@ -7763,14 +8390,15 @@ inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
|
|
|
7763
8390
|
const std::string &content_type) {
|
|
7764
8391
|
return send_with_content_provider("POST", path, headers, nullptr,
|
|
7765
8392
|
content_length, std::move(content_provider),
|
|
7766
|
-
nullptr, content_type);
|
|
8393
|
+
nullptr, content_type, nullptr);
|
|
7767
8394
|
}
|
|
7768
8395
|
|
|
7769
8396
|
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
|
|
7770
8397
|
ContentProviderWithoutLength content_provider,
|
|
7771
8398
|
const std::string &content_type) {
|
|
7772
8399
|
return send_with_content_provider("POST", path, headers, nullptr, 0, nullptr,
|
|
7773
|
-
std::move(content_provider), content_type
|
|
8400
|
+
std::move(content_provider), content_type,
|
|
8401
|
+
nullptr);
|
|
7774
8402
|
}
|
|
7775
8403
|
|
|
7776
8404
|
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
|
|
@@ -7779,6 +8407,13 @@ inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
|
|
|
7779
8407
|
return Post(path, headers, query, "application/x-www-form-urlencoded");
|
|
7780
8408
|
}
|
|
7781
8409
|
|
|
8410
|
+
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
|
|
8411
|
+
const Params ¶ms, Progress progress) {
|
|
8412
|
+
auto query = detail::params_to_query_str(params);
|
|
8413
|
+
return Post(path, headers, query, "application/x-www-form-urlencoded",
|
|
8414
|
+
progress);
|
|
8415
|
+
}
|
|
8416
|
+
|
|
7782
8417
|
inline Result ClientImpl::Post(const std::string &path,
|
|
7783
8418
|
const MultipartFormDataItems &items) {
|
|
7784
8419
|
return Post(path, Headers(), items);
|
|
@@ -7816,7 +8451,7 @@ ClientImpl::Post(const std::string &path, const Headers &headers,
|
|
|
7816
8451
|
return send_with_content_provider(
|
|
7817
8452
|
"POST", path, headers, nullptr, 0, nullptr,
|
|
7818
8453
|
get_multipart_content_provider(boundary, items, provider_items),
|
|
7819
|
-
content_type);
|
|
8454
|
+
content_type, nullptr);
|
|
7820
8455
|
}
|
|
7821
8456
|
|
|
7822
8457
|
inline Result ClientImpl::Put(const std::string &path) {
|
|
@@ -7833,7 +8468,15 @@ inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
|
|
|
7833
8468
|
const char *body, size_t content_length,
|
|
7834
8469
|
const std::string &content_type) {
|
|
7835
8470
|
return send_with_content_provider("PUT", path, headers, body, content_length,
|
|
7836
|
-
nullptr, nullptr, content_type);
|
|
8471
|
+
nullptr, nullptr, content_type, nullptr);
|
|
8472
|
+
}
|
|
8473
|
+
|
|
8474
|
+
inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
|
|
8475
|
+
const char *body, size_t content_length,
|
|
8476
|
+
const std::string &content_type,
|
|
8477
|
+
Progress progress) {
|
|
8478
|
+
return send_with_content_provider("PUT", path, headers, body, content_length,
|
|
8479
|
+
nullptr, nullptr, content_type, progress);
|
|
7837
8480
|
}
|
|
7838
8481
|
|
|
7839
8482
|
inline Result ClientImpl::Put(const std::string &path, const std::string &body,
|
|
@@ -7841,12 +8484,27 @@ inline Result ClientImpl::Put(const std::string &path, const std::string &body,
|
|
|
7841
8484
|
return Put(path, Headers(), body, content_type);
|
|
7842
8485
|
}
|
|
7843
8486
|
|
|
8487
|
+
inline Result ClientImpl::Put(const std::string &path, const std::string &body,
|
|
8488
|
+
const std::string &content_type,
|
|
8489
|
+
Progress progress) {
|
|
8490
|
+
return Put(path, Headers(), body, content_type, progress);
|
|
8491
|
+
}
|
|
8492
|
+
|
|
7844
8493
|
inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
|
|
7845
8494
|
const std::string &body,
|
|
7846
8495
|
const std::string &content_type) {
|
|
7847
8496
|
return send_with_content_provider("PUT", path, headers, body.data(),
|
|
7848
|
-
body.size(), nullptr, nullptr,
|
|
7849
|
-
|
|
8497
|
+
body.size(), nullptr, nullptr, content_type,
|
|
8498
|
+
nullptr);
|
|
8499
|
+
}
|
|
8500
|
+
|
|
8501
|
+
inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
|
|
8502
|
+
const std::string &body,
|
|
8503
|
+
const std::string &content_type,
|
|
8504
|
+
Progress progress) {
|
|
8505
|
+
return send_with_content_provider("PUT", path, headers, body.data(),
|
|
8506
|
+
body.size(), nullptr, nullptr, content_type,
|
|
8507
|
+
progress);
|
|
7850
8508
|
}
|
|
7851
8509
|
|
|
7852
8510
|
inline Result ClientImpl::Put(const std::string &path, size_t content_length,
|
|
@@ -7868,14 +8526,15 @@ inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
|
|
|
7868
8526
|
const std::string &content_type) {
|
|
7869
8527
|
return send_with_content_provider("PUT", path, headers, nullptr,
|
|
7870
8528
|
content_length, std::move(content_provider),
|
|
7871
|
-
nullptr, content_type);
|
|
8529
|
+
nullptr, content_type, nullptr);
|
|
7872
8530
|
}
|
|
7873
8531
|
|
|
7874
8532
|
inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
|
|
7875
8533
|
ContentProviderWithoutLength content_provider,
|
|
7876
8534
|
const std::string &content_type) {
|
|
7877
8535
|
return send_with_content_provider("PUT", path, headers, nullptr, 0, nullptr,
|
|
7878
|
-
std::move(content_provider), content_type
|
|
8536
|
+
std::move(content_provider), content_type,
|
|
8537
|
+
nullptr);
|
|
7879
8538
|
}
|
|
7880
8539
|
|
|
7881
8540
|
inline Result ClientImpl::Put(const std::string &path, const Params ¶ms) {
|
|
@@ -7888,6 +8547,13 @@ inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
|
|
|
7888
8547
|
return Put(path, headers, query, "application/x-www-form-urlencoded");
|
|
7889
8548
|
}
|
|
7890
8549
|
|
|
8550
|
+
inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
|
|
8551
|
+
const Params ¶ms, Progress progress) {
|
|
8552
|
+
auto query = detail::params_to_query_str(params);
|
|
8553
|
+
return Put(path, headers, query, "application/x-www-form-urlencoded",
|
|
8554
|
+
progress);
|
|
8555
|
+
}
|
|
8556
|
+
|
|
7891
8557
|
inline Result ClientImpl::Put(const std::string &path,
|
|
7892
8558
|
const MultipartFormDataItems &items) {
|
|
7893
8559
|
return Put(path, Headers(), items);
|
|
@@ -7925,7 +8591,7 @@ ClientImpl::Put(const std::string &path, const Headers &headers,
|
|
|
7925
8591
|
return send_with_content_provider(
|
|
7926
8592
|
"PUT", path, headers, nullptr, 0, nullptr,
|
|
7927
8593
|
get_multipart_content_provider(boundary, items, provider_items),
|
|
7928
|
-
content_type);
|
|
8594
|
+
content_type, nullptr);
|
|
7929
8595
|
}
|
|
7930
8596
|
inline Result ClientImpl::Patch(const std::string &path) {
|
|
7931
8597
|
return Patch(path, std::string(), std::string());
|
|
@@ -7937,12 +8603,26 @@ inline Result ClientImpl::Patch(const std::string &path, const char *body,
|
|
|
7937
8603
|
return Patch(path, Headers(), body, content_length, content_type);
|
|
7938
8604
|
}
|
|
7939
8605
|
|
|
8606
|
+
inline Result ClientImpl::Patch(const std::string &path, const char *body,
|
|
8607
|
+
size_t content_length,
|
|
8608
|
+
const std::string &content_type,
|
|
8609
|
+
Progress progress) {
|
|
8610
|
+
return Patch(path, Headers(), body, content_length, content_type, progress);
|
|
8611
|
+
}
|
|
8612
|
+
|
|
7940
8613
|
inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
|
|
7941
8614
|
const char *body, size_t content_length,
|
|
7942
8615
|
const std::string &content_type) {
|
|
8616
|
+
return Patch(path, headers, body, content_length, content_type, nullptr);
|
|
8617
|
+
}
|
|
8618
|
+
|
|
8619
|
+
inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
|
|
8620
|
+
const char *body, size_t content_length,
|
|
8621
|
+
const std::string &content_type,
|
|
8622
|
+
Progress progress) {
|
|
7943
8623
|
return send_with_content_provider("PATCH", path, headers, body,
|
|
7944
8624
|
content_length, nullptr, nullptr,
|
|
7945
|
-
content_type);
|
|
8625
|
+
content_type, progress);
|
|
7946
8626
|
}
|
|
7947
8627
|
|
|
7948
8628
|
inline Result ClientImpl::Patch(const std::string &path,
|
|
@@ -7951,12 +8631,26 @@ inline Result ClientImpl::Patch(const std::string &path,
|
|
|
7951
8631
|
return Patch(path, Headers(), body, content_type);
|
|
7952
8632
|
}
|
|
7953
8633
|
|
|
8634
|
+
inline Result ClientImpl::Patch(const std::string &path,
|
|
8635
|
+
const std::string &body,
|
|
8636
|
+
const std::string &content_type,
|
|
8637
|
+
Progress progress) {
|
|
8638
|
+
return Patch(path, Headers(), body, content_type, progress);
|
|
8639
|
+
}
|
|
8640
|
+
|
|
7954
8641
|
inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
|
|
7955
8642
|
const std::string &body,
|
|
7956
8643
|
const std::string &content_type) {
|
|
8644
|
+
return Patch(path, headers, body, content_type, nullptr);
|
|
8645
|
+
}
|
|
8646
|
+
|
|
8647
|
+
inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
|
|
8648
|
+
const std::string &body,
|
|
8649
|
+
const std::string &content_type,
|
|
8650
|
+
Progress progress) {
|
|
7957
8651
|
return send_with_content_provider("PATCH", path, headers, body.data(),
|
|
7958
|
-
body.size(), nullptr, nullptr,
|
|
7959
|
-
|
|
8652
|
+
body.size(), nullptr, nullptr, content_type,
|
|
8653
|
+
progress);
|
|
7960
8654
|
}
|
|
7961
8655
|
|
|
7962
8656
|
inline Result ClientImpl::Patch(const std::string &path, size_t content_length,
|
|
@@ -7978,14 +8672,15 @@ inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
|
|
|
7978
8672
|
const std::string &content_type) {
|
|
7979
8673
|
return send_with_content_provider("PATCH", path, headers, nullptr,
|
|
7980
8674
|
content_length, std::move(content_provider),
|
|
7981
|
-
nullptr, content_type);
|
|
8675
|
+
nullptr, content_type, nullptr);
|
|
7982
8676
|
}
|
|
7983
8677
|
|
|
7984
8678
|
inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
|
|
7985
8679
|
ContentProviderWithoutLength content_provider,
|
|
7986
8680
|
const std::string &content_type) {
|
|
7987
8681
|
return send_with_content_provider("PATCH", path, headers, nullptr, 0, nullptr,
|
|
7988
|
-
std::move(content_provider), content_type
|
|
8682
|
+
std::move(content_provider), content_type,
|
|
8683
|
+
nullptr);
|
|
7989
8684
|
}
|
|
7990
8685
|
|
|
7991
8686
|
inline Result ClientImpl::Delete(const std::string &path) {
|
|
@@ -8003,14 +8698,30 @@ inline Result ClientImpl::Delete(const std::string &path, const char *body,
|
|
|
8003
8698
|
return Delete(path, Headers(), body, content_length, content_type);
|
|
8004
8699
|
}
|
|
8005
8700
|
|
|
8701
|
+
inline Result ClientImpl::Delete(const std::string &path, const char *body,
|
|
8702
|
+
size_t content_length,
|
|
8703
|
+
const std::string &content_type,
|
|
8704
|
+
Progress progress) {
|
|
8705
|
+
return Delete(path, Headers(), body, content_length, content_type, progress);
|
|
8706
|
+
}
|
|
8707
|
+
|
|
8006
8708
|
inline Result ClientImpl::Delete(const std::string &path,
|
|
8007
8709
|
const Headers &headers, const char *body,
|
|
8008
8710
|
size_t content_length,
|
|
8009
8711
|
const std::string &content_type) {
|
|
8712
|
+
return Delete(path, headers, body, content_length, content_type, nullptr);
|
|
8713
|
+
}
|
|
8714
|
+
|
|
8715
|
+
inline Result ClientImpl::Delete(const std::string &path,
|
|
8716
|
+
const Headers &headers, const char *body,
|
|
8717
|
+
size_t content_length,
|
|
8718
|
+
const std::string &content_type,
|
|
8719
|
+
Progress progress) {
|
|
8010
8720
|
Request req;
|
|
8011
8721
|
req.method = "DELETE";
|
|
8012
8722
|
req.headers = headers;
|
|
8013
8723
|
req.path = path;
|
|
8724
|
+
req.progress = progress;
|
|
8014
8725
|
|
|
8015
8726
|
if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
|
|
8016
8727
|
req.body.assign(body, content_length);
|
|
@@ -8024,6 +8735,14 @@ inline Result ClientImpl::Delete(const std::string &path,
|
|
|
8024
8735
|
return Delete(path, Headers(), body.data(), body.size(), content_type);
|
|
8025
8736
|
}
|
|
8026
8737
|
|
|
8738
|
+
inline Result ClientImpl::Delete(const std::string &path,
|
|
8739
|
+
const std::string &body,
|
|
8740
|
+
const std::string &content_type,
|
|
8741
|
+
Progress progress) {
|
|
8742
|
+
return Delete(path, Headers(), body.data(), body.size(), content_type,
|
|
8743
|
+
progress);
|
|
8744
|
+
}
|
|
8745
|
+
|
|
8027
8746
|
inline Result ClientImpl::Delete(const std::string &path,
|
|
8028
8747
|
const Headers &headers,
|
|
8029
8748
|
const std::string &body,
|
|
@@ -8031,6 +8750,15 @@ inline Result ClientImpl::Delete(const std::string &path,
|
|
|
8031
8750
|
return Delete(path, headers, body.data(), body.size(), content_type);
|
|
8032
8751
|
}
|
|
8033
8752
|
|
|
8753
|
+
inline Result ClientImpl::Delete(const std::string &path,
|
|
8754
|
+
const Headers &headers,
|
|
8755
|
+
const std::string &body,
|
|
8756
|
+
const std::string &content_type,
|
|
8757
|
+
Progress progress) {
|
|
8758
|
+
return Delete(path, headers, body.data(), body.size(), content_type,
|
|
8759
|
+
progress);
|
|
8760
|
+
}
|
|
8761
|
+
|
|
8034
8762
|
inline Result ClientImpl::Options(const std::string &path) {
|
|
8035
8763
|
return Options(path, Headers());
|
|
8036
8764
|
}
|
|
@@ -8138,6 +8866,8 @@ inline void ClientImpl::set_address_family(int family) {
|
|
|
8138
8866
|
|
|
8139
8867
|
inline void ClientImpl::set_tcp_nodelay(bool on) { tcp_nodelay_ = on; }
|
|
8140
8868
|
|
|
8869
|
+
inline void ClientImpl::set_ipv6_v6only(bool on) { ipv6_v6only_ = on; }
|
|
8870
|
+
|
|
8141
8871
|
inline void ClientImpl::set_socket_options(SocketOptions socket_options) {
|
|
8142
8872
|
socket_options_ = std::move(socket_options);
|
|
8143
8873
|
}
|
|
@@ -8187,13 +8917,11 @@ inline void ClientImpl::set_ca_cert_store(X509_STORE *ca_cert_store) {
|
|
|
8187
8917
|
inline X509_STORE *ClientImpl::create_ca_cert_store(const char *ca_cert,
|
|
8188
8918
|
std::size_t size) const {
|
|
8189
8919
|
auto mem = BIO_new_mem_buf(ca_cert, static_cast<int>(size));
|
|
8920
|
+
auto se = detail::scope_exit([&] { BIO_free_all(mem); });
|
|
8190
8921
|
if (!mem) { return nullptr; }
|
|
8191
8922
|
|
|
8192
8923
|
auto inf = PEM_X509_INFO_read_bio(mem, nullptr, nullptr, nullptr);
|
|
8193
|
-
if (!inf) {
|
|
8194
|
-
BIO_free_all(mem);
|
|
8195
|
-
return nullptr;
|
|
8196
|
-
}
|
|
8924
|
+
if (!inf) { return nullptr; }
|
|
8197
8925
|
|
|
8198
8926
|
auto cts = X509_STORE_new();
|
|
8199
8927
|
if (cts) {
|
|
@@ -8207,13 +8935,21 @@ inline X509_STORE *ClientImpl::create_ca_cert_store(const char *ca_cert,
|
|
|
8207
8935
|
}
|
|
8208
8936
|
|
|
8209
8937
|
sk_X509_INFO_pop_free(inf, X509_INFO_free);
|
|
8210
|
-
BIO_free_all(mem);
|
|
8211
8938
|
return cts;
|
|
8212
8939
|
}
|
|
8213
8940
|
|
|
8214
8941
|
inline void ClientImpl::enable_server_certificate_verification(bool enabled) {
|
|
8215
8942
|
server_certificate_verification_ = enabled;
|
|
8216
8943
|
}
|
|
8944
|
+
|
|
8945
|
+
inline void ClientImpl::enable_server_hostname_verification(bool enabled) {
|
|
8946
|
+
server_hostname_verification_ = enabled;
|
|
8947
|
+
}
|
|
8948
|
+
|
|
8949
|
+
inline void ClientImpl::set_server_certificate_verifier(
|
|
8950
|
+
std::function<bool(SSL *ssl)> verifier) {
|
|
8951
|
+
server_certificate_verifier_ = verifier;
|
|
8952
|
+
}
|
|
8217
8953
|
#endif
|
|
8218
8954
|
|
|
8219
8955
|
inline void ClientImpl::set_logger(Logger logger) {
|
|
@@ -8257,13 +8993,30 @@ inline SSL *ssl_new(socket_t sock, SSL_CTX *ctx, std::mutex &ctx_mutex,
|
|
|
8257
8993
|
return ssl;
|
|
8258
8994
|
}
|
|
8259
8995
|
|
|
8260
|
-
inline void ssl_delete(std::mutex &ctx_mutex, SSL *ssl,
|
|
8996
|
+
inline void ssl_delete(std::mutex &ctx_mutex, SSL *ssl, socket_t sock,
|
|
8261
8997
|
bool shutdown_gracefully) {
|
|
8262
8998
|
// sometimes we may want to skip this to try to avoid SIGPIPE if we know
|
|
8263
8999
|
// the remote has closed the network connection
|
|
8264
9000
|
// Note that it is not always possible to avoid SIGPIPE, this is merely a
|
|
8265
9001
|
// best-efforts.
|
|
8266
|
-
if (shutdown_gracefully) {
|
|
9002
|
+
if (shutdown_gracefully) {
|
|
9003
|
+
#ifdef _WIN32
|
|
9004
|
+
(void)(sock);
|
|
9005
|
+
SSL_shutdown(ssl);
|
|
9006
|
+
#else
|
|
9007
|
+
timeval tv;
|
|
9008
|
+
tv.tv_sec = 1;
|
|
9009
|
+
tv.tv_usec = 0;
|
|
9010
|
+
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
|
|
9011
|
+
reinterpret_cast<const void *>(&tv), sizeof(tv));
|
|
9012
|
+
|
|
9013
|
+
auto ret = SSL_shutdown(ssl);
|
|
9014
|
+
while (ret == 0) {
|
|
9015
|
+
std::this_thread::sleep_for(std::chrono::milliseconds{100});
|
|
9016
|
+
ret = SSL_shutdown(ssl);
|
|
9017
|
+
}
|
|
9018
|
+
#endif
|
|
9019
|
+
}
|
|
8267
9020
|
|
|
8268
9021
|
std::lock_guard<std::mutex> guard(ctx_mutex);
|
|
8269
9022
|
SSL_free(ssl);
|
|
@@ -8366,7 +9119,7 @@ inline ssize_t SSLSocketStream::read(char *ptr, size_t size) {
|
|
|
8366
9119
|
if (SSL_pending(ssl_) > 0) {
|
|
8367
9120
|
return SSL_read(ssl_, ptr, static_cast<int>(size));
|
|
8368
9121
|
} else if (is_readable()) {
|
|
8369
|
-
std::this_thread::sleep_for(std::chrono::
|
|
9122
|
+
std::this_thread::sleep_for(std::chrono::microseconds{10});
|
|
8370
9123
|
ret = SSL_read(ssl_, ptr, static_cast<int>(size));
|
|
8371
9124
|
if (ret >= 0) { return ret; }
|
|
8372
9125
|
err = SSL_get_error(ssl_, ret);
|
|
@@ -8397,7 +9150,7 @@ inline ssize_t SSLSocketStream::write(const char *ptr, size_t size) {
|
|
|
8397
9150
|
while (--n >= 0 && err == SSL_ERROR_WANT_WRITE) {
|
|
8398
9151
|
#endif
|
|
8399
9152
|
if (is_writable()) {
|
|
8400
|
-
std::this_thread::sleep_for(std::chrono::
|
|
9153
|
+
std::this_thread::sleep_for(std::chrono::microseconds{10});
|
|
8401
9154
|
ret = SSL_write(ssl_, ptr, static_cast<int>(handle_size));
|
|
8402
9155
|
if (ret >= 0) { return ret; }
|
|
8403
9156
|
err = SSL_get_error(ssl_, ret);
|
|
@@ -8439,7 +9192,7 @@ inline SSLServer::SSLServer(const char *cert_path, const char *private_key_path,
|
|
|
8439
9192
|
SSL_OP_NO_COMPRESSION |
|
|
8440
9193
|
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
|
8441
9194
|
|
|
8442
|
-
SSL_CTX_set_min_proto_version(ctx_,
|
|
9195
|
+
SSL_CTX_set_min_proto_version(ctx_, TLS1_2_VERSION);
|
|
8443
9196
|
|
|
8444
9197
|
if (private_key_password != nullptr && (private_key_password[0] != '\0')) {
|
|
8445
9198
|
SSL_CTX_set_default_passwd_cb_userdata(
|
|
@@ -8449,7 +9202,8 @@ inline SSLServer::SSLServer(const char *cert_path, const char *private_key_path,
|
|
|
8449
9202
|
|
|
8450
9203
|
if (SSL_CTX_use_certificate_chain_file(ctx_, cert_path) != 1 ||
|
|
8451
9204
|
SSL_CTX_use_PrivateKey_file(ctx_, private_key_path, SSL_FILETYPE_PEM) !=
|
|
8452
|
-
1
|
|
9205
|
+
1 ||
|
|
9206
|
+
SSL_CTX_check_private_key(ctx_) != 1) {
|
|
8453
9207
|
SSL_CTX_free(ctx_);
|
|
8454
9208
|
ctx_ = nullptr;
|
|
8455
9209
|
} else if (client_ca_cert_file_path || client_ca_cert_dir_path) {
|
|
@@ -8471,7 +9225,7 @@ inline SSLServer::SSLServer(X509 *cert, EVP_PKEY *private_key,
|
|
|
8471
9225
|
SSL_OP_NO_COMPRESSION |
|
|
8472
9226
|
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
|
8473
9227
|
|
|
8474
|
-
SSL_CTX_set_min_proto_version(ctx_,
|
|
9228
|
+
SSL_CTX_set_min_proto_version(ctx_, TLS1_2_VERSION);
|
|
8475
9229
|
|
|
8476
9230
|
if (SSL_CTX_use_certificate(ctx_, cert) != 1 ||
|
|
8477
9231
|
SSL_CTX_use_PrivateKey(ctx_, private_key) != 1) {
|
|
@@ -8505,6 +9259,19 @@ inline bool SSLServer::is_valid() const { return ctx_; }
|
|
|
8505
9259
|
|
|
8506
9260
|
inline SSL_CTX *SSLServer::ssl_context() const { return ctx_; }
|
|
8507
9261
|
|
|
9262
|
+
inline void SSLServer::update_certs(X509 *cert, EVP_PKEY *private_key,
|
|
9263
|
+
X509_STORE *client_ca_cert_store) {
|
|
9264
|
+
|
|
9265
|
+
std::lock_guard<std::mutex> guard(ctx_mutex_);
|
|
9266
|
+
|
|
9267
|
+
SSL_CTX_use_certificate(ctx_, cert);
|
|
9268
|
+
SSL_CTX_use_PrivateKey(ctx_, private_key);
|
|
9269
|
+
|
|
9270
|
+
if (client_ca_cert_store != nullptr) {
|
|
9271
|
+
SSL_CTX_set_cert_store(ctx_, client_ca_cert_store);
|
|
9272
|
+
}
|
|
9273
|
+
}
|
|
9274
|
+
|
|
8508
9275
|
inline bool SSLServer::process_and_close_socket(socket_t sock) {
|
|
8509
9276
|
auto ssl = detail::ssl_new(
|
|
8510
9277
|
sock, ctx_, ctx_mutex_,
|
|
@@ -8516,20 +9283,29 @@ inline bool SSLServer::process_and_close_socket(socket_t sock) {
|
|
|
8516
9283
|
|
|
8517
9284
|
auto ret = false;
|
|
8518
9285
|
if (ssl) {
|
|
9286
|
+
std::string remote_addr;
|
|
9287
|
+
int remote_port = 0;
|
|
9288
|
+
detail::get_remote_ip_and_port(sock, remote_addr, remote_port);
|
|
9289
|
+
|
|
9290
|
+
std::string local_addr;
|
|
9291
|
+
int local_port = 0;
|
|
9292
|
+
detail::get_local_ip_and_port(sock, local_addr, local_port);
|
|
9293
|
+
|
|
8519
9294
|
ret = detail::process_server_socket_ssl(
|
|
8520
9295
|
svr_sock_, ssl, sock, keep_alive_max_count_, keep_alive_timeout_sec_,
|
|
8521
9296
|
read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
|
|
8522
9297
|
write_timeout_usec_,
|
|
8523
|
-
[
|
|
8524
|
-
|
|
8525
|
-
|
|
9298
|
+
[&](Stream &strm, bool close_connection, bool &connection_closed) {
|
|
9299
|
+
return process_request(strm, remote_addr, remote_port, local_addr,
|
|
9300
|
+
local_port, close_connection,
|
|
9301
|
+
connection_closed,
|
|
8526
9302
|
[&](Request &req) { req.ssl = ssl; });
|
|
8527
9303
|
});
|
|
8528
9304
|
|
|
8529
9305
|
// Shutdown gracefully if the result seemed successful, non-gracefully if
|
|
8530
9306
|
// the connection appeared to be closed.
|
|
8531
9307
|
const bool shutdown_gracefully = ret;
|
|
8532
|
-
detail::ssl_delete(ctx_mutex_, ssl, shutdown_gracefully);
|
|
9308
|
+
detail::ssl_delete(ctx_mutex_, ssl, sock, shutdown_gracefully);
|
|
8533
9309
|
}
|
|
8534
9310
|
|
|
8535
9311
|
detail::shutdown_socket(sock);
|
|
@@ -8551,6 +9327,8 @@ inline SSLClient::SSLClient(const std::string &host, int port,
|
|
|
8551
9327
|
: ClientImpl(host, port, client_cert_path, client_key_path) {
|
|
8552
9328
|
ctx_ = SSL_CTX_new(TLS_client_method());
|
|
8553
9329
|
|
|
9330
|
+
SSL_CTX_set_min_proto_version(ctx_, TLS1_2_VERSION);
|
|
9331
|
+
|
|
8554
9332
|
detail::split(&host_[0], &host_[host_.size()], '.',
|
|
8555
9333
|
[&](const char *b, const char *e) {
|
|
8556
9334
|
host_components_.emplace_back(b, e);
|
|
@@ -8758,36 +9536,47 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
|
|
|
8758
9536
|
}
|
|
8759
9537
|
|
|
8760
9538
|
if (server_certificate_verification_) {
|
|
8761
|
-
|
|
9539
|
+
if (server_certificate_verifier_) {
|
|
9540
|
+
if (!server_certificate_verifier_(ssl2)) {
|
|
9541
|
+
error = Error::SSLServerVerification;
|
|
9542
|
+
return false;
|
|
9543
|
+
}
|
|
9544
|
+
} else {
|
|
9545
|
+
verify_result_ = SSL_get_verify_result(ssl2);
|
|
8762
9546
|
|
|
8763
|
-
|
|
8764
|
-
|
|
8765
|
-
|
|
8766
|
-
|
|
9547
|
+
if (verify_result_ != X509_V_OK) {
|
|
9548
|
+
error = Error::SSLServerVerification;
|
|
9549
|
+
return false;
|
|
9550
|
+
}
|
|
8767
9551
|
|
|
8768
|
-
|
|
9552
|
+
auto server_cert = SSL_get1_peer_certificate(ssl2);
|
|
9553
|
+
auto se = detail::scope_exit([&] { X509_free(server_cert); });
|
|
8769
9554
|
|
|
8770
|
-
|
|
8771
|
-
|
|
8772
|
-
|
|
8773
|
-
|
|
9555
|
+
if (server_cert == nullptr) {
|
|
9556
|
+
error = Error::SSLServerVerification;
|
|
9557
|
+
return false;
|
|
9558
|
+
}
|
|
8774
9559
|
|
|
8775
|
-
|
|
8776
|
-
|
|
8777
|
-
|
|
8778
|
-
|
|
9560
|
+
if (server_hostname_verification_) {
|
|
9561
|
+
if (!verify_host(server_cert)) {
|
|
9562
|
+
error = Error::SSLServerHostnameVerification;
|
|
9563
|
+
return false;
|
|
9564
|
+
}
|
|
9565
|
+
}
|
|
8779
9566
|
}
|
|
8780
|
-
X509_free(server_cert);
|
|
8781
9567
|
}
|
|
8782
9568
|
|
|
8783
9569
|
return true;
|
|
8784
9570
|
},
|
|
8785
9571
|
[&](SSL *ssl2) {
|
|
9572
|
+
#if defined(OPENSSL_IS_BORINGSSL)
|
|
9573
|
+
SSL_set_tlsext_host_name(ssl2, host_.c_str());
|
|
9574
|
+
#else
|
|
8786
9575
|
// NOTE: Direct call instead of using the OpenSSL macro to suppress
|
|
8787
9576
|
// -Wold-style-cast warning
|
|
8788
|
-
// SSL_set_tlsext_host_name(ssl2, host_.c_str());
|
|
8789
9577
|
SSL_ctrl(ssl2, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name,
|
|
8790
9578
|
static_cast<void *>(const_cast<char *>(host_.c_str())));
|
|
9579
|
+
#endif
|
|
8791
9580
|
return true;
|
|
8792
9581
|
});
|
|
8793
9582
|
|
|
@@ -8812,7 +9601,8 @@ inline void SSLClient::shutdown_ssl_impl(Socket &socket,
|
|
|
8812
9601
|
return;
|
|
8813
9602
|
}
|
|
8814
9603
|
if (socket.ssl) {
|
|
8815
|
-
detail::ssl_delete(ctx_mutex_, socket.ssl,
|
|
9604
|
+
detail::ssl_delete(ctx_mutex_, socket.ssl, socket.sock,
|
|
9605
|
+
shutdown_gracefully);
|
|
8816
9606
|
socket.ssl = nullptr;
|
|
8817
9607
|
}
|
|
8818
9608
|
assert(socket.ssl == nullptr);
|
|
@@ -8861,8 +9651,8 @@ SSLClient::verify_host_with_subject_alt_name(X509 *server_cert) const {
|
|
|
8861
9651
|
|
|
8862
9652
|
auto type = GEN_DNS;
|
|
8863
9653
|
|
|
8864
|
-
struct in6_addr addr6
|
|
8865
|
-
struct in_addr addr
|
|
9654
|
+
struct in6_addr addr6{};
|
|
9655
|
+
struct in_addr addr{};
|
|
8866
9656
|
size_t addr_len = 0;
|
|
8867
9657
|
|
|
8868
9658
|
#ifndef __MINGW32__
|
|
@@ -8965,7 +9755,7 @@ inline Client::Client(const std::string &scheme_host_port,
|
|
|
8965
9755
|
const std::string &client_cert_path,
|
|
8966
9756
|
const std::string &client_key_path) {
|
|
8967
9757
|
const static std::regex re(
|
|
8968
|
-
R"((?:([a-z]+):\/\/)?(?:\[([\d:]+)\]|([^:/?#]+))(?::(\d+))?)");
|
|
9758
|
+
R"((?:([a-z]+):\/\/)?(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)");
|
|
8969
9759
|
|
|
8970
9760
|
std::smatch m;
|
|
8971
9761
|
if (std::regex_match(scheme_host_port, m, re)) {
|
|
@@ -9002,10 +9792,12 @@ inline Client::Client(const std::string &scheme_host_port,
|
|
|
9002
9792
|
client_key_path);
|
|
9003
9793
|
}
|
|
9004
9794
|
} else {
|
|
9795
|
+
// NOTE: Update TEST(UniversalClientImplTest, Ipv6LiteralAddress)
|
|
9796
|
+
// if port param below changes.
|
|
9005
9797
|
cli_ = detail::make_unique<ClientImpl>(scheme_host_port, 80,
|
|
9006
9798
|
client_cert_path, client_key_path);
|
|
9007
9799
|
}
|
|
9008
|
-
}
|
|
9800
|
+
} // namespace detail
|
|
9009
9801
|
|
|
9010
9802
|
inline Client::Client(const std::string &host, int port)
|
|
9011
9803
|
: cli_(detail::make_unique<ClientImpl>(host, port)) {}
|
|
@@ -9111,15 +9903,30 @@ inline Result Client::Post(const std::string &path, const Headers &headers,
|
|
|
9111
9903
|
const std::string &content_type) {
|
|
9112
9904
|
return cli_->Post(path, headers, body, content_length, content_type);
|
|
9113
9905
|
}
|
|
9906
|
+
inline Result Client::Post(const std::string &path, const Headers &headers,
|
|
9907
|
+
const char *body, size_t content_length,
|
|
9908
|
+
const std::string &content_type, Progress progress) {
|
|
9909
|
+
return cli_->Post(path, headers, body, content_length, content_type,
|
|
9910
|
+
progress);
|
|
9911
|
+
}
|
|
9114
9912
|
inline Result Client::Post(const std::string &path, const std::string &body,
|
|
9115
9913
|
const std::string &content_type) {
|
|
9116
9914
|
return cli_->Post(path, body, content_type);
|
|
9117
9915
|
}
|
|
9916
|
+
inline Result Client::Post(const std::string &path, const std::string &body,
|
|
9917
|
+
const std::string &content_type, Progress progress) {
|
|
9918
|
+
return cli_->Post(path, body, content_type, progress);
|
|
9919
|
+
}
|
|
9118
9920
|
inline Result Client::Post(const std::string &path, const Headers &headers,
|
|
9119
9921
|
const std::string &body,
|
|
9120
9922
|
const std::string &content_type) {
|
|
9121
9923
|
return cli_->Post(path, headers, body, content_type);
|
|
9122
9924
|
}
|
|
9925
|
+
inline Result Client::Post(const std::string &path, const Headers &headers,
|
|
9926
|
+
const std::string &body,
|
|
9927
|
+
const std::string &content_type, Progress progress) {
|
|
9928
|
+
return cli_->Post(path, headers, body, content_type, progress);
|
|
9929
|
+
}
|
|
9123
9930
|
inline Result Client::Post(const std::string &path, size_t content_length,
|
|
9124
9931
|
ContentProvider content_provider,
|
|
9125
9932
|
const std::string &content_type) {
|
|
@@ -9150,6 +9957,10 @@ inline Result Client::Post(const std::string &path, const Headers &headers,
|
|
|
9150
9957
|
const Params ¶ms) {
|
|
9151
9958
|
return cli_->Post(path, headers, params);
|
|
9152
9959
|
}
|
|
9960
|
+
inline Result Client::Post(const std::string &path, const Headers &headers,
|
|
9961
|
+
const Params ¶ms, Progress progress) {
|
|
9962
|
+
return cli_->Post(path, headers, params, progress);
|
|
9963
|
+
}
|
|
9153
9964
|
inline Result Client::Post(const std::string &path,
|
|
9154
9965
|
const MultipartFormDataItems &items) {
|
|
9155
9966
|
return cli_->Post(path, items);
|
|
@@ -9180,15 +9991,29 @@ inline Result Client::Put(const std::string &path, const Headers &headers,
|
|
|
9180
9991
|
const std::string &content_type) {
|
|
9181
9992
|
return cli_->Put(path, headers, body, content_length, content_type);
|
|
9182
9993
|
}
|
|
9994
|
+
inline Result Client::Put(const std::string &path, const Headers &headers,
|
|
9995
|
+
const char *body, size_t content_length,
|
|
9996
|
+
const std::string &content_type, Progress progress) {
|
|
9997
|
+
return cli_->Put(path, headers, body, content_length, content_type, progress);
|
|
9998
|
+
}
|
|
9183
9999
|
inline Result Client::Put(const std::string &path, const std::string &body,
|
|
9184
10000
|
const std::string &content_type) {
|
|
9185
10001
|
return cli_->Put(path, body, content_type);
|
|
9186
10002
|
}
|
|
10003
|
+
inline Result Client::Put(const std::string &path, const std::string &body,
|
|
10004
|
+
const std::string &content_type, Progress progress) {
|
|
10005
|
+
return cli_->Put(path, body, content_type, progress);
|
|
10006
|
+
}
|
|
9187
10007
|
inline Result Client::Put(const std::string &path, const Headers &headers,
|
|
9188
10008
|
const std::string &body,
|
|
9189
10009
|
const std::string &content_type) {
|
|
9190
10010
|
return cli_->Put(path, headers, body, content_type);
|
|
9191
10011
|
}
|
|
10012
|
+
inline Result Client::Put(const std::string &path, const Headers &headers,
|
|
10013
|
+
const std::string &body,
|
|
10014
|
+
const std::string &content_type, Progress progress) {
|
|
10015
|
+
return cli_->Put(path, headers, body, content_type, progress);
|
|
10016
|
+
}
|
|
9192
10017
|
inline Result Client::Put(const std::string &path, size_t content_length,
|
|
9193
10018
|
ContentProvider content_provider,
|
|
9194
10019
|
const std::string &content_type) {
|
|
@@ -9219,6 +10044,10 @@ inline Result Client::Put(const std::string &path, const Headers &headers,
|
|
|
9219
10044
|
const Params ¶ms) {
|
|
9220
10045
|
return cli_->Put(path, headers, params);
|
|
9221
10046
|
}
|
|
10047
|
+
inline Result Client::Put(const std::string &path, const Headers &headers,
|
|
10048
|
+
const Params ¶ms, Progress progress) {
|
|
10049
|
+
return cli_->Put(path, headers, params, progress);
|
|
10050
|
+
}
|
|
9222
10051
|
inline Result Client::Put(const std::string &path,
|
|
9223
10052
|
const MultipartFormDataItems &items) {
|
|
9224
10053
|
return cli_->Put(path, items);
|
|
@@ -9246,20 +10075,44 @@ inline Result Client::Patch(const std::string &path, const char *body,
|
|
|
9246
10075
|
const std::string &content_type) {
|
|
9247
10076
|
return cli_->Patch(path, body, content_length, content_type);
|
|
9248
10077
|
}
|
|
10078
|
+
inline Result Client::Patch(const std::string &path, const char *body,
|
|
10079
|
+
size_t content_length,
|
|
10080
|
+
const std::string &content_type,
|
|
10081
|
+
Progress progress) {
|
|
10082
|
+
return cli_->Patch(path, body, content_length, content_type, progress);
|
|
10083
|
+
}
|
|
9249
10084
|
inline Result Client::Patch(const std::string &path, const Headers &headers,
|
|
9250
10085
|
const char *body, size_t content_length,
|
|
9251
10086
|
const std::string &content_type) {
|
|
9252
10087
|
return cli_->Patch(path, headers, body, content_length, content_type);
|
|
9253
10088
|
}
|
|
10089
|
+
inline Result Client::Patch(const std::string &path, const Headers &headers,
|
|
10090
|
+
const char *body, size_t content_length,
|
|
10091
|
+
const std::string &content_type,
|
|
10092
|
+
Progress progress) {
|
|
10093
|
+
return cli_->Patch(path, headers, body, content_length, content_type,
|
|
10094
|
+
progress);
|
|
10095
|
+
}
|
|
9254
10096
|
inline Result Client::Patch(const std::string &path, const std::string &body,
|
|
9255
10097
|
const std::string &content_type) {
|
|
9256
10098
|
return cli_->Patch(path, body, content_type);
|
|
9257
10099
|
}
|
|
10100
|
+
inline Result Client::Patch(const std::string &path, const std::string &body,
|
|
10101
|
+
const std::string &content_type,
|
|
10102
|
+
Progress progress) {
|
|
10103
|
+
return cli_->Patch(path, body, content_type, progress);
|
|
10104
|
+
}
|
|
9258
10105
|
inline Result Client::Patch(const std::string &path, const Headers &headers,
|
|
9259
10106
|
const std::string &body,
|
|
9260
10107
|
const std::string &content_type) {
|
|
9261
10108
|
return cli_->Patch(path, headers, body, content_type);
|
|
9262
10109
|
}
|
|
10110
|
+
inline Result Client::Patch(const std::string &path, const Headers &headers,
|
|
10111
|
+
const std::string &body,
|
|
10112
|
+
const std::string &content_type,
|
|
10113
|
+
Progress progress) {
|
|
10114
|
+
return cli_->Patch(path, headers, body, content_type, progress);
|
|
10115
|
+
}
|
|
9263
10116
|
inline Result Client::Patch(const std::string &path, size_t content_length,
|
|
9264
10117
|
ContentProvider content_provider,
|
|
9265
10118
|
const std::string &content_type) {
|
|
@@ -9294,20 +10147,44 @@ inline Result Client::Delete(const std::string &path, const char *body,
|
|
|
9294
10147
|
const std::string &content_type) {
|
|
9295
10148
|
return cli_->Delete(path, body, content_length, content_type);
|
|
9296
10149
|
}
|
|
10150
|
+
inline Result Client::Delete(const std::string &path, const char *body,
|
|
10151
|
+
size_t content_length,
|
|
10152
|
+
const std::string &content_type,
|
|
10153
|
+
Progress progress) {
|
|
10154
|
+
return cli_->Delete(path, body, content_length, content_type, progress);
|
|
10155
|
+
}
|
|
9297
10156
|
inline Result Client::Delete(const std::string &path, const Headers &headers,
|
|
9298
10157
|
const char *body, size_t content_length,
|
|
9299
10158
|
const std::string &content_type) {
|
|
9300
10159
|
return cli_->Delete(path, headers, body, content_length, content_type);
|
|
9301
10160
|
}
|
|
10161
|
+
inline Result Client::Delete(const std::string &path, const Headers &headers,
|
|
10162
|
+
const char *body, size_t content_length,
|
|
10163
|
+
const std::string &content_type,
|
|
10164
|
+
Progress progress) {
|
|
10165
|
+
return cli_->Delete(path, headers, body, content_length, content_type,
|
|
10166
|
+
progress);
|
|
10167
|
+
}
|
|
9302
10168
|
inline Result Client::Delete(const std::string &path, const std::string &body,
|
|
9303
10169
|
const std::string &content_type) {
|
|
9304
10170
|
return cli_->Delete(path, body, content_type);
|
|
9305
10171
|
}
|
|
10172
|
+
inline Result Client::Delete(const std::string &path, const std::string &body,
|
|
10173
|
+
const std::string &content_type,
|
|
10174
|
+
Progress progress) {
|
|
10175
|
+
return cli_->Delete(path, body, content_type, progress);
|
|
10176
|
+
}
|
|
9306
10177
|
inline Result Client::Delete(const std::string &path, const Headers &headers,
|
|
9307
10178
|
const std::string &body,
|
|
9308
10179
|
const std::string &content_type) {
|
|
9309
10180
|
return cli_->Delete(path, headers, body, content_type);
|
|
9310
10181
|
}
|
|
10182
|
+
inline Result Client::Delete(const std::string &path, const Headers &headers,
|
|
10183
|
+
const std::string &body,
|
|
10184
|
+
const std::string &content_type,
|
|
10185
|
+
Progress progress) {
|
|
10186
|
+
return cli_->Delete(path, headers, body, content_type, progress);
|
|
10187
|
+
}
|
|
9311
10188
|
inline Result Client::Options(const std::string &path) {
|
|
9312
10189
|
return cli_->Options(path);
|
|
9313
10190
|
}
|
|
@@ -9417,6 +10294,15 @@ inline void Client::set_proxy_digest_auth(const std::string &username,
|
|
|
9417
10294
|
inline void Client::enable_server_certificate_verification(bool enabled) {
|
|
9418
10295
|
cli_->enable_server_certificate_verification(enabled);
|
|
9419
10296
|
}
|
|
10297
|
+
|
|
10298
|
+
inline void Client::enable_server_hostname_verification(bool enabled) {
|
|
10299
|
+
cli_->enable_server_hostname_verification(enabled);
|
|
10300
|
+
}
|
|
10301
|
+
|
|
10302
|
+
inline void Client::set_server_certificate_verifier(
|
|
10303
|
+
std::function<bool(SSL *ssl)> verifier) {
|
|
10304
|
+
cli_->set_server_certificate_verifier(verifier);
|
|
10305
|
+
}
|
|
9420
10306
|
#endif
|
|
9421
10307
|
|
|
9422
10308
|
inline void Client::set_logger(Logger logger) {
|