0
点赞
收藏
分享

微信扫一扫

Rust Web 全栈开发 - 3 HTTP响应

女侠展昭 2022-04-04 阅读 62

3. HTTP响应

在前面我们编写了HTTP请求相关的的代码

现在我们在如下文件中继续编写与HTTP响应相关的代码

首先我们需要定义HttpResponse结构体

然后再为其实现一些trait和方法,最后我们会针对这写方法和trait进行测试

具体代码如下

use std::collections::HashMap;
use std::io::{Result,Write};


//import three traits

#[derive(Debug, PartialEq, Clone)]


//define a struct that includes some properties
pub struct HttpResponse<'a> {
     version: &'a str,
     status_code: &'a str,
     status_text: &'a str,
     headers: Option<HashMap<&'a str,&'a str>>,
     body:Option<String>, 
}

//implement trait for struct above
//it can specify the default value to HttpResponse(because the trait has a method related to struct(HttpResponse))

impl <'a> Default for HttpResponse<'a> {
     fn default()->Self {

          //some default values

          Self {
               version: "HTTP/1.1".into(),
               status_code:"200".into(),
               status_text:"OK".into(),
               headers:None,
               body:None,
          }
     }
}

//implement methods

impl<'a> HttpResponse<'a> {

     //create new struct (HttpResponse) 
     pub fn new (
     
          status_code: &'a str,
          headers: Option<HashMap<&'a str,&'a str>>,
          body: Option<String>

     ) -> HttpResponse<'a> {

          let mut response: HttpResponse<'a> = HttpResponse::default();
          if status_code != "200" {
               response.status_code = status_code.into();
          }; 
          response.headers = match &headers {
              Some(_h) => headers,
              None => {
                   let mut h = HashMap::new();
                   h.insert("Content-Type","text/html");
                   Some(h)
              }
          };
          response.status_text = match response.status_code {
               "200" => "OK".into(),
               "400" =>"Bad Request".into(),
               "404" =>"Not Found".into(),
               "500" => "Internal Server Error".into(),
               _ =>"Not Found".into(),
          };
          response.body = body;

          response
     }

     //send a response
     pub fn send_response(&self, write_stream: &mut impl Write)-> Result<()> {

          let res = self.clone();
          let response_string: String = String::from(res);
          let _ = write!(write_stream, "{}",response_string);

          Ok(())
     }
     
     fn version(&self) -> &str {
          self.version
     }

     fn status_code(&self)->&str {
          self.status_code
          }

     fn status_text(&self)->&str {
          self.status_text
     }

     fn headers(&self) -> String {

          let map: HashMap<&str,&str> = self.headers.clone().unwrap();
          let mut header_string :String = "".into();

          for (k,v) in map.iter(){
               header_string = format!("{}{}:{}\r\n", header_string, k,v);
          }
          header_string
     }

     pub fn body(&self) -> &str {
          match &self.body {
               Some(b) => b.as_str(),
               None => "",
          }
     }
}

//implement trait for struct above
//convert HttpResponse to String

impl <'a> From<HttpResponse<'a>> for String {
     fn from(res:HttpResponse)->String {
          let res1 = res.clone();
          format!(
               "{} {} {}\r\n{}Content-Length:{}\r\n\r\n{}",
               &res1.version(),
               &res1.status_code(),
               &res1.status_text(),
               &res1.headers(),
               &res.body.unwrap().len(),
               &res1.body()
          )
     }
}

//test method

#[cfg(test)]

mod tests {

     use super::*;

     #[test]

     fn test_response_struct_creation_404() {
          let response_actual = HttpResponse::new(
               "404", 
               None, 
               Some("xxxx".into())
          );
      
          let response_expected = HttpResponse{
               version: "HTTP/1.1",
               status_code:"404",
               status_text:"Not Found",
               headers: {
                    let mut h = HashMap::new();
                    h.insert("Content-Type","text/html");
                    Some(h)
               },
               body:Some("xxxx".into())
          };

          assert_eq!(response_expected,response_actual);
          
     }

     #[test]

     fn test_response_struct_creation_200() {
          let response_actual = HttpResponse::new("200",None,Some("xxxx".into()));
      
          let response_expected = HttpResponse{
               version: "HTTP/1.1",
               status_code:"200",
               status_text:"OK",
               headers: {
                    let mut h = HashMap::new();
                    h.insert("Content-Type","text/html");
                    Some(h)
               },
              body:Some("xxxx".into()),
          };

          assert_eq!(response_expected,response_actual);
          
     }

     #[test]

     fn test_http_response_creation() {
          let response_expected = HttpResponse {
               version:"HTTP/1.1",
               status_code:"404",
               status_text:"Not Found",
               headers:{
                    let mut h = HashMap::new();
                    h.insert("Content-Type","text/html");
                    Some(h)
               },
               body:Some("xxxx".into()),
          };
          let http_string: String = response_expected.into();
          let actual_string = "HTTP/1.1 404 Not Found\r\nContent-Type:text/html\r\nContent-Length:4\r\n\r\nxxxx";

          assert_eq!(http_string,actual_string);
     }

}
举报

相关推荐

0 条评论