Skip to main content

base_http_content/
upload_store.rs

1// Released under the MIT License.
2// Copyright, 2026, by Samuel Williams.
3
4use base_scheduler::Cancellation;
5use base_web_content::UploadHead;
6use std::{error::Error, fmt, future::Future};
7
8/// Storage for uploads, which [`read_content`](crate::read_content) streams each upload into as it arrives.
9///
10/// Each upload is created, written in pieces, and then finished, which gives the handle the declared struct holds in its [`Upload`](base_web_content::Upload). An upload that fails, or whose content stops arriving, is aborted, and a finished upload whose content is refused is removed. [`FileStore`](crate::FileStore) stores uploads in files.
11///
12/// Uploads are stored before the whole body has been validated, so a store must not make an upload visible to anything else until the application accepts it.
13pub trait UploadStore: Send {
14    /// What the declared struct holds for a stored upload, such as a path.
15    type Handle: Send;
16    /// An upload being stored.
17    type Upload: Send;
18    /// Why a store operation failed.
19    type Error: Error + Send + Sync + 'static;
20
21    /// Begin storing an upload. When this fails, nothing of the upload is stored.
22    ///
23    /// The head's filename and media type are what the client declared, and must not choose where the upload is stored.
24    fn create(
25        &mut self,
26        head: &UploadHead,
27        cancellation: &Cancellation,
28    ) -> impl Future<Output = Result<Self::Upload, Self::Error>> + Send;
29
30    /// Store some of an upload's content, after what was stored before. When this fails, the caller must abort the upload, as [`read_content`](crate::read_content) does.
31    fn write(
32        &mut self,
33        upload: &mut Self::Upload,
34        content: &[u8],
35        cancellation: &Cancellation,
36    ) -> impl Future<Output = Result<(), Self::Error>> + Send;
37
38    /// Complete an upload whose content has all been written, returning its handle. When this fails, the caller must abort the upload, as [`read_content`](crate::read_content) does.
39    fn finish(
40        &mut self,
41        upload: &mut Self::Upload,
42        cancellation: &Cancellation,
43    ) -> impl Future<Output = Result<Self::Handle, Self::Error>> + Send;
44
45    /// Remove whatever was stored of an upload that was not finished, or whose finish failed. It is not cancellable, since it cleans up after a failure.
46    fn abort(
47        &mut self,
48        upload: Self::Upload,
49    ) -> impl Future<Output = Result<(), Self::Error>> + Send;
50
51    /// Remove a finished upload. It is not cancellable, since it cleans up after a failure.
52    fn remove(
53        &mut self,
54        handle: Self::Handle,
55    ) -> impl Future<Output = Result<(), Self::Error>> + Send;
56}
57
58/// A store for declarations without uploads, which refuses any upload.
59///
60/// A declaration without uploads accepts handles of every type, so it can be read with this store, whose handle is `()`. If the declaration does have uploads of `Upload<()>`, an upload fails to store with [`NoUploadsError`].
61#[derive(Clone, Copy, Debug, Default)]
62pub struct NoUploads;
63
64/// An upload reached [`NoUploads`].
65#[derive(Clone, Copy, Debug, PartialEq, Eq)]
66pub struct NoUploadsError;
67
68impl fmt::Display for NoUploadsError {
69    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
70        formatter.write_str("no store was given for uploads")
71    }
72}
73
74impl Error for NoUploadsError {}
75
76impl UploadStore for NoUploads {
77    type Handle = ();
78    type Upload = ();
79    type Error = NoUploadsError;
80
81    async fn create(&mut self, _: &UploadHead, _: &Cancellation) -> Result<(), NoUploadsError> {
82        Err(NoUploadsError)
83    }
84
85    async fn write(
86        &mut self,
87        _: &mut (),
88        _: &[u8],
89        _: &Cancellation,
90    ) -> Result<(), NoUploadsError> {
91        Err(NoUploadsError)
92    }
93
94    async fn finish(&mut self, _: &mut (), _: &Cancellation) -> Result<(), NoUploadsError> {
95        Err(NoUploadsError)
96    }
97
98    async fn abort(&mut self, _: ()) -> Result<(), NoUploadsError> {
99        Ok(())
100    }
101
102    async fn remove(&mut self, _: ()) -> Result<(), NoUploadsError> {
103        Ok(())
104    }
105}