main.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /*
  2. Copyright (C) 2015-2017 Antoine Tenart
  3. Antoine Tenart <antoine.tenart@ack.tf>
  4. This file is licensed under the terms of the GNU General Public License version
  5. 2. This program is licensed "as is" without any warranty of any kind, whether
  6. express or implied.
  7. */
  8. package main
  9. import (
  10. "fmt"
  11. "log"
  12. "net"
  13. "net/http"
  14. "os"
  15. "path"
  16. "strconv"
  17. "strings"
  18. "github.com/atotto/clipboard"
  19. docopt "github.com/docopt/docopt-go"
  20. )
  21. var (
  22. version = "serve 0.2"
  23. usage = `Temporary HTTP server to share local files
  24. Usage:
  25. serve [options] [FILE]
  26. serve --help
  27. Options:
  28. FILE File or directory to serve [default: .]
  29. -p <port>, --port <port> Port number to listen on [default: 8080]
  30. -c <count>, --count <count> Limit the number of allowed GET to <count>
  31. -h --help Print this help
  32. `
  33. )
  34. func outboundIP() net.IP {
  35. c, err := net.Dial("udp", "8.8.8.8:80")
  36. if err != nil {
  37. log.Fatal(err)
  38. }
  39. defer c.Close()
  40. return c.LocalAddr().(*net.UDPAddr).IP
  41. }
  42. func logConnexion(r *http.Request, extra string) {
  43. client, _, err := net.SplitHostPort(r.RemoteAddr)
  44. if err != nil {
  45. client = "unknown client"
  46. }
  47. fmt.Printf("Connexion from %s requesting %s%s\n", client,
  48. r.URL.Path, extra)
  49. }
  50. func main() {
  51. var handler http.Handler = nil
  52. var count int = -1
  53. args, _ := docopt.Parse(usage, os.Args[1:], true, version, true)
  54. f, _ := args["FILE"].(string)
  55. f = path.Clean(f)
  56. if f == "" {
  57. f = "."
  58. }
  59. resource := path.Base(f)
  60. fi, err := os.Stat(f)
  61. if err != nil {
  62. log.Fatal(err)
  63. }
  64. switch mode := fi.Mode(); {
  65. case mode.IsRegular():
  66. if limit, ok := args["--count"].(string); ok {
  67. var err error
  68. count, err = strconv.Atoi(limit)
  69. if err != nil {
  70. log.Fatal(err)
  71. }
  72. }
  73. if resource == "." {
  74. resource = ""
  75. }
  76. handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  77. var extra string = ""
  78. if count > 1 {
  79. extra = fmt.Sprintf(", %d remaining GET",
  80. count-1)
  81. }
  82. logConnexion(r, extra)
  83. if r.URL.Path != fmt.Sprintf("/%s", resource) {
  84. http.Error(w, "File not found", 404)
  85. return
  86. }
  87. if count > 0 {
  88. count--
  89. }
  90. w.Header().Set("Content-Type", "application/octet-stream")
  91. w.Header().Set("Content-Transfer-Encoding", "binary")
  92. w.Header().Set("Content-Disposition",
  93. fmt.Sprintf("attachment; filename=%s", resource))
  94. w.Header().Set("Content-Length",
  95. strconv.FormatInt(fi.Size(), 10))
  96. w.Header().Set("Cache-Control", "private")
  97. w.Header().Set("Pragma", "private")
  98. w.Header().Set("Expires", "0")
  99. http.ServeFile(w, r, f)
  100. if count == 0 {
  101. os.Exit(0)
  102. }
  103. })
  104. case mode.IsDir():
  105. resource = ""
  106. handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  107. logConnexion(r, "")
  108. upath := r.URL.Path
  109. if !strings.HasPrefix(upath, "/") {
  110. upath = fmt.Sprintf("/%s", upath)
  111. }
  112. http.ServeFile(w, r, fmt.Sprintf("%s%s", f, upath))
  113. })
  114. default:
  115. log.Fatal("Error: unsupported file type.")
  116. }
  117. uri := fmt.Sprintf("http://%s:%s/%s", outboundIP(), args["--port"].(string), resource)
  118. fmt.Printf("Serving %s at %s\n", f, uri)
  119. err = clipboard.WriteAll(uri)
  120. if err != nil {
  121. log.Print(err)
  122. }
  123. err = http.ListenAndServe(fmt.Sprintf(":%s", args["--port"].(string)), handler)
  124. if err != nil {
  125. log.Fatal(err)
  126. }
  127. }