Replace Hyper with Warp for HTTP server

- Use Warp
- Optimize clones
- HTTPS server
- Content-Length limit
- HTTP Basic Auth
- Stop server with Ctrl-C
This commit is contained in:
Adrián Arroyo Calle
2023-09-05 20:40:58 +02:00
parent 841aaa78b4
commit 660860bccf
9 changed files with 682 additions and 339 deletions

476
Cargo.lock generated
View File

@@ -81,9 +81,15 @@ checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
[[package]]
name = "base64"
version = "0.21.3"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "base64"
version = "0.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
[[package]]
name = "bit-set"
@@ -188,9 +194,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.13.0"
version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
[[package]]
name = "byte-tools"
@@ -206,9 +212,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
version = "1.4.0"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
[[package]]
name = "cc"
@@ -227,17 +233,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.26"
version = "0.4.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"time",
"wasm-bindgen",
"winapi",
"windows-targets",
]
[[package]]
@@ -365,19 +370,19 @@ dependencies = [
[[package]]
name = "ctrlc"
version = "3.4.0"
version = "3.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a011bbe2c35ce9c1f143b7af6f94f29a167beb4cd1d29e6740ce836f723120e"
checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf"
dependencies = [
"nix",
"nix 0.27.1",
"windows-sys",
]
[[package]]
name = "dashmap"
version = "5.5.1"
version = "5.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edd72493923899c6f10c641bdbdeddc7183d6396641d99c1a0d1597f37f92e28"
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
dependencies = [
"cfg-if",
"hashbrown 0.14.0",
@@ -551,9 +556,9 @@ checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
[[package]]
name = "errno"
version = "0.3.2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd"
dependencies = [
"errno-dragonfly",
"libc",
@@ -699,7 +704,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.32",
"syn 2.0.37",
]
[[package]]
@@ -769,7 +774,7 @@ dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
"wasi",
"wasm-bindgen",
]
@@ -832,6 +837,30 @@ version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
[[package]]
name = "headers"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270"
dependencies = [
"base64 0.21.4",
"bytes",
"headers-core",
"http",
"httpdate",
"mime",
"sha1",
]
[[package]]
name = "headers-core"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
dependencies = [
"http",
]
[[package]]
name = "heck"
version = "0.3.3"
@@ -843,9 +872,9 @@ dependencies = [
[[package]]
name = "hermit-abi"
version = "0.3.2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
[[package]]
name = "home"
@@ -903,29 +932,6 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "http-body"
version = "1.0.0-rc.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "951dfc2e32ac02d67c90c0d65bd27009a635dc9b381a2cc7d284ab01e3a0150d"
dependencies = [
"bytes",
"http",
]
[[package]]
name = "http-body-util"
version = "0.1.0-rc.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08ef12f041acdd397010e5fb6433270c147d3b8b2d0a840cd7fff8e531dca5c8"
dependencies = [
"bytes",
"futures-util",
"http",
"http-body 1.0.0-rc.2",
"pin-project-lite",
]
[[package]]
name = "httparse"
version = "1.8.0"
@@ -950,7 +956,7 @@ dependencies = [
"futures-util",
"h2",
"http",
"http-body 0.4.5",
"http-body",
"httparse",
"httpdate",
"itoa",
@@ -962,28 +968,6 @@ dependencies = [
"want",
]
[[package]]
name = "hyper"
version = "1.0.0-rc.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b75264b2003a3913f118d35c586e535293b3e22e41f074930762929d071e092"
dependencies = [
"bytes",
"futures-channel",
"futures-core",
"futures-util",
"h2",
"http",
"http-body 1.0.0-rc.2",
"httparse",
"httpdate",
"itoa",
"pin-project-lite",
"tokio",
"tracing",
"want",
]
[[package]]
name = "hyper-tls"
version = "0.5.0"
@@ -991,7 +975,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes",
"hyper 0.14.27",
"hyper",
"native-tls",
"tokio",
"tokio-native-tls",
@@ -1119,9 +1103,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.147"
version = "0.2.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
[[package]]
name = "libffi"
@@ -1154,9 +1138,9 @@ dependencies = [
[[package]]
name = "linux-raw-sys"
version = "0.4.5"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128"
[[package]]
name = "lock_api"
@@ -1214,9 +1198,9 @@ checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
[[package]]
name = "memchr"
version = "2.5.0"
version = "2.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
[[package]]
name = "mime"
@@ -1224,6 +1208,16 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "mime_guess"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
dependencies = [
"mime",
"unicase",
]
[[package]]
name = "miniz_oxide"
version = "0.7.1"
@@ -1253,7 +1247,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
dependencies = [
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
"wasi",
"windows-sys",
]
@@ -1285,6 +1279,24 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "multer"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2"
dependencies = [
"bytes",
"encoding_rs",
"futures-util",
"http",
"httparse",
"log",
"memchr",
"mime",
"spin 0.9.8",
"version_check",
]
[[package]]
name = "native-tls"
version = "0.2.11"
@@ -1320,9 +1332,20 @@ dependencies = [
[[package]]
name = "nix"
version = "0.26.3"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abbbc55ad7b13aac85f9401c796dcda1b864e07fcad40ad47792eaa8932ea502"
checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
dependencies = [
"bitflags 1.3.2",
"cfg-if",
"libc",
]
[[package]]
name = "nix"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
dependencies = [
"bitflags 2.4.0",
"cfg-if",
@@ -1374,9 +1397,9 @@ dependencies = [
[[package]]
name = "object"
version = "0.32.0"
version = "0.32.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe"
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
dependencies = [
"memchr",
]
@@ -1416,7 +1439,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.32",
"syn 2.0.37",
]
[[package]]
@@ -1427,9 +1450,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.92"
version = "0.9.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db7e971c2c2bba161b2d2fdf37080177eff520b3bc044787c7f1f5f9e78d869b"
checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d"
dependencies = [
"cc",
"libc",
@@ -1582,6 +1605,26 @@ dependencies = [
"siphasher",
]
[[package]]
name = "pin-project"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.37",
]
[[package]]
name = "pin-project-lite"
version = "0.2.13"
@@ -1647,9 +1690,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
[[package]]
name = "proc-macro2"
version = "1.0.66"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
dependencies = [
"unicode-ident",
]
@@ -1756,15 +1799,15 @@ version = "0.11.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1"
dependencies = [
"base64 0.21.3",
"base64 0.21.4",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"h2",
"http",
"http-body 0.4.5",
"hyper 0.14.27",
"http-body",
"hyper",
"hyper-tls",
"ipnet",
"js-sys",
@@ -1796,7 +1839,7 @@ dependencies = [
"cc",
"libc",
"once_cell",
"spin",
"spin 0.5.2",
"untrusted",
"web-sys",
"winapi",
@@ -1812,7 +1855,7 @@ dependencies = [
"getrandom",
"libc",
"once_cell",
"spin",
"spin 0.5.2",
"untrusted",
"web-sys",
"winapi",
@@ -1846,9 +1889,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustix"
version = "0.38.9"
version = "0.38.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bfe0f2582b4931a45d1fa608f8a8722e8b3c7ac54dd6d5f3b3212791fedef49"
checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f"
dependencies = [
"bitflags 2.4.0",
"errno",
@@ -1857,6 +1900,27 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "rustls"
version = "0.20.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99"
dependencies = [
"log",
"ring",
"sct",
"webpki",
]
[[package]]
name = "rustls-pemfile"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
dependencies = [
"base64 0.21.4",
]
[[package]]
name = "rustversion"
version = "1.0.14"
@@ -1877,7 +1941,7 @@ dependencies = [
"libc",
"log",
"memchr",
"nix",
"nix 0.26.4",
"radix_trie",
"scopeguard",
"unicode-segmentation",
@@ -1910,6 +1974,12 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "scoped-tls"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
[[package]]
name = "scopeguard"
version = "1.2.0"
@@ -1942,8 +2012,6 @@ dependencies = [
"getrandom",
"git-version",
"hostname",
"http-body-util",
"hyper 1.0.0-rc.3",
"indexmap",
"lazy_static",
"lexical",
@@ -1975,16 +2043,27 @@ dependencies = [
"static_assertions",
"strum",
"strum_macros",
"syn 2.0.32",
"syn 2.0.37",
"to-syn-value",
"to-syn-value_derive",
"tokio",
"walkdir",
"warp",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "sct"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "security-framework"
version = "2.9.2"
@@ -2047,14 +2126,14 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.32",
"syn 2.0.37",
]
[[package]]
name = "serde_json"
version = "1.0.105"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
dependencies = [
"itoa",
"ryu",
@@ -2095,7 +2174,18 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.32",
"syn 2.0.37",
]
[[package]]
name = "sha1"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures",
"digest 0.10.7",
]
[[package]]
@@ -2179,9 +2269,9 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.11.0"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
[[package]]
name = "socket2"
@@ -2195,9 +2285,9 @@ dependencies = [
[[package]]
name = "socket2"
version = "0.5.3"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877"
checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e"
dependencies = [
"libc",
"windows-sys",
@@ -2209,6 +2299,12 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]]
name = "static_assertions"
version = "1.1.0"
@@ -2291,9 +2387,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.32"
version = "2.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2"
checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
dependencies = [
"proc-macro2",
"quote",
@@ -2338,33 +2434,22 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
[[package]]
name = "thiserror"
version = "1.0.47"
version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f"
checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.47"
version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.32",
]
[[package]]
name = "time"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
dependencies = [
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi",
"syn 2.0.37",
]
[[package]]
@@ -2388,7 +2473,7 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfcc684f2ceaec3b4e8689657c9e0944b07bf5e34563e0bd758c4d42c05c82ed"
dependencies = [
"syn 2.0.32",
"syn 2.0.37",
"to-syn-value_derive",
]
@@ -2400,7 +2485,7 @@ checksum = "3dfffda778de8443144ff3b042ddf14e8bc5445f0fd9fe937c3d252535dc9212"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.32",
"syn 2.0.37",
]
[[package]]
@@ -2417,7 +2502,7 @@ dependencies = [
"parking_lot 0.12.1",
"pin-project-lite",
"signal-hook-registry",
"socket2 0.5.3",
"socket2 0.5.4",
"tokio-macros",
"windows-sys",
]
@@ -2430,7 +2515,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.32",
"syn 2.0.37",
]
[[package]]
@@ -2444,10 +2529,44 @@ dependencies = [
]
[[package]]
name = "tokio-util"
version = "0.7.8"
name = "tokio-rustls"
version = "0.23.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d"
checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
dependencies = [
"rustls",
"tokio",
"webpki",
]
[[package]]
name = "tokio-stream"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842"
dependencies = [
"futures-core",
"pin-project-lite",
"tokio",
]
[[package]]
name = "tokio-tungstenite"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd"
dependencies = [
"futures-util",
"log",
"tokio",
"tungstenite",
]
[[package]]
name = "tokio-util"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d"
dependencies = [
"bytes",
"futures-core",
@@ -2470,6 +2589,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [
"cfg-if",
"log",
"pin-project-lite",
"tracing-core",
]
@@ -2490,10 +2610,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]]
name = "typenum"
version = "1.16.0"
name = "tungstenite"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788"
dependencies = [
"base64 0.13.1",
"byteorder",
"bytes",
"http",
"httparse",
"log",
"rand",
"sha1",
"thiserror",
"url",
"utf-8",
]
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicase"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
dependencies = [
"version_check",
]
[[package]]
name = "unicode-bidi"
@@ -2503,9 +2651,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
[[package]]
name = "unicode-ident"
version = "1.0.11"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-normalization"
@@ -2524,9 +2672,9 @@ checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
[[package]]
name = "unicode-width"
version = "0.1.10"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "untrusted"
@@ -2536,9 +2684,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "url"
version = "2.4.0"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb"
checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
dependencies = [
"form_urlencoded",
"idna",
@@ -2580,9 +2728,9 @@ dependencies = [
[[package]]
name = "walkdir"
version = "2.3.3"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
dependencies = [
"same-file",
"winapi-util",
@@ -2598,10 +2746,36 @@ dependencies = [
]
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
name = "warp"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
checksum = "ba431ef570df1287f7f8b07e376491ad54f84d26ac473489427231e1718e1f69"
dependencies = [
"bytes",
"futures-channel",
"futures-util",
"headers",
"http",
"hyper",
"log",
"mime",
"mime_guess",
"multer",
"percent-encoding",
"pin-project",
"rustls-pemfile",
"scoped-tls",
"serde",
"serde_json",
"serde_urlencoded",
"tokio",
"tokio-rustls",
"tokio-stream",
"tokio-tungstenite",
"tokio-util",
"tower-service",
"tracing",
]
[[package]]
name = "wasi"
@@ -2630,7 +2804,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.32",
"syn 2.0.37",
"wasm-bindgen-shared",
]
@@ -2664,7 +2838,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.32",
"syn 2.0.37",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -2685,6 +2859,16 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "webpki"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0e74f82d49d545ad128049b7e88f6576df2da6b02e9ce565c6f533be576957e"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "winapi"
version = "0.3.9"
@@ -2703,9 +2887,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
dependencies = [
"winapi",
]

View File

@@ -21,7 +21,7 @@ ffi = ["dep:libffi"]
repl = ["dep:crossterm", "dep:ctrlc", "dep:rustyline"]
hostname = ["dep:hostname"]
tls = ["dep:native-tls"]
http = ["dep:hyper", "dep:reqwest"]
http = ["dep:warp", "dep:reqwest"]
rust_beta_channel = []
crypto-full = []
@@ -66,7 +66,6 @@ ryu = "1.0.9"
futures = "0.3"
libloading = "0.7"
derive_deref = "1.1.1"
http-body-util = "0.1.0-rc.2"
bytes = "1"
dashu = "0.4.0"
num-order = { version = "1.2.0" }
@@ -79,7 +78,7 @@ crossterm = { version = "0.20.0", optional = true }
ctrlc = { version = "3.2.2", optional = true }
rustyline = { version = "12.0.0", optional = true }
native-tls = { version = "0.2.4", optional = true }
hyper = { version = "=1.0.0-rc.3", features = ["full"], optional = true }
warp = { version = "=0.3.5", features = ["tls"], optional = true }
reqwest = { version = "0.11.18", features = ["blocking"], optional = true }
tokio = { version = "1.28.2", features = ["full"] }

View File

@@ -624,7 +624,7 @@ The modules that ship with Scryer Prolog are also called
Probabilistic predicates and random number generators.
* [`http/http_open`](src/lib/http/http_open.pl) Open a stream to
read answers from web servers. HTTPS is also supported.
* [`http/http_server`](src/lib/http/http_server.pl) Runs a HTTP/1.1 and HTTP/2.0 web server. Uses [Hyper](https://hyper.rs) as a backend. Supports some query and form handling.
* [`http/http_server`](src/lib/http/http_server.pl) Runs a HTTP/1.1 and HTTP/2.0 web server. Uses [Warp](https://github.com/seanmonstar/warp) as a backend. Supports some query and form handling.
* [`sgml`](src/lib/sgml.pl)
`load_html/3` and `load_xml/3` represent HTML and XML documents
as Prolog terms for convenient and efficient reasoning. Use

View File

@@ -558,7 +558,7 @@ enum SystemClauseType {
DeterministicLengthRundown,
#[strum_discriminants(strum(props(Arity = "7", Name = "$http_open")))]
HttpOpen,
#[strum_discriminants(strum(props(Arity = "2", Name = "$http_listen")))]
#[strum_discriminants(strum(props(Arity = "5", Name = "$http_listen")))]
HttpListen,
#[strum_discriminants(strum(props(Arity = "7", Name = "$http_accept")))]
HttpAccept,

View File

@@ -1,55 +1,23 @@
use bytes::Bytes;
use http_body_util::Full;
use hyper::service::Service;
use hyper::{body::Incoming as IncomingBody, Request, Response};
use std::future::Future;
use std::pin::Pin;
use std::sync::{Arc, Condvar, Mutex};
use std::sync::{Arc, Mutex, Condvar};
use std::io::BufRead;
use warp::http;
pub struct HttpListener {
pub incoming: std::sync::mpsc::Receiver<HttpRequest>,
}
#[derive(Debug)]
pub struct HttpRequest {
pub request: Request<IncomingBody>,
pub request_data: HttpRequestData,
pub response: HttpResponse,
}
pub type HttpResponse = Arc<(Mutex<bool>, Mutex<Option<Response<Full<Bytes>>>>, Condvar)>;
pub type HttpResponse = Arc<(Mutex<bool>, Mutex<Option<warp::reply::Response>>, Condvar)>;
pub struct HttpService {
pub tx: std::sync::mpsc::SyncSender<HttpRequest>,
}
impl Service<Request<IncomingBody>> for HttpService {
type Response = Response<Full<Bytes>>;
type Error = hyper::Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
fn call(&mut self, req: Request<IncomingBody>) -> Self::Future {
// new connection!
// we send the Request info to Prolog
let response = Arc::new((Mutex::new(false), Mutex::new(None), Condvar::new()));
let http_request = HttpRequest {
request: req,
response: Arc::clone(&response),
};
self.tx.send(http_request).unwrap();
// we wait for the Response info from Prolog
{
let (ready, _response, cvar) = &*response;
let mut ready = ready.lock().unwrap();
while !*ready {
ready = cvar.wait(ready).unwrap();
}
}
{
let (_, response, _) = &*response;
let response = response.lock().unwrap().take();
let res = response.expect("Data race error in HTTP Server");
Box::pin(async move { Ok(res) })
}
}
pub struct HttpRequestData {
pub method: http::Method,
pub headers: http::HeaderMap,
pub path: String,
pub query: String,
pub body: Box<dyn BufRead + Send>,
}

View File

@@ -6,8 +6,8 @@
*/
/** This library provides an starting point to build HTTP server based applications.
It is based on [Hyper](https://hyper.rs/), which allows for HTTP/1.0, HTTP/1.1 and HTTP/2. However,
some advanced features that Hyper provides are still not accesible.
It is based on [Warp](https://github.com/seanmonstar/warp), which allows for HTTP/1.0, HTTP/1.1 and HTTP/2. However,
some advanced features that Warp provides are still not accesible.
## Usage
@@ -46,7 +46,6 @@ recommeded to use the helper predicates, which are easier to understand and clea
Some things that are still missing:
- Read forms in multipart format
- HTTP Basic Auth
- Session handling via cookies
- HTML Templating (but you can use [Teruel](https://github.com/aarroyoc/teruel/), [Marquete](https://github.com/aarroyoc/marquete/) or [Djota](https://github.com/aarroyoc/djota) for that)
*/
@@ -54,14 +53,19 @@ Some things that are still missing:
:- module(http_server, [
http_listen/2,
http_listen/3,
http_headers/2,
http_status_code/2,
http_body/2,
http_redirect/2,
http_query/3
http_query/3,
http_basic_auth/4
]).
:- meta_predicate http_listen(?, :).
:- meta_predicate http_listen(?, :, ?).
:- meta_predicate http_basic_auth(:, :, ?, ?).
:- use_module(library(charsio)).
:- use_module(library(crypto)).
@@ -74,25 +78,58 @@ Some things that are still missing:
%% http_listen(+Port, +Handlers).
%
% Listens for HTTP connections on port Port. Each handler on the list Handlers should be of the form: `HttpVerb(PathUnification, Predicate)`.
% For example: `get(user/User, get_info(User))` will match an HTTP request that is a GET, the path unifies with /user/User (where User is a variable)
% and it will call `get_info` with three arguments: an `http_request` term, an `http_response` term and User.
% Equivalent to `http_listen(Port, Handlers, [])`.
http_listen(Port, Module:Handlers0) :-
must_be(integer, Port),
must_be(list, Handlers0),
maplist(module_qualification(Module), Handlers0, Handlers),
http_listen_(Port, Handlers).
http_listen_(Port, Handlers, []).
%% http_listen(+Port, +Handlers, +Options).
%
% Listens for HTTP connections on port Port. Each handler on the list Handlers should be of the form: `HttpVerb(PathUnification, Predicate)`.
% For example: `get(user/User, get_info(User))` will match an HTTP request that is a GET, the path unifies with /user/User (where User is a variable)
% and it will call `get_info` with three arguments: an `http_request` term, an `http_response` term and User.
%
% The following options are supported:
%
% - `tls_key(+Key)` - a TLS key for HTTPS (string)
% - `tls_cert(+Cert)` - a TLS cert for HTTPS (string)
% - `content_length_limit(+Limit)` - maximum length (in bytes) for the incoming bodies. By default, 32KB.
%
% In order to have a HTTPS server (instead of plain HTTP), both `tls_key` and `tls_cert` options must be provided.
http_listen(Port, Module:Handlers0, Options) :-
must_be(integer, Port),
must_be(list, Handlers0),
must_be(list, Options),
maplist(module_qualification(Module), Handlers0, Handlers),
http_listen_(Port, Handlers, Options).
module_qualification(M, H0, H) :-
H0 =.. [Method, Path, Goal],
H =.. [Method, Path, M:Goal].
http_listen_(Port, Handlers) :-
http_listen_(Port, Handlers, Options) :-
parse_options(Options, TLSKey, TLSCert, ContentLengthLimit),
phrase(format_("0.0.0.0:~d", [Port]), Addr),
'$http_listen'(Addr, HttpListener),!,
'$http_listen'(Addr, HttpListener, TLSKey, TLSCert, ContentLengthLimit),!,
format("Listening at ~s\n", [Addr]),
http_loop(HttpListener, Handlers).
parse_options(Options, TLSKey, TLSCert, ContentLengthLimit) :-
member_option_default(tls_key, Options, "", TLSKey),
member_option_default(tls_cert, Options, "", TLSCert),
member_option_default(content_length_limit, Options, 32768, ContentLengthLimit),
must_be(integer, ContentLengthLimit).
member_option_default(Key, List, _Default, Value) :-
X =.. [Key, Value],
member(X, List).
member_option_default(Key, List, Default, Default) :-
X =.. [Key, _],
\+ member(X, List).
http_loop(HttpListener, Handlers) :-
'$http_accept'(HttpListener, RequestMethod, RequestPath, RequestHeaders, RequestQuery, RequestStream, ResponseHandle),
current_time(Time),
@@ -114,7 +151,7 @@ http_loop(HttpListener, Handlers) :-
)
; (
'$http_answer'(ResponseHandle, 404, [], ResponseStream),
call_cleanup(format(ResponseStream, "Not Found"), close(ResponseStream)))
call_cleanup(format(ResponseStream, "Not Found", []), close(ResponseStream)))
),
http_loop(HttpListener, Handlers).
@@ -352,3 +389,49 @@ url_decode([Char|Chars]) -->
url_decode(Chars).
url_decode([]) --> [].
%% http_basic_auth(+LoginPredicate, +Handler, +Request, -Response)
%
% Metapredicate that wraps an existing Handler with an HTTP Basic Auth flow.
% Checks if a given user + password is authorized to execute that handler, returning 401
% if it's not satisfied.
%
% `LoginPredicate` must be a predicate of arity 2 that takes a User and a Password.
% `Handler` will have, in addition to the Request and Response arguments, a User argument
% containing the User given in the authentication.
%
% Example:
%
% ```
% main :-
% http_listen(8800,[get('/', http_basic_auth(login, inside_handler("data")))]).
%
% login(User, Pass) :-
% User = "aarroyoc",
% Pass = "123456".
%
% inside_handler(Data, User, Request, Response) :-
% http_body(Response, text(User)).
% ```
http_basic_auth(LoginPredicate, Handler, Request, Response) :-
http_headers(Request, Headers),
member("authorization"-AuthorizationStr, Headers),
append("Basic ", Coded, AuthorizationStr),
chars_base64(UserPass, Coded, []),
append(User, [':'|Password], UserPass),
(
call(LoginPredicate, User, Password) ->
call(Handler, User, Request, Response)
; http_basic_auth_unauthorized_response(Response)
).
http_basic_auth(_LoginPredicate, _Handler, Request, Response) :-
http_headers(Request, Headers),
\+ member("authorization"-_, Headers),
http_basic_auth_unauthorized_response(Response).
http_basic_auth_unauthorized_response(Response) :-
http_status_code(Response, 401),
http_headers(Response, ["www-authenticate"-"Basic realm=\"Scryer Prolog\", charset=\"UTF-8\""]),
http_body(Response, text("Unauthorized")).

View File

@@ -5499,6 +5499,17 @@ impl Machine {
if interruption {
self.machine_st.throw_interrupt_exception();
self.machine_st.backtrack();
#[cfg(not(target_arch = "wasm32"))]
let runtime = tokio::runtime::Runtime::new().unwrap();
#[cfg(target_arch = "wasm32")]
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
let old_runtime = std::mem::replace(&mut self.runtime, runtime);
old_runtime.shutdown_background();
}
}
Err(_) => unreachable!(),

View File

@@ -30,6 +30,9 @@ use std::ptr;
#[cfg(feature = "tls")]
use native_tls::TlsStream;
#[cfg(feature = "http")]
use warp::hyper;
#[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)]
#[bits = 1]
pub enum StreamType {
@@ -290,9 +293,9 @@ impl Read for HttpReadStream {
#[cfg(feature = "http")]
pub struct HttpWriteStream {
status_code: u16,
headers: hyper::HeaderMap,
headers: mem::ManuallyDrop<hyper::HeaderMap>,
response: TypedArenaPtr<HttpResponse>,
buffer: Vec<u8>,
buffer: mem::ManuallyDrop<Vec<u8>>,
}
#[cfg(feature = "http")]
@@ -312,23 +315,32 @@ impl Write for HttpWriteStream {
#[inline]
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
#[cfg(feature = "http")]
impl HttpWriteStream {
fn drop(&mut self) {
let headers = unsafe { mem::ManuallyDrop::take(&mut self.headers) };
let buffer = unsafe { mem::ManuallyDrop::take(&mut self.buffer) };
let (ready, response, cvar) = &**self.response;
let mut ready = ready.lock().unwrap();
{
let mut response = response.lock().unwrap();
let bytes = bytes::Bytes::copy_from_slice(&self.buffer);
let mut response_ = hyper::Response::builder().status(self.status_code);
*response_.headers_mut().unwrap() = self.headers.clone();
*response = Some(response_.body(http_body_util::Full::new(bytes)).unwrap());
let mut response_ = warp::http::Response::builder()
.status(self.status_code);
*response_.headers_mut().unwrap() = headers;
*response = Some(response_.body(warp::hyper::Body::from(buffer)).unwrap());
}
*ready = true;
cvar.notify_one();
}
}
Ok(())
}
}
#[derive(Debug)]
pub struct StandardOutputStream {}
@@ -1247,8 +1259,8 @@ impl Stream {
StreamLayout::new(CharReader::new(HttpWriteStream {
response,
status_code,
headers,
buffer: Vec::new(),
headers: mem::ManuallyDrop::new(headers),
buffer: mem::ManuallyDrop::new(Vec::new()),
})),
arena
))
@@ -1300,6 +1312,7 @@ impl Stream {
}
#[cfg(feature = "http")]
Stream::HttpWrite(ref mut http_stream) => {
http_stream.inner_mut().drop();
unsafe {
http_stream.set_tag(ArenaHeaderTag::Dropped);
std::ptr::drop_in_place(&mut http_stream.inner_mut().buffer as *mut _);

View File

@@ -14,7 +14,7 @@ use crate::forms::*;
use crate::heap_iter::*;
use crate::heap_print::*;
#[cfg(feature = "http")]
use crate::http::{HttpListener, HttpResponse, HttpService};
use crate::http::{HttpRequestData, HttpListener, HttpResponse, HttpRequest};
use crate::instructions::*;
use crate::machine;
use crate::machine::code_walker::*;
@@ -44,14 +44,14 @@ pub(crate) use ref_thread_local::RefThreadLocal;
use std::cell::Cell;
use std::cmp::Ordering;
use std::collections::BTreeSet;
use std::collections::{BTreeSet};
use std::convert::TryFrom;
use std::env;
#[cfg(feature = "ffi")]
use std::ffi::CString;
use std::fs;
use std::hash::{BuildHasher, BuildHasherDefault};
use std::io::{ErrorKind, Read, Write};
use std::io::{ErrorKind, Read, BufRead, Write};
use std::iter::{once, FromIterator};
use std::mem;
use std::net::{SocketAddr, TcpListener, TcpStream, ToSocketAddrs};
@@ -59,6 +59,7 @@ use std::num::NonZeroU32;
use std::ops::Sub;
use std::process;
use std::str::FromStr;
use std::sync::{Mutex, Arc, Condvar};
use chrono::{offset::Local, DateTime};
#[cfg(not(target_arch = "wasm32"))]
@@ -91,16 +92,15 @@ use base64;
use roxmltree;
use select;
use bytes::Buf;
use http_body_util::BodyExt;
#[cfg(feature = "http")]
use hyper::header::{HeaderName, HeaderValue};
use warp::hyper::header::{HeaderValue, HeaderName};
#[cfg(feature = "http")]
use hyper::server::conn::http1;
use warp::hyper::{HeaderMap, Method};
#[cfg(feature = "http")]
use hyper::{HeaderMap, Method};
use warp::{Buf, Filter};
#[cfg(feature = "http")]
use reqwest::Url;
use futures::future;
#[cfg(feature = "repl")]
pub(crate) fn get_key() -> KeyEvent {
@@ -4412,13 +4412,50 @@ impl Machine {
#[inline(always)]
pub(crate) fn http_listen(&mut self) -> CallResult {
let address_sink = self.deref_register(1);
let tls_key = self.deref_register(3);
let tls_cert = self.deref_register(4);
let content_length_limit = self.deref_register(5);
const CONTENT_LENGTH_LIMIT_DEFAULT: u64 = 32768;
let content_length_limit = match Number::try_from(content_length_limit) {
Ok(Number::Fixnum(n)) => if n.get_num() >= 0 {
n.get_num() as u64
} else {
CONTENT_LENGTH_LIMIT_DEFAULT
},
Ok(Number::Integer(n)) => {
let n: Result<u64, _> = (&*n).try_into();
match n {
Ok(u) => u,
Err(_) => CONTENT_LENGTH_LIMIT_DEFAULT,
}
}
_ => CONTENT_LENGTH_LIMIT_DEFAULT,
};
let ssl_server: Option<(String,String)> = {
match self.machine_st.value_to_str_like(tls_key) {
Some(key) => {
match self.machine_st.value_to_str_like(tls_cert) {
Some(cert) => {
let key_str = key.as_str();
let cert_str = cert.as_str();
if key_str.is_empty() || cert_str.is_empty() {
None
} else {
Some((key_str.to_string(), cert_str.to_string()))
}
}
None => None
}
}
None => None
}
};
if let Some(address_str) = self.machine_st.value_to_str_like(address_sink) {
let address_string = address_str.as_str();
let addr: SocketAddr = match address_string
.to_socket_addrs()
.ok()
.and_then(|mut s| s.next())
{
let addr: SocketAddr = match address_string.to_socket_addrs().ok().and_then(|mut s| s.next()) {
Some(addr) => addr,
_ => {
self.machine_st.fail = true;
@@ -4428,36 +4465,64 @@ impl Machine {
let (tx, rx) = std::sync::mpsc::sync_channel(1024);
let _guard = self.runtime.enter();
let listener = match self
.runtime
.block_on(async { tokio::net::TcpListener::bind(addr).await })
{
Ok(listener) => listener,
Err(_) => {
return Err(self.machine_st.open_permission_error(
address_sink,
atom!("http_listen"),
2,
));
fn get_reader(body: impl Buf + Send + 'static) -> Box<dyn BufRead + Send> {
Box::new(body.reader())
}
let serve = warp::body::aggregate()
.and(warp::header::optional::<u64>(warp::http::header::CONTENT_LENGTH.as_str()))
.and(warp::method())
.and(warp::header::headers_cloned())
.and(warp::path::full())
.and(warp::query::raw().or_else(|_| future::ready(Ok::<(String,), warp::Rejection>(("".to_string(),)))))
.map(move |body, content_length, method, headers: warp::http::HeaderMap, path: warp::filters::path::FullPath, query| {
if let Some(content_length) = content_length {
if content_length > content_length_limit {
return warp::http::Response::builder()
.status(413)
.body(warp::hyper::Body::empty())
.unwrap();
}
}
let http_request_data = HttpRequestData {
method,
headers,
path: path.as_str().to_string(),
query,
body: get_reader(body),
};
let response = Arc::new((Mutex::new(false), Mutex::new(None), Condvar::new()));
let http_request = HttpRequest { request_data: http_request_data, response: Arc::clone(&response) };
// we send the request to http_accept
tx.send(http_request).unwrap();
// we wait for the Response info from Prolog
{
let (ready, _response, cvar) = &*response;
let mut ready = ready.lock().unwrap();
while !*ready {
ready = cvar.wait(ready).unwrap();
}
}
{
let (_, response, _) = &*response;
let response = response.lock().unwrap().take();
response.expect("Data race error in HTTP server")
}
});
self.runtime.spawn(async move {
loop {
let tx = tx.clone();
let (stream, _) = listener.accept().await.unwrap();
match ssl_server {
Some((key, cert)) => {
warp::serve(serve).tls().key(key).cert(cert).run(addr).await
}
None => {
warp::serve(serve).run(addr).await
}
}
});
tokio::task::spawn(async move {
if let Err(err) = http1::Builder::new()
.serve_connection(stream, HttpService { tx })
.await
{
eprintln!("Error serving connection: {:?}", err);
}
});
}
});
let http_listener = HttpListener { incoming: rx };
let http_listener = arena_alloc!(http_listener, &mut self.machine_st.arena);
let addr = self.deref_register(2);
@@ -4482,26 +4547,26 @@ impl Machine {
(HeapCellValueTag::Cons, cons_ptr) => {
match_untyped_arena_ptr!(cons_ptr,
(ArenaHeaderTag::HttpListener, http_listener) => {
match http_listener.incoming.recv() {
loop {
match http_listener.incoming.recv_timeout(std::time::Duration::from_millis(200)) {
Ok(request) => {
let method_atom = match *request.request.method() {
let method_atom = match request.request_data.method {
Method::GET => atom!("get"),
Method::POST => atom!("post"),
Method::PUT => atom!("put"),
Method::DELETE => atom!("delete"),
Method::PATCH => atom!("patch"),
Method::HEAD => atom!("head"),
_ => unreachable!(),
Method::OPTIONS => atom!("options"),
Method::TRACE => atom!("trace"),
Method::CONNECT => atom!("connect"),
_ => atom!("unsupported_extension"),
};
let path_atom = AtomTable::build_with(&self.machine_st.atom_tbl, request.request.uri().path());
let path_atom = AtomTable::build_with(&self.machine_st.atom_tbl, &request.request_data.path);
let path_cell = atom_as_cstr_cell!(path_atom);
let headers: Vec<HeapCellValue> = request.request.headers().iter().map(|(header_name, header_value)| {
let headers: Vec<HeapCellValue> = request.request_data.headers.iter().map(|(header_name, header_value)| {
let h = self.machine_st.heap.len();
let header_term = functor!(
AtomTable::build_with(&self.machine_st.atom_tbl, header_name.as_str()),
[cell(string_as_cstr_cell!(AtomTable::build_with(&self.machine_st.atom_tbl, header_value.to_str().unwrap())))]
);
let header_term = functor!(AtomTable::build_with(&self.machine_st.atom_tbl, header_name.as_str()), [cell(string_as_cstr_cell!(AtomTable::build_with(&self.machine_st.atom_tbl, header_value.to_str().unwrap())))]);
self.machine_st.heap.extend(header_term.into_iter());
str_loc_as_cell!(h)
@@ -4509,17 +4574,13 @@ impl Machine {
let headers_list = iter_to_heap_list(&mut self.machine_st.heap, headers.into_iter());
let query_str = request.request.uri().query().unwrap_or("");
let query_atom = AtomTable::build_with(&self.machine_st.atom_tbl, query_str);
let query_str = request.request_data.query;
let query_atom = AtomTable::build_with(&self.machine_st.atom_tbl, &query_str);
let query_cell = string_as_cstr_cell!(query_atom);
let hyper_req = request.request;
let buf = self.runtime.block_on(async {hyper_req.collect().await.unwrap().aggregate()});
let reader = buf.reader();
let mut stream = Stream::from_http_stream(
path_atom,
Box::new(reader),
request.request_data.body,
&mut self.machine_st.arena
);
*stream.options_mut() = StreamOptions::default();
@@ -4535,12 +4596,36 @@ impl Machine {
self.machine_st.bind(query.as_var().unwrap(), query_cell);
self.machine_st.bind(stream_addr.as_var().unwrap(), stream);
self.machine_st.bind(handle_addr.as_var().unwrap(), typed_arena_ptr_as_cell!(handle));
break
}
Err(std::sync::mpsc::RecvTimeoutError::Timeout) => {
let interrupted = machine::INTERRUPT.load(std::sync::atomic::Ordering::Relaxed);
match machine::INTERRUPT.compare_exchange(
interrupted,
false,
std::sync::atomic::Ordering::Relaxed,
std::sync::atomic::Ordering::Relaxed,
) {
Ok(interruption) => {
if interruption {
self.machine_st.throw_interrupt_exception();
self.machine_st.backtrack();
let old_runtime = std::mem::replace(&mut self.runtime, tokio::runtime::Runtime::new().unwrap());
old_runtime.shutdown_background();
break
}
}
Err(_) => unreachable!(),
}
}
Err(_) => {
self.machine_st.fail = true;
}
}
}
}
_ => {
unreachable!();
}