diff options
author | Dominik Picheta <dominikpicheta@googlemail.com> | 2012-12-23 11:22:42 +0000 |
---|---|---|
committer | Dominik Picheta <dominikpicheta@googlemail.com> | 2012-12-23 11:22:42 +0000 |
commit | 3cbac135465d63a320ff5fcdb5d3ba4ba89da4c8 (patch) | |
tree | f3b2ad93d0f74d96a41f3692a924a82f9494061a /lib/pure/httpclient.nim | |
parent | 6cb8edfce94c9236dfd8a30380d7474a8ede6f87 (diff) | |
download | Nim-3cbac135465d63a320ff5fcdb5d3ba4ba89da4c8.tar.gz |
Rewrote the implementation of parsing chunked transfer coding in
httpclient. Fixes #272.
Diffstat (limited to 'lib/pure/httpclient.nim')
-rwxr-xr-x | lib/pure/httpclient.nim | 92 |
1 files changed, 36 insertions, 56 deletions
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 20b448123..5be4af8a4 100755 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -80,62 +80,43 @@ proc fileError(msg: string) = e.msg = msg raise e -proc charAt(d: var string, i: var int, s: TSocket): char {.inline.} = - result = d[i] - while result == '\0': - d = string(s.recv()) - i = 0 - result = d[i] - proc parseChunks(s: TSocket): string = - # get chunks: - var i = 0 result = "" - var d = s.recv().string + var ri = 0 while true: + var chunkSizeStr = "" var chunkSize = 0 - var digitFound = false - while true: - case d[i] - of '0'..'9': - digitFound = true - chunkSize = chunkSize shl 4 or (ord(d[i]) - ord('0')) - 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 = string(s.recv()) - i = -1 - else: break - inc(i) - if not digitFound: httpError("Chunksize expected") + if s.recvLine(chunkSizeStr): + var i = 0 + if chunkSizeStr == "": + httpError("Server terminated connection prematurely") + while true: + case chunkSizeStr[i] + of '0'..'9': + chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('0')) + of 'a'..'f': + chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('a') + 10) + of 'A'..'F': + chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('A') + 10) + of '\0': + break + of ';': + # http://tools.ietf.org/html/rfc2616#section-3.6.1 + # We don't care about chunk-extensions. + break + else: + httpError("Invalid chunk size: " & chunkSizeStr) + inc(i) if chunkSize <= 0: 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 = substr(d, i, i+chunkSize-1) - var size = x.len - result.add(x) - inc(i, size) - if size < chunkSize: - # read in the rest: - var missing = chunkSize - size - var L = result.len - setLen(result, L + missing) - while missing > 0: - var bytesRead = s.recv(addr(result[L]), missing) - inc(L, bytesRead) - dec(missing, bytesRead) - # next chunk: - d = string(s.recv()) - i = 0 - # skip trailing CR-LF: - while charAt(d, i, s) in {'\C', '\L'}: inc(i) + result.setLen(ri+chunkSize) + var bytesRead = 0 + while bytesRead != chunkSize: + let ret = recv(s, addr(result[ri]), chunkSize-bytesRead) + ri += ret + bytesRead += ret + s.skip(2) # Skip \c\L + # Trailer headers will only be sent if the request specifies that we want + # them: http://tools.ietf.org/html/rfc2616#section-3.6.1 proc parseBody(s: TSocket, headers: PStringTable): string = @@ -250,7 +231,6 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "", ## | Requests ``url`` with the specified ``httpMethod``. ## | Extra headers can be specified and must be seperated by ``\c\L`` var r = parseUrl(url) - var headers = substr($httpMethod, len("http")) headers.add(" /" & r.path & r.query) @@ -285,7 +265,7 @@ proc redirection(status: string): bool = return True proc get*(url: string, maxRedirects = 5, sslContext: PSSLContext = defaultSSLContext): TResponse = - ## | GET's the ``url`` and returns a ``TResponse`` object + ## | GETs the ``url`` and returns a ``TResponse`` object ## | This proc also handles redirection result = request(url) for i in 1..maxRedirects: @@ -295,7 +275,7 @@ proc get*(url: string, maxRedirects = 5, sslContext: PSSLContext = defaultSSLCon result = request(locationHeader, sslContext = sslContext) proc getContent*(url: string, sslContext: PSSLContext = defaultSSLContext): string = - ## | GET's the body and returns it as a string. + ## | GETs the body and returns it as a string. ## | Raises exceptions for the status codes ``4xx`` and ``5xx`` var r = get(url, sslContext = sslContext) if r.status[0] in {'4','5'}: @@ -305,7 +285,7 @@ proc getContent*(url: string, sslContext: PSSLContext = defaultSSLContext): stri proc post*(url: string, extraHeaders = "", body = "", maxRedirects = 5, sslContext: PSSLContext = defaultSSLContext): TResponse = - ## | POST's ``body`` to the ``url`` and returns a ``TResponse`` object. + ## | POSTs ``body`` to the ``url`` and returns a ``TResponse`` object. ## | This proc adds the necessary Content-Length header. ## | This proc also handles redirection. var xh = extraHeaders & "Content-Length: " & $len(body) & "\c\L" @@ -319,7 +299,7 @@ proc post*(url: string, extraHeaders = "", body = "", proc postContent*(url: string, extraHeaders = "", body = "", sslContext: PSSLContext = defaultSSLContext): string = - ## | POST's ``body`` to ``url`` and returns the response's body as a string + ## | POSTs ``body`` to ``url`` and returns the response's body as a string ## | Raises exceptions for the status codes ``4xx`` and ``5xx`` var r = post(url, extraHeaders, body) if r.status[0] in {'4','5'}: |