/* Copyright (C) 2015-2017 Antoine Tenart Antoine Tenart This file is licensed under the terms of the GNU General Public License version 2. This program is licensed "as is" without any warranty of any kind, whether express or implied. */ package main import ( "fmt" "log" "net" "net/http" "os" "path" "strconv" "github.com/atotto/clipboard" docopt "github.com/docopt/docopt-go" ) var ( version = "serve 0.2" usage = `Temporary HTTP server to share local files Usage: serve [options] [FILE] serve --help Options: FILE File or directory to serve [default: .] -p , --port Port number to listen on [default: 8080] -c , --count Limit the number of allowed GET to -h --help Print this help ` ) func outboundIP() net.IP { c, err := net.Dial("udp", "8.8.8.8:80") if err != nil { log.Fatal(err) } defer c.Close() return c.LocalAddr().(*net.UDPAddr).IP } func main() { var handler http.Handler = nil var count int = -1 args, _ := docopt.Parse(usage, os.Args[1:], true, version, true) f, _ := args["FILE"].(string) f = path.Clean(f) if f == "" { f = "." } resource := path.Base(f) fi, err := os.Stat(f) if err != nil { log.Fatal(err) } switch mode := fi.Mode(); { case mode.IsRegular(): if limit, ok := args["--count"].(string); ok { var err error count, err = strconv.Atoi(limit) if err != nil { log.Fatal(err) } } if resource == "." { resource = "" } handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var extra string = "" if count > 1 { extra = fmt.Sprintf(", %d remaining GET", count - 1) } client, _, err := net.SplitHostPort(r.RemoteAddr) if err != nil { client = "unknown client" } fmt.Printf("Connexion from %s requesting %s%s\n", client, r.URL.Path, extra) if r.URL.Path != fmt.Sprintf("/%s", resource) { http.Error(w, "File not found", 404) return } if count > 0 { count-- } w.Header().Set("Content-Type", "application/octet-stream") w.Header().Set("Content-Transfer-Encoding", "binary") w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", resource)) w.Header().Set("Content-Length", strconv.FormatInt(fi.Size(), 10)) w.Header().Set("Cache-Control", "private") w.Header().Set("Pragma", "private") w.Header().Set("Expires", "0") http.ServeFile(w, r, f) if count == 0 { os.Exit(0) } }) case mode.IsDir(): resource = "" handler = http.FileServer(http.Dir(f)) default: log.Fatal("Error: unsupported file type.") } uri := fmt.Sprintf("http://%s:%s/%s", outboundIP(), args["--port"].(string), resource) fmt.Printf("Serving %s at %s\n", f, uri) err = clipboard.WriteAll(uri) if err != nil { log.Print(err) } err = http.ListenAndServe(":" + args["--port"].(string), handler) if err != nil { log.Fatal(err) } }