diff options
Diffstat (limited to 'examples/http-server')
| -rw-r--r-- | examples/http-server/CHANGES.md | 5 | ||||
| -rw-r--r-- | examples/http-server/README.md | 8 | ||||
| -rw-r--r-- | examples/http-server/connection-queue.tm | 25 | ||||
| -rw-r--r-- | examples/http-server/http-server.tm | 149 | ||||
| -rw-r--r-- | examples/http-server/modules.ini | 8 | ||||
| -rw-r--r-- | examples/http-server/sample-site/foo.html | 6 | ||||
| -rw-r--r-- | examples/http-server/sample-site/hello.txt | 1 | ||||
| -rw-r--r-- | examples/http-server/sample-site/index.html | 16 | ||||
| -rwxr-xr-x | examples/http-server/sample-site/random.tm | 17 | ||||
| -rw-r--r-- | examples/http-server/sample-site/styles.css | 11 |
10 files changed, 0 insertions, 246 deletions
diff --git a/examples/http-server/CHANGES.md b/examples/http-server/CHANGES.md deleted file mode 100644 index 42ae752c..00000000 --- a/examples/http-server/CHANGES.md +++ /dev/null @@ -1,5 +0,0 @@ -# Version History - -## v1.0 - -Initial version diff --git a/examples/http-server/README.md b/examples/http-server/README.md deleted file mode 100644 index 78c8d793..00000000 --- a/examples/http-server/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# HTTP Server - -This is a simple multithreaded Tomo HTTP server that can be run like this: - -``` -tomo -e http-server.tm -./http-server ./sample-site -``` diff --git a/examples/http-server/connection-queue.tm b/examples/http-server/connection-queue.tm deleted file mode 100644 index c56069e1..00000000 --- a/examples/http-server/connection-queue.tm +++ /dev/null @@ -1,25 +0,0 @@ -use pthreads - -func _assert_success(name:Text, val:Int32; inline) - fail("$name() failed!") if val < 0 - -struct ConnectionQueue(_connections:@[Int32]=@[], _mutex=pthread_mutex_t.new(), _cond=pthread_cond_t.new()) - func enqueue(queue:ConnectionQueue, connection:Int32) - queue._mutex.lock() - queue._connections.insert(connection) - queue._mutex.unlock() - queue._cond.signal() - - - func dequeue(queue:ConnectionQueue -> Int32) - conn : Int32? - - queue._mutex.lock() - - while queue._connections.length == 0 - queue._cond.wait(queue._mutex) - - conn = queue._connections.pop(1) - queue._mutex.unlock() - queue._cond.signal() - return conn! diff --git a/examples/http-server/http-server.tm b/examples/http-server/http-server.tm deleted file mode 100644 index dbe57805..00000000 --- a/examples/http-server/http-server.tm +++ /dev/null @@ -1,149 +0,0 @@ -#!/bin/env tomo - -# This file provides an HTTP server module and standalone executable - -use <stdio.h> -use <stdlib.h> -use <string.h> -use <unistd.h> -use <arpa/inet.h> -use <err.h> - -use commands -use pthreads -use patterns - -use ./connection-queue.tm - -func serve(port:Int32, handler:func(request:HTTPRequest -> HTTPResponse), num_threads=16) - connections := ConnectionQueue() - workers : &[@pthread_t] - for i in num_threads - workers.insert(pthread_t.new(func() - repeat - connection := connections.dequeue() - request_text := C_code:Text``` - Text_t request = EMPTY_TEXT; - char buf[1024] = {}; - for (ssize_t n; (n = read(@connection, buf, sizeof(buf) - 1)) > 0; ) { - buf[n] = 0; - request = Text$concat(request, Text$from_strn(buf, n)); - if (request.length > 1000000 || strstr(buf, "\r\n\r\n")) - break; - } - request - ``` - - request := HTTPRequest.from_text(request_text) or skip - response := handler(request).bytes() - C_code ` - if (@response.stride != 1) - List$compact(&@response, 1); - write(@connection, @response.data, @response.length); - close(@connection); - ` - )) - - - sock := C_code:Int32 ` - int s = socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) err(1, "Couldn't connect to socket!"); - - int opt = 1; - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) - err(1, "Couldn't set socket option"); - - struct sockaddr_in addr = {AF_INET, htons(@port), INADDR_ANY}; - if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) - err(1, "Couldn't bind to socket"); - if (listen(s, 8) < 0) - err(1, "Couldn't listen on socket"); - - s - ` - - repeat - conn := C_code:Int32`accept(@sock, NULL, NULL)` - stop if conn < 0 - connections.enqueue(conn) - - say("Shutting down...") - for w in workers - w.cancel() - -struct HTTPRequest(method:Text, path:Text, version:Text, headers:[Text], body:Text) - func from_text(text:Text -> HTTPRequest?) - m := text.pattern_captures($Pat'{word} {..} HTTP/{..}{crlf}{..}') or return none - method := m[1] - path := m[2].replace_pattern($Pat'{2+ /}', '/') - version := m[3] - rest := m[-1].pattern_captures($Pat'{..}{2 crlf}{0+ ..}') or return none - headers := rest[1].split_pattern($Pat'{crlf}') - body := rest[-1] - return HTTPRequest(method, path, version, headers, body) - -struct HTTPResponse(body:Text, status=200, content_type="text/plain", headers:{Text=Text}={}) - func bytes(r:HTTPResponse -> [Byte]) - body_bytes := r.body.bytes() - extra_headers := (++: "$k: $v\r\n" for k,v in r.headers) or "" - return " - HTTP/1.1 $(r.status) OK\r - Content-Length: $(body_bytes.length + 2)\r - Content-Type: $(r.content_type)\r - Connection: close\r - $extra_headers - \r\n - ".bytes() ++ body_bytes - -func _content_type(file:Path -> Text) - when file.extension() is "html" return "text/html" - is "tm" return "text/html" - is "js" return "text/javascript" - is "css" return "text/css" - else return "text/plain" - -enum RouteEntry(ServeFile(file:Path), Redirect(destination:Text)) - func respond(entry:RouteEntry, request:HTTPRequest -> HTTPResponse) - when entry is ServeFile(file) - body := if file.can_execute() - Command(Text(file)).get_output()! - else - file.read()! - return HTTPResponse(body, content_type=_content_type(file)) - is Redirect(destination) - return HTTPResponse("Found", 302, headers={"Location"=destination}) - -func load_routes(directory:Path -> {Text=RouteEntry}) - routes : &{Text=RouteEntry} - for file in (directory ++ (./*)).glob() - skip unless file.is_file() - contents := file.read() or skip - server_path := "/" ++ "/".join(file.relative_to(directory).components) - if file.base_name() == "index.html" - canonical := server_path.without_suffix("index.html") - routes[server_path] = Redirect(canonical) - routes[canonical] = ServeFile(file) - else if file.extension() == "html" - canonical := server_path.without_suffix(".html") - routes[server_path] = Redirect(canonical) - routes[canonical] = ServeFile(file) - else if file.extension() == "tm" - canonical := server_path.without_suffix(".tm") - routes[server_path] = Redirect(canonical) - routes[canonical] = ServeFile(file) - else - routes[server_path] = ServeFile(file) - return routes[] - -func main(directory:Path, port=Int32(8080)) - say("Serving on port $port") - routes := load_routes(directory) - say("Hosting: $routes") - - serve(port, func(request:HTTPRequest) - if handler := routes[request.path] - return handler.respond(request) - else - return HTTPResponse("Not found!", 404) - ) - diff --git a/examples/http-server/modules.ini b/examples/http-server/modules.ini deleted file mode 100644 index 171e11d2..00000000 --- a/examples/http-server/modules.ini +++ /dev/null @@ -1,8 +0,0 @@ -[pthreads] -version=v1.0 - -[patterns] -version=v1.0 - -[commands] -version=v1.0 diff --git a/examples/http-server/sample-site/foo.html b/examples/http-server/sample-site/foo.html deleted file mode 100644 index 162a7146..00000000 --- a/examples/http-server/sample-site/foo.html +++ /dev/null @@ -1,6 +0,0 @@ -<!DOCTYPE HTML> -<html> - <body> - This is the <b>foo</b> page. - </body> -</html> diff --git a/examples/http-server/sample-site/hello.txt b/examples/http-server/sample-site/hello.txt deleted file mode 100644 index e965047a..00000000 --- a/examples/http-server/sample-site/hello.txt +++ /dev/null @@ -1 +0,0 @@ -Hello diff --git a/examples/http-server/sample-site/index.html b/examples/http-server/sample-site/index.html deleted file mode 100644 index 8e1573bb..00000000 --- a/examples/http-server/sample-site/index.html +++ /dev/null @@ -1,16 +0,0 @@ -<!DOCTYPE HTML> -<html> - <head> - <title>HTTP Example</title> - <link rel="stylesheet" href="styles.css"> - </head> - <body> - <p> - Hello <b>world!</b> - </p> - - <p> - Try going to <a href="/random">/random</a> or <a href="/foo">/foo</a> or <a href="/hello.txt">/hello.txt</a> - </p> - </body> -</html> diff --git a/examples/http-server/sample-site/random.tm b/examples/http-server/sample-site/random.tm deleted file mode 100755 index 153ac2af..00000000 --- a/examples/http-server/sample-site/random.tm +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/env tomo -use random - -func main() - say(" - <!DOCTYPE HTML> - <html> - <head> - <title>Random Number</title> - <link rel="stylesheet" href="styles.css"> - </head> - <body> - <h1>Random Number</h1> - Your random number is: $(random.int(1,100)) - </body> - </html> - ") diff --git a/examples/http-server/sample-site/styles.css b/examples/http-server/sample-site/styles.css deleted file mode 100644 index f15d25de..00000000 --- a/examples/http-server/sample-site/styles.css +++ /dev/null @@ -1,11 +0,0 @@ -body{ - margin:40px auto; - max-width:650px; - line-height:1.6; - font-size:18px; - color:#444; - padding:0 10px; -} -h1,h2,h3{ - line-height:1.2 -} |
