commit abd45c8bb0d1a36197f7782f8afd05c58aa9ceb6
parent 415f91390f5fba22aa9b2d9d43bf35bfc50ae81c
Author: Daniel Moch <daniel@danielmoch.com>
Date: Sun, 6 Dec 2020 19:37:30 -0500
Add manpages; improve readme
Diffstat:
M | .gitignore | | | 4 | +++- |
M | Makefile | | | 33 | +++++++++++++++++++++++++++------ |
M | README | | | 36 | +++++++++++++++++++++++++++++++++++- |
M | cmd/shrt/main.go | | | 38 | ++++++++++++++++++++++++-------------- |
A | config.mk | | | 9 | +++++++++ |
A | shrt.1 | | | 101 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | shrtfile.5 | | | 65 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
7 files changed, 264 insertions(+), 22 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,3 +1,5 @@
-shrt
+/shrt
shrt.conf
shrt.db
+shrt-*.tar.gz
+/shrt*/
diff --git a/Makefile b/Makefile
@@ -1,15 +1,37 @@
-VERSION := 0.1.0-dev0
+.POSIX:
+
+include config.mk
all: shrt
go.mod: cmd/shrt/main.go *.go
- go mod tidy
- touch go.mod
+ ${GO} mod tidy
+ @touch go.mod
shrt: go.mod
- go build -ldflags "-X main.version=${VERSION}" ./cmd/shrt
+ ${GO} build -ldflags ${GO_LDFLAGS} ./cmd/shrt
clean:
rm -f shrt
-.PHONY: all clean-
\ No newline at end of file
+install: shrt
+ install -Dm755 shrt ${DESTDIR}${PREFIX}/bin/shrt
+ install -Dm644 shrt.1 ${DESTDIR}${MANPATH}/man1/shrt.1
+ install -Dm644 shrt.1 ${DESTDIR}${MANPATH}/man5/shrtfile.5
+
+uninstall:
+ rm -f ${DESTDIR}${PREFIX}/bin/shrt
+ rm -f ${DESTDIR}${MANPATH}/man1/shrt.1
+ rm -f ${DESTDIR}${MANPATH}/man5/shrtfile.5
+
+dist:
+ rm -rf shrt-${VERSION}
+ mkdir shrt-${VERSION}
+ cp -r ${DIST_SRC} shrt-${VERSION}
+ tar -cf - shrt-${VERSION} | gzip > shrt-${VERSION}.tar.gz
+
+distclean:
+ rm -rf shrt-${VERSION}
+ rm -f shrt-${VERSION}.tar.gz
+
+.PHONY: all clean install uninstall dist distclean
diff --git a/README b/README
@@ -7,4 +7,38 @@ putting all the vowels in "shrt" and enjoy yourself!
Also handles go-get redirects.
There's no UI to add a new shortlink at this time. Just edit the DB by
-hand.
+hand and kill -HUP the process.
+
+building
+--------
+
+$ make
+
+installation
+------------
+
+# make install
+
+using
+-----
+
+Note that by default shrt expects its data files to be relative to the
+current directory.
+
+$ shrt -h
+usage: shrt [-hv] [-d dbpath] [-c cfgpath] [-l listenaddr] [init]
+$ shrt init
+server name: example.com
+SCM type: git # or hg, etc.. used for go-get redirects
+repo suffix (blank for none): .git # suffix to add to go-get repo URIs
+redirect base url: https://git.example.com
+bare redirect url: https://www.example.com
+$ shrt -l localhost:8080
+2020/12/06 12:57:01 listening on localhost:8080
+
+HTTPS is out-of-scope. Use a reverse-proxy with TLS termination.
+
+more documentation
+------------------
+
+$ man 1 shrt
diff --git a/cmd/shrt/main.go b/cmd/shrt/main.go
@@ -6,8 +6,11 @@ import (
"log"
"net/http"
"os"
+ "os/signal"
"path"
"strings"
+ "sync"
+ "syscall"
goshrt "djmo.ch/go-shrt"
)
@@ -23,6 +26,7 @@ const (
var (
arg0 = path.Base(os.Args[0])
+ mux = sync.RWMutex{}
shrt, cfg *goshrt.ShrtFile
version string
@@ -56,12 +60,6 @@ func handl(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("Request path not allowed\n"))
return
}
- if strings.Contains(key, "/") {
- log.Println("bad request: " + key)
- w.WriteHeader(http.StatusForbidden)
- w.Write([]byte("Request path not allowed\n"))
- return
- }
if key == "robots.txt" {
log.Println("incoming robot")
@@ -71,14 +69,6 @@ func handl(w http.ResponseWriter, req *http.Request) {
w.Write([]byte(resp))
return
}
- if key == "robots.txt" {
- log.Println("incoming robot")
- resp := "# Welcome to Shrt\n"
- resp += "User-Agent: *\n"
- resp += "Disallow:\n"
- w.Write([]byte(resp))
- return
- }
if key == "" && cfg.Get("barerdr") != "" {
log.Println("shortlink request for /")
@@ -88,6 +78,8 @@ func handl(w http.ResponseWriter, req *http.Request) {
return
}
+ mux.RLock()
+ defer mux.RUnlock()
if val := shrt.Get(key); val != "" {
log.Println("shortlink request for", key)
w.Header().Add("Location", val)
@@ -171,6 +163,22 @@ func doInit(path string) {
m.Write()
}
+func hangup(dbpath string) {
+ hup := make(chan os.Signal)
+ signal.Notify(hup, syscall.SIGHUP)
+ for {
+ <-hup
+ tmpShrt, err := goshrt.ReadShrtFile(dbpath)
+ if err != nil {
+ log.Printf("db error -- %s\n", err.Error())
+ } else {
+ mux.Lock()
+ shrt = tmpShrt
+ mux.Unlock()
+ }
+ }
+}
+
func main() {
var err error
if len(os.Args) > 4 {
@@ -223,6 +231,8 @@ func main() {
os.Exit(errShrtFile)
}
+ go hangup(dbpath)
+
http.Handle("/", http.HandlerFunc(handl))
log.Println("listening on", listenaddr)
log.Fatal(http.ListenAndServe(listenaddr, nil))
diff --git a/config.mk b/config.mk
@@ -0,0 +1,9 @@
+PREFIX := /usr/local
+MANPATH := ${PREFIX}/man
+
+SRC = cmd/shrt/main.go shrtfile.go
+DIST_SRC = cmd shrtfile.go Makefile config.mk shrt.1 shrtfile.5 README LICENSE go.mod go.sum
+VERSION := 0.1.0-dev0
+
+GO_LDFLAGS := "-X main.version=${VERSION}"
+GO := go
diff --git a/shrt.1 b/shrt.1
@@ -0,0 +1,101 @@
+.\" See LICENSE file for copyright and license details
+.Dd 2020-12-06
+.Dt SHRT 1
+.Os
+.Sh NAME
+.Nm shrt
+.Nd URL shortener and go-get handler
+.Sh SYNOPSIS
+.Nm
+.Op Fl hv
+.Op Fl c Ar cfgpath
+.Op Fl d Ar dbpath
+.Op Fl l Ar listenaddr
+.Op Ar init
+.Sh DESCRIPTION
+.Nm
+is a URL shortener service (much like bit.ly without the trackers)
+that also handles go-get requests.
+The latter are a specific GET request query used by the Go programming
+language toolchain to aid in the downloading of utilities and
+libraries prior to build and installation.
+.Pp
+Upon invocation,
+.Nm
+does one of two things is done depending on the presence or absence
+of the
+.Ar init
+argument.
+If the
+.Ar init
+argument is present, a series of questions is asked, the responses
+are recorded in a configuration file, and the program exits.
+See
+.Xr shrtfile 5
+for a description of the config file syntax and contents.
+If the
+.Ar init
+argument is absent,
+.Nm
+reads the configuration and database files into memory, binds to
+the port specified by the
+.Fl l
+flag, and begins serving requests.
+.Pp
+Shortlinks are recorded in the database, and any request path not
+matching a shortlink is assumed to be a go-get request.
+This is by design, but can result in specious redirects.
+Additionally, subdirectory paths are not allowed.
+.Pp
+Shortlinks generate an HTTP 301 response.
+Go-get requests generate an HTTP 200 response.
+If configured, requests to the base path (i.e., "/") generate an
+HTTP 302 response.
+.Pp
+The database file is human-readable and formatted according to
+.Xr shrtfile 5 ,
+basically a key-value store.
+In order to add a new shortlink to the database, simply edit the file.
+After saving, send SIGHUP to a running server process to reload the
+file (see
+.Xr kill 1 ).
+.Sh OPTIONS
+.Bl -tag -width Ds
+.It Fl h
+Print usage and exit.
+.It Fl v
+Print version and exit.
+.It Fl c Ar cfgpath
+Change the path to search for the configuration file (default: shrt.conf)
+.It Fl d Ar dbpath
+Change the path to search for the database (default: shrt.db)
+.It Fl l Ar listenaddr
+Change the address:port to bind to (default: 0.0.0.0:8080)
+.El
+.Sh EXAMPLES
+Initialize the
+.Nm
+configuration file:
+.Pp
+.Dl $ shrt init
+.Pp
+Run the server on localhost, port 8080:
+.Pp
+.Dl $ shrt -l localhost:8080
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr shrtfile 5 ,
+.Xr kill 1
+.br
+RFC 7231: Hypertext Transfer Protocol (HTTP/1.1): Semantics and
+Content
+.br
+.Lk https://golang.org/doc/articles/go_command.html?h=go+get "About the go command"
+.Sh HISTORY
+.Nm
+began in November 2020.
+.Sh AUTHORS
+.Nm
+was written by
+.An Daniel Moch Aq Mt daniel@danielmoch.com .
diff --git a/shrtfile.5 b/shrtfile.5
@@ -0,0 +1,65 @@
+.\" See LICENSE file for copyright and license details
+.Dd 2020-12-06
+.Dt SHRTFILE 5
+.Os
+.Sh NAME
+.Nm shrtfile ,
+.Nm shrt.conf ,
+.Nm shrt.db
+.Nd URL shortener data files
+.Sh DESCRIPTION
+Shrtfiles are simple key-value values used by the
+.Xr shrt 1
+URL shortener.
+The syntax of the file is human readable.
+Each line represents a key-value pair.
+The key is everything to the left of the first equals sign, and the
+value is everything to the right.
+Whitespace is trimmed from the beginning and end of both keys and
+values.
+.Pp
+.Pa shrt.db
+Is a shrtfile containing all of the shortlinks recognized by the server.
+The key is the shortlink (i.e., the request path), and the value
+is the redirect URL.
+.Pp
+.Pa shrt.conf
+is a shrtfile with a specific set of keys:
+.Bl -tag -width Ds -compact
+.It srvname
+This is the FQDN of the
+.Xr shrt 1
+server instance.
+By convention URL shorteners keep this as short as possible (think
+bit.ly, or something similar).
+.It scmtype
+The scmtype defines what SCM type to insert into go-get responses
+(e.g., git, hg).
+.It suffix
+The suffix is appended to the redirect URL for go-get requests.
+Use this if, for instance, you're redirecting to a Git server that
+uses the .git extension for all of its clone URLs.
+.It rdrname
+The rdrname is the full, base URL to use for go-get redirects.
+The formula for these redirects is {rdrname}/{request path}{suffix}.
+.It barerdr
+The barerdr is the redirect URL for requests to the base path (i.e.,
+"/").
+.El
+.Sh FILES
+.Bl -tag -width Ds -compact
+.It Pa shrt.conf
+.It Pa shrt.db
+.El
+.Sh EXAMPLES
+The following file contents would suffice for
+.Pa shrt.conf :
+.Bd -literal
+srvname = example.com
+scmtype = git
+suffix = .git
+rdrname = https://git.example.com
+barerdr = https://www.example.com
+.Ed
+.Sh SEE ALSO
+.Xr shrt 1