nanohttp/
lib.rs

1//! # nanohttp
2//!
3//! `nanohttp` is a small zero-dependency library for parsing HTTP requests and building HTTP
4//! responses.
5//!
6//! It is intended purely as an implementation of the HTTP protocol, and therefore does not
7//! handle things like routing, json serialization and deserialization, or building a HTTP server.
8//! See the examples below for how you can use it in combination with a TCP server and a runtime
9//! library such as [tokio](https://docs.rs/tokio/latest/tokio/) or
10//! [async-std](https://docs.rs/async-std/latest/async_std/) to build a custom HTTP server.
11//!
12//! This library is intended to abstract away the details of dealing with HTTP, without removing
13//! the need to understand how HTTP works at a high level. For example there are a few helper
14//! methods which will automatically set relevant headers. But for the most part, it is up to the
15//! consumer of the library to ensure that the correct headers are set, and generally ensure that
16//! the constructed HTTP response is valid. An example of this is ensuring that the `Location`
17//! header is set when returning a `303` response code.
18//!
19//! ## Examples
20//!
21//! Parse an incoming HTTP request.
22//!
23//! ```
24//! use nanohttp::{Request, Method};
25//!
26//! let req = "GET / HTTP/1.1\r\n";
27//! let res = Request::from_string(req).unwrap();
28//!
29//! assert_eq!(res.method, Method::GET);
30//! assert_eq!(res.path.uri, "/");
31//!
32//! ```
33//!
34//! Build a HTTP response, and convert it to a valid HTTP message.
35//!
36//! ```
37//! use nanohttp::{Response, Status, Header};
38//!
39//! let html = "<html><head></head><body><h1>Hello, world!</h1></body></html>";
40//! let res = Response::body(html)
41//!     .header(Header::new("Content-Type", "text/html"))
42//!     .header(Header::new("Content-Length", &html.len().to_string()))
43//!     .status(Status::Ok);
44//!
45//! assert_eq!(res.to_string(), "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: 61\r\n\r\n<html><head></head><body><h1>Hello, world!</h1></body></html>");
46//!
47//! ```
48//!
49//! Use `nanohttp` to build a custom TCP server using only the
50//! [async-std](https://docs.rs/async-std/latest/async_std/) crate as a dependency.
51//!
52//! ```
53//! use std::str::from_utf8;
54//!
55//! use async_std::io::{ReadExt, WriteExt};
56//! use async_std::net::{TcpListener, TcpStream};
57//! use async_std::task;
58//!
59//! use nanohttp::{Method, Status, Request, Response};
60//!
61//! async fn handler(req: Request) -> Response {
62//!     match req.path.uri.as_str() {
63//!         "/" => match req.method {
64//!             Method::GET => Response::empty().status(Status::Ok),
65//!             _ => Response::empty().status(Status::NotAllowed),
66//!         },
67//!         "/hello" => match req.method {
68//!             Method::GET => {
69//!                 let html = "<html><head><title>Hello, world!</title></head><body><h1>Hello, world!</h1></body></html>";
70//!                 Response::content(html, "text/html").status(Status::Ok)
71//!             },
72//!             _ => Response::empty().status(Status::NotAllowed),
73//!         },
74//!         _ => Response::empty().status(Status::NotFound),
75//!     }
76//! }
77//!
78//! async fn handle_connection(mut connection: TcpStream) {
79//!     let mut buffer = [0; 1024];
80//!
81//!     connection.read(&mut buffer).await.unwrap();
82//!
83//!     let req_text = from_utf8(&buffer).unwrap().trim_end_matches("\0");
84//!
85//!     let req = Request::from_string(req_text).unwrap();
86//!     let res = handler(req).await.to_string();
87//!
88//!     let res_bytes = res.as_bytes();
89//!
90//!     connection.write(res_bytes).await.unwrap();
91//!     connection.flush().await.unwrap();
92//! }
93//!
94//! #[async_std::main]
95//! async fn main() {
96//!     let listener = TcpListener::bind("127.0.0.1:8000").await.unwrap();
97//!
98//!     loop {
99//!         let (connection, _) = listener.accept().await.unwrap();
100//!         task::spawn(async move {
101//!             handle_connection(connection).await;
102//!         });
103//!     }
104//! }
105//! ```
106
107mod error;
108mod header;
109mod method;
110mod request;
111mod response;
112mod status;
113
114pub use error::{Error, ErrorType};
115pub use header::Header;
116pub use method::Method;
117pub use request::{Path, Request};
118pub use response::Response;
119pub use status::Status;