diff options
author | bptato <nincsnevem662@gmail.com> | 2024-06-20 20:04:14 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2024-06-20 20:06:45 +0200 |
commit | 2ab1e53b4bc15af3319994fdb25bb739b4b8e6db (patch) | |
tree | 22e32f721c783f3ee934498ec95b58f5a117ac67 /src/loader | |
parent | 60dc37269cd2dc8cdf23d9f77680f6af9490032f (diff) | |
download | chawan-2ab1e53b4bc15af3319994fdb25bb739b4b8e6db.tar.gz |
loader: better error handling
we no longer crash on broken codecs. yay
Diffstat (limited to 'src/loader')
-rw-r--r-- | src/loader/connecterror.nim | 1 | ||||
-rw-r--r-- | src/loader/loader.nim | 42 | ||||
-rw-r--r-- | src/loader/loaderhandle.nim | 7 |
3 files changed, 30 insertions, 20 deletions
diff --git a/src/loader/connecterror.nim b/src/loader/connecterror.nim index 08f7b436..c3099b0f 100644 --- a/src/loader/connecterror.nim +++ b/src/loader/connecterror.nim @@ -1,4 +1,5 @@ type ConnectErrorCode* = enum + ERROR_FAILED_TO_REDIRECT = (-17, "failed to redirect request body") ERROR_URL_NOT_IN_CACHE = (-16, "URL was not found in the cache") ERROR_FILE_NOT_IN_CACHE = (-15, "file was not found in the cache") ERROR_FAILED_TO_EXECUTE_CGI_SCRIPT = (-14, "failed to execute CGI script") diff --git a/src/loader/loader.nim b/src/loader/loader.nim index 89d97cde..f0ecb384 100644 --- a/src/loader/loader.nim +++ b/src/loader/loader.nim @@ -216,16 +216,21 @@ proc getOutputId(ctx: LoaderContext): int = proc redirectToStream(ctx: LoaderContext; output: OutputHandle; ps: PosixStream): bool = - if output.currentBuffer != nil: - let n = ps.sendData(output.currentBuffer, output.currentBufferIdx) - if unlikely(n < output.currentBuffer.len - output.currentBufferIdx): - ps.sclose() - return false - for buffer in output.buffers: - let n = ps.sendData(buffer) - if unlikely(n < buffer.len): - ps.sclose() - return false + try: + if output.currentBuffer != nil: + let n = ps.sendData(output.currentBuffer, output.currentBufferIdx) + if unlikely(n < output.currentBuffer.len - output.currentBufferIdx): + ps.sclose() + return false + for buffer in output.buffers: + let n = ps.sendData(buffer) + if unlikely(n < buffer.len): + ps.sclose() + return false + except ErrorBrokenPipe: + # ps or output is dead; give up. + ps.sclose() + return false if output.istreamAtEnd: ps.sclose() elif output.parent != nil: @@ -329,8 +334,7 @@ proc loadStreamRegular(ctx: LoaderContext; handle, cachedHandle: LoaderHandle) = handle.outputs.del(i) for output in handle.outputs: if r == hrrBrokenPipe: - output.ostream.sclose() - output.ostream = nil + output.oclose() elif cachedHandle != nil: output.parent = cachedHandle cachedHandle.outputs.add(output) @@ -341,8 +345,7 @@ proc loadStreamRegular(ctx: LoaderContext; handle, cachedHandle: LoaderHandle) = ctx.outputMap[output.ostream.fd] = output else: assert output.ostream.fd notin ctx.outputMap - output.ostream.sclose() - output.ostream = nil + output.oclose() handle.outputs.setLen(0) handle.iclose() @@ -418,13 +421,16 @@ proc loadResource(ctx: LoaderContext; client: ClientData; config: LoaderClientCo handle.loadCGI(request, ctx.config.cgiDir, prevurl, config.insecureSSLNoVerify, ostream) if handle.istream != nil: - ctx.addFd(handle) if ostream != nil: let output = ctx.findOutput(request.body.outputId, client) if output != nil: - doAssert ctx.redirectToStream(output, ostream) + if not ctx.redirectToStream(output, ostream): + # give up. + handle.rejectHandle(ERROR_FAILED_TO_REDIRECT) + return else: ostream.sclose() + ctx.addFd(handle) else: handle.close() elif request.url.scheme == "stream": @@ -704,6 +710,7 @@ proc acceptConnection(ctx: LoaderContext) = ctx.resume(stream, client, r) except ErrorBrokenPipe: # receiving end died while reading the file; give up. + assert stream.fd notin ctx.outputMap stream.sclose() proc exitLoader(ctx: LoaderContext) = @@ -820,8 +827,7 @@ proc finishCycle(ctx: LoaderContext; unregRead: var seq[LoaderHandle]; if output.registered: ctx.selector.unregister(output.ostream.fd) ctx.outputMap.del(output.ostream.fd) - output.ostream.sclose() - output.ostream = nil + output.oclose() let handle = output.parent if handle != nil: # may be nil if from loadStream S_ISREG let i = handle.outputs.find(output) diff --git a/src/loader/loaderhandle.nim b/src/loader/loaderhandle.nim index 31a41571..42f10c6e 100644 --- a/src/loader/loaderhandle.nim +++ b/src/loader/loaderhandle.nim @@ -185,10 +185,13 @@ proc iclose*(handle: LoaderHandle) = handle.istream.sclose() handle.istream = nil +proc oclose*(output: OutputHandle) = + output.ostream.sclose() + output.ostream = nil + proc close*(handle: LoaderHandle) = handle.iclose() for output in handle.outputs: #TODO assert not output.registered if output.ostream != nil: - output.ostream.sclose() - output.ostream = nil + output.oclose() |