Browse Source

Various improvements

Signed-off-by: Antoine Tenart <antoine.tenart@ack.tf>
Antoine Tenart 7 years ago
parent
commit
524b77aa52
4 changed files with 123 additions and 68 deletions
  1. 1 1
      .gitignore
  2. 2 2
      README.md
  3. 120 0
      main.go
  4. 0 65
      webserv.go

+ 1 - 1
.gitignore

@@ -1 +1 @@
-webserv
+serve

+ 2 - 2
README.md

@@ -1,5 +1,5 @@
-# Webserv
+# Serve
 
-Webserv is a stupid simple program to share files and directories over http from
+Serve is a stupid simple program to share files and directories over http from
 the command line. It is written in Go and can also be used to stream videos or
 big files, where Pyhton's SimpleHTTPServer can't.

+ 120 - 0
main.go

@@ -0,0 +1,120 @@
+/*
+Copyright (C) 2015-2017 Antoine Tenart
+
+Antoine Tenart <antoine.tenart@ack.tf>
+
+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 <port>             Port number to listen on [default: 8080]
+  -c <count>, --count <count>          Limit the number of allowed GET to <count>
+  -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) }
+}

+ 0 - 65
webserv.go

@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2015 Antoine Tenart
- *
- * Antoine Tenart <antoine.tenart@ack.tf>
- *
- * 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 (
-	"errors"
-	"net/http"
-	"os"
-	"path"
-
-	docopt "github.com/docopt/docopt-go"
-)
-
-var (
-	version = "webserv 0.1"
-	usage = `Temporary http server to serve files
-
-Usage:
-  webserv [-d <directory> | -f <file>] [-p <port>]
-  webserv --help
-
-Options:
-  -d <directory>, --dir <directory>    Serve the given directory [default: ./]
-  -f <file>, --file <file>             Serve the given file
-  -p <port>, --port <port>             Port number to listen on [default: 8080]
-  --help                               Print this help
-`
-)
-
-type File string
-
-func (f File) Open(name string) (http.File, error) {
-	if name != ("/" + path.Clean(string(f))) {
-		return nil, errors.New("http: invalid request")
-	}
-
-	file, err := os.Open(string(f))
-	if err != nil {
-		return nil, err
-	}
-
-	return file, nil
-}
-
-func main() {
-	var fs http.FileSystem
-
-	args, _ := docopt.Parse(usage, os.Args[1:], true, version, true)
-
-	if f, ok := args["--file"].(string); ok {
-		fs = File(f)
-	} else {
-		fs = http.Dir(args["--dir"].(string))
-	}
-	http.Handle("/", http.FileServer(fs))
-	http.ListenAndServe(":" + args["--port"].(string), nil)
-}