Created
February 19, 2011 01:26
-
-
Save teepark/834730 to your computer and use it in GitHub Desktop.
a little http server (and hello world app) in io
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
HttpServer := Object clone do( | |
at := method(address, | |
server := self clone | |
address = address splitN(":", 1) | |
ip := address at(0) | |
port := if(address size > 1, address at(1) asNumber, 80); | |
if (ip at(0) > 57 or ip at(0) < 48, | |
ip = DNSResolver ipForHostName(ip) | |
) | |
server socket := Socket clone | |
server socket setIpAddress(IPAddress clone setIp(ip) setPort(port)) | |
server socket setReadTimeout(60 * 60 * 24 * 365) | |
server | |
) | |
run := method( | |
socket serverOpen returnIfError | |
while(true, | |
client_sock := socket serverWaitForConnection | |
if (client_sock isError, continue) | |
HttpConnection with(self, client_sock) @handleRequests | |
) | |
) | |
handle := method(request, | |
Exception raise("override me") | |
) | |
) | |
HttpConnection := Object clone do( | |
with := method(server, sock, | |
conn := self clone | |
conn socket := sock | |
conn server := server | |
conn | |
) | |
handleRequests := method( | |
while (self socket isOpen and handleOneRequest, true) | |
) | |
readRequestLine := method( | |
request := Object clone | |
line := readLine | |
if (line asMutable strip size == 0, | |
line = readLine | |
) | |
data := line splitNoEmpties(" ") | |
if (data size != 3, return nil) | |
if (data at(2) beginsWithSeq("HTTP/") not, return nil) | |
request method := data at(0) | |
path_qs := data at(1) splitN("?", 1) | |
request path := path_qs at(0) | |
request queryString := path_qs at(1) | |
request httpVersion := data at(2) exSlice(5) asNumber | |
request | |
) | |
readHeaders := method( | |
headers := Map clone | |
while (true, | |
chunk := readLine | |
if (chunk size == 0, break) | |
chunk = chunk splitN(":", 1) | |
headers atPut(chunk at(0) asLowercase, chunk) | |
) | |
headers | |
) | |
readBody := method(bytes, | |
self socket readBytes(bytes) | |
) | |
handleOneRequest := method( | |
request := readRequestLine | |
if (request isNil, | |
return false | |
) | |
request headers := readHeaders | |
if (request headers hasKey("content-length") \ | |
and list("POST", "PUT") contains(request method), | |
request body := readBody( | |
request headers at("content-length") at(1) asNumber) | |
) | |
response := self server handle(request) | |
if (response headers detect(k, k asLowercase == "content-length") not, | |
response headers atPut("Content-Length", response body size asString) | |
) | |
response headers = response headers map(k, v, "#{k}: #{v}" interpolate) join("\n") | |
self socket write("""HTTP/1.1 #{code} #{status} | |
#{headers} | |
#{body}""" interpolate(response) asMutable replaceSeq("\n", "\r\n")) | |
true | |
) | |
readLine := method( | |
text := socket readUntilSeq("\n") | |
if (text endsWithSeq("\r"), | |
text exSlice(0, -1) | |
, | |
text | |
) | |
) | |
) | |
if (Sequence hasSlot("splitN") not, | |
Sequence splitN := method(sep, n, | |
size := sep size | |
data := clone | |
result := list() | |
for (i, 1, n, | |
index := data findSeq(sep) | |
if (index isNil not, | |
result append(data exSlice(0, index)) | |
data = data exSlice(index + size) | |
) | |
) | |
result append(data) | |
) | |
) | |
// example hello world application | |
HttpServer at("127.0.0.1:8010") do( | |
handle := method(request, | |
Object clone do( | |
code := 200 | |
status := "OK" | |
headers := Map clone atPut("Content-Type", "text/plain") | |
body := "hello, world" | |
) | |
) | |
) run |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment