CSE 331: Software Design and Implementation, Autumn 2026
Your job is to deliver code that you know works.
$ javac Guestbook.java $ java Guestbook Serving at http://localhost:9331/
Ada, hello world: and now?$ java Guestbook Serving at http://localhost:9331/ GET / GET /favicon.ico POST / GET /favicon.ico GET / GET /favicon.ico
Browser A sends GET /, text; the terminal prints it
handle builds the page from the empty book, and sends it as text
Browser A draws the text: the heading, the boxes, the button
Post: POST /, ending with name=Ada&message=hello+world
handle adds the message, builds the page again, and sends it
Browser A draws the new page: the message, and empty boxes
Browser B sends its own GET /: the same line on the terminal
One book, so B's page is built with Ada's message in it
Browser B draws it: a message nobody typed in browser B
21public class Guestbook {
22 // The one book, shared by every request the server handles.
23 private static Book book = new Book();static book: every request, from any browser, reads or adds to itGET / HTTP/1.1
Host: localhost:933141String method = exchange.getRequestMethod();
42System.out.println(method + " " + exchange.getRequestURI());The method, GET, and the path, /: line 41 reads them, line 42 prints them
Which server the request is for; then lines about the browser, and a blank line
HTTP/1.1 200 OK
Content-type: text/html; charset=utf-8
Content-length: 178
<html><body>55byte[] page = page().getBytes(StandardCharsets.UTF_8);
56exchange.getResponseHeaders()
57 .set("Content-Type", "text/html; charset=utf-8");
58exchange.sendResponseHeaders(200, page.length);
59exchange.getResponseBody().write(page);
60exchange.close();A status, 200: the request was understood and answered
A header: what the body is, text in HTML
A header, the body's length: 178 bytes, counted after line 55 makes them
A blank line, then the body: the page, in HTML, text with tags
POST / HTTP/1.1
Host: localhost:9331
Content-Length: 28
Content-Type: application/x-www-form-urlencoded
name=Ada&message=hello+world46if (method.equals("POST")) {
47 byte[] bytes = exchange.getRequestBody().readAllBytes();
48 String body = new String(bytes, StandardCharsets.UTF_8);
49 Map<String, String> fields = parseForm(body);
50 book.add(fields.get("name"), fields.get("message"));The method is POST, so line 46 runs the branch
A body after the blank line, the form's fields: read as text
Split at & and =, decoded: + was a space
The message goes into the book; then the page, as for any request
25public static void main(String[] args) throws IOException {
26 HttpServer server =
27 HttpServer.create(new InetSocketAddress(9331), 0);
28 server.createContext("/", Guestbook::handle);
29 server.start();
30 System.out.println("Serving at http://localhost:9331/");
31}The calculator's main was a loop. Seven lines here, and no loop: where is it?
Not a call: the method handle itself, handed to the server as a value
The loop starts inside HttpServer; main returns, and the program keeps running
HttpServer: wait for an event, call handleHttpServer is a framework: nothing in the file calls handle, yet it runsGET / and POST /curl sends whatever request it is told to: what else could arrive?Your job is to deliver code that you know works.
$ curl http://localhost:9331/favicon.ico <html><body> <h1>Guestbook</h1> ⋮
Line 28: handle answers /, a prefix of every path: every path gets the page
$ curl -d '' http://localhost:9331/ ⋮ <li>null: null</li> ⋮
parseForm's map held neither field, so line 50 added null: null
$ curl -d 'name=%&message=x' http://localhost:9331/ curl: (52) Empty reply from server
parseForm requires a form's body, and nothing in handle checks: URLDecoder threw
$ curl -d 'name=Eve&message=%3Cb%3Ehello%3C%2Fb%3E' http://localhost:9331/ ⋮ <li>Eve: <b>hello</b></li> ⋮
Every later visitor's browser reads the tag: hello, in bold
<script> can run in every later visitor's browserGET /
GET /favicon.ico
POST /
The browser asks first, then sends the POST again: the message twice