Permalink
Browse files

Improved pattern parsing. Added better halt().

  • Loading branch information...
1 parent b706c75 commit 275837f0606e203f5207473402127078ec4ab4b2 @dom96 committed May 4, 2012
Showing with 191 additions and 104 deletions.
  1. +83 −20 jester.nim
  2. +108 −84 patterns.nim
View
@@ -1,16 +1,21 @@
-import httpserver, sockets, strtabs, re, htmlgen, tables, parseutils
+import httpserver, sockets, strtabs, re, htmlgen, tables, parseutils, os
import patterns, errorpages
from cgi import decodeData, ECgi
type
- TCallbackRet = tuple[code: THttpCode, headers: PStringTable, content: string]
+ TCallbackRet = tuple[action: TCallbackAction, code: THttpCode,
+ headers: PStringTable, content: string]
TCallback = proc (request: TRequest): TCallbackRet
TJester = object
s: TServer
routes*: seq[tuple[m: PMatch, c: TCallback]]
+ options: TOptions
+
+ TOptions = object
+ staticDir: string # By default ./public
TRegexMatch = tuple[compiled: TRegex, original: string]
@@ -35,10 +40,17 @@ type
Http404 = "404 Not Found",
Http502 = "502 Bad Gateway"
+ TCallbackAction = enum
+ TCActionSend, TCActionPass, TCActionHalt
+
const jesterVer = "0.1.0"
+proc initOptions(j: var TJester) =
+ j.options.staticDir = getAppDir() / "public"
+
var j: TJester
j.routes = @[]
+j.initOptions()
when not defined(writeStatusContent):
proc writeStatusContent(c: TSocket, status, content: string, headers: PStringTable) =
@@ -61,8 +73,18 @@ proc handleHTTPRequest(client: TSocket, path, query: string) =
echo("[Warning] Incorrect query. Got: ", query)
template routeReq(): stmt =
- let (code, headers, content) = route.c(req)
- client.writeStatusContent($code, content, headers)
+ let (action, code, headers, content) = route.c(req)
+ case action
+ of TCActionSend:
+ client.writeStatusContent($code, content, headers)
+ matched = true
+ break
+ of TCActionPass:
+ matched = false
+ of TCActionHalt:
+ matched = true
+ client.writeStatusContent($code, content, headers)
+ break
var matched = false
var req: TRequest
@@ -74,20 +96,26 @@ proc handleHTTPRequest(client: TSocket, path, query: string) =
if path =~ route.m.regexMatch.compiled:
req.matches = matches
routeReq()
- matched = true
- break
+
of MSpecial:
let (match, params) = route.m.pattern.match(path)
#echo(path, " =@ ", route.m.pattern, " | ", match, " ", params)
if match:
for key, val in params:
req.params[key] = val
routeReq()
- matched = true
- break
+
if not matched:
- client.writeStatusContent($Http404, error($Http404, jesterVer),
- {"Content-type": "text/html"}.newStringTable)
+ # Find static file.
+ # TODO: Caching.
+ if existsFile(j.options.staticDir / path):
+ var file = readFile(j.options.staticDir / path)
+ # TODO: Mimetypes
+ client.writeStatusContent($Http200, file,
+ {"Content-type": "text/plain"}.newStringTable)
+ else:
+ client.writeStatusContent($Http404, error($Http404, jesterVer),
+ {"Content-type": "text/html"}.newStringTable)
client.close()
@@ -103,8 +131,8 @@ proc regex*(s: string, flags = {reExtended, reStudy}): TRegexMatch =
result = (re(s, flags), s)
template setDefaultResp(): stmt =
- bind error, jesterVer
- result = (Http502, {"Content-Type": "text/html"}.newStringTable,
+ bind error, jesterVer, TCActionSend
+ result = (TCActionSend, Http502, {"Content-Type": "text/html"}.newStringTable,
error($Http502, jesterVer))
template get*(path: string, body: stmt): stmt =
@@ -120,29 +148,64 @@ template get*(path: string, body: stmt): stmt =
setDefaultResp()
body)))
-template getRe*(path: TRegexMatch, body: stmt): stmt =
+template getRe*(rePath: TRegexMatch, body: stmt): stmt =
block:
bind j, PMatch, TRequest, TCallbackRet, setDefaultResp
var match: PMatch
new(match)
match.typ = MRegex
- match.regexMatch = path
+ match.regexMatch = rePath
j.routes.add((match, (proc (request: TRequest): TCallbackRet =
setDefaultResp()
body)))
-template resp*(v: tuple[code: THttpCode,
- headers: openarray[tuple[key, value: string]],
- content: string]): stmt =
- return (v[0], v[1].newStringTable, v[2])
+template resp*(code: THttpCode,
+ headers: openarray[tuple[key, value: string]],
+ content: string): stmt =
+ return (TCActionSend, v[0], v[1].newStringTable, v[2])
template resp*(content: string): stmt =
## Responds
- return (Http200, {"Content-Type": "text/html"}.newStringTable, content)
+ bind TCActionSend
+ return (TCActionSend, Http200,
+ {"Content-Type": "text/html"}.newStringTable, content)
+
+template pass*(): stmt =
+ bind TCActionPass
+ return (TCActionPass, Http404, nil, "")
+
+template halt*(code: THttpCode,
+ headers: openarray[tuple[key, value: string]],
+ content: string): stmt =
+ bind TCActionHalt
+ return (TCActionHalt, code, headers.newStringTable, content)
+
+template halt*(): stmt =
+ bind error, jesterVer
+ halt(Http404, {:}, error($Http404, jesterVer))
+
+template halt*(code: THttpCode): stmt =
+ bind error, jesterVer
+ halt(code, {:}, error($code, jesterVer))
+
+template halt*(content: string): stmt =
+ halt(Http404, {:}, content)
+
+template halt*(code: THttpCode, content: string): stmt =
+ halt(code, {:}, content)
template `@`*(s: string): expr =
## Retrieves the parameter ``s`` from ``request.params``. ``""`` will be
## returned if parameter doesn't exist.
request.params[s]
-
+proc `staticDir=`*(dir: string) =
+ ## Sets the directory in which Jester will look for static files. It is
+ ## ``./public`` by default.
+ ##
+ ## The files will be served like so:
+ ##
+ ## ./public/css/style.css -> http://example.com/css/style.css
+ ##
+ ## (``./public`` is not included in the final URL)
+ j.options.staticDir = dir
Oops, something went wrong.

0 comments on commit 275837f

Please sign in to comment.