Skip to content

Instantly share code, notes, and snippets.

@miku
Last active December 11, 2023 21:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save miku/b5d856ef96a1f78530d8abbeb8f4d13d to your computer and use it in GitHub Desktop.
Save miku/b5d856ef96a1f78530d8abbeb8f4d13d to your computer and use it in GitHub Desktop.
Share directory via HTTP, similar to python -m SimpleHTTPServer - webshare
module gist.github.com/miku/b5d856ef96a1f78530d8abbeb8f4d13d
go 1.15
require github.com/mdp/qrterminal/v3 v3.0.0 // indirect
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mdp/qrterminal v1.0.1 h1:07+fzVDlPuBlXS8tB0ktTAyf+Lp1j2+2zK3fBOL5b7c=
github.com/mdp/qrterminal v1.0.1/go.mod h1:Z33WhxQe9B6CdW37HaVqcRKzP+kByF3q/qLxOGe12xQ=
github.com/mdp/qrterminal/v3 v3.0.0 h1:ywQqLRBXWTktytQNDKFjhAvoGkLVN3J2tAFZ0kMd9xQ=
github.com/mdp/qrterminal/v3 v3.0.0/go.mod h1:NJpfAs7OAm77Dy8EkWrtE4aq+cE6McoLXlBqXQEwvE0=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=
rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs=
.PHONY: clean install
webshare: webshare.go
go build -o $@ $<
clean:
rm -f webshare
rm -f webshare.1
webshare.1: webshare.md
pandoc $< -s -t man > $@
PREFIX = $(HOME)
BINDIR = $(PREFIX)/bin
MANDIR = $(PREFIX)/man/man1
install: webshare webshare.1
install -d $(BINDIR) $(MANDIR)
install webshare $(BINDIR)
install webshare.1 $(MANDIR)
// webshare serves the current directory on port 3000.
package main
import (
"flag"
"fmt"
"log"
"net"
"net/http"
"os"
"path"
"strings"
"github.com/mdp/qrterminal"
)
var (
port = flag.Int("p", 3000, "port to listen on")
directory = flag.String("d", ".", "directory to share")
qrPrefix = flag.String("q", "192", "ip addr prefix to print qr code for")
)
var privateIPBlocks []*net.IPNet
func init() {
for _, cidr := range []string{
"127.0.0.0/8", // IPv4 loopback
"10.0.0.0/8", // RFC1918
"172.16.0.0/12", // RFC1918
"192.168.0.0/16", // RFC1918
"169.254.0.0/16", // RFC3927 link-local
"::1/128", // IPv6 loopback
"fe80::/10", // IPv6 link-local
"fc00::/7", // IPv6 unique local addr
} {
_, block, err := net.ParseCIDR(cidr)
if err != nil {
panic(fmt.Errorf("parse error on %q: %v", cidr, err))
}
privateIPBlocks = append(privateIPBlocks, block)
}
}
func isPrivateIP(ip net.IP) bool {
if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() {
return true
}
for _, block := range privateIPBlocks {
if block.Contains(ip) {
return true
}
}
return false
}
func loggingHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Println(r.RemoteAddr, r.Method, r.URL.Path)
fn := path.Join(".", r.URL.Path)
file, err := os.Open(fn)
if err == nil {
defer file.Close()
fi, err := file.Stat()
if err == nil {
log.Printf("%s [%d]", file.Name(), fi.Size())
}
}
h.ServeHTTP(w, r)
})
}
func main() {
flag.Parse()
fs := http.FileServer(http.Dir(*directory))
http.Handle("/", loggingHandler(fs))
addrs, err := net.InterfaceAddrs()
if err != nil {
log.Fatal(err)
}
config := qrterminal.Config{
Level: qrterminal.M,
Writer: os.Stdout,
BlackChar: qrterminal.WHITE,
WhiteChar: qrterminal.BLACK,
QuietZone: 1,
}
for _, addr := range addrs {
if ipnet, ok := addr.(*net.IPNet); ok {
if ipnet.IP.To4() != nil {
mark := "public"
if isPrivateIP(ipnet.IP) {
mark = "private"
}
link := fmt.Sprintf("http://%s:%d", ipnet.IP.String(), *port)
log.Printf("%s [%s]", link, mark)
if strings.HasPrefix(ipnet.IP.String(), *qrPrefix) {
qrterminal.GenerateWithConfig(link, config)
}
}
}
}
if err := http.ListenAndServe(fmt.Sprintf(":%d", *port), nil); err != nil {
log.Fatal(err)
}
}

% WEBSHARE(1) % Martin Czygan % November 2018

NAME

webshare - share a directory over HTTP

SYNOPSIS

webshare [-p PORT] [-d DIRECTORY]

DESCRIPTION

Share a directory over HTTP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment