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}