Skip to content

Instantly share code, notes, and snippets.

@teepark
Created February 19, 2011 01:26
Show Gist options
  • Save teepark/834730 to your computer and use it in GitHub Desktop.
Save teepark/834730 to your computer and use it in GitHub Desktop.
a little http server (and hello world app) in io
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