summary refs log tree commit diff stats
path: root/tests/deps/jester-#head/jester.nim
diff options
context:
space:
mode:
Diffstat (limited to 'tests/deps/jester-#head/jester.nim')
-rw-r--r--tests/deps/jester-#head/jester.nim121
1 files changed, 78 insertions, 43 deletions
diff --git a/tests/deps/jester-#head/jester.nim b/tests/deps/jester-#head/jester.nim
index d9db50856..1118214c2 100644
--- a/tests/deps/jester-#head/jester.nim
+++ b/tests/deps/jester-#head/jester.nim
@@ -1,6 +1,6 @@
 # Copyright (C) 2015 Dominik Picheta
 # MIT License - Look at license.txt for details.
-import net, strtabs, re, tables, parseutils, os, strutils, uri,
+import net, strtabs, re, tables, os, strutils, uri,
        times, mimetypes, asyncnet, asyncdispatch, macros, md5,
        logging, httpcore, asyncfile, macrocache, json, options,
        strformat
@@ -23,6 +23,7 @@ export SameSite
 when useHttpBeast:
   import httpbeast except Settings, Request
   import options
+  from nativesockets import close
 else:
   import asynchttpserver except Request
 
@@ -72,14 +73,14 @@ type
     of RouteCode:
       data: ResponseData
 
-const jesterVer = "0.4.0"
+const jesterVer = "0.4.3"
 
 proc toStr(headers: Option[RawHeaders]): string =
   return $newHttpHeaders(headers.get(@({:})))
 
 proc createHeaders(headers: RawHeaders): string =
   result = ""
-  if headers != nil:
+  if headers.len > 0:
     for header in headers:
       let (key, value) = header
       result.add(key & ": " & value & "\c\L")
@@ -98,22 +99,24 @@ proc unsafeSend(request: Request, content: string) =
 
 proc send(
   request: Request, code: HttpCode, headers: Option[RawHeaders], body: string
-) =
+): Future[void] =
   when useHttpBeast:
     let h =
       if headers.isNone: ""
       else: headers.get().createHeaders
     request.getNativeReq.send(code, body, h)
+    var fut = newFuture[void]()
+    complete(fut)
+    return fut
   else:
-    # TODO: This may cause issues if we send too fast.
-    asyncCheck request.getNativeReq.respond(
+    return request.getNativeReq.respond(
       code, body, newHttpHeaders(headers.get(@({:})))
     )
 
 proc statusContent(request: Request, status: HttpCode, content: string,
-                   headers: Option[RawHeaders]) =
+                   headers: Option[RawHeaders]): Future[void] =
   try:
-    send(request, status, headers, content)
+    result = send(request, status, headers, content)
     when not defined(release):
       logging.debug("  $1 $2" % [$status, toStr(headers)])
   except:
@@ -174,7 +177,11 @@ proc sendStaticIfExists(
         return Http403
 
       let fileSize = getFileSize(p)
-      let mimetype = req.settings.mimes.getMimetype(p.splitFile.ext[1 .. ^1])
+      let ext = p.splitFile.ext
+      let mimetype = req.settings.mimes.getMimetype(
+        if ext.len > 0: ext[1 .. ^1]
+        else: ""
+      )
       if fileSize < 10_000_000: # 10 mb
         var file = readFile(p)
 
@@ -183,18 +190,18 @@ proc sendStaticIfExists(
         # If the user has a cached version of this file and it matches our
         # version, let them use it
         if req.headers.hasKey("If-None-Match") and req.headers["If-None-Match"] == hashed:
-          req.statusContent(Http304, "", none[RawHeaders]())
+          await req.statusContent(Http304, "", none[RawHeaders]())
         else:
-          req.statusContent(Http200, file, some(@({
-                              "Content-Type": mimetype,
-                              "ETag": hashed
-                            })))
+          await req.statusContent(Http200, file, some(@({
+            "Content-Type": mimetype,
+            "ETag": hashed
+          })))
       else:
         let headers = @({
           "Content-Type": mimetype,
           "Content-Length": $fileSize
         })
-        req.statusContent(Http200, "", some(headers))
+        await req.statusContent(Http200, "", some(headers))
 
         var fileStream = newFutureStream[string]("sendStaticIfExists")
         var file = openAsync(p, fmRead)
@@ -216,13 +223,22 @@ proc sendStaticIfExists(
   # If we get to here then no match could be found.
   return Http404
 
+proc close*(request: Request) =
+  ## Closes client socket connection.
+  ##
+  ## Routes using this procedure must enable raw mode.
+  let nativeReq = request.getNativeReq()
+  when useHttpBeast:
+    nativeReq.forget()
+  nativeReq.client.close()
+
 proc defaultErrorFilter(error: RouteError): ResponseData =
   case error.kind
   of RouteException:
     let e = error.exc
     let traceback = getStackTrace(e)
     var errorMsg = e.msg
-    if errorMsg.isNil: errorMsg = "(nil)"
+    if errorMsg.len == 0: errorMsg = "(empty)"
 
     let error = traceback & errorMsg
     logging.error(error)
@@ -295,9 +311,11 @@ proc handleFileRequest(
     jes.settings.staticDir / cgi.decodeUrl(req.pathInfo)
   )
 
-  # Verify that this isn't outside our static` dir.
+  # Verify that this isn't outside our static dir.
   var status = Http400
-  if path.splitFile.dir.startsWith(jes.settings.staticDir):
+  let pathDir = path.splitFile.dir / ""
+  let staticDir = jes.settings.staticDir / ""
+  if pathDir.startsWith(staticDir):
     if existsDir(path):
       status = await sendStaticIfExists(
         req,
@@ -347,7 +365,7 @@ proc handleRequestSlow(
         not dispatchedError and respData.content.len == 0:
       respData = await dispatchError(jes, req, initRouteError(respData))
 
-    statusContent(
+    await statusContent(
       req,
       respData.code,
       respData.content,
@@ -368,7 +386,7 @@ proc handleRequest(jes: Jester, httpReq: NativeRequest): Future[void] =
     if likely(jes.matchers.len == 1 and not jes.matchers[0].async):
       let respData = jes.matchers[0].syncProc(req)
       if likely(respData.matched):
-        statusContent(
+        return statusContent(
           req,
           respData.code,
           respData.content,
@@ -383,6 +401,8 @@ proc handleRequest(jes: Jester, httpReq: NativeRequest): Future[void] =
     let respDataFut = dispatchError(jes, req, initRouteError(exc))
     return handleRequestSlow(jes, req, respDataFut, true)
 
+  assert(not result.isNil, "Expected handleRequest to return a valid future.")
+
 proc newSettings*(
   port = Port(5000), staticDir = getCurrentDir() / "public",
   appName = "", bindAddr = "", reusePort = false,
@@ -461,14 +481,19 @@ proc serve*(
       ]
     )
   else:
-    logging.info("Jester is making jokes at http://0.0.0.0:$1$2" %
-                 [$self.settings.port, self.settings.appName])
+    when defined(windows):
+      logging.info("Jester is making jokes at http://127.0.0.1:$1$2 (all interfaces)" %
+                   [$self.settings.port, self.settings.appName])
+    else:
+      logging.info("Jester is making jokes at http://0.0.0.0:$1$2" %
+                   [$self.settings.port, self.settings.appName])
 
   var jes = self
   when useHttpBeast:
     run(
       proc (req: httpbeast.Request): Future[void] =
-        result = handleRequest(jes, req),
+         {.gcsafe.}:
+          result = handleRequest(jes, req),
       httpbeast.initSettings(self.settings.port, self.settings.bindAddr)
     )
   else:
@@ -484,14 +509,6 @@ proc serve*(
       asyncCheck serveFut
     runForever()
 
-template resp*(code: HttpCode,
-               headers: openarray[tuple[key, value: string]],
-               content: string): typed =
-  ## Sets ``(code, headers, content)`` as the response.
-  bind TCActionSend, newHttpHeaders
-  result = (TCActionSend, code, headers.newHttpHeaders.some(), content, true)
-  break route
-
 template setHeader(headers: var Option[RawHeaders], key, value: string): typed =
   bind isNone
   if isNone(headers):
@@ -509,6 +526,17 @@ template setHeader(headers: var Option[RawHeaders], key, value: string): typed =
       # Add key if it doesn't exist.
       headers = some(h & @({key: value}))
 
+template resp*(code: HttpCode,
+               headers: openarray[tuple[key, val: string]],
+               content: string): typed =
+  ## Sets ``(code, headers, content)`` as the response.
+  bind TCActionSend
+  result = (TCActionSend, code, none[RawHeaders](), content, true)
+  for header in headers:
+    setHeader(result[2], header[0], header[1])
+  break route
+
+
 template resp*(content: string, contentType = "text/html;charset=utf-8"): typed =
   ## Sets ``content`` as the response; ``Http200`` as the status code
   ## and ``contentType`` as the Content-Type.
@@ -687,7 +715,8 @@ proc daysForward*(days: int): DateTime =
   return getTime().utc + initTimeInterval(days = days)
 
 template setCookie*(name, value: string, expires="",
-                    sameSite: SameSite=Lax): typed =
+                    sameSite: SameSite=Lax, secure = false,
+                    httpOnly = false, domain = "", path = "") =
   ## Creates a cookie which stores ``value`` under ``name``.
   ##
   ## The SameSite argument determines the level of CSRF protection that
@@ -695,7 +724,7 @@ template setCookie*(name, value: string, expires="",
   ## should protect you from most vulnerabilities. Note that this is only
   ## supported by some browsers:
   ## https://caniuse.com/#feat=same-site-cookie-attribute
-  let newCookie = makeCookie(name, value, expires)
+  let newCookie = makeCookie(name, value, expires, domain, path, secure, httpOnly, sameSite)
   if isSome(result[2]) and
      (let headers = result[2].get(); headers.toTable.hasKey("Set-Cookie")):
     result[2] = some(headers & @({"Set-Cookie": newCookie}))
@@ -703,9 +732,12 @@ template setCookie*(name, value: string, expires="",
     setHeader(result[2], "Set-Cookie", newCookie)
 
 template setCookie*(name, value: string, expires: DateTime,
-                    sameSite: SameSite=Lax): typed =
+                    sameSite: SameSite=Lax, secure = false,
+                    httpOnly = false, domain = "", path = "") =
   ## Creates a cookie which stores ``value`` under ``name``.
-  setCookie(name, value, format(expires, "ddd',' dd MMM yyyy HH:mm:ss 'GMT'"))
+  setCookie(name, value,
+            format(expires.utc, "ddd',' dd MMM yyyy HH:mm:ss 'GMT'"),
+            sameSite, secure, httpOnly, domain, path)
 
 proc normalizeUri*(uri: string): string =
   ## Remove any trailing ``/``.
@@ -721,7 +753,10 @@ proc checkAction*(respData: var ResponseData): bool =
   of TCActionPass:
     result = false
   of TCActionNothing:
-    assert(false)
+    raise newException(
+      ValueError,
+      "Missing route action, did you forget to use `resp` in your route?"
+    )
 
 proc skipDo(node: NimNode): NimNode {.compiletime.} =
   if node.kind == nnkDo:
@@ -764,14 +799,14 @@ proc ctParsePattern(pattern, pathPrefix: string): NimNode {.compiletime.} =
       newStrLitNode(node.text),
       newIdentNode(if node.optional: "true" else: "false"))
 
-template setDefaultResp*(): typed =
+template setDefaultResp*() =
   # TODO: bindSym this in the 'routes' macro and put it in each route
   bind TCActionNothing, newHttpHeaders
   result.action = TCActionNothing
   result.code = Http200
   result.content = ""
 
-template declareSettings(): typed {.dirty.} =
+template declareSettings() {.dirty.} =
   when not declaredInScope(settings):
     var settings = newSettings()
 
@@ -1299,7 +1334,7 @@ proc routesEx(name: string, body: NimNode): NimNode =
     for branch in exceptionBranches:
       stmts.add(newIfStmt(branch))
     errorHandlerProc[6][0][1][^1][1][1][0] = stmts
-  if httpCodeBranches.len > 1:
+  if httpCodeBranches.len != 0:
     var stmts = newStmtList()
     for branch in httpCodeBranches:
       stmts.add(newIfStmt(branch))
@@ -1313,7 +1348,7 @@ proc routesEx(name: string, body: NimNode): NimNode =
   # echo toStrLit(result)
   # echo treeRepr(result)
 
-macro routes*(body: untyped): typed =
+macro routes*(body: untyped) =
   result = routesEx("match", body)
   let jesIdent = genSym(nskVar, "jes")
   let matchIdent = newIdentNode("match")
@@ -1329,13 +1364,13 @@ macro routes*(body: untyped): typed =
       serve(`jesIdent`)
   )
 
-macro router*(name: untyped, body: untyped): typed =
+macro router*(name: untyped, body: untyped) =
   if name.kind != nnkIdent:
     error("Need an ident.", name)
 
-  routesEx($name.ident, body)
+  routesEx(strVal(name), body)
 
-macro settings*(body: untyped): typed =
+macro settings*(body: untyped) =
   #echo(treeRepr(body))
   expectKind(body, nnkStmtList)