mirror of
https://github.com/amigan/rustypaste-pretty.git
synced 2024-11-22 04:19:47 -05:00
feat(paste): support pasting files from remote URLs
This commit is contained in:
parent
bd86c27b08
commit
7a6842e181
6 changed files with 202 additions and 102 deletions
174
Cargo.lock
generated
174
Cargo.lock
generated
|
@ -14,7 +14,7 @@ dependencies = [
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"log",
|
"log",
|
||||||
"pin-project 0.4.28",
|
"pin-project 0.4.28",
|
||||||
"tokio 0.2.25",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "177837a10863f15ba8d3ae3ec12fac1099099529ed20083a27fdfe247381d0dc"
|
checksum = "177837a10863f15ba8d3ae3ec12fac1099099529ed20083a27fdfe247381d0dc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-codec",
|
"actix-codec",
|
||||||
"actix-rt 1.1.1",
|
"actix-rt",
|
||||||
"actix-service",
|
"actix-service",
|
||||||
"actix-utils",
|
"actix-utils",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
|
@ -33,8 +33,11 @@ dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http",
|
||||||
"log",
|
"log",
|
||||||
|
"rustls",
|
||||||
|
"tokio-rustls",
|
||||||
"trust-dns-proto",
|
"trust-dns-proto",
|
||||||
"trust-dns-resolver",
|
"trust-dns-resolver",
|
||||||
|
"webpki",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -65,11 +68,12 @@ checksum = "5cb8958da437716f3f31b0e76f8daf36554128517d7df37ceba7df00f09622ee"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-codec",
|
"actix-codec",
|
||||||
"actix-connect",
|
"actix-connect",
|
||||||
"actix-rt 1.1.1",
|
"actix-rt",
|
||||||
"actix-service",
|
"actix-service",
|
||||||
"actix-threadpool",
|
"actix-threadpool",
|
||||||
|
"actix-tls",
|
||||||
"actix-utils",
|
"actix-utils",
|
||||||
"base64",
|
"base64 0.13.0",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"brotli2",
|
"brotli2",
|
||||||
"bytes 0.5.6",
|
"bytes 0.5.6",
|
||||||
|
@ -114,16 +118,6 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "actix-macros"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c2f86cd6857c135e6e9fe57b1619a88d1f94a7df34c00e11fe13e64fd3438837"
|
|
||||||
dependencies = [
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "actix-multipart"
|
name = "actix-multipart"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -161,24 +155,13 @@ version = "1.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "143fcc2912e0d1de2bcf4e2f720d2a60c28652ab4179685a1ee159e0fb3db227"
|
checksum = "143fcc2912e0d1de2bcf4e2f720d2a60c28652ab4179685a1ee159e0fb3db227"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-macros 0.1.3",
|
"actix-macros",
|
||||||
"actix-threadpool",
|
"actix-threadpool",
|
||||||
"copyless",
|
"copyless",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"tokio 0.2.25",
|
"tokio",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "actix-rt"
|
|
||||||
version = "2.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ea360596a50aa9af459850737f99293e5cb9114ae831118cb6026b3bbc7583ad"
|
|
||||||
dependencies = [
|
|
||||||
"actix-macros 0.2.1",
|
|
||||||
"futures-core",
|
|
||||||
"tokio 1.10.1",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -188,13 +171,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "45407e6e672ca24784baa667c5d32ef109ccdd8d5e0b5ebb9ef8a67f4dfb708e"
|
checksum = "45407e6e672ca24784baa667c5d32ef109ccdd8d5e0b5ebb9ef8a67f4dfb708e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-codec",
|
"actix-codec",
|
||||||
"actix-rt 1.1.1",
|
"actix-rt",
|
||||||
"actix-service",
|
"actix-service",
|
||||||
"actix-utils",
|
"actix-utils",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"log",
|
"log",
|
||||||
"mio 0.6.23",
|
"mio",
|
||||||
"mio-uds",
|
"mio-uds",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"slab",
|
"slab",
|
||||||
|
@ -217,8 +200,8 @@ version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "47239ca38799ab74ee6a8a94d1ce857014b2ac36f242f70f3f75a66f691e791c"
|
checksum = "47239ca38799ab74ee6a8a94d1ce857014b2ac36f242f70f3f75a66f691e791c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-macros 0.1.3",
|
"actix-macros",
|
||||||
"actix-rt 1.1.1",
|
"actix-rt",
|
||||||
"actix-server",
|
"actix-server",
|
||||||
"actix-service",
|
"actix-service",
|
||||||
"log",
|
"log",
|
||||||
|
@ -250,6 +233,10 @@ dependencies = [
|
||||||
"actix-service",
|
"actix-service",
|
||||||
"actix-utils",
|
"actix-utils",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
"rustls",
|
||||||
|
"tokio-rustls",
|
||||||
|
"webpki",
|
||||||
|
"webpki-roots",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -259,7 +246,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2e9022dec56632d1d7979e59af14f0597a28a830a9c1c7fec8b2327eb9f16b5a"
|
checksum = "2e9022dec56632d1d7979e59af14f0597a28a830a9c1c7fec8b2327eb9f16b5a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-codec",
|
"actix-codec",
|
||||||
"actix-rt 1.1.1",
|
"actix-rt",
|
||||||
"actix-service",
|
"actix-service",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"bytes 0.5.6",
|
"bytes 0.5.6",
|
||||||
|
@ -280,9 +267,9 @@ checksum = "e641d4a172e7faa0862241a20ff4f1f5ab0ab7c279f00c2d4587b77483477b86"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-codec",
|
"actix-codec",
|
||||||
"actix-http",
|
"actix-http",
|
||||||
"actix-macros 0.1.3",
|
"actix-macros",
|
||||||
"actix-router",
|
"actix-router",
|
||||||
"actix-rt 1.1.1",
|
"actix-rt",
|
||||||
"actix-server",
|
"actix-server",
|
||||||
"actix-service",
|
"actix-service",
|
||||||
"actix-testing",
|
"actix-testing",
|
||||||
|
@ -302,6 +289,7 @@ dependencies = [
|
||||||
"mime",
|
"mime",
|
||||||
"pin-project 1.0.8",
|
"pin-project 1.0.8",
|
||||||
"regex",
|
"regex",
|
||||||
|
"rustls",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
|
@ -379,9 +367,9 @@ checksum = "b381e490e7b0cfc37ebc54079b0413d8093ef43d14a4e4747083f7fa47a9e691"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-codec",
|
"actix-codec",
|
||||||
"actix-http",
|
"actix-http",
|
||||||
"actix-rt 1.1.1",
|
"actix-rt",
|
||||||
"actix-service",
|
"actix-service",
|
||||||
"base64",
|
"base64 0.13.0",
|
||||||
"bytes 0.5.6",
|
"bytes 0.5.6",
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
|
@ -390,6 +378,7 @@ dependencies = [
|
||||||
"mime",
|
"mime",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
|
"rustls",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
|
@ -401,6 +390,12 @@ version = "0.2.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b"
|
checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
|
@ -844,7 +839,7 @@ dependencies = [
|
||||||
"http",
|
"http",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"slab",
|
"slab",
|
||||||
"tokio 0.2.25",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-futures",
|
"tracing-futures",
|
||||||
|
@ -1120,25 +1115,12 @@ dependencies = [
|
||||||
"kernel32-sys",
|
"kernel32-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"miow 0.2.2",
|
"miow",
|
||||||
"net2",
|
"net2",
|
||||||
"slab",
|
"slab",
|
||||||
"winapi 0.2.8",
|
"winapi 0.2.8",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mio"
|
|
||||||
version = "0.7.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"log",
|
|
||||||
"miow 0.3.7",
|
|
||||||
"ntapi",
|
|
||||||
"winapi 0.3.9",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio-uds"
|
name = "mio-uds"
|
||||||
version = "0.6.8"
|
version = "0.6.8"
|
||||||
|
@ -1147,7 +1129,7 @@ checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iovec",
|
"iovec",
|
||||||
"libc",
|
"libc",
|
||||||
"mio 0.6.23",
|
"mio",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1162,15 +1144,6 @@ dependencies = [
|
||||||
"ws2_32-sys",
|
"ws2_32-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "miow"
|
|
||||||
version = "0.3.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
|
|
||||||
dependencies = [
|
|
||||||
"winapi 0.3.9",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "net2"
|
name = "net2"
|
||||||
version = "0.2.37"
|
version = "0.2.37"
|
||||||
|
@ -1203,15 +1176,6 @@ dependencies = [
|
||||||
"version_check 0.9.3",
|
"version_check 0.9.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ntapi"
|
|
||||||
version = "0.3.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
|
|
||||||
dependencies = [
|
|
||||||
"winapi 0.3.9",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.13.0"
|
version = "1.13.0"
|
||||||
|
@ -1535,13 +1499,26 @@ dependencies = [
|
||||||
"semver 0.11.0",
|
"semver 0.11.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls"
|
||||||
|
version = "0.18.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5d1126dcf58e93cee7d098dbda643b5f92ed724f1f6a63007c1116eed6700c81"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.12.3",
|
||||||
|
"log",
|
||||||
|
"ring",
|
||||||
|
"sct",
|
||||||
|
"webpki",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustypaste"
|
name = "rustypaste"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-files",
|
"actix-files",
|
||||||
"actix-multipart",
|
"actix-multipart",
|
||||||
"actix-rt 2.3.0",
|
"actix-rt",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"byte-unit",
|
"byte-unit",
|
||||||
"config",
|
"config",
|
||||||
|
@ -1574,6 +1551,16 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sct"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce"
|
||||||
|
dependencies = [
|
||||||
|
"ring",
|
||||||
|
"untrusted",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
@ -1904,7 +1891,7 @@ dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"memchr",
|
"memchr",
|
||||||
"mio 0.6.23",
|
"mio",
|
||||||
"mio-uds",
|
"mio-uds",
|
||||||
"pin-project-lite 0.1.12",
|
"pin-project-lite 0.1.12",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
|
@ -1913,19 +1900,15 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio-rustls"
|
||||||
version = "1.10.1"
|
version = "0.14.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "92036be488bb6594459f2e03b60e42df6f937fe6ca5c5ffdcb539c6b84dc40f5"
|
checksum = "e12831b255bcfa39dc0436b01e19fea231a37db570686c06ee72c423479f889a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"futures-core",
|
||||||
"libc",
|
"rustls",
|
||||||
"mio 0.7.13",
|
"tokio",
|
||||||
"once_cell",
|
"webpki",
|
||||||
"parking_lot",
|
|
||||||
"pin-project-lite 0.2.7",
|
|
||||||
"signal-hook-registry",
|
|
||||||
"winapi 0.3.9",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1939,7 +1922,7 @@ dependencies = [
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"log",
|
"log",
|
||||||
"pin-project-lite 0.1.12",
|
"pin-project-lite 0.1.12",
|
||||||
"tokio 0.2.25",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1998,7 +1981,7 @@ dependencies = [
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio 0.2.25",
|
"tokio",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2017,7 +2000,7 @@ dependencies = [
|
||||||
"resolv-conf",
|
"resolv-conf",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio 0.2.25",
|
"tokio",
|
||||||
"trust-dns-proto",
|
"trust-dns-proto",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2235,6 +2218,25 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "webpki"
|
||||||
|
version = "0.21.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea"
|
||||||
|
dependencies = [
|
||||||
|
"ring",
|
||||||
|
"untrusted",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "webpki-roots"
|
||||||
|
version = "0.20.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0f20dea7535251981a9670857150d571846545088359b28e4951d350bdaf179f"
|
||||||
|
dependencies = [
|
||||||
|
"webpki",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "widestring"
|
name = "widestring"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
|
|
|
@ -13,7 +13,7 @@ categories = ["web-programming::http-server"]
|
||||||
include = ["src/**/*", "Cargo.*", "LICENSE", "README.md", "CHANGELOG.md"]
|
include = ["src/**/*", "Cargo.*", "LICENSE", "README.md", "CHANGELOG.md"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-web = "3.3.2"
|
actix-web = { version = "3.3.2", features = ["rustls"] }
|
||||||
actix-multipart = "0.3.0"
|
actix-multipart = "0.3.0"
|
||||||
actix-files = "0.5.0"
|
actix-files = "0.5.0"
|
||||||
env_logger = "0.9.0"
|
env_logger = "0.9.0"
|
||||||
|
@ -45,7 +45,7 @@ version = "0.5.0"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix-rt = "2.3.0"
|
actix-rt = "1.1.1"
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
opt-level = 0
|
opt-level = 0
|
||||||
|
|
13
README.md
13
README.md
|
@ -85,24 +85,30 @@ $ curl -F "file=@x.txt" -H "expire:10min" "<server_address>"
|
||||||
|
|
||||||
(supported units: `ns`, `us`, `ms`, `sec`, `min`, `hours`, `days`, `weeks`, `months`, `years`)
|
(supported units: `ns`, `us`, `ms`, `sec`, `min`, `hours`, `days`, `weeks`, `months`, `years`)
|
||||||
|
|
||||||
#### One Shot
|
#### One shot
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ curl -F "oneshot=@x.txt" "<server_address>"
|
$ curl -F "oneshot=@x.txt" "<server_address>"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Cleaning Up Expired Files
|
#### Cleaning up expired files
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ find upload/ -maxdepth 2 -type f -iname "*.[0-9]*" -exec rm -v {} \;
|
$ find upload/ -maxdepth 2 -type f -iname "*.[0-9]*" -exec rm -v {} \;
|
||||||
```
|
```
|
||||||
|
|
||||||
#### URL Shortening
|
#### URL shortening
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ curl -F "url=https://example.com/some/long/url" "<server_address>"
|
$ curl -F "url=https://example.com/some/long/url" "<server_address>"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Paste file from remote URL
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ curl -F "remote=https://example.com/file.png" "<server_address>"
|
||||||
|
```
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
|
|
||||||
To start the server:
|
To start the server:
|
||||||
|
@ -178,7 +184,6 @@ http {
|
||||||
|
|
||||||
### Roadmap
|
### Roadmap
|
||||||
|
|
||||||
- Support uploading files from given URL
|
|
||||||
- Hot reload the configuration file
|
- Hot reload the configuration file
|
||||||
|
|
||||||
### Contributing
|
### Contributing
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use actix_web::client::ClientBuilder;
|
||||||
use actix_web::middleware::Logger;
|
use actix_web::middleware::Logger;
|
||||||
use actix_web::{App, HttpServer};
|
use actix_web::{App, HttpServer};
|
||||||
use rustypaste::config::Config;
|
use rustypaste::config::Config;
|
||||||
|
@ -6,6 +7,7 @@ use rustypaste::server;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::Result as IoResult;
|
use std::io::Result as IoResult;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
async fn main() -> IoResult<()> {
|
async fn main() -> IoResult<()> {
|
||||||
|
@ -19,8 +21,13 @@ async fn main() -> IoResult<()> {
|
||||||
fs::create_dir_all(paste_type.get_path(&server_config.upload_path))?;
|
fs::create_dir_all(paste_type.get_path(&server_config.upload_path))?;
|
||||||
}
|
}
|
||||||
let mut http_server = HttpServer::new(move || {
|
let mut http_server = HttpServer::new(move || {
|
||||||
|
let http_client = ClientBuilder::default()
|
||||||
|
.timeout(Duration::from_secs(30))
|
||||||
|
.disable_redirects()
|
||||||
|
.finish();
|
||||||
App::new()
|
App::new()
|
||||||
.data(config.clone())
|
.data(config.clone())
|
||||||
|
.data(http_client)
|
||||||
.wrap(Logger::default())
|
.wrap(Logger::default())
|
||||||
.configure(server::configure_routes)
|
.configure(server::configure_routes)
|
||||||
})
|
})
|
||||||
|
|
78
src/paste.rs
78
src/paste.rs
|
@ -1,5 +1,9 @@
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
|
use crate::file::Directory;
|
||||||
use crate::header::ContentDisposition;
|
use crate::header::ContentDisposition;
|
||||||
|
use crate::util;
|
||||||
|
use actix_web::client::Client;
|
||||||
|
use actix_web::{error, Error};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io::{Error as IoError, ErrorKind as IoErrorKind, Result as IoResult, Write};
|
use std::io::{Error as IoError, ErrorKind as IoErrorKind, Result as IoResult, Write};
|
||||||
|
@ -12,6 +16,8 @@ use url::Url;
|
||||||
pub enum PasteType {
|
pub enum PasteType {
|
||||||
/// Any type of file.
|
/// Any type of file.
|
||||||
File,
|
File,
|
||||||
|
/// A file that is on a remote URL.
|
||||||
|
RemoteFile,
|
||||||
/// A file that allowed to be accessed once.
|
/// A file that allowed to be accessed once.
|
||||||
Oneshot,
|
Oneshot,
|
||||||
/// A file that only contains an URL.
|
/// A file that only contains an URL.
|
||||||
|
@ -23,6 +29,8 @@ impl<'a> TryFrom<&'a ContentDisposition> for PasteType {
|
||||||
fn try_from(content_disposition: &'a ContentDisposition) -> Result<Self, Self::Error> {
|
fn try_from(content_disposition: &'a ContentDisposition) -> Result<Self, Self::Error> {
|
||||||
if content_disposition.has_form_field("file") {
|
if content_disposition.has_form_field("file") {
|
||||||
Ok(Self::File)
|
Ok(Self::File)
|
||||||
|
} else if content_disposition.has_form_field("remote") {
|
||||||
|
Ok(Self::RemoteFile)
|
||||||
} else if content_disposition.has_form_field("oneshot") {
|
} else if content_disposition.has_form_field("oneshot") {
|
||||||
Ok(Self::Oneshot)
|
Ok(Self::Oneshot)
|
||||||
} else if content_disposition.has_form_field("url") {
|
} else if content_disposition.has_form_field("url") {
|
||||||
|
@ -37,7 +45,7 @@ impl PasteType {
|
||||||
/// Returns the corresponding directory of the paste type.
|
/// Returns the corresponding directory of the paste type.
|
||||||
pub fn get_dir(&self) -> String {
|
pub fn get_dir(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Self::File => String::new(),
|
Self::File | Self::RemoteFile => String::new(),
|
||||||
Self::Oneshot => String::from("oneshot"),
|
Self::Oneshot => String::from("oneshot"),
|
||||||
Self::Url => String::from("url"),
|
Self::Url => String::from("url"),
|
||||||
}
|
}
|
||||||
|
@ -138,6 +146,50 @@ impl Paste {
|
||||||
Ok(file_name)
|
Ok(file_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Downloads a file from URL and stores it with [`store_file`].
|
||||||
|
///
|
||||||
|
/// - File name is inferred from URL if the last URL segment is a file.
|
||||||
|
/// - Same content length configuration is applied for download limit.
|
||||||
|
/// - Checks SHA256 digest of the downloaded file for preventing duplication.
|
||||||
|
/// - Assumes `self.data` contains a valid URL, otherwise returns an error.
|
||||||
|
pub async fn store_remote_file(
|
||||||
|
&mut self,
|
||||||
|
expiry_date: Option<u128>,
|
||||||
|
client: &Client,
|
||||||
|
config: &Config,
|
||||||
|
) -> Result<String, Error> {
|
||||||
|
let data = str::from_utf8(&self.data).map_err(error::ErrorBadRequest)?;
|
||||||
|
let url = Url::parse(data).map_err(error::ErrorBadRequest)?;
|
||||||
|
let file_name = url
|
||||||
|
.path_segments()
|
||||||
|
.and_then(|segments| segments.last())
|
||||||
|
.and_then(|name| if name.is_empty() { None } else { Some(name) })
|
||||||
|
.unwrap_or("file");
|
||||||
|
let mut response = client.get(url.as_str()).send().await?;
|
||||||
|
let payload_limit = config
|
||||||
|
.server
|
||||||
|
.max_content_length
|
||||||
|
.get_bytes()
|
||||||
|
.try_into()
|
||||||
|
.map_err(error::ErrorInternalServerError)?;
|
||||||
|
let bytes = response.body().limit(payload_limit).await?.to_vec();
|
||||||
|
let bytes_checksum = util::sha256_digest(&*bytes)?;
|
||||||
|
self.data = bytes;
|
||||||
|
if !config.paste.duplicate_files.unwrap_or(true) {
|
||||||
|
if let Some(file) =
|
||||||
|
Directory::try_from(config.server.upload_path.as_path())?.get_file(bytes_checksum)
|
||||||
|
{
|
||||||
|
return Ok(file
|
||||||
|
.path
|
||||||
|
.file_name()
|
||||||
|
.map(|v| v.to_string_lossy())
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(self.store_file(file_name, expiry_date, config)?)
|
||||||
|
}
|
||||||
|
|
||||||
/// Writes an URL to a file in upload directory.
|
/// Writes an URL to a file in upload directory.
|
||||||
///
|
///
|
||||||
/// - Checks if the data is a valid URL.
|
/// - Checks if the data is a valid URL.
|
||||||
|
@ -169,10 +221,13 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::random::{RandomURLConfig, RandomURLType};
|
use crate::random::{RandomURLConfig, RandomURLType};
|
||||||
use crate::util;
|
use crate::util;
|
||||||
|
use actix_web::client::Client;
|
||||||
|
use actix_web::web::Data;
|
||||||
|
use byte_unit::Byte;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
#[test]
|
#[actix_rt::test]
|
||||||
fn test_paste_data() -> IoResult<()> {
|
async fn test_paste_data() -> Result<(), Error> {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.server.upload_path = env::current_dir()?;
|
config.server.upload_path = env::current_dir()?;
|
||||||
config.paste.random_url = RandomURLConfig {
|
config.paste.random_url = RandomURLConfig {
|
||||||
|
@ -257,6 +312,23 @@ mod tests {
|
||||||
};
|
};
|
||||||
assert!(paste.store_url(None, &config).is_err());
|
assert!(paste.store_url(None, &config).is_err());
|
||||||
|
|
||||||
|
config.server.max_content_length = Byte::from_str("30k").unwrap();
|
||||||
|
let url = String::from("https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg");
|
||||||
|
let mut paste = Paste {
|
||||||
|
data: url.as_bytes().to_vec(),
|
||||||
|
type_: PasteType::RemoteFile,
|
||||||
|
};
|
||||||
|
let client_data = Data::new(Client::default());
|
||||||
|
let file_name = paste.store_remote_file(None, &client_data, &config).await?;
|
||||||
|
let file_path = PasteType::RemoteFile
|
||||||
|
.get_path(&config.server.upload_path)
|
||||||
|
.join(&file_name);
|
||||||
|
assert_eq!(
|
||||||
|
"8c712905b799905357b8202d0cb7a244cefeeccf7aa5eb79896645ac50158ffa",
|
||||||
|
util::sha256_digest(&*paste.data)?
|
||||||
|
);
|
||||||
|
fs::remove_file(file_path)?;
|
||||||
|
|
||||||
for paste_type in &[PasteType::Url, PasteType::Oneshot] {
|
for paste_type in &[PasteType::Url, PasteType::Oneshot] {
|
||||||
fs::remove_dir(paste_type.get_path(&config.server.upload_path))?;
|
fs::remove_dir(paste_type.get_path(&config.server.upload_path))?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ use crate::paste::{Paste, PasteType};
|
||||||
use crate::util;
|
use crate::util;
|
||||||
use actix_files::NamedFile;
|
use actix_files::NamedFile;
|
||||||
use actix_multipart::Multipart;
|
use actix_multipart::Multipart;
|
||||||
|
use actix_web::client::Client;
|
||||||
use actix_web::{error, get, post, web, Error, HttpRequest, HttpResponse, Responder};
|
use actix_web::{error, get, post, web, Error, HttpRequest, HttpResponse, Responder};
|
||||||
use byte_unit::Byte;
|
use byte_unit::Byte;
|
||||||
use futures_util::stream::StreamExt;
|
use futures_util::stream::StreamExt;
|
||||||
|
@ -37,7 +38,7 @@ async fn serve(
|
||||||
let alt_path = type_.get_path(&config.server.upload_path).join(&*file);
|
let alt_path = type_.get_path(&config.server.upload_path).join(&*file);
|
||||||
let alt_path = util::glob_match_file(alt_path)?;
|
let alt_path = util::glob_match_file(alt_path)?;
|
||||||
if alt_path.exists()
|
if alt_path.exists()
|
||||||
|| path.file_name().map(|v| v.to_str()).flatten() == Some(&type_.get_dir())
|
|| path.file_name().and_then(|v| v.to_str()) == Some(&type_.get_dir())
|
||||||
{
|
{
|
||||||
path = alt_path;
|
path = alt_path;
|
||||||
paste_type = *type_;
|
paste_type = *type_;
|
||||||
|
@ -46,7 +47,7 @@ async fn serve(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match paste_type {
|
match paste_type {
|
||||||
PasteType::File | PasteType::Oneshot => {
|
PasteType::File | PasteType::RemoteFile | PasteType::Oneshot => {
|
||||||
let response = NamedFile::open(&path)
|
let response = NamedFile::open(&path)
|
||||||
.map_err(|_| error::ErrorNotFound("file is not found or expired :("))?
|
.map_err(|_| error::ErrorNotFound("file is not found or expired :("))?
|
||||||
.disable_content_disposition()
|
.disable_content_disposition()
|
||||||
|
@ -79,6 +80,7 @@ async fn serve(
|
||||||
async fn upload(
|
async fn upload(
|
||||||
request: HttpRequest,
|
request: HttpRequest,
|
||||||
mut payload: Multipart,
|
mut payload: Multipart,
|
||||||
|
client: web::Data<Client>,
|
||||||
config: web::Data<Config>,
|
config: web::Data<Config>,
|
||||||
) -> Result<HttpResponse, Error> {
|
) -> Result<HttpResponse, Error> {
|
||||||
let connection = request.connection_info();
|
let connection = request.connection_info();
|
||||||
|
@ -102,7 +104,10 @@ async fn upload(
|
||||||
log::warn!("{} sent zero bytes", host);
|
log::warn!("{} sent zero bytes", host);
|
||||||
return Err(error::ErrorBadRequest("invalid file size"));
|
return Err(error::ErrorBadRequest("invalid file size"));
|
||||||
}
|
}
|
||||||
if paste_type != PasteType::Oneshot && !config.paste.duplicate_files.unwrap_or(true) {
|
if paste_type != PasteType::Oneshot
|
||||||
|
&& paste_type != PasteType::RemoteFile
|
||||||
|
&& !config.paste.duplicate_files.unwrap_or(true)
|
||||||
|
{
|
||||||
let bytes_checksum = util::sha256_digest(&*bytes)?;
|
let bytes_checksum = util::sha256_digest(&*bytes)?;
|
||||||
if let Some(file) = Directory::try_from(config.server.upload_path.as_path())?
|
if let Some(file) = Directory::try_from(config.server.upload_path.as_path())?
|
||||||
.get_file(bytes_checksum)
|
.get_file(bytes_checksum)
|
||||||
|
@ -120,18 +125,27 @@ async fn upload(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let bytes_unit = Byte::from_bytes(bytes.len() as u128).get_appropriate_unit(false);
|
let mut paste = Paste {
|
||||||
let paste = Paste {
|
|
||||||
data: bytes.to_vec(),
|
data: bytes.to_vec(),
|
||||||
type_: paste_type,
|
type_: paste_type,
|
||||||
};
|
};
|
||||||
let file_name = match paste_type {
|
let file_name = match paste.type_ {
|
||||||
PasteType::File | PasteType::Oneshot => {
|
PasteType::File | PasteType::Oneshot => {
|
||||||
paste.store_file(content.get_file_name()?, expiry_date, &config)?
|
paste.store_file(content.get_file_name()?, expiry_date, &config)?
|
||||||
}
|
}
|
||||||
|
PasteType::RemoteFile => {
|
||||||
|
paste
|
||||||
|
.store_remote_file(expiry_date, &client, &config)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
PasteType::Url => paste.store_url(expiry_date, &config)?,
|
PasteType::Url => paste.store_url(expiry_date, &config)?,
|
||||||
};
|
};
|
||||||
log::info!("{} ({}) is uploaded from {}", file_name, bytes_unit, host);
|
log::info!(
|
||||||
|
"{} ({}) is uploaded from {}",
|
||||||
|
file_name,
|
||||||
|
Byte::from_bytes(paste.data.len() as u128).get_appropriate_unit(false),
|
||||||
|
host
|
||||||
|
);
|
||||||
urls.push(format!(
|
urls.push(format!(
|
||||||
"{}://{}/{}\n",
|
"{}://{}/{}\n",
|
||||||
connection.scheme(),
|
connection.scheme(),
|
||||||
|
|
Loading…
Reference in a new issue