.\" Automatically generated by Pandoc 3.7.0.1 .\" .TH "CHA-LOCALCGI" "5" .SH Local CGI support in Chawan Chawan supports the invocation of CGI scripts placed in a directory specified in the \f[CR]external.cgi\-dir\f[R] configuration option. By default, this is set to \f[CR]$CHA_DIR/cgi\-bin\f[R] (i.e.\ \f[CR]\(ti/.chawan/cgi\-bin\f[R] or \f[CR]\(ti/.config/chawan/cgi\-bin\f[R], depending on \f[CR]config.toml\f[R]\(cqs location) and \f[CR]/usr/local/libexec/chawan/cgi\-bin\f[R]. .PP A CGI script in one of these directories can be executed by visiting the URL \f[CR]cgi\-bin:script\-name\f[R]. \f[CR]$PATH_INFO\f[R] and \f[CR]$QUERY_STRING\f[R] are set as normal, i.e.\ \f[CR]cgi\-bin:script\-name/abcd?defgh=ijkl\f[R] will set \f[CR]$PATH_INFO\f[R] to \f[CR]/abcd\f[R], and \f[CR]$QUERY_STRING\f[R] to \f[CR]defgh=ijkl\f[R]. .PP Further notes on processing CGI paths: .IP \(bu 2 The URL must be opaque, so you must not add a double slash after the scheme. e.g.\ \f[CR]cgi\-bin://script\-name\f[R] will NOT work, only \f[CR]cgi\-bin:script\-name\f[R]. .IP \(bu 2 Paths beginning with \f[CR]/cgi\-bin/\f[R] or \f[CR]/$LIB/\f[R] are stripped of this segment automatically. So e.g.\ \f[CR]cgi\-bin:/cgi\-bin/script\-name\f[R] becomes \f[CR]cgi\-bin:script\-name\f[R]. .IP \(bu 2 If \f[CR]external.w3m\-cgi\-compat\f[R] is true, file: URLs are converted to \f[CR]cgi\-bin:\f[R] URLs if the path name starts with \f[CR]/cgi\-bin/\f[R], \f[CR]/$LIB/\f[R], or the path of a local CGI script. Note: this is unsafe, please do not use it unless you must. .IP \(bu 2 Absolute paths are accepted as e.g.\ \f[CR]cgi\-bin:/path/to/cgi/dir/script\-name\f[R]. Note however, that this only works if \f[CR]/path/to/cgi/dir\f[R] has already been specified as a CGI directory in \f[CR]external.cgi\-dir\f[R]. .SS Headers Local CGI scripts may send some headers that Chawan will interpret specially (and thus will not pass forward to e.g.\ the fetch API, etc): .IP \(bu 2 \f[CR]Status\f[R]: interpreted as the HTTP status code. .IP \(bu 2 \f[CR]Cha\-Control\f[R]: special header, see below. .PP These headers \f[B]must\f[R] be sent before any regular headers. Headers received after a regular header or a \f[CR]Cha\-Control: ControlDone\f[R] header will be treated as regular headers. .PP The \f[CR]Cha\-Control\f[R] header\(cqs value is parsed as follows: .IP .EX Cha\-Control\-Value = Command *Parameter Command = ALPHA *ALPHA Parameter = SPACE *CHAR .EE .PP In other words, it is \f[CR]Command [Param1] [Param2] ...\f[R]. .PP Currently available commands are: .IP \(bu 2 \f[CR]Connected\f[R]: Takes no parameters. Must be the first reported header; it means that connection to the server has been successfully established, but no data has been received yet. When any other header is sent first, Chawan will act as if a \f[CR]Cha\-Control: Connected\f[R] header had been implicitly sent before that. .IP \(bu 2 \f[CR]ConnectionError\f[R]: Must be the first reported header. Parameter 1 is the error code, see below. If any following parameters are given, they are concatenated to form a custom error message. .RS 2 .PP Note: short but descriptive error messages are preferred, messages that do not fit on the screen are currently truncated. .RE .IP \(bu 2 \f[CR]ControlDone\f[R]: Signals that no more special headers will be sent; this means that \f[CR]Cha\-Control\f[R] and \f[CR]Status\f[R] headers sent after this must be interpreted as regular headers (and thus e.g.\ will be available for JS code calling the script using the fetch API). .RS 2 .PP WARNING: this header must be sent before any non\-hardcoded headers that take external input. For example, an HTTP client would have to send \f[CR]Cha\-Control: ControlDone\f[R] before returning the retrieved headers. .RE .PP Following is a list of error codes and their string counterparts. CGI scripts may use either (but not both) in a ConnectionError header. .IP \(bu 2 \f[CR]1 InternalError\f[R]: 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. .IP \(bu 2 \f[CR]2 InvalidMethod\f[R]: The client requested data using a method not supported by this protocol. .IP \(bu 2 \f[CR]3 InvalidURL\f[R]: The request URL could not be interpreted as a valid URL for this format. .IP \(bu 2 \f[CR]4 FileNotFound\f[R]: No file was found at the requested address, so 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 \(lqno file found\(rq is NOT a connection error, and is better represented as a response with a 404 status code. .IP \(bu 2 \f[CR]5 ConnectionRefused\f[R]: The server refused to establish a connection. .IP \(bu 2 \f[CR]6 ProxyRefusedToConnect\f[R]: The proxy refused to establish a connection. .IP \(bu 2 \f[CR]7 FailedToResolveHost\f[R]: The hostname could not be resolved. .IP \(bu 2 \f[CR]8 FailedToResolveProxy\f[R]: The proxy could not be resolved. .IP \(bu 2 \f[CR]9 ProxyAuthFail\f[R]: The proxy refused the provided username/password. .IP \(bu 2 \f[CR]10 InvalidResponse\f[R]: The server\(cqs response deviates from the specification so badly that it cannot be meaningfully processed. .IP \(bu 2 \f[CR]11 ProxyInvalidResponse\f[R]: The proxy\(cqs response deviates from the specification so badly that it cannot be meaningfully processed. .SS Environment variables Chawan sets the following environment variables: .IP \(bu 2 \f[CR]SERVER_SOFTWARE=\(dqChawan\(dq\f[R] .IP \(bu 2 \f[CR]SERVER_PROTOCOL=\(dqHTTP/1.0\(dq\f[R] .IP \(bu 2 \f[CR]SERVER_NAME=\(dqlocalhost\(dq\f[R] .IP \(bu 2 \f[CR]SERVER_PORT=\(dq80\(dq\f[R] .IP \(bu 2 \f[CR]REMOTE_HOST=\(dqlocalhost\(dq\f[R] .IP \(bu 2 \f[CR]REMOTE_ADDR=\(dq127.0.0.1\(dq\f[R] .IP \(bu 2 \f[CR]GATEWAY_INTERFACE=\(dqCGI/1.1\(dq\f[R] .IP \(bu 2 \f[CR]SCRIPT_NAME=\(dq/cgi\-bin/script\-name\(dq\f[R] if called with a relative path, and \f[CR]\(dq/path/to/script/script\-name\(dq\f[R] if called with an absolute path. .IP \(bu 2 \f[CR]SCRIPT_FILENAME=\(dq/path/to/script/script\-name\(dq\f[R] .IP \(bu 2 \f[CR]QUERY_STRING=\f[R] the query string (i.e.\ \f[CR]URL.search\f[R]). This variable is percent\-encoded. .IP \(bu 2 \f[CR]PATH_INFO=\f[R] everything after the script\(cqs path name, e.g.\ for \f[CR]cgi\-bin:script\-name/abcd/efgh\f[R] \f[CR]\(dq/abcd/efgh\(dq\f[R]. This variable is NOT percent\-encoded. .IP \(bu 2 \f[CR]REQUEST_URI=\(dq$SCRIPT_NAME/$PATH_INFO?$QUERY_STRING\f[R] .IP \(bu 2 \f[CR]REQUEST_METHOD=\f[R] HTTP method used for making the request, e.g.\ GET or POST .IP \(bu 2 \f[CR]REQUEST_HEADERS=\f[R] A newline\-separated list of all headers for this request. .IP \(bu 2 \f[CR]CHA_LIBEXEC_DIR=\f[R] The libexec directory Chawan was configured to use at compile time. See the tools section below for details on why this is useful. .IP \(bu 2 \f[CR]CONTENT_TYPE=\f[R] for POST requests, the Content\-Type header. Not set for other request types (e.g.\ GET). .IP \(bu 2 \f[CR]CONTENT_LENGTH=\f[R] the content length, if $CONTENT_TYPE has been set. .IP \(bu 2 \f[CR]ALL_PROXY=\f[R] if a proxy has been set, the proxy URL. WARNING: for security reasons, this \f[B]must\f[R] be respected when making external connections. If a CGI script does not support proxies, it must never make any external connections when the \f[CR]ALL_PROXY\f[R] variable is set, but rather return an error message. .IP \(bu 2 \f[CR]HTTP_COOKIE=\f[R] if set, the Cookie header. .IP \(bu 2 \f[CR]HTTP_REFERER=\f[R] if set, the Referer header. .IP \(bu 2 \f[CR]CHA_TMP_DIR=\f[R] directory used for storing temporary files. .IP \(bu 2 \f[CR]CHA_DIR=\f[R] location of the config file. .PP For requests originating from a urimethodmap rewrite, Chawan will also set the parsed URL\(cqs parts as environment variables. Use of these is highly encouraged, to avoid exploits originating from double\-parsing of URLs. .PP If \f[CR]example://username:password\(atexample.org:1234/path/name.html?example\f[R] is the original URL, then: .IP \(bu 2 \f[CR]MAPPED_URI_SCHEME=\f[R] the scheme of the original URL, in this case \f[CR]example\f[R]. .IP \(bu 2 \f[CR]MAPPED_URI_USERNAME=\f[R] the username part, in this case \f[CR]username\f[R]. If no username was specified, the variable is set to the empty string. .IP \(bu 2 \f[CR]MAPPED_URI_PASSWORD=\f[R] the password part, in this case \f[CR]password\f[R]. If no password was specified, the variable is set to the empty string. .IP \(bu 2 \f[CR]MAPPED_URI_HOST=\f[R] the host part, in this case \f[CR]host.org\f[R] If no host was specified, the variable is set to the empty string. (An example of a URL with no host: \f[CR]about:blank\f[R], here \f[CR]blank\f[R] is the path name.) .IP \(bu 2 \f[CR]MAPPED_URI_PORT=\f[R] the port, in this case \f[CR]1234\f[R]. If no port was specified, the variable is set to the empty string. (In this case, the CGI script is expected to use the default port for the scheme, if any.) .IP \(bu 2 \f[CR]MAPPED_URI_PATH=\f[R] the path name, in this case \f[CR]/path/name.html?example\f[R]. If no path was specified, the variable is set to the empty string. The path name is percent\-encoded. .IP \(bu 2 \f[CR]MAPPED_URI_QUERY=\f[R] the query string, in this case \f[CR]example\f[R]. Unlike in JavaScript, no question mark is prepended to the string. The query string is percent\-encoded as well. .PP The fragment part is omitted intentionally. .SS Request body If the request body is not empty, it is streamed into the program through the standard input. .PP Note that this may be both an application/x\-www\-form\-urlencoded or a multipart/form\-data request; \f[CR]CONTENT_TYPE\f[R] stores information about the request type, and in case of a multipart request, the boundary as well. .SS Tools Chawan provides certain helper binaries that may be useful for CGI scripts. These can be portably accessed by executing \f[CR]\(dq$CHA_LIBEXEC_DIR\(dq/[program]\f[R]. .PP Currently, the following tools are available: .IP \(bu 2 \f[CR]urldec\f[R]: percent\-decode strings passed on standard input. .IP \(bu 2 \f[CR]urlenc\f[R]: percent\-encode strings passed on standard input, taking a percent\-encode set as the first parameter. .SS Troubleshooting Note that standard error is redirected to the browser console (by default, M\-cM\-c). This makes it easy to debug a misbehaving CGI script, but may also slow down the browser in case of excessive logging. If this is not the desired behavior, wrap your script into a shell script that redirects stderr to /dev/null. .SS My script is returning a \(lqFailed to execute script\(rq error message. This means the \f[CR]execl\f[R] call to the script failed. Make sure that your CGI script\(cqs executable bit is set, i.e.\ run \f[CR]chmod +x /path/to/cgi/script\f[R]. .SS My script is returning an \(lqinvalid CGI path\(rq error message. Make sure that you did not include leading slashes. Reminder: \f[CR]cgi\-bin://script\-name\f[R] does not work, use \f[CR]cgi\-bin:script\-name\f[R]. .SS My script is returning a \(lqCGI file not found\(rq error message. Double check that your CGI script is in the correct location. Also, make sure that you are not accidentally calling the script with an absolute path via \f[CR]cgi\-bin:/script\-name\f[R] (instead of the correct \f[CR]cgi\-bin:script\-name\f[R]). .PP It is also possible that \f[CR]external.cgi\-dir\f[R] is not really set to the directory your script is in. Note that by default, this depends on the binary\(cqs path, so e.g.\ if your binary is in \f[CR]\(ti/src/chawan/target/release/bin/cha\f[R], but you put your CGI script to \f[CR]/usr/local/libexec/chawan/cgi\-bin\f[R], then it will not work. .SS My script is returning a \(lqfailed to set up CGI script\(rq error message. This means that either \f[CR]pipe\f[R] or \f[CR]fork\f[R] failed. Maybe you are running out of memory? .SS See also \f[B]cha\f[R](1) \f[B]cha\-urimethodmap\f[R](5)