From 8a97b5b1d7bfdf34a8972bcc9294c01f101018f2 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Thu, 22 Feb 2024 16:11:44 +0000 Subject: [PATCH] feat: [#483] allow upload torrent with application/octet-stream HTTP header Content-Type. Some users are having problems uploading torrents becuase the client (browser or other clients) use the HTTP header Contetnt-Type: `application/octet-stream` instead of: `application/x-bittorrent` It seems that the reason is they don't have any application associated to that extension. So it uses the generic binary file mime type. The MIME type can be inferred from the file extension. If the system or application uploading the file has a specific association for .torrent files, it might set the MIME type to application/x-bittorrent. In the absence of such association, it might fall back to the generic application/octet-stream. --- src/web/api/client/v1/responses.rs | 10 +++++++++- src/web/api/server/v1/contexts/torrent/errors.rs | 4 +++- src/web/api/server/v1/contexts/torrent/handlers.rs | 4 ++-- tests/common/responses.rs | 9 ++++++++- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/web/api/client/v1/responses.rs b/src/web/api/client/v1/responses.rs index aae5a338..bacdcba6 100644 --- a/src/web/api/client/v1/responses.rs +++ b/src/web/api/client/v1/responses.rs @@ -71,7 +71,7 @@ impl BinaryResponse { #[must_use] pub fn is_a_bit_torrent_file(&self) -> bool { - self.is_ok() && self.is_bittorrent_content_type() + self.is_ok() && (self.is_bittorrent_content_type() || self.is_octet_stream_content_type()) } #[must_use] @@ -82,6 +82,14 @@ impl BinaryResponse { false } + #[must_use] + pub fn is_octet_stream_content_type(&self) -> bool { + if let Some(content_type) = &self.content_type { + return content_type == "application/octet-stream"; + } + false + } + #[must_use] pub fn is_ok(&self) -> bool { self.status == 200 diff --git a/src/web/api/server/v1/contexts/torrent/errors.rs b/src/web/api/server/v1/contexts/torrent/errors.rs index 87166419..2c18bbb2 100644 --- a/src/web/api/server/v1/contexts/torrent/errors.rs +++ b/src/web/api/server/v1/contexts/torrent/errors.rs @@ -21,7 +21,9 @@ pub enum Request { #[display(fmt = "torrent tags string is not a valid JSON.")] TagsArrayIsNotValidJson, - #[display(fmt = "upload torrent request header `content-type` should be `application/x-bittorrent`.")] + #[display( + fmt = "upload torrent request header `content-type` should be preferably `application/x-bittorrent` or `application/octet-stream`." + )] InvalidFileType, #[display(fmt = "cannot write uploaded torrent bytes (binary file) into memory.")] diff --git a/src/web/api/server/v1/contexts/torrent/handlers.rs b/src/web/api/server/v1/contexts/torrent/handlers.rs index e72151e0..ddba8df0 100644 --- a/src/web/api/server/v1/contexts/torrent/handlers.rs +++ b/src/web/api/server/v1/contexts/torrent/handlers.rs @@ -301,7 +301,7 @@ pub async fn create_random_torrent_handler(State(_app_data): State> /// /// - The text fields do not contain a valid UTF8 string. /// - The torrent file data is not valid because: -/// - The content type is not `application/x-bittorrent`. +/// - The content type is not `application/x-bittorrent` or `application/octet-stream`. /// - The multipart content is invalid. /// - The torrent file pieces key has a length that is not a multiple of 20. /// - The binary data cannot be decoded as a torrent file. @@ -350,7 +350,7 @@ async fn build_add_torrent_request_from_payload(mut payload: Multipart) -> Resul "torrent" => { let content_type = field.content_type().unwrap(); - if content_type != "application/x-bittorrent" { + if content_type != "application/x-bittorrent" && content_type != "application/octet-stream" { return Err(errors::Request::InvalidFileType); } diff --git a/tests/common/responses.rs b/tests/common/responses.rs index 2545a9e8..0d9388e2 100644 --- a/tests/common/responses.rs +++ b/tests/common/responses.rs @@ -54,7 +54,7 @@ impl BinaryResponse { } } pub fn is_a_bit_torrent_file(&self) -> bool { - self.is_ok() && self.is_bittorrent_content_type() + self.is_ok() && (self.is_bittorrent_content_type() || self.is_octet_stream_content_type()) } pub fn is_bittorrent_content_type(&self) -> bool { @@ -64,6 +64,13 @@ impl BinaryResponse { false } + pub fn is_octet_stream_content_type(&self) -> bool { + if let Some(content_type) = &self.content_type { + return content_type == "application/octet-stream"; + } + false + } + pub fn is_ok(&self) -> bool { self.status == 200 }