# Lab 7: WriterT Web Server Logging

Posted on December 2, 2019

## Announcements

This is the last lab. Because of reading period, it is due Wednesday by 11:59pm; but hopefully you will finish it in class today.

## The Web

Sir Tim Berners-Lee announced the first public website in August, 1991.

Hypertext was an old idea, TCP networking was widespread, and the domain name system was already several years old. In retrospect, the combination of these things into what we now know as the Web seems obvious, but the Web was a comparatively late arrival to the internet.

The core innovations that enabled the explosive growth of the Web were two fairly simple protocols:

1. HTML, a simple text display language with unidirectional URL links to resources on the same or different computers.
2. HTTP, a simple protocol for requesting such resources.

You’ve probably seen some HTML, but perhaps not HTTP. The basics are simple enough. Let’s fetch the first web page—manually.

$nc -c info.cern.ch 80 or$ telnet info.cern.ch 80

This command uses the domain name system to translate “info.cern.ch” into an internet address and then opens a TCP connection on port 80 to the computer at that address.

Nothing happens because we haven’t sent anything over the connection yet, but anything we type will be sent to info.cern.ch. Let’s ask for the page.

GET /hypertext/WWW/TheProject.html HTTP/1.1
Host: info.cern.ch

In the old days you wouldn’t even need the “Host” line, but now it is necessary because one computer might be serving pages for multiple domains.

Hit return twice to indicate that the request is complete and we are ready for a response. It should come immediately:

HTTP/1.1 200 OK
Date: Mon, 27 Nov 2017 10:27:04 GMT
Server: Apache
Last-Modified: Thu, 03 Dec 1992 08:37:20 GMT
ETag: "40521e06-8a9-291e721905000"
Accept-Ranges: bytes
Content-Length: 2217
Connection: close
Content-Type: text/html

<TITLE>The World Wide Web project</TITLE>
<NEXTID N="55">
<BODY>
<H1>World Wide Web</H1>The WorldWideWeb (W3) is a wide-area<A
NAME=0 HREF="WhatIs.html">
hypermedia</A> information retrieval
...
</BODY>
Connection closed by foreign host.

Look at that! Party like it’s 1991.

Let’s take a look at the headers:

HTTP/1.1 200 OK
Date: Mon, 27 Nov 2017 10:27:04 GMT
Server: Apache
Last-Modified: Thu, 03 Dec 1992 08:37:20 GMT
ETag: "40521e06-8a9-291e721905000"
Accept-Ranges: bytes
Content-Length: 2217
Connection: close
Content-Type: text/html

“200 OK” on the first line means the server was able to serve our request as expected. The remaining header lines contain other information about the response. Not all header fields are required, but the most important are “Content-Length”, which explains how long the response is (after the headers) and “Content-Type”, which tells us how to interpret the data. As with the request, the response headers end with two newlines (technically "\r\n\r\n") and then Content-Length bytes of response data follow.

The TCP connection is closed at the end of the request. To make another request, you open another TCP connection, send request headers, and wait for a response.

Using a TCP tool like telnet for making HTTP requests is a little unwieldy, so you might use curl instead…

$curl -v http://info.cern.ch/hypertext/WWW/TheProject.html …or just use a web browser. ## Haskell HTTP Server We were able to connect and get a response because over at CERN there’s a computer program running constantly, waiting for TCP connections. When a TCP connection is opened, it listens for an HTTP request on the connection and, if a request is made, formulates and sends a response. If you look at your Lab 7 starter code, you’ll see just such a server implemented in less than 300 lines of Haskell. You should spend some time understanding how it works. ## Your Task The server logs HTTP requests as they come in. To isolate logging, all request log lines are placed into the WriterT monad transformer. When the request is complete, these log lines are transformed by adding a prefix, and then the lines are printed. This server would function perfectly, but it’s missing some code to implement WriterT. Your job is to write the core functions of the WriterT monad transformer. All you have to do is fill in the undefined’s in the Lab7.hs file. After you do so, then compiling and running the lab…$ ghc Lab7.hs && ./Lab7

…should start a webserver that you can access at http://localhost:2222/. Requesting a page should output the expected log lines in the console:

Connection accepted from 127.0.0.1:60156
[127.0.0.1:60156] Requested /ascii_art/quality_controller.html
[127.0.0.1:60156] 200 OK
[127.0.0.1:60156] Connection closed.
Connection accepted from 127.0.0.1:60156
[127.0.0.1:60156] Requested /favicon.ico
[127.0.0.1:60156] Connection closed.
Connection accepted from 127.0.0.1:60156
[127.0.0.1:60156] Connection closed.
Connection accepted from 127.0.0.1:60156
[127.0.0.1:60156] Connection broken.

Corresponding to the following commands executed in another terminal:

$curl http://localhost:2222/ascii_art/quality_controller.html$ curl http://localhost:2222/favicon.ico
$printf "asdf\r\n\r\n" | nc localhost 2222$ echo "asdf" | telnet localhost 2222

You may need some packages.

$cabal install network$ cabal install regex-compat

## Hints

Read the types and think about them! For example, if the signature says some type is Applicative, that pretty much guarantees that you need to use pure or <*> on a value of that type. And these particular types are rich enough that if you manage to get a function to typecheck, there’s a decent (though not assured) chance that you’ve written it correctly.

If you get stuck, take a look at this 2016 monad transformers lecture. If you’re really stuck, understand a canonical implementation of WriterT—but don’t be lazy about “getting it”: regenerate your own solution from memory. As always, cite your sources in comments in your file.

## Submission

Again, the lab is due by 11:59pm Wednesday.