1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//! An experimental generic S3 server
//!
//! ## Public API
//!
//! ### Type: `S3Service`, `SharedS3Service`
//!
//! [`S3Service`] is the actual S3 service owner. [`SharedS3Service`] is like `Arc<S3Service>`.
//!
//! [`S3Service`] contains internal handlers, a storage and a optional auth provider.
//!
//! [`hyper::service::Service<Request>`] is implemented for [`SharedS3Service`].
//!
//! When a new tcp stream connects, the server should clone [`SharedS3Service`], then handle each http request by `S3Service::hyper_call` or `S3Service::handle`.
//!
//! An [`S3Service`] instance can be integrated into a [`hyper`] application.
//!
//! See `src/bin/s3-server.rs` for how to setup an [`S3Service`].
//!
//! ### Trait: `S3Storage`
//!
//! [`S3Storage`] is an async trait.
//!
//! Each method of [`S3Storage`] represents a server-side S3 API.
//!
//! [`S3Service`] extracts DTO from http request, dispatches requests to the storage and converts the output into http response.
//!
//! ### Trait: `S3Auth`
//!
//! [`S3Auth`] is an async trait.
//!
//! An [`S3Auth`] instance provides AK/SK management.
//!
//! [`S3Service`] looks up secret access keys from an auth provider and checks http signature (if any) by the AK and SK.
//!
//! ## Internal API
//!
//! ### Type: `S3Error`, `S3StorageError<E>`, `S3AuthError`
//!
//! `S3Error` contains error code, message, error source, span trace and backtrace.
//!
//! `S3StorageError<E>` and `S3AuthError` are special kinds of `S3Error`. They can be converted into `S3Error`.
//!
//! See `src/internal_macros.rs` for how to create an `S3Error` by macros.
//!
//! ### Trait: `S3Handler`
//!
//! An `S3Handler` determines whether the http request matches it.
//!
//! If the http request matches the handler,
//! then the handler will be called with two arguments:
//! `&mut ReqContext<'_>` and `&(dyn S3Storage + Send + Sync)`.
//!
//! ### Trait: `S3Output`
//!
//! `S3Output` represents types which can be converted into a response.
//!
//! `S3Output` is implemented for DTOs and results.
//!
//! ### S3 types
//!
//! `S3Path` represents a path in the S3 storage.
//!
//! All types in `src/dto.rs` are data transfer objects which represent the input or output of S3 APIs.
//!
//! All types in `src/headers` are http headers which may occur in an S3 http request.
//!
//! All types in `src/streams` are http body streams which may occur in an S3 http request.

#![forbid(unsafe_code)]
#![deny(
    // The following are allowed by default lints according to
    // https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html
    anonymous_parameters,
    bare_trait_objects,
    // box_pointers,
    elided_lifetimes_in_paths,
    missing_copy_implementations,
    missing_debug_implementations,
    missing_docs,
    single_use_lifetimes,
    trivial_casts,
    trivial_numeric_casts,
    // unreachable_pub,
    unstable_features,
    unused_extern_crates,
    unused_import_braces,
    unused_qualifications,
    unused_results,
    variant_size_differences,

    // Deny all Clippy lints even Clippy allow some by default
    // https://rust-lang.github.io/rust-clippy/master/
    clippy::all,
    clippy::restriction,
    clippy::pedantic,
    clippy::nursery,
    clippy::cargo,
)]
#![allow(
    // Some explicitly allowed Clippy lints, must have clear reason to allow
    clippy::implicit_return, // actually omitting the return keyword is idiomatic Rust code
    clippy::missing_inline_in_public_items, // In general, it is not bad
    clippy::module_name_repetitions, // Allowed by default
    clippy::panic, // Panic when fatal failures occur
    clippy::blanket_clippy_restriction_lints,
    clippy::separated_literal_suffix, // Conflicts with `clippy::unseparated_literal_suffix`
    clippy::shadow_reuse, // It is a common pattern
)]
#![cfg_attr(test, allow(
    clippy::unwrap_used, // Tests need [`unwrap`]
    clippy::indexing_slicing, // Fail fast
    clippy::expect_used
))]

#[macro_use]
mod internal_macros;

pub(crate) mod utils;

mod data_structures;
mod ops;
mod output;
mod signature_v4;
mod streams;

mod auth;
mod service;
mod storage;

pub use self::auth::{S3Auth, SimpleAuth};
pub use self::service::{S3Service, SharedS3Service};
pub use self::storage::S3Storage;

pub mod dto;
pub mod errors;
pub mod headers;
pub mod path;
pub mod storages;

/// Request type
pub(crate) type Request = hyper::Request<Body>;

/// Response type
pub(crate) type Response = hyper::Response<Body>;

/// `Box<dyn std::error::Error + Send + Sync + 'static>`
pub(crate) type BoxStdError = Box<dyn std::error::Error + Send + Sync + 'static>;

pub(crate) use async_trait::async_trait;
pub(crate) use hyper::{Body, Method, StatusCode};
pub(crate) use mime::Mime;