From 4ee431a805bff5c587c63378f3cc1ba880752310 Mon Sep 17 00:00:00 2001 From: Xuanwo Date: Mon, 25 Dec 2023 13:24:32 +0800 Subject: [PATCH] refactor: Polish http_util parse headers (#3817) Signed-off-by: Xuanwo --- core/src/raw/http_util/header.rs | 88 ++++++++++++++++---------------- 1 file changed, 43 insertions(+), 45 deletions(-) diff --git a/core/src/raw/http_util/header.rs b/core/src/raw/http_util/header.rs index 25d8919fbbf..f266f7c0c46 100644 --- a/core/src/raw/http_util/header.rs +++ b/core/src/raw/http_util/header.rs @@ -19,7 +19,6 @@ use base64::engine::general_purpose; use base64::Engine; use chrono::DateTime; use chrono::Utc; -use http::header::AsHeaderName; use http::header::CACHE_CONTROL; use http::header::CONTENT_DISPOSITION; use http::header::CONTENT_LENGTH; @@ -28,8 +27,8 @@ use http::header::CONTENT_TYPE; use http::header::ETAG; use http::header::LAST_MODIFIED; use http::header::LOCATION; -use http::HeaderMap; use http::HeaderValue; +use http::{HeaderMap, HeaderName}; use md5::Digest; use crate::raw::*; @@ -45,7 +44,6 @@ use crate::Result; /// The returned value maybe a relative path, like `/index.html`, `/robots.txt`, etc. pub fn parse_location(headers: &HeaderMap) -> Result> { parse_header_to_str(headers, LOCATION) - .map_err(|e| e.with_operation("http_util::parse_location")) } /// Parse cache control from header map. @@ -56,82 +54,82 @@ pub fn parse_location(headers: &HeaderMap) -> Result> { /// maybe `no-cache`, `max-age=3600`, etc. pub fn parse_cache_control(headers: &HeaderMap) -> Result> { parse_header_to_str(headers, CACHE_CONTROL) - .map_err(|e| e.with_operation("http_util::parse_cache_control")) } /// Parse content length from header map. pub fn parse_content_length(headers: &HeaderMap) -> Result> { - let v = parse_header_to_str(headers, CONTENT_LENGTH) - .map_err(|e| e.with_operation("http_util::parse_content_length"))?; - - match v { - None => Ok(None), - Some(v) => Ok(Some(v.parse::().map_err(|e| { - Error::new(ErrorKind::Unexpected, "header value is not valid integer") - .with_operation("http_util::parse_content_length") - .set_source(e) - })?)), - } + parse_header_to_str(headers, CONTENT_LENGTH)? + .map(|v| { + v.parse::().map_err(|e| { + Error::new(ErrorKind::Unexpected, "header value is not valid integer").set_source(e) + }) + }) + .transpose() } /// Parse content md5 from header map. pub fn parse_content_md5(headers: &HeaderMap) -> Result> { parse_header_to_str(headers, "content-md5") - .map_err(|e| e.with_operation("http_util::parse_content_md5")) } /// Parse content type from header map. pub fn parse_content_type(headers: &HeaderMap) -> Result> { parse_header_to_str(headers, CONTENT_TYPE) - .map_err(|e| e.with_operation("http_util::parse_content_type")) } /// Parse content range from header map. pub fn parse_content_range(headers: &HeaderMap) -> Result> { - let v = parse_header_to_str(headers, CONTENT_RANGE) - .map_err(|e| e.with_operation("http_util::parse_content_range"))?; - - match v { - None => Ok(None), - Some(v) => Ok(Some(v.parse()?)), - } + parse_header_to_str(headers, CONTENT_RANGE)? + .map(|v| v.parse()) + .transpose() } /// Parse last modified from header map. pub fn parse_last_modified(headers: &HeaderMap) -> Result>> { - let v = parse_header_to_str(headers, LAST_MODIFIED) - .map_err(|e| e.with_operation("http_util::parse_content_disposition"))?; - - match v { - None => Ok(None), - Some(v) => Ok(Some(parse_datetime_from_rfc2822(v)?)), - } + parse_header_to_str(headers, LAST_MODIFIED)? + .map(parse_datetime_from_rfc2822) + .transpose() } /// Parse etag from header map. pub fn parse_etag(headers: &HeaderMap) -> Result> { - parse_header_to_str(headers, ETAG).map_err(|e| e.with_operation("http_util::parse_etag")) + parse_header_to_str(headers, ETAG) } /// Parse Content-Disposition for header map pub fn parse_content_disposition(headers: &HeaderMap) -> Result> { parse_header_to_str(headers, CONTENT_DISPOSITION) - .map_err(|e| e.with_operation("http_util::parse_content_disposition")) } /// Parse header value to string according to name. -pub fn parse_header_to_str(headers: &HeaderMap, name: K) -> Result> { - match headers.get(name) { - None => Ok(None), - Some(v) => Ok(Some(v.to_str().map_err(|e| { - Error::new( - ErrorKind::Unexpected, - "header value has to be valid utf-8 string", - ) - .with_operation("http_util::parse_header_to_str") - .set_source(e) - })?)), - } +#[inline] +pub fn parse_header_to_str(headers: &HeaderMap, name: K) -> Result> +where + HeaderName: TryFrom, +{ + let name = HeaderName::try_from(name).map_err(|_| { + Error::new( + ErrorKind::Unexpected, + "header name must be valid http header name but not", + ) + .with_operation("http_util::parse_header_to_str") + })?; + + let value = if let Some(v) = headers.get(name.clone()) { + v + } else { + return Ok(None); + }; + + Ok(Some(value.to_str().map_err(|e| { + Error::new( + ErrorKind::Unexpected, + "header value must be valid utf-8 string but not", + ) + .with_operation("http_util::parse_header_to_str") + .with_context("header_name", name.as_str()) + .set_source(e) + })?)) } /// parse_into_metadata will parse standards http headers into Metadata.