Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial checkin

  • Loading branch information...
commit 927689a9084b980a88fa0bf93320cdb99aad16fd 0 parents
_why authored
13 samples/simple.io
@@ -0,0 +1,13 @@
+//
+// The most trivial Yown app
+//
+doRelativeFile("../yown.io")
+
+YownSimple := Yown clone do(
+ get("/test",
+ html(
+ title("Hello??")
+ h1("THIS IS A TEST")
+ )
+ )
+) run
51 yown.io
@@ -0,0 +1,51 @@
+//
+// Yown
+// a little web doodad for Io
+//
+
+doRelativeFile("yown/splitlines.io")
+
+Yown := Object clone do(
+
+ list("builder", "splitlines", "webrequest", "webserver") foreach(lib,
+ doRelativeFile("yown/" .. lib .. ".io"))
+
+ //
+ // The `get`, `put`, etc.
+ // (Incoming action handlers)
+ //
+ handlers := Map clone
+ list("get", "post", "put", "delete") foreach(action,
+ handlers atPut(action, List clone)
+ setSlot(action,
+ method(url, addHandler(call message name, url, call message argAt(1)))
+ )
+ )
+
+ addHandler := method(action, url, block,
+ handlers at(action) append(list("^#{url}$" interpolate asRegex, block))
+ )
+
+ handleRequest := method(req,
+ match := handlers at(req command asLowercase) detect(l,
+ req queryPath matchesRegex(l at(0))
+ )
+ if (match,
+ doMessage(match at(1)),
+ "404 NOT FOUND")
+ )
+
+ //
+ // Starts the builtin server
+ //
+ run := method(
+ WebServer run(self)
+ )
+
+ //
+ // Main HTML method
+ //
+ html := method(
+ Builder doMessage(call message)
+ )
+)
27 yown/builder.io
@@ -0,0 +1,27 @@
+//
+// Yown Builder
+// html construction kit
+//
+Builder := Object clone
+Builder tag := method(name, nodes,
+ inner := ""
+ attrs := name split(".")
+ if (attrs size > 1,
+ name := attrs at(0)
+ attrs := " class='" .. attrs slice(1) join(" ") .. "'",
+ attrs := ""
+ )
+ while(nodes,
+ if(nodes name != ";",
+ inner = inner .. if(nodes argCount > 0,
+ tag(nodes name, nodes argAt(0)),
+ doMessage(nodes))
+ )
+ nodes = nodes next
+ )
+ "<#{name}#{attrs}>#{inner}</#{name}>" interpolate
+)
+
+Builder forward := method(
+ tag(call message name, call message argAt(0))
+)
45 yown/splitlines.io
@@ -0,0 +1,45 @@
+//
+// Stolen from the Io Socket addon
+// used by the web server objects
+//
+Sequence hasSlot("splitLines") ifFalse(
+ Sequence splitLines := method(
+ lineStart := 0
+ resultList := List clone
+
+ nextCrIndex := nil
+ nextLfIndex := nil
+
+ while(lineStart < size,
+ nextCrIndex = findSeq("\r", lineStart)
+ nextLfIndex = findSeq("\n", lineStart)
+
+ if(nextCrIndex and nextLfIndex,
+ if(nextCrIndex < nextLfIndex,
+ nextLfIndex = nil,
+ nextCrIndex = nil
+ )
+ )
+
+ if(nextCrIndex,
+ resultList append(slice(lineStart, nextCrIndex))
+ if(at(nextCrIndex + 1) == 10,
+ lineStart = nextCrIndex + 2
+ ,
+ lineStart = nextCrIndex + 1
+ )
+ ,
+ if(nextLfIndex,
+ resultList append(slice(lineStart, nextLfIndex))
+ lineStart = nextLfIndex + 1
+ ,
+ break
+ )
+ )
+ )
+
+ resultList append(slice(lineStart, size))
+
+ return resultList
+ )
+)
252 yown/webrequest.io
@@ -0,0 +1,252 @@
+//
+// Stolen from the Io Socket addon
+// the web request object
+//
+// Use:
+// req command -> the action
+// req queryPath -> the full path
+// req queryArgs -> Map of query vars
+//
+WebRequest := Object clone do(
+ lineMode := 1
+
+ mandatorySpacePattern := "[ \t]+"
+ optionalSpacePattern := "[ \t]*"
+ tokenPattern := "([^\\x00-\\x1F\\x7F()<>@.;:\\\\\"/[\\]?={} \t]+)"
+ quotedPattern := "\"((?:\\\\\"|[^\"])+\)\""
+
+ headerPattern := "^" .. tokenPattern .. optionalSpacePattern .. ":" .. optionalSpacePattern .. "(.*)$"
+ commandPattern := "^" .. tokenPattern .. mandatorySpacePattern .. "(.*)$"
+ pairPattern := "^" .. optionalSpacePattern .. tokenPattern .. optionalSpacePattern .. "=" .. optionalSpacePattern .. "(?:" .. tokenPattern .. "|" .. quotedPattern .. ")(?:;(.*))?$"
+ queryPattern := "^([^?]*).(.*)$"
+
+ headerRegex := Regex clone with(headerPattern)
+ commandRegex := Regex clone with(commandPattern)
+ pairRegex := Regex clone with(pairPattern)
+ queryRegex := Regex clone with(queryPattern)
+
+ init := method(
+ self sentCookies := Map clone
+ )
+
+ lineBuffer := method(
+ self lineBuffer := Sequence clone
+ )
+
+ rawHeaders := method(
+ self rawHeaders := List clone
+ )
+
+ headers := method(
+ self headers := Map clone
+ self rawHeaders foreach(v,
+ self headers atPut(v at(0) asString, v at(1) asString)
+ )
+ return self headers
+ )
+
+ sentBuffer := method(
+ self sentBuffer := Sequence clone
+ )
+
+ queryArgs := method(
+ self parseQuery; return queryArgs
+ )
+
+ queryPath := method(
+ self parseQuery; return queryPath
+ )
+
+ queryCookies := method(
+ self parseQueryCookies; return queryCookies
+ )
+
+ handleSocket := method(aSocket,
+ self mySocket := aSocket
+
+ while(self mySocket isOpen,
+ if(self mySocket streamReadNextChunk,
+ input := self mySocket readBuffer
+ // writeln(input)
+ self handleInput(input)
+ )
+ )
+ )
+
+ handleInput := method(readBuffer,
+ if(lineMode,
+ lineBuffer appendSeq(readBuffer)
+ readBuffer empty
+
+ readLines := lineBuffer asString splitLines
+
+ rest := readLines pop
+
+ readLines foreach(line, self currentParser(line))
+
+ if(lineMode,
+ self lineBuffer := rest asBuffer,
+ self currentParser(rest asString)
+ )
+ ,
+ self lineBuffer appendSeq(readBuffer)
+ self currentParser(readBuffer asString)
+ )
+ )
+
+ handleRequest := method(request,
+ self sendResponse (200, "OK")
+ self sendHeader ("Content-type", "text/HTML")
+ self endHeaders ()
+ self close
+ )
+
+
+ currentParser := method(line,
+ self chainParser("commandParser", line)
+ )
+
+ chainParser := method(parserName, line,
+ self currentParser := self getSlot(parserName)
+ self currentParser(line)
+ )
+
+ commandParser := method(line,
+ match := line matchesOfRegex(self commandRegex) all first
+ if(match,
+ command := match
+ self command := command at(1)
+ self arguments := command at(2) splitNoEmpties(" ")
+ ,
+ self chainParser("headerParser", line)
+ )
+ )
+
+ headerParser := method(line,
+ match := line matchesOfRegex(self headerRegex) all first
+ if(match,
+ header := match
+ self rawHeaders append(
+ List clone append(header at(1), header at(2))
+ )
+ ,
+ self chainParser("completeParser", line)
+ )
+ )
+
+ completeParser := method(line,
+ if(line size == 0,
+ self determineCommand,
+ Lobby write(
+ "Server does not understand http command: '",
+ line, "'\n"
+ )
+ )
+ )
+
+ determineCommand := method(
+ if(command == "GET",
+ self handleRequest(self)
+ ,
+ if(command == "POST",
+ self lineBuffer empty
+ self currentParser := self getSlot("formParser")
+ self contentLength := self headers at(
+ "Content-Length"
+ )
+ self lineMode = nil
+ )
+ )
+ )
+
+ formParser := method(data,
+ lineBuffer appendSeq(data)
+ if(lineBuffer size >= contentLength,
+ self queryPath := self arguments at(0)
+ self queryArgs := CGI parseString(
+ lineBuffer asString
+ )
+ self handleRequest(self)
+ lineBuffer empty
+ )
+ )
+
+ parseQuery := method(
+ // This method is invoked lazily by queryPath and queryArgs
+ query := self arguments at(0) asString
+ if(query findSeq("?"),
+ match := query matchesOfRegex(self queryRegex) all first
+ self queryPath := match at(1)
+
+ self queryArgs := CGI parseString(
+ match at(2)
+ )
+ ,
+ self queryPath := query
+ self queryArgs := Map clone
+ )
+ )
+
+ parseQueryCookies := method(
+ cookieHeader := self headers at("Cookie")
+
+ self queryCookies := Map clone
+
+ loop(
+ cookieHeader ifNil(return)
+ results := cookieHeader matchesOfRegex(pairRegex) all first
+ results ifNil(return)
+
+ if(results at(2) == "",
+ self queryCookies atPut(
+ results at(1), results at(3)
+ )
+ ,
+ self queryCookies atPut(
+ results at(1), results at(2)
+ )
+ )
+ cookieHeader := results at(4)
+ )
+ )
+ sendCookie := method(key, value,
+ sentCookies atPut(key, value)
+ )
+ sendList := method(data,
+ data foreach(v, self sentBuffer appendSeq(v))
+ )
+ send := method(
+ sendList(call message argsEvaluatedIn(call sender))
+ )
+ sendHeader := method(key, value,
+ self send(key, ": ", value, "\r\n")
+ )
+ endHeaders := method(
+ self send("\r\n")
+ )
+ sendResponse := method(code, message,
+ self responseCode := code
+ self responseMessage := message
+ )
+ flush := method(
+ self removeSlot("sentBuffer")
+ )
+ done := method(
+ self mySocket streamWrite(
+ "HTTP/1.1 " .. self responseCode asString .. " " ..
+ self responseMessage .. "\r\n"
+ )
+ self sentCookies foreach(key, value,
+ self mySocket streamWrite(
+ "Set-cookie: " .. key .. "=" .. value .. "\r\n"
+ )
+ )
+ self mySocket streamWrite(sentBuffer asString)
+ // writeln(sentBuffer asString) // debug
+ self flush
+ )
+ close := method(
+ self hasSlot("sentBuffer") ifTrue(self done)
+ self mySocket close
+ )
+)
30 yown/webserver.io
@@ -0,0 +1,30 @@
+//
+// Yown WebServer
+// starts on port 8010
+//
+// The Socket stuff has been pretty unstable in Io, so be
+// sure you're running the latest pull. Or step back a few
+// days maybe?
+//
+MyHandler := WebRequest clone do(
+ handleRequest := method(request,
+ self sendResponse (200, "OK")
+ self sendHeader ("Content-type", "text/HTML")
+ self endHeaders ()
+ self send(app handleRequest(request))
+ self close
+ )
+)
+
+WebServer := Server clone do(
+ setPort(8010)
+ handleSocket := method(aSocket,
+ handler := Yown MyHandler clone
+ handler app := app
+ handler @handleSocket(aSocket)
+ )
+ run := method(app,
+ self setSlot("app", app)
+ start
+ )
+)
Please sign in to comment.
Something went wrong with that request. Please try again.