about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-09-28 17:54:13 +0200
committerbptato <nincsnevem662@gmail.com>2024-09-28 17:54:13 +0200
commit6a0e957e1f2c9f5bea0882efbf2e0494cd5074fa (patch)
tree3d6206a2bc8676d2fd913c3958e5186fc3375c2b
parent9c257361388f5007871a36eea3abc815a8740d66 (diff)
downloadchawan-6a0e957e1f2c9f5bea0882efbf2e0494cd5074fa.tar.gz
loader: clean up connecterror
* allow string values for public errors
* remove unused errors
* update naming
-rw-r--r--Makefile10
-rw-r--r--adapter/img/sixel.nim16
-rw-r--r--adapter/protocol/curlerrors.nim19
-rw-r--r--adapter/protocol/file.nim9
-rw-r--r--adapter/protocol/ftp.nim6
-rw-r--r--adapter/protocol/gopher.nim5
-rw-r--r--doc/localcgi.md19
-rw-r--r--src/loader/connecterror.nim90
-rw-r--r--src/loader/loader.nim53
9 files changed, 123 insertions, 104 deletions
diff --git a/Makefile b/Makefile
index 1b5b7857..ce63385c 100644
--- a/Makefile
+++ b/Makefile
@@ -99,14 +99,12 @@ $(OUTDIR_CGI_BIN)/http: adapter/protocol/curlwrap.nim \
 		adapter/protocol/curlerrors.nim adapter/protocol/curl.nim \
 		src/utils/sandbox.nim $(twtstr)
 $(OUTDIR_CGI_BIN)/about: res/chawan.html res/license.md
-$(OUTDIR_CGI_BIN)/file: adapter/protocol/dirlist.nim $(twtstr) \
-		src/utils/strwidth.nim src/loader/connecterror.nim
-$(OUTDIR_CGI_BIN)/ftp: adapter/protocol/dirlist.nim $(twtstr) \
-		src/utils/strwidth.nim src/loader/connecterror.nim src/types/opt.nim \
-		adapter/protocol/curl.nim
+$(OUTDIR_CGI_BIN)/file: adapter/protocol/dirlist.nim $(twtstr) src/utils/strwidth.nim
+$(OUTDIR_CGI_BIN)/ftp: adapter/protocol/dirlist.nim $(twtstr) src/utils/strwidth.nim \
+		src/types/opt.nim adapter/protocol/curl.nim
 $(OUTDIR_CGI_BIN)/gopher: adapter/protocol/curlwrap.nim adapter/protocol/curlerrors.nim \
 		adapter/gophertypes.nim adapter/protocol/curl.nim \
-		src/loader/connecterror.nim $(twtstr)
+		$(twtstr)
 $(OUTDIR_CGI_BIN)/stbi: adapter/img/stbi.nim adapter/img/stb_image.c \
 		adapter/img/stb_image.h src/utils/sandbox.nim $(dynstream)
 $(OUTDIR_CGI_BIN)/jebp: adapter/img/jebp.c adapter/img/jebp.h \
diff --git a/adapter/img/sixel.nim b/adapter/img/sixel.nim
index beaac144..3552004b 100644
--- a/adapter/img/sixel.nim
+++ b/adapter/img/sixel.nim
@@ -483,21 +483,21 @@ proc encode(img: openArray[RGBAColorBE]; width, height, offx, offy, cropw: int;
 proc parseDimensions(s: string): (int, int) =
   let s = s.split('x')
   if s.len != 2:
-    die("Cha-Control: ConnectionError 1 wrong dimensions\n")
+    die("Cha-Control: ConnectionError InternalError wrong dimensions\n")
   let w = parseUInt32(s[0], allowSign = false)
   let h = parseUInt32(s[1], allowSign = false)
   if w.isNone or w.isNone:
-    die("Cha-Control: ConnectionError 1 wrong dimensions\n")
+    die("Cha-Control: ConnectionError InternalError wrong dimensions\n")
   return (int(w.get), int(h.get))
 
 proc main() =
   let scheme = getEnv("MAPPED_URI_SCHEME")
   let f = scheme.after('+')
   if f != "x-sixel":
-    die("Cha-Control: ConnectionError 1 unknown format " & f)
+    die("Cha-Control: ConnectionError InternalError unknown format " & f)
   case getEnv("MAPPED_URI_PATH")
   of "decode":
-    die("Cha-Control: ConnectionError 1 not implemented\n")
+    die("Cha-Control: ConnectionError InternalError not implemented\n")
   of "encode":
     var width = 0
     var height = 0
@@ -517,19 +517,19 @@ proc main() =
       of "Cha-Image-Crop-Width":
         let q = parseUInt32(s, allowSign = false)
         if q.isNone:
-          die("Cha-Control: ConnectionError 1 wrong palette\n")
+          die("Cha-Control: ConnectionError InternalError wrong palette\n")
         cropw = int(q.get)
       of "Cha-Image-Sixel-Halfdump":
         halfdump = true
       of "Cha-Image-Sixel-Palette":
         let q = parseUInt16(s, allowSign = false)
         if q.isNone:
-          die("Cha-Control: ConnectionError 1 wrong palette\n")
+          die("Cha-Control: ConnectionError InternalError wrong palette\n")
         palette = int(q.get)
       of "Cha-Image-Quality":
         let q = parseUInt16(s, allowSign = false)
         if q.isNone:
-          die("Cha-Control: ConnectionError 1 wrong quality\n")
+          die("Cha-Control: ConnectionError InternalError wrong quality\n")
         quality = int(q.get)
     if cropw == -1:
       cropw = width
@@ -549,7 +549,7 @@ proc main() =
     let ps = newPosixStream(STDIN_FILENO)
     let src = ps.recvDataLoopOrMmap(L)
     if src == nil:
-      die("Cha-Control: ConnectionError 1 failed to read input\n")
+      die("Cha-Control: ConnectionError InternalError failed to read input\n")
     enterNetworkSandbox() # don't swallow stat
     let p = cast[ptr UncheckedArray[RGBAColorBE]](src.p)
     p.toOpenArray(0, n - 1).encode(width, height, offx, offy, cropw, halfdump,
diff --git a/adapter/protocol/curlerrors.nim b/adapter/protocol/curlerrors.nim
index ce50cd82..8ad05936 100644
--- a/adapter/protocol/curlerrors.nim
+++ b/adapter/protocol/curlerrors.nim
@@ -1,17 +1,16 @@
 import curl
-import loader/connecterror
 
-func curlErrorToChaError*(res: CURLcode): ConnectErrorCode =
+func curlErrorToChaError*(res: CURLcode): string =
   return case res
-  of CURLE_OK: CONNECTION_SUCCESS
-  of CURLE_URL_MALFORMAT: ERROR_INVALID_URL #TODO should never occur...
-  of CURLE_COULDNT_CONNECT: ERROR_CONNECTION_REFUSED
-  of CURLE_COULDNT_RESOLVE_PROXY: ERROR_FAILED_TO_RESOLVE_PROXY
-  of CURLE_COULDNT_RESOLVE_HOST: ERROR_FAILED_TO_RESOLVE_HOST
-  of CURLE_PROXY: ERROR_PROXY_REFUSED_TO_CONNECT
-  else: ERROR_INTERNAL
+  of CURLE_OK: ""
+  of CURLE_URL_MALFORMAT: "InvalidURL" #TODO should never occur...
+  of CURLE_COULDNT_CONNECT: "ConnectionRefused"
+  of CURLE_COULDNT_RESOLVE_PROXY: "FailedToResolveProxy"
+  of CURLE_COULDNT_RESOLVE_HOST: "FailedToResolveHost"
+  of CURLE_PROXY: "ProxyRefusedToConnect"
+  else: "InternalError"
 
 proc getCurlConnectionError*(res: CURLcode): string =
-  let e = $int(curlErrorToChaError(res))
+  let e = curlErrorToChaError(res)
   let msg = $curl_easy_strerror(res)
   return "Cha-Control: ConnectionError " & e & " " & msg & "\n"
diff --git a/adapter/protocol/file.nim b/adapter/protocol/file.nim
index bd2c34a2..bf135180 100644
--- a/adapter/protocol/file.nim
+++ b/adapter/protocol/file.nim
@@ -4,7 +4,6 @@ import std/times
 
 import dirlist
 
-import loader/connecterror
 import utils/twtstr
 
 proc loadDir(path, opath: string) =
@@ -79,11 +78,6 @@ proc loadFile(f: File) =
       break
 
 proc main() =
-  if getEnv("MAPPED_URI_HOST") != "":
-    let code = int(ERROR_INVALID_URL)
-    stdout.write("Cha-Control: ConnectionError " & $code &
-      " cannot use host in file")
-    return
   let opath = getEnv("MAPPED_URI_PATH")
   let path = percentDecode(opath)
   var f: File
@@ -92,7 +86,6 @@ proc main() =
   elif dirExists(path):
     loadDir(path, opath)
   else:
-    let code = int(ERROR_FILE_NOT_FOUND)
-    stdout.write("Cha-Control: ConnectionError " & $code)
+    stdout.write("Cha-Control: ConnectionError FileNotFound")
 
 main()
diff --git a/adapter/protocol/ftp.nim b/adapter/protocol/ftp.nim
index 4484180f..f46f8aee 100644
--- a/adapter/protocol/ftp.nim
+++ b/adapter/protocol/ftp.nim
@@ -7,7 +7,6 @@ import curlerrors
 import curlwrap
 import dirlist
 
-import loader/connecterror
 import utils/twtstr
 
 type FtpHandle = ref object
@@ -280,7 +279,7 @@ proc main() =
   if op.dirmode:
     let surl = url.get(CURLUPART_URL, cuint(CURLU_PUNY2IDN))
     if surl == nil:
-      stdout.write("Cha-Control: ConnectionError " & $int(ERROR_INVALID_URL))
+      stdout.write("Cha-Control: ConnectionError InvalidURL\n")
       curl_url_cleanup(url)
       curl_easy_cleanup(curl)
       return
@@ -306,8 +305,7 @@ proc main() =
     curl.setopt(CURLOPT_PROXY, purl)
   if getEnv("REQUEST_METHOD") != "GET":
     # fail
-    let code = $int(ERROR_INVALID_METHOD)
-    stdout.write("Cha-Control: ConnectionError " & $code & "\n")
+    stdout.write("Cha-Control: ConnectionError InvalidMethod\n")
   else:
     let res = curl_easy_perform(curl)
     if res != CURLE_OK:
diff --git a/adapter/protocol/gopher.nim b/adapter/protocol/gopher.nim
index 14e34b7a..13ade18c 100644
--- a/adapter/protocol/gopher.nim
+++ b/adapter/protocol/gopher.nim
@@ -9,7 +9,6 @@ import curlwrap
 
 import ../gophertypes
 
-import loader/connecterror
 import utils/twtstr
 
 type GopherHandle = ref object
@@ -58,7 +57,7 @@ proc main() =
   let curl = curl_easy_init()
   doAssert curl != nil
   if getEnv("REQUEST_METHOD") != "GET":
-    stdout.write("Cha-Control: ConnectionError " & $int(ERROR_INVALID_METHOD))
+    stdout.write("Cha-Control: ConnectionError InvalidMethod")
     return
   var path = getEnv("MAPPED_URI_PATH")
   if path.len < 1:
@@ -84,7 +83,7 @@ proc main() =
     const flags = cuint(CURLU_PUNY2IDN)
     let surl = url.get(CURLUPART_URL, flags)
     if surl == nil:
-      stdout.write("Cha-Control: ConnectionError " & $int(ERROR_INVALID_URL))
+      stdout.write("Cha-Control: ConnectionError InvalidURL")
     else:
       op.loadSearch($surl)
   else:
diff --git a/doc/localcgi.md b/doc/localcgi.md
index 17ebc778..bcf91e80 100644
--- a/doc/localcgi.md
+++ b/doc/localcgi.md
@@ -77,25 +77,26 @@ Currently available commands are:
   take external input. For example, an HTTP client would have to send
   `Cha-Control: ControlDone` before returning the retrieved headers.
 
-List of public error codes:
+Following is a list of error codes and their string counterparts. CGI scripts
+may use either (but not both) in a ConnectionError header.
 
-* `1 internal error`: An internal error prevented the script from retrieving
+* `1 InternalError`: An internal error prevented the script from retrieving
   the requested resource. CGI scripts can also use this to signal that they
   have no information on what went wrong.
-* `2 invalid method`: The client requested data using a method not supported
+* `2 InvalidMethod`: The client requested data using a method not supported
   by this protocol.
-* `3 invalid URL`: The request URL could not be interpreted as a valid URL
+* `3 InvalidURL`: The request URL could not be interpreted as a valid URL
   for this format.
-* `4 file not found`: No file was found at the requested address, and thus
+* `4 FileNotFound`: No file was found at the requested address, and thus
   the request is meaningless. Note: this should only be used by protocols
   that do not rely on a client-server architecture, e.g. local file access,
   local databases, or peer-to-peer file retrieval mechanisms. A server
   responding with "no file found" is NOT a connection error, and is better
   represented as a response with a 404 status code.
-* `5 failed to resolve host`: The hostname could not be resolved.
-* `6 failed to resolve proxy`: The proxy could not be resolved.
-* `7 connection refused`: The server refused to establish a connection.
-* `8 proxy refused to connect`: The proxy refused to establish a connection.
+* `5 FailedToResolveHost`: The hostname could not be resolved.
+* `6 FailedToResolveProxy`: The proxy could not be resolved.
+* `7 ConnectionRefused`: The server refused to establish a connection.
+* `8 ProxyRefusedToConnect`: The proxy refused to establish a connection.
 
 ## Environment variables
 
diff --git a/src/loader/connecterror.nim b/src/loader/connecterror.nim
index d8b06881..878bc8d0 100644
--- a/src/loader/connecterror.nim
+++ b/src/loader/connecterror.nim
@@ -1,36 +1,64 @@
-type ConnectErrorCode* = enum
-  ERROR_CGI_CACHED_BODY_NOT_FOUND = (-18, "cached request body not found")
-  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")
-  ERROR_CGI_NO_DATA = (-13, "CGI script returned no data")
-  ERROR_CGI_MALFORMED_HEADER = (-12, "CGI script returned a malformed header")
-  ERROR_CGI_INVALID_CHA_CONTROL = (-11, "CGI got invalid Cha-Control header")
-  ERROR_TOO_MANY_REWRITES = (-10, "too many URI method map rewrites")
-  ERROR_INVALID_URI_METHOD_ENTRY = (-9, "invalid URI method entry")
-  ERROR_CGI_FILE_NOT_FOUND = (-8, "CGI file not found")
-  ERROR_INVALID_CGI_PATH = (-7, "invalid CGI path")
-  ERROR_FAIL_SETUP_CGI = (-6, "failed to set up CGI script")
-  ERROR_NO_CGI_DIR = (-5, "no local-CGI directory configured")
-  ERROR_SOURCE_NOT_FOUND = (-4, "clone source could not be found")
-  ERROR_LOADER_KILLED = (-3, "loader killed during transfer")
-  ERROR_DISALLOWED_URL = (-2, "url not allowed by filter")
-  ERROR_UNKNOWN_SCHEME = (-1, "unknown scheme")
-  CONNECTION_SUCCESS = (0, "connection successful")
-  ERROR_INTERNAL = (1, "internal error")
-  ERROR_INVALID_METHOD = (2, "invalid method")
-  ERROR_INVALID_URL = (3, "invalid URL")
-  ERROR_FILE_NOT_FOUND = (4, "file not found")
-  ERROR_CONNECTION_REFUSED = (5, "connection refused")
-  ERROR_PROXY_REFUSED_TO_CONNECT = (6, "proxy refused to connect")
-  ERROR_FAILED_TO_RESOLVE_HOST = (7, "failed to resolve host")
-  ERROR_FAILED_TO_RESOLVE_PROXY = (8, "failed to resolve proxy")
+type ConnectionError* = enum
+  ceCGIOutputHandleNotFound = -17
+  ceCGIFailedToOpenCacheOutput = -16
+  ceCGICachedBodyNotFound = -15
+  ceFailedToRedirect = -14
+  ceURLNotInCache = -13
+  ceFileNotInCache = -12
+  ceFailedToExecuteCGIScript = -11
+  ceCGIMalformedHeader = -10
+  ceCGIInvalidChaControl = -9
+  ceTooManyRewrites = -8
+  ceInvalidURIMethodEntry = -7
+  ceCGIFileNotFound = -6
+  ceInvalidCGIPath = -5
+  ceFailedToSetUpCGI = -4
+  ceNoCGIDir = -3
+  ceDisallowedURL = -2
+  ceUnknownScheme = -1
+  ceNone = 0
+  ceInternalError = (1, "InternalError")
+  ceInvalidMethod = (2, "InvalidMethod")
+  ceInvalidURL = (3, "InvalidURL")
+  ceFileNotFound = (4, "FileNotFound")
+  ceConnectionRefused = (5, "ConnectionRefused")
+  ceProxyRefusedToConnect = (6, "ProxyRefusedToConnect")
+  ceFailedToResolveHost = (7, "FailedToResolveHost")
+  ceFailedToResolveProxy = (8, "FailedToResolveProxy")
 
-converter toInt*(code: ConnectErrorCode): int =
+const ErrorMessages* = [
+  ceCGIOutputHandleNotFound: "request body output handle not found",
+  ceCGIFailedToOpenCacheOutput: "failed to open cache output",
+  ceCGICachedBodyNotFound: "cached request body not found",
+  ceFailedToRedirect: "failed to redirect request body",
+  ceURLNotInCache: "URL was not found in the cache",
+  ceFileNotInCache: "file was not found in the cache",
+  ceFailedToExecuteCGIScript: "failed to execute CGI script",
+  ceCGIMalformedHeader: "CGI script returned a malformed header",
+  ceCGIInvalidChaControl: "CGI got invalid Cha-Control header",
+  ceTooManyRewrites: "too many URI method map rewrites",
+  ceInvalidURIMethodEntry: "invalid URI method entry",
+  ceCGIFileNotFound: "CGI file not found",
+  ceInvalidCGIPath: "invalid CGI path",
+  ceFailedToSetUpCGI: "failed to set up CGI script",
+  ceNoCGIDir: "no local-CGI directory configured",
+  ceDisallowedURL: "url not allowed by filter",
+  ceUnknownScheme: "unknown scheme",
+  ceNone: "connection successful",
+  ceInternalError: "internal error",
+  ceInvalidMethod: "invalid method",
+  ceInvalidURL: "invalid URL",
+  ceFileNotFound: "file not found",
+  ceConnectionRefused: "connection refused",
+  ceProxyRefusedToConnect: "proxy refused to connect",
+  ceFailedToResolveHost: "failed to resolve host",
+  ceFailedToResolveProxy: "failed to resolve proxy",
+]
+
+converter toInt*(code: ConnectionError): int =
   return int(code)
 
 func getLoaderErrorMessage*(code: int): string =
-  if code in int(ConnectErrorCode.low)..int(ConnectErrorCode.high):
-    return $ConnectErrorCode(code)
+  if code in int(ConnectionError.low)..int(ConnectionError.high):
+    return ErrorMessages[ConnectionError(code)]
   return "unexpected error code " & $code
diff --git a/src/loader/loader.nim b/src/loader/loader.nim
index 732336f9..9ebc6917 100644
--- a/src/loader/loader.nim
+++ b/src/loader/loader.nim
@@ -100,7 +100,7 @@ func canRewriteForCGICompat(ctx: LoaderContext; path: string): bool =
       return true
   return false
 
-proc rejectHandle(handle: InputHandle; code: ConnectErrorCode; msg = "") =
+proc rejectHandle(handle: InputHandle; code: ConnectionError; msg = "") =
   handle.sendResult(code, msg)
   handle.close()
 
@@ -307,7 +307,7 @@ proc handleFirstLine(handle: InputHandle; line: string; headers: Headers;
   let k = line.until(':')
   if k.len == line.len:
     # invalid
-    handle.sendResult(ERROR_CGI_MALFORMED_HEADER)
+    handle.sendResult(ceCGIMalformedHeader)
     return crError
   let v = line.substr(k.len + 1).strip()
   if k.equalsIgnoreCase("Status"):
@@ -321,10 +321,13 @@ proc handleFirstLine(handle: InputHandle; line: string; headers: Headers;
     elif v.startsWithIgnoreCase("ConnectionError"):
       let errs = v.split(' ')
       if errs.len <= 1:
-        handle.sendResult(ERROR_CGI_INVALID_CHA_CONTROL)
+        handle.sendResult(ceCGIInvalidChaControl)
       else:
-        let fb = int32(ERROR_CGI_INVALID_CHA_CONTROL)
-        let code = int(parseInt32(errs[1]).get(fb))
+        var code = int32(ceCGIInvalidChaControl)
+        if (let x = parseInt32(errs[1]); x.isSome):
+          code = x.get
+        elif (let x = strictParseEnum[ConnectionError](errs[1]); x.isSome):
+          code = int32(x.get)
         var message = ""
         if errs.len > 2:
           message &= errs[2]
@@ -335,7 +338,7 @@ proc handleFirstLine(handle: InputHandle; line: string; headers: Headers;
       return crError
     elif v.startsWithIgnoreCase("ControlDone"):
       return crDone
-    handle.sendResult(ERROR_CGI_INVALID_CHA_CONTROL)
+    handle.sendResult(ceCGIInvalidChaControl)
     return crError
   handle.sendResult(0) # success
   headers.add(k, v)
@@ -584,20 +587,20 @@ proc parseCGIPath(ctx: LoaderContext; request: Request): CGIPath =
 proc loadCGI(ctx: LoaderContext; client: ClientData; handle: InputHandle;
     request: Request; prevURL: URL; config: LoaderClientConfig) =
   if ctx.config.cgiDir.len == 0:
-    handle.sendResult(ERROR_NO_CGI_DIR)
+    handle.sendResult(ceNoCGIDir)
     return
   let cpath = ctx.parseCGIPath(request)
   if cpath.cmd == "" or cpath.basename in ["", ".", ".."] or
       cpath.basename[0] == '~':
-    handle.sendResult(ERROR_INVALID_CGI_PATH)
+    handle.sendResult(ceInvalidCGIPath)
     return
   if not fileExists(cpath.cmd):
-    handle.sendResult(ERROR_CGI_FILE_NOT_FOUND)
+    handle.sendResult(ceCGIFileNotFound)
     return
   # Pipe the response body as stdout.
   var pipefd: array[2, cint] # child -> parent
   if pipe(pipefd) == -1:
-    handle.sendResult(ERROR_FAIL_SETUP_CGI)
+    handle.sendResult(ceFailedToSetUpCGI)
     return
   let istreamOut = newPosixStream(pipefd[0]) # read by loader
   var ostreamOut = newPosixStream(pipefd[1]) # written by child
@@ -610,7 +613,7 @@ proc loadCGI(ctx: LoaderContext; client: ClientData; handle: InputHandle;
     # RDWR, otherwise mmap won't work
     ostreamOut = newPosixStream(tmpf, O_CREAT or O_RDWR, 0o600)
     if ostreamOut == nil:
-      handle.sendResult(ERROR_FAIL_SETUP_CGI)
+      handle.sendResult(ceCGIFailedToOpenCacheOutput)
       return
     let cacheId = handle.output.outputId # welp
     client.cacheMap.add(CachedItem(
@@ -629,7 +632,7 @@ proc loadCGI(ctx: LoaderContext; client: ClientData; handle: InputHandle;
     var n: int
     (istream, n) = client.openCachedItem(request.body.cacheId)
     if istream == nil:
-      handle.sendResult(ERROR_CGI_CACHED_BODY_NOT_FOUND)
+      handle.sendResult(ceCGICachedBodyNotFound)
       return
     cachedHandle = ctx.findCachedHandle(request.body.cacheId)
     if cachedHandle != nil: # cached item still open, switch to streaming mode
@@ -637,13 +640,13 @@ proc loadCGI(ctx: LoaderContext; client: ClientData; handle: InputHandle;
   elif request.body.t == rbtOutput:
     outputIn = ctx.findOutput(request.body.outputId, client)
     if outputIn == nil:
-      handle.sendResult(ERROR_FAIL_SETUP_CGI)
+      handle.sendResult(ceCGIOutputHandleNotFound)
       return
   if request.body.t in {rbtString, rbtMultipart, rbtOutput} or
       request.body.t == rbtCache and istream2 != nil:
     var pipefdRead: array[2, cint] # parent -> child
     if pipe(pipefdRead) == -1:
-      handle.sendResult(ERROR_FAIL_SETUP_CGI)
+      handle.sendResult(ceFailedToSetUpCGI)
       return
     istream = newPosixStream(pipefdRead[0])
     ostream = newPosixStream(pipefdRead[1])
@@ -651,7 +654,7 @@ proc loadCGI(ctx: LoaderContext; client: ClientData; handle: InputHandle;
   stderr.flushFile()
   let pid = fork()
   if pid == -1:
-    handle.sendResult(ERROR_FAIL_SETUP_CGI)
+    handle.sendResult(ceFailedToSetUpCGI)
   elif pid == 0:
     istreamOut.sclose() # close read
     discard dup2(ostreamOut.fd, 1) # dup stdout
@@ -679,7 +682,7 @@ proc loadCGI(ctx: LoaderContext; client: ClientData; handle: InputHandle;
       if ctx.handleMap[i] != nil:
         discard close(cint(i))
     discard execl(cstring(cpath.cmd), cstring(cpath.basename), nil)
-    let code = int(ERROR_FAILED_TO_EXECUTE_CGI_SCRIPT)
+    let code = int(ceFailedToExecuteCGIScript)
     stdout.write("Cha-Control: ConnectionError " & $code & " " &
       ($strerror(errno)).deleteChars({'\n', '\r'}))
     quit(1)
@@ -738,7 +741,7 @@ proc loadStream(ctx: LoaderContext; client: ClientData; handle: InputHandle;
       # not loading from cache, so cachedHandle is nil
       ctx.loadStreamRegular(handle, nil)
   do:
-    handle.sendResult(ERROR_FILE_NOT_FOUND, "stream not found")
+    handle.sendResult(ceFileNotFound, "stream not found")
 
 proc loadFromCache(ctx: LoaderContext; client: ClientData; handle: InputHandle;
     request: Request) =
@@ -750,7 +753,7 @@ proc loadFromCache(ctx: LoaderContext; client: ClientData; handle: InputHandle;
       ps.seek(startFrom)
     handle.stream = ps
     if ps == nil:
-      handle.rejectHandle(ERROR_FILE_NOT_IN_CACHE)
+      handle.rejectHandle(ceFileNotInCache)
       client.cacheMap.del(n)
       return
     handle.sendResult(0)
@@ -760,7 +763,7 @@ proc loadFromCache(ctx: LoaderContext; client: ClientData; handle: InputHandle;
     let cachedHandle = ctx.findCachedHandle(id)
     ctx.loadStreamRegular(handle, cachedHandle)
   else:
-    handle.sendResult(ERROR_URL_NOT_IN_CACHE)
+    handle.sendResult(ceURLNotInCache)
 
 # Data URL handler.
 # Moved back into loader from CGI, because data URLs can get extremely long
@@ -796,7 +799,7 @@ proc loadData(ctx: LoaderContext; handle: InputHandle; request: Request) =
   let url = request.url
   var ct = url.path.s.until(',')
   if AllChars - Ascii + Controls - {'\t', ' '} in ct:
-    handle.sendResult(ERROR_INVALID_URL, "invalid data URL")
+    handle.sendResult(ceInvalidURL, "invalid data URL")
     handle.close()
     return
   let sd = ct.len + 1 # data start
@@ -804,7 +807,7 @@ proc loadData(ctx: LoaderContext; handle: InputHandle; request: Request) =
   if ct.endsWith(";base64"):
     let d = atob0(body) # decode from ct end + 1
     if d.isNone:
-      handle.sendResult(ERROR_INVALID_URL, "invalid data URL")
+      handle.sendResult(ceInvalidURL, "invalid data URL")
       handle.close()
       return
     ct.setLen(ct.len - ";base64".len) # remove base64 indicator
@@ -853,11 +856,11 @@ proc loadResource(ctx: LoaderContext; client: ClientData;
         inc tries
         redo = true
       of ummrWrongURL:
-        handle.rejectHandle(ERROR_INVALID_URI_METHOD_ENTRY)
+        handle.rejectHandle(ceInvalidURIMethodEntry)
       of ummrNotFound:
-        handle.rejectHandle(ERROR_UNKNOWN_SCHEME)
+        handle.rejectHandle(ceUnknownScheme)
   if tries >= MaxRewrites:
-    handle.rejectHandle(ERROR_TOO_MANY_REWRITES)
+    handle.rejectHandle(ceTooManyRewrites)
 
 proc setupRequestDefaults(request: Request; config: LoaderClientConfig) =
   for k, v in config.defaultHeaders.table:
@@ -880,7 +883,7 @@ proc load(ctx: LoaderContext; stream: SocketStream; request: Request;
     handle.url = request.url
     handle.output.url = request.url
   if not config.filter.match(request.url):
-    handle.rejectHandle(ERROR_DISALLOWED_URL)
+    handle.rejectHandle(ceDisallowedURL)
   else:
     request.setupRequestDefaults(config)
     ctx.loadResource(client, config, request, handle)