1 Goal
2 Server Requests
3 Encoding
3.1 Encoding running programs as continuations
4 Encoding status
5 Threading
6 HANDIN
7 Partners
8 Suggested Development Steps
9 Sample Code

Assignment 7, CSC430, Winter 2012

1 Goal

The goal of this assignment is to write a simple web server that can run programs, and can inform users about what’s going on.

More specifically, your servers must evaluate programs written in the Froggy language–no, there’s no good reason for the name that I can think of–which consists of the following forms:

You’ll notice that none of these expressions evaluate to a value; that’s okay. Also, it’s a very very simple language; it can’t run forever, and it can’t really compute anything. In fact, adding those features—arithmetic, control flow, etc.—wouldn’t really be very conceptually challenging, but they would add bulk and time to the implementation.

2 Server Requests

Your servers must listen on a particular port—we’ll agree on these ports later—for three kinds of requests, formatted as standard http requests.

3 Encoding

3.1 Encoding running programs as continuations

Passing a continuation/program to a new server requires encoding it as a stream of bytes in a POST request.

We’ll be using JSON to encode these values–it’s a *very* common exchange format, and you should be able to find a JSON package for nearly any environment.

In a run request, the byte string associated with the POST request should be a single JSON-encoded string, represented using utf-8, with this format:

{name:<programname>,mood:<programmood>,kont:<programkont>}

... where <programname> and <programmood> are strings, and <programkont> is another JSON-encoded value, following this template:

<programkont> = {ty:"base-k",args:[]}

              | {ty:"loop-k",args:[<number>,<exp>,<programkont>]}

              | {ty:"seq-k",args:[[<exp>,...],<programkont>]}

... where <number> is a number, [<exp>,...] is a comma-separated array of <exp>s, and an exp is another JSON-encoded value, following this template:

<exp> = {ty:"sleep",args:[<number>]}

      | {ty:"set-mood",args:[<string>]}

      | {ty:"loop",args:[<number>,<exp>]}

      | {ty:"goto",args:[<string>,<number>]}

      | {ty:"seq",args:[<exp>,...]}

... with the same conventions as above, and where <string> is a string.

As an example, Here’s an example of a POST bytestring:

{"name": "Wilhelm", "kont": {"args": [14, {"args": [{"args": ["confused!"], "ty": "set-mood"}, {"args": [3.2], "ty": "sleep"}], "ty": "seq"}, {"args": [], "ty": "base-k"}], "ty": "loop-k"}, "mood": "AIIEEE!"}

Note that standard JSON rules apply: whitespace is unimportant outside of strings, and the order of fields within curly braces is also unimportant.

This byte string represents a program called "Wilhelm" that will loop 14 more times, each time changing its mood to "Confused!" and then sleeping for 3.2 seconds.

Here’s another one:

{"name": "Columbus", "kont": {"args": [[{"args": [1492], "ty": "sleep"}, {"args": ["new-world.org", 8829], "ty": "goto"}], {"args": [], "ty": "base-k"}], "ty": "seq-k"}, "mood": "leaving for America"}

This one represents a program called "Columbus" that will wait 1492 seconds, then move itself to the server running on port 8829 at "new-world.org".

4 Encoding status

In response to a json-status.html request, your server must respond with a list of the programs running on the server, and their moods. This should be encoded as a list of JSON objects where each one has a name and mood field. The response should be given the application/json MIME type. So, a status request to a server might result in this:

[{"name": "MyProgram","mood": "sulky"},{"name":"Dr. Chipper","mood":"relentlessly optimistic"}]

5 Threading

Your life will be much simpler if you choose an environment with support for threading, and if you use it to run each program on its own thread.

6 HANDIN

Handin has two parts: you must leave your server running over the weekend, and you must hand in a bundle (.tar or .zip) containing your code.

Submit your code by visiting the URL

https://brinckerhoff.org:7980

... and signing in.

Note that this site uses a self-signed certificate with SHA1 fingerprint

20:F1:42:B4:5E:6B:B9:5A:7D:AC:1A:F0:67:E3:D0:4C:E7:63:88:8E

... so you’ll probably have to confirm a security exception.

Include in your bundle all of the code that you wrote, but don’t include any library or framework code; my goal is to read your code, not to run it. Be sure to include a TEAM file that tells whom you worked with. A README file indicating what each file contains would also be helpful.

7 Partners

On this assignment, you may work with any partner that you like (in the class, of course).

8 Suggested Development Steps

Trying to tackle this project all at once will probably get you in trouble. I would suggest following these incremental steps:

9 Sample Code

Here’s a small Racket program that starts a server on a given port that just echoes the text of the POST request back:

#lang racket
 
(require web-server/servlet-env
         web-server/http/xexpr
         web-server/http)
 
; the function that handles requests:
(define (start request)
  (define post-bytes (request-post-data/raw
                      request))
  (response/xexpr `(html (p "raw POST bytes:")
                         (pre ,(format "~a" post-bytes)))))
 
; start serving the 'start' function on port 8054:
(serve/servlet start
               #:servlet-regexp #px".*"
               #:port 8054
               #:launch-browser? #f
               #:listen-ip #f)

Here’s a small racket program that sends a POST request to a server, and gathers the response bytes:

#lang racket
 
(require net/url
         (planet dherman/json))
 
; ping the server
 
; the URL to send the request to:
(define local-url (string->url "http://localhost:8054/ping.html"))
 
; the byte-string to attach as the POST bytes:
(define post-bytes (string->bytes/utf-8
                    (jsexpr->json (hash "a" 134
                                        "z" (list 4 5)))))
 
; make the request, receiving the port for the response:
(define response-port (post-pure-port local-url post-bytes))
 
; suck all of the characters out of the port:
(regexp-match #px".*" response-port)