Skip to content

Instantly share code, notes, and snippets.

@treeform
Created March 2, 2021 07:50
Show Gist options
  • Save treeform/9d0e2fc9a4e8b6e1a1e7d571c01be403 to your computer and use it in GitHub Desktop.
Save treeform/9d0e2fc9a4e8b6e1a1e7d571c01be403 to your computer and use it in GitHub Desktop.
Some code to do http chunked encoding.
proc fetchStr(req: Request): (string, seq[string]) =
## Fetches a URL and returns header and chunks.
var socket = newSocket()
if req.url.scheme == "https":
var ctx =
try:
let caCertPath = getAppDir() / "cacert.pem"
if not fileExists(caCertPath):
writeFile(caCertPath, cacertData)
# let certFile = getCurrentDir() / "cacert.pem"
# echo certFile
# echo existsFile(certFile)
# newContext(verifyMode = CVerifyPeer, certFile = certFile)
newContext(verifyMode = CVerifyPeer)
except:
var message = getCurrentExceptionMsg()
raise newException(PuppyError, message)
#wrapSocket(ctx, socket)
socket.connect(req.url.hostname, Port(443))
try:
ctx.wrapConnectedSocket(
socket, handshakeAsClient, req.url.hostname)
except:
var message = getCurrentExceptionMsg()
if "error:14094410:SSL" in message:
message = "Not Secure: Domain failed SSL certificate check."
raise newException(PuppyError, message)
else:
socket.connect(req.url.hostname, Port(80))
socket.send($req)
var
chunked: bool
contentLength: int
var res = ""
while true:
let line = socket.recvLine()
res.add line & CRLF
let lineLower = line.toLowerAscii()
if line == CRLF:
break
elif lineLower.startsWith("content-length:"):
contentLength = parseInt(line.split(" ")[1])
# elif lineLower.startsWith("x-uncompressed-content-length:"):
# contentLength = parseInt(line.split(" ")[1])
elif lineLower == "transfer-encoding: chunked":
chunked = true
var chunks: seq[string]
if chunked:
while true:
var chunkLenStr: string
while true:
var readChar: char
let readLen = socket.recv(readChar.addr, 1)
doAssert readLen == 1
chunkLenStr.add(readChar)
if chunkLenStr.endsWith(CRLF):
break
if chunkLenStr == CRLF:
break
var chunkLen: int
discard parseHex(chunkLenStr, chunkLen)
if chunkLen == 0:
break
var chunk = newString(chunkLen)
let readLen = socket.recv(chunk[0].addr, chunkLen)
doAssert readLen == chunkLen
chunks.add(chunk)
var endStr = newString(2)
let readLen2 = socket.recv(endStr[0].addr, 2)
doAssert endStr == CRLF
else:
var chunk = newString(contentLength)
let readLen = socket.recv(chunk[0].addr, contentLength)
doAssert readLen == contentLength
chunks.add(chunk[0..^3])
return (res, chunks)
proc fetch(req: Request): Response =
let (resBody, chunks) = fetchStr(req)
var res = Response()
res.url = req.url
let resLines = resBody.split(CRLF)
let headerArr = resLines[0].split(" ")
res.code = parseInt(headerArr[1])
res.body = join(chunks)
return res
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment