1010/// let server = Server::new("127.0.0.1:8080".to_string());
1111/// server.run();
1212/// ```
13- use crate :: http:: { Request , Response , StatusCode } ;
13+ use crate :: http:: { ParseError , Request , Response , StatusCode } ;
1414use std:: io:: { Read , Write } ; // For reading from the TCP stream
1515use std:: net:: TcpListener ; // For listening to TCP connections
1616
17- const DEFAULT_BODY : & str = "<html><body><h1>Hello</h1></body></html>" ;
17+ /// A trait for handling HTTP requests. Instead of implementing handling logic over
18+ /// and over in the `Server` struct, we can implement it in a separate struct
19+ /// and pass it to the `Server` as a parameter, in order to reduce repetition.
20+ /// This is useful for testing and for implementing different handlers for different routes.
21+ pub trait Handler {
22+ fn handle_request ( & mut self , request : & Request ) -> Response ;
23+ fn handle_bad_request ( & mut self , e : & ParseError ) -> Response {
24+ println ! ( "Error: parsing request\n {}" , e) ;
25+ Response :: new ( StatusCode :: BadRequest , None )
26+ }
27+ }
28+
1829#[ derive( Debug ) ]
1930pub struct Server {
2031 pub addr : String , // Address to bind the server to (e.g., "127.0.0.1:8080")
@@ -30,7 +41,7 @@ impl Server {
3041 }
3142
3243 /// Runs the server, listening for incoming TCP connections and handling requests.
33- pub fn run ( & self ) {
44+ pub fn run ( & self , mut handler : impl Handler ) {
3445 println ! ( "Listening on {}" , self . addr) ;
3546 // Bind the TCP listener to the specified address
3647 let listener = TcpListener :: bind ( & self . addr ) . unwrap ( ) ;
@@ -53,29 +64,17 @@ impl Server {
5364 String :: from_utf8_lossy( & buffer[ ..bytes_read] )
5465 ) ;
5566 // Attempt to parse the HTTP request from the buffer
56- match Request :: try_from ( & buffer[ ..bytes_read] ) {
57- Ok ( request) => {
58- // Debug print the parsed request
59- dbg ! ( request) ;
60- // Create a response with a status code of 200 OK and a body of "Hello"
61- let response = Response :: new (
62- StatusCode :: Ok ,
63- Some ( DEFAULT_BODY . to_string ( ) ) ,
64- ) ;
65- // Write the response to the client
66- if let Err ( e) = response. send ( & mut sock_stream) {
67- // If there's an error writing to the client, print the error
68- println ! (
69- "========== Error: Failed to write response to client ==========\n {}" ,
70- e
71- ) ;
72- }
73- }
74- Err ( e) => {
75- // Print any parsing errors
76- println ! ( "========== Error ==========\n {}" , e) ;
77- }
67+ let response = match Request :: try_from ( & buffer[ ..bytes_read] ) {
68+ Ok ( request) => handler. handle_request ( & request) ,
69+ Err ( e) => handler. handle_bad_request ( & e) ,
70+ } ;
71+
72+ // Write the response to the client
73+ if let Err ( e) = response. send ( & mut sock_stream) {
74+ // If there's an error writing to the client, print the error
75+ println ! ( "Error: Failed to write response\n {}" , e) ;
7876 }
77+
7978 // 2 ways to convert between Request and &[u8] using TryFrom and TryInto:
8079 // Request::try_from(&buffer[..bytes_read]);
8180 // let res: &Result<Request, _> = &buffer[..].try_into();
0 commit comments