add CGI docs to readme, make readme gmi compatible and add $DATA_LENGTH to cgi vars

This commit is contained in:
Hedy Li 2021-08-03 10:43:41 +08:00
parent 44b8fc116d
commit 01e0687594
Signed by: hedy
GPG Key ID: B51B5A8D1B176372
3 changed files with 53 additions and 22 deletions

View File

@ -6,21 +6,24 @@ A static spartan server with many features:
* /~user directories * /~user directories
* directory listing * directory listing
* CONF or TOML config file * CONF or TOML config file
* directory listing options
* user directory feature and userdir path
* CGI * CGI
* per user CGI (unsafe, like molly-brown)
* input data as stdin pipe
## install ## install
you have two options for now:
### with `go get` ### with `go get`
first, you need to have go installed and have a folder `~/go` with `$GOPATH` pointing to it. first, you need to have go installed and have a folder `~/go` with `$GOPATH` pointing to it.
then you can call `go get git.sr.ht/~hedy/spsrv` and there will be a binary at `~/go/bin/` with the source code at `~/go/src/`
```
go get git.sr.ht/~hedy/spsrv
```
there will be a binary at `~/go/bin/` with the source code at `~/go/src/`
feel free to move the binary somewhere else like `/usr/sbin/` feel free to move the binary somewhere else like `/usr/sbin/`
### build it yourself ### or just build it yourself
run `git clone https://git.sr.ht/~hedy/spsrv` from any directory and `cd spsrv` run `git clone https://git.sr.ht/~hedy/spsrv` from any directory and `cd spsrv`
make sure you have go installed and working. make sure you have go installed and working.
@ -28,10 +31,14 @@ make sure you have go installed and working.
``` ```
go build go build
``` ```
when it finishes, the binary will be in the current directory. when it finishes, the binary will be in the current directory.
### otherwise...
If you don't have/want go installed, you can contact me, and if you're lucky, I have the same OS as you and you can use my compiled binary (lol). I'll eventually have automated uploads of binaries for various architectures for each release in the future. If you don't have/want go installed, you can contact me, and if you're lucky, I have the same OS as you and you can use my compiled binary (lol). I'll eventually have automated uploads of binaries for various architectures for each release in the future.
## configuration ## configuration
The default config file location is `/etc/spsrv.conf` you can specify your own path by running spsrv like The default config file location is `/etc/spsrv.conf` you can specify your own path by running spsrv like
@ -49,26 +56,26 @@ Here are the config options and their default values
**general** **general**
- `port=300`: port to listen to * `port=300`: port to listen to
- `hostname="localhost"`: if this is set, any request that for hostnames other than this value would be rejected * `hostname="localhost"`: if this is set, any request that for hostnames other than this value would be rejected
- `rootdir="/var/spartan"`: folder for fetching files * `rootdir="/var/spartan"`: folder for fetching files
**directory listing** **directory listing**
- `dirlistEnable=true`: enable directory listing for folders that does not have `index.gmi` * `dirlistEnable=true`: enable directory listing for folders that does not have `index.gmi`
- `dirlistReverse=false`: reverse the order of which files are listed * `dirlistReverse=false`: reverse the order of which files are listed
- `dirlistSort="name"`: how files are sorted, only "name", "size", and "time" are accepted. Defaults to "name" if an unknown option is encountered * `dirlistSort="name"`: how files are sorted, only "name", "size", and "time" are accepted. Defaults to "name" if an unknown option is encountered
- `dirlistTitles=true`: if true, directory listing will use first top level header in `*.gmi` files instead of the filename * `dirlistTitles=true`: if true, directory listing will use first top level header in `*.gmi` files instead of the filename
**~user/ directories** **~user/ directories**
- `userdirEnable=true`: enable serving `/~user/*` requests * `userdirEnable=true`: enable serving `/~user/*` requests
- `userdir="public_spartan"`: root directory for users. This should not have trailing slashes, and it is relative to `/home/user/` * `userdir="public_spartan"`: root directory for users. This should not have trailing slashes, and it is relative to `/home/user/`
**CGI** **CGI**
- `CGIPaths=["cgi/"]`: list of paths where world-executable files will be run as CGI processes. These paths would be checked if it prefix the requested path. For the default value, a request of `/cgi/hi.sh` (requesting to `./public/cgi/hi.sh`, for example) will run `hi.sh` script if it's world executable. * `CGIPaths=["cgi/"]`: list of paths where world-executable files will be run as CGI processes. These paths would be checked if it prefix the requested path. For the default value, a request of `/cgi/hi.sh` (requesting to `./public/cgi/hi.sh`, for example) will run `hi.sh` script if it's world executable.
- `usercgiEnable=false`: enable running user's CGI scripts too. This is dangerous as spsrv does not (yet) change the Uid of the CGI process, hence the process would be ran by the same user that is running the server, which could mean write access to configuration files, etc. Note that this option will be assumed `false` if `userdirEnable` is set to `false`. Which means if user directories are not enabled, there will be no per-user CGI. * `usercgiEnable=false`: enable running user's CGI scripts too. This is dangerous as spsrv does not (yet) change the Uid of the CGI process, hence the process would be ran by the same user that is running the server, which could mean write access to configuration files, etc. Note that this option will be assumed `false` if `userdirEnable` is set to `false`. Which means if user directories are not enabled, there will be no per-user CGI.
## CLI ## CLI
@ -83,13 +90,34 @@ Usage: spsrv [ [ -c <path> -h <hostname> -p <port> -d <path> ] | --help ]
-p, --port int Port to listen to`) -p, --port int Port to listen to`)
``` ```
Note that you *cannot* set the hostname or the dir path to `,` because spsrv uses that to check whether Note that you *cannot* set the hostname or the dir path to `,` because spsrv uses that to check whether you provided an option. You can't set port to `0` either, sorry, this limitation comes with the advantage of being able to override config values from the command line.
you provided an option. You can't set port to `0` either, sorry, this limitation comes with the advantage
of being able to override config values from the command line.
There are no arguments wanted when running spsrv, only options as listed above :) There are no arguments wanted when running spsrv, only options as listed above :)
## CGI
The following environment values are set for CGI scripts:
```
GATEWAY_INTERFACE # CGI/1.1
REMOTE_ADDR # Remote address
SCRIPT_PATH # (Relative) path of the CGI script
SERVER_SOFTWARE # SPSRV
SERVER_PROTOCOL # SPARTAN
REQUEST_METHOD # Set to nothing
SERVER_PORT # Port
SERVER_NAME # Hostname
DATA_LENGTH # Input data length
```
The data block, if any, will be piped as stdin to the CGI process.
Keep in mind that CGI scripts (as of now) are run by the same user as the server process, hence it is generally dangerous for allowing users to have their own CGI scripts. See configuration section for more details.
## todo ## todo
```
- [x] /folder to /folder/ redirects - [x] /folder to /folder/ redirects
- [x] directory listing - [x] directory listing
- [ ] logging to files - [ ] logging to files
@ -107,3 +135,4 @@ There are no arguments wanted when running spsrv, only options as listed above :
- [x] pipe data block - [x] pipe data block
- [ ] user cgi config and change uid to user - [ ] user cgi config and change uid to user
- [ ] regex in cgi paths - [ ] regex in cgi paths
```

View File

@ -110,13 +110,14 @@ func prepareCGIVariables(conf *Config, req *Request, script_path string) map[str
func prepareGatewayVariables(conf *Config, req *Request) map[string]string { func prepareGatewayVariables(conf *Config, req *Request) map[string]string {
vars := make(map[string]string) vars := make(map[string]string)
// vars["QUERY_STRING"] = URL.RawQuery
vars["REQUEST_METHOD"] = "" vars["REQUEST_METHOD"] = ""
vars["SERVER_NAME"] = conf.Hostname vars["SERVER_NAME"] = conf.Hostname
vars["SERVER_PORT"] = strconv.Itoa(conf.Port) vars["SERVER_PORT"] = strconv.Itoa(conf.Port)
vars["SERVER_PROTOCOL"] = "SPARTAN" vars["SERVER_PROTOCOL"] = "SPARTAN"
vars["SERVER_SOFTWARE"] = "SPSRV" vars["SERVER_SOFTWARE"] = "SPSRV"
vars["DATA_LENGTH"] = strconv.Itoa(req.dataLen)
host, _, _ := net.SplitHostPort((*req.netConn).RemoteAddr().String()) host, _, _ := net.SplitHostPort((*req.netConn).RemoteAddr().String())
vars["REMOTE_ADDR"] = host vars["REMOTE_ADDR"] = host
return vars return vars

View File

@ -24,6 +24,7 @@ type Request struct {
user string user string
path string // Requested path path string // Requested path
filePath string // Actual file path that does not include the content dir name filePath string // Actual file path that does not include the content dir name
dataLen int
data string data string
} }
@ -184,7 +185,7 @@ func handleConnection(netConn net.Conn, conf *Config) {
data += newData data += newData
} }
} }
req := &Request{path: reqPath, netConn: &netConn, conn: conn, data: data} req := &Request{path: reqPath, netConn: &netConn, conn: conn, data: data, dataLen: dataLen}
// Time to fetch the files! // Time to fetch the files!
path := resolvePath(reqPath, conf, req) path := resolvePath(reqPath, conf, req)