added system.del; delete; insert
This commit is contained in:
parent
e22c73fd89
commit
6ecbed7284
5 changed files with 93 additions and 34 deletions
|
|
@ -17,7 +17,7 @@ type
|
||||||
TResponse* = tuple[
|
TResponse* = tuple[
|
||||||
version: string, status: string, headers: seq[THeader],
|
version: string, status: string, headers: seq[THeader],
|
||||||
body: string]
|
body: string]
|
||||||
THeader* = tuple[htype: string, hvalue: string]
|
THeader* = tuple[htype, hvalue: string]
|
||||||
|
|
||||||
EInvalidProtocol* = object of EBase ## exception that is raised when server
|
EInvalidProtocol* = object of EBase ## exception that is raised when server
|
||||||
## does not conform to the implemented
|
## does not conform to the implemented
|
||||||
|
|
@ -54,20 +54,49 @@ proc getHeaderValue*(headers: seq[THeader], name: string): string =
|
||||||
return headers[i].hvalue
|
return headers[i].hvalue
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
proc parseChunks(data: var string, start: int, s: TSocket): string =
|
proc charAt(d: var string, i: var int, s: TSocket): char {.inline.} =
|
||||||
|
result = d[i]
|
||||||
|
while result == '\0':
|
||||||
|
d = s.recv()
|
||||||
|
i = 0
|
||||||
|
result = d[i]
|
||||||
|
|
||||||
|
proc parseChunks(d: var string, start: int, s: TSocket): string =
|
||||||
# get chunks:
|
# get chunks:
|
||||||
var i = start
|
var i = start
|
||||||
result = ""
|
result = ""
|
||||||
while true:
|
while true:
|
||||||
var chunkSize = 0
|
var chunkSize = 0
|
||||||
var j = parseHex(data, chunkSize, i)
|
var digitFound = false
|
||||||
if j <= 0: break
|
echo "number: ", copy(d, i, i + 10)
|
||||||
inc(i, j)
|
while true:
|
||||||
while data[i] notin {'\C', '\L', '\0'}: inc(i)
|
case d[i]
|
||||||
if data[i] == '\C': inc(i)
|
of '0'..'9':
|
||||||
if data[i] == '\L': inc(i)
|
digitFound = true
|
||||||
if chunkSize <= 0: break
|
chunkSize = chunkSize shl 4 or (ord(d[i]) - ord('0'))
|
||||||
var x = copy(data, i, i+chunkSize-1)
|
of 'a'..'f':
|
||||||
|
digitFound = true
|
||||||
|
chunkSize = chunkSize shl 4 or (ord(d[i]) - ord('a') + 10)
|
||||||
|
of 'A'..'F':
|
||||||
|
digitFound = true
|
||||||
|
chunkSize = chunkSize shl 4 or (ord(d[i]) - ord('A') + 10)
|
||||||
|
of '\0':
|
||||||
|
d = s.recv()
|
||||||
|
i = -1
|
||||||
|
else: break
|
||||||
|
inc(i)
|
||||||
|
|
||||||
|
echo "chunksize: ", chunkSize
|
||||||
|
if chunkSize <= 0:
|
||||||
|
echo copy(d, i)
|
||||||
|
assert digitFound
|
||||||
|
break
|
||||||
|
while charAt(d, i, s) notin {'\C', '\L', '\0'}: inc(i)
|
||||||
|
if charAt(d, i, s) == '\C': inc(i)
|
||||||
|
if charAt(d, i, s) == '\L': inc(i)
|
||||||
|
else: httpError("CR-LF after chunksize expected")
|
||||||
|
|
||||||
|
var x = copy(d, i, i+chunkSize-1)
|
||||||
var size = x.len
|
var size = x.len
|
||||||
result.add(x)
|
result.add(x)
|
||||||
|
|
||||||
|
|
@ -82,18 +111,17 @@ proc parseChunks(data: var string, start: int, s: TSocket): string =
|
||||||
dec(missing, bytesRead)
|
dec(missing, bytesRead)
|
||||||
|
|
||||||
# next chunk:
|
# next chunk:
|
||||||
data = s.recv()
|
d = s.recv()
|
||||||
i = 0
|
i = 0
|
||||||
# skip trailing CR-LF:
|
# skip trailing CR-LF:
|
||||||
while data[i] in {'\C', '\L'}: inc(i)
|
while charAt(d, i, s) in {'\C', '\L'}: inc(i)
|
||||||
if data[i] == '\0': data.add(s.recv())
|
|
||||||
|
|
||||||
proc parseBody(data: var string, start: int, s: TSocket,
|
proc parseBody(d: var string, start: int, s: TSocket,
|
||||||
headers: seq[THeader]): string =
|
headers: seq[THeader]): string =
|
||||||
if getHeaderValue(headers, "Transfer-Encoding") == "chunked":
|
if getHeaderValue(headers, "Transfer-Encoding") == "chunked":
|
||||||
result = parseChunks(data, start, s)
|
result = parseChunks(d, start, s)
|
||||||
else:
|
else:
|
||||||
result = copy(data, start)
|
result = copy(d, start)
|
||||||
# -REGION- Content-Length
|
# -REGION- Content-Length
|
||||||
# (http://tools.ietf.org/html/rfc2616#section-4.4) NR.3
|
# (http://tools.ietf.org/html/rfc2616#section-4.4) NR.3
|
||||||
var contentLengthHeader = getHeaderValue(headers, "Content-Length")
|
var contentLengthHeader = getHeaderValue(headers, "Content-Length")
|
||||||
|
|
@ -112,7 +140,7 @@ proc parseBody(data: var string, start: int, s: TSocket,
|
||||||
result.add(moreData)
|
result.add(moreData)
|
||||||
|
|
||||||
proc parseResponse(s: TSocket): TResponse =
|
proc parseResponse(s: TSocket): TResponse =
|
||||||
var data = s.recv()
|
var d = s.recv()
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
||||||
# Parse the version
|
# Parse the version
|
||||||
|
|
@ -120,7 +148,7 @@ proc parseResponse(s: TSocket): TResponse =
|
||||||
# ``HTTP/1.1`` 200 OK
|
# ``HTTP/1.1`` 200 OK
|
||||||
|
|
||||||
var matches: array[0..1, string]
|
var matches: array[0..1, string]
|
||||||
var L = data.matchLen(peg"\i 'HTTP/' {'1.1'/'1.0'} \s+ {(!\n .)*}\n",
|
var L = d.matchLen(peg"\i 'HTTP/' {'1.1'/'1.0'} \s+ {(!\n .)*}\n",
|
||||||
matches, i)
|
matches, i)
|
||||||
if L < 0: httpError("invalid HTTP header")
|
if L < 0: httpError("invalid HTTP header")
|
||||||
|
|
||||||
|
|
@ -135,29 +163,29 @@ proc parseResponse(s: TSocket): TResponse =
|
||||||
result.headers = @[]
|
result.headers = @[]
|
||||||
while true:
|
while true:
|
||||||
var key = ""
|
var key = ""
|
||||||
while data[i] != ':':
|
while d[i] != ':':
|
||||||
if data[i] == '\0': httpError("invalid HTTP header, ':' expected")
|
if d[i] == '\0': httpError("invalid HTTP header, ':' expected")
|
||||||
key.add(data[i])
|
key.add(d[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
inc(i) # skip ':'
|
inc(i) # skip ':'
|
||||||
if data[i] == ' ': inc(i) # skip if the character is a space
|
if d[i] == ' ': inc(i) # skip if the character is a space
|
||||||
var val = ""
|
var val = ""
|
||||||
while data[i] notin {'\C', '\L', '\0'}:
|
while d[i] notin {'\C', '\L', '\0'}:
|
||||||
val.add(data[i])
|
val.add(d[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
||||||
result.headers.add((key, val))
|
result.headers.add((key, val))
|
||||||
|
|
||||||
if data[i] == '\C': inc(i)
|
if d[i] == '\C': inc(i)
|
||||||
if data[i] == '\L': inc(i)
|
if d[i] == '\L': inc(i)
|
||||||
else: httpError("invalid HTTP header, CR-LF expected")
|
else: httpError("invalid HTTP header, CR-LF expected")
|
||||||
|
|
||||||
if data[i] == '\C': inc(i)
|
if d[i] == '\C': inc(i)
|
||||||
if data[i] == '\L':
|
if d[i] == '\L':
|
||||||
inc(i)
|
inc(i)
|
||||||
break
|
break
|
||||||
|
|
||||||
result.body = parseBody(data, i, s, result.headers)
|
result.body = parseBody(d, i, s, result.headers)
|
||||||
|
|
||||||
proc request*(url: string): TResponse =
|
proc request*(url: string): TResponse =
|
||||||
var r = parse(url)
|
var r = parse(url)
|
||||||
|
|
@ -169,6 +197,8 @@ proc request*(url: string): TResponse =
|
||||||
headers = "GET / HTTP/1.1\c\L"
|
headers = "GET / HTTP/1.1\c\L"
|
||||||
|
|
||||||
add(headers, "Host: " & r.hostname & "\c\L\c\L")
|
add(headers, "Host: " & r.hostname & "\c\L\c\L")
|
||||||
|
add(headers, "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; pl;" &
|
||||||
|
" rv:1.9.2) Gecko/20100115 Firefox/3.6")
|
||||||
|
|
||||||
var s = socket()
|
var s = socket()
|
||||||
s.connect(r.hostname, TPort(80))
|
s.connect(r.hostname, TPort(80))
|
||||||
|
|
@ -210,4 +240,7 @@ proc downloadFile*(url: string, outputFilename: string) =
|
||||||
|
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
downloadFile("http://www.google.com", "GoogleTest.html")
|
#downloadFile("http://force7.de/nimrod/index.html", "nimrodindex.html")
|
||||||
|
#downloadFile("http://www.httpwatch.com/", "ChunkTest.html")
|
||||||
|
downloadFile("http://www.httpwatch.com/httpgallery/chunked/", "ChunkTest.html")
|
||||||
|
|
||||||
|
|
|
||||||
0
lib/pure/parseutils.nim
Normal file → Executable file
0
lib/pure/parseutils.nim
Normal file → Executable file
|
|
@ -321,8 +321,8 @@ proc parseEntity(my: var TXmlParser, dest: var string) =
|
||||||
elif buf[pos] == 'g' and buf[pos+1] == 't' and buf[pos+2] == ';':
|
elif buf[pos] == 'g' and buf[pos+1] == 't' and buf[pos+2] == ';':
|
||||||
add(dest, '>')
|
add(dest, '>')
|
||||||
inc(pos, 2)
|
inc(pos, 2)
|
||||||
elif buf[pos] == 'a' and buf[pos+1] == 'm' and buf[pos+2] == 'p'
|
elif buf[pos] == 'a' and buf[pos+1] == 'm' and buf[pos+2] == 'p' and
|
||||||
and buf[pos+3] == ';':
|
buf[pos+3] == ';':
|
||||||
add(dest, '&')
|
add(dest, '&')
|
||||||
inc(pos, 3)
|
inc(pos, 3)
|
||||||
elif buf[pos] == 'a' and buf[pos+1] == 'p' and buf[pos+2] == 'o' and
|
elif buf[pos] == 'a' and buf[pos+1] == 'p' and buf[pos+2] == 'o' and
|
||||||
|
|
|
||||||
|
|
@ -698,6 +698,31 @@ proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
|
||||||
setLen(x, xl + y.len)
|
setLen(x, xl + y.len)
|
||||||
for i in 0..high(y): x[xl+i] = y[i]
|
for i in 0..high(y): x[xl+i] = y[i]
|
||||||
|
|
||||||
|
proc del* [T](x: var seq[T], i: int) {.noSideEffect.} =
|
||||||
|
## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
|
||||||
|
## This is an O(1) operation.
|
||||||
|
var xl = x.len
|
||||||
|
x[i] = x[xl-1]
|
||||||
|
setLen(x, xl-1)
|
||||||
|
|
||||||
|
proc delete*[T](x: var seq[T], i: int) {.noSideEffect.} =
|
||||||
|
## deletes the item at index `i` by moving ``x[i+1..]`` by one position.
|
||||||
|
## This is an O(n) operation.
|
||||||
|
var xl = x.len
|
||||||
|
for j in i..xl-2: x[j] = x[j+1]
|
||||||
|
setLen(x, xl-1)
|
||||||
|
|
||||||
|
proc insert*[T](x: var seq[T], item: T, i = 0) {.noSideEffect.} =
|
||||||
|
## inserts `item` into `x` at position `i`.
|
||||||
|
var xl = x.len
|
||||||
|
setLen(x, xl+1)
|
||||||
|
var j = xl-1
|
||||||
|
while j >= i:
|
||||||
|
x[j+1] = x[j]
|
||||||
|
inc(j)
|
||||||
|
x[i] = item
|
||||||
|
|
||||||
|
|
||||||
proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.}
|
proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.}
|
||||||
## takes any Nimrod variable and returns its string representation. It
|
## takes any Nimrod variable and returns its string representation. It
|
||||||
## works even for complex data graphs with cycles. This is a great
|
## works even for complex data graphs with cycles. This is a great
|
||||||
|
|
|
||||||
|
|
@ -311,7 +311,8 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int, maxRecDepth: int)
|
||||||
toRope("align"), toRope(n.align),
|
toRope("align"), toRope(n.align),
|
||||||
toRope("sons"), result])
|
toRope("sons"), result])
|
||||||
|
|
||||||
proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int, maxRecDepth: int): PRope =
|
proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int,
|
||||||
|
maxRecDepth: int): PRope =
|
||||||
var istr: PRope
|
var istr: PRope
|
||||||
if n == nil:
|
if n == nil:
|
||||||
result = toRope("null")
|
result = toRope("null")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue