tide/
server.rs

1//! An HTTP server
2
3use async_std::io;
4use async_std::sync::Arc;
5
6#[cfg(feature = "cookies")]
7use crate::cookies;
8use crate::listener::{Listener, ToListener};
9use crate::log;
10use crate::middleware::{Middleware, Next};
11use crate::router::{Router, Selection};
12use crate::{Endpoint, Request, Route};
13
14/// An HTTP server.
15///
16/// Servers are built up as a combination of *state*, *endpoints* and *middleware*:
17///
18/// - Server state is user-defined, and is provided via the [`Server::with_state`] function. The
19/// state is available as a shared reference to all app endpoints.
20///
21/// - Endpoints provide the actual application-level code corresponding to
22/// particular URLs. The [`Server::at`] method creates a new *route* (using
23/// standard router syntax), which can then be used to register endpoints
24/// for particular HTTP request types.
25///
26/// - Middleware extends the base Tide framework with additional request or
27/// response processing, such as compression, default headers, or logging. To
28/// add middleware to an app, use the [`Server::middleware`] method.
29pub struct Server<State> {
30    router: Arc<Router<State>>,
31    state: State,
32    /// Holds the middleware stack.
33    ///
34    /// Note(Fishrock123): We do actually want this structure.
35    /// The outer Arc allows us to clone in .respond() without cloning the array.
36    /// The Vec allows us to add middleware at runtime.
37    /// The inner Arc-s allow MiddlewareEndpoint-s to be cloned internally.
38    /// We don't use a Mutex around the Vec here because adding a middleware during execution should be an error.
39    #[allow(clippy::rc_buffer)]
40    middleware: Arc<Vec<Arc<dyn Middleware<State>>>>,
41}
42
43impl Server<()> {
44    /// Create a new Tide server.
45    ///
46    /// # Examples
47    ///
48    /// ```no_run
49    /// # use async_std::task::block_on;
50    /// # fn main() -> Result<(), std::io::Error> { block_on(async {
51    /// #
52    /// let mut app = tide::new();
53    /// app.at("/").get(|_| async { Ok("Hello, world!") });
54    /// app.listen("127.0.0.1:8080").await?;
55    /// #
56    /// # Ok(()) }) }
57    /// ```
58    #[must_use]
59    pub fn new() -> Self {
60        Self::with_state(())
61    }
62}
63
64impl Default for Server<()> {
65    fn default() -> Self {
66        Self::new()
67    }
68}
69
70impl<State> Server<State>
71where
72    State: Clone + Send + Sync + 'static,
73{
74    /// Create a new Tide server with shared application scoped state.
75    ///
76    /// Application scoped state is useful for storing items
77    ///
78    /// # Examples
79    ///
80    /// ```no_run
81    /// # use async_std::task::block_on;
82    /// # fn main() -> Result<(), std::io::Error> { block_on(async {
83    /// #
84    /// use tide::Request;
85    ///
86    /// /// The shared application state.
87    /// #[derive(Clone)]
88    /// struct State {
89    ///     name: String,
90    /// }
91    ///
92    /// // Define a new instance of the state.
93    /// let state = State {
94    ///     name: "Nori".to_string()
95    /// };
96    ///
97    /// // Initialize the application with state.
98    /// let mut app = tide::with_state(state);
99    /// app.at("/").get(|req: Request<State>| async move {
100    ///     Ok(format!("Hello, {}!", &req.state().name))
101    /// });
102    /// app.listen("127.0.0.1:8080").await?;
103    /// #
104    /// # Ok(()) }) }
105    /// ```
106    pub fn with_state(state: State) -> Self {
107        Self {
108            router: Arc::new(Router::new()),
109            middleware: Arc::new(vec![
110                #[cfg(feature = "cookies")]
111                Arc::new(cookies::CookiesMiddleware::new()),
112                #[cfg(feature = "logger")]
113                Arc::new(log::LogMiddleware::new()),
114            ]),
115            state,
116        }
117    }
118
119    /// Add a new route at the given `path`, relative to root.
120    ///
121    /// Routing means mapping an HTTP request to an endpoint. Here Tide applies
122    /// a "table of contents" approach, which makes it easy to see the overall
123    /// app structure. Endpoints are selected solely by the path and HTTP method
124    /// of a request: the path determines the resource and the HTTP verb the
125    /// respective endpoint of the selected resource. Example:
126    ///
127    /// ```rust,no_run
128    /// # let mut app = tide::Server::new();
129    /// app.at("/").get(|_| async { Ok("Hello, world!") });
130    /// ```
131    ///
132    /// A path is comprised of zero or many segments, i.e. non-empty strings
133    /// separated by '/'. There are two kinds of segments: concrete and
134    /// wildcard. A concrete segment is used to exactly match the respective
135    /// part of the path of the incoming request. A wildcard segment on the
136    /// other hand extracts and parses the respective part of the path of the
137    /// incoming request to pass it along to the endpoint as an argument. A
138    /// wildcard segment is written as `:name`, which creates an endpoint
139    /// parameter called `name`. It is not possible to define wildcard segments
140    /// with different names for otherwise identical paths.
141    ///
142    /// Alternatively a wildcard definitions can start with a `*`, for example
143    /// `*path`, which means that the wildcard will match to the end of given
144    /// path, no matter how many segments are left, even nothing.
145    ///
146    /// The name of the parameter can be omitted to define a path that matches
147    /// the required structure, but where the parameters are not required.
148    /// `:` will match a segment, and `*` will match an entire path.
149    ///
150    /// Here are some examples omitting the HTTP verb based endpoint selection:
151    ///
152    /// ```rust,no_run
153    /// # let mut app = tide::Server::new();
154    /// app.at("/");
155    /// app.at("/hello");
156    /// app.at("add_two/:num");
157    /// app.at("files/:user/*");
158    /// app.at("static/*path");
159    /// app.at("static/:context/:");
160    /// ```
161    ///
162    /// There is no fallback route matching, i.e. either a resource is a full
163    /// match or not, which means that the order of adding resources has no
164    /// effect.
165    pub fn at<'a>(&'a mut self, path: &str) -> Route<'a, State> {
166        let router = Arc::get_mut(&mut self.router)
167            .expect("Registering routes is not possible after the Server has started");
168        Route::new(router, path.to_owned())
169    }
170
171    /// Add middleware to an application.
172    ///
173    /// Middleware provides customization of the request/response cycle, such as compression,
174    /// logging, or header modification. Middleware is invoked when processing a request, and can
175    /// either continue processing (possibly modifying the response) or immediately return a
176    /// response. See the [`Middleware`] trait for details.
177    ///
178    /// Middleware can only be added at the "top level" of an application, and is processed in the
179    /// order in which it is applied.
180    pub fn with<M>(&mut self, middleware: M) -> &mut Self
181    where
182        M: Middleware<State>,
183    {
184        log::trace!("Adding middleware {}", middleware.name());
185        let m = Arc::get_mut(&mut self.middleware)
186            .expect("Registering middleware is not possible after the Server has started");
187        m.push(Arc::new(middleware));
188        self
189    }
190
191    /// Asynchronously serve the app with the supplied listener.
192    ///
193    /// This is a shorthand for calling `Server::bind`, logging the `ListenInfo`
194    /// instances from `Listener::info`, and then calling `Listener::accept`.
195    ///
196    /// # Examples
197    ///
198    /// ```no_run
199    /// # use async_std::task::block_on;
200    /// # fn main() -> Result<(), std::io::Error> { block_on(async {
201    /// #
202    /// let mut app = tide::new();
203    /// app.at("/").get(|_| async { Ok("Hello, world!") });
204    /// app.listen("127.0.0.1:8080").await?;
205    /// #
206    /// # Ok(()) }) }
207    /// ```
208    pub async fn listen<L: ToListener<State>>(self, listener: L) -> io::Result<()> {
209        let mut listener = listener.to_listener()?;
210        listener.bind(self).await?;
211        for info in listener.info().iter() {
212            log::info!("Server listening on {}", info);
213        }
214        listener.accept().await?;
215        Ok(())
216    }
217
218    /// Asynchronously bind the listener.
219    ///
220    /// Bind the listener. This starts the listening process by opening the
221    /// necessary network ports, but not yet accepting incoming connections.
222    /// `Listener::listen` should be called after this to start accepting
223    /// connections.
224    ///
225    /// When calling `Listener::info` multiple `ListenInfo` instances may be
226    /// returned. This is useful when using for example `ConcurrentListener`
227    /// which enables a single server to listen on muliple ports.
228    ///
229    /// # Examples
230    ///
231    /// ```no_run
232    /// # use async_std::task::block_on;
233    /// # fn main() -> Result<(), std::io::Error> { block_on(async {
234    /// #
235    /// use tide::prelude::*;
236    ///
237    /// let mut app = tide::new();
238    /// app.at("/").get(|_| async { Ok("Hello, world!") });
239    /// let mut listener = app.bind("127.0.0.1:8080").await?;
240    /// for info in listener.info().iter() {
241    ///     println!("Server listening on {}", info);
242    /// }
243    /// listener.accept().await?;
244    /// #
245    /// # Ok(()) }) }
246    /// ```
247    pub async fn bind<L: ToListener<State>>(
248        self,
249        listener: L,
250    ) -> io::Result<<L as ToListener<State>>::Listener> {
251        let mut listener = listener.to_listener()?;
252        listener.bind(self).await?;
253        Ok(listener)
254    }
255
256    /// Respond to a `Request` with a `Response`.
257    ///
258    /// This method is useful for testing endpoints directly,
259    /// or for creating servers over custom transports.
260    ///
261    /// # Examples
262    ///
263    /// ```no_run
264    /// # #[async_std::main]
265    /// # async fn main() -> http_types::Result<()> {
266    /// #
267    /// use tide::http::{Url, Method, Request, Response};
268    ///
269    /// let mut app = tide::new();
270    /// app.at("/").get(|_| async { Ok("hello world") });
271    ///
272    /// let req = Request::new(Method::Get, Url::parse("https://example.com")?);
273    /// let res: Response = app.respond(req).await?;
274    ///
275    /// assert_eq!(res.status(), 200);
276    /// #
277    /// # Ok(()) }
278    /// ```
279    pub async fn respond<Req, Res>(&self, req: Req) -> http_types::Result<Res>
280    where
281        Req: Into<http_types::Request>,
282        Res: From<http_types::Response>,
283    {
284        let req = req.into();
285        let Self {
286            router,
287            state,
288            middleware,
289        } = self.clone();
290
291        let method = req.method().to_owned();
292        let Selection { endpoint, params } = router.route(&req.url().path(), method);
293        let route_params = vec![params];
294        let req = Request::new(state, req, route_params);
295
296        let next = Next {
297            endpoint,
298            next_middleware: &middleware,
299        };
300
301        let res = next.run(req).await;
302        let res: http_types::Response = res.into();
303        Ok(res.into())
304    }
305
306    /// Gets a reference to the server's state. This is useful for testing and nesting:
307    ///
308    /// # Example
309    ///
310    /// ```rust
311    /// # #[derive(Clone)] struct SomeAppState;
312    /// let mut app = tide::with_state(SomeAppState);
313    /// let mut admin = tide::with_state(app.state().clone());
314    /// admin.at("/").get(|_| async { Ok("nested app with cloned state") });
315    /// app.at("/").nest(admin);
316    /// ```
317    pub fn state(&self) -> &State {
318        &self.state
319    }
320}
321
322impl<State: Send + Sync + 'static> std::fmt::Debug for Server<State> {
323    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
324        f.debug_struct("Server").finish()
325    }
326}
327
328impl<State: Clone> Clone for Server<State> {
329    fn clone(&self) -> Self {
330        Self {
331            router: self.router.clone(),
332            state: self.state.clone(),
333            middleware: self.middleware.clone(),
334        }
335    }
336}
337
338#[async_trait::async_trait]
339impl<State: Clone + Sync + Send + 'static, InnerState: Clone + Sync + Send + 'static>
340    Endpoint<State> for Server<InnerState>
341{
342    async fn call(&self, req: Request<State>) -> crate::Result {
343        let Request {
344            req,
345            mut route_params,
346            ..
347        } = req;
348        let path = req.url().path().to_owned();
349        let method = req.method().to_owned();
350        let router = self.router.clone();
351        let middleware = self.middleware.clone();
352        let state = self.state.clone();
353
354        let Selection { endpoint, params } = router.route(&path, method);
355        route_params.push(params);
356        let req = Request::new(state, req, route_params);
357
358        let next = Next {
359            endpoint,
360            next_middleware: &middleware,
361        };
362
363        Ok(next.run(req).await)
364    }
365}
366
367#[crate::utils::async_trait]
368impl<State: Clone + Send + Sync + Unpin + 'static> http_client::HttpClient for Server<State> {
369    async fn send(&self, req: crate::http::Request) -> crate::http::Result<crate::http::Response> {
370        self.respond(req).await
371    }
372}
373
374#[cfg(test)]
375mod test {
376    use crate as tide;
377
378    #[test]
379    fn allow_nested_server_with_same_state() {
380        let inner = tide::new();
381        let mut outer = tide::new();
382        outer.at("/foo").get(inner);
383    }
384
385    #[test]
386    fn allow_nested_server_with_different_state() {
387        let inner = tide::with_state(1);
388        let mut outer = tide::new();
389        outer.at("/foo").get(inner);
390    }
391}