mirror of
https://github.com/dutchcoders/transfer.sh.git
synced 2020-11-18 19:53:40 -08:00
implemented (alternate) storage providers, local file also possible now
This commit is contained in:
parent
477e02fa24
commit
16ad1833d2
@ -51,7 +51,7 @@ go get github.com/kennygrant/sanitize
|
||||
grunt serve
|
||||
grunt build
|
||||
|
||||
sh transfer-server/run.sh
|
||||
go run transfersh-server/*.go -provider=local --port 8080 --temp=/tmp/ --basedir=/tmp/
|
||||
```
|
||||
|
||||
## Build
|
||||
|
@ -35,19 +35,18 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/dutchcoders/go-clamd"
|
||||
"github.com/goamz/goamz/s3"
|
||||
"github.com/golang/gddo/httputil/header"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/kennygrant/sanitize"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"log"
|
||||
"math/rand"
|
||||
"mime"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
html_template "html/template"
|
||||
@ -112,13 +111,6 @@ func postHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
bucket, err := getBucket()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, "Error occured copying to output stream", 500)
|
||||
return
|
||||
}
|
||||
|
||||
token := Encode(10000000 + int64(rand.Intn(1000000000)))
|
||||
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
@ -175,18 +167,16 @@ func postHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
contentLength := n
|
||||
|
||||
key := fmt.Sprintf("%s/%s", token, filename)
|
||||
log.Printf("Uploading %s %s %d %s", token, filename, contentLength, contentType)
|
||||
|
||||
log.Printf("Uploading %s %d %s", key, contentLength, contentType)
|
||||
|
||||
if err = bucket.PutReader(key, reader, contentLength, contentType, s3.PublicRead, s3.Options{}); err != nil {
|
||||
if err = storage.Put(token, filename, reader, contentType, uint64(contentLength)); err != nil {
|
||||
log.Print(err)
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "https://transfer.sh/%s\n", key)
|
||||
fmt.Fprintf(w, "https://transfer.sh/%s/%s\n", token, filename)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -285,22 +275,13 @@ func putHandler(w http.ResponseWriter, r *http.Request) {
|
||||
contentType = mime.TypeByExtension(filepath.Ext(vars["filename"]))
|
||||
}
|
||||
|
||||
key := fmt.Sprintf("%s/%s", Encode(10000000+int64(rand.Intn(1000000000))), filename)
|
||||
token := Encode(10000000+int64(rand.Intn(1000000000)))
|
||||
|
||||
log.Printf("Uploading %s %d %s", key, contentLength, contentType)
|
||||
log.Printf("Uploading %s %d %s", token, filename, contentLength, contentType)
|
||||
|
||||
var b *s3.Bucket
|
||||
var err error
|
||||
|
||||
b, err = getBucket()
|
||||
if err != nil {
|
||||
http.Error(w, errors.New("Could not open bucket").Error(), 500)
|
||||
return
|
||||
}
|
||||
|
||||
err = b.PutReader(key, reader, contentLength, contentType, s3.PublicRead, s3.Options{})
|
||||
|
||||
if err != nil {
|
||||
if err = storage.Put(token, filename, reader, contentType, uint64(contentLength)); err != nil {
|
||||
http.Error(w, errors.New("Could not save file").Error(), 500)
|
||||
return
|
||||
}
|
||||
@ -309,7 +290,7 @@ func putHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
|
||||
fmt.Fprintf(w, "https://transfer.sh/%s\n", key)
|
||||
fmt.Fprintf(w, "https://transfer.sh/%s/%s\n", token, filename)
|
||||
}
|
||||
|
||||
func zipHandler(w http.ResponseWriter, r *http.Request) {
|
||||
@ -317,22 +298,19 @@ func zipHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
files := vars["files"]
|
||||
|
||||
b, err := getBucket()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
|
||||
filename := fmt.Sprintf("transfersh-%d.zip", uint16(time.Now().UnixNano()))
|
||||
zipfilename := fmt.Sprintf("transfersh-%d.zip", uint16(time.Now().UnixNano()))
|
||||
|
||||
w.Header().Set("Content-Type", "application/zip")
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", zipfilename))
|
||||
w.Header().Set("Connection", "close")
|
||||
|
||||
zw := zip.NewWriter(w)
|
||||
|
||||
for _, key := range strings.Split(files, ",") {
|
||||
rc, err := b.GetResponse(key)
|
||||
token := sanitize.Path(strings.Split(key, "/")[0])
|
||||
filename := sanitize.Path(strings.Split(key, "/")[1])
|
||||
|
||||
reader, _, _, err := storage.Get(token, filename)
|
||||
if err != nil {
|
||||
if err.Error() == "The specified key does not exist." {
|
||||
http.Error(w, "File not found", 404)
|
||||
@ -344,7 +322,7 @@ func zipHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
defer rc.Body.Close()
|
||||
defer reader.Close()
|
||||
|
||||
header := &zip.FileHeader{
|
||||
Name: strings.Split(key, "/")[1],
|
||||
@ -353,8 +331,6 @@ func zipHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ModifiedDate: uint16(time.Now().UnixNano()),
|
||||
}
|
||||
|
||||
fi := rc.Body
|
||||
|
||||
fw, err := zw.CreateHeader(header)
|
||||
|
||||
if err != nil {
|
||||
@ -363,7 +339,7 @@ func zipHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = io.Copy(fw, fi); err != nil {
|
||||
if _, err = io.Copy(fw, reader); err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
http.Error(w, "Internal server error.", 500)
|
||||
return
|
||||
@ -382,16 +358,10 @@ func tarGzHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
files := vars["files"]
|
||||
|
||||
b, err := getBucket()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
|
||||
filename := fmt.Sprintf("transfersh-%d.tar.gz", uint16(time.Now().UnixNano()))
|
||||
tarfilename := fmt.Sprintf("transfersh-%d.tar.gz", uint16(time.Now().UnixNano()))
|
||||
|
||||
w.Header().Set("Content-Type", "application/x-gzip")
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", tarfilename))
|
||||
w.Header().Set("Connection", "close")
|
||||
|
||||
os := gzip.NewWriter(w)
|
||||
@ -401,7 +371,10 @@ func tarGzHandler(w http.ResponseWriter, r *http.Request) {
|
||||
defer zw.Close()
|
||||
|
||||
for _, key := range strings.Split(files, ",") {
|
||||
rc, err := b.GetResponse(key)
|
||||
token := strings.Split(key, "/")[0]
|
||||
filename := strings.Split(key, "/")[1]
|
||||
|
||||
reader, _, contentLength, err := storage.Get(token, filename)
|
||||
if err != nil {
|
||||
if err.Error() == "The specified key does not exist." {
|
||||
http.Error(w, "File not found", 404)
|
||||
@ -413,9 +386,7 @@ func tarGzHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
defer rc.Body.Close()
|
||||
|
||||
contentLength, err := strconv.Atoi(rc.Header.Get("Content-Length"))
|
||||
defer reader.Close()
|
||||
|
||||
header := &tar.Header{
|
||||
Name: strings.Split(key, "/")[1],
|
||||
@ -429,9 +400,7 @@ func tarGzHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
fi := rc.Body
|
||||
|
||||
if _, err = io.Copy(zw, fi); err != nil {
|
||||
if _, err = io.Copy(zw, reader); err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
http.Error(w, "Internal server error.", 500)
|
||||
return
|
||||
@ -444,23 +413,20 @@ func tarHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
files := vars["files"]
|
||||
|
||||
b, err := getBucket()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
|
||||
filename := fmt.Sprintf("transfersh-%d.tar", uint16(time.Now().UnixNano()))
|
||||
tarfilename := fmt.Sprintf("transfersh-%d.tar", uint16(time.Now().UnixNano()))
|
||||
|
||||
w.Header().Set("Content-Type", "application/x-tar")
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", tarfilename))
|
||||
w.Header().Set("Connection", "close")
|
||||
|
||||
zw := tar.NewWriter(w)
|
||||
defer zw.Close()
|
||||
|
||||
for _, key := range strings.Split(files, ",") {
|
||||
rc, err := b.GetResponse(key)
|
||||
token := strings.Split(key, "/")[0]
|
||||
filename := strings.Split(key, "/")[1]
|
||||
|
||||
reader, _, contentLength, err := storage.Get(token, filename)
|
||||
if err != nil {
|
||||
if err.Error() == "The specified key does not exist." {
|
||||
http.Error(w, "File not found", 404)
|
||||
@ -472,9 +438,7 @@ func tarHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
defer rc.Body.Close()
|
||||
|
||||
contentLength, err := strconv.Atoi(rc.Header.Get("Content-Length"))
|
||||
defer reader.Close()
|
||||
|
||||
header := &tar.Header{
|
||||
Name: strings.Split(key, "/")[1],
|
||||
@ -488,9 +452,7 @@ func tarHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
fi := rc.Body
|
||||
|
||||
if _, err = io.Copy(zw, fi); err != nil {
|
||||
if _, err = io.Copy(zw, reader); err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
http.Error(w, "Internal server error.", 500)
|
||||
return
|
||||
@ -504,15 +466,7 @@ func getHandler(w http.ResponseWriter, r *http.Request) {
|
||||
token := vars["token"]
|
||||
filename := vars["filename"]
|
||||
|
||||
key := fmt.Sprintf("%s/%s", token, filename)
|
||||
|
||||
b, err := getBucket()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
|
||||
rc, err := b.GetResponse(key)
|
||||
reader, contentType, contentLength, err := storage.Get(token, filename)
|
||||
if err != nil {
|
||||
if err.Error() == "The specified key does not exist." {
|
||||
http.Error(w, "File not found", 404)
|
||||
@ -524,15 +478,13 @@ func getHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
defer rc.Body.Close()
|
||||
defer reader.Close()
|
||||
|
||||
contentType := rc.Header.Get("Content-Type")
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
w.Header().Set("Content-Length", strconv.FormatUint(contentLength, 10))
|
||||
|
||||
mediaType, _, _ := mime.ParseMediaType(contentType)
|
||||
|
||||
fmt.Println(mediaType)
|
||||
|
||||
switch {
|
||||
case mediaType == "text/html":
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
|
||||
@ -546,7 +498,7 @@ func getHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Header().Set("Connection", "close")
|
||||
|
||||
if _, err = io.Copy(w, rc.Body); err != nil {
|
||||
if _, err = io.Copy(w, reader); err != nil {
|
||||
http.Error(w, "Error occured copying to output stream", 500)
|
||||
return
|
||||
}
|
||||
|
@ -51,6 +51,8 @@ var config struct {
|
||||
Temp string
|
||||
}
|
||||
|
||||
var storage Storage
|
||||
|
||||
func init() {
|
||||
config.AWS_ACCESS_KEY = os.Getenv("AWS_ACCESS_KEY")
|
||||
config.AWS_SECRET_KEY = os.Getenv("AWS_SECRET_KEY")
|
||||
@ -111,7 +113,9 @@ func main() {
|
||||
|
||||
port := flag.String("port", "8080", "port number, default: 8080")
|
||||
temp := flag.String("temp", "", "")
|
||||
basedir := flag.String("basedir", "", "")
|
||||
logpath := flag.String("log", "", "")
|
||||
provider := flag.String("provider", "s3", "")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
@ -127,6 +131,24 @@ func main() {
|
||||
}
|
||||
|
||||
config.Temp = *temp
|
||||
|
||||
var err error
|
||||
|
||||
switch *provider {
|
||||
case "s3":
|
||||
storage, err = NewS3Storage()
|
||||
case "local":
|
||||
if *basedir == "" {
|
||||
log.Panic("basedir not set")
|
||||
}
|
||||
|
||||
storage, err = NewLocalStorage(*basedir)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Panic("Error while creating storage.")
|
||||
}
|
||||
|
||||
log.Printf("Transfer.sh server started. :%v using temp folder: %s", *port, config.Temp)
|
||||
log.Printf("---------------------------")
|
||||
|
||||
|
1
transfersh-server/static/404.txt
Normal file
1
transfersh-server/static/404.txt
Normal file
@ -0,0 +1 @@
|
||||
|
100
transfersh-server/storage.go
Normal file
100
transfersh-server/storage.go
Normal file
@ -0,0 +1,100 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"github.com/goamz/goamz/s3"
|
||||
"strconv"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type Storage interface {
|
||||
Get(token string, filename string) (reader io.ReadCloser, contentType string, contentLength uint64, err error)
|
||||
Put(token string, filename string, reader io.Reader, contentType string, contentLength uint64) error
|
||||
}
|
||||
|
||||
type LocalStorage struct {
|
||||
Storage
|
||||
basedir string
|
||||
}
|
||||
|
||||
func NewLocalStorage(basedir string) (*LocalStorage, error) {
|
||||
return &LocalStorage {basedir: basedir}, nil
|
||||
}
|
||||
|
||||
|
||||
func (s *LocalStorage) Get(token string, filename string) (reader io.ReadCloser, contentType string, contentLength uint64, err error) {
|
||||
path := filepath.Join(s.basedir, token, filename)
|
||||
|
||||
// content type , content length
|
||||
if reader, err = os.Open(path); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var fi os.FileInfo
|
||||
if fi, err = os.Lstat(path); err != nil {
|
||||
}
|
||||
|
||||
contentLength = uint64(fi.Size())
|
||||
|
||||
contentType = ""
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *LocalStorage) Put(token string, filename string, reader io.Reader, contentType string, contentLength uint64) error {
|
||||
var f io.WriteCloser
|
||||
var err error
|
||||
|
||||
path := filepath.Join(s.basedir, token)
|
||||
|
||||
if err = os.Mkdir(path, 0700); err != nil && !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
if f, err = os.OpenFile(filepath.Join(path, filename), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600); err != nil {
|
||||
fmt.Printf("%s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
if _, err = io.Copy(f, reader); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type S3Storage struct {
|
||||
Storage
|
||||
bucket *s3.Bucket
|
||||
}
|
||||
|
||||
func NewS3Storage() (*S3Storage, error) {
|
||||
bucket, err := getBucket()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &S3Storage {bucket: bucket}, nil
|
||||
}
|
||||
|
||||
func (s *S3Storage) Get(token string, filename string) (reader io.ReadCloser, contentType string, contentLength uint64, err error) {
|
||||
key := fmt.Sprintf("%s/%s", token, filename)
|
||||
|
||||
// content type , content length
|
||||
response, err := s.bucket.GetResponse(key)
|
||||
contentType = ""
|
||||
contentLength, err = strconv.ParseUint(response.Header.Get("Content-Length"), 10, 0)
|
||||
|
||||
reader = response.Body
|
||||
return
|
||||
}
|
||||
|
||||
func (s *S3Storage) Put(token string, filename string, reader io.Reader, contentType string, contentLength uint64) error {
|
||||
key := fmt.Sprintf("%s/%s", token, filename)
|
||||
err := s.bucket.PutReader(key, reader, int64(contentLength), contentType, s3.Private, s3.Options{})
|
||||
return err
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user