Browse Source

implemented (alternate) storage providers, local file also possible now

tags/v1.0.0
Remco 9 years ago
parent
commit
16ad1833d2
5 changed files with 160 additions and 85 deletions
  1. +1
    -1
      README.md
  2. +36
    -84
      transfersh-server/handlers.go
  3. +22
    -0
      transfersh-server/main.go
  4. +1
    -0
      transfersh-server/static/404.txt
  5. +100
    -0
      transfersh-server/storage.go

+ 1
- 1
README.md View File

@@ -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


+ 36
- 84
transfersh-server/handlers.go View File

@@ -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
}


+ 22
- 0
transfersh-server/main.go View File

@@ -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
- 0
transfersh-server/static/404.txt View File

@@ -0,0 +1 @@


+ 100
- 0
transfersh-server/storage.go View 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…
Cancel
Save