Repository: bearcove/loona (language: rust)

Issue:
Build docs in CI (and deny warnings)



Discussion / hints:

Fix patch:
diff --git a/Justfile b/Justfile
index 14bbbba2..7f9749ca 100644
--- a/Justfile
+++ b/Justfile
@@ -7,7 +7,6 @@ _default:
 ci-test: #!/bin/bash -eux
     just httpwg-hyper
     just cov
-    just httpwg-over-tcp
 
 cov:
     #!/bin/bash -eux
@@ -21,6 +20,14 @@ cov:
 httpwg-hyper:
 	cargo build --release -p httpwg-hyper
 
+d *args:
+    just doc {{args}}
+
+doc:
+    #!/usr/bin/env -S bash -eux
+    export RUSTDOCFLAGS="-D warnings"
+    cargo doc --no-deps --document-private-items
+
 t *args:
     just test {{args}}
 
diff --git a/crates/buffet/src/io.rs b/crates/buffet/src/io.rs
index 0dbb9486..f21cb6b8 100644
--- a/crates/buffet/src/io.rs
+++ b/crates/buffet/src/io.rs
@@ -13,7 +13,7 @@ pub trait ReadOwned {
 #[allow(async_fn_in_trait)] // we never require Send
 pub trait WriteOwned {
     /// Write a single buffer, taking ownership for the duration of the write.
-    /// Might perform a partial write, see [WriteOwned::write_all]
+    /// Might perform a partial write, see [WriteOwned::write_all_owned]
     async fn write_owned(&mut self, buf: impl Into<Piece>) -> BufResult<usize, Piece>;
 
     /// Write a single buffer, re-trying the write if the kernel does a partial
@@ -38,7 +38,7 @@ pub trait WriteOwned {
     }
 
     /// Write a list of buffers, taking ownership for the duration of the write.
-    /// Might perform a partial write, see [WriteOwned::writev_all]
+    /// Might perform a partial write, see [WriteOwned::writev_all_owned]
     async fn writev_owned(&mut self, list: &PieceList) -> std::io::Result<usize> {
         let mut total = 0;
 
diff --git a/crates/httpwg-macros/src/lib.rs b/crates/httpwg-macros/src/lib.rs
index a60ab22e..e8cd3a2d 100644
--- a/crates/httpwg-macros/src/lib.rs
+++ b/crates/httpwg-macros/src/lib.rs
@@ -780,7 +780,7 @@ $body
 ///
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 #[test]
 fn sends_headers_frame_with_uppercase_field_name() {
@@ -795,7 +795,7 @@ $body
 ///
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 #[test]
 fn sends_headers_frame_with_space_in_field_name() {
@@ -810,7 +810,7 @@ $body
 ///
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 #[test]
 fn sends_headers_frame_with_non_visible_ascii() {
@@ -825,7 +825,7 @@ $body
 ///
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 #[test]
 fn sends_headers_frame_with_del_character() {
@@ -840,7 +840,7 @@ $body
 ///
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 #[test]
 fn sends_headers_frame_with_non_ascii_character() {
@@ -854,7 +854,7 @@ $body
 ///
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 #[test]
 fn sends_headers_frame_with_colon_in_field_name() {
@@ -867,7 +867,7 @@ $body
 ///
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 #[test]
 fn sends_headers_frame_with_lf_in_field_value() {
@@ -880,7 +880,7 @@ $body
 ///
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 #[test]
 fn sends_headers_frame_with_cr_in_field_value() {
@@ -893,7 +893,7 @@ $body
 ///
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 #[test]
 fn sends_headers_frame_with_nul_in_field_value() {
@@ -905,7 +905,7 @@ $body
 /// (ASCII SP or HTAB, 0x20 or 0x09).
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 #[test]
 fn sends_headers_frame_with_leading_space_in_field_value() {
@@ -917,7 +917,7 @@ $body
 /// (ASCII SP or HTAB, 0x20 or 0x09).
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 #[test]
 fn sends_headers_frame_with_trailing_tab_in_field_value() {
@@ -925,12 +925,12 @@ use __group::sends_headers_frame_with_trailing_tab_in_field_value as test;
 $body
 }
 
-/// HTTP/2 does not use the Connection header field (Section 7.6.1 of [HTTP]) to
+/// HTTP/2 does not use the Connection header field (Section 7.6.1 of HTTP) to
 /// indicate connection-specific header fields; in this protocol,
 /// connection-specific metadata is conveyed by other means. An endpoint MUST
 /// NOT generate an HTTP/2 message containing connection-specific header fields.
 /// This includes the Connection header field and those listed as having
-/// connection-specific semantics in Section 7.6.1 of [HTTP] (that is,
+/// connection-specific semantics in Section 7.6.1 of HTTP (that is,
 /// Proxy-Connection, Keep-Alive, Transfer-Encoding, and Upgrade). Any message
 /// containing connection-specific header fields MUST be treated as malformed
 /// (Section 8.1.1).
@@ -940,13 +940,13 @@ use __group::sends_headers_frame_with_connection_header as test;
 $body
 }
 
-/// HTTP/2 does not use the Connection header field (Section 7.6.1 of [HTTP]) to
+/// HTTP/2 does not use the Connection header field (Section 7.6.1 of HTTP) to
 /// indicate connection-specific header fields; in this protocol,
 /// connection-specific metadata is conveyed by other means. An endpoint MUST
 /// NOT generate an HTTP/2 message containing connection-specific header fields.
 ///
 /// This includes the Connection header field and those listed as having
-/// connection-specific semantics in Section 7.6.1 of [HTTP] (that is,
+/// connection-specific semantics in Section 7.6.1 of HTTP (that is,
 /// Proxy-Connection, Keep-Alive, Transfer-Encoding, and Upgrade). Any message
 /// containing connection-specific header fields MUST be treated as malformed
 /// (Section 8.1.1).
@@ -956,13 +956,13 @@ use __group::sends_headers_frame_with_proxy_connection_header as test;
 $body
 }
 
-/// HTTP/2 does not use the Connection header field (Section 7.6.1 of [HTTP]) to
+/// HTTP/2 does not use the Connection header field (Section 7.6.1 of HTTP) to
 /// indicate connection-specific header fields; in this protocol,
 /// connection-specific metadata is conveyed by other means. An endpoint MUST
 /// NOT generate an HTTP/2 message containing connection-specific header fields.
 ///
 /// This includes the Connection header field and those listed as having
-/// connection-specific semantics in Section 7.6.1 of [HTTP] (that is,
+/// connection-specific semantics in Section 7.6.1 of HTTP (that is,
 /// Proxy-Connection, Keep-Alive, Transfer-Encoding, and Upgrade). Any message
 /// containing connection-specific header fields MUST be treated as malformed
 /// (Section 8.1.1).
@@ -972,13 +972,13 @@ use __group::sends_headers_frame_with_keep_alive_header as test;
 $body
 }
 
-/// HTTP/2 does not use the Connection header field (Section 7.6.1 of [HTTP]) to
+/// HTTP/2 does not use the Connection header field (Section 7.6.1 of HTTP) to
 /// indicate connection-specific header fields; in this protocol,
 /// connection-specific metadata is conveyed by other means. An endpoint MUST
 /// NOT generate an HTTP/2 message containing connection-specific header fields.
 ///
 /// This includes the Connection header field and those listed as having
-/// connection-specific semantics in Section 7.6.1 of [HTTP] (that is,
+/// connection-specific semantics in Section 7.6.1 of HTTP (that is,
 /// Proxy-Connection, Keep-Alive, Transfer-Encoding, and Upgrade). Any message
 /// containing connection-specific header fields MUST be treated as malformed
 /// (Section 8.1.1).
@@ -988,13 +988,13 @@ use __group::sends_headers_frame_with_transfer_encoding_header as test;
 $body
 }
 
-/// HTTP/2 does not use the Connection header field (Section 7.6.1 of [HTTP]) to
+/// HTTP/2 does not use the Connection header field (Section 7.6.1 of HTTP) to
 /// indicate connection-specific header fields; in this protocol,
 /// connection-specific metadata is conveyed by other means. An endpoint MUST
 /// NOT generate an HTTP/2 message containing connection-specific header fields.
 ///
 /// This includes the Connection header field and those listed as having
-/// connection-specific semantics in Section 7.6.1 of [HTTP] (that is,
+/// connection-specific semantics in Section 7.6.1 of HTTP (that is,
 /// Proxy-Connection, Keep-Alive, Transfer-Encoding, and Upgrade). Any message
 /// containing connection-specific header fields MUST be treated as malformed
 /// (Section 8.1.1).
@@ -1053,9 +1053,9 @@ $body
 /// A server SHOULD treat a request as malformed if it contains a Host header
 /// field that identifies an entity that differs from the entity in the
 /// ":authority" pseudo-header field. The values of fields need to be normalized
-/// to compare them (see Section 6.2 of [RFC3986]). An origin server can apply
+/// to compare them (see Section 6.2 of RFC3986). An origin server can apply
 /// any normalization method, whereas other servers MUST perform scheme-based
-/// normalization (see Section 6.2.3 of [RFC3986]) of the two fields.
+/// normalization (see Section 6.2.3 of RFC3986) of the two fields.
 ///
 /// cf. <https://www.rfc-editor.org/rfc/rfc3986.html#section-6.2.3>
 #[test]
@@ -1070,7 +1070,7 @@ $body
 ///
 /// an OPTIONS request for an "http" or "https" URI that does not include a path
 /// component; these MUST include a ":path" pseudo-header field with a value of
-/// '*' (see Section 7.1 of [HTTP]). CONNECT requests (Section 8.5), where the
+/// '*' (see Section 7.1 of HTTP). CONNECT requests (Section 8.5), where the
 /// ":path" pseudo-header field is omitted.
 #[test]
 fn sends_headers_frame_with_empty_path_component() {
@@ -1116,7 +1116,7 @@ use __group::client_sends_push_promise_frame as test;
 $body
 }
 
-/// The CONNECT method (Section 9.3.6 of [HTTP]) is used to convert an HTTP
+/// The CONNECT method (Section 9.3.6 of HTTP) is used to convert an HTTP
 /// connection into a tunnel to a remote host. CONNECT is primarily used with
 /// HTTP proxies to establish a TLS session with an origin server for the
 /// purposes of interacting with "https" resources.
diff --git a/crates/httpwg/src/rfc9113/_8_expressing_http_semantics_in_http2.rs b/crates/httpwg/src/rfc9113/_8_expressing_http_semantics_in_http2.rs
index c95892b4..d0cb5c99 100644
--- a/crates/httpwg/src/rfc9113/_8_expressing_http_semantics_in_http2.rs
+++ b/crates/httpwg/src/rfc9113/_8_expressing_http_semantics_in_http2.rs
@@ -43,7 +43,7 @@ pub async fn sends_second_headers_frame_without_end_stream<IO: IntoHalves>(
 // frame payload lengths that form the content, unless the message is defined as
 // having no content. For example, 204 or 304 responses contain no content, as
 // does the response to a HEAD request. A response that is defined to have no
-// content, as described in Section 6.4.1 of [HTTP], MAY have a non-zero
+// content, as described in Section 6.4.1 of HTTP, MAY have a non-zero
 // content-length header field, even though no content is included in DATA
 // frames.
 //
@@ -101,7 +101,7 @@ pub async fn sends_headers_frame_with_incorrect_content_length_multiple_data_fra
 ///
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 pub async fn sends_headers_frame_with_uppercase_field_name<IO: IntoHalves>(
     mut conn: Conn<IO>,
@@ -123,7 +123,7 @@ pub async fn sends_headers_frame_with_uppercase_field_name<IO: IntoHalves>(
 ///
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 pub async fn sends_headers_frame_with_space_in_field_name<IO: IntoHalves>(
     mut conn: Conn<IO>,
@@ -145,7 +145,7 @@ pub async fn sends_headers_frame_with_space_in_field_name<IO: IntoHalves>(
 ///
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 pub async fn sends_headers_frame_with_non_visible_ascii<IO: IntoHalves>(
     mut conn: Conn<IO>,
@@ -167,7 +167,7 @@ pub async fn sends_headers_frame_with_non_visible_ascii<IO: IntoHalves>(
 ///
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 pub async fn sends_headers_frame_with_del_character<IO: IntoHalves>(
     mut conn: Conn<IO>,
@@ -189,7 +189,7 @@ pub async fn sends_headers_frame_with_del_character<IO: IntoHalves>(
 ///
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 pub async fn sends_headers_frame_with_non_ascii_character<IO: IntoHalves>(
     mut conn: Conn<IO>,
@@ -210,7 +210,7 @@ pub async fn sends_headers_frame_with_non_ascii_character<IO: IntoHalves>(
 ///
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 pub async fn sends_headers_frame_with_colon_in_field_name<IO: IntoHalves>(
     mut conn: Conn<IO>,
@@ -230,7 +230,7 @@ pub async fn sends_headers_frame_with_colon_in_field_name<IO: IntoHalves>(
 ///
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 pub async fn sends_headers_frame_with_lf_in_field_value<IO: IntoHalves>(
     mut conn: Conn<IO>,
@@ -250,7 +250,7 @@ pub async fn sends_headers_frame_with_lf_in_field_value<IO: IntoHalves>(
 ///
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 pub async fn sends_headers_frame_with_cr_in_field_value<IO: IntoHalves>(
     mut conn: Conn<IO>,
@@ -270,7 +270,7 @@ pub async fn sends_headers_frame_with_cr_in_field_value<IO: IntoHalves>(
 ///
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 pub async fn sends_headers_frame_with_nul_in_field_value<IO: IntoHalves>(
     mut conn: Conn<IO>,
@@ -290,7 +290,7 @@ pub async fn sends_headers_frame_with_nul_in_field_value<IO: IntoHalves>(
 
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 pub async fn sends_headers_frame_with_leading_space_in_field_value<IO: IntoHalves>(
     mut conn: Conn<IO>,
@@ -310,7 +310,7 @@ pub async fn sends_headers_frame_with_leading_space_in_field_value<IO: IntoHalve
 
 /// When a request message violates one of these requirements, an implementation
 /// SHOULD generate a 400 (Bad Request) status code (see Section 15.5.1 of
-/// [HTTP]), unless a more suitable status code is defined or the status code
+/// HTTP), unless a more suitable status code is defined or the status code
 /// cannot be sent (e.g., because the error occurs in a trailer field).
 pub async fn sends_headers_frame_with_trailing_tab_in_field_value<IO: IntoHalves>(
     mut conn: Conn<IO>,
@@ -327,12 +327,12 @@ pub async fn sends_headers_frame_with_trailing_tab_in_field_value<IO: IntoHalves
 
 //---- Section 8.2.2: Connection-Specific Header Fields
 
-/// HTTP/2 does not use the Connection header field (Section 7.6.1 of [HTTP]) to
+/// HTTP/2 does not use the Connection header field (Section 7.6.1 of HTTP) to
 /// indicate connection-specific header fields; in this protocol,
 /// connection-specific metadata is conveyed by other means. An endpoint MUST
 /// NOT generate an HTTP/2 message containing connection-specific header fields.
 /// This includes the Connection header field and those listed as having
-/// connection-specific semantics in Section 7.6.1 of [HTTP] (that is,
+/// connection-specific semantics in Section 7.6.1 of HTTP (that is,
 /// Proxy-Connection, Keep-Alive, Transfer-Encoding, and Upgrade). Any message
 /// containing connection-specific header fields MUST be treated as malformed
 /// (Section 8.1.1).
@@ -349,13 +349,13 @@ pub async fn sends_headers_frame_with_connection_header<IO: IntoHalves>(
     Ok(())
 }
 
-/// HTTP/2 does not use the Connection header field (Section 7.6.1 of [HTTP]) to
+/// HTTP/2 does not use the Connection header field (Section 7.6.1 of HTTP) to
 /// indicate connection-specific header fields; in this protocol,
 /// connection-specific metadata is conveyed by other means. An endpoint MUST
 /// NOT generate an HTTP/2 message containing connection-specific header fields.
 ///
 /// This includes the Connection header field and those listed as having
-/// connection-specific semantics in Section 7.6.1 of [HTTP] (that is,
+/// connection-specific semantics in Section 7.6.1 of HTTP (that is,
 /// Proxy-Connection, Keep-Alive, Transfer-Encoding, and Upgrade). Any message
 /// containing connection-specific header fields MUST be treated as malformed
 /// (Section 8.1.1).
@@ -372,13 +372,13 @@ pub async fn sends_headers_frame_with_proxy_connection_header<IO: IntoHalves>(
     Ok(())
 }
 
-/// HTTP/2 does not use the Connection header field (Section 7.6.1 of [HTTP]) to
+/// HTTP/2 does not use the Connection header field (Section 7.6.1 of HTTP) to
 /// indicate connection-specific header fields; in this protocol,
 /// connection-specific metadata is conveyed by other means. An endpoint MUST
 /// NOT generate an HTTP/2 message containing connection-specific header fields.
 ///
 /// This includes the Connection header field and those listed as having
-/// connection-specific semantics in Section 7.6.1 of [HTTP] (that is,
+/// connection-specific semantics in Section 7.6.1 of HTTP (that is,
 /// Proxy-Connection, Keep-Alive, Transfer-Encoding, and Upgrade). Any message
 /// containing connection-specific header fields MUST be treated as malformed
 /// (Section 8.1.1).
@@ -395,13 +395,13 @@ pub async fn sends_headers_frame_with_keep_alive_header<IO: IntoHalves>(
     Ok(())
 }
 
-/// HTTP/2 does not use the Connection header field (Section 7.6.1 of [HTTP]) to
+/// HTTP/2 does not use the Connection header field (Section 7.6.1 of HTTP) to
 /// indicate connection-specific header fields; in this protocol,
 /// connection-specific metadata is conveyed by other means. An endpoint MUST
 /// NOT generate an HTTP/2 message containing connection-specific header fields.
 ///
 /// This includes the Connection header field and those listed as having
-/// connection-specific semantics in Section 7.6.1 of [HTTP] (that is,
+/// connection-specific semantics in Section 7.6.1 of HTTP (that is,
 /// Proxy-Connection, Keep-Alive, Transfer-Encoding, and Upgrade). Any message
 /// containing connection-specific header fields MUST be treated as malformed
 /// (Section 8.1.1).
@@ -418,13 +418,13 @@ pub async fn sends_headers_frame_with_transfer_encoding_header<IO: IntoHalves>(
     Ok(())
 }
 
-/// HTTP/2 does not use the Connection header field (Section 7.6.1 of [HTTP]) to
+/// HTTP/2 does not use the Connection header field (Section 7.6.1 of HTTP) to
 /// indicate connection-specific header fields; in this protocol,
 /// connection-specific metadata is conveyed by other means. An endpoint MUST
 /// NOT generate an HTTP/2 message containing connection-specific header fields.
 ///
 /// This includes the Connection header field and those listed as having
-/// connection-specific semantics in Section 7.6.1 of [HTTP] (that is,
+/// connection-specific semantics in Section 7.6.1 of HTTP (that is,
 /// Proxy-Connection, Keep-Alive, Transfer-Encoding, and Upgrade). Any message
 /// containing connection-specific header fields MUST be treated as malformed
 /// (Section 8.1.1).
@@ -547,9 +547,9 @@ pub async fn sends_headers_frame_with_duplicate_pseudo_headers<IO: IntoHalves>(
 /// A server SHOULD treat a request as malformed if it contains a Host header
 /// field that identifies an entity that differs from the entity in the
 /// ":authority" pseudo-header field. The values of fields need to be normalized
-/// to compare them (see Section 6.2 of [RFC3986]). An origin server can apply
+/// to compare them (see Section 6.2 of RFC3986). An origin server can apply
 /// any normalization method, whereas other servers MUST perform scheme-based
-/// normalization (see Section 6.2.3 of [RFC3986]) of the two fields.
+/// normalization (see Section 6.2.3 of RFC3986) of the two fields.
 ///
 /// cf. <https://www.rfc-editor.org/rfc/rfc3986.html#section-6.2.3>
 pub async fn sends_headers_frame_with_mismatched_host_authority<IO: IntoHalves>(
@@ -581,7 +581,7 @@ pub async fn sends_headers_frame_with_mismatched_host_authority<IO: IntoHalves>(
 ///
 /// an OPTIONS request for an "http" or "https" URI that does not include a path
 /// component; these MUST include a ":path" pseudo-header field with a value of
-/// '*' (see Section 7.1 of [HTTP]). CONNECT requests (Section 8.5), where the
+/// '*' (see Section 7.1 of HTTP). CONNECT requests (Section 8.5), where the
 /// ":path" pseudo-header field is omitted.
 pub async fn sends_headers_frame_with_empty_path_component<IO: IntoHalves>(
     mut conn: Conn<IO>,
@@ -721,7 +721,7 @@ pub async fn client_sends_push_promise_frame<IO: IntoHalves>(
 
 //---- Section 8.5: The CONNECT Method
 
-/// The CONNECT method (Section 9.3.6 of [HTTP]) is used to convert an HTTP
+/// The CONNECT method (Section 9.3.6 of HTTP) is used to convert an HTTP
 /// connection into a tunnel to a remote host. CONNECT is primarily used with
 /// HTTP proxies to establish a TLS session with an origin server for the
 /// purposes of interacting with "https" resources.
diff --git a/crates/loona-h2/src/lib.rs b/crates/loona-h2/src/lib.rs
index bbec1b33..a5bfa122 100644
--- a/crates/loona-h2/src/lib.rs
+++ b/crates/loona-h2/src/lib.rs
@@ -34,7 +34,7 @@ pub trait IntoPiece {
     fn into_piece(self, scratch: &mut RollMut) -> std::io::Result<Piece>;
 }
 
-/// See https://httpwg.org/specs/rfc9113.html#FrameTypes
+/// See <https://httpwg.org/specs/rfc9113.html#FrameTypes>
 #[EnumRepr(type = "u8")]
 #[derive(Debug, Clone, Copy)]
 pub enum RawFrameType {
@@ -78,7 +78,7 @@ impl FrameType {
     }
 }
 
-/// See https://httpwg.org/specs/rfc9113.html#DATA
+/// See <https://httpwg.org/specs/rfc9113.html#DATA>
 #[bitflags]
 #[repr(u8)]
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -87,7 +87,7 @@ pub enum DataFlags {
     EndStream = 0x01,
 }
 
-/// See https://httpwg.org/specs/rfc9113.html#rfc.section.6.2
+/// See <https://httpwg.org/specs/rfc9113.html#rfc.section.6.2>
 #[bitflags]
 #[repr(u8)]
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -98,7 +98,7 @@ pub enum HeadersFlags {
     EndStream = 0x01,
 }
 
-/// See https://httpwg.org/specs/rfc9113.html#SETTINGS
+/// See <https://httpwg.org/specs/rfc9113.html#SETTINGS>
 #[bitflags]
 #[repr(u8)]
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -106,7 +106,7 @@ pub enum SettingsFlags {
     Ack = 0x01,
 }
 
-/// See https://httpwg.org/specs/rfc9113.html#PING
+/// See <https://httpwg.org/specs/rfc9113.html#PING>
 #[bitflags]
 #[repr(u8)]
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -114,7 +114,7 @@ pub enum PingFlags {
     Ack = 0x01,
 }
 
-/// See https://httpwg.org/specs/rfc9113.html#CONTINUATION
+/// See <https://httpwg.org/specs/rfc9113.html#CONTINUATION>
 #[bitflags]
 #[repr(u8)]
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -231,7 +231,7 @@ impl fmt::Display for StreamId {
     }
 }
 
-/// See https://httpwg.org/specs/rfc9113.html#FrameHeader
+/// See <https://httpwg.org/specs/rfc9113.html#FrameHeader>
 pub struct Frame {
     pub frame_type: FrameType,
     pub reserved: u8,
@@ -411,7 +411,7 @@ impl IntoPiece for Frame {
     }
 }
 
-/// See https://httpwg.org/specs/rfc9113.html#FrameHeader - the first bit
+/// See <https://httpwg.org/specs/rfc9113.html#FrameHeader> - the first bit
 /// is reserved, and the rest is a 31-bit stream id
 pub fn parse_bit_and_u31(i: Roll) -> IResult<Roll, (u8, u32)> {
     // first, parse a u32:
@@ -485,7 +485,7 @@ fn test_pack_bit_and_u31_panic_val_too_large() {
     pack_bit_and_u31(0, 1 << 31);
 }
 
-// cf. https://httpwg.org/specs/rfc9113.html#HEADERS
+// cf. <https://httpwg.org/specs/rfc9113.html#HEADERS>
 #[derive(Debug)]
 pub struct PrioritySpec {
     pub exclusive: bool,
@@ -567,7 +567,7 @@ pub enum KnownErrorCode {
 
     /// The endpoint sent a SETTINGS frame but did not receive a response in a
     /// timely manner. See Section 6.5.3 ("Settings Synchronization").
-    /// https://httpwg.org/specs/rfc9113.html#SettingsSync
+    /// <https://httpwg.org/specs/rfc9113.html#SettingsSync>
     SettingsTimeout = 0x04,
 
     /// The endpoint received a frame after a stream was half-closed.
@@ -578,7 +578,7 @@ pub enum KnownErrorCode {
 
     /// The endpoint refused the stream prior to performing any application
     /// processing (see Section 8.7 for details).
-    /// https://httpwg.org/specs/rfc9113.html#Reliability
+    /// <https://httpwg.org/specs/rfc9113.html#Reliability>
     RefusedStream = 0x07,
 
     /// The endpoint uses this error code to indicate that the stream is no
@@ -591,7 +591,7 @@ pub enum KnownErrorCode {
 
     /// The connection established in response to a CONNECT request (Section
     /// 8.5) was reset or abnormally closed.
-    /// https://httpwg.org/specs/rfc9113.html#CONNECT
+    /// <https://httpwg.org/specs/rfc9113.html#CONNECT>
     ConnectError = 0x0a,
 
     /// The endpoint detected that its peer is exhibiting a behavior that might
@@ -600,7 +600,7 @@ pub enum KnownErrorCode {
 
     /// The underlying transport has properties that do not meet minimum
     /// security requirements (see Section 9.2).
-    /// https://httpwg.org/specs/rfc9113.html#TLSUsage
+    /// <https://httpwg.org/specs/rfc9113.html#TLSUsage>
     InadequateSecurity = 0x0c,
 
     /// The endpoint requires that HTTP/1.1 be used instead of HTTP/2.
@@ -615,14 +615,14 @@ impl TryFrom<ErrorCode> for KnownErrorCode {
     }
 }
 
-/// cf. https://httpwg.org/specs/rfc9113.html#SettingValues
+/// cf. <https://httpwg.org/specs/rfc9113.html#SettingValues>
 #[derive(Clone, Copy, Debug)]
 pub struct Settings {
     /// This setting allows the sender to inform the remote endpoint of the
     /// maximum size of the compression table used to decode field blocks, in
     /// units of octets. The encoder can select any size equal to or less than
     /// this value by using signaling specific to the compression format inside
-    /// a field block (see [COMPRESSION]). The initial value is 4,096 octets.
+    /// a field block (see COMPRESSION). The initial value is 4,096 octets.
     pub header_table_size: u32,
 
     /// This setting can be used to enable or disable server push. A server MUST
@@ -693,7 +693,7 @@ pub struct Settings {
 
 impl Default for Settings {
     fn default() -> Self {
-        // cf. https://httpwg.org/specs/rfc9113.html#SettingValues
+        // cf. <https://httpwg.org/specs/rfc9113.html#SettingValues>
         Self {
             header_table_size: 4096,
             enable_push: false,
diff --git a/crates/loona-hpack/src/lib.rs b/crates/loona-hpack/src/lib.rs
index 0dabebd4..7264fdfd 100644
--- a/crates/loona-hpack/src/lib.rs
+++ b/crates/loona-hpack/src/lib.rs
@@ -224,7 +224,7 @@ impl<'a> HeaderTable<'a> {
     /// table. They are merged into a single index address space, though.
     ///
     /// This is according to the [HPACK spec, section 2.3.3.]
-    /// (http://http2.github.io/http2-spec/compression.html#index.address.space)
+    /// <http://http2.github.io/http2-spec/compression.html#index.address.space>
     pub fn get_from_table(&self, index: usize) -> Option<(&[u8], &[u8])> {
         // The IETF defined table indexing as 1-based.
         // So, before starting, make sure the given index is within the proper
diff --git a/crates/loona/src/h1/parse.rs b/crates/loona/src/h1/parse.rs
index d35a3822..112fb1c3 100644
--- a/crates/loona/src/h1/parse.rs
+++ b/crates/loona/src/h1/parse.rs
@@ -54,19 +54,19 @@ pub fn method(i: Roll) -> IResult<Roll, Method> {
 }
 
 /// A short textual identifier that does not include whitspace or delimiters,
-/// cf. https://httpwg.org/specs/rfc9110.html#rule.token.separators
+/// cf. <https://httpwg.org/specs/rfc9110.html#rule.token.separators>
 pub fn token(i: Roll) -> IResult<Roll, RollStr> {
     let (i, token) = take_while1(is_tchar)(i)?;
     let token = unsafe { token.to_string_unchecked() };
     Ok((i, token))
 }
 
-/// cf. https://httpwg.org/specs/rfc9110.html#rule.token.separators
+/// cf. <https://httpwg.org/specs/rfc9110.html#rule.token.separators>
 fn is_tchar(c: u8) -> bool {
     c.is_ascii_graphic() && !is_delimiter(c)
 }
 
-/// cf. https://httpwg.org/specs/rfc9110.html#rule.token.separators
+/// cf. <https://httpwg.org/specs/rfc9110.html#rule.token.separators>
 fn is_delimiter(c: u8) -> bool {
     memchr::memchr(c, br#"(),/:;<=>?@[\]{}""#).is_some()
 }
@@ -78,7 +78,7 @@ fn path(i: Roll) -> IResult<Roll, RollStr> {
 }
 
 /// Returns true if `c` is a character that can be found in an URI
-/// cf. https://stackoverflow.com/a/7109208
+/// cf. <https://stackoverflow.com/a/7109208>
 fn is_uri_char(c: u8) -> bool {
     memchr::memchr(
         c,
diff --git a/crates/loona/src/h2/server.rs b/crates/loona/src/h2/server.rs
index 6d63966a..f536cd66 100644
--- a/crates/loona/src/h2/server.rs
+++ b/crates/loona/src/h2/server.rs
@@ -1517,7 +1517,7 @@ impl<D: ServerDriver + 'static, W: WriteOwned> ServerContext<D, W> {
                     };
 
                     // Note: An implementation that validates fields according to the definitions in
-                    // Sections 5.1 and 5.5 of [HTTP] only needs an additional check that field
+                    // Sections 5.1 and 5.5 of HTTP only needs an additional check that field
                     // names do not include uppercase characters.
                     if key.iter().any(|b: &u8| b.is_ascii_uppercase()) {
                         req_error = Some(H2StreamError::BadRequest(


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index e21af2b3..8459e626 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -62,9 +62,69 @@ jobs:
         uses: codecov/codecov-action@v4
         with:
           token: ${{ secrets.CODECOV_TOKEN }}
-          fail_ci_if_error: true
+          fail_ci_if_error: false
           verbose: true
           file: coverage/lcov.info
+  test-httpwg-cli:
+    env:
+      CARGO_TERM_COLOR: always
+    runs-on:
+      - namespace-profile-linux-amd64
+    steps:
+      - name: Check out repository code
+        uses: actions/checkout@v4
+        with:
+          fetch-depth: 2
+      - name: Setup cargo cache
+        uses: namespacelabs/nscloud-cache-action@v1
+        with:
+          path: |
+            ./target
+            ./target-cov
+            ~/.cargo/git
+            ~/.cargo/registry
+            ~/.rustup
+      - name: Install Rust specified toolchain
+        run: |
+          rustc --version
+      - uses: taiki-e/install-action@v2
+        with:
+          tool: just,cargo-nextest,cargo-llvm-cov
+      - name: Run httpwg tests (over TCP)
+        run: |
+          cd ${{ github.workspace }}
+          just httpwg-over-tcp
+
+  doc:
+    env:
+      CARGO_TERM_COLOR: always
+    runs-on:
+      - namespace-profile-linux-amd64
+    steps:
+      - name: Check out repository code
+        uses: actions/checkout@v4
+        with:
+          fetch-depth: 2
+      - name: Setup cargo cache
+        uses: namespacelabs/nscloud-cache-action@v1
+        with:
+          path: |
+            ./target
+            ./target-cov
+            ~/.cargo/git
+            ~/.cargo/registry
+            ~/.rustup
+      - name: Install Rust specified toolchain
+        run: |
+          rustc --version
+      - uses: taiki-e/install-action@v2
+        with:
+          tool: just,cargo-nextest,cargo-llvm-cov
+      - name: Generate docs (deny warnings)
+        run: |
+          cd ${{ github.workspace }}
+          export RUSTDOCFLAGS="-Dwarnings"
+          cargo doc --no-deps --document-private-items --all-features
   httpwg-gen:
     env:
       CARGO_TERM_COLOR: always