From 698f8c2f01ea549d77d7dc3338a12e04c11057b9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:02:58 +0200 Subject: Adding upstream version 1.64.0+dfsg1. Signed-off-by: Daniel Baumann --- .../ch20-web-server/listing-20-01/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-01/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-01/src/main.rs | 11 +++ .../ch20-web-server/listing-20-02/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-02/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-02/src/main.rs | 25 ++++++ .../ch20-web-server/listing-20-03/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-03/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-03/src/main.rs | 29 +++++++ .../ch20-web-server/listing-20-05/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-05/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-05/hello.html | 11 +++ .../ch20-web-server/listing-20-05/src/main.rs | 38 +++++++++ .../ch20-web-server/listing-20-06/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-06/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-06/hello.html | 11 +++ .../ch20-web-server/listing-20-06/src/main.rs | 37 +++++++++ .../ch20-web-server/listing-20-07/404.html | 11 +++ .../ch20-web-server/listing-20-07/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-07/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-07/hello.html | 11 +++ .../ch20-web-server/listing-20-07/src/main.rs | 45 ++++++++++ .../ch20-web-server/listing-20-09/404.html | 11 +++ .../ch20-web-server/listing-20-09/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-09/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-09/hello.html | 11 +++ .../ch20-web-server/listing-20-09/src/main.rs | 40 +++++++++ .../ch20-web-server/listing-20-10/404.html | 11 +++ .../ch20-web-server/listing-20-10/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-10/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-10/hello.html | 11 +++ .../ch20-web-server/listing-20-10/src/main.rs | 52 ++++++++++++ .../ch20-web-server/listing-20-11/404.html | 11 +++ .../ch20-web-server/listing-20-11/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-11/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-11/hello.html | 11 +++ .../ch20-web-server/listing-20-11/src/main.rs | 43 ++++++++++ .../ch20-web-server/listing-20-12/404.html | 11 +++ .../ch20-web-server/listing-20-12/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-12/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-12/hello.html | 11 +++ .../ch20-web-server/listing-20-12/output.txt | 10 +++ .../ch20-web-server/listing-20-12/src/main.rs | 44 ++++++++++ .../ch20-web-server/listing-20-13/404.html | 11 +++ .../ch20-web-server/listing-20-13/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-13/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-13/hello.html | 11 +++ .../ch20-web-server/listing-20-13/src/lib.rs | 27 ++++++ .../ch20-web-server/listing-20-13/src/main.rs | 43 ++++++++++ .../ch20-web-server/listing-20-14/404.html | 11 +++ .../ch20-web-server/listing-20-14/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-14/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-14/hello.html | 11 +++ .../ch20-web-server/listing-20-14/src/lib.rs | 40 +++++++++ .../ch20-web-server/listing-20-14/src/main.rs | 43 ++++++++++ .../ch20-web-server/listing-20-15/404.html | 11 +++ .../ch20-web-server/listing-20-15/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-15/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-15/hello.html | 11 +++ .../ch20-web-server/listing-20-15/src/lib.rs | 53 ++++++++++++ .../ch20-web-server/listing-20-15/src/main.rs | 43 ++++++++++ .../ch20-web-server/listing-20-16/404.html | 11 +++ .../ch20-web-server/listing-20-16/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-16/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-16/hello.html | 11 +++ .../ch20-web-server/listing-20-16/src/lib.rs | 58 +++++++++++++ .../ch20-web-server/listing-20-16/src/main.rs | 43 ++++++++++ .../ch20-web-server/listing-20-17/404.html | 11 +++ .../ch20-web-server/listing-20-17/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-17/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-17/hello.html | 11 +++ .../ch20-web-server/listing-20-17/output.txt | 13 +++ .../ch20-web-server/listing-20-17/src/lib.rs | 65 +++++++++++++++ .../ch20-web-server/listing-20-17/src/main.rs | 43 ++++++++++ .../ch20-web-server/listing-20-18/404.html | 11 +++ .../ch20-web-server/listing-20-18/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-18/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-18/hello.html | 11 +++ .../ch20-web-server/listing-20-18/src/lib.rs | 76 +++++++++++++++++ .../ch20-web-server/listing-20-18/src/main.rs | 43 ++++++++++ .../ch20-web-server/listing-20-19/404.html | 11 +++ .../ch20-web-server/listing-20-19/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-19/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-19/hello.html | 11 +++ .../ch20-web-server/listing-20-19/src/lib.rs | 69 ++++++++++++++++ .../ch20-web-server/listing-20-19/src/main.rs | 43 ++++++++++ .../ch20-web-server/listing-20-20/404.html | 11 +++ .../ch20-web-server/listing-20-20/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-20/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-20/hello.html | 11 +++ .../ch20-web-server/listing-20-20/src/lib.rs | 68 ++++++++++++++++ .../ch20-web-server/listing-20-20/src/main.rs | 43 ++++++++++ .../ch20-web-server/listing-20-21/404.html | 11 +++ .../ch20-web-server/listing-20-21/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-21/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-21/hello.html | 11 +++ .../ch20-web-server/listing-20-21/src/lib.rs | 67 +++++++++++++++ .../ch20-web-server/listing-20-21/src/main.rs | 43 ++++++++++ .../ch20-web-server/listing-20-22/404.html | 11 +++ .../ch20-web-server/listing-20-22/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-22/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-22/hello.html | 11 +++ .../ch20-web-server/listing-20-22/output.txt | 14 ++++ .../ch20-web-server/listing-20-22/src/lib.rs | 76 +++++++++++++++++ .../ch20-web-server/listing-20-22/src/main.rs | 43 ++++++++++ .../ch20-web-server/listing-20-23/404.html | 11 +++ .../ch20-web-server/listing-20-23/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-23/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-23/hello.html | 11 +++ .../ch20-web-server/listing-20-23/src/lib.rs | 95 ++++++++++++++++++++++ .../ch20-web-server/listing-20-23/src/main.rs | 45 ++++++++++ .../ch20-web-server/listing-20-24/404.html | 11 +++ .../ch20-web-server/listing-20-24/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-24/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-24/hello.html | 11 +++ .../ch20-web-server/listing-20-24/src/lib.rs | 92 +++++++++++++++++++++ .../ch20-web-server/listing-20-24/src/main.rs | 45 ++++++++++ .../ch20-web-server/listing-20-25/404.html | 11 +++ .../ch20-web-server/listing-20-25/Cargo.lock | 6 ++ .../ch20-web-server/listing-20-25/Cargo.toml | 6 ++ .../ch20-web-server/listing-20-25/hello.html | 11 +++ .../ch20-web-server/listing-20-25/src/lib.rs | 92 +++++++++++++++++++++ .../ch20-web-server/listing-20-25/src/main.rs | 53 ++++++++++++ .../404.html | 11 +++ .../Cargo.lock | 6 ++ .../Cargo.toml | 6 ++ .../hello.html | 11 +++ .../output.txt | 10 +++ .../src/lib.rs | 1 + .../src/main.rs | 45 ++++++++++ .../no-listing-02-impl-threadpool-new/404.html | 11 +++ .../no-listing-02-impl-threadpool-new/Cargo.lock | 6 ++ .../no-listing-02-impl-threadpool-new/Cargo.toml | 6 ++ .../no-listing-02-impl-threadpool-new/hello.html | 11 +++ .../no-listing-02-impl-threadpool-new/output.txt | 10 +++ .../no-listing-02-impl-threadpool-new/src/lib.rs | 7 ++ .../no-listing-02-impl-threadpool-new/src/main.rs | 43 ++++++++++ .../no-listing-03-define-execute/404.html | 11 +++ .../no-listing-03-define-execute/Cargo.lock | 6 ++ .../no-listing-03-define-execute/Cargo.toml | 6 ++ .../no-listing-03-define-execute/hello.html | 11 +++ .../no-listing-03-define-execute/output.txt | 3 + .../no-listing-03-define-execute/src/lib.rs | 18 ++++ .../no-listing-03-define-execute/src/main.rs | 43 ++++++++++ .../404.html | 11 +++ .../Cargo.lock | 6 ++ .../Cargo.toml | 6 ++ .../hello.html | 11 +++ .../output.txt | 24 ++++++ .../src/lib.rs | 76 +++++++++++++++++ .../src/main.rs | 43 ++++++++++ .../no-listing-05-fix-worker-new/404.html | 11 +++ .../no-listing-05-fix-worker-new/Cargo.lock | 6 ++ .../no-listing-05-fix-worker-new/Cargo.toml | 6 ++ .../no-listing-05-fix-worker-new/hello.html | 11 +++ .../no-listing-05-fix-worker-new/src/lib.rs | 83 +++++++++++++++++++ .../no-listing-05-fix-worker-new/src/main.rs | 43 ++++++++++ .../no-listing-06-fix-threadpool-drop/404.html | 11 +++ .../no-listing-06-fix-threadpool-drop/Cargo.lock | 6 ++ .../no-listing-06-fix-threadpool-drop/Cargo.toml | 6 ++ .../no-listing-06-fix-threadpool-drop/hello.html | 11 +++ .../no-listing-06-fix-threadpool-drop/src/lib.rs | 81 ++++++++++++++++++ .../no-listing-06-fix-threadpool-drop/src/main.rs | 45 ++++++++++ .../no-listing-07-final-code/404.html | 11 +++ .../no-listing-07-final-code/Cargo.lock | 6 ++ .../no-listing-07-final-code/Cargo.toml | 6 ++ .../no-listing-07-final-code/hello.html | 11 +++ .../no-listing-07-final-code/src/lib.rs | 92 +++++++++++++++++++++ .../no-listing-07-final-code/src/main.rs | 51 ++++++++++++ 169 files changed, 3502 insertions(+) create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-01/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-01/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-01/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-02/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-02/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-02/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-03/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-03/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-03/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-05/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-05/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-05/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-05/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-06/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-06/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-06/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-06/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-07/404.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-07/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-07/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-07/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-07/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-09/404.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-09/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-09/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-09/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-09/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-10/404.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-10/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-10/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-10/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-10/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-11/404.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-11/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-11/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-11/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-11/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-12/404.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-12/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-12/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-12/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-12/output.txt create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-12/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-13/404.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-13/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-13/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-13/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-13/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-13/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-14/404.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-14/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-14/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-14/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-14/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-14/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-15/404.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-15/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-15/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-15/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-15/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-15/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-16/404.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-16/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-16/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-16/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-16/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-16/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-17/404.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-17/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-17/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-17/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-17/output.txt create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-17/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-17/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-18/404.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-18/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-18/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-18/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-18/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-18/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-19/404.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-19/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-19/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-19/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-19/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-19/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-20/404.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-20/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-20/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-20/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-20/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-20/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-21/404.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-21/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-21/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-21/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-21/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-21/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-22/404.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-22/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-22/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-22/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-22/output.txt create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-22/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-22/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-23/404.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-23/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-23/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-23/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-23/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-23/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-24/404.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-24/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-24/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-24/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-24/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-24/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-25/404.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-25/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-25/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-25/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-25/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/listing-20-25/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/404.html create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/output.txt create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/404.html create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/output.txt create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/404.html create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/output.txt create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/404.html create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/output.txt create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/404.html create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/404.html create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/src/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-07-final-code/404.html create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-07-final-code/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-07-final-code/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-07-final-code/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-07-final-code/src/lib.rs create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-07-final-code/src/main.rs (limited to 'src/doc/book/listings/ch20-web-server') diff --git a/src/doc/book/listings/ch20-web-server/listing-20-01/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-01/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-01/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-01/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-01/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-01/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-01/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-01/src/main.rs new file mode 100644 index 000000000..d868c3ec1 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-01/src/main.rs @@ -0,0 +1,11 @@ +use std::net::TcpListener; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + println!("Connection established!"); + } +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-02/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-02/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-02/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-02/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-02/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-02/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-02/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-02/src/main.rs new file mode 100644 index 000000000..7240c73c7 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-02/src/main.rs @@ -0,0 +1,25 @@ +use std::{ + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + handle_connection(stream); + } +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let http_request: Vec<_> = buf_reader + .lines() + .map(|result| result.unwrap()) + .take_while(|line| !line.is_empty()) + .collect(); + + println!("Request: {:#?}", http_request); +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-03/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-03/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-03/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-03/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-03/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-03/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-03/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-03/src/main.rs new file mode 100644 index 000000000..c72d4a9c6 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-03/src/main.rs @@ -0,0 +1,29 @@ +use std::{ + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + handle_connection(stream); + } +} + +// ANCHOR: here +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let http_request: Vec<_> = buf_reader + .lines() + .map(|result| result.unwrap()) + .take_while(|line| !line.is_empty()) + .collect(); + + let response = "HTTP/1.1 200 OK\r\n\r\n"; + + stream.write_all(response.as_bytes()).unwrap(); +} +// ANCHOR_END: here diff --git a/src/doc/book/listings/ch20-web-server/listing-20-05/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-05/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-05/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-05/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-05/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-05/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-05/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-05/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-05/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-05/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-05/src/main.rs new file mode 100644 index 000000000..d4b78b640 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-05/src/main.rs @@ -0,0 +1,38 @@ +// ANCHOR: here +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, +}; +// --snip-- + +// ANCHOR_END: here +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + handle_connection(stream); + } +} + +// ANCHOR: here +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let http_request: Vec<_> = buf_reader + .lines() + .map(|result| result.unwrap()) + .take_while(|line| !line.is_empty()) + .collect(); + + let status_line = "HTTP/1.1 200 OK"; + let contents = fs::read_to_string("hello.html").unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} +// ANCHOR_END: here diff --git a/src/doc/book/listings/ch20-web-server/listing-20-06/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-06/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-06/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-06/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-06/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-06/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-06/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-06/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-06/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-06/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-06/src/main.rs new file mode 100644 index 000000000..5523a42d7 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-06/src/main.rs @@ -0,0 +1,37 @@ +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + handle_connection(stream); + } +} +// ANCHOR: here +// --snip-- + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + if request_line == "GET / HTTP/1.1" { + let status_line = "HTTP/1.1 200 OK"; + let contents = fs::read_to_string("hello.html").unwrap(); + let length = contents.len(); + + let response = format!( + "{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}" + ); + + stream.write_all(response.as_bytes()).unwrap(); + } else { + // some other request + } +} +// ANCHOR_END: here diff --git a/src/doc/book/listings/ch20-web-server/listing-20-07/404.html b/src/doc/book/listings/ch20-web-server/listing-20-07/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-07/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-07/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-07/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-07/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-07/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-07/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-07/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-07/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-07/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-07/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-07/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-07/src/main.rs new file mode 100644 index 000000000..a14b7d538 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-07/src/main.rs @@ -0,0 +1,45 @@ +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + handle_connection(stream); + } +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + if request_line == "GET / HTTP/1.1" { + let status_line = "HTTP/1.1 200 OK"; + let contents = fs::read_to_string("hello.html").unwrap(); + let length = contents.len(); + + let response = format!( + "{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}" + ); + + stream.write_all(response.as_bytes()).unwrap(); + // ANCHOR: here + // --snip-- + } else { + let status_line = "HTTP/1.1 404 NOT FOUND"; + let contents = fs::read_to_string("404.html").unwrap(); + let length = contents.len(); + + let response = format!( + "{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}" + ); + + stream.write_all(response.as_bytes()).unwrap(); + } + // ANCHOR_END: here +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-09/404.html b/src/doc/book/listings/ch20-web-server/listing-20-09/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-09/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-09/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-09/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-09/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-09/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-09/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-09/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-09/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-09/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-09/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-09/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-09/src/main.rs new file mode 100644 index 000000000..ffc51e803 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-09/src/main.rs @@ -0,0 +1,40 @@ +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + handle_connection(stream); + } +} +// ANCHOR: here +// --snip-- + +fn handle_connection(mut stream: TcpStream) { + // --snip-- + // ANCHOR_END: here + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + // ANCHOR: here + + let (status_line, filename) = if request_line == "GET / HTTP/1.1" { + ("HTTP/1.1 200 OK", "hello.html") + } else { + ("HTTP/1.1 404 NOT FOUND", "404.html") + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} +// ANCHOR_END: here diff --git a/src/doc/book/listings/ch20-web-server/listing-20-10/404.html b/src/doc/book/listings/ch20-web-server/listing-20-10/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-10/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-10/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-10/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-10/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-10/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-10/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-10/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-10/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-10/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-10/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-10/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-10/src/main.rs new file mode 100644 index 000000000..5a18b45c0 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-10/src/main.rs @@ -0,0 +1,52 @@ +// ANCHOR: here +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; +// --snip-- +// ANCHOR_END: here + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + handle_connection(stream); + } +} +// ANCHOR: here + +fn handle_connection(mut stream: TcpStream) { + // --snip-- + + // ANCHOR_END: here + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + // ANCHOR: here + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + // --snip-- + // ANCHOR_END: here + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); + // ANCHOR: here +} +// ANCHOR_END: here diff --git a/src/doc/book/listings/ch20-web-server/listing-20-11/404.html b/src/doc/book/listings/ch20-web-server/listing-20-11/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-11/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-11/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-11/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-11/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-11/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-11/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-11/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-11/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-11/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-11/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-11/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-11/src/main.rs new file mode 100644 index 000000000..1181357b0 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-11/src/main.rs @@ -0,0 +1,43 @@ +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +// ANCHOR: here +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + thread::spawn(|| { + handle_connection(stream); + }); + } +} +// ANCHOR_END: here + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-12/404.html b/src/doc/book/listings/ch20-web-server/listing-20-12/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-12/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-12/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-12/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-12/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-12/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-12/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-12/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-12/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-12/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-12/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-12/output.txt b/src/doc/book/listings/ch20-web-server/listing-20-12/output.txt new file mode 100644 index 000000000..57a58b960 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-12/output.txt @@ -0,0 +1,10 @@ +$ cargo check + Checking hello v0.1.0 (file:///projects/hello) +error[E0433]: failed to resolve: use of undeclared type `ThreadPool` + --> src/main.rs:11:16 + | +11 | let pool = ThreadPool::new(4); + | ^^^^^^^^^^ use of undeclared type `ThreadPool` + +For more information about this error, try `rustc --explain E0433`. +error: could not compile `hello` due to previous error diff --git a/src/doc/book/listings/ch20-web-server/listing-20-12/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-12/src/main.rs new file mode 100644 index 000000000..21b9a80f1 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-12/src/main.rs @@ -0,0 +1,44 @@ +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +// ANCHOR: here +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } +} +// ANCHOR_END: here + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-13/404.html b/src/doc/book/listings/ch20-web-server/listing-20-13/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-13/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-13/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-13/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-13/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-13/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-13/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-13/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-13/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-13/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-13/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-13/src/lib.rs b/src/doc/book/listings/ch20-web-server/listing-20-13/src/lib.rs new file mode 100644 index 000000000..35960e7c0 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-13/src/lib.rs @@ -0,0 +1,27 @@ +pub struct ThreadPool; + +// ANCHOR: here +impl ThreadPool { + /// Create a new ThreadPool. + /// + /// The size is the number of threads in the pool. + /// + /// # Panics + /// + /// The `new` function will panic if the size is zero. + pub fn new(size: usize) -> ThreadPool { + assert!(size > 0); + + ThreadPool + } + + // --snip-- + // ANCHOR_END: here + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + } + // ANCHOR: here +} +// ANCHOR_END: here diff --git a/src/doc/book/listings/ch20-web-server/listing-20-13/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-13/src/main.rs new file mode 100644 index 000000000..79efb28a2 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-13/src/main.rs @@ -0,0 +1,43 @@ +use hello::ThreadPool; +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-14/404.html b/src/doc/book/listings/ch20-web-server/listing-20-14/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-14/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-14/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-14/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-14/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-14/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-14/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-14/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-14/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-14/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-14/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-14/src/lib.rs b/src/doc/book/listings/ch20-web-server/listing-20-14/src/lib.rs new file mode 100644 index 000000000..c1fa1828b --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-14/src/lib.rs @@ -0,0 +1,40 @@ +// ANCHOR: here +use std::thread; + +pub struct ThreadPool { + threads: Vec>, +} + +impl ThreadPool { + // --snip-- + // ANCHOR_END: here + /// Create a new ThreadPool. + /// + /// The size is the number of threads in the pool. + /// + /// # Panics + /// + /// The `new` function will panic if the size is zero. + // ANCHOR: here + pub fn new(size: usize) -> ThreadPool { + assert!(size > 0); + + let mut threads = Vec::with_capacity(size); + + for _ in 0..size { + // create some threads and store them in the vector + } + + ThreadPool { threads } + } + // --snip-- + // ANCHOR_END: here + + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + } + // ANCHOR: here +} +// ANCHOR_END: here diff --git a/src/doc/book/listings/ch20-web-server/listing-20-14/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-14/src/main.rs new file mode 100644 index 000000000..79efb28a2 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-14/src/main.rs @@ -0,0 +1,43 @@ +use hello::ThreadPool; +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-15/404.html b/src/doc/book/listings/ch20-web-server/listing-20-15/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-15/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-15/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-15/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-15/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-15/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-15/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-15/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-15/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-15/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-15/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-15/src/lib.rs b/src/doc/book/listings/ch20-web-server/listing-20-15/src/lib.rs new file mode 100644 index 000000000..80a6eeeb3 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-15/src/lib.rs @@ -0,0 +1,53 @@ +// ANCHOR: here +use std::thread; + +pub struct ThreadPool { + workers: Vec, +} + +impl ThreadPool { + // --snip-- + // ANCHOR_END: here + /// Create a new ThreadPool. + /// + /// The size is the number of threads in the pool. + /// + /// # Panics + /// + /// The `new` function will panic if the size is zero. + // ANCHOR: here + pub fn new(size: usize) -> ThreadPool { + assert!(size > 0); + + let mut workers = Vec::with_capacity(size); + + for id in 0..size { + workers.push(Worker::new(id)); + } + + ThreadPool { workers } + } + // --snip-- + // ANCHOR_END: here + + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + } + // ANCHOR: here +} + +struct Worker { + id: usize, + thread: thread::JoinHandle<()>, +} + +impl Worker { + fn new(id: usize) -> Worker { + let thread = thread::spawn(|| {}); + + Worker { id, thread } + } +} +// ANCHOR_END: here diff --git a/src/doc/book/listings/ch20-web-server/listing-20-15/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-15/src/main.rs new file mode 100644 index 000000000..79efb28a2 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-15/src/main.rs @@ -0,0 +1,43 @@ +use hello::ThreadPool; +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-16/404.html b/src/doc/book/listings/ch20-web-server/listing-20-16/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-16/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-16/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-16/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-16/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-16/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-16/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-16/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-16/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-16/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-16/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-16/src/lib.rs b/src/doc/book/listings/ch20-web-server/listing-20-16/src/lib.rs new file mode 100644 index 000000000..411c1d003 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-16/src/lib.rs @@ -0,0 +1,58 @@ +// ANCHOR: here +use std::{sync::mpsc, thread}; + +pub struct ThreadPool { + workers: Vec, + sender: mpsc::Sender, +} + +struct Job; + +impl ThreadPool { + // --snip-- + // ANCHOR_END: here + /// Create a new ThreadPool. + /// + /// The size is the number of threads in the pool. + /// + /// # Panics + /// + /// The `new` function will panic if the size is zero. + // ANCHOR: here + pub fn new(size: usize) -> ThreadPool { + assert!(size > 0); + + let (sender, receiver) = mpsc::channel(); + + let mut workers = Vec::with_capacity(size); + + for id in 0..size { + workers.push(Worker::new(id)); + } + + ThreadPool { workers, sender } + } + // --snip-- + // ANCHOR_END: here + + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + } + // ANCHOR: here +} +// ANCHOR_END: here + +struct Worker { + id: usize, + thread: thread::JoinHandle<()>, +} + +impl Worker { + fn new(id: usize) -> Worker { + let thread = thread::spawn(|| {}); + + Worker { id, thread } + } +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-16/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-16/src/main.rs new file mode 100644 index 000000000..79efb28a2 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-16/src/main.rs @@ -0,0 +1,43 @@ +use hello::ThreadPool; +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-17/404.html b/src/doc/book/listings/ch20-web-server/listing-20-17/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-17/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-17/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-17/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-17/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-17/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-17/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-17/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-17/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-17/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-17/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-17/output.txt b/src/doc/book/listings/ch20-web-server/listing-20-17/output.txt new file mode 100644 index 000000000..8bedfecfd --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-17/output.txt @@ -0,0 +1,13 @@ +$ cargo check + Checking hello v0.1.0 (file:///projects/hello) +error[E0382]: use of moved value: `receiver` + --> src/lib.rs:26:42 + | +21 | let (sender, receiver) = mpsc::channel(); + | -------- move occurs because `receiver` has type `std::sync::mpsc::Receiver`, which does not implement the `Copy` trait +... +26 | workers.push(Worker::new(id, receiver)); + | ^^^^^^^^ value moved here, in previous iteration of loop + +For more information about this error, try `rustc --explain E0382`. +error: could not compile `hello` due to previous error diff --git a/src/doc/book/listings/ch20-web-server/listing-20-17/src/lib.rs b/src/doc/book/listings/ch20-web-server/listing-20-17/src/lib.rs new file mode 100644 index 000000000..d764879e5 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-17/src/lib.rs @@ -0,0 +1,65 @@ +use std::{sync::mpsc, thread}; + +pub struct ThreadPool { + workers: Vec, + sender: mpsc::Sender, +} + +struct Job; + +// ANCHOR: here +impl ThreadPool { + // --snip-- + // ANCHOR_END: here + /// Create a new ThreadPool. + /// + /// The size is the number of threads in the pool. + /// + /// # Panics + /// + /// The `new` function will panic if the size is zero. + // ANCHOR: here + pub fn new(size: usize) -> ThreadPool { + assert!(size > 0); + + let (sender, receiver) = mpsc::channel(); + + let mut workers = Vec::with_capacity(size); + + for id in 0..size { + workers.push(Worker::new(id, receiver)); + } + + ThreadPool { workers, sender } + } + // --snip-- + // ANCHOR_END: here + + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + } + // ANCHOR: here +} + +// --snip-- + +// ANCHOR_END: here + +struct Worker { + id: usize, + thread: thread::JoinHandle<()>, +} + +// ANCHOR: here +impl Worker { + fn new(id: usize, receiver: mpsc::Receiver) -> Worker { + let thread = thread::spawn(|| { + receiver; + }); + + Worker { id, thread } + } +} +// ANCHOR_END: here diff --git a/src/doc/book/listings/ch20-web-server/listing-20-17/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-17/src/main.rs new file mode 100644 index 000000000..79efb28a2 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-17/src/main.rs @@ -0,0 +1,43 @@ +use hello::ThreadPool; +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-18/404.html b/src/doc/book/listings/ch20-web-server/listing-20-18/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-18/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-18/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-18/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-18/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-18/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-18/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-18/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-18/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-18/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-18/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-18/src/lib.rs b/src/doc/book/listings/ch20-web-server/listing-20-18/src/lib.rs new file mode 100644 index 000000000..4bff8acad --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-18/src/lib.rs @@ -0,0 +1,76 @@ +// ANCHOR: here +use std::{ + sync::{mpsc, Arc, Mutex}, + thread, +}; +// --snip-- + +// ANCHOR_END: here +pub struct ThreadPool { + workers: Vec, + sender: mpsc::Sender, +} + +struct Job; + +// ANCHOR: here +impl ThreadPool { + // --snip-- + // ANCHOR_END: here + /// Create a new ThreadPool. + /// + /// The size is the number of threads in the pool. + /// + /// # Panics + /// + /// The `new` function will panic if the size is zero. + // ANCHOR: here + pub fn new(size: usize) -> ThreadPool { + assert!(size > 0); + + let (sender, receiver) = mpsc::channel(); + + let receiver = Arc::new(Mutex::new(receiver)); + + let mut workers = Vec::with_capacity(size); + + for id in 0..size { + workers.push(Worker::new(id, Arc::clone(&receiver))); + } + + ThreadPool { workers, sender } + } + + // --snip-- + // ANCHOR_END: here + + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + } + // ANCHOR: here +} + +// --snip-- + +// ANCHOR_END: here +struct Worker { + id: usize, + thread: thread::JoinHandle<()>, +} + +// ANCHOR: here +impl Worker { + fn new(id: usize, receiver: Arc>>) -> Worker { + // --snip-- + // ANCHOR_END: here + let thread = thread::spawn(|| { + receiver; + }); + + Worker { id, thread } + // ANCHOR: here + } +} +// ANCHOR_END: here diff --git a/src/doc/book/listings/ch20-web-server/listing-20-18/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-18/src/main.rs new file mode 100644 index 000000000..79efb28a2 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-18/src/main.rs @@ -0,0 +1,43 @@ +use hello::ThreadPool; +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-19/404.html b/src/doc/book/listings/ch20-web-server/listing-20-19/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-19/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-19/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-19/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-19/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-19/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-19/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-19/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-19/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-19/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-19/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-19/src/lib.rs b/src/doc/book/listings/ch20-web-server/listing-20-19/src/lib.rs new file mode 100644 index 000000000..aeb1facd6 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-19/src/lib.rs @@ -0,0 +1,69 @@ +use std::{ + sync::{mpsc, Arc, Mutex}, + thread, +}; + +pub struct ThreadPool { + workers: Vec, + sender: mpsc::Sender, +} + +// ANCHOR: here +// --snip-- + +type Job = Box; + +impl ThreadPool { + // --snip-- + // ANCHOR_END: here + /// Create a new ThreadPool. + /// + /// The size is the number of threads in the pool. + /// + /// # Panics + /// + /// The `new` function will panic if the size is zero. + pub fn new(size: usize) -> ThreadPool { + assert!(size > 0); + + let (sender, receiver) = mpsc::channel(); + + let receiver = Arc::new(Mutex::new(receiver)); + + let mut workers = Vec::with_capacity(size); + + for id in 0..size { + workers.push(Worker::new(id, Arc::clone(&receiver))); + } + + ThreadPool { workers, sender } + } + // ANCHOR: here + + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + let job = Box::new(f); + + self.sender.send(job).unwrap(); + } +} + +// --snip-- +// ANCHOR_END: here + +struct Worker { + id: usize, + thread: thread::JoinHandle<()>, +} + +impl Worker { + fn new(id: usize, receiver: Arc>>) -> Worker { + let thread = thread::spawn(|| { + receiver; + }); + + Worker { id, thread } + } +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-19/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-19/src/main.rs new file mode 100644 index 000000000..79efb28a2 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-19/src/main.rs @@ -0,0 +1,43 @@ +use hello::ThreadPool; +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-20/404.html b/src/doc/book/listings/ch20-web-server/listing-20-20/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-20/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-20/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-20/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-20/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-20/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-20/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-20/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-20/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-20/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-20/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-20/src/lib.rs b/src/doc/book/listings/ch20-web-server/listing-20-20/src/lib.rs new file mode 100644 index 000000000..86157c9e7 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-20/src/lib.rs @@ -0,0 +1,68 @@ +use std::{ + sync::{mpsc, Arc, Mutex}, + thread, +}; + +pub struct ThreadPool { + workers: Vec, + sender: mpsc::Sender, +} + +type Job = Box; + +impl ThreadPool { + /// Create a new ThreadPool. + /// + /// The size is the number of threads in the pool. + /// + /// # Panics + /// + /// The `new` function will panic if the size is zero. + pub fn new(size: usize) -> ThreadPool { + assert!(size > 0); + + let (sender, receiver) = mpsc::channel(); + + let receiver = Arc::new(Mutex::new(receiver)); + + let mut workers = Vec::with_capacity(size); + + for id in 0..size { + workers.push(Worker::new(id, Arc::clone(&receiver))); + } + + ThreadPool { workers, sender } + } + + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + let job = Box::new(f); + + self.sender.send(job).unwrap(); + } +} + +struct Worker { + id: usize, + thread: thread::JoinHandle<()>, +} + +// ANCHOR: here +// --snip-- + +impl Worker { + fn new(id: usize, receiver: Arc>>) -> Worker { + let thread = thread::spawn(move || loop { + let job = receiver.lock().unwrap().recv().unwrap(); + + println!("Worker {id} got a job; executing."); + + job(); + }); + + Worker { id, thread } + } +} +// ANCHOR_END: here diff --git a/src/doc/book/listings/ch20-web-server/listing-20-20/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-20/src/main.rs new file mode 100644 index 000000000..79efb28a2 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-20/src/main.rs @@ -0,0 +1,43 @@ +use hello::ThreadPool; +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-21/404.html b/src/doc/book/listings/ch20-web-server/listing-20-21/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-21/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-21/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-21/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-21/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-21/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-21/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-21/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-21/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-21/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-21/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-21/src/lib.rs b/src/doc/book/listings/ch20-web-server/listing-20-21/src/lib.rs new file mode 100644 index 000000000..17b37e77b --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-21/src/lib.rs @@ -0,0 +1,67 @@ +use std::{ + sync::{mpsc, Arc, Mutex}, + thread, +}; + +pub struct ThreadPool { + workers: Vec, + sender: mpsc::Sender, +} + +type Job = Box; + +impl ThreadPool { + /// Create a new ThreadPool. + /// + /// The size is the number of threads in the pool. + /// + /// # Panics + /// + /// The `new` function will panic if the size is zero. + pub fn new(size: usize) -> ThreadPool { + assert!(size > 0); + + let (sender, receiver) = mpsc::channel(); + + let receiver = Arc::new(Mutex::new(receiver)); + + let mut workers = Vec::with_capacity(size); + + for id in 0..size { + workers.push(Worker::new(id, Arc::clone(&receiver))); + } + + ThreadPool { workers, sender } + } + + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + let job = Box::new(f); + + self.sender.send(job).unwrap(); + } +} + +struct Worker { + id: usize, + thread: thread::JoinHandle<()>, +} +// ANCHOR: here +// --snip-- + +impl Worker { + fn new(id: usize, receiver: Arc>>) -> Worker { + let thread = thread::spawn(move || { + while let Ok(job) = receiver.lock().unwrap().recv() { + println!("Worker {id} got a job; executing."); + + job(); + } + }); + + Worker { id, thread } + } +} +// ANCHOR_END: here diff --git a/src/doc/book/listings/ch20-web-server/listing-20-21/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-21/src/main.rs new file mode 100644 index 000000000..79efb28a2 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-21/src/main.rs @@ -0,0 +1,43 @@ +use hello::ThreadPool; +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-22/404.html b/src/doc/book/listings/ch20-web-server/listing-20-22/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-22/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-22/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-22/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-22/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-22/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-22/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-22/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-22/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-22/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-22/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-22/output.txt b/src/doc/book/listings/ch20-web-server/listing-20-22/output.txt new file mode 100644 index 000000000..4402092e9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-22/output.txt @@ -0,0 +1,14 @@ +$ cargo check + Checking hello v0.1.0 (file:///projects/hello) +error[E0507]: cannot move out of `worker.thread` which is behind a mutable reference + --> src/lib.rs:52:13 + | +52 | worker.thread.join().unwrap(); + | ^^^^^^^^^^^^^ ------ `worker.thread` moved due to this method call + | | + | move occurs because `worker.thread` has type `JoinHandle<()>`, which does not implement the `Copy` trait + | +note: this function takes ownership of the receiver `self`, which moves `worker.thread` + +For more information about this error, try `rustc --explain E0507`. +error: could not compile `hello` due to previous error diff --git a/src/doc/book/listings/ch20-web-server/listing-20-22/src/lib.rs b/src/doc/book/listings/ch20-web-server/listing-20-22/src/lib.rs new file mode 100644 index 000000000..72a8c4808 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-22/src/lib.rs @@ -0,0 +1,76 @@ +use std::{ + sync::{mpsc, Arc, Mutex}, + thread, +}; + +pub struct ThreadPool { + workers: Vec, + sender: mpsc::Sender, +} + +type Job = Box; + +impl ThreadPool { + /// Create a new ThreadPool. + /// + /// The size is the number of threads in the pool. + /// + /// # Panics + /// + /// The `new` function will panic if the size is zero. + pub fn new(size: usize) -> ThreadPool { + assert!(size > 0); + + let (sender, receiver) = mpsc::channel(); + + let receiver = Arc::new(Mutex::new(receiver)); + + let mut workers = Vec::with_capacity(size); + + for id in 0..size { + workers.push(Worker::new(id, Arc::clone(&receiver))); + } + + ThreadPool { workers, sender } + } + + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + let job = Box::new(f); + + self.sender.send(job).unwrap(); + } +} + +// ANCHOR: here +impl Drop for ThreadPool { + fn drop(&mut self) { + for worker in &mut self.workers { + println!("Shutting down worker {}", worker.id); + + worker.thread.join().unwrap(); + } + } +} +// ANCHOR_END: here + +struct Worker { + id: usize, + thread: thread::JoinHandle<()>, +} + +impl Worker { + fn new(id: usize, receiver: Arc>>) -> Worker { + let thread = thread::spawn(move || loop { + let job = receiver.lock().unwrap().recv().unwrap(); + + println!("Worker {id} got a job; executing."); + + job(); + }); + + Worker { id, thread } + } +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-22/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-22/src/main.rs new file mode 100644 index 000000000..79efb28a2 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-22/src/main.rs @@ -0,0 +1,43 @@ +use hello::ThreadPool; +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-23/404.html b/src/doc/book/listings/ch20-web-server/listing-20-23/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-23/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-23/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-23/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-23/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-23/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-23/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-23/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-23/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-23/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-23/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-23/src/lib.rs b/src/doc/book/listings/ch20-web-server/listing-20-23/src/lib.rs new file mode 100644 index 000000000..eea339b02 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-23/src/lib.rs @@ -0,0 +1,95 @@ +use std::{ + sync::{mpsc, Arc, Mutex}, + thread, +}; + +// ANCHOR: here +pub struct ThreadPool { + workers: Vec, + sender: Option>, +} +// --snip-- +// ANCHOR_END: here + +type Job = Box; + +// ANCHOR: here +impl ThreadPool { + // ANCHOR_END: here + /// Create a new ThreadPool. + /// + /// The size is the number of threads in the pool. + /// + /// # Panics + /// + /// The `new` function will panic if the size is zero. + // ANCHOR: here + pub fn new(size: usize) -> ThreadPool { + // --snip-- + + // ANCHOR_END: here + assert!(size > 0); + + let (sender, receiver) = mpsc::channel(); + + let receiver = Arc::new(Mutex::new(receiver)); + + let mut workers = Vec::with_capacity(size); + + for id in 0..size { + workers.push(Worker::new(id, Arc::clone(&receiver))); + } + + // ANCHOR: here + ThreadPool { + workers, + sender: Some(sender), + } + } + + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + let job = Box::new(f); + + self.sender.as_ref().unwrap().send(job).unwrap(); + } +} + +impl Drop for ThreadPool { + fn drop(&mut self) { + drop(self.sender.take()); + + for worker in &mut self.workers { + println!("Shutting down worker {}", worker.id); + + if let Some(thread) = worker.thread.take() { + thread.join().unwrap(); + } + } + } +} +// ANCHOR_END: here + +struct Worker { + id: usize, + thread: Option>, +} + +impl Worker { + fn new(id: usize, receiver: Arc>>) -> Worker { + let thread = thread::spawn(move || loop { + let job = receiver.lock().unwrap().recv().unwrap(); + + println!("Worker {id} got a job; executing."); + + job(); + }); + + Worker { + id, + thread: Some(thread), + } + } +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-23/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-23/src/main.rs new file mode 100644 index 000000000..b6aa046d1 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-23/src/main.rs @@ -0,0 +1,45 @@ +use hello::ThreadPool; +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming().take(2) { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } + + println!("Shutting down."); +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-24/404.html b/src/doc/book/listings/ch20-web-server/listing-20-24/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-24/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-24/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-24/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-24/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-24/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-24/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-24/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-24/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-24/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-24/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-24/src/lib.rs b/src/doc/book/listings/ch20-web-server/listing-20-24/src/lib.rs new file mode 100644 index 000000000..55e8fef8f --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-24/src/lib.rs @@ -0,0 +1,92 @@ +use std::{ + sync::{mpsc, Arc, Mutex}, + thread, +}; + +pub struct ThreadPool { + workers: Vec, + sender: Option>, +} + +type Job = Box; + +impl ThreadPool { + /// Create a new ThreadPool. + /// + /// The size is the number of threads in the pool. + /// + /// # Panics + /// + /// The `new` function will panic if the size is zero. + pub fn new(size: usize) -> ThreadPool { + assert!(size > 0); + + let (sender, receiver) = mpsc::channel(); + + let receiver = Arc::new(Mutex::new(receiver)); + + let mut workers = Vec::with_capacity(size); + + for id in 0..size { + workers.push(Worker::new(id, Arc::clone(&receiver))); + } + + ThreadPool { + workers, + sender: Some(sender), + } + } + + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + let job = Box::new(f); + + self.sender.as_ref().unwrap().send(job).unwrap(); + } +} + +impl Drop for ThreadPool { + fn drop(&mut self) { + drop(self.sender.take()); + + for worker in &mut self.workers { + println!("Shutting down worker {}", worker.id); + + if let Some(thread) = worker.thread.take() { + thread.join().unwrap(); + } + } + } +} + +struct Worker { + id: usize, + thread: Option>, +} + +// ANCHOR: here +impl Worker { + fn new(id: usize, receiver: Arc>>) -> Worker { + let thread = thread::spawn(move || loop { + match receiver.lock().unwrap().recv() { + Ok(job) => { + println!("Worker {id} got a job; executing."); + + job(); + } + Err(_) => { + println!("Worker {id} disconnected; shutting down."); + break; + } + } + }); + + Worker { + id, + thread: Some(thread), + } + } +} +// ANCHOR_END: here diff --git a/src/doc/book/listings/ch20-web-server/listing-20-24/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-24/src/main.rs new file mode 100644 index 000000000..b6aa046d1 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-24/src/main.rs @@ -0,0 +1,45 @@ +use hello::ThreadPool; +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming().take(2) { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } + + println!("Shutting down."); +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-25/404.html b/src/doc/book/listings/ch20-web-server/listing-20-25/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-25/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-25/Cargo.lock b/src/doc/book/listings/ch20-web-server/listing-20-25/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-25/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-25/Cargo.toml b/src/doc/book/listings/ch20-web-server/listing-20-25/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-25/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/listing-20-25/hello.html b/src/doc/book/listings/ch20-web-server/listing-20-25/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-25/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/listing-20-25/src/lib.rs b/src/doc/book/listings/ch20-web-server/listing-20-25/src/lib.rs new file mode 100644 index 000000000..54c0489ab --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-25/src/lib.rs @@ -0,0 +1,92 @@ +use std::{ + sync::{mpsc, Arc, Mutex}, + thread, +}; + +pub struct ThreadPool { + workers: Vec, + sender: Option>, +} + +type Job = Box; + +impl ThreadPool { + /// Create a new ThreadPool. + /// + /// The size is the number of threads in the pool. + /// + /// # Panics + /// + /// The `new` function will panic if the size is zero. + pub fn new(size: usize) -> ThreadPool { + assert!(size > 0); + + let (sender, receiver) = mpsc::channel(); + + let receiver = Arc::new(Mutex::new(receiver)); + + let mut workers = Vec::with_capacity(size); + + for id in 0..size { + workers.push(Worker::new(id, Arc::clone(&receiver))); + } + + ThreadPool { + workers, + sender: Some(sender), + } + } + + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + let job = Box::new(f); + + self.sender.as_ref().unwrap().send(job).unwrap(); + } +} + +impl Drop for ThreadPool { + fn drop(&mut self) { + drop(self.sender.take()); + + for worker in &mut self.workers { + println!("Shutting down worker {}", worker.id); + + if let Some(thread) = worker.thread.take() { + thread.join().unwrap(); + } + } + } +} + +struct Worker { + id: usize, + thread: Option>, +} + +impl Worker { + fn new(id: usize, receiver: Arc>>) -> Worker { + let thread = thread::spawn(move || loop { + let message = receiver.lock().unwrap().recv(); + + match message { + Ok(job) => { + println!("Worker {id} got a job; executing."); + + job(); + } + Err(_) => { + println!("Worker {id} disconnected; shutting down."); + break; + } + } + }); + + Worker { + id, + thread: Some(thread), + } + } +} diff --git a/src/doc/book/listings/ch20-web-server/listing-20-25/src/main.rs b/src/doc/book/listings/ch20-web-server/listing-20-25/src/main.rs new file mode 100644 index 000000000..a649ff103 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/listing-20-25/src/main.rs @@ -0,0 +1,53 @@ +use hello::ThreadPool; +use std::fs; +use std::io::prelude::*; +use std::net::TcpListener; +use std::net::TcpStream; +use std::thread; +use std::time::Duration; + +// ANCHOR: here +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming().take(2) { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } + + println!("Shutting down."); +} +// ANCHOR_END: here + +fn handle_connection(mut stream: TcpStream) { + let mut buffer = [0; 1024]; + stream.read(&mut buffer).unwrap(); + + let get = b"GET / HTTP/1.1\r\n"; + let sleep = b"GET /sleep HTTP/1.1\r\n"; + + let (status_line, filename) = if buffer.starts_with(get) { + ("HTTP/1.1 200 OK", "hello.html") + } else if buffer.starts_with(sleep) { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } else { + ("HTTP/1.1 404 NOT FOUND", "404.html") + }; + + let contents = fs::read_to_string(filename).unwrap(); + + let response = format!( + "{}\r\nContent-Length: {}\r\n\r\n{}", + status_line, + contents.len(), + contents + ); + + stream.write_all(response.as_bytes()).unwrap(); + stream.flush().unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/404.html b/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/Cargo.lock b/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/Cargo.toml b/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/hello.html b/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/output.txt b/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/output.txt new file mode 100644 index 000000000..fa337b8a8 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/output.txt @@ -0,0 +1,10 @@ +$ cargo check + Checking hello v0.1.0 (file:///projects/hello) +error[E0599]: no function or associated item named `new` found for struct `ThreadPool` in the current scope + --> src/main.rs:12:28 + | +12 | let pool = ThreadPool::new(4); + | ^^^ function or associated item not found in `ThreadPool` + +For more information about this error, try `rustc --explain E0599`. +error: could not compile `hello` due to previous error diff --git a/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/src/lib.rs b/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/src/lib.rs new file mode 100644 index 000000000..7312e293d --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/src/lib.rs @@ -0,0 +1 @@ +pub struct ThreadPool; diff --git a/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/src/main.rs b/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/src/main.rs new file mode 100644 index 000000000..f7b42167f --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/src/main.rs @@ -0,0 +1,45 @@ +// ANCHOR: here +use hello::ThreadPool; +// ANCHOR_END: here +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/404.html b/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/Cargo.lock b/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/Cargo.toml b/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/hello.html b/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/output.txt b/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/output.txt new file mode 100644 index 000000000..44c8f3953 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/output.txt @@ -0,0 +1,10 @@ +$ cargo check + Checking hello v0.1.0 (file:///projects/hello) +error[E0599]: no method named `execute` found for struct `ThreadPool` in the current scope + --> src/main.rs:17:14 + | +17 | pool.execute(|| { + | ^^^^^^^ method not found in `ThreadPool` + +For more information about this error, try `rustc --explain E0599`. +error: could not compile `hello` due to previous error diff --git a/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/src/lib.rs b/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/src/lib.rs new file mode 100644 index 000000000..f0e1890bb --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/src/lib.rs @@ -0,0 +1,7 @@ +pub struct ThreadPool; + +impl ThreadPool { + pub fn new(size: usize) -> ThreadPool { + ThreadPool + } +} diff --git a/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/src/main.rs b/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/src/main.rs new file mode 100644 index 000000000..79efb28a2 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/src/main.rs @@ -0,0 +1,43 @@ +use hello::ThreadPool; +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/404.html b/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/Cargo.lock b/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/Cargo.toml b/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/hello.html b/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/output.txt b/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/output.txt new file mode 100644 index 000000000..dc76c43d6 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/output.txt @@ -0,0 +1,3 @@ +$ cargo check + Checking hello v0.1.0 (file:///projects/hello) + Finished dev [unoptimized + debuginfo] target(s) in 0.24s diff --git a/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/src/lib.rs b/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/src/lib.rs new file mode 100644 index 000000000..1321ab873 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/src/lib.rs @@ -0,0 +1,18 @@ +pub struct ThreadPool; + +// ANCHOR: here +impl ThreadPool { + // --snip-- + // ANCHOR_END: here + pub fn new(size: usize) -> ThreadPool { + ThreadPool + } + + // ANCHOR: here + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + } +} +// ANCHOR_END: here diff --git a/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/src/main.rs b/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/src/main.rs new file mode 100644 index 000000000..79efb28a2 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-03-define-execute/src/main.rs @@ -0,0 +1,43 @@ +use hello::ThreadPool; +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/404.html b/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/Cargo.lock b/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/Cargo.toml b/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/hello.html b/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/output.txt b/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/output.txt new file mode 100644 index 000000000..34d30fe05 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/output.txt @@ -0,0 +1,24 @@ +$ cargo check + Checking hello v0.1.0 (file:///projects/hello) +error[E0599]: no method named `join` found for enum `Option` in the current scope + --> src/lib.rs:52:27 + | +52 | worker.thread.join().unwrap(); + | ^^^^ method not found in `Option>` + +error[E0308]: mismatched types + --> src/lib.rs:72:22 + | +72 | Worker { id, thread } + | ^^^^^^ expected enum `Option`, found struct `JoinHandle` + | + = note: expected enum `Option>` + found struct `JoinHandle<_>` +help: try wrapping the expression in `Some` + | +72 | Worker { id, thread: Some(thread) } + | +++++++++++++ + + +Some errors have detailed explanations: E0308, E0599. +For more information about an error, try `rustc --explain E0308`. +error: could not compile `hello` due to 2 previous errors diff --git a/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/src/lib.rs b/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/src/lib.rs new file mode 100644 index 000000000..6ef710a26 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/src/lib.rs @@ -0,0 +1,76 @@ +use std::{ + sync::{mpsc, Arc, Mutex}, + thread, +}; + +pub struct ThreadPool { + workers: Vec, + sender: mpsc::Sender, +} + +type Job = Box; + +impl ThreadPool { + /// Create a new ThreadPool. + /// + /// The size is the number of threads in the pool. + /// + /// # Panics + /// + /// The `new` function will panic if the size is zero. + pub fn new(size: usize) -> ThreadPool { + assert!(size > 0); + + let (sender, receiver) = mpsc::channel(); + + let receiver = Arc::new(Mutex::new(receiver)); + + let mut workers = Vec::with_capacity(size); + + for id in 0..size { + workers.push(Worker::new(id, Arc::clone(&receiver))); + } + + ThreadPool { workers, sender } + } + + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + let job = Box::new(f); + + self.sender.send(job).unwrap(); + } +} + +impl Drop for ThreadPool { + fn drop(&mut self) { + for worker in &mut self.workers { + println!("Shutting down worker {}", worker.id); + + worker.thread.join().unwrap(); + } + } +} + +// ANCHOR: here +struct Worker { + id: usize, + thread: Option>, +} +// ANCHOR_END: here + +impl Worker { + fn new(id: usize, receiver: Arc>>) -> Worker { + let thread = thread::spawn(move || loop { + let job = receiver.lock().unwrap().recv().unwrap(); + + println!("Worker {id} got a job; executing."); + + job(); + }); + + Worker { id, thread } + } +} diff --git a/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/src/main.rs b/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/src/main.rs new file mode 100644 index 000000000..79efb28a2 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/src/main.rs @@ -0,0 +1,43 @@ +use hello::ThreadPool; +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/404.html b/src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/Cargo.lock b/src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/Cargo.toml b/src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/hello.html b/src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/src/lib.rs b/src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/src/lib.rs new file mode 100644 index 000000000..ede3750a1 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/src/lib.rs @@ -0,0 +1,83 @@ +use std::{ + sync::{mpsc, Arc, Mutex}, + thread, +}; + +pub struct ThreadPool { + workers: Vec, + sender: mpsc::Sender, +} + +type Job = Box; + +impl ThreadPool { + /// Create a new ThreadPool. + /// + /// The size is the number of threads in the pool. + /// + /// # Panics + /// + /// The `new` function will panic if the size is zero. + pub fn new(size: usize) -> ThreadPool { + assert!(size > 0); + + let (sender, receiver) = mpsc::channel(); + + let receiver = Arc::new(Mutex::new(receiver)); + + let mut workers = Vec::with_capacity(size); + + for id in 0..size { + workers.push(Worker::new(id, Arc::clone(&receiver))); + } + + ThreadPool { workers, sender } + } + + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + let job = Box::new(f); + + self.sender.send(job).unwrap(); + } +} + +impl Drop for ThreadPool { + fn drop(&mut self) { + for worker in &mut self.workers { + println!("Shutting down worker {}", worker.id); + + worker.thread.join().unwrap(); + } + } +} + +struct Worker { + id: usize, + thread: Option>, +} + +// ANCHOR: here +impl Worker { + fn new(id: usize, receiver: Arc>>) -> Worker { + // --snip-- + + // ANCHOR_END: here + let thread = thread::spawn(move || loop { + let job = receiver.lock().unwrap().recv().unwrap(); + + println!("Worker {id} got a job; executing."); + + job(); + }); + + // ANCHOR: here + Worker { + id, + thread: Some(thread), + } + } +} +// ANCHOR_END: here diff --git a/src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/src/main.rs b/src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/src/main.rs new file mode 100644 index 000000000..79efb28a2 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-05-fix-worker-new/src/main.rs @@ -0,0 +1,43 @@ +use hello::ThreadPool; +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/404.html b/src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/Cargo.lock b/src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/Cargo.toml b/src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/hello.html b/src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/src/lib.rs b/src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/src/lib.rs new file mode 100644 index 000000000..b795ea53b --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/src/lib.rs @@ -0,0 +1,81 @@ +use std::{ + sync::{mpsc, Arc, Mutex}, + thread, +}; + +pub struct ThreadPool { + workers: Vec, + sender: mpsc::Sender, +} + +type Job = Box; + +impl ThreadPool { + /// Create a new ThreadPool. + /// + /// The size is the number of threads in the pool. + /// + /// # Panics + /// + /// The `new` function will panic if the size is zero. + pub fn new(size: usize) -> ThreadPool { + assert!(size > 0); + + let (sender, receiver) = mpsc::channel(); + + let receiver = Arc::new(Mutex::new(receiver)); + + let mut workers = Vec::with_capacity(size); + + for id in 0..size { + workers.push(Worker::new(id, Arc::clone(&receiver))); + } + + ThreadPool { workers, sender } + } + + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + let job = Box::new(f); + + self.sender.send(job).unwrap(); + } +} + +// ANCHOR: here +impl Drop for ThreadPool { + fn drop(&mut self) { + for worker in &mut self.workers { + println!("Shutting down worker {}", worker.id); + + if let Some(thread) = worker.thread.take() { + thread.join().unwrap(); + } + } + } +} +// ANCHOR_END: here + +struct Worker { + id: usize, + thread: Option>, +} + +impl Worker { + fn new(id: usize, receiver: Arc>>) -> Worker { + let thread = thread::spawn(move || loop { + let job = receiver.lock().unwrap().recv().unwrap(); + + println!("Worker {id} got a job; executing."); + + job(); + }); + + Worker { + id, + thread: Some(thread), + } + } +} diff --git a/src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/src/main.rs b/src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/src/main.rs new file mode 100644 index 000000000..b6aa046d1 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-06-fix-threadpool-drop/src/main.rs @@ -0,0 +1,45 @@ +use hello::ThreadPool; +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, + thread, + time::Duration, +}; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming().take(2) { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } + + println!("Shutting down."); +} + +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&mut stream); + let request_line = buf_reader.lines().next().unwrap().unwrap(); + + let (status_line, filename) = match &request_line[..] { + "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"), + "GET /sleep HTTP/1.1" => { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } + _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), + }; + + let contents = fs::read_to_string(filename).unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + stream.write_all(response.as_bytes()).unwrap(); +} diff --git a/src/doc/book/listings/ch20-web-server/no-listing-07-final-code/404.html b/src/doc/book/listings/ch20-web-server/no-listing-07-final-code/404.html new file mode 100644 index 000000000..88d8e9152 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-07-final-code/404.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Oops!

+

Sorry, I don't know what you're asking for.

+ + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-07-final-code/Cargo.lock b/src/doc/book/listings/ch20-web-server/no-listing-07-final-code/Cargo.lock new file mode 100644 index 000000000..f2d069f46 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-07-final-code/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "hello" +version = "0.1.0" + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-07-final-code/Cargo.toml b/src/doc/book/listings/ch20-web-server/no-listing-07-final-code/Cargo.toml new file mode 100644 index 000000000..fe619478a --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-07-final-code/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/doc/book/listings/ch20-web-server/no-listing-07-final-code/hello.html b/src/doc/book/listings/ch20-web-server/no-listing-07-final-code/hello.html new file mode 100644 index 000000000..fe442d6b9 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-07-final-code/hello.html @@ -0,0 +1,11 @@ + + + + + Hello! + + +

Hello!

+

Hi from Rust

+ + diff --git a/src/doc/book/listings/ch20-web-server/no-listing-07-final-code/src/lib.rs b/src/doc/book/listings/ch20-web-server/no-listing-07-final-code/src/lib.rs new file mode 100644 index 000000000..54c0489ab --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-07-final-code/src/lib.rs @@ -0,0 +1,92 @@ +use std::{ + sync::{mpsc, Arc, Mutex}, + thread, +}; + +pub struct ThreadPool { + workers: Vec, + sender: Option>, +} + +type Job = Box; + +impl ThreadPool { + /// Create a new ThreadPool. + /// + /// The size is the number of threads in the pool. + /// + /// # Panics + /// + /// The `new` function will panic if the size is zero. + pub fn new(size: usize) -> ThreadPool { + assert!(size > 0); + + let (sender, receiver) = mpsc::channel(); + + let receiver = Arc::new(Mutex::new(receiver)); + + let mut workers = Vec::with_capacity(size); + + for id in 0..size { + workers.push(Worker::new(id, Arc::clone(&receiver))); + } + + ThreadPool { + workers, + sender: Some(sender), + } + } + + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + let job = Box::new(f); + + self.sender.as_ref().unwrap().send(job).unwrap(); + } +} + +impl Drop for ThreadPool { + fn drop(&mut self) { + drop(self.sender.take()); + + for worker in &mut self.workers { + println!("Shutting down worker {}", worker.id); + + if let Some(thread) = worker.thread.take() { + thread.join().unwrap(); + } + } + } +} + +struct Worker { + id: usize, + thread: Option>, +} + +impl Worker { + fn new(id: usize, receiver: Arc>>) -> Worker { + let thread = thread::spawn(move || loop { + let message = receiver.lock().unwrap().recv(); + + match message { + Ok(job) => { + println!("Worker {id} got a job; executing."); + + job(); + } + Err(_) => { + println!("Worker {id} disconnected; shutting down."); + break; + } + } + }); + + Worker { + id, + thread: Some(thread), + } + } +} diff --git a/src/doc/book/listings/ch20-web-server/no-listing-07-final-code/src/main.rs b/src/doc/book/listings/ch20-web-server/no-listing-07-final-code/src/main.rs new file mode 100644 index 000000000..3161c2ee5 --- /dev/null +++ b/src/doc/book/listings/ch20-web-server/no-listing-07-final-code/src/main.rs @@ -0,0 +1,51 @@ +use hello::ThreadPool; +use std::fs; +use std::io::prelude::*; +use std::net::TcpListener; +use std::net::TcpStream; +use std::thread; +use std::time::Duration; + +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming().take(2) { + let stream = stream.unwrap(); + + pool.execute(|| { + handle_connection(stream); + }); + } + + println!("Shutting down."); +} + +fn handle_connection(mut stream: TcpStream) { + let mut buffer = [0; 1024]; + stream.read(&mut buffer).unwrap(); + + let get = b"GET / HTTP/1.1\r\n"; + let sleep = b"GET /sleep HTTP/1.1\r\n"; + + let (status_line, filename) = if buffer.starts_with(get) { + ("HTTP/1.1 200 OK", "hello.html") + } else if buffer.starts_with(sleep) { + thread::sleep(Duration::from_secs(5)); + ("HTTP/1.1 200 OK", "hello.html") + } else { + ("HTTP/1.1 404 NOT FOUND", "404.html") + }; + + let contents = fs::read_to_string(filename).unwrap(); + + let response = format!( + "{}\r\nContent-Length: {}\r\n\r\n{}", + status_line, + contents.len(), + contents + ); + + stream.write_all(response.as_bytes()).unwrap(); + stream.flush().unwrap(); +} -- cgit v1.2.3