diff options
author | bptato <nincsnevem662@gmail.com> | 2024-03-12 19:51:03 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2024-03-12 20:20:24 +0100 |
commit | 22480a38c618aea42285b20868231f247932f2ab (patch) | |
tree | ba9b562124c1c30782ed87cd94122e962b80f637 /src/loader | |
parent | 232d861836993d81f7828a2917e8d242a23194e0 (diff) | |
download | chawan-22480a38c618aea42285b20868231f247932f2ab.tar.gz |
loader: remove applyHeaders
Better compute the values we need on-demand at the call sites; this way, we can pass through content type attributes to mailcap too. (Also, remove a bug where applyResponse was called twice.)
Diffstat (limited to 'src/loader')
-rw-r--r-- | src/loader/loader.nim | 42 | ||||
-rw-r--r-- | src/loader/response.nim | 38 |
2 files changed, 31 insertions, 49 deletions
diff --git a/src/loader/loader.nim b/src/loader/loader.nim index 70f84043..904069a6 100644 --- a/src/loader/loader.nim +++ b/src/loader/loader.nim @@ -43,11 +43,8 @@ import types/cookie import types/referrer import types/urimethodmap import types/url -import utils/mimeguess import utils/twtstr -import chagashi/charset - export request export response @@ -760,38 +757,7 @@ proc runFileLoader*(fd: cint; config: LoaderConfig) = ctx.finishCycle(unregRead, unregWrite) ctx.exitLoader() -proc getAttribute(contentType, attrname: string): string = - let kvs = contentType.after(';') - var i = kvs.find(attrname) - var s = "" - if i != -1 and kvs.len > i + attrname.len and - kvs[i + attrname.len] == '=': - i += attrname.len + 1 - while i < kvs.len and kvs[i] in AsciiWhitespace: - inc i - var q = false - for j, c in kvs.toOpenArray(i, kvs.high): - if q: - s &= c - elif c == '\\': - q = true - elif c == ';' or c in AsciiWhitespace: - break - else: - s &= c - return s - -proc applyHeaders(response: Response; request: Request) = - if "Content-Type" in response.headers.table: - #TODO this is inefficient and broken on several levels. (In particular, - # it breaks mailcap named attributes other than charset.) - # Ideally, contentType would be a separate object type. - let header = response.headers.table["Content-Type"][0].toLowerAscii() - response.contentType = header.until(';').strip().toLowerAscii() - response.charset = getCharset(header.getAttribute("charset")) - else: - response.contentType = guessContentType($response.url.path, - "application/octet-stream", DefaultGuess) +proc getRedirect*(response: Response; request: Request): Request = if "Location" in response.headers.table: if response.status in 301u16..303u16 or response.status in 307u16..308u16: let location = response.headers.table["Location"][0] @@ -801,14 +767,15 @@ proc applyHeaders(response: Response; request: Request) = request.httpMethod notin {HTTP_GET, HTTP_HEAD}) or (response.status == 301 or response.status == 302 and request.httpMethod == HTTP_POST): - response.redirect = newRequest(url.get, HTTP_GET, + return newRequest(url.get, HTTP_GET, mode = request.mode, credentialsMode = request.credentialsMode, destination = request.destination) else: - response.redirect = newRequest(url.get, request.httpMethod, + return newRequest(url.get, request.httpMethod, body = request.body, multipart = request.multipart, mode = request.mode, credentialsMode = request.credentialsMode, destination = request.destination) + return nil proc connect(loader: FileLoader; buffered = true): SocketStream = let stream = connectSocketStream(loader.process, buffered, blocking = true) @@ -899,7 +866,6 @@ proc handleHeaders(response: Response; request: Request; stream: SocketStream) = stream.sread(response.outputId) stream.sread(response.status) stream.sread(response.headers) - response.applyHeaders(request) # Only a stream of the response body may arrive after this point. response.body = stream diff --git a/src/loader/response.nim b/src/loader/response.nim index 6add4928..f419c432 100644 --- a/src/loader/response.nim +++ b/src/loader/response.nim @@ -1,4 +1,6 @@ import std/streams +import std/strutils +import std/tables import bindings/quickjs import io/promise @@ -10,6 +12,8 @@ import loader/headers import loader/request import types/blob import types/url +import utils/mimeguess +import utils/twtstr import chagashi/charset import chagashi/decoder @@ -37,15 +41,12 @@ type res*: int body*: SocketStream bodyUsed* {.jsget.}: bool - contentType*: string status* {.jsget.}: uint16 headers* {.jsget.}: Headers headersGuard: HeadersGuard - redirect*: Request url*: URL #TODO should be urllist? unregisterFun*: proc() bodyRead*: Promise[string] - charset*: Charset internalMessage*: string # should NOT be exposed to JS! outputId*: int @@ -87,6 +88,23 @@ proc close*(response: Response) {.jsfunc.} = if response.body != nil: response.body.close() +func getCharset*(this: Response; fallback: Charset): Charset = + if "Content-Type" notin this.headers.table: + return fallback + let header = this.headers.table["Content-Type"][0].toLowerAscii() + let cs = header.getContentTypeAttr("charset").getCharset() + if cs == CHARSET_UNKNOWN: + return fallback + return cs + +func getContentType*(this: Response): string = + if "Content-Type" in this.headers.table: + let header = this.headers.table["Content-Type"][0].toLowerAscii() + return header.until(';').strip() + # also use DefaultGuess for container, so that local mime.types cannot + # override buffer mime.types + return DefaultGuess.guessContentType(this.url.pathname) + proc text*(response: Response): Promise[JSResult[string]] {.jsfunc.} = if response.body == nil: let p = newPromise[JSResult[string]]() @@ -101,16 +119,13 @@ proc text*(response: Response): Promise[JSResult[string]] {.jsfunc.} = let bodyRead = response.bodyRead response.bodyRead = nil return bodyRead.then(proc(s: string): JSResult[string] = - let cs = if response.charset == CHARSET_UNKNOWN: - CHARSET_UTF_8 - else: - response.charset + let charset = response.getCharset(CHARSET_UTF_8) #TODO this is inefficient # maybe add a JS type that turns a seq[char] into JS strings - if cs in {CHARSET_UTF_8, CHARSET_UNKNOWN}: + if charset == CHARSET_UTF_8: ok(s.toValidUTF8()) else: - ok(newTextDecoder(cs).decodeAll(s)) + ok(newTextDecoder(charset).decodeAll(s)) ) proc blob*(response: Response): Promise[JSResult[Blob]] {.jsfunc.} = @@ -122,13 +137,14 @@ proc blob*(response: Response): Promise[JSResult[Blob]] {.jsfunc.} = return p let bodyRead = response.bodyRead response.bodyRead = nil + let contentType = response.getContentType() return bodyRead.then(proc(s: string): JSResult[Blob] = if s.len == 0: - return ok(newBlob(nil, 0, response.contentType, nil)) + return ok(newBlob(nil, 0, contentType, nil)) GC_ref(s) let deallocFun = proc() = GC_unref(s) - let blob = newBlob(unsafeAddr s[0], s.len, response.contentType, deallocFun) + let blob = newBlob(unsafeAddr s[0], s.len, contentType, deallocFun) ok(blob)) proc json(ctx: JSContext, this: Response): Promise[JSResult[JSValue]] |