]> Repositorios git - scryer-prolog.git/commitdiff
Replace Hyper with Warp for HTTP server
authorAdrián Arroyo Calle <[email protected]>
Tue, 5 Sep 2023 18:40:58 +0000 (20:40 +0200)
committerAdrián Arroyo Calle <[email protected]>
Wed, 27 Sep 2023 16:50:19 +0000 (18:50 +0200)
- Use Warp
- Optimize clones
- HTTPS server
- Content-Length limit
- HTTP Basic Auth
- Stop server with Ctrl-C

Cargo.lock
Cargo.toml
README.md
build/instructions_template.rs
src/http.rs
src/lib/http/http_server.pl
src/machine/dispatch.rs
src/machine/streams.rs
src/machine/system_calls.rs

index c383d82e3cbea86398dfc17001e124e3a9511a11..e054b9db063d473c2b4ec07c71b8212dd571dca4 100644 (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]]
@@ -2443,11 +2528,45 @@ dependencies = [
  "tokio",
 ]
 
+[[package]]
+name = "tokio-rustls"
+version = "0.23.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+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.8"
+version = "0.7.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d"
+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",
 ]
@@ -2489,11 +2609,39 @@ version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
 
+[[package]]
+name = "tungstenite"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788"
+dependencies = [
+ "base64 0.13.1",
+ "byteorder",
+ "bytes",
+ "http",
+ "httparse",
+ "log",
+ "rand",
+ "sha1",
+ "thiserror",
+ "url",
+ "utf-8",
+]
+
 [[package]]
 name = "typenum"
-version = "1.16.0"
+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 = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
+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",
 ]
index 92b35dedb3232f04a05add107eb95de2fee7382a..dbf7cfc05739f3f78134dc8021afd1f579ca848c 100644 (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"] }
 
index 4ba1f9d69a51a715bed04d57b6a59b65201cd0a3..81236b65a129dae3a206a63733c601664d878358 100644 (file)
--- a/README.md
+++ b/README.md
@@ -624,7 +624,7 @@ The modules that ship with Scryer&nbsp;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&nbsp;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&nbsp;documents
   as Prolog&nbsp;terms for convenient and efficient reasoning. Use
index f0a5a49f8576918b6cb43618420ce257c2cbe196..894254c77db7b8dd6d37dbd2b32b49589e510b18 100644 (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,
index 13d6ff312ab0ae4b9a942e4cb88899d5deeaa85b..46888f122082d99875bf450c148a5232fa443924 100644 (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 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();
+pub type HttpResponse = Arc<(Mutex<bool>, Mutex<Option<warp::reply::Response>>, Condvar)>;
 
-        // 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>,
 }
index 381d56077370f276ee30b6cdfe3b4c9fb0b0b427..faa76ce5a769d873791d4800ca6618b8a80880ef 100644 (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).
 %
+% 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, +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. 
-http_listen(Port, Module:Handlers0) :-
+% 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).
+    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")).
+       
index 89174091710354360b07279997d3c2fb4b2d223c..1ac431897877afa7a321d92d5ca43bb81f7015c9 100644 (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!(),
index b56324179a85dee621243675bcfa61fcad96cc10..1dfbfaa914dac7ce5a39239d56a623d4c83de31c 100644 (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,24 +315,33 @@ impl Write for HttpWriteStream {
 
     #[inline]
     fn flush(&mut self) -> std::io::Result<()> {
-        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());
-        }
-        *ready = true;
-        cvar.notify_one();
+       Ok(())
+    }
+}
 
-        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 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();
     }
 }
 
+
 #[derive(Debug)]
 pub struct StandardOutputStream {}
 
@@ -1243,15 +1255,15 @@ impl Stream {
         headers: hyper::HeaderMap,
         arena: &mut Arena,
     ) -> Self {
-        Stream::HttpWrite(arena_alloc!(
-            StreamLayout::new(CharReader::new(HttpWriteStream {
-                response,
-                status_code,
-                headers,
-                buffer: Vec::new(),
-            })),
-            arena
-        ))
+       Stream::HttpWrite(arena_alloc!(
+           StreamLayout::new(CharReader::new(HttpWriteStream {
+               response,
+               status_code,
+               headers: mem::ManuallyDrop::new(headers),
+               buffer: mem::ManuallyDrop::new(Vec::new()),
+           })),
+           arena
+       ))
     }
 
     #[inline]
@@ -1299,7 +1311,8 @@ impl Stream {
                 Ok(())
             }
             #[cfg(feature = "http")]
-            Stream::HttpWrite(ref mut http_stream) => {
+           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 _);
index 34b26808d5603e0c41a25cea960e783035c4a42a..897dab67365c30056529e811e2029d92f3886e13 100644 (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,54 +4412,119 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn http_listen(&mut self) -> CallResult {
         let address_sink = self.deref_register(1);
-        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())
-            {
-                Some(addr) => addr,
+       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()) {
+               Some(addr) => addr,
                 _ => {
                     self.machine_st.fail = true;
                     return Ok(());
                 }
             };
 
-            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,
-                    ));
-                }
-            };
-
-            self.runtime.spawn(async move {
-                loop {
-                    let tx = tx.clone();
-                    let (stream, _) = listener.accept().await.unwrap();
-
-                    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 (tx, rx) = std::sync::mpsc::sync_channel(1024);
+
+           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 {
+               match ssl_server {
+                   Some((key, cert)) => {
+                       warp::serve(serve).tls().key(key).cert(cert).run(addr).await
+                   }
+                   None => {
+                       warp::serve(serve).run(addr).await
+                   }
+               }
+           });
+
+           let http_listener = HttpListener { incoming: rx };
+           let http_listener = arena_alloc!(http_listener, &mut self.machine_st.arena);
             let addr = self.deref_register(2);
             self.machine_st.bind(
                 addr.as_var().unwrap(),
@@ -4472,75 +4537,95 @@ impl Machine {
     #[cfg(feature = "http")]
     #[inline(always)]
     pub(crate) fn http_accept(&mut self) -> CallResult {
-        let culprit = self.deref_register(1);
-        let method = self.deref_register(2);
-        let path = self.deref_register(3);
-        let query = self.deref_register(5);
-        let stream_addr = self.deref_register(6);
-        let handle_addr = self.deref_register(7);
-        read_heap_cell!(culprit,
-            (HeapCellValueTag::Cons, cons_ptr) => {
-            match_untyped_arena_ptr!(cons_ptr,
-                (ArenaHeaderTag::HttpListener, http_listener) => {
-                    match http_listener.incoming.recv() {
-                    Ok(request) => {
-                        let method_atom = match *request.request.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!(),
-                    };
-                    let path_atom = AtomTable::build_with(&self.machine_st.atom_tbl, request.request.uri().path());
-                    let path_cell = atom_as_cstr_cell!(path_atom);
-                    let headers: Vec<HeapCellValue> = request.request.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())))]
-                        );
-
-                        self.machine_st.heap.extend(header_term.into_iter());
-                        str_loc_as_cell!(h)
-                    }).collect();
-
-                    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_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),
-                        &mut self.machine_st.arena
-                    );
-                    *stream.options_mut() = StreamOptions::default();
-                    stream.options_mut().set_stream_type(StreamType::Binary);
-                    self.indices.streams.insert(stream);
-                    let stream = stream_as_cell!(stream);
-
-                    let handle = arena_alloc!(request.response, &mut self.machine_st.arena);
-
-                    self.machine_st.bind(method.as_var().unwrap(), atom_as_cell!(method_atom));
-                    self.machine_st.bind(path.as_var().unwrap(), path_cell);
-                    unify!(self.machine_st, heap_loc_as_cell!(headers_list), self.machine_st.registers[4]);
-                    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));
-                    }
-                    Err(_) => {
-                        self.machine_st.fail = true;
+       let culprit = self.deref_register(1);
+       let method = self.deref_register(2);
+       let path = self.deref_register(3);
+       let query = self.deref_register(5);
+       let stream_addr = self.deref_register(6);
+       let handle_addr = self.deref_register(7);
+       read_heap_cell!(culprit,
+           (HeapCellValueTag::Cons, cons_ptr) => {
+               match_untyped_arena_ptr!(cons_ptr,
+                   (ArenaHeaderTag::HttpListener, http_listener) => {
+                       loop {
+                       match http_listener.incoming.recv_timeout(std::time::Duration::from_millis(200)) {
+                           Ok(request) => {
+                               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"),
+                                   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_data.path);
+                               let path_cell = atom_as_cstr_cell!(path_atom);
+                               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())))]);
+
+                                    self.machine_st.heap.extend(header_term.into_iter());
+                                    str_loc_as_cell!(h)
+                                }).collect();
+
+                                let headers_list = iter_to_heap_list(&mut self.machine_st.heap, headers.into_iter());
+
+                               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 mut stream = Stream::from_http_stream(
+                                   path_atom,
+                                   request.request_data.body,
+                                   &mut self.machine_st.arena
+                               );
+                               *stream.options_mut() = StreamOptions::default();
+                               stream.options_mut().set_stream_type(StreamType::Binary);
+                               self.indices.streams.insert(stream);
+                               let stream = stream_as_cell!(stream);
+
+                                let handle = arena_alloc!(request.response, &mut self.machine_st.arena);
+
+                                self.machine_st.bind(method.as_var().unwrap(), atom_as_cell!(method_atom));
+                                self.machine_st.bind(path.as_var().unwrap(), path_cell);
+                                unify!(self.machine_st, heap_loc_as_cell!(headers_list), self.machine_st.registers[4]);
+                                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!();
                 }