mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-20 06:20:38 +00:00
@@ -29,13 +29,10 @@
|
||||
## writeLine(stdout, "your password: " & myData["password"])
|
||||
## writeLine(stdout, "</body></html>")
|
||||
|
||||
import strutils, os, strtabs, cookies, uri
|
||||
import std/[strutils, os, strtabs, cookies, uri]
|
||||
export uri.encodeUrl, uri.decodeUrl
|
||||
|
||||
|
||||
import std/private/decode_helpers
|
||||
|
||||
|
||||
proc addXmlChar(dest: var string, c: char) {.inline.} =
|
||||
case c
|
||||
of '&': add(dest, "&")
|
||||
@@ -46,23 +43,23 @@ proc addXmlChar(dest: var string, c: char) {.inline.} =
|
||||
|
||||
proc xmlEncode*(s: string): string =
|
||||
## Encodes a value to be XML safe:
|
||||
## * ``"`` is replaced by ``"``
|
||||
## * ``<`` is replaced by ``<``
|
||||
## * ``>`` is replaced by ``>``
|
||||
## * ``&`` is replaced by ``&``
|
||||
## * `"` is replaced by `"`
|
||||
## * `<` is replaced by `<`
|
||||
## * `>` is replaced by `>`
|
||||
## * `&` is replaced by `&`
|
||||
## * every other character is carried over.
|
||||
result = newStringOfCap(s.len + s.len shr 2)
|
||||
for i in 0..len(s)-1: addXmlChar(result, s[i])
|
||||
|
||||
type
|
||||
CgiError* = object of IOError ## Exception that is raised if a CGI error occurs
|
||||
RequestMethod* = enum ## the used request method
|
||||
CgiError* = object of IOError ## Exception that is raised if a CGI error occurs.
|
||||
RequestMethod* = enum ## The used request method.
|
||||
methodNone, ## no REQUEST_METHOD environment variable
|
||||
methodPost, ## query uses the POST method
|
||||
methodGet ## query uses the GET method
|
||||
|
||||
proc cgiError*(msg: string) {.noreturn.} =
|
||||
## Raises a ``CgiError`` exception with message `msg`.
|
||||
## Raises a `CgiError` exception with message `msg`.
|
||||
raise newException(CgiError, msg)
|
||||
|
||||
proc getEncodedData(allowedMethods: set[RequestMethod]): string =
|
||||
@@ -97,7 +94,7 @@ iterator decodeData*(allowedMethods: set[RequestMethod] =
|
||||
{methodNone, methodPost, methodGet}): tuple[key, value: TaintedString] =
|
||||
## Reads and decodes CGI data and yields the (name, value) pairs the
|
||||
## data consists of. If the client does not use a method listed in the
|
||||
## `allowedMethods` set, a ``CgiError`` exception is raised.
|
||||
## `allowedMethods` set, a `CgiError` exception is raised.
|
||||
let data = getEncodedData(allowedMethods)
|
||||
try:
|
||||
for (key, value) in uri.decodeQuery(data):
|
||||
@@ -107,155 +104,155 @@ iterator decodeData*(allowedMethods: set[RequestMethod] =
|
||||
|
||||
proc readData*(allowedMethods: set[RequestMethod] =
|
||||
{methodNone, methodPost, methodGet}): StringTableRef =
|
||||
## Read CGI data. If the client does not use a method listed in the
|
||||
## `allowedMethods` set, an `ECgi` exception is raised.
|
||||
## Reads CGI data. If the client does not use a method listed in the
|
||||
## `allowedMethods` set, a `CgiError` exception is raised.
|
||||
result = newStringTable()
|
||||
for name, value in decodeData(allowedMethods):
|
||||
result[name.string] = value.string
|
||||
|
||||
proc readData*(data: string): StringTableRef =
|
||||
## Read CGI data from a string.
|
||||
## Reads CGI data from a string.
|
||||
result = newStringTable()
|
||||
for name, value in decodeData(data):
|
||||
result[name.string] = value.string
|
||||
|
||||
proc validateData*(data: StringTableRef, validKeys: varargs[string]) =
|
||||
## validates data; raises `ECgi` if this fails. This checks that each variable
|
||||
## Validates data; raises `CgiError` if this fails. This checks that each variable
|
||||
## name of the CGI `data` occurs in the `validKeys` array.
|
||||
for key, val in pairs(data):
|
||||
if find(validKeys, key) < 0:
|
||||
cgiError("unknown variable name: " & key)
|
||||
|
||||
proc getContentLength*(): string =
|
||||
## returns contents of the ``CONTENT_LENGTH`` environment variable
|
||||
## Returns contents of the `CONTENT_LENGTH` environment variable.
|
||||
return getEnv("CONTENT_LENGTH").string
|
||||
|
||||
proc getContentType*(): string =
|
||||
## returns contents of the ``CONTENT_TYPE`` environment variable
|
||||
## Returns contents of the `CONTENT_TYPE` environment variable.
|
||||
return getEnv("CONTENT_Type").string
|
||||
|
||||
proc getDocumentRoot*(): string =
|
||||
## returns contents of the ``DOCUMENT_ROOT`` environment variable
|
||||
## Returns contents of the `DOCUMENT_ROOT` environment variable.
|
||||
return getEnv("DOCUMENT_ROOT").string
|
||||
|
||||
proc getGatewayInterface*(): string =
|
||||
## returns contents of the ``GATEWAY_INTERFACE`` environment variable
|
||||
## Returns contents of the `GATEWAY_INTERFACE` environment variable.
|
||||
return getEnv("GATEWAY_INTERFACE").string
|
||||
|
||||
proc getHttpAccept*(): string =
|
||||
## returns contents of the ``HTTP_ACCEPT`` environment variable
|
||||
## Returns contents of the `HTTP_ACCEPT` environment variable.
|
||||
return getEnv("HTTP_ACCEPT").string
|
||||
|
||||
proc getHttpAcceptCharset*(): string =
|
||||
## returns contents of the ``HTTP_ACCEPT_CHARSET`` environment variable
|
||||
## Returns contents of the `HTTP_ACCEPT_CHARSET` environment variable.
|
||||
return getEnv("HTTP_ACCEPT_CHARSET").string
|
||||
|
||||
proc getHttpAcceptEncoding*(): string =
|
||||
## returns contents of the ``HTTP_ACCEPT_ENCODING`` environment variable
|
||||
## Returns contents of the `HTTP_ACCEPT_ENCODING` environment variable.
|
||||
return getEnv("HTTP_ACCEPT_ENCODING").string
|
||||
|
||||
proc getHttpAcceptLanguage*(): string =
|
||||
## returns contents of the ``HTTP_ACCEPT_LANGUAGE`` environment variable
|
||||
## Returns contents of the `HTTP_ACCEPT_LANGUAGE` environment variable.
|
||||
return getEnv("HTTP_ACCEPT_LANGUAGE").string
|
||||
|
||||
proc getHttpConnection*(): string =
|
||||
## returns contents of the ``HTTP_CONNECTION`` environment variable
|
||||
## Returns contents of the `HTTP_CONNECTION` environment variable.
|
||||
return getEnv("HTTP_CONNECTION").string
|
||||
|
||||
proc getHttpCookie*(): string =
|
||||
## returns contents of the ``HTTP_COOKIE`` environment variable
|
||||
## Returns contents of the `HTTP_COOKIE` environment variable.
|
||||
return getEnv("HTTP_COOKIE").string
|
||||
|
||||
proc getHttpHost*(): string =
|
||||
## returns contents of the ``HTTP_HOST`` environment variable
|
||||
## Returns contents of the `HTTP_HOST` environment variable.
|
||||
return getEnv("HTTP_HOST").string
|
||||
|
||||
proc getHttpReferer*(): string =
|
||||
## returns contents of the ``HTTP_REFERER`` environment variable
|
||||
## Returns contents of the `HTTP_REFERER` environment variable.
|
||||
return getEnv("HTTP_REFERER").string
|
||||
|
||||
proc getHttpUserAgent*(): string =
|
||||
## returns contents of the ``HTTP_USER_AGENT`` environment variable
|
||||
## Returns contents of the `HTTP_USER_AGENT` environment variable.
|
||||
return getEnv("HTTP_USER_AGENT").string
|
||||
|
||||
proc getPathInfo*(): string =
|
||||
## returns contents of the ``PATH_INFO`` environment variable
|
||||
## Returns contents of the `PATH_INFO` environment variable.
|
||||
return getEnv("PATH_INFO").string
|
||||
|
||||
proc getPathTranslated*(): string =
|
||||
## returns contents of the ``PATH_TRANSLATED`` environment variable
|
||||
## Returns contents of the `PATH_TRANSLATED` environment variable.
|
||||
return getEnv("PATH_TRANSLATED").string
|
||||
|
||||
proc getQueryString*(): string =
|
||||
## returns contents of the ``QUERY_STRING`` environment variable
|
||||
## Returns contents of the `QUERY_STRING` environment variable.
|
||||
return getEnv("QUERY_STRING").string
|
||||
|
||||
proc getRemoteAddr*(): string =
|
||||
## returns contents of the ``REMOTE_ADDR`` environment variable
|
||||
## Returns contents of the `REMOTE_ADDR` environment variable.
|
||||
return getEnv("REMOTE_ADDR").string
|
||||
|
||||
proc getRemoteHost*(): string =
|
||||
## returns contents of the ``REMOTE_HOST`` environment variable
|
||||
## Returns contents of the `REMOTE_HOST` environment variable.
|
||||
return getEnv("REMOTE_HOST").string
|
||||
|
||||
proc getRemoteIdent*(): string =
|
||||
## returns contents of the ``REMOTE_IDENT`` environment variable
|
||||
## Returns contents of the `REMOTE_IDENT` environment variable.
|
||||
return getEnv("REMOTE_IDENT").string
|
||||
|
||||
proc getRemotePort*(): string =
|
||||
## returns contents of the ``REMOTE_PORT`` environment variable
|
||||
## Returns contents of the `REMOTE_PORT` environment variable.
|
||||
return getEnv("REMOTE_PORT").string
|
||||
|
||||
proc getRemoteUser*(): string =
|
||||
## returns contents of the ``REMOTE_USER`` environment variable
|
||||
## Returns contents of the `REMOTE_USER` environment variable.
|
||||
return getEnv("REMOTE_USER").string
|
||||
|
||||
proc getRequestMethod*(): string =
|
||||
## returns contents of the ``REQUEST_METHOD`` environment variable
|
||||
## Returns contents of the `REQUEST_METHOD` environment variable.
|
||||
return getEnv("REQUEST_METHOD").string
|
||||
|
||||
proc getRequestURI*(): string =
|
||||
## returns contents of the ``REQUEST_URI`` environment variable
|
||||
## Returns contents of the `REQUEST_URI` environment variable.
|
||||
return getEnv("REQUEST_URI").string
|
||||
|
||||
proc getScriptFilename*(): string =
|
||||
## returns contents of the ``SCRIPT_FILENAME`` environment variable
|
||||
## Returns contents of the `SCRIPT_FILENAME` environment variable.
|
||||
return getEnv("SCRIPT_FILENAME").string
|
||||
|
||||
proc getScriptName*(): string =
|
||||
## returns contents of the ``SCRIPT_NAME`` environment variable
|
||||
## Returns contents of the `SCRIPT_NAME` environment variable.
|
||||
return getEnv("SCRIPT_NAME").string
|
||||
|
||||
proc getServerAddr*(): string =
|
||||
## returns contents of the ``SERVER_ADDR`` environment variable
|
||||
## Returns contents of the `SERVER_ADDR` environment variable.
|
||||
return getEnv("SERVER_ADDR").string
|
||||
|
||||
proc getServerAdmin*(): string =
|
||||
## returns contents of the ``SERVER_ADMIN`` environment variable
|
||||
## Returns contents of the `SERVER_ADMIN` environment variable.
|
||||
return getEnv("SERVER_ADMIN").string
|
||||
|
||||
proc getServerName*(): string =
|
||||
## returns contents of the ``SERVER_NAME`` environment variable
|
||||
## Returns contents of the `SERVER_NAME` environment variable.
|
||||
return getEnv("SERVER_NAME").string
|
||||
|
||||
proc getServerPort*(): string =
|
||||
## returns contents of the ``SERVER_PORT`` environment variable
|
||||
## Returns contents of the `SERVER_PORT` environment variable.
|
||||
return getEnv("SERVER_PORT").string
|
||||
|
||||
proc getServerProtocol*(): string =
|
||||
## returns contents of the ``SERVER_PROTOCOL`` environment variable
|
||||
## Returns contents of the `SERVER_PROTOCOL` environment variable.
|
||||
return getEnv("SERVER_PROTOCOL").string
|
||||
|
||||
proc getServerSignature*(): string =
|
||||
## returns contents of the ``SERVER_SIGNATURE`` environment variable
|
||||
## Returns contents of the `SERVER_SIGNATURE` environment variable.
|
||||
return getEnv("SERVER_SIGNATURE").string
|
||||
|
||||
proc getServerSoftware*(): string =
|
||||
## returns contents of the ``SERVER_SOFTWARE`` environment variable
|
||||
## Returns contents of the `SERVER_SOFTWARE` environment variable.
|
||||
return getEnv("SERVER_SOFTWARE").string
|
||||
|
||||
proc setTestData*(keysvalues: varargs[string]) =
|
||||
## fills the appropriate environment variables to test your CGI application.
|
||||
## Fills the appropriate environment variables to test your CGI application.
|
||||
## This can only simulate the 'GET' request method. `keysvalues` should
|
||||
## provide embedded (name, value)-pairs. Example:
|
||||
##
|
||||
@@ -273,7 +270,7 @@ proc setTestData*(keysvalues: varargs[string]) =
|
||||
putEnv("QUERY_STRING", query)
|
||||
|
||||
proc writeContentType*() =
|
||||
## call this before starting to send your HTML data to `stdout`. This
|
||||
## Calls this before starting to send your HTML data to `stdout`. This
|
||||
## implements this part of the CGI protocol:
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
discard """
|
||||
output: "works"
|
||||
"""
|
||||
|
||||
import cgi, strtabs
|
||||
import std/[cgi, strtabs]
|
||||
|
||||
proc handleRequest(query: string): StringTableRef =
|
||||
iterator foo(): StringTableRef {.closure.} =
|
||||
@@ -26,4 +22,3 @@ proc main =
|
||||
quit "but now a leak"
|
||||
|
||||
main()
|
||||
echo "works"
|
||||
|
||||
@@ -1,25 +1,10 @@
|
||||
discard """
|
||||
output: '''
|
||||
import std/unittest
|
||||
import std/[cgi, strtabs, sugar]
|
||||
|
||||
[Suite] Test cgi module
|
||||
(key: "a", value: "1")
|
||||
(key: "b", value: "0")
|
||||
(key: "c", value: "3")
|
||||
(key: "d", value: "")
|
||||
(key: "e", value: "")
|
||||
(key: "a", value: "5")
|
||||
(key: "a", value: "t e x t")
|
||||
(key: "e", value: "http://w3schools.com/my test.asp?name=ståle&car=saab")
|
||||
'''
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import cgi, strtabs
|
||||
|
||||
suite "Test cgi module":
|
||||
block: # Test cgi module
|
||||
const queryString = "foo=bar&фу=бар&checked=✓&list=1,2,3&with_space=text%20with%20space"
|
||||
|
||||
test "test query parsing with readData":
|
||||
block: # test query parsing with readData
|
||||
let parsedQuery = readData(queryString)
|
||||
|
||||
check parsedQuery["foo"] == "bar"
|
||||
@@ -34,5 +19,8 @@ suite "Test cgi module":
|
||||
# bug #15369
|
||||
let queryString = "a=1&b=0&c=3&d&e&a=5&a=t%20e%20x%20t&e=http%3A%2F%2Fw3schools.com%2Fmy%20test.asp%3Fname%3Dst%C3%A5le%26car%3Dsaab"
|
||||
|
||||
for pair in decodeData(queryString):
|
||||
echo pair
|
||||
doAssert collect(for pair in decodeData(queryString): pair) ==
|
||||
@[("a", "1"), ("b", "0"), ("c", "3"),
|
||||
("d", ""),("e", ""), ("a", "5"), ("a", "t e x t"),
|
||||
("e", "http://w3schools.com/my test.asp?name=ståle&car=saab")
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user