mirror of
https://github.com/waku-org/nwaku.git
synced 2025-02-16 00:47:24 +00:00
1220 lines
44 KiB
Nim
1220 lines
44 KiB
Nim
import std/strutils,
|
|
unittest2,
|
|
../httputils
|
|
|
|
# Some tests are borrowed from
|
|
# https://github.com/nodejs/http-parser/blob/master/test.c
|
|
|
|
const RequestVectors = [
|
|
"GET /test HTTP/1.1\r\n" &
|
|
"User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1\r\n" &
|
|
"Host: 0.0.0.0=5000\r\n" &
|
|
"Accept: */*\r\n" &
|
|
"\r\n",
|
|
"GET /favicon.ico HTTP/1.1\r\n" &
|
|
"Host: 0.0.0.0=5000\r\n" &
|
|
"User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\n" &
|
|
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" &
|
|
"Accept-Language: en-us,en;q=0.5\r\n" &
|
|
"Accept-Encoding: gzip,deflate\r\n" &
|
|
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" &
|
|
"Keep-Alive: 300\r\n" &
|
|
"Connection: keep-alive\r\n" &
|
|
"\r\n",
|
|
"GET /dumbfuck HTTP/1.1\r\n" &
|
|
"aaaaaaaaaaaaa:++++++++++\r\n" &
|
|
"\r\n",
|
|
"GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n" &
|
|
"\r\n",
|
|
"GET /get_no_headers_no_body/world HTTP/1.0\r\n" &
|
|
"\r\n",
|
|
"POST /get_one_header_no_body HTTP/2.0\r\n" &
|
|
"Accept: */*\r\n" &
|
|
"\r\n",
|
|
"GET /get_funky_content_length_body_hello HTTP/1.0\r\n" &
|
|
"conTENT-Length: 5\r\n" &
|
|
"\r\n",
|
|
"POST /post_identity_body_world?q=search#hey HTTP/1.1\r\n" &
|
|
"Accept: */*\r\n" &
|
|
"Transfer-Encoding: identity\r\n" &
|
|
"Content-Length: 5\r\n" &
|
|
"\r\n",
|
|
"GET /with_\"stupid\"_quotes?foo=\"bar\" HTTP/1.1\r\n\r\n",
|
|
"CONNECT foo.bar.com:443 HTTP/1.0\r\n" &
|
|
"User-agent: Mozilla/1.1N\r\n" &
|
|
"Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n" &
|
|
"Content-Length: 10\r\n" &
|
|
"\r\n",
|
|
"PUT /!#$&'()*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]_abcdefghijklmnopqrstuvwxyz~ HTTP/1.1\r\n" &
|
|
"Host: example.com\r\n" &
|
|
"Connection: Upgrade\r\n" &
|
|
"Upgrade: HTTP/2.0\r\n" &
|
|
"Content-Length: 15\r\n" &
|
|
"\r\n",
|
|
"GET / HTTP/1.0\r\n\r\n",
|
|
"POST / HTTP/1.0\r\n\r\n",
|
|
"PUT / HTTP/1.0\r\n\r\n",
|
|
"PATCH / HTTP/1.0\r\n\r\n",
|
|
"DELETE / HTTP/1.0\r\n\r\n",
|
|
"OPTIONS / HTTP/1.0\r\n\r\n",
|
|
"TRACE / HTTP/1.0\r\n\r\n",
|
|
"CONNECT / HTTP/1.0\r\n\r\n",
|
|
"CONNECT / HTTP/2.0\r\n" &
|
|
"!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~: !#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~\r\n" &
|
|
"\r\n",
|
|
"POST /empty_header HTTP/1.1\r\n" &
|
|
"Server: \r\n" &
|
|
"Accept: */*\r\n" &
|
|
"\r\n",
|
|
"TRACE / HTTP/1.1\r\n" &
|
|
"Server: \r\n" &
|
|
"\r\n",
|
|
"GET / HTTP/0.9\r\n" &
|
|
"Content-Length: 99223372036854775807\r\n" &
|
|
"\r\n",
|
|
"POST / HTTP/1.1\r\n" &
|
|
"Host:example.amazonaws.com\r\n" &
|
|
"X-Amz-Date:20150830T123600Z\r\n\r\nhello",
|
|
"GET /%E1%88%B4 HTTP/1.1\r\n" &
|
|
"Host:example.amazonaws.com\r\n" &
|
|
"X-Amz-Date:20150830T123600Z\r\n\r\n",
|
|
"GET / HTTP/1.1\r\n" &
|
|
"Sec-Fetch-User: ?1\r\n" &
|
|
"Sec-Fetch-Mode:@1\r\n\r\n"
|
|
]
|
|
|
|
const RequestHeaderTexts = [
|
|
(k: "User-Agent", v: "curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1"),
|
|
(k: "Host", v: "0.0.0.0=5000"),
|
|
(k: "Accept", v: "*/*"),
|
|
|
|
(k: "Host", v: "0.0.0.0=5000"),
|
|
(k: "User-Agent", v: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0"),
|
|
(k: "Accept", v: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"),
|
|
(k: "Accept-Language", v: "en-us,en;q=0.5"),
|
|
(k: "Accept-Encoding", v: "gzip,deflate"),
|
|
(k: "Accept-Charset", v: "ISO-8859-1,utf-8;q=0.7,*;q=0.7"),
|
|
(k: "Keep-Alive", v: "300"),
|
|
(k: "Connection", v: "keep-alive"),
|
|
|
|
(k: "aaaaaaaaaaaaa", v: "++++++++++"),
|
|
|
|
(k: "Accept", v: "*/*"),
|
|
|
|
(k: "Content-Length", v: "5"),
|
|
|
|
(k: "Accept", v: "*/*"),
|
|
(k: "Transfer-Encoding", v: "identity"),
|
|
(k: "Content-Length", v: "5"),
|
|
|
|
(k: "User-agent", v: "Mozilla/1.1N"),
|
|
(k: "Proxy-authorization", v: "basic aGVsbG86d29ybGQ="),
|
|
(k: "Content-Length", v: "10"),
|
|
|
|
(k: "Host", v: "example.com"),
|
|
(k: "Connection", v: "Upgrade"),
|
|
(k: "Upgrade", v: "HTTP/2.0"),
|
|
(k: "Content-Length", v: "15"),
|
|
|
|
(k: "!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~", v: "!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~"),
|
|
|
|
(k: "Server", v: ""),
|
|
(k: "Accept", v: "*/*"),
|
|
|
|
(k: "Server", v: ""),
|
|
|
|
(k: "Content-Length", v: "99223372036854775807"),
|
|
|
|
(k: "Host", v: "example.amazonaws.com"),
|
|
(k: "X-Amz-Date", v: "20150830T123600Z"),
|
|
|
|
(k: "Host", v: "example.amazonaws.com"),
|
|
(k: "X-Amz-Date", v: "20150830T123600Z"),
|
|
|
|
(k: "Sec-Fetch-User", v: "?1"),
|
|
(k: "Sec-Fetch-Mode", v: "@1")
|
|
]
|
|
|
|
const RequestResults = [
|
|
0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0xC2, 0x8E, 0x8E,
|
|
0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
|
|
0x8E, 0x8E, 0x8E, 0x8E
|
|
]
|
|
|
|
const RequestHeaders = [
|
|
(0, 2), (3, 10), (11, 11), (0, -1), (0, -1), (12, 12), (13, 13), (14, 16),
|
|
(0, -1), (17, 19), (20, 23), (0, -1), (0, -1), (0, -1), (0, -1), (0, -1),
|
|
(0, -1), (0, -1), (0, -1), (24, 24), (25, 26), (27, 27), (28, 28), (29, 30),
|
|
(31, 32), (33, 34)
|
|
]
|
|
|
|
const RequestVersions = [
|
|
HttpVersion11, HttpVersion11, HttpVersion11, HttpVersion11, HttpVersion10,
|
|
HttpVersion20, HttpVersion10, HttpVersion11, HttpVersion11, HttpVersion10,
|
|
HttpVersion11, HttpVersion10, HttpVersion10, HttpVersion10, HttpVersion10,
|
|
HttpVersion10, HttpVersion10, HttpVersion10, HttpVersion10, HttpVersion20,
|
|
HttpVersion11, HttpVersion11, HttpVersion09, HttpVersion11, HttpVersion11,
|
|
HttpVersion11
|
|
]
|
|
|
|
const RequestUris = [
|
|
"/test", "/favicon.ico", "/dumbfuck", "/forums/1/topics/2375?page=1#posts-17408",
|
|
"/get_no_headers_no_body/world", "/get_one_header_no_body",
|
|
"/get_funky_content_length_body_hello", "/post_identity_body_world?q=search#hey",
|
|
"/with_\"stupid\"_quotes?foo=\"bar\"", "foo.bar.com:443",
|
|
"/!#$&'()*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]_abcdefghijklmnopqrstuvwxyz~",
|
|
"/", "/", "/", "/", "/", "/", "/", "/", "/", "/empty_header", "/", "/", "/",
|
|
"/%E1%88%B4", "/"
|
|
]
|
|
|
|
const RequestCLengths = [
|
|
0, 0, 0, 0, 0, 0, 5, 5, -1, 10, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0,
|
|
0
|
|
]
|
|
|
|
const ResponseVectors = [
|
|
"HTTP/1.1 301 Moved Permanently\r\n" &
|
|
"Location: http://www.google.com/\r\n" &
|
|
"Content-Type: text/html; charset=UTF-8\r\n" &
|
|
"Date: Sun, 26 Apr 2009 11:11:49 GMT\r\n" &
|
|
"Expires: Tue, 26 May 2009 11:11:49 GMT\r\n" &
|
|
"X-$PrototypeBI-Version: 1.6.0.3\r\n" &
|
|
"Cache-Control: public, max-age=2592000\r\n" &
|
|
"Server: gws\r\n" &
|
|
"Content-Length: 219 \r\n" &
|
|
"\r\n",
|
|
"HTTP/1.0 200 OK\r\n" &
|
|
"Date: Tue, 04 Aug 2009 07:59:32 GMT\r\n" &
|
|
"Server: Apache\r\n" &
|
|
"X-Powered-By: Servlet/2.5 JSP/2.1\r\n" &
|
|
"Content-Type: text/xml; charset=utf-8\r\n" &
|
|
"Connection: close\r\n" &
|
|
"\r\n",
|
|
"HTTP/1.1 404 Not Found\r\n\r\n",
|
|
"HTTP/1.1 503\r\n\r\n",
|
|
"HTTP/1.1 200 OK\n",
|
|
"HTTP/1.1 200 OK\r\n" &
|
|
"Server: DCLK-AdSvr\r\n" &
|
|
"Content-Type: text/xml\r\n" &
|
|
"Content-Length: 0\r\n" &
|
|
"DCLK_imp: v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o\r\n" &
|
|
"\r\n",
|
|
"HTTP/1.0 301 Moved Permanently\r\n" &
|
|
"Date: Thu, 03 Jun 2010 09:56:32 GMT\r\n" &
|
|
"Server: Apache/2.2.3 (Red Hat)\r\n" &
|
|
"Cache-Control: public\r\n" &
|
|
"Pragma: \r\n" &
|
|
"Location: http://www.bonjourmadame.fr/\r\n" &
|
|
"Vary: Accept-Encoding\r\n" &
|
|
"Content-Length: 0\r\n" &
|
|
"Content-Type: text/html; charset=UTF-8\r\n" &
|
|
"Connection: keep-alive\r\n" &
|
|
"\r\n",
|
|
"HTTP/1.1 200 OK\r\n" &
|
|
"Date: Tue, 28 Sep 2010 01:14:13 GMT\r\n" &
|
|
"Server: Apache\r\n" &
|
|
"Cache-Control: no-cache, must-revalidate\r\n" &
|
|
"Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n" &
|
|
".et-Cookie: PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com\r\n" &
|
|
"Vary: Accept-Encoding\r\n" &
|
|
"_eep-Alive: timeout=45\r\n" &
|
|
"_onnection: Keep-Alive\r\n" &
|
|
"Transfer-Encoding: chunked\r\n" &
|
|
"Content-Type: text/html\r\n" &
|
|
"Connection: close\r\n" &
|
|
"\r\n",
|
|
"HTTP/1.1 301 MovedPermanently\r\n" &
|
|
"Date: Wed, 15 May 2013 17:06:33 GMT\r\n" &
|
|
"Server: Server\r\n" &
|
|
"x-amz-id-1: 0GPHKXSJQ826RK7GZEB2\r\n" &
|
|
"p3p: policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"\r\n" &
|
|
"x-amz-id-2: STN69VZxIFSz9YJLbz1GDbxpbjG6Qjmmq5E3DxRhOUw+Et0p4hr7c/Q8qNcx4oAD\r\n" &
|
|
"Location: http://www.amazon.com/Dan-Brown/e/B000AP9DSU/ref=s9_pop_gw_al1?_encoding=UTF8&refinementId=618073011&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=center-2&pf_rd_r=0SHYY5BZXN3KR20BNFAY&pf_rd_t=101&pf_rd_p=1263340922&pf_rd_i=507846\r\n" &
|
|
"Vary: Accept-Encoding,User-Agent\r\n" &
|
|
"Content-Type: text/html; charset=ISO-8859-1\r\n" &
|
|
"Transfer-Encoding: chunked\r\n" &
|
|
"\r\n",
|
|
"HTTP/2.0 200 Success\r\n" &
|
|
"!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~: !#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~\r\n" &
|
|
"\r\n",
|
|
"HTTP/0.9 200\r\n" &
|
|
"Content-Length: 15\r\n" &
|
|
"\r\n",
|
|
"HTTP/0.9 200\r\n" &
|
|
"Content-Length: 99223372036854775807\r\n" &
|
|
"\r\n",
|
|
"HTTP/1.1 200 \r\n" &
|
|
"content-length: 458\r\n" &
|
|
"\r\n"
|
|
]
|
|
|
|
const ResponseHeaderTexts = [
|
|
(k: "Location", v: "http://www.google.com/"),
|
|
(k: "Content-Type", v: "text/html; charset=UTF-8"),
|
|
(k: "Date", v: "Sun, 26 Apr 2009 11:11:49 GMT"),
|
|
(k: "Expires", v: "Tue, 26 May 2009 11:11:49 GMT"),
|
|
(k: "X-$PrototypeBI-Version", v: "1.6.0.3"),
|
|
(k: "Cache-Control", v: "public, max-age=2592000"),
|
|
(k: "Server", v: "gws"),
|
|
(k: "Content-Length", v: "219 "),
|
|
|
|
(k: "Date", v: "Tue, 04 Aug 2009 07:59:32 GMT"),
|
|
(k: "Server", v: "Apache"),
|
|
(k: "X-Powered-By", v: "Servlet/2.5 JSP/2.1"),
|
|
(k: "Content-Type", v: "text/xml; charset=utf-8"),
|
|
(k: "Connection", v: "close"),
|
|
|
|
(k: "Server", v: "DCLK-AdSvr"),
|
|
(k: "Content-Type", v: "text/xml"),
|
|
(k: "Content-Length", v: "0"),
|
|
(k: "DCLK_imp", v: "v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o"),
|
|
|
|
(k: "Date", v: "Thu, 03 Jun 2010 09:56:32 GMT"),
|
|
(k: "Server", v: "Apache/2.2.3 (Red Hat)"),
|
|
(k: "Cache-Control", v: "public"),
|
|
(k: "Pragma", v: ""),
|
|
(k: "Location", v: "http://www.bonjourmadame.fr/"),
|
|
(k: "Vary", v: "Accept-Encoding"),
|
|
(k: "Content-Length", v: "0"),
|
|
(k: "Content-Type", v: "text/html; charset=UTF-8"),
|
|
(k: "Connection", v: "keep-alive"),
|
|
|
|
(k: "Date", v: "Tue, 28 Sep 2010 01:14:13 GMT"),
|
|
(k: "Server", v: "Apache"),
|
|
(k: "Cache-Control", v: "no-cache, must-revalidate"),
|
|
(k: "Expires", v: "Mon, 26 Jul 1997 05:00:00 GMT"),
|
|
(k: ".et-Cookie", v: "PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com"),
|
|
(k: "Vary", v: "Accept-Encoding"),
|
|
(k: "_eep-Alive", v: "timeout=45"),
|
|
(k: "_onnection", v: "Keep-Alive"),
|
|
(k: "Transfer-Encoding", v: "chunked"),
|
|
(k: "Content-Type", v: "text/html"),
|
|
(k: "Connection", v: "close"),
|
|
|
|
(k: "Date", v: "Wed, 15 May 2013 17:06:33 GMT"),
|
|
(k: "Server", v: "Server"),
|
|
(k: "x-amz-id-1", v: "0GPHKXSJQ826RK7GZEB2"),
|
|
(k: "p3p", v: "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""),
|
|
(k: "x-amz-id-2", v: "STN69VZxIFSz9YJLbz1GDbxpbjG6Qjmmq5E3DxRhOUw+Et0p4hr7c/Q8qNcx4oAD"),
|
|
(k: "Location", v: "http://www.amazon.com/Dan-Brown/e/B000AP9DSU/ref=s9_pop_gw_al1?_encoding=UTF8&refinementId=618073011&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=center-2&pf_rd_r=0SHYY5BZXN3KR20BNFAY&pf_rd_t=101&pf_rd_p=1263340922&pf_rd_i=507846"),
|
|
(k: "Vary", v: "Accept-Encoding,User-Agent"),
|
|
(k: "Content-Type", v: "text/html; charset=ISO-8859-1"),
|
|
(k: "Transfer-Encoding", v: "chunked"),
|
|
|
|
(k: "!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~", v: "!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~"),
|
|
|
|
(k: "Content-Length", v: "15"),
|
|
|
|
(k: "Content-Length", v: "99223372036854775807"),
|
|
|
|
(k: "Content-Length", v: "458")
|
|
]
|
|
|
|
const ResponseResults = [ 0x9F, 0x9F, 0x9F, 0x9F, 0xC3, 0x9F, 0x9F, 0x9F, 0x9F,
|
|
0x9F, 0x9F, 0x9F, 0x9F ]
|
|
|
|
const ResponseHeaders = [ (0, 7), (8, 12), (0, -1), (0, -1), (0, -1), (13, 16),
|
|
(17, 25), (26, 36), (37, 45), (46, 46), (47, 47),
|
|
(48, 48), (49, 49)]
|
|
|
|
const ResponseVersions = [HttpVersion11, HttpVersion10, HttpVersion11,
|
|
HttpVersion11, HttpVersion11, HttpVersion11,
|
|
HttpVersion10, HttpVersion11, HttpVersion11,
|
|
HttpVersion20, HttpVersion09, HttpVersion09,
|
|
HttpVersion11]
|
|
|
|
const ResponseCodes = [301, 200, 404, 503, 200, 200, 301, 200, 301, 200, 200,
|
|
200, 200]
|
|
|
|
const ResponseReasons = ["Moved Permanently", "OK", "Not Found", "", "", "OK",
|
|
"Moved Permanently", "OK", "MovedPermanently",
|
|
"Success", "", "", ""]
|
|
const ResponseCLengths = [ 219, 0, 0, 0, -1, 0, 0, 0, 0, 0, 15, -1, 458]
|
|
|
|
suite "HTTP Procedures test suite":
|
|
test "HTTP Request Vectors":
|
|
for i in 0..<len(RequestVectors):
|
|
var a = cast[seq[char]](RequestVectors[i])
|
|
var req = parseRequest(a)
|
|
if RequestResults[i] == 0x8E:
|
|
check:
|
|
req.success() == true
|
|
req.uri() == RequestUris[i]
|
|
block: # Check null-termination for cstring compat
|
|
let uri = req.uri()
|
|
let puri = cast[ptr UncheckedArray[char]](uri[0].unsafeAddr)
|
|
puri[uri.len] == '\0'
|
|
req.version == RequestVersions[i]
|
|
len(req) == RequestHeaders[i][1] - RequestHeaders[i][0] + 1
|
|
req.contentLength() == RequestCLengths[i]
|
|
else:
|
|
check:
|
|
req.success() == false
|
|
req.failed() == true
|
|
req.state == RequestResults[i]
|
|
req.contentLength() == RequestCLengths[i]
|
|
|
|
if len(req) > 0:
|
|
for citem in req.headers():
|
|
var found = false
|
|
for ei in RequestHeaders[i][0]..RequestHeaders[i][1]:
|
|
if cmpIgnoreCase(citem.name, RequestHeaderTexts[ei].k) == 0 and
|
|
cmpIgnoreCase(citem.value, RequestHeaderTexts[ei].v) == 0:
|
|
found = true
|
|
break
|
|
check found == true
|
|
|
|
for ei in RequestHeaders[i][0]..RequestHeaders[i][1]:
|
|
check (RequestHeaderTexts[ei].k in req) == true
|
|
|
|
for ei in RequestHeaders[i][0]..RequestHeaders[i][1]:
|
|
check (req[RequestHeaderTexts[ei].k] == RequestHeaderTexts[ei].v)
|
|
|
|
test "HTTP Response Vectors":
|
|
for i in 0..<len(ResponseVectors):
|
|
var a = cast[seq[char]](ResponseVectors[i])
|
|
var resp = parseResponse(a)
|
|
if ResponseResults[i] == 0x9F:
|
|
check:
|
|
resp.success() == true
|
|
resp.reason() == ResponseReasons[i]
|
|
resp.version == ResponseVersions[i]
|
|
resp.code == ResponseCodes[i]
|
|
len(resp) == ResponseHeaders[i][1] - ResponseHeaders[i][0] + 1
|
|
resp.contentLength() == ResponseCLengths[i]
|
|
else:
|
|
check:
|
|
resp.success() == false
|
|
resp.failed() == true
|
|
resp.state == ResponseResults[i]
|
|
resp.contentLength() == ResponseCLengths[i]
|
|
|
|
if len(resp) > 0:
|
|
for citem in resp.headers():
|
|
var found = false
|
|
for ei in ResponseHeaders[i][0]..ResponseHeaders[i][1]:
|
|
if cmpIgnoreCase(citem.name, ResponseHeaderTexts[ei].k) == 0 and
|
|
cmpIgnoreCase(citem.value, ResponseHeaderTexts[ei].v) == 0:
|
|
found = true
|
|
break
|
|
check found == true
|
|
|
|
for ei in ResponseHeaders[i][0]..ResponseHeaders[i][1]:
|
|
check (ResponseHeaderTexts[ei].k in resp) == true
|
|
|
|
for ei in ResponseHeaders[i][0]..ResponseHeaders[i][1]:
|
|
check (resp[ResponseHeaderTexts[ei].k] == ResponseHeaderTexts[ei].v)
|
|
|
|
test "HTTP request methods test":
|
|
const MethodRequests = [
|
|
("GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n", MethodGet),
|
|
("POST / HTTP/1.1\r\nHost: www.google.com\r\n\r\n", MethodPost),
|
|
("HEAD / HTTP/1.1\r\nHost: www.google.com\r\n\r\n", MethodHead),
|
|
("PUT / HTTP/1.1\r\nHost: www.google.com\r\n\r\n", MethodPut),
|
|
("DELETE / HTTP/1.1\r\nHost: www.google.com\r\n\r\n", MethodDelete),
|
|
("TRACE / HTTP/1.1\r\nHost: www.google.com\r\n\r\n", MethodTrace),
|
|
("OPTIONS / HTTP/1.1\r\nHost: www.google.com\r\n\r\n", MethodOptions),
|
|
("CONNECT / HTTP/1.1\r\nHost: www.google.com\r\n\r\n", MethodConnect),
|
|
("PATCH / HTTP/1.1\r\nHost: www.google.com\r\n\r\n", MethodPatch)
|
|
]
|
|
|
|
for item in MethodRequests:
|
|
var req = parseRequest(item[0], true)
|
|
check:
|
|
req.success()
|
|
req.meth == item[1]
|
|
|
|
test "HTTP methods conversion vectors":
|
|
check:
|
|
$MethodGet == "GET"
|
|
$MethodPost == "POST"
|
|
$MethodHead == "HEAD"
|
|
$MethodPut == "PUT"
|
|
$MethodDelete == "DELETE"
|
|
$MethodTrace == "TRACE"
|
|
$MethodOptions == "OPTIONS"
|
|
$MethodConnect == "CONNECT"
|
|
$MethodPatch == "PATCH"
|
|
$MethodError == "ERROR"
|
|
|
|
test "Validate header name/value":
|
|
var chs = " "
|
|
for a in 0..255:
|
|
if chr(a) notin HEADERNAME:
|
|
chs[0] = chr(a)
|
|
check checkHeaderName(chs) == false
|
|
else:
|
|
chs[0] = chr(a)
|
|
check checkHeaderName(chs) == true
|
|
|
|
chs = " "
|
|
for a in 0..255:
|
|
if chr(a) notin {'\r', '\n'}:
|
|
chs[0] = chr(a)
|
|
check checkHeaderValue(chs) == true
|
|
else:
|
|
chs[0] = chr(a)
|
|
check checkHeaderValue(chs) == false
|
|
|
|
test "Parsing headers test":
|
|
var headersStr = ""
|
|
for item in ResponseHeaderTexts:
|
|
let line = item.k & ": " & item.v & "\r\n"
|
|
headersStr.add(line)
|
|
headersStr.add("\r\n")
|
|
var headersSeq = newSeq[byte](len(headersStr))
|
|
copyMem(addr headersSeq[0], addr headersStr[0], len(headersSeq))
|
|
let list = parseHeaders(headersSeq)
|
|
check:
|
|
list.success() == true
|
|
len(list) == len(ResponseHeaderTexts)
|
|
|
|
test "Content-Disposition test vectors":
|
|
type TestOutput = (bool, string, seq[(string, string)])
|
|
|
|
proc runDispTest(test: string): TestOutput =
|
|
let cdisp = parseDisposition(test, true)
|
|
var fields: seq[tuple[k: string, v: string]]
|
|
if cdisp.success():
|
|
for k, v in cdisp.fields():
|
|
fields.add((k, v))
|
|
(true, cdisp.dispositionType(), fields)
|
|
else:
|
|
(false, "", fields)
|
|
|
|
check:
|
|
runDispTest("") == (false, "", @[]).TestOutput
|
|
runDispTest("a") == (true, "a", @[]).TestOutput
|
|
runDispTest("aa") == (true, "aa", @[]).TestOutput
|
|
runDispTest("form-data") == (true, "form-data", @[]).TestOutput
|
|
runDispTest("form-data; name=token5; value=token6") ==
|
|
(true, "form-data", @[("name", "token5"), ("value", "token6")])
|
|
runDispTest("form-data; name=\"quoted1\"; filename=\"quoted2.txt\"") ==
|
|
(true, "form-data", @[("name", "quoted1"), ("filename", "quoted2.txt")])
|
|
runDispTest("form-data; filename=\"quoted.txt\";name=noquote") ==
|
|
(true, "form-data", @[("filename", "quoted.txt"), ("name", "noquote")])
|
|
runDispTest("form-data; filename=\"123\\\"\\\"\\\"456\"") ==
|
|
(true, "form-data", @[("filename", "123\"\"\"456")])
|
|
runDispTest("form-data; filename=123\"") == (false, "", @[]).TestOutput
|
|
runDispTest("form-data; filename=123;") == (false, "", @[]).TestOutput
|
|
runDispTest("form-data; filename=123") ==
|
|
(true, "form-data", @[("filename", "123")])
|
|
runDispTest("form-data; filename=\"\"") ==
|
|
(true, "form-data", @[("filename", "")])
|
|
runDispTest("form-data; filename=") ==
|
|
(true, "form-data", @[("filename", "")])
|
|
runDispTest("form-data; a=;b=;c=;d=\"\";e=") ==
|
|
(true, "form-data", @[("a", ""), ("b", ""), ("c", ""), ("d", ""),
|
|
("e", "")])
|
|
runDispTest("form-data;a=\"''''\"") ==
|
|
(true, "form-data", @[("a", "''''")])
|
|
|
|
test "Accept header test vectors":
|
|
# This is default accept header strings for different browsers
|
|
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation/List_of_default_Accept_values
|
|
const SuccessVectors = [
|
|
("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
|
|
@[
|
|
("text/html", "", 1.0),
|
|
("application/xhtml+xml", "", 1.0),
|
|
("application/xml", "q=0.9", 0.9),
|
|
("image/webp", "", 1.0),
|
|
("*/*", "q=0.8", 0.8)
|
|
]
|
|
),
|
|
("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
@[
|
|
("text/html", "", 1.0),
|
|
("application/xhtml+xml", "", 1.0),
|
|
("application/xml", "q=0.9", 0.9),
|
|
("*/*", "q=0.8", 0.8)
|
|
]
|
|
),
|
|
("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
|
|
@[
|
|
("text/html", "", 1.0),
|
|
("application/xhtml+xml", "", 1.0),
|
|
("application/xml", "q=0.9", 0.9),
|
|
("image/webp", "", 1.0),
|
|
("*/*", "q=0.8", 0.8)
|
|
]
|
|
),
|
|
("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
@[
|
|
("text/html", "", 1.0),
|
|
("application/xhtml+xml", "", 1.0),
|
|
("application/xml", "q=0.9", 0.9),
|
|
("*/*", "q=0.8", 0.8)
|
|
]
|
|
),
|
|
("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
|
|
@[
|
|
("text/html", "", 1.0),
|
|
("application/xhtml+xml", "", 1.0),
|
|
("application/xml", "q=0.9", 0.9),
|
|
("image/webp", "", 1.0),
|
|
("image/apng", "", 1.0),
|
|
("*/*", "q=0.8", 0.8)
|
|
]
|
|
),
|
|
("image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, application/msword, */*",
|
|
@[
|
|
("image/jpeg", "", 1.0),
|
|
("application/x-ms-application", "", 1.0),
|
|
("image/gif", "", 1.0),
|
|
("application/xaml+xml", "", 1.0),
|
|
("image/pjpeg", "", 1.0),
|
|
("application/x-ms-xbap", "", 1.0),
|
|
("application/x-shockwave-flash", "", 1.0),
|
|
("application/msword", "", 1.0),
|
|
("*/*", "", 1.0)
|
|
]
|
|
),
|
|
("text/html, application/xhtml+xml, image/jxr, */*",
|
|
@[
|
|
("text/html", "", 1.0),
|
|
("application/xhtml+xml", "", 1.0),
|
|
("image/jxr", "", 1.0),
|
|
("*/*", "", 1.0)
|
|
]
|
|
),
|
|
("text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1",
|
|
@[
|
|
("text/html", "", 1.0),
|
|
("application/xml", "q=0.9", 0.9),
|
|
("application/xhtml+xml", "", 1.0),
|
|
("image/png", "", 1.0),
|
|
("image/webp", "", 1.0),
|
|
("image/jpeg", "", 1.0),
|
|
("image/gif", "", 1.0),
|
|
("image/x-xbitmap", "", 1.0),
|
|
("*/*", "q=0.1", 0.1)
|
|
]
|
|
),
|
|
("image/webp,*/*",
|
|
@[
|
|
("image/webp", "", 1.0),
|
|
("*/*", "", 1.0)
|
|
]
|
|
),
|
|
("*/*",
|
|
@[
|
|
("*/*", "", 1.0)
|
|
]
|
|
),
|
|
("image/png,image/*;q=0.8,*/*;q=0.5",
|
|
@[
|
|
("image/png", "", 1.0),
|
|
("image/*", "q=0.8", 0.8),
|
|
("*/*", "q=0.5", 0.5)
|
|
]
|
|
),
|
|
("image/webp,image/png,image/svg+xml,image/*;q=0.8,video/*;q=0.8,*/*;q=0.5",
|
|
@[
|
|
("image/webp", "", 1.0),
|
|
("image/png", "", 1.0),
|
|
("image/svg+xml", "", 1.0),
|
|
("image/*", "q=0.8", 0.8),
|
|
("video/*", "q=0.8", 0.8),
|
|
("*/*", "q=0.5", 0.5)
|
|
]
|
|
),
|
|
("image/png,image/svg+xml,image/*;q=0.8,video/*;q=0.8,*/*;q=0.5",
|
|
@[
|
|
("image/png", "", 1.0),
|
|
("image/svg+xml", "", 1.0),
|
|
("image/*", "q=0.8", 0.8),
|
|
("video/*", "q=0.8", 0.8),
|
|
("*/*", "q=0.5", 0.5)
|
|
]
|
|
),
|
|
("image/avif,image/webp,image/apng,image/*,*/*;q=0.8",
|
|
@[
|
|
("image/avif", "", 1.0),
|
|
("image/webp", "", 1.0),
|
|
("image/apng", "", 1.0),
|
|
("image/*", "", 1.0),
|
|
("*/*", "q=0.8", 0.8)
|
|
]
|
|
),
|
|
("image/png,image/svg+xml,image/*;q=0.8, */*;q=0.5",
|
|
@[
|
|
("image/png", "", 1.0),
|
|
("image/svg+xml", "", 1.0),
|
|
("image/*", "q=0.8", 0.8),
|
|
("*/*", "q=0.5", 0.5)
|
|
]
|
|
),
|
|
("video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5",
|
|
@[
|
|
("video/webm", "", 1.0),
|
|
("video/ogg", "", 1.0),
|
|
("video/*", "q=0.9", 0.9),
|
|
("application/ogg", "q=0.7", 0.7),
|
|
("audio/*", "q=0.6", 0.6),
|
|
("*/*", "q=0.5", 0.5)
|
|
]
|
|
),
|
|
("audio/webm,audio/ogg,audio/wav,audio/*;q=0.9,application/ogg;q=0.7,video/*;q=0.6,*/*;q=0.5",
|
|
@[
|
|
("audio/webm", "", 1.0),
|
|
("audio/ogg", "", 1.0),
|
|
("audio/wav", "", 1.0),
|
|
("audio/*", "q=0.9", 0.9),
|
|
("application/ogg", "q=0.7", 0.7),
|
|
("video/*", "q=0.6", 0.6),
|
|
("*/*", "q=0.5", 0.5)
|
|
]
|
|
),
|
|
("application/javascript, */*;q=0.8",
|
|
@[
|
|
("application/javascript", "", 1.0),
|
|
("*/*", "q=0.8", 0.8)
|
|
]
|
|
),
|
|
("text/css,*/*;q=0.1",
|
|
@[
|
|
("text/css", "", 1.0),
|
|
("*/*", "q=0.1", 0.1)
|
|
]
|
|
),
|
|
("text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1",
|
|
@[
|
|
("text/html", "", 1.0),
|
|
("application/xml", "q=0.9", 0.9),
|
|
("application/xhtml+xml", "", 1.0),
|
|
("image/png", "", 1.0),
|
|
("image/webp", "", 1.0),
|
|
("image/jpeg", "", 1.0),
|
|
("image/gif", "", 1.0),
|
|
("image/x-xbitmap", "", 1.0),
|
|
("*/*", "q=0.1", 0.1)
|
|
]
|
|
),
|
|
("",
|
|
@[
|
|
("*/*", "", 1.0)
|
|
]
|
|
)
|
|
]
|
|
|
|
for vector in SuccessVectors:
|
|
let info = getAcceptInfo(vector[0])
|
|
check info.isOk() == true
|
|
var items = info.get().data
|
|
check len(items) == len(vector[1])
|
|
var expects = vector[1]
|
|
for item in items:
|
|
let tocheck = ($item.mediaType, item.parameters(), item.qvalue)
|
|
let index = expects.find(tocheck)
|
|
check index >= 0
|
|
expects.del(index)
|
|
|
|
test "Q-value parser tests":
|
|
const FailureVectors = [
|
|
"1.0000", "0.0000", "2", "a", ".", "1#", "0#", "1.1", "1.2", "1.a",
|
|
"0.a", "1.01", "1.11", "1.10", "1.001", "1.010", "1.011", "1.100",
|
|
"1.101", "1.110", "1.111", "1.009", "0.00a", "0.0a0", "0.a00",
|
|
"1,", "1,0", "1,00", "1,000", "0,", "0,0", "0,00", "0,000", "0 ",
|
|
"0 00", "0 000", "1 000"
|
|
]
|
|
check:
|
|
getQvalue("1").tryGet() == 1.0
|
|
getQvalue("0").tryGet() == 0.0
|
|
getQvalue("1.").tryGet() == 1.0
|
|
getQvalue("0.").tryGet() == 0.0
|
|
getQvalue("1.0").tryGet() == 1.0
|
|
getQvalue("0.0").tryGet() == 0.0
|
|
getQvalue("1.00").tryGet() == 1.0
|
|
getQvalue("0.00").tryGet() == 0.0
|
|
getQvalue("1.000").tryGet() == 1.0
|
|
getQvalue("0.000").tryGet() == 0.0
|
|
|
|
for i in 0 ..< 1000:
|
|
let qres = getQvalue("0." & $i)
|
|
check qres.isOk() == true
|
|
|
|
for i in 1 ..< 1000:
|
|
let qres = getQvalue("1." & $i)
|
|
check qres.isErr() == true
|
|
|
|
for item in FailureVectors:
|
|
check getQvalue(item).isErr() == true
|
|
|
|
test "Media-type comparison tests":
|
|
check:
|
|
cmp(MediaType.init("*/*"), MediaType.init("*/*")) == 0
|
|
cmp(MediaType.init("application/json"), MediaType.init("*/*")) == 0
|
|
cmp(MediaType.init("*/*"), MediaType.init("application/json")) == 0
|
|
cmp(MediaType.init("*/json"), MediaType.init("*/*")) == 0
|
|
cmp(MediaType.init("*/*"), MediaType.init("*/json")) == 0
|
|
cmp(MediaType.init("application/*"), MediaType.init("*/*")) == 0
|
|
cmp(MediaType.init("*/*"), MediaType.init("application/*")) == 0
|
|
cmp(MediaType.init("application/*"), MediaType.init("*/json")) == 0
|
|
cmp(MediaType.init("*/json"), MediaType.init("application/*")) == 0
|
|
cmp(MediaType.init("application/json"),
|
|
MediaType.init("application/cbor")) != 0
|
|
cmp(MediaType.init("*/json"),
|
|
MediaType.init("application/cbor")) != 0
|
|
cmp(MediaType.init("application/cbor"),
|
|
MediaType.init("*/json")) != 0
|
|
|
|
test "Content-type selection tests":
|
|
const
|
|
jsonMediaType = MediaType.init("application/json")
|
|
sszMediaType = MediaType.init("application/octet-stream")
|
|
plainTextMediaType = MediaType.init("text/plain")
|
|
imageMediaType = MediaType.init("image/jpg")
|
|
|
|
singleHeader = @[
|
|
(
|
|
"application/json",
|
|
@[
|
|
"application/json"
|
|
]
|
|
)
|
|
]
|
|
|
|
acceptHeaders = [
|
|
("application/json, application/octet-stream",
|
|
@[
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"application/json"
|
|
]
|
|
),
|
|
("application/octet-stream, application/json",
|
|
@[
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"application/json"
|
|
]
|
|
),
|
|
("application/json;q=0.9, application/octet-stream",
|
|
@[
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/octet-stream",
|
|
"application/octet-stream",
|
|
"application/octet-stream",
|
|
"application/octet-stream"
|
|
]
|
|
),
|
|
("application/json, application/octet-stream;q=0.9",
|
|
@[
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"application/json",
|
|
"application/json",
|
|
"application/json"
|
|
]
|
|
),
|
|
("application/json;q=0.9, application/octet-stream;q=0.8",
|
|
@[
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"application/json",
|
|
"application/json",
|
|
"application/json"
|
|
]
|
|
),
|
|
("text/plain, application/octet-stream, application/json",
|
|
@[
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"application/json"
|
|
]
|
|
),
|
|
("text/plain, application/json;q=0.8, application/octet-stream;q=0.8",
|
|
@[
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"text/plain",
|
|
"text/plain"
|
|
]
|
|
),
|
|
("text/plain, application/json;q=0.8, application/octet-stream;q=0.5",
|
|
@[
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"application/json",
|
|
"text/plain",
|
|
"text/plain"
|
|
]
|
|
),
|
|
("text/plain;q=0.8, application/json, application/octet-stream;q=0.8",
|
|
@[
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"application/json",
|
|
"application/json",
|
|
"application/json"
|
|
]
|
|
),
|
|
("text/*, application/json, application/octet-stream",
|
|
@[
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"application/json"
|
|
]
|
|
),
|
|
("text/*, application/json;q=0.8, application/octet-stream;q=0.5",
|
|
@[
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"application/json",
|
|
"text/plain",
|
|
"text/plain"
|
|
]
|
|
),
|
|
("image/jpg, text/plain, application/octet-stream, application/json",
|
|
@[
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"image/jpg"
|
|
]
|
|
),
|
|
("image/jpg;q=1, text/plain;q=0.2, application/octet-stream;q=0.2, application/json;q=0.2",
|
|
@[
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"image/jpg"
|
|
]
|
|
),
|
|
("*/*",
|
|
@[
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"image/jpg"
|
|
]
|
|
),
|
|
(
|
|
"application/*",
|
|
@[
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"application/octet-stream",
|
|
"application/json",
|
|
"application/json"
|
|
]
|
|
)
|
|
]
|
|
|
|
for vector in singleHeader:
|
|
let res0 = selectContentType(getAcceptInfo(vector[0]).get().data, jsonMediaType)
|
|
let res1 = selectContentType(getAcceptInfo(vector[0]).get().data, sszMediaType)
|
|
let res2 = selectContentType(getAcceptInfo(vector[0]).get().data, jsonMediaType,
|
|
sszMediaType)
|
|
let res3 = selectContentType(getAcceptInfo(vector[0]).get().data, sszMediaType,
|
|
jsonMediaType)
|
|
let res4 = selectContentType(getAcceptInfo(vector[0]).get().data, jsonMediaType,
|
|
sszMediaType,
|
|
plainTextMediaType)
|
|
let res5 = selectContentType(getAcceptInfo(vector[0]).get().data, imageMediaType,
|
|
jsonMediaType,
|
|
sszMediaType,
|
|
plainTextMediaType)
|
|
check:
|
|
res0.isOk() == true
|
|
res1.isErr() == true
|
|
res2.isOk() == true
|
|
res3.isOk() == true
|
|
res4.isOk() == true
|
|
res5.isOk() == true
|
|
res0.get() == MediaType.init(vector[1][0])
|
|
res2.get() == MediaType.init(vector[1][0])
|
|
res3.get() == MediaType.init(vector[1][0])
|
|
res4.get() == MediaType.init(vector[1][0])
|
|
res5.get() == MediaType.init(vector[1][0])
|
|
|
|
for vector in acceptHeaders:
|
|
let res0 = selectContentType(getAcceptInfo(vector[0]).get().data, jsonMediaType)
|
|
let res1 = selectContentType(getAcceptInfo(vector[0]).get().data, sszMediaType)
|
|
let res2 = selectContentType(getAcceptInfo(vector[0]).get().data, jsonMediaType,
|
|
sszMediaType)
|
|
let res3 = selectContentType(getAcceptInfo(vector[0]).get().data, sszMediaType,
|
|
jsonMediaType)
|
|
let res4 = selectContentType(getAcceptInfo(vector[0]).get().data, jsonMediaType,
|
|
sszMediaType,
|
|
plainTextMediaType)
|
|
let res5 = selectContentType(getAcceptInfo(vector[0]).get().data, imageMediaType,
|
|
jsonMediaType,
|
|
sszMediaType,
|
|
plainTextMediaType)
|
|
check:
|
|
res0.isOk() == true
|
|
res1.isOk() == true
|
|
res2.isOk() == true
|
|
res3.isOk() == true
|
|
res4.isOk() == true
|
|
res5.isOk() == true
|
|
res0.get() == MediaType.init(vector[1][0])
|
|
res1.get() == MediaType.init(vector[1][1])
|
|
res2.get() == MediaType.init(vector[1][2])
|
|
res3.get() == MediaType.init(vector[1][3])
|
|
res4.get() == MediaType.init(vector[1][4])
|
|
res5.get() == MediaType.init(vector[1][5])
|
|
|
|
test "Content-Type header parser mime-types vectors test":
|
|
let filename = "tests/mimetypes.txt"
|
|
for line in filename.lines():
|
|
if len(line) != 0:
|
|
check:
|
|
getContentType(line).isOk()
|
|
getContentType(line & "; charset=utf-8").isOk()
|
|
getContentType(line & "; charset=\"utf-8\"").isOk()
|
|
|
|
test "Content-Type header parser test vectors":
|
|
|
|
const
|
|
Token = "!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyz" &
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
QdText =
|
|
"\t !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ" &
|
|
"[]^_`abcdefghijklmnopqrstuvwxyz{|}~" &
|
|
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F" &
|
|
"\x90\x91\x92\x93\x94\x95\x96\x97\x99\x99\x9A\x9B\x9C\x9D\x9E\x9F" &
|
|
"\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xAA\xA9\xAA\xAB\xAC\xAD\xAE\xAF" &
|
|
"\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xBB\xB9\xBA\xBB\xBC\xBD\xBE\xBF" &
|
|
"\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xCC\xC9\xCA\xCB\xCC\xCD\xCE\xCF" &
|
|
"\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xDD\xD9\xDA\xDB\xDC\xDD\xDE\xDF" &
|
|
"\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xEE\xE9\xEA\xEB\xEC\xEE\xEE\xEF" &
|
|
"\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xFF\xF9\xFA\xFB\xFC\xFF\xFE\xFF"
|
|
|
|
FailureVectors = [
|
|
"",
|
|
"\x7F",
|
|
"\x80",
|
|
"\xFF",
|
|
" ",
|
|
"\t",
|
|
"text",
|
|
"html",
|
|
"text/",
|
|
"text\\",
|
|
" text/html",
|
|
"\xFFtext/html",
|
|
"\x80text/html",
|
|
"\x7Ftext/html",
|
|
"tex\x7Ft/html",
|
|
"text/\xFFhtml",
|
|
"text/\x80html",
|
|
"text/\x7Fhtml",
|
|
"text/html;",
|
|
"text/html; ",
|
|
"text/html;a",
|
|
"text/html;\xFF",
|
|
"text/html;\x80",
|
|
"text/html;\x7F",
|
|
"text/html;a=;",
|
|
"text/html;a=b;b=c;c=d;",
|
|
"text/html;a=b;b=c;c=d; ",
|
|
"text/html;a=\"",
|
|
"text/html;a=\"\"\"",
|
|
"text/html;a=\x7F",
|
|
"text/html;a=\x80",
|
|
"text/html;a=\xFF",
|
|
"text/html;a=\x00",
|
|
"text/html;a=\x1F",
|
|
"text/html;a=\"\x00\"",
|
|
"text/html;a=\"\x1F\"",
|
|
"text/html;a= "
|
|
]
|
|
|
|
SuccessVectors = [
|
|
("text/html;a=", ("text/html",
|
|
@[("a", "")])),
|
|
("text/html", ("text/html",
|
|
@[])),
|
|
("text/html;a=\"\"", ("text/html",
|
|
@[("a", "")])),
|
|
("text/html;a=\"\\\\\"", ("text/html",
|
|
@[("a", "\\")])),
|
|
("text/html;a=\"\\\"\"", ("text/html",
|
|
@[("a", "\"")])),
|
|
("text/html;a=\"\\aa\"", ("text/html",
|
|
@[("a", "aa")])),
|
|
("text/html;a=\"\x80\xFF\"", ("text/html",
|
|
@[("a", "\x80\xFF")])),
|
|
("text/html;a=\"\t\"", ("text/html",
|
|
@[("a", "\t")])),
|
|
("text/html;a=\" \"", ("text/html",
|
|
@[("a", " ")])),
|
|
("text/html;a=b", ("text/html",
|
|
@[("a", "b")])),
|
|
("text/html;a=\"b\"", ("text/html",
|
|
@[("a", "b")])),
|
|
("text/html;a=b;b=c", ("text/html",
|
|
@[("a", "b"), ("b", "c")])),
|
|
("text/html;a=b;b=c;c=d", ("text/html",
|
|
@[("a", "b"), ("b", "c"), ("c", "d")])),
|
|
("text/html;a=;b=;c=", ("text/html",
|
|
@[("a", ""), ("b", ""), ("c", "")])),
|
|
("text/html;a=;b=c;c=d", ("text/html",
|
|
@[("a", ""), ("b", "c"), ("c", "d")])),
|
|
("text/html;a=b;b=;c=d", ("text/html",
|
|
@[("a", "b"), ("b", ""), ("c", "d")])),
|
|
("text/html;a=b;b=c;c=", ("text/html",
|
|
@[("a", "b"), ("b", "c"), ("c", "")])),
|
|
("text/html;a=;b=\"\";c=", ("text/html",
|
|
@[("a", ""), ("b", ""), ("c", "")])),
|
|
("text/html;a=;b=\"\";c=\"\"", ("text/html",
|
|
@[("a", ""), ("b", ""), ("c", "")]))
|
|
]
|
|
for item in FailureVectors:
|
|
check getContentType(item).isErr()
|
|
|
|
for item in SuccessVectors:
|
|
let res = getContentType(item[0])
|
|
check res.isOk()
|
|
let content = res.get()
|
|
check:
|
|
content.mediaType.media & "/" & content.mediaType.subtype == item[1][0]
|
|
let params = content.params
|
|
check:
|
|
len(params) == len(item[1][1])
|
|
for index, param in params.pairs():
|
|
check:
|
|
param[0] == item[1][1][index][0]
|
|
param[1] == item[1][1][index][1]
|
|
|
|
block:
|
|
# Token/Token; Token=Token; Token="QdText"
|
|
let contentType = Token & "/" & Token & "; " &
|
|
Token & "=" & Token & "; " &
|
|
Token & "=\"" & QdText & "\""
|
|
let res = getContentType(contentType)
|
|
check res.isOk()
|
|
let data = res.get()
|
|
check:
|
|
data.mediaType.media == Token
|
|
data.mediaType.subtype == Token
|
|
data.params[0] == (name: Token, value: Token)
|
|
data.params[1] == (name: Token, value: QdText)
|
|
|
|
test "isValid(MediaType) test":
|
|
let filename = "tests/mimetypes.txt"
|
|
for line in filename.lines():
|
|
if len(line) != 0:
|
|
check isValid(MediaType.init(line)) == true
|
|
check:
|
|
isValid(MediaType.init("*/*")) == true
|
|
isValid(MediaType.init("application/*")) == true
|
|
|
|
test "isWildCard(MediaType) test":
|
|
let filename = "tests/mimetypes.txt"
|
|
for line in filename.lines():
|
|
if len(line) != 0:
|
|
check isWildCard(MediaType.init(line)) == false
|
|
check:
|
|
isWildCard(MediaType.init("*/*")) == true
|
|
isWildCard(MediaType.init("text/*")) == true
|
|
isWildCard(MediaType.init("image/*")) == true
|
|
|
|
test "(ContentTypeData, MediaType) comparison":
|
|
let filename = "tests/mimetypes.txt"
|
|
for line in filename.lines():
|
|
if len(line) != 0:
|
|
let
|
|
contentType1 = getContentType(line & "; charset=utf-8").tryGet()
|
|
contentType2 = getContentType(line & "; charset=ISO-8859-1").tryGet()
|
|
mediaType = MediaType.init(line)
|
|
|
|
check:
|
|
contentType1 == mediaType
|
|
contentType2 == mediaType
|
|
contentType1 == MediaType.init("*/*")
|
|
|
|
test "(ContentTypeData, ContentTypeData) comparison":
|
|
let filename = "tests/mimetypes.txt"
|
|
for line in filename.lines():
|
|
if len(line) != 0:
|
|
let
|
|
contentType1 = getContentType(line).tryGet()
|
|
contentType2 = getContentType(line & "; charset=\"utf-8\"").tryGet()
|
|
contentType3 = getContentType(line & "; charset=utf-8").tryGet()
|
|
contentType4 = getContentType(line & "; ChArSeT=utf-8").tryGet()
|
|
contentType5 = getContentType(line & "; ChArSeT=UTF-8").tryGet()
|
|
contentType6 = getContentType(line & "; ChArSeT=ISO-8859-1").tryGet()
|
|
contentType7 = getContentType(line & "; ChArSeT=iso-8859-1").tryGet()
|
|
|
|
check:
|
|
contentType1 == contentType1
|
|
contentType1 != contentType2
|
|
contentType1 != contentType3
|
|
contentType1 != contentType4
|
|
contentType1 != contentType5
|
|
contentType1 != contentType6
|
|
contentType1 != contentType7
|
|
|
|
contentType2 == contentType2
|
|
contentType2 == contentType3
|
|
contentType2 == contentType4
|
|
contentType2 == contentType5
|
|
contentType2 != contentType6
|
|
contentType2 != contentType7
|
|
|
|
contentType3 == contentType3
|
|
contentType3 == contentType4
|
|
contentType3 == contentType5
|
|
contentType3 != contentType6
|
|
contentType3 != contentType7
|
|
|
|
contentType4 == contentType4
|
|
contentType4 == contentType5
|
|
contentType4 != contentType6
|
|
contentType4 != contentType7
|
|
|
|
contentType5 == contentType5
|
|
contentType5 != contentType6
|
|
contentType5 != contentType7
|
|
|
|
contentType6 == contentType6
|
|
contentType6 == contentType7
|
|
|
|
contentType7 == contentType7
|
|
|
|
test "ContenTypeData to string test":
|
|
let filename = "tests/mimetypes.txt"
|
|
for line in filename.lines():
|
|
if len(line) != 0:
|
|
let header = line & "; charset=\"utf-8\"; boundary=\"boundary\""
|
|
let
|
|
contentType1 = getContentType(
|
|
line & "; charset=utf-8; boundary=boundary").tryGet()
|
|
contentType2 = getContentType(line).tryGet()
|
|
check:
|
|
$contentType1 == header
|
|
$contentType2 == line
|
|
check:
|
|
$ContentTypeData(status: HttpStatus.Failure) == "<incomplete>"
|