Merge branch 'devel' of https://github.com/Araq/Nim into devel

Conflicts:
	compiler/semexprs.nim
This commit is contained in:
Araq 2015-01-07 02:44:22 +01:00
commit 65310266d8
46 changed files with 991 additions and 490 deletions

View file

@ -878,6 +878,10 @@ else:
let data = PData(info.key.data)
assert data.fd == info.key.fd.TAsyncFD
#echo("In poll ", data.fd.cint)
if EvError in info.events:
closeSocket(data.fd)
continue
if EvRead in info.events:
# Callback may add items to ``data.readCBs`` which causes issues if
# we are iterating over ``data.readCBs`` at the same time. We therefore

View file

@ -17,6 +17,8 @@
## as the response body.
##
## .. code-block::nim
## import asynchttpserver, asyncdispatch
##
## var server = newAsyncHttpServer()
## proc cb(req: Request) {.async.} =
## await req.respond(Http200, "Hello World")

View file

@ -32,21 +32,12 @@
## the server.
##
## .. code-block:: Nim
## var headers: string = "Content-Type: multipart/form-data; boundary=xyz\c\L"
## var body: string = "--xyz\c\L"
## # soap 1.2 output
## body.add("Content-Disposition: form-data; name=\"output\"\c\L")
## body.add("\c\Lsoap12\c\L")
## var data = newMultipartData()
## data["output"] = "soap12"
## data["uploaded_file"] = ("test.html", "text/html",
## "<html><head></head><body><p>test</p></body></html>")
##
## # html
## body.add("--xyz\c\L")
## body.add("Content-Disposition: form-data; name=\"uploaded_file\";" &
## " filename=\"test.html\"\c\L")
## body.add("Content-Type: text/html\c\L")
## body.add("\c\L<html><head></head><body><p>test</p></body></html>\c\L")
## body.add("--xyz--")
##
## echo(postContent("http://validator.w3.org/check", headers, body))
## echo postContent("http://validator.w3.org/check", multipart=data)
##
## Asynchronous HTTP requests
## ==========================
@ -88,7 +79,7 @@
## constructor should be used for this purpose. However,
## currently only basic authentication is supported.
import net, strutils, uri, parseutils, strtabs, base64, os
import net, strutils, uri, parseutils, strtabs, base64, os, mimetypes, math
import asyncnet, asyncdispatch
import rawsockets
@ -103,6 +94,10 @@ type
url*: Uri
auth*: string
MultipartEntries* = openarray[tuple[name, content: string]]
MultipartData* = ref object
content: seq[string]
ProtocolError* = object of IOError ## exception that is raised when server
## does not conform to the implemented
## protocol
@ -282,6 +277,109 @@ proc newProxy*(url: string, auth = ""): Proxy =
## Constructs a new ``TProxy`` object.
result = Proxy(url: parseUri(url), auth: auth)
proc newMultipartData*: MultipartData =
## Constructs a new ``MultipartData`` object.
MultipartData(content: @[])
proc add*(p: var MultipartData, name, content: string, filename: string = nil,
contentType: string = nil) =
## Add a value to the multipart data. Raises a `ValueError` exception if
## `name`, `filename` or `contentType` contain newline characters.
if {'\c','\L'} in name:
raise newException(ValueError, "name contains a newline character")
if filename != nil and {'\c','\L'} in filename:
raise newException(ValueError, "filename contains a newline character")
if contentType != nil and {'\c','\L'} in contentType:
raise newException(ValueError, "contentType contains a newline character")
var str = "Content-Disposition: form-data; name=\"" & name & "\""
if filename != nil:
str.add("; filename=\"" & filename & "\"")
str.add("\c\L")
if contentType != nil:
str.add("Content-Type: " & contentType & "\c\L")
str.add("\c\L" & content & "\c\L")
p.content.add(str)
proc add*(p: var MultipartData, xs: MultipartEntries): MultipartData
{.discardable.} =
## Add a list of multipart entries to the multipart data `p`. All values are
## added without a filename and without a content type.
##
## .. code-block:: Nim
## data.add({"action": "login", "format": "json"})
for name, content in xs.items:
p.add(name, content)
result = p
proc newMultipartData*(xs: MultipartEntries): MultipartData =
## Create a new multipart data object and fill it with the entries `xs`
## directly.
##
## .. code-block:: Nim
## var data = newMultipartData({"action": "login", "format": "json"})
result = MultipartData(content: @[])
result.add(xs)
proc addFiles*(p: var MultipartData, xs: openarray[tuple[name, file: string]]):
MultipartData {.discardable.} =
## Add files to a multipart data object. The file will be opened from your
## disk, read and sent with the automatically determined MIME type. Raises an
## `IOError` if the file cannot be opened or reading fails. To manually
## specify file content, filename and MIME type, use `[]=` instead.
##
## .. code-block:: Nim
## data.addFiles({"uploaded_file": "public/test.html"})
var m = newMimetypes()
for name, file in xs.items:
var contentType: string
let (dir, fName, ext) = splitFile(file)
if ext.len > 0:
contentType = m.getMimetype(ext[1..ext.high], nil)
p.add(name, readFile(file), fName & ext, contentType)
result = p
proc `[]=`*(p: var MultipartData, name, content: string) =
## Add a multipart entry to the multipart data `p`. The value is added
## without a filename and without a content type.
##
## .. code-block:: Nim
## data["username"] = "NimUser"
p.add(name, content)
proc `[]=`*(p: var MultipartData, name: string,
file: tuple[name, contentType, content: string]) =
## Add a file to the multipart data `p`, specifying filename, contentType and
## content manually.
##
## .. code-block:: Nim
## data["uploaded_file"] = ("test.html", "text/html",
## "<html><head></head><body><p>test</p></body></html>")
p.add(name, file.content, file.name, file.contentType)
proc format(p: MultipartData): tuple[header, body: string] =
if p == nil or p.content == nil or p.content.len == 0:
return ("", "")
# Create boundary that is not in the data to be formatted
var bound: string
while true:
bound = $random(int.high)
var found = false
for s in p.content:
if bound in s:
found = true
if not found:
break
result.header = "Content-Type: multipart/form-data; boundary=" & bound & "\c\L"
result.body = ""
for s in p.content:
result.body.add("--" & bound & "\c\L" & s)
result.body.add("--" & bound & "--\c\L")
proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
body = "",
sslContext: SSLContext = defaultSSLContext,
@ -294,7 +392,9 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
var r = if proxy == nil: parseUri(url) else: proxy.url
var headers = substr($httpMethod, len("http"))
if proxy == nil:
headers.add(" /" & r.path & r.query)
headers.add(" " & r.path)
if r.query.len > 0:
headers.add("?" & r.query)
else:
headers.add(" " & url)
@ -387,15 +487,30 @@ proc post*(url: string, extraHeaders = "", body = "",
maxRedirects = 5,
sslContext: SSLContext = defaultSSLContext,
timeout = -1, userAgent = defUserAgent,
proxy: Proxy = nil): Response =
proxy: Proxy = nil,
multipart: MultipartData = nil): Response =
## | POSTs ``body`` to the ``url`` and returns a ``Response`` object.
## | This proc adds the necessary Content-Length header.
## | This proc also handles redirection.
## | Extra headers can be specified and must be separated by ``\c\L``.
## | An optional timeout can be specified in miliseconds, if reading from the
## server takes longer than specified an ETimeout exception will be raised.
var xh = extraHeaders & "Content-Length: " & $len(body) & "\c\L"
result = request(url, httpPOST, xh, body, sslContext, timeout, userAgent,
## | The optional ``multipart`` parameter can be used to create
## ``multipart/form-data`` POSTs comfortably.
let (mpHeaders, mpBody) = format(multipart)
template withNewLine(x): expr =
if x.len > 0 and not x.endsWith("\c\L"):
x & "\c\L"
else:
x
var xb = mpBody.withNewLine() & body.withNewLine()
var xh = extraHeaders.withNewLine() & mpHeaders.withNewLine() &
withNewLine("Content-Length: " & $len(xb))
result = request(url, httpPOST, xh, xb, sslContext, timeout, userAgent,
proxy)
var lastUrl = ""
for i in 1..maxRedirects:
@ -410,14 +525,17 @@ proc postContent*(url: string, extraHeaders = "", body = "",
maxRedirects = 5,
sslContext: SSLContext = defaultSSLContext,
timeout = -1, userAgent = defUserAgent,
proxy: Proxy = nil): string =
proxy: Proxy = nil,
multipart: MultipartData = nil): string =
## | POSTs ``body`` to ``url`` and returns the response's body as a string
## | Raises exceptions for the status codes ``4xx`` and ``5xx``
## | Extra headers can be specified and must be separated by ``\c\L``.
## | An optional timeout can be specified in miliseconds, if reading from the
## server takes longer than specified an ETimeout exception will be raised.
## | The optional ``multipart`` parameter can be used to create
## ``multipart/form-data`` POSTs comfortably.
var r = post(url, extraHeaders, body, maxRedirects, sslContext, timeout,
userAgent, proxy)
userAgent, proxy, multipart)
if r.status[0] in {'4','5'}:
raise newException(HttpRequestError, r.status)
else:
@ -442,7 +560,9 @@ proc generateHeaders(r: Uri, httpMethod: HttpMethod,
headers: StringTableRef): string =
result = substr($httpMethod, len("http"))
# TODO: Proxies
result.add(" /" & r.path & r.query)
result.add(" " & r.path)
if r.query.len > 0:
result.add("?" & r.query)
result.add(" HTTP/1.1\c\L")
add(result, "Host: " & r.hostname & "\c\L")
@ -706,18 +826,9 @@ when isMainModule:
#var r = get("http://validator.w3.org/check?uri=http%3A%2F%2Fgoogle.com&
# charset=%28detect+automatically%29&doctype=Inline&group=0")
var headers: string = "Content-Type: multipart/form-data; boundary=xyz\c\L"
var body: string = "--xyz\c\L"
# soap 1.2 output
body.add("Content-Disposition: form-data; name=\"output\"\c\L")
body.add("\c\Lsoap12\c\L")
var data = newMultipartData()
data["output"] = "soap12"
data["uploaded_file"] = ("test.html", "text/html",
"<html><head></head><body><p>test</p></body></html>")
# html
body.add("--xyz\c\L")
body.add("Content-Disposition: form-data; name=\"uploaded_file\";" &
" filename=\"test.html\"\c\L")
body.add("Content-Type: text/html\c\L")
body.add("\c\L<html><head></head><body><p>test</p></body></html>\c\L")
body.add("--xyz--")
echo(postContent("http://validator.w3.org/check", headers, body))
echo postContent("http://validator.w3.org/check", multipart=data)

View file

@ -9,18 +9,20 @@
## Module for computing MD5 checksums.
type
MD5State = array[0..3, int32]
MD5Block = array[0..15, int32]
MD5CBits = array[0..7, int8]
MD5Digest* = array[0..15, int8]
MD5Buffer = array[0..63, int8]
MD5Context* {.final.} = object
import unsigned
type
MD5State = array[0..3, uint32]
MD5Block = array[0..15, uint32]
MD5CBits = array[0..7, uint8]
MD5Digest* = array[0..15, uint8]
MD5Buffer = array[0..63, uint8]
MD5Context* {.final.} = object
state: MD5State
count: array[0..1, int32]
count: array[0..1, uint32]
buffer: MD5Buffer
const
const
padding: cstring = "\x80\0\0\0" &
"\0\0\0\0\0\0\0\0" &
"\0\0\0\0\0\0\0\0" &
@ -31,60 +33,60 @@ const
"\0\0\0\0\0\0\0\0" &
"\0\0\0\0"
proc F(x, y, z: int32): int32 {.inline.} =
proc F(x, y, z: uint32): uint32 {.inline.} =
result = (x and y) or ((not x) and z)
proc G(x, y, z: int32): int32 {.inline.} =
proc G(x, y, z: uint32): uint32 {.inline.} =
result = (x and z) or (y and (not z))
proc H(x, y, z: int32): int32 {.inline.} =
proc H(x, y, z: uint32): uint32 {.inline.} =
result = x xor y xor z
proc I(x, y, z: int32): int32 {.inline.} =
proc I(x, y, z: uint32): uint32 {.inline.} =
result = y xor (x or (not z))
proc rot(x: var int32, n: int8) {.inline.} =
x = toU32(x shl ze(n)) or (x shr toU32(32 -% ze(n)))
proc rot(x: var uint32, n: uint8) {.inline.} =
x = (x shl n) or (x shr (32'u32 - n))
proc FF(a: var int32, b, c, d, x: int32, s: int8, ac: int32) =
a = a +% F(b, c, d) +% x +% ac
proc FF(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
a = a + F(b, c, d) + x + ac
rot(a, s)
a = a +% b
a = a + b
proc GG(a: var int32, b, c, d, x: int32, s: int8, ac: int32) =
a = a +% G(b, c, d) +% x +% ac
proc GG(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
a = a + G(b, c, d) + x + ac
rot(a, s)
a = a +% b
a = a + b
proc HH(a: var int32, b, c, d, x: int32, s: int8, ac: int32) =
a = a +% H(b, c, d) +% x +% ac
proc HH(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
a = a + H(b, c, d) + x + ac
rot(a, s)
a = a +% b
a = a + b
proc II(a: var int32, b, c, d, x: int32, s: int8, ac: int32) =
a = a +% I(b, c, d) +% x +% ac
proc II(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
a = a + I(b, c, d) + x + ac
rot(a, s)
a = a +% b
a = a + b
proc encode(dest: var MD5Block, src: cstring) =
proc encode(dest: var MD5Block, src: cstring) =
var j = 0
for i in 0..high(dest):
dest[i] = toU32(ord(src[j]) or
ord(src[j+1]) shl 8 or
ord(src[j+2]) shl 16 or
ord(src[j+3]) shl 24)
dest[i] = uint32(ord(src[j])) or
uint32(ord(src[j+1])) shl 8 or
uint32(ord(src[j+2])) shl 16 or
uint32(ord(src[j+3])) shl 24
inc(j, 4)
proc decode(dest: var openArray[int8], src: openArray[int32]) =
proc decode(dest: var openArray[uint8], src: openArray[uint32]) =
var i = 0
for j in 0..high(src):
dest[i] = toU8(src[j] and 0xff'i32)
dest[i+1] = toU8(src[j] shr 8'i32 and 0xff'i32)
dest[i+2] = toU8(src[j] shr 16'i32 and 0xff'i32)
dest[i+3] = toU8(src[j] shr 24'i32 and 0xff'i32)
dest[i] = src[j] and 0xff'u32
dest[i+1] = src[j] shr 8 and 0xff'u32
dest[i+2] = src[j] shr 16 and 0xff'u32
dest[i+3] = src[j] shr 24 and 0xff'u32
inc(i, 4)
proc transform(buffer: pointer, state: var MD5State) =
proc transform(buffer: pointer, state: var MD5State) =
var
myBlock: MD5Block
encode(myBlock, cast[cstring](buffer))
@ -92,111 +94,111 @@ proc transform(buffer: pointer, state: var MD5State) =
var b = state[1]
var c = state[2]
var d = state[3]
FF(a, b, c, d, myBlock[0], 7'i8, 0xD76AA478'i32)
FF(d, a, b, c, myBlock[1], 12'i8, 0xE8C7B756'i32)
FF(c, d, a, b, myBlock[2], 17'i8, 0x242070DB'i32)
FF(b, c, d, a, myBlock[3], 22'i8, 0xC1BDCEEE'i32)
FF(a, b, c, d, myBlock[4], 7'i8, 0xF57C0FAF'i32)
FF(d, a, b, c, myBlock[5], 12'i8, 0x4787C62A'i32)
FF(c, d, a, b, myBlock[6], 17'i8, 0xA8304613'i32)
FF(b, c, d, a, myBlock[7], 22'i8, 0xFD469501'i32)
FF(a, b, c, d, myBlock[8], 7'i8, 0x698098D8'i32)
FF(d, a, b, c, myBlock[9], 12'i8, 0x8B44F7AF'i32)
FF(c, d, a, b, myBlock[10], 17'i8, 0xFFFF5BB1'i32)
FF(b, c, d, a, myBlock[11], 22'i8, 0x895CD7BE'i32)
FF(a, b, c, d, myBlock[12], 7'i8, 0x6B901122'i32)
FF(d, a, b, c, myBlock[13], 12'i8, 0xFD987193'i32)
FF(c, d, a, b, myBlock[14], 17'i8, 0xA679438E'i32)
FF(b, c, d, a, myBlock[15], 22'i8, 0x49B40821'i32)
GG(a, b, c, d, myBlock[1], 5'i8, 0xF61E2562'i32)
GG(d, a, b, c, myBlock[6], 9'i8, 0xC040B340'i32)
GG(c, d, a, b, myBlock[11], 14'i8, 0x265E5A51'i32)
GG(b, c, d, a, myBlock[0], 20'i8, 0xE9B6C7AA'i32)
GG(a, b, c, d, myBlock[5], 5'i8, 0xD62F105D'i32)
GG(d, a, b, c, myBlock[10], 9'i8, 0x02441453'i32)
GG(c, d, a, b, myBlock[15], 14'i8, 0xD8A1E681'i32)
GG(b, c, d, a, myBlock[4], 20'i8, 0xE7D3FBC8'i32)
GG(a, b, c, d, myBlock[9], 5'i8, 0x21E1CDE6'i32)
GG(d, a, b, c, myBlock[14], 9'i8, 0xC33707D6'i32)
GG(c, d, a, b, myBlock[3], 14'i8, 0xF4D50D87'i32)
GG(b, c, d, a, myBlock[8], 20'i8, 0x455A14ED'i32)
GG(a, b, c, d, myBlock[13], 5'i8, 0xA9E3E905'i32)
GG(d, a, b, c, myBlock[2], 9'i8, 0xFCEFA3F8'i32)
GG(c, d, a, b, myBlock[7], 14'i8, 0x676F02D9'i32)
GG(b, c, d, a, myBlock[12], 20'i8, 0x8D2A4C8A'i32)
HH(a, b, c, d, myBlock[5], 4'i8, 0xFFFA3942'i32)
HH(d, a, b, c, myBlock[8], 11'i8, 0x8771F681'i32)
HH(c, d, a, b, myBlock[11], 16'i8, 0x6D9D6122'i32)
HH(b, c, d, a, myBlock[14], 23'i8, 0xFDE5380C'i32)
HH(a, b, c, d, myBlock[1], 4'i8, 0xA4BEEA44'i32)
HH(d, a, b, c, myBlock[4], 11'i8, 0x4BDECFA9'i32)
HH(c, d, a, b, myBlock[7], 16'i8, 0xF6BB4B60'i32)
HH(b, c, d, a, myBlock[10], 23'i8, 0xBEBFBC70'i32)
HH(a, b, c, d, myBlock[13], 4'i8, 0x289B7EC6'i32)
HH(d, a, b, c, myBlock[0], 11'i8, 0xEAA127FA'i32)
HH(c, d, a, b, myBlock[3], 16'i8, 0xD4EF3085'i32)
HH(b, c, d, a, myBlock[6], 23'i8, 0x04881D05'i32)
HH(a, b, c, d, myBlock[9], 4'i8, 0xD9D4D039'i32)
HH(d, a, b, c, myBlock[12], 11'i8, 0xE6DB99E5'i32)
HH(c, d, a, b, myBlock[15], 16'i8, 0x1FA27CF8'i32)
HH(b, c, d, a, myBlock[2], 23'i8, 0xC4AC5665'i32)
II(a, b, c, d, myBlock[0], 6'i8, 0xF4292244'i32)
II(d, a, b, c, myBlock[7], 10'i8, 0x432AFF97'i32)
II(c, d, a, b, myBlock[14], 15'i8, 0xAB9423A7'i32)
II(b, c, d, a, myBlock[5], 21'i8, 0xFC93A039'i32)
II(a, b, c, d, myBlock[12], 6'i8, 0x655B59C3'i32)
II(d, a, b, c, myBlock[3], 10'i8, 0x8F0CCC92'i32)
II(c, d, a, b, myBlock[10], 15'i8, 0xFFEFF47D'i32)
II(b, c, d, a, myBlock[1], 21'i8, 0x85845DD1'i32)
II(a, b, c, d, myBlock[8], 6'i8, 0x6FA87E4F'i32)
II(d, a, b, c, myBlock[15], 10'i8, 0xFE2CE6E0'i32)
II(c, d, a, b, myBlock[6], 15'i8, 0xA3014314'i32)
II(b, c, d, a, myBlock[13], 21'i8, 0x4E0811A1'i32)
II(a, b, c, d, myBlock[4], 6'i8, 0xF7537E82'i32)
II(d, a, b, c, myBlock[11], 10'i8, 0xBD3AF235'i32)
II(c, d, a, b, myBlock[2], 15'i8, 0x2AD7D2BB'i32)
II(b, c, d, a, myBlock[9], 21'i8, 0xEB86D391'i32)
state[0] = state[0] +% a
state[1] = state[1] +% b
state[2] = state[2] +% c
state[3] = state[3] +% d
proc md5Init*(c: var MD5Context) =
## initializes a MD5Context
c.state[0] = 0x67452301'i32
c.state[1] = 0xEFCDAB89'i32
c.state[2] = 0x98BADCFE'i32
c.state[3] = 0x10325476'i32
c.count[0] = 0'i32
c.count[1] = 0'i32
FF(a, b, c, d, myBlock[0], 7'u8, 0xD76AA478'u32)
FF(d, a, b, c, myBlock[1], 12'u8, 0xE8C7B756'u32)
FF(c, d, a, b, myBlock[2], 17'u8, 0x242070DB'u32)
FF(b, c, d, a, myBlock[3], 22'u8, 0xC1BDCEEE'u32)
FF(a, b, c, d, myBlock[4], 7'u8, 0xF57C0FAF'u32)
FF(d, a, b, c, myBlock[5], 12'u8, 0x4787C62A'u32)
FF(c, d, a, b, myBlock[6], 17'u8, 0xA8304613'u32)
FF(b, c, d, a, myBlock[7], 22'u8, 0xFD469501'u32)
FF(a, b, c, d, myBlock[8], 7'u8, 0x698098D8'u32)
FF(d, a, b, c, myBlock[9], 12'u8, 0x8B44F7AF'u32)
FF(c, d, a, b, myBlock[10], 17'u8, 0xFFFF5BB1'u32)
FF(b, c, d, a, myBlock[11], 22'u8, 0x895CD7BE'u32)
FF(a, b, c, d, myBlock[12], 7'u8, 0x6B901122'u32)
FF(d, a, b, c, myBlock[13], 12'u8, 0xFD987193'u32)
FF(c, d, a, b, myBlock[14], 17'u8, 0xA679438E'u32)
FF(b, c, d, a, myBlock[15], 22'u8, 0x49B40821'u32)
GG(a, b, c, d, myBlock[1], 5'u8, 0xF61E2562'u32)
GG(d, a, b, c, myBlock[6], 9'u8, 0xC040B340'u32)
GG(c, d, a, b, myBlock[11], 14'u8, 0x265E5A51'u32)
GG(b, c, d, a, myBlock[0], 20'u8, 0xE9B6C7AA'u32)
GG(a, b, c, d, myBlock[5], 5'u8, 0xD62F105D'u32)
GG(d, a, b, c, myBlock[10], 9'u8, 0x02441453'u32)
GG(c, d, a, b, myBlock[15], 14'u8, 0xD8A1E681'u32)
GG(b, c, d, a, myBlock[4], 20'u8, 0xE7D3FBC8'u32)
GG(a, b, c, d, myBlock[9], 5'u8, 0x21E1CDE6'u32)
GG(d, a, b, c, myBlock[14], 9'u8, 0xC33707D6'u32)
GG(c, d, a, b, myBlock[3], 14'u8, 0xF4D50D87'u32)
GG(b, c, d, a, myBlock[8], 20'u8, 0x455A14ED'u32)
GG(a, b, c, d, myBlock[13], 5'u8, 0xA9E3E905'u32)
GG(d, a, b, c, myBlock[2], 9'u8, 0xFCEFA3F8'u32)
GG(c, d, a, b, myBlock[7], 14'u8, 0x676F02D9'u32)
GG(b, c, d, a, myBlock[12], 20'u8, 0x8D2A4C8A'u32)
HH(a, b, c, d, myBlock[5], 4'u8, 0xFFFA3942'u32)
HH(d, a, b, c, myBlock[8], 11'u8, 0x8771F681'u32)
HH(c, d, a, b, myBlock[11], 16'u8, 0x6D9D6122'u32)
HH(b, c, d, a, myBlock[14], 23'u8, 0xFDE5380C'u32)
HH(a, b, c, d, myBlock[1], 4'u8, 0xA4BEEA44'u32)
HH(d, a, b, c, myBlock[4], 11'u8, 0x4BDECFA9'u32)
HH(c, d, a, b, myBlock[7], 16'u8, 0xF6BB4B60'u32)
HH(b, c, d, a, myBlock[10], 23'u8, 0xBEBFBC70'u32)
HH(a, b, c, d, myBlock[13], 4'u8, 0x289B7EC6'u32)
HH(d, a, b, c, myBlock[0], 11'u8, 0xEAA127FA'u32)
HH(c, d, a, b, myBlock[3], 16'u8, 0xD4EF3085'u32)
HH(b, c, d, a, myBlock[6], 23'u8, 0x04881D05'u32)
HH(a, b, c, d, myBlock[9], 4'u8, 0xD9D4D039'u32)
HH(d, a, b, c, myBlock[12], 11'u8, 0xE6DB99E5'u32)
HH(c, d, a, b, myBlock[15], 16'u8, 0x1FA27CF8'u32)
HH(b, c, d, a, myBlock[2], 23'u8, 0xC4AC5665'u32)
II(a, b, c, d, myBlock[0], 6'u8, 0xF4292244'u32)
II(d, a, b, c, myBlock[7], 10'u8, 0x432AFF97'u32)
II(c, d, a, b, myBlock[14], 15'u8, 0xAB9423A7'u32)
II(b, c, d, a, myBlock[5], 21'u8, 0xFC93A039'u32)
II(a, b, c, d, myBlock[12], 6'u8, 0x655B59C3'u32)
II(d, a, b, c, myBlock[3], 10'u8, 0x8F0CCC92'u32)
II(c, d, a, b, myBlock[10], 15'u8, 0xFFEFF47D'u32)
II(b, c, d, a, myBlock[1], 21'u8, 0x85845DD1'u32)
II(a, b, c, d, myBlock[8], 6'u8, 0x6FA87E4F'u32)
II(d, a, b, c, myBlock[15], 10'u8, 0xFE2CE6E0'u32)
II(c, d, a, b, myBlock[6], 15'u8, 0xA3014314'u32)
II(b, c, d, a, myBlock[13], 21'u8, 0x4E0811A1'u32)
II(a, b, c, d, myBlock[4], 6'u8, 0xF7537E82'u32)
II(d, a, b, c, myBlock[11], 10'u8, 0xBD3AF235'u32)
II(c, d, a, b, myBlock[2], 15'u8, 0x2AD7D2BB'u32)
II(b, c, d, a, myBlock[9], 21'u8, 0xEB86D391'u32)
state[0] = state[0] + a
state[1] = state[1] + b
state[2] = state[2] + c
state[3] = state[3] + d
proc md5Init*(c: var MD5Context) =
## initializes a MD5Context
c.state[0] = 0x67452301'u32
c.state[1] = 0xEFCDAB89'u32
c.state[2] = 0x98BADCFE'u32
c.state[3] = 0x10325476'u32
c.count[0] = 0'u32
c.count[1] = 0'u32
zeroMem(addr(c.buffer), sizeof(MD5buffer))
proc md5Update*(c: var MD5Context, input: cstring, len: int) =
proc md5Update*(c: var MD5Context, input: cstring, len: int) =
## updates the MD5Context with the `input` data of length `len`
var input = input
var Index = (c.count[0] shr 3) and 0x3F
c.count[0] = c.count[0] +% toU32(len shl 3)
if c.count[0] < (len shl 3): c.count[1] = c.count[1] +% 1'i32
c.count[1] = c.count[1] +% toU32(len shr 29)
var Index = int((c.count[0] shr 3) and 0x3F)
c.count[0] = c.count[0] + (uint32(len) shl 3)
if c.count[0] < (uint32(len) shl 3): c.count[1] = c.count[1] + 1'u32
c.count[1] = c.count[1] + (uint32(len) shr 29)
var PartLen = 64 - Index
if len >= PartLen:
if len >= PartLen:
copyMem(addr(c.buffer[Index]), input, PartLen)
transform(addr(c.buffer), c.state)
var i = PartLen
while i + 63 < len:
while i + 63 < len:
transform(addr(input[i]), c.state)
inc(i, 64)
copyMem(addr(c.buffer[0]), addr(input[i]), len-i)
else:
copyMem(addr(c.buffer[Index]), addr(input[0]), len)
proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
## finishes the MD5Context and stores the result in `digest`
var
Bits: MD5CBits
PadLen: int
decode(Bits, c.count)
var Index = (c.count[0] shr 3) and 0x3F
var Index = int((c.count[0] shr 3) and 0x3F)
if Index < 56: PadLen = 56 - Index
else: PadLen = 120 - Index
md5Update(c, padding, PadLen)
@ -204,34 +206,34 @@ proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
decode(digest, c.state)
zeroMem(addr(c), sizeof(MD5Context))
proc toMD5*(s: string): MD5Digest =
proc toMD5*(s: string): MD5Digest =
## computes the MD5Digest value for a string `s`
var c: MD5Context
md5Init(c)
md5Update(c, cstring(s), len(s))
md5Final(c, result)
proc `$`*(D: MD5Digest): string =
proc `$`*(D: MD5Digest): string =
## converts a MD5Digest value into its string representation
const digits = "0123456789abcdef"
result = ""
for i in 0..15:
for i in 0..15:
add(result, digits[(D[i] shr 4) and 0xF])
add(result, digits[D[i] and 0xF])
proc getMD5*(s: string): string =
proc getMD5*(s: string): string =
## computes an MD5 value of `s` and returns its string representation
var
var
c: MD5Context
d: MD5Digest
md5Init(c)
md5Update(c, cstring(s), len(s))
md5Final(c, d)
result = $d
proc `==`*(D1, D2: MD5Digest): bool =
proc `==`*(D1, D2: MD5Digest): bool =
## checks if two MD5Digest values are identical
for i in 0..15:
for i in 0..15:
if D1[i] != D2[i]: return false
return true
@ -241,5 +243,3 @@ when isMainModule:
assert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") ==
"7e716d0e702df0505fc72e2b89467910")
assert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e")

View file

@ -23,7 +23,7 @@ proc `$`*(x: SocketHandle): string {.borrow.}
type
Event* = enum
EvRead, EvWrite
EvRead, EvWrite, EvError
SelectorKey* = ref object
fd*: SocketHandle
@ -146,12 +146,19 @@ elif defined(linux):
## on the ``fd``.
result = @[]
let evNum = epoll_wait(s.epollFD, addr s.events[0], 64.cint, timeout.cint)
if evNum < 0: raiseOSError(osLastError())
if evNum < 0:
let err = osLastError()
if err.cint == EINTR:
return @[]
raiseOSError(osLastError())
if evNum == 0: return @[]
for i in 0 .. <evNum:
let fd = s.events[i].data.fd.SocketHandle
var evSet: set[Event] = {}
if (s.events[i].events and EPOLLERR) != 0: evSet = evSet + {EvError}
if (s.events[i].events and EPOLLHUP) != 0: evSet = evSet + {EvError}
if (s.events[i].events and EPOLLRDHUP) != 0: evSet = evSet + {EvError}
if (s.events[i].events and EPOLLIN) != 0: evSet = evSet + {EvRead}
if (s.events[i].events and EPOLLOUT) != 0: evSet = evSet + {EvWrite}
let selectorKey = s.fds[fd]

View file

@ -1,7 +1,7 @@
#
#
# Nim's Runtime Library
# (c) Copyright 2012 Nim Contributors
# (c) Copyright 2015 Nim Contributors
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@ -9,12 +9,27 @@
## :Author: Zahary Karadjov
##
## This module implements the standard unit testing facilities such as
## suites, fixtures and test cases as well as facilities for combinatorial
## and randomzied test case generation (not yet available)
## and object mocking (not yet available)
## This module implements boilerplate to make testing easy.
##
## It is loosely based on C++'s boost.test and Haskell's QuickTest
## Example:
##
## .. code:: nim
##
## suite "description for this stuff":
## test "essential truths":
## # give up and stop if this fails
## require(true)
##
## test "slightly less obvious stuff":
## # print a nasty message and move on, skipping
## # the remainder of this block
## check(1 != 1)
## check("asd"[2] == 'd')
##
## test "out of bounds error is thrown on bad access":
## let v = @[1, 2, 3] # you can do initialization here
## expect(IndexError):
## discard v[4]
import
macros
@ -209,3 +224,5 @@ if envOutLvl.len > 0:
if $opt == envOutLvl:
outputLevel = opt
break
system.addQuitProc(resetAttributes)

View file

@ -16,6 +16,7 @@ type
Uri* = object
scheme*, username*, password*: string
hostname*, port*, path*, query*, anchor*: string
opaque*: bool
{.deprecated: [TUrl: Url, TUri: Uri].}
@ -115,6 +116,8 @@ proc parseUri*(uri: string): Uri =
if authority == "":
raise newException(ValueError, "Expected authority got nothing.")
parseAuthority(authority, result)
else:
result.opaque = true
# Path
parsePath(uri, i, result)
@ -256,7 +259,10 @@ proc `$`*(u: Uri): string =
result = ""
if u.scheme.len > 0:
result.add(u.scheme)
result.add("://")
if u.opaque:
result.add(":")
else:
result.add("://")
if u.username.len > 0:
result.add(u.username)
if u.password.len > 0:
@ -268,22 +274,28 @@ proc `$`*(u: Uri): string =
result.add(":")
result.add(u.port)
if u.path.len > 0:
if u.path[0] != '/': result.add("/")
result.add(u.path)
result.add(u.query)
result.add(u.anchor)
if u.query.len > 0:
result.add("?")
result.add(u.query)
if u.anchor.len > 0:
result.add("#")
result.add(u.anchor)
when isMainModule:
block:
let test = parseUri("http://localhost:8080/test")
let str = "http://localhost:8080/test"
let test = parseUri(str)
doAssert test.scheme == "http"
doAssert test.port == "8080"
doAssert test.path == "/test"
doAssert test.hostname == "localhost"
doAssert($test == str)
block:
let test = parseUri("foo://username:password@example.com:8042/over/there" &
"/index.dtb?type=animal&name=narwhal#nose")
let str = "foo://username:password@example.com:8042/over/there" &
"/index.dtb?type=animal&name=narwhal#nose"
let test = parseUri(str)
doAssert test.scheme == "foo"
doAssert test.username == "username"
doAssert test.password == "password"
@ -292,34 +304,45 @@ when isMainModule:
doAssert test.path == "/over/there/index.dtb"
doAssert test.query == "type=animal&name=narwhal"
doAssert test.anchor == "nose"
doAssert($test == str)
block:
let test = parseUri("urn:example:animal:ferret:nose")
let str = "urn:example:animal:ferret:nose"
let test = parseUri(str)
doAssert test.scheme == "urn"
doAssert test.path == "example:animal:ferret:nose"
doAssert($test == str)
block:
let test = parseUri("mailto:username@example.com?subject=Topic")
let str = "mailto:username@example.com?subject=Topic"
let test = parseUri(str)
doAssert test.scheme == "mailto"
doAssert test.username == "username"
doAssert test.hostname == "example.com"
doAssert test.query == "subject=Topic"
doAssert($test == str)
block:
let test = parseUri("magnet:?xt=urn:sha1:72hsga62ba515sbd62&dn=foobar")
let str = "magnet:?xt=urn:sha1:72hsga62ba515sbd62&dn=foobar"
let test = parseUri(str)
doAssert test.scheme == "magnet"
doAssert test.query == "xt=urn:sha1:72hsga62ba515sbd62&dn=foobar"
doAssert($test == str)
block:
let test = parseUri("/test/foo/bar?q=2#asdf")
let str = "/test/foo/bar?q=2#asdf"
let test = parseUri(str)
doAssert test.scheme == ""
doAssert test.path == "/test/foo/bar"
doAssert test.query == "q=2"
doAssert test.anchor == "asdf"
doAssert($test == str)
block:
let test = parseUri("test/no/slash")
let str = "test/no/slash"
let test = parseUri(str)
doAssert test.path == "test/no/slash"
doAssert($test == str)
# Remove dot segments tests
block:
@ -371,5 +394,3 @@ when isMainModule:
block:
let test = parseUri("http://example.com/foo/") / "/bar/asd"
doAssert test.path == "/foo/bar/asd"

View file

@ -49,7 +49,7 @@ type
waMarkGlobal, # part of the backup/debug mark&sweep
waMarkPrecise, # part of the backup/debug mark&sweep
waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack,
waCollectWhite,
waCollectWhite #, waDebug
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
# A ref type can have a finalizer that is called before the object's
@ -595,9 +595,15 @@ proc scan(s: PCell) =
else:
s.setColor(rcWhite)
forAllChildren(s, waScan)
proc collectWhite(s: PCell) =
if s.color == rcWhite and s notin gch.cycleRoots:
# This is a hacky way to deal with the following problem (bug #1796)
# Consider this content in cycleRoots:
# x -> a; y -> a where 'a' is an acyclic object so not included in
# cycleRoots itself. Then 'collectWhite' used to free 'a' twice. The
# 'isAllocatedPtr' check prevents this. This also means we do not need
# to query 's notin gch.cycleRoots' at all.
if isAllocatedPtr(gch.region, s) and s.color == rcWhite:
s.setColor(rcBlack)
forAllChildren(s, waCollectWhite)
freeCyclicCell(gch, s)
@ -648,6 +654,28 @@ when useMarkForDebug or useBackupGc:
if objStart != nil:
markS(gch, objStart)
when logGC:
var
cycleCheckA: array[100, PCell]
cycleCheckALen = 0
proc alreadySeen(c: PCell): bool =
for i in 0 .. <cycleCheckALen:
if cycleCheckA[i] == c: return true
if cycleCheckALen == len(cycleCheckA):
gcAssert(false, "cycle detection overflow")
quit 1
cycleCheckA[cycleCheckALen] = c
inc cycleCheckALen
proc debugGraph(s: PCell) =
if alreadySeen(s):
writeCell("child cell (already seen) ", s)
else:
writeCell("cell {", s)
forAllChildren(s, waDebug)
c_fprintf(c_stdout, "}\n")
proc doOperation(p: pointer, op: TWalkOp) =
if p == nil: return
var c: PCell = usrToCell(p)
@ -690,6 +718,7 @@ proc doOperation(p: pointer, op: TWalkOp) =
of waMarkPrecise:
when useMarkForDebug or useBackupGc:
add(gch.tempStack, c)
#of waDebug: debugGraph(c)
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
doOperation(d, TWalkOp(op))
@ -702,7 +731,6 @@ when useMarkForDebug or useBackupGc:
proc collectRoots(gch: var TGcHeap) =
for s in elements(gch.cycleRoots):
excl(gch.cycleRoots, s)
collectWhite(s)
proc collectCycles(gch: var TGcHeap) =

View file

@ -1344,7 +1344,7 @@ when not defined(useNimRtl):
else:
dec(gch.recGcLock)
proc GC_setStrategy(strategy: TGC_Strategy) =
proc GC_setStrategy(strategy: GC_Strategy) =
case strategy
of gcThroughput: nil
of gcResponsiveness: nil

View file

@ -144,7 +144,7 @@ when defined(boehmgc):
proc GC_disable() = boehmGC_disable()
proc GC_enable() = boehmGC_enable()
proc GC_fullCollect() = boehmGCfullCollect()
proc GC_setStrategy(strategy: TGC_Strategy) = discard
proc GC_setStrategy(strategy: GC_Strategy) = discard
proc GC_enableMarkAndSweep() = discard
proc GC_disableMarkAndSweep() = discard
proc GC_getStatistics(): string = return ""
@ -221,7 +221,7 @@ elif defined(nogc) and defined(useMalloc):
proc GC_disable() = discard
proc GC_enable() = discard
proc GC_fullCollect() = discard
proc GC_setStrategy(strategy: TGC_Strategy) = discard
proc GC_setStrategy(strategy: GC_Strategy) = discard
proc GC_enableMarkAndSweep() = discard
proc GC_disableMarkAndSweep() = discard
proc GC_getStatistics(): string = return ""
@ -281,7 +281,7 @@ elif defined(nogc):
proc GC_disable() = discard
proc GC_enable() = discard
proc GC_fullCollect() = discard
proc GC_setStrategy(strategy: TGC_Strategy) = discard
proc GC_setStrategy(strategy: GC_Strategy) = discard
proc GC_enableMarkAndSweep() = discard
proc GC_disableMarkAndSweep() = discard
proc GC_getStatistics(): string = return ""

View file

@ -12,7 +12,7 @@
when defined(Unix):
const
lib = "libmysqlclient.so.15"
lib = "libmysqlclient.so.(15|16|17|18)"
when defined(Windows):
const
lib = "libmysql.dll"

View file

@ -50,7 +50,7 @@ when useWinVersion:
from winlean import SocketHandle
else:
const
versions = "(|.1.0.0|.0.9.9|.0.9.8|.0.9.7|.0.9.6|.0.9.5|.0.9.4)"
versions = "(.10|.1.0.1|.1.0.0|.0.9.9|.0.9.8|.0.9.7|.0.9.6|.0.9.5|.0.9.4)"
when defined(macosx):
const
DLLSSLName = "libssl" & versions & ".dylib"