From 8d821ceac175739be3a0f094ffb89acb318d51b8 Mon Sep 17 00:00:00 2001 From: Adarsh Dhital Khatri Date: Wed, 25 Mar 2026 10:16:14 +0545 Subject: [PATCH] fix(docs, xtask): repair cross-book links and harden local serve - Retarget C# companion links from missing source-docs paths to book SUMMARYs. - Fix type-driven correctness intro to link Rust Patterns source, not index.html. - Resolve static file paths under site/ with canonicalization and percent-decoding. - Match xtask landing page blurbs to the root README. --- csharp-book/src/ch13-concurrency.md | 2 +- csharp-book/src/ch14-unsafe-rust-and-ffi.md | 2 +- .../src/ch16-3-rust-tooling-ecosystem.md | 8 +-- .../src/ch00-introduction.md | 12 ++-- xtask/src/main.rs | 67 +++++++++++++++++-- 5 files changed, 72 insertions(+), 19 deletions(-) diff --git a/csharp-book/src/ch13-concurrency.md b/csharp-book/src/ch13-concurrency.md index 9801cbe..891e011 100644 --- a/csharp-book/src/ch13-concurrency.md +++ b/csharp-book/src/ch13-concurrency.md @@ -6,7 +6,7 @@ > > **Difficulty:** 🔴 Advanced -> **Deep dive**: For production async patterns (stream processing, graceful shutdown, connection pooling, cancellation safety), see the companion [Async Rust Training](../../source-docs/ASYNC_RUST_TRAINING.md) guide. +> **Deep dive**: For production async patterns (stream processing, graceful shutdown, connection pooling, cancellation safety), see the companion [Async Rust Training](../../async-book/src/summary.md) guide. > > **Prerequisites**: [Ownership & Borrowing](ch07-ownership-and-borrowing.md) and [Smart Pointers](ch07-3-smart-pointers-beyond-single-ownership.md) (Rc vs Arc decision tree). diff --git a/csharp-book/src/ch14-unsafe-rust-and-ffi.md b/csharp-book/src/ch14-unsafe-rust-and-ffi.md index de5da3c..a8e8494 100644 --- a/csharp-book/src/ch14-unsafe-rust-and-ffi.md +++ b/csharp-book/src/ch14-unsafe-rust-and-ffi.md @@ -7,7 +7,7 @@ Unsafe Rust allows you to perform operations that the borrow checker cannot verify. Use it sparingly and with clear documentation. -> **Advanced coverage**: For safe abstraction patterns over unsafe code (arena allocators, lock-free structures, custom vtables), see [Rust Patterns](../../source-docs/RUST_PATTERNS.md). +> **Advanced coverage**: For safe abstraction patterns over unsafe code (arena allocators, lock-free structures, custom vtables), see [Rust Patterns](../../rust-patterns-book/src/summary.md). ### When You Need Unsafe ```rust diff --git a/csharp-book/src/ch16-3-rust-tooling-ecosystem.md b/csharp-book/src/ch16-3-rust-tooling-ecosystem.md index 9cf162d..9b7bccb 100644 --- a/csharp-book/src/ch16-3-rust-tooling-ecosystem.md +++ b/csharp-book/src/ch16-3-rust-tooling-ecosystem.md @@ -119,7 +119,7 @@ cargo expand module_name # Expand specific module For deeper exploration of advanced topics mentioned in this guide, see the companion training documents: -- **[Rust Patterns](../../source-docs/RUST_PATTERNS.md)** — Pin projections, custom allocators, arena patterns, lock-free data structures, and advanced unsafe patterns -- **[Async Rust Training](../../source-docs/ASYNC_RUST_TRAINING.md)** — Deep dive into tokio, async cancellation safety, stream processing, and production async architectures -- **[Rust Training for C++ Developers](./RUST_TRAINING_FOR_CPP.md)** — Useful if your team also has C++ experience; covers move semantics mapping, RAII differences, and template vs generics -- **[Rust Training for C Developers](./RUST_TRAINING_FOR_C.md)** — Relevant for interop scenarios; covers FFI patterns, embedded Rust debugging, and `no_std` programming \ No newline at end of file +- **[Rust Patterns](../../rust-patterns-book/src/SUMMARY.md)** — Pin projections, custom allocators, arena patterns, lock-free data structures, and advanced unsafe patterns +- **[Async Rust Training](../../async-book/src/SUMMARY.md)** — Deep dive into tokio, async cancellation safety, stream processing, and production async architectures +- **[Rust Training for C++ Developers](../../c-cpp-book/src/SUMMARY.md)** — Useful if your team also has C++ experience; covers move semantics mapping, RAII differences, and template vs generics +- **[Rust Training for C Developers](../../c-cpp-book/src/SUMMARY.md)** — Relevant for interop scenarios; covers FFI patterns, embedded Rust debugging, and `no_std` programming \ No newline at end of file diff --git a/type-driven-correctness-book/src/ch00-introduction.md b/type-driven-correctness-book/src/ch00-introduction.md index 8cfbd40..8669035 100644 --- a/type-driven-correctness-book/src/ch00-introduction.md +++ b/type-driven-correctness-book/src/ch00-introduction.md @@ -8,7 +8,7 @@ --- -A practical guide to using Rust's type system to make entire classes of bugs **impossible to compile**. While the companion [Rust Patterns](../rust-patterns-book/index.html) book covers the mechanics (traits, associated types, type-state), this guide shows how to **apply** those mechanics to real-world domains — hardware diagnostics, cryptography, protocol validation, and embedded systems. +A practical guide to using Rust's type system to make entire classes of bugs **impossible to compile**. While the companion [Rust Patterns](../../rust-patterns-book/src/SUMMARY.md) book covers the mechanics (traits, associated types, type-state), this guide shows how to **apply** those mechanics to real-world domains — hardware diagnostics, cryptography, protocol validation, and embedded systems. Every pattern here follows one principle: **push invariants from runtime checks into the type system so the compiler enforces them.** @@ -61,11 +61,11 @@ Every pattern here follows one principle: **push invariants from runtime checks | Concept | Where to learn it | |---------|-------------------| -| Ownership and borrowing | [Rust Patterns](../rust-patterns-book/index.html), ch01 | -| Traits and associated types | [Rust Patterns](../rust-patterns-book/index.html), ch02 | -| Newtypes and type-state | [Rust Patterns](../rust-patterns-book/index.html), ch03 | -| PhantomData | [Rust Patterns](../rust-patterns-book/index.html), ch04 | -| Generics and trait bounds | [Rust Patterns](../rust-patterns-book/index.html), ch01 | +| Ownership and borrowing | [Rust Patterns](../rust-patterns-book/src/SUMMARY.md), ch01 | +| Traits and associated types | [Rust Patterns](../rust-patterns-book/src/SUMMARY.md), ch02 | +| Newtypes and type-state | [Rust Patterns](../rust-patterns-book/src/SUMMARY.md), ch03 | +| PhantomData | [Rust Patterns](../rust-patterns-book/src/SUMMARY.md), ch04 | +| Generics and trait bounds | [Rust Patterns](../rust-patterns-book/src/SUMMARY.md), ch01 | ## The Correct-by-Construction Spectrum diff --git a/xtask/src/main.rs b/xtask/src/main.rs index a6a8b08..5295bdd 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -289,10 +289,68 @@ fn write_landing_page(site: &Path) { println!(" ✓ index.html"); } +/// Resolve `request_target` (HTTP request path, e.g. `/foo/bar?x=1`) to a file under `site_canon`. +/// Returns `None` for traversal attempts, missing files, or paths that escape `site_canon` (symlinks). +fn resolve_site_file(site_canon: &Path, request_target: &str) -> Option { + let path_only = request_target.split('?').next()?.split('#').next()?; + let decoded = percent_decode_path(path_only); + if decoded.as_bytes().contains(&0) { + return None; + } + let rel = decoded.trim_start_matches('/'); + let mut file_path = site_canon.to_path_buf(); + if !rel.is_empty() { + for seg in rel.split('/').filter(|s| !s.is_empty()) { + if seg == ".." { + return None; + } + file_path.push(seg); + } + } + if file_path.is_dir() { + file_path.push("index.html"); + } + let real = fs::canonicalize(&file_path).ok()?; + if !real.starts_with(site_canon) { + return None; + } + real.is_file().then_some(real) +} + +fn hex_val(c: u8) -> Option { + match c { + b'0'..=b'9' => Some(c - b'0'), + b'a'..=b'f' => Some(c - b'a' + 10), + b'A'..=b'F' => Some(c - b'A' + 10), + _ => None, + } +} + +fn percent_decode_path(input: &str) -> String { + let mut decoded = Vec::with_capacity(input.len()); + let b = input.as_bytes(); + let mut i = 0; + while i < b.len() { + if b[i] == b'%' && i + 2 < b.len() { + if let (Some(hi), Some(lo)) = (hex_val(b[i + 1]), hex_val(b[i + 2])) { + decoded.push(hi << 4 | lo); + i += 3; + continue; + } + } + decoded.push(b[i]); + i += 1; + } + String::from_utf8_lossy(&decoded).into_owned() +} + // ── serve ──────────────────────────────────────────────────────────── fn cmd_serve() { let site = project_root().join("site"); + let site_canon = fs::canonicalize(&site).expect( + "site/ not found — run `cargo xtask build` first (e.g. `cargo xtask serve` runs build automatically)", + ); let addr = "127.0.0.1:3000"; let listener = TcpListener::bind(addr).expect("failed to bind port 3000"); @@ -313,12 +371,7 @@ fn cmd_serve() { .and_then(|line| line.split_whitespace().nth(1)) .unwrap_or("/"); - let mut file_path = site.join(path.trim_start_matches('/')); - if file_path.is_dir() { - file_path = file_path.join("index.html"); - } - - if file_path.is_file() { + if let Some(file_path) = resolve_site_file(&site_canon, path) { let body = fs::read(&file_path).unwrap_or_default(); let mime = guess_mime(&file_path); let header = format!( @@ -404,4 +457,4 @@ fn cmd_clean() { println!("Removed {dir_name}/"); } } -} +} \ No newline at end of file