pub struct HttpServerBuilder { /* private fields */ }
Expand description

Builds an HTTP server.

Implementations§

source§

impl HttpServerBuilder

source

pub fn new() -> Self

Makes a new builder these default settings:

  • Listens on 127.0.0.1
  • Picks a random port
  • 100 max connections
  • 64 KiB small body length
  • no cache dir, server rejects large request bodies
Examples found in repository?
examples/minimal.rs (line 40)
35
36
37
38
39
40
41
42
43
44
45
pub fn main() {
    safina_timer::start_timer_thread();
    let executor = safina_executor::Executor::default();
    executor
        .block_on(
            HttpServerBuilder::new()
                .listen_addr(socket_addr_127_0_0_1(8000))
                .spawn_and_join(|_req: Request| Response::not_found_404()),
        )
        .unwrap();
}
More examples
Hide additional examples
examples/events-sse.rs (line 92)
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
pub fn main() {
    println!("Access the server at http://127.0.0.1:8000/subscribe");
    let event_sender_thread_permit = Permit::new();
    let state = Arc::new(State::new());
    let state_clone = state.clone();
    std::thread::spawn(move || event_sender_thread(state_clone, event_sender_thread_permit));
    safina_timer::start_timer_thread();
    let executor = safina_executor::Executor::default();
    let request_handler =
        move |req: Request| log_request_and_response(req, |req| handle_req(state, req)).unwrap();
    executor
        .block_on(
            HttpServerBuilder::new()
                .listen_addr(socket_addr_127_0_0_1(8000))
                .max_conns(100)
                .spawn_and_join(request_handler),
        )
        .unwrap();
}
examples/http-put.rs (line 94)
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
pub fn main() {
    println!("Access the server at http://127.0.0.1:8000/upload");
    let _guard = set_global_logger(
        LogFileWriter::new_builder("log", 100 * 1024 * 1024)
            .start_writer_thread()
            .unwrap(),
    )
    .unwrap();
    safina_timer::start_timer_thread();
    let executor = safina_executor::Executor::default();
    let cache_dir = TempDir::new().unwrap();
    let state = Arc::new(State::new());
    let request_handler =
        move |req: Request| log_request_and_response(req, |req| handle_req(state, req)).unwrap();
    executor
        .block_on(
            HttpServerBuilder::new()
                .listen_addr(socket_addr_127_0_0_1(8000))
                .max_conns(100)
                .small_body_len(64 * 1024)
                .receive_large_bodies(cache_dir.path())
                .spawn_and_join(request_handler),
        )
        .unwrap();
}
source

pub fn listen_addr(self, addr: SocketAddr) -> Self

Examples found in repository?
examples/minimal.rs (line 41)
35
36
37
38
39
40
41
42
43
44
45
pub fn main() {
    safina_timer::start_timer_thread();
    let executor = safina_executor::Executor::default();
    executor
        .block_on(
            HttpServerBuilder::new()
                .listen_addr(socket_addr_127_0_0_1(8000))
                .spawn_and_join(|_req: Request| Response::not_found_404()),
        )
        .unwrap();
}
More examples
Hide additional examples
examples/events-sse.rs (line 93)
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
pub fn main() {
    println!("Access the server at http://127.0.0.1:8000/subscribe");
    let event_sender_thread_permit = Permit::new();
    let state = Arc::new(State::new());
    let state_clone = state.clone();
    std::thread::spawn(move || event_sender_thread(state_clone, event_sender_thread_permit));
    safina_timer::start_timer_thread();
    let executor = safina_executor::Executor::default();
    let request_handler =
        move |req: Request| log_request_and_response(req, |req| handle_req(state, req)).unwrap();
    executor
        .block_on(
            HttpServerBuilder::new()
                .listen_addr(socket_addr_127_0_0_1(8000))
                .max_conns(100)
                .spawn_and_join(request_handler),
        )
        .unwrap();
}
examples/http-put.rs (line 95)
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
pub fn main() {
    println!("Access the server at http://127.0.0.1:8000/upload");
    let _guard = set_global_logger(
        LogFileWriter::new_builder("log", 100 * 1024 * 1024)
            .start_writer_thread()
            .unwrap(),
    )
    .unwrap();
    safina_timer::start_timer_thread();
    let executor = safina_executor::Executor::default();
    let cache_dir = TempDir::new().unwrap();
    let state = Arc::new(State::new());
    let request_handler =
        move |req: Request| log_request_and_response(req, |req| handle_req(state, req)).unwrap();
    executor
        .block_on(
            HttpServerBuilder::new()
                .listen_addr(socket_addr_127_0_0_1(8000))
                .max_conns(100)
                .small_body_len(64 * 1024)
                .receive_large_bodies(cache_dir.path())
                .spawn_and_join(request_handler),
        )
        .unwrap();
}
source

pub fn max_conns(self, n: usize) -> Self

Sets the maximum number of connections to handle at one time.

When the server is handling the maximum number of connections, it waits for a connection to drop before accepting new ones.

Each connection uses a file handle. Some processes run with a limit on the number of file handles. The OS kernel also has a limit for all processes combined.

Panics

Panics when n is zero.

Examples found in repository?
examples/events-sse.rs (line 94)
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
pub fn main() {
    println!("Access the server at http://127.0.0.1:8000/subscribe");
    let event_sender_thread_permit = Permit::new();
    let state = Arc::new(State::new());
    let state_clone = state.clone();
    std::thread::spawn(move || event_sender_thread(state_clone, event_sender_thread_permit));
    safina_timer::start_timer_thread();
    let executor = safina_executor::Executor::default();
    let request_handler =
        move |req: Request| log_request_and_response(req, |req| handle_req(state, req)).unwrap();
    executor
        .block_on(
            HttpServerBuilder::new()
                .listen_addr(socket_addr_127_0_0_1(8000))
                .max_conns(100)
                .spawn_and_join(request_handler),
        )
        .unwrap();
}
More examples
Hide additional examples
examples/http-put.rs (line 96)
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
pub fn main() {
    println!("Access the server at http://127.0.0.1:8000/upload");
    let _guard = set_global_logger(
        LogFileWriter::new_builder("log", 100 * 1024 * 1024)
            .start_writer_thread()
            .unwrap(),
    )
    .unwrap();
    safina_timer::start_timer_thread();
    let executor = safina_executor::Executor::default();
    let cache_dir = TempDir::new().unwrap();
    let state = Arc::new(State::new());
    let request_handler =
        move |req: Request| log_request_and_response(req, |req| handle_req(state, req)).unwrap();
    executor
        .block_on(
            HttpServerBuilder::new()
                .listen_addr(socket_addr_127_0_0_1(8000))
                .max_conns(100)
                .small_body_len(64 * 1024)
                .receive_large_bodies(cache_dir.path())
                .spawn_and_join(request_handler),
        )
        .unwrap();
}
source

pub fn receive_large_bodies(self, cache_dir: &Path) -> Self

Save large request bodies to this directory.

If you do not call this method, the server will refuse all requests with bodies larger than small_body_len with 413 Payload Too Large. It will also refuse all bodies with unknown length.

Example
use servlin::{HttpServerBuilder, Request, Response};
use servlin::reexport::{safina_executor, safina_timer};
use std::io::Read;

let cache_dir = temp_dir::TempDir::new().unwrap();
let handler = move |req: Request| {
    if req.body.is_pending() {
        return Response::get_body_and_reprocess(1024 * 1024);
    }
    let len = req.body.reader().unwrap().bytes().count();
    Response::text(200, format!("body len={}", len))
};
safina_timer::start_timer_thread();
safina_executor::Executor::default().block_on(
    HttpServerBuilder::new()
        .receive_large_bodies(cache_dir.path())
        .spawn_and_join(handler)
).unwrap();
Examples found in repository?
examples/http-put.rs (line 98)
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
pub fn main() {
    println!("Access the server at http://127.0.0.1:8000/upload");
    let _guard = set_global_logger(
        LogFileWriter::new_builder("log", 100 * 1024 * 1024)
            .start_writer_thread()
            .unwrap(),
    )
    .unwrap();
    safina_timer::start_timer_thread();
    let executor = safina_executor::Executor::default();
    let cache_dir = TempDir::new().unwrap();
    let state = Arc::new(State::new());
    let request_handler =
        move |req: Request| log_request_and_response(req, |req| handle_req(state, req)).unwrap();
    executor
        .block_on(
            HttpServerBuilder::new()
                .listen_addr(socket_addr_127_0_0_1(8000))
                .max_conns(100)
                .small_body_len(64 * 1024)
                .receive_large_bodies(cache_dir.path())
                .spawn_and_join(request_handler),
        )
        .unwrap();
}
source

pub fn small_body_len(self, n: usize) -> Self

Automatically receive request bodies up to length n, saving them in memory.

The default value is 64 KiB.

Reject larger requests with 413 Payload Too Large. See receive_large_bodies.

You can estimate the server memory usage with: small_body_len * max_conns. Using the default settings: 64 KiB * 100 connections => 6.4 MiB.

Examples found in repository?
examples/http-put.rs (line 97)
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
pub fn main() {
    println!("Access the server at http://127.0.0.1:8000/upload");
    let _guard = set_global_logger(
        LogFileWriter::new_builder("log", 100 * 1024 * 1024)
            .start_writer_thread()
            .unwrap(),
    )
    .unwrap();
    safina_timer::start_timer_thread();
    let executor = safina_executor::Executor::default();
    let cache_dir = TempDir::new().unwrap();
    let state = Arc::new(State::new());
    let request_handler =
        move |req: Request| log_request_and_response(req, |req| handle_req(state, req)).unwrap();
    executor
        .block_on(
            HttpServerBuilder::new()
                .listen_addr(socket_addr_127_0_0_1(8000))
                .max_conns(100)
                .small_body_len(64 * 1024)
                .receive_large_bodies(cache_dir.path())
                .spawn_and_join(request_handler),
        )
        .unwrap();
}
source

pub fn permit(self, p: Permit) -> Self

Sets the permit used by the server.

Revoke the permit to make the server gracefully shut down.

Example
use servlin::{Response, HttpServerBuilder};
use servlin::reexport::{safina_executor, safina_timer};
use std::net::SocketAddr;
use permit::Permit;

safina_timer::start_timer_thread();
let executor = safina_executor::Executor::default();
let permit = Permit::new();
let (addr, stopped_receiver) = executor.block_on(
    HttpServerBuilder::new()
        .permit(permit.new_sub())
        .spawn(move |req| Response::text(200, "yo"))
).unwrap();
do_some_requests(addr).unwrap();
drop(permit); // Tell server to shut down.
stopped_receiver.recv(); // Wait for server to stop.
source

pub async fn spawn<F>( self, request_handler: F ) -> Result<(SocketAddr, Receiver<()>), Error>
where F: FnOnce(Request) -> Response + 'static + Clone + Send + Sync,

Spawns the server task.

Returns (addr, stopped_receiver). The server is listening on addr. After the server gracefully shuts down, it sends a message on stopped_receiver.

Errors

Returns an error when it fails to bind to the listen_addr.

source

pub async fn spawn_and_join<F>(self, request_handler: F) -> Result<(), Error>
where F: FnOnce(Request) -> Response + 'static + Clone + Send + Sync,

Spawns the server task and waits for it to shutdown gracefully.

Errors

Returns an error when it fails to bind to the listen_addr.

Examples found in repository?
examples/minimal.rs (line 42)
35
36
37
38
39
40
41
42
43
44
45
pub fn main() {
    safina_timer::start_timer_thread();
    let executor = safina_executor::Executor::default();
    executor
        .block_on(
            HttpServerBuilder::new()
                .listen_addr(socket_addr_127_0_0_1(8000))
                .spawn_and_join(|_req: Request| Response::not_found_404()),
        )
        .unwrap();
}
More examples
Hide additional examples
examples/events-sse.rs (line 95)
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
pub fn main() {
    println!("Access the server at http://127.0.0.1:8000/subscribe");
    let event_sender_thread_permit = Permit::new();
    let state = Arc::new(State::new());
    let state_clone = state.clone();
    std::thread::spawn(move || event_sender_thread(state_clone, event_sender_thread_permit));
    safina_timer::start_timer_thread();
    let executor = safina_executor::Executor::default();
    let request_handler =
        move |req: Request| log_request_and_response(req, |req| handle_req(state, req)).unwrap();
    executor
        .block_on(
            HttpServerBuilder::new()
                .listen_addr(socket_addr_127_0_0_1(8000))
                .max_conns(100)
                .spawn_and_join(request_handler),
        )
        .unwrap();
}
examples/http-put.rs (line 99)
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
pub fn main() {
    println!("Access the server at http://127.0.0.1:8000/upload");
    let _guard = set_global_logger(
        LogFileWriter::new_builder("log", 100 * 1024 * 1024)
            .start_writer_thread()
            .unwrap(),
    )
    .unwrap();
    safina_timer::start_timer_thread();
    let executor = safina_executor::Executor::default();
    let cache_dir = TempDir::new().unwrap();
    let state = Arc::new(State::new());
    let request_handler =
        move |req: Request| log_request_and_response(req, |req| handle_req(state, req)).unwrap();
    executor
        .block_on(
            HttpServerBuilder::new()
                .listen_addr(socket_addr_127_0_0_1(8000))
                .max_conns(100)
                .small_body_len(64 * 1024)
                .receive_large_bodies(cache_dir.path())
                .spawn_and_join(request_handler),
        )
        .unwrap();
}

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more