http_async/lib.rs
1//! Simple Server, who speaks the Hyper Text Transfer Protocol, with async-std.
2//! # Usage
3//! Include this:
4//! ```
5//! [dependencies]
6//! http-async = "0.1"
7//! ```
8//! in you project `Cargo.toml`-file.
9//! # Licence
10//! MIT
11
12#![warn(clippy::all)]
13#![allow(clippy::suspicious_else_formatting)]
14
15#![allow(non_snake_case)]
16#![allow(non_upper_case_globals)]
17#![warn(missing_docs)]
18#![warn(future_incompatible)]
19
20/// Header of Requests and Responses.
21pub mod header;
22/// Protocol Methods.
23pub mod method;
24/// Path and Queries to Resources.
25pub mod path;
26/// Requests to Server.
27pub mod request;
28/// Responses to Client.
29pub mod response;
30/// Status Codes
31pub mod status;
32/// Protocol Versions.
33pub mod version;
34
35use
36{
37 crate::
38 {
39 request::
40 {
41 Request,
42 },
43 response::
44 {
45 Response,
46 },
47 status::
48 {
49 Status,
50 },
51 },
52 async_std::
53 {
54 io::
55 {
56 Error,
57 },
58 net::
59 {
60 SocketAddr,
61 TcpListener,
62 ToSocketAddrs,
63 },
64 prelude::*,
65 sync::
66 {
67 Arc,
68 },
69 task::
70 {
71 spawn,
72 },
73 },
74 std::
75 {
76 fmt::
77 {
78 Display,
79 },
80 },
81};
82
83/// Configuration of the HTTP Server.
84pub struct Configuration
85{
86 /// Address, on which the Server should listen to.
87 pub address: SocketAddr,
88 /// Maximum Bytes of Request Content.
89 /// Prevents DOS by Allocation a large Buffer (Header ›Content-Length‹ could contain any decimal value) without ever filling it.
90 pub maxContent: usize,
91 /// Maximum Numbers of Headers.
92 /// Prevents Slow Lorris Attacks:
93 /// Client might slowly send Header by Header for ever,
94 /// but because neither the Connection times out nor the Request every ends,
95 /// the Server keeps reading the Stream.
96 pub maxHeaderEntries: usize,
97 /// Maximum Length of a Header.
98 pub maxHeaderLength: usize,
99 /// Maximum Length of Path.
100 /// Prevents Slow Lorris Attacks.
101 pub maxPathLength: usize,
102 /// Maximum Length of Query String.
103 /// Prevents Slow Lorris Attacks.
104 pub maxQueryLength: usize,
105}
106
107/// Just send this content successfully.
108#[macro_export]
109macro_rules! content
110{
111 (
112 $Type:expr,
113 $Path:expr
114 )
115 => {
116 http_async::Content
117 (
118 http_async::status::Status::Ok,
119 $Type,
120 include_bytes! ( $Path )
121 .to_vec(),
122 )
123 };
124}
125
126/// Content of a Hyper Text Transfer Protocol Response.
127pub struct Content
128{
129 statusCode: Status,
130 contentType: &'static str,
131 contentBody: Vec < u8 >,
132}
133
134/// Constructor for `Content`.
135///
136/// # Arguments
137/// * `` –
138pub fn Content
139(
140 statusCode: Status,
141 contentType: &'static str,
142 contentBody: Vec < u8 >,
143)
144-> Content
145{
146 Content
147 {
148 statusCode,
149 contentType,
150 contentBody,
151 }
152}
153
154/// Simple Key-Value-Pair. E.g. for header-fields, Queries, etc.
155#[derive(Debug)]
156pub struct KeyValuePair
157{
158 /// Key.
159 pub key: String,
160 /// Value.
161 pub value: String,
162}
163
164/// Creates a `Future` to start a Hyper Text Transfer Protocol Server.
165///
166/// # Arguments
167/// * `address` – server binds to this address,
168/// * `this` – some data, that will be passed to `handler` everytime, someone connects,
169/// * `handler` – handler for Hyper Text Transfer Protocol Requests.
170pub async fn server
171<
172 Address,
173 Data,
174 Handler,
175>
176(
177 address: Address,
178 this: Arc < Data >,
179 handler: Arc < Handler >,
180)
181-> Result
182 <
183 (),
184 Error,
185 >
186where
187 Address: ToSocketAddrs + Display + Send + Sync + Clone + 'static,
188 Data: Send + Sync + 'static,
189 Handler: Send + Sync + 'static +
190 Fn
191 (
192 Request,
193 Arc < Data >,
194 )
195 -> Response,
196{
197 let socket
198 = TcpListener::bind ( &address )
199 .await
200 .expect ( "Failed to bind" );
201 println!
202 (
203 "Waiting for connections on {}",
204 address,
205 );
206 loop
207 {
208 let this = this.clone ( );
209 let handler = handler.clone ( );
210 let address = address.clone ( );
211 let
212 (
213 mut tcpStream,
214 client
215 )
216 = socket
217 .accept()
218 .await
219 .unwrap();
220 spawn
221 (
222 async move
223 {
224 let mut counter = 0;
225 loop
226 {
227 match Request()
228 .parse
229 (
230 &mut tcpStream,
231 ).await
232 {
233 Ok ( request )
234 => match match tcpStream
235 .write
236 (
237 handler
238 (
239 request,
240 this.clone(),
241 )
242 .into_vector ( )
243 .as_slice ( )
244 )
245 .await
246 {
247 Ok ( _ )
248 => tcpStream
249 .flush().await,
250 Err ( error )
251 => Err ( error ),
252 }
253 {
254 Ok ( _ )
255 => println!
256 (
257 "Success! {} -> {} #{}",
258 address,
259 client,
260 counter,
261 ),
262 Err ( error )
263 => {
264 eprintln!
265 (
266 "Send Fail: {}",
267 error,
268 );
269 break;
270 },
271 },
272 Err ( error )
273 => {
274 eprintln!
275 (
276 "Input Fail: {}",
277 error,
278 );
279 break;
280 }
281 }
282 counter += 1;
283 }
284 }
285 );
286 }
287}