Merge branch 'devel' into fix_time_offset_in_times_js

This commit is contained in:
Konstantin Molchanov 2017-03-29 16:54:36 +04:00 • committed by GitHub
commit 04646052ab
10 changed files with 97 additions and 48 deletions

View file

@ -133,8 +133,8 @@ doc.file = """<?xml version="1.0" encoding="utf-8" ?>
<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/> <link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
<!-- Google fonts --> <!-- Google fonts -->
<link href='http://fonts.googleapis.com/css?family=Raleway:400,600,900' rel='stylesheet' type='text/css'/> <link href='https://fonts.googleapis.com/css?family=Raleway:400,600,900' rel='stylesheet' type='text/css'/>
<link href='http://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/> <link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
<!-- CSS --> <!-- CSS -->
<title>$title</title> <title>$title</title>

View file

@ -130,6 +130,16 @@ type
readOnly*: bool readOnly*: bool
options*: seq[OptionElement] options*: seq[OptionElement]
# https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
HtmlElement* = ref object of Element
contentEditable*: string
isContentEditable*: bool
dir*: string
offsetHeight*: int
offsetWidth*: int
offsetLeft*: int
offsetTop*: int
LinkElement* = ref LinkObj LinkElement* = ref LinkObj
LinkObj {.importc.} = object of ElementObj LinkObj {.importc.} = object of ElementObj
target*: cstring target*: cstring
@ -270,6 +280,8 @@ type
wordSpacing*: cstring wordSpacing*: cstring
zIndex*: int zIndex*: int
# TODO: A lot of the fields in Event belong to a more specific type of event.
# TODO: Should we clean this up?
Event* = ref EventObj Event* = ref EventObj
EventObj {.importc.} = object of RootObj EventObj {.importc.} = object of RootObj
target*: Node target*: Node
@ -310,6 +322,20 @@ type
SUBMIT*: int SUBMIT*: int
UNLOAD*: int UNLOAD*: int
TouchList* {.importc.} = ref object of RootObj
length*: int
TouchEvent* {.importc.} = ref object of Event
changedTouches*, targetTouches*, touches*: TouchList
Touch* {.importc.} = ref object of RootObj
identifier*: int
screenX*, screenY*, clientX*, clientY*, pageX*, pageY*: int
target*: Element
radiusX*, radiusY*: int
rotationAngle*: int
force*: float
Location* = ref LocationObj Location* = ref LocationObj
LocationObj {.importc.} = object of RootObj LocationObj {.importc.} = object of RootObj
hash*: cstring hash*: cstring
@ -488,6 +514,10 @@ proc setAttribute*(s: Style, attr, value: cstring, caseSensitive=false)
# Event "methods" # Event "methods"
proc preventDefault*(ev: Event) proc preventDefault*(ev: Event)
# TouchEvent "methods"
proc identifiedTouch*(list: TouchList): Touch
proc item*(list: TouchList, i: int): Touch
{.pop.} {.pop.}
var var

View file

@ -109,12 +109,17 @@ type
Dirent* {.importc: "struct dirent", Dirent* {.importc: "struct dirent",
header: "<dirent.h>", final, pure.} = object ## dirent_t struct header: "<dirent.h>", final, pure.} = object ## dirent_t struct
d_ino*: Ino ## File serial number. d_ino*: Ino ## File serial number.
when defined(linux) or defined(macosx) or defined(bsd): when defined(dragonfly):
# DragonflyBSD doesn't have `d_reclen` field.
d_type*: uint8
elif defined(linux) or defined(macosx) or defined(freebsd) or
defined(netbsd) or defined(openbsd):
d_reclen*: cshort ## Length of this record. (not POSIX) d_reclen*: cshort ## Length of this record. (not POSIX)
d_type*: int8 ## Type of file; not supported by all filesystem types. d_type*: int8 ## Type of file; not supported by all filesystem types.
## (not POSIX) ## (not POSIX)
when defined(linux) or defined(bsd): when defined(linux) or defined(openbsd):
d_off*: Off ## Not an offset. Value that ``telldir()`` would return. d_off*: Off ## Not an offset. Value that ``telldir()`` would return.
d_name*: array[0..255, char] ## Name of entry. d_name*: array[0..255, char] ## Name of entry.
Tflock* {.importc: "struct flock", final, pure, Tflock* {.importc: "struct flock", final, pure,

View file

@ -36,6 +36,9 @@ import httpcore
export httpcore except parseHeader export httpcore except parseHeader
const
maxLine = 8*1024
# TODO: If it turns out that the decisions that asynchttpserver makes # TODO: If it turns out that the decisions that asynchttpserver makes
# explicitly, about whether to close the client sockets or upgrade them are # explicitly, about whether to close the client sockets or upgrade them are
# wrong, then add a return value which determines what to do for the callback. # wrong, then add a return value which determines what to do for the callback.
@ -97,6 +100,18 @@ proc respond*(req: Request, code: HttpCode, content: string,
if headers != nil: if headers != nil:
msg.addHeaders(headers) msg.addHeaders(headers)
msg.add("Content-Length: ")
# this particular way saves allocations:
msg.add content.len
msg.add "\c\L\c\L"
msg.add(content)
result = req.client.send(msg)
proc respondError(req: Request, code: HttpCode): Future[void] =
## Responds to the request with the specified ``HttpCode``.
let content = $code
var msg = "HTTP/1.1 " & content & "\c\L"
msg.add("Content-Length: " & $content.len & "\c\L\c\L") msg.add("Content-Length: " & $content.len & "\c\L\c\L")
msg.add(content) msg.add(content)
result = req.client.send(msg) result = req.client.send(msg)
@ -139,12 +154,16 @@ proc processClient(client: AsyncSocket, address: string,
for i in 0..1: for i in 0..1:
lineFut.mget().setLen(0) lineFut.mget().setLen(0)
lineFut.clean() lineFut.clean()
await client.recvLineInto(lineFut) # TODO: Timeouts. await client.recvLineInto(lineFut, maxLength=maxLine) # TODO: Timeouts.
if lineFut.mget == "": if lineFut.mget == "":
client.close() client.close()
return return
if lineFut.mget.len > maxLine:
await request.respondError(Http413)
client.close()
return
if lineFut.mget != "\c\L": if lineFut.mget != "\c\L":
break break
@ -157,19 +176,17 @@ proc processClient(client: AsyncSocket, address: string,
# TODO: this is likely slow. # TODO: this is likely slow.
request.reqMethod = parseEnum[HttpMethod]("http" & linePart) request.reqMethod = parseEnum[HttpMethod]("http" & linePart)
except ValueError: except ValueError:
asyncCheck request.respond(Http400, "Invalid request method. Got: " & asyncCheck request.respondError(Http400)
linePart)
continue continue
of 1: parseUri(linePart, request.url) of 1: parseUri(linePart, request.url)
of 2: of 2:
try: try:
request.protocol = parseProtocol(linePart) request.protocol = parseProtocol(linePart)
except ValueError: except ValueError:
asyncCheck request.respond(Http400, asyncCheck request.respondError(Http400)
"Invalid request protocol. Got: " & linePart)
continue continue
else: else:
await request.respond(Http400, "Invalid request. Got: " & lineFut.mget) await request.respondError(Http400)
continue continue
inc i inc i
@ -178,10 +195,13 @@ proc processClient(client: AsyncSocket, address: string,
i = 0 i = 0
lineFut.mget.setLen(0) lineFut.mget.setLen(0)
lineFut.clean() lineFut.clean()
await client.recvLineInto(lineFut) await client.recvLineInto(lineFut, maxLength=maxLine)
if lineFut.mget == "": if lineFut.mget == "":
client.close(); return client.close(); return
if lineFut.mget.len > maxLine:
await request.respondError(Http413)
client.close(); return
if lineFut.mget == "\c\L": break if lineFut.mget == "\c\L": break
let (key, value) = parseHeader(lineFut.mget) let (key, value) = parseHeader(lineFut.mget)
request.headers[key] = value request.headers[key] = value

View file

@ -40,6 +40,8 @@ template createCb(retFutureSym, iteratorNameSym,
else: else:
next.callback = cb next.callback = cb
except: except:
futureVarCompletions
if retFutureSym.finished: if retFutureSym.finished:
# Take a look at tasyncexceptions for the bug which this fixes. # Take a look at tasyncexceptions for the bug which this fixes.
# That test explains it better than I can here. # That test explains it better than I can here.
@ -47,7 +49,6 @@ template createCb(retFutureSym, iteratorNameSym,
else: else:
retFutureSym.fail(getCurrentException()) retFutureSym.fail(getCurrentException())
futureVarCompletions
cb() cb()
#{.pop.} #{.pop.}
proc generateExceptionCheck(futSym, proc generateExceptionCheck(futSym,
@ -123,12 +124,16 @@ template createVar(result: var NimNode, futSymName: string,
result.add newVarStmt(futSym, asyncProc) # -> var future<x> = y result.add newVarStmt(futSym, asyncProc) # -> var future<x> = y
useVar(result, futSym, valueReceiver, rootReceiver, fromNode) useVar(result, futSym, valueReceiver, rootReceiver, fromNode)
proc createFutureVarCompletions(futureVarIdents: seq[NimNode]): NimNode proc createFutureVarCompletions(futureVarIdents: seq[NimNode],
{.compileTime.} = fromNode: NimNode): NimNode {.compileTime.} =
result = newStmtList() result = newNimNode(nnkStmtList, fromNode)
# Add calls to complete each FutureVar parameter. # Add calls to complete each FutureVar parameter.
for ident in futureVarIdents: for ident in futureVarIdents:
# Only complete them if they have not been completed already by the user. # Only complete them if they have not been completed already by the user.
# TODO: Once https://github.com/nim-lang/Nim/issues/5617 is fixed.
# TODO: Add line info to the complete() call!
# In the meantime, this was really useful for debugging :)
#result.add(newCall(newIdentNode("echo"), newStrLitNode(fromNode.lineinfo)))
result.add newIfStmt( result.add newIfStmt(
( (
newCall(newIdentNode("not"), newCall(newIdentNode("not"),
@ -145,6 +150,10 @@ proc processBody(node, retFutureSym: NimNode,
case node.kind case node.kind
of nnkReturnStmt: of nnkReturnStmt:
result = newNimNode(nnkStmtList, node) result = newNimNode(nnkStmtList, node)
# As I've painfully found out, the order here really DOES matter.
result.add createFutureVarCompletions(futureVarIdents, node)
if node[0].kind == nnkEmpty: if node[0].kind == nnkEmpty:
if not subTypeIsVoid: if not subTypeIsVoid:
result.add newCall(newIdentNode("complete"), retFutureSym, result.add newCall(newIdentNode("complete"), retFutureSym,
@ -158,8 +167,6 @@ proc processBody(node, retFutureSym: NimNode,
else: else:
result.add newCall(newIdentNode("complete"), retFutureSym, x) result.add newCall(newIdentNode("complete"), retFutureSym, x)
result.add createFutureVarCompletions(futureVarIdents)
result.add newNimNode(nnkReturnStmt, node).add(newNilLit()) result.add newNimNode(nnkReturnStmt, node).add(newNilLit())
return # Don't process the children of this return stmt return # Don't process the children of this return stmt
of nnkCommand, nnkCall: of nnkCommand, nnkCall:
@ -347,6 +354,8 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
futureVarIdents, nil) futureVarIdents, nil)
# don't do anything with forward bodies (empty) # don't do anything with forward bodies (empty)
if procBody.kind != nnkEmpty: if procBody.kind != nnkEmpty:
procBody.add(createFutureVarCompletions(futureVarIdents, nil))
if not subtypeIsVoid: if not subtypeIsVoid:
procBody.insert(0, newNimNode(nnkPragma).add(newIdentNode("push"), procBody.insert(0, newNimNode(nnkPragma).add(newIdentNode("push"),
newNimNode(nnkExprColonExpr).add(newNimNode(nnkBracketExpr).add( newNimNode(nnkExprColonExpr).add(newNimNode(nnkBracketExpr).add(
@ -366,8 +375,6 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
# -> complete(retFuture) # -> complete(retFuture)
procBody.add(newCall(newIdentNode("complete"), retFutureSym)) procBody.add(newCall(newIdentNode("complete"), retFutureSym))
procBody.add(createFutureVarCompletions(futureVarIdents))
var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")], var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
procBody, nnkIteratorDef) procBody, nnkIteratorDef)
closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure")) closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure"))
@ -377,7 +384,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
#var cbName = newIdentNode("cb") #var cbName = newIdentNode("cb")
var procCb = getAst createCb(retFutureSym, iteratorNameSym, var procCb = getAst createCb(retFutureSym, iteratorNameSym,
newStrLitNode(prc[0].getName), newStrLitNode(prc[0].getName),
createFutureVarCompletions(futureVarIdents)) createFutureVarCompletions(futureVarIdents, nil))
outerProcBody.add procCb outerProcBody.add procCb
# -> return retFuture # -> return retFuture
@ -398,7 +405,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
if procBody.kind != nnkEmpty: if procBody.kind != nnkEmpty:
result[6] = outerProcBody result[6] = outerProcBody
#echo(treeRepr(result)) #echo(treeRepr(result))
#if prc[0].getName == "beta": #if prc[0].getName == "recvLineInto":
# echo(toStrLit(result)) # echo(toStrLit(result))
macro async*(prc: untyped): untyped = macro async*(prc: untyped): untyped =

View file

@ -464,8 +464,7 @@ proc recvLineInto*(socket: AsyncSocket, resString: FutureVar[string],
## The partial line **will be lost**. ## The partial line **will be lost**.
## ##
## The ``maxLength`` parameter determines the maximum amount of characters ## The ``maxLength`` parameter determines the maximum amount of characters
## that can be read before a ``ValueError`` is raised. This prevents Denial ## that can be read. ``resString`` will be truncated after that.
## of Service (DOS) attacks.
## ##
## **Warning**: The ``Peek`` flag is not yet implemented. ## **Warning**: The ``Peek`` flag is not yet implemented.
## ##
@ -519,10 +518,7 @@ proc recvLineInto*(socket: AsyncSocket, resString: FutureVar[string],
socket.currPos.inc() socket.currPos.inc()
# Verify that this isn't a DOS attack: #3847. # Verify that this isn't a DOS attack: #3847.
if resString.mget.len > maxLength: if resString.mget.len > maxLength: break
let msg = "recvLine received more than the specified `maxLength` " &
"allowed."
raise newException(ValueError, msg)
else: else:
var c = "" var c = ""
while true: while true:
@ -546,10 +542,7 @@ proc recvLineInto*(socket: AsyncSocket, resString: FutureVar[string],
resString.mget.add c resString.mget.add c
# Verify that this isn't a DOS attack: #3847. # Verify that this isn't a DOS attack: #3847.
if resString.mget.len > maxLength: if resString.mget.len > maxLength: break
let msg = "recvLine received more than the specified `maxLength` " &
"allowed."
raise newException(ValueError, msg)
resString.complete() resString.complete()
proc recvLine*(socket: AsyncSocket, proc recvLine*(socket: AsyncSocket,
@ -569,8 +562,7 @@ proc recvLine*(socket: AsyncSocket,
## The partial line **will be lost**. ## The partial line **will be lost**.
## ##
## The ``maxLength`` parameter determines the maximum amount of characters ## The ``maxLength`` parameter determines the maximum amount of characters
## that can be read before a ``ValueError`` is raised. This prevents Denial ## that can be read. The result is truncated after that.
## of Service (DOS) attacks.
## ##
## **Warning**: The ``Peek`` flag is not yet implemented. ## **Warning**: The ``Peek`` flag is not yet implemented.
## ##

View file

@ -418,7 +418,7 @@ proc spawn*(call: expr): expr {.magic: "Spawn".}
proc pinnedSpawn*(id: ThreadId; call: expr): expr {.magic: "Spawn".} proc pinnedSpawn*(id: ThreadId; call: expr): expr {.magic: "Spawn".}
## always spawns a new task on the worker thread with ``id``, so that ## always spawns a new task on the worker thread with ``id``, so that
## the 'call' is **always** executed on ## the 'call' is **always** executed on
## the this thread. 'call' has to be proc call 'p(...)' where 'p' ## the thread. 'call' has to be proc call 'p(...)' where 'p'
## is gcsafe and has a return type that is either 'void' or compatible ## is gcsafe and has a return type that is either 'void' or compatible
## with ``FlowVar[T]``. ## with ``FlowVar[T]``.

View file

@ -285,7 +285,7 @@ proc `$`*(code: HttpCode): string =
proc `==`*(a, b: HttpCode): bool {.borrow.} proc `==`*(a, b: HttpCode): bool {.borrow.}
proc `==`*(rawCode: string, code: HttpCode): bool = proc `==`*(rawCode: string, code: HttpCode): bool =
return rawCode.toLower() == ($code).toLower() return cmpIgnoreCase(rawCode, $code) == 0
proc is2xx*(code: HttpCode): bool = proc is2xx*(code: HttpCode): bool =
## Determines whether ``code`` is a 2xx HTTP status code. ## Determines whether ``code`` is a 2xx HTTP status code.
@ -304,7 +304,7 @@ proc is5xx*(code: HttpCode): bool =
return code.int in {500 .. 599} return code.int in {500 .. 599}
proc `$`*(httpMethod: HttpMethod): string = proc `$`*(httpMethod: HttpMethod): string =
return (system.`$`(httpMethod))[4 .. ^1].toUpper() return (system.`$`(httpMethod))[4 .. ^1].toUpperAscii()
when isMainModule: when isMainModule:
var test = newHttpHeaders() var test = newHttpHeaders()

View file

@ -1010,8 +1010,7 @@ proc readLine*(socket: Socket, line: var TaintedString, timeout = -1,
## the specified time an ETimeout exception will be raised. ## the specified time an ETimeout exception will be raised.
## ##
## The ``maxLength`` parameter determines the maximum amount of characters ## The ``maxLength`` parameter determines the maximum amount of characters
## that can be read before a ``ValueError`` is raised. This prevents Denial ## that can be read. The result is truncated after that.
## of Service (DOS) attacks.
## ##
## **Warning**: Only the ``SafeDisconn`` flag is currently supported. ## **Warning**: Only the ``SafeDisconn`` flag is currently supported.
@ -1047,10 +1046,7 @@ proc readLine*(socket: Socket, line: var TaintedString, timeout = -1,
add(line.string, c) add(line.string, c)
# Verify that this isn't a DOS attack: #3847. # Verify that this isn't a DOS attack: #3847.
if line.string.len > maxLength: if line.string.len > maxLength: break
let msg = "recvLine received more than the specified `maxLength` " &
"allowed."
raise newException(ValueError, msg)
proc recvLine*(socket: Socket, timeout = -1, proc recvLine*(socket: Socket, timeout = -1,
flags = {SocketFlag.SafeDisconn}, flags = {SocketFlag.SafeDisconn},
@ -1069,8 +1065,7 @@ proc recvLine*(socket: Socket, timeout = -1,
## the specified time an ETimeout exception will be raised. ## the specified time an ETimeout exception will be raised.
## ##
## The ``maxLength`` parameter determines the maximum amount of characters ## The ``maxLength`` parameter determines the maximum amount of characters
## that can be read before a ``ValueError`` is raised. This prevents Denial ## that can be read. The result is truncated after that.
## of Service (DOS) attacks.
## ##
## **Warning**: Only the ``SafeDisconn`` flag is currently supported. ## **Warning**: Only the ``SafeDisconn`` flag is currently supported.
result = "" result = ""

View file

@ -508,8 +508,8 @@ else:
freeAddrInfo(aiList) freeAddrInfo(aiList)
# for some reason Windows select doesn't return both # for some reason Windows select doesn't return both
# descriptors from first call, so we need to make 2 calls # descriptors from first call, so we need to make 2 calls
discard selector.select(100) discard selector.select(1000)
var rcm = selector.select(100) var rcm = selector.select(1000)
assert(len(rcm) == 2) assert(len(rcm) == 2)
var sockAddress = SockAddr() var sockAddress = SockAddr()
@ -526,7 +526,7 @@ else:
selector.updateHandle(client_socket, {Event.Read}) selector.updateHandle(client_socket, {Event.Read})
var rc2 = selector.select(100) var rc2 = selector.select(1000)
assert(len(rc2) == 1) assert(len(rc2) == 1)
var read_count = recv(server2_socket, addr buffer[0], 128, 0) var read_count = recv(server2_socket, addr buffer[0], 128, 0)
@ -595,7 +595,7 @@ else:
proc event_wait_thread(event: SelectEvent) {.thread.} = proc event_wait_thread(event: SelectEvent) {.thread.} =
var selector = newSelector[int]() var selector = newSelector[int]()
selector.registerEvent(event, 1) selector.registerEvent(event, 1)
var rc = selector.select(500) var rc = selector.select(1500)
if len(rc) == 1: if len(rc) == 1:
inc(counter) inc(counter)
selector.unregister(event) selector.unregister(event)