diff options
author | bptato <nincsnevem662@gmail.com> | 2023-12-13 12:08:05 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2023-12-13 12:56:28 +0100 |
commit | ab203acf554993d15e37604773f160c84b4d8252 (patch) | |
tree | 45428aa45bc751f788cc5c52c32b15bb8a2363f1 /src/types | |
parent | bf761bcb6dcc5288a86aa5e8c2b67df3f0df056b (diff) | |
download | chawan-ab203acf554993d15e37604773f160c84b4d8252.tar.gz |
Move http out of main binary
Now it is (technically) no longer mandatory to link to libcurl. Also, Chawan is at last completely protocol and network backend agnostic :) * Implement multipart requests in local CGI * Implement simultaneous download of CGI data * Add REQUEST_HEADERS env var with all headers * cssparser: add a missing check in consumeEscape
Diffstat (limited to 'src/types')
-rw-r--r-- | src/types/blob.nim | 13 | ||||
-rw-r--r-- | src/types/formdata.nim | 66 |
2 files changed, 74 insertions, 5 deletions
diff --git a/src/types/blob.nim b/src/types/blob.nim index 9ddca2b5..5da7317d 100644 --- a/src/types/blob.nim +++ b/src/types/blob.nim @@ -1,5 +1,6 @@ -import options -import strutils +import std/options +import std/os +import std/strutils import js/dict import js/fromjs @@ -92,12 +93,14 @@ proc newWebFile(ctx: JSContext, fileBits: seq[string], fileName: string, #TODO File, Blob constructors -func size*(this: WebFile): uint64 {.jsfget.} = - #TODO use stat instead +proc getSize*(this: Blob): uint64 = if this.isfile: - return uint64(this.file.getFileSize()) + return uint64(WebFile(this).path.getFileSize()) return this.size +proc size*(this: WebFile): uint64 {.jsfget.} = + return this.getSize() + func name*(this: WebFile): string {.jsfget.} = if this.path.len > 0 and this.path[^1] != '/': return this.path.afterLast('/') diff --git a/src/types/formdata.nim b/src/types/formdata.nim index 2bc26e22..b1957998 100644 --- a/src/types/formdata.nim +++ b/src/types/formdata.nim @@ -1,5 +1,9 @@ +import std/streams +import std/strutils + import js/javascript import types/blob +import utils/twtstr type FormDataEntry* = object @@ -13,9 +17,71 @@ type FormData* = ref object entries*: seq[FormDataEntry] + boundary*: string jsDestructor(FormData) iterator items*(this: FormData): FormDataEntry {.inline.} = for entry in this.entries: yield entry + +proc calcLength*(this: FormData): int = + result = 0 + for entry in this.entries: + result += "--\r\n".len + this.boundary.len # always have boundary + #TODO maybe make CRLF for name first? + result += entry.name.len # always have name + # these must be percent-encoded, with 2 char overhead: + result += entry.name.count({'\r', '\n', '"'}) * 2 + if entry.isstr: + result += "Content-Disposition: form-data; name=\"\"\r\n".len + result += entry.svalue.len + else: + result += "Content-Disposition: form-data; name=\"\";".len + # file name + result += " filename=\"\"\r\n".len + result += entry.filename.len + # dquot must be quoted with 2 char overhead + result += entry.filename.count('"') * 2 + # content type + result += "Content-Type: \r\n".len + result += entry.value.ctype.len + if entry.value.isfile: + result += int(WebFile(entry.value).getSize()) + else: + result += int(entry.value.size) + result += "\r\n".len # header is always followed by \r\n + result += "\r\n".len # value is always followed by \r\n + +proc getContentType*(this: FormData): string = + return "multipart/form-data; boundary=" & this.boundary + +proc writeEntry*(stream: Stream, entry: FormDataEntry, boundary: string) = + stream.write("--" & boundary & "\r\n") + let name = percentEncode(entry.name, {'"', '\r', '\n'}) + if entry.isstr: + stream.write("Content-Disposition: form-data; name=\"" & name & "\"\r\n") + stream.write("\r\n") + stream.write(entry.svalue) + else: + stream.write("Content-Disposition: form-data; name=\"" & name & "\";") + let filename = percentEncode(entry.filename, {'"', '\r', '\n'}) + stream.write(" filename=\"" & filename & "\"\r\n") + let blob = entry.value + let ctype = if blob.ctype == "": + "application/octet-stream" + else: + blob.ctype + stream.write("Content-Type: " & ctype & "\r\n") + if blob.isfile: + let fs = newFileStream(WebFile(blob).path) + if fs != nil: + var buf {.noInit.}: array[4096, uint8] + while true: + let n = fs.readData(addr buf[0], 4096) + stream.writeData(addr buf[0], n) + if n != 4096: break + else: + stream.writeData(blob.buffer, int(blob.size)) + stream.write("\r\n") + stream.write("\r\n") |