From 0a77d0c2e980735d4df5cd6b5222f9bd5648730a Mon Sep 17 00:00:00 2001 From: DarkCat09 Date: Thu, 1 Aug 2024 12:28:13 +0400 Subject: [PATCH] docs: add comments (and blank lines) --- src/lib.rs | 27 ++++++++++++++++++++++++++- src/status.rs | 5 +++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 30618e8..2b21702 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,43 +46,68 @@ impl From for Client { impl Client { pub async fn request(self: &Self, url_str: &str) -> Result { let url = Url::parse(url_str).map_err(|e| InvalidUrl::ParseError(e))?; + // for proxying http(s) through gemini server, + // use Client::request_with_host if url.scheme() != "gemini" { + // deny non-Gemini req return Err(InvalidUrl::SchemeNotGemini.into()); } + // userinfo (user:pswd@) is not allowed in Gemini if !url.username().is_empty() { return Err(InvalidUrl::UserinfoPresent.into()); } + let host = url.host_str().ok_or(InvalidUrl::ConvertError)?; let addr = (host, url.port().unwrap_or(1965)) .to_socket_addrs()? .next() .ok_or(InvalidUrl::ConvertError)?; + let domain = pki_types::ServerName::try_from(host) .map_err(|_| InvalidUrl::ConvertError)? .to_owned(); + let stream = TcpStream::connect(&addr).await?; let mut stream = self.connector.connect(domain, stream).await?; + + // Write URL, then CRLF stream.write_all(url_str.as_bytes()).await?; stream.write_all(b"\r\n").await?; + let mut buf: [u8; 3] = [0, 0, 0]; // 2 digits, space stream.read_exact(&mut buf).await?; let status = Status::parse_status(&buf)?; + let mut message: Vec = Vec::new(); let mut buf_reader = tokio::io::BufReader::new(&mut stream); - let mut buf: [u8; 1] = [0]; + let mut buf: [u8; 1] = [0]; // buffer for LF (\n) + + // reading message after status code + // until CRLF (\r\n) loop { + // until CR buf_reader.read_until(b'\r', &mut message).await?; + // now read next char... buf_reader.read_exact(&mut buf).await?; if buf[0] == b'\n' { + // ...and check if it's LF break; } else { + // ...otherwise, CR is a part of message, not a CRLF terminator, + // so append that one byte that's supposed to be LF (but not LF) + // to the message buffer message.push(buf[0].into()); } } + + // trim last CR if message.last().is_some_and(|c| c == &b'\r') { message.pop(); } + + // Vec -> ASCII or UTF-8 String let message = String::from_utf8(message)?; + Ok(Response::new(status, message, stream)) } } diff --git a/src/status.rs b/src/status.rs index 42effe5..e59bc3e 100644 --- a/src/status.rs +++ b/src/status.rs @@ -54,11 +54,16 @@ const ASCII_ZERO: u8 = 48; // '0' impl Status { pub fn parse_status(buf: &[u8]) -> Result { + // simple decimal digit conversion + // '2' - '0' = 50 - 48 = 2 (from byte '2' to uint 2) let first = buf[0] - ASCII_ZERO; let second = buf[1] - ASCII_ZERO; Ok(Status { + // get enum item for 2-digit status code status_code: StatusCode::try_from_primitive(first * 10 + second)?, + // get enum entry for first digit reply_type: ReplyType::try_from_primitive(first)?, + // provide separate field for the 2nd digit second_digit: second, }) }