1
0
mirror of https://github.com/Luzifer/cloudkeys-go.git synced 2024-09-19 15:42:58 +00:00

introduced context to all http handlers and use a specific http client

for S3 requests
This commit is contained in:
Martin Thielecke 2017-12-28 01:40:20 +00:00
parent 54526cff4c
commit 84d1c7e741
9 changed files with 59 additions and 45 deletions

21
ajax.go
View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"context"
"crypto/sha1" "crypto/sha1"
"encoding/json" "encoding/json"
"fmt" "fmt"
@ -23,16 +24,16 @@ func (a ajaxResponse) Bytes() []byte {
return out return out
} }
func ajaxGetHandler(res http.ResponseWriter, r *http.Request, session *sessions.Session, ctx *pongo2.Context) (*string, error) { func ajaxGetHandler(c context.Context, res http.ResponseWriter, r *http.Request, session *sessions.Session, ctx *pongo2.Context) (*string, error) {
res.Header().Set("Content-Type", "application/json") res.Header().Set("Content-Type", "application/json")
user, _ := checkLogin(r, session) user, _ := checkLogin(c, r, session)
if user == nil || !storage.IsPresent(user.UserFile) { if user == nil || !storage.IsPresent(c, user.UserFile) {
res.Write(ajaxResponse{Error: true}.Bytes()) res.Write(ajaxResponse{Error: true}.Bytes())
return nil, nil return nil, nil
} }
userFileRaw, err := storage.Read(user.UserFile) userFileRaw, err := storage.Read(c, user.UserFile)
if err != nil { if err != nil {
log.WithError(err).Error("Could not read user file from storage") log.WithError(err).Error("Could not read user file from storage")
res.Write(ajaxResponse{Error: true}.Bytes()) res.Write(ajaxResponse{Error: true}.Bytes())
@ -45,21 +46,21 @@ func ajaxGetHandler(res http.ResponseWriter, r *http.Request, session *sessions.
return nil, nil return nil, nil
} }
func ajaxPostHandler(res http.ResponseWriter, r *http.Request, session *sessions.Session, ctx *pongo2.Context) (*string, error) { func ajaxPostHandler(c context.Context, res http.ResponseWriter, r *http.Request, session *sessions.Session, ctx *pongo2.Context) (*string, error) {
res.Header().Set("Content-Type", "application/json") res.Header().Set("Content-Type", "application/json")
user, _ := checkLogin(r, session) user, _ := checkLogin(c, r, session)
if user == nil { if user == nil {
res.Write(ajaxResponse{Error: true, Type: "login"}.Bytes()) res.Write(ajaxResponse{Error: true, Type: "login"}.Bytes())
return nil, nil return nil, nil
} }
if !storage.IsPresent(user.UserFile) { if !storage.IsPresent(c, user.UserFile) {
res.Write(ajaxResponse{Error: true, Type: "register"}.Bytes()) res.Write(ajaxResponse{Error: true, Type: "register"}.Bytes())
return nil, nil return nil, nil
} }
userFileRaw, err := storage.Read(user.UserFile) userFileRaw, err := storage.Read(c, user.UserFile)
if err != nil { if err != nil {
log.WithError(err).Error("Could not read user file from storage") log.WithError(err).Error("Could not read user file from storage")
res.Write(ajaxResponse{Error: true, Type: "storage_error"}.Bytes()) res.Write(ajaxResponse{Error: true, Type: "storage_error"}.Bytes())
@ -84,7 +85,7 @@ func ajaxPostHandler(res http.ResponseWriter, r *http.Request, session *sessions
return nil, nil return nil, nil
} }
if err := storage.Backup(user.UserFile); err != nil { if err := storage.Backup(c, user.UserFile); err != nil {
log.WithError(err).Error("Could not create backup of user file") log.WithError(err).Error("Could not create backup of user file")
res.Write(ajaxResponse{Error: true, Type: "storage_error"}.Bytes()) res.Write(ajaxResponse{Error: true, Type: "storage_error"}.Bytes())
return nil, nil return nil, nil
@ -95,7 +96,7 @@ func ajaxPostHandler(res http.ResponseWriter, r *http.Request, session *sessions
d, _ := userFile.GetData() d, _ := userFile.GetData()
if err := storage.Write(user.UserFile, d); err != nil { if err := storage.Write(c, user.UserFile, d); err != nil {
log.WithError(err).Error("Could not write user file to storage") log.WithError(err).Error("Could not write user file to storage")
res.Write(ajaxResponse{Error: true, Type: "storage_error"}.Bytes()) res.Write(ajaxResponse{Error: true, Type: "storage_error"}.Bytes())
return nil, nil return nil, nil

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"context"
"net/http" "net/http"
"github.com/flosch/pongo2" "github.com/flosch/pongo2"
@ -8,7 +9,7 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
type httpHelperFunc func(res http.ResponseWriter, r *http.Request, session *sessions.Session, ctx *pongo2.Context) (*string, error) type httpHelperFunc func(c context.Context, res http.ResponseWriter, r *http.Request, session *sessions.Session, ctx *pongo2.Context) (*string, error)
func httpHelper(f httpHelperFunc) http.HandlerFunc { func httpHelper(f httpHelperFunc) http.HandlerFunc {
return func(res http.ResponseWriter, r *http.Request) { return func(res http.ResponseWriter, r *http.Request) {
@ -19,7 +20,9 @@ func httpHelper(f httpHelperFunc) http.HandlerFunc {
ctx["error"] = errFlash[0].(string) ctx["error"] = errFlash[0].(string)
} }
template, err := f(res, r, sess, &ctx) c := getContext(r)
template, err := f(c, res, r, sess, &ctx)
if err != nil { if err != nil {
http.Error(res, "An error ocurred.", http.StatusInternalServerError) http.Error(res, "An error ocurred.", http.StatusInternalServerError)
log.WithError(err).Error("Unable to execute template") log.WithError(err).Error("Unable to execute template")
@ -27,8 +30,7 @@ func httpHelper(f httpHelperFunc) http.HandlerFunc {
} }
if template != nil { if template != nil {
ts := pongo2.NewSet("frontend") ts := pongo2.NewSet("frontend", pongo2.MustNewLocalFileSystemLoader("templates"))
ts.SetBaseDirectory("templates")
tpl, err := ts.FromFile(*template) tpl, err := ts.FromFile(*template)
if err != nil { if err != nil {
log.WithError(err).WithFields(log.Fields{ log.WithError(err).WithFields(log.Fields{
@ -52,7 +54,7 @@ func httpHelper(f httpHelperFunc) http.HandlerFunc {
} }
func simpleTemplateOutput(template string) httpHelperFunc { func simpleTemplateOutput(template string) httpHelperFunc {
return func(res http.ResponseWriter, r *http.Request, session *sessions.Session, ctx *pongo2.Context) (*string, error) { return func(c context.Context, res http.ResponseWriter, r *http.Request, session *sessions.Session, ctx *pongo2.Context) (*string, error) {
return &template, nil return &template, nil
} }
} }

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"context"
"crypto/sha1" "crypto/sha1"
"fmt" "fmt"
"net/http" "net/http"
@ -15,19 +16,19 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
func loginHandler(res http.ResponseWriter, r *http.Request, session *sessions.Session, ctx *pongo2.Context) (*string, error) { func loginHandler(c context.Context, res http.ResponseWriter, r *http.Request, session *sessions.Session, ctx *pongo2.Context) (*string, error) {
var ( var (
username = strings.ToLower(r.FormValue("username")) username = strings.ToLower(r.FormValue("username"))
password = r.FormValue("password") password = r.FormValue("password")
deprecatedPassword = fmt.Sprintf("%x", sha1.Sum([]byte(cfg.PasswordSalt+r.FormValue("password")))) // Here for backwards compatibility deprecatedPassword = fmt.Sprintf("%x", sha1.Sum([]byte(cfg.PasswordSalt+r.FormValue("password")))) // Here for backwards compatibility
) )
if !storage.IsPresent(createUserFilename(username)) { if !storage.IsPresent(c, createUserFilename(username)) {
(*ctx)["error"] = true (*ctx)["error"] = true
return stringPointer("login.html"), nil return stringPointer("login.html"), nil
} }
userFileRaw, err := storage.Read(createUserFilename(username)) userFileRaw, err := storage.Read(c, createUserFilename(username))
if err != nil { if err != nil {
log.WithError(err).Error("Unable to read user file") log.WithError(err).Error("Unable to read user file")
(*ctx)["error"] = true (*ctx)["error"] = true
@ -68,14 +69,14 @@ func loginHandler(res http.ResponseWriter, r *http.Request, session *sessions.Se
return nil, nil return nil, nil
} }
func logoutHandler(res http.ResponseWriter, r *http.Request, session *sessions.Session, ctx *pongo2.Context) (*string, error) { func logoutHandler(c context.Context, res http.ResponseWriter, r *http.Request, session *sessions.Session, ctx *pongo2.Context) (*string, error) {
session.Values["authorizedAccounts"] = authorizedAccounts{} session.Values["authorizedAccounts"] = authorizedAccounts{}
session.Save(r, res) session.Save(r, res)
http.Redirect(res, r, "overview", http.StatusFound) http.Redirect(res, r, "overview", http.StatusFound)
return nil, nil return nil, nil
} }
func checkLogin(r *http.Request, session *sessions.Session) (*authorizedAccount, error) { func checkLogin(c context.Context, r *http.Request, session *sessions.Session) (*authorizedAccount, error) {
vars := mux.Vars(r) vars := mux.Vars(r)
idx, err := strconv.ParseInt(vars["userIndex"], 10, 64) idx, err := strconv.ParseInt(vars["userIndex"], 10, 64)
if err != nil { if err != nil {

View File

@ -1,16 +1,17 @@
package main package main
import ( import (
"context"
"net/http" "net/http"
"github.com/flosch/pongo2" "github.com/flosch/pongo2"
"github.com/gorilla/sessions" "github.com/gorilla/sessions"
) )
func overviewHandler(res http.ResponseWriter, r *http.Request, session *sessions.Session, ctx *pongo2.Context) (*string, error) { func overviewHandler(c context.Context, res http.ResponseWriter, r *http.Request, session *sessions.Session, ctx *pongo2.Context) (*string, error) {
user, _ := checkLogin(r, session) user, _ := checkLogin(c, r, session)
if user == nil || !storage.IsPresent(user.UserFile) { if user == nil || !storage.IsPresent(c, user.UserFile) {
http.Redirect(res, r, "../../login", http.StatusFound) http.Redirect(res, r, "../../login", http.StatusFound)
return nil, nil return nil, nil
} }

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"context"
"net/http" "net/http"
"strings" "strings"
@ -11,7 +12,7 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
func registerHandler(res http.ResponseWriter, r *http.Request, session *sessions.Session, ctx *pongo2.Context) (*string, error) { func registerHandler(c context.Context, res http.ResponseWriter, r *http.Request, session *sessions.Session, ctx *pongo2.Context) (*string, error) {
var ( var (
username = strings.ToLower(r.FormValue("username")) username = strings.ToLower(r.FormValue("username"))
password = r.FormValue("password") password = r.FormValue("password")
@ -22,7 +23,7 @@ func registerHandler(res http.ResponseWriter, r *http.Request, session *sessions
return stringPointer("register.html"), nil return stringPointer("register.html"), nil
} }
if storage.IsPresent(createUserFilename(username)) { if storage.IsPresent(c, createUserFilename(username)) {
(*ctx)["exists"] = true (*ctx)["exists"] = true
return stringPointer("register.html"), nil return stringPointer("register.html"), nil
} }
@ -38,7 +39,7 @@ func registerHandler(res http.ResponseWriter, r *http.Request, session *sessions
d.MetaData.Password = string(hashedPassword) d.MetaData.Password = string(hashedPassword)
data, _ := d.GetData() data, _ := d.GetData()
if err := storage.Write(createUserFilename(username), data); err != nil { if err := storage.Write(c, createUserFilename(username), data); err != nil {
log.WithError(err).Error("Could not write user file to storage") log.WithError(err).Error("Could not write user file to storage")
(*ctx)["error"] = true (*ctx)["error"] = true
return stringPointer("register.html"), nil return stringPointer("register.html"), nil

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"context"
"fmt" "fmt"
"io" "io"
"net/url" "net/url"
@ -11,10 +12,10 @@ var (
) )
type storageAdapter interface { type storageAdapter interface {
Write(identifier string, data io.Reader) error Write(ctx context.Context, identifier string, data io.Reader) error
Read(identifier string) (io.Reader, error) Read(ctx context.Context, identifier string) (io.Reader, error)
IsPresent(identifier string) bool IsPresent(ctx context.Context, identifier string) bool
Backup(identifier string) error Backup(ctx context.Context, identifier string) error
} }
type storageAdapterInitializer func(*url.URL) (storageAdapter, error) type storageAdapterInitializer func(*url.URL) (storageAdapter, error)

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"context"
"fmt" "fmt"
"io" "io"
"net/url" "net/url"
@ -37,7 +38,7 @@ func newLocalStorage(u *url.URL) (storageAdapter, error) {
} }
// Write store the data of a dataObject into the storage // Write store the data of a dataObject into the storage
func (l *LocalStorage) Write(identifier string, data io.Reader) error { func (l *LocalStorage) Write(ctx context.Context, identifier string, data io.Reader) error {
f, err := os.Create(path.Join(l.path, identifier)) f, err := os.Create(path.Join(l.path, identifier))
if err != nil { if err != nil {
return err return err
@ -49,18 +50,18 @@ func (l *LocalStorage) Write(identifier string, data io.Reader) error {
} }
// Read reads the data of a dataObject from the storage // Read reads the data of a dataObject from the storage
func (l *LocalStorage) Read(identifier string) (io.Reader, error) { func (l *LocalStorage) Read(ctx context.Context, identifier string) (io.Reader, error) {
return os.Open(path.Join(l.path, identifier)) return os.Open(path.Join(l.path, identifier))
} }
// IsPresent checks for the presence of an userfile identifier // IsPresent checks for the presence of an userfile identifier
func (l *LocalStorage) IsPresent(identifier string) bool { func (l *LocalStorage) IsPresent(ctx context.Context, identifier string) bool {
_, err := os.Stat(path.Join(l.path, identifier)) _, err := os.Stat(path.Join(l.path, identifier))
return err == nil return err == nil
} }
// Backup creates a backup of the old data // Backup creates a backup of the old data
func (l *LocalStorage) Backup(identifier string) error { func (l *LocalStorage) Backup(ctx context.Context, identifier string) error {
ts := strconv.FormatInt(time.Now().Unix(), 10) ts := strconv.FormatInt(time.Now().Unix(), 10)
o, err := os.Open(path.Join(l.path, identifier)) o, err := os.Open(path.Join(l.path, identifier))

View File

@ -2,6 +2,7 @@ package main
import ( import (
"bytes" "bytes"
"context"
"io" "io"
"io/ioutil" "io/ioutil"
"net/url" "net/url"
@ -38,7 +39,7 @@ func newRedisStorage(u *url.URL) (storageAdapter, error) {
} }
// Write store the data of a dataObject into the storage // Write store the data of a dataObject into the storage
func (r *RedisStorage) Write(identifier string, data io.Reader) error { func (r *RedisStorage) Write(ctx context.Context, identifier string, data io.Reader) error {
d, err := ioutil.ReadAll(data) d, err := ioutil.ReadAll(data)
if err != nil { if err != nil {
return err return err
@ -48,13 +49,13 @@ func (r *RedisStorage) Write(identifier string, data io.Reader) error {
} }
// Read reads the data of a dataObject from the storage // Read reads the data of a dataObject from the storage
func (r *RedisStorage) Read(identifier string) (io.Reader, error) { func (r *RedisStorage) Read(ctx context.Context, identifier string) (io.Reader, error) {
content, err := r.conn.Get(r.prefix + identifier) content, err := r.conn.Get(r.prefix + identifier)
return bytes.NewReader(content), err return bytes.NewReader(content), err
} }
// IsPresent checks for the presence of an userfile identifier // IsPresent checks for the presence of an userfile identifier
func (r *RedisStorage) IsPresent(identifier string) bool { func (r *RedisStorage) IsPresent(ctx context.Context, identifier string) bool {
e, err := r.conn.Exists(r.prefix + identifier) e, err := r.conn.Exists(r.prefix + identifier)
if err != nil { if err != nil {
log.WithError(err).WithFields(log.Fields{ log.WithError(err).WithFields(log.Fields{
@ -66,12 +67,12 @@ func (r *RedisStorage) IsPresent(identifier string) bool {
} }
// Backup creates a backup of the old data // Backup creates a backup of the old data
func (r *RedisStorage) Backup(identifier string) error { func (r *RedisStorage) Backup(ctx context.Context, identifier string) error {
ts := strconv.FormatInt(time.Now().Unix(), 10) ts := strconv.FormatInt(time.Now().Unix(), 10)
data, err := r.Read(identifier) data, err := r.Read(ctx, identifier)
if err != nil { if err != nil {
return err return err
} }
return r.Write(identifier+":backup:"+ts, data) return r.Write(ctx, identifier+":backup:"+ts, data)
} }

View File

@ -2,6 +2,7 @@ package main
import ( import (
"bytes" "bytes"
"context"
"fmt" "fmt"
"io" "io"
"net/url" "net/url"
@ -35,10 +36,11 @@ func newS3Storage(u *url.URL) (storageAdapter, error) {
} }
// Write store the data of a dataObject into the storage // Write store the data of a dataObject into the storage
func (s *S3Storage) Write(identifier string, data io.Reader) error { func (s *S3Storage) Write(ctx context.Context, identifier string, data io.Reader) error {
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
io.Copy(buf, data) io.Copy(buf, data)
s.conn.Config.HTTPClient = getHTTPClient(ctx)
_, err := s.conn.PutObject(&s3.PutObjectInput{ _, err := s.conn.PutObject(&s3.PutObjectInput{
Bucket: aws.String(s.bucket), Bucket: aws.String(s.bucket),
Body: bytes.NewReader(buf.Bytes()), Body: bytes.NewReader(buf.Bytes()),
@ -48,7 +50,8 @@ func (s *S3Storage) Write(identifier string, data io.Reader) error {
} }
// Read reads the data of a dataObject from the storage // Read reads the data of a dataObject from the storage
func (s *S3Storage) Read(identifier string) (io.Reader, error) { func (s *S3Storage) Read(ctx context.Context, identifier string) (io.Reader, error) {
s.conn.Config.HTTPClient = getHTTPClient(ctx)
out, err := s.conn.GetObject(&s3.GetObjectInput{ out, err := s.conn.GetObject(&s3.GetObjectInput{
Bucket: aws.String(s.bucket), Bucket: aws.String(s.bucket),
Key: aws.String(path.Join(s.path, identifier)), Key: aws.String(path.Join(s.path, identifier)),
@ -62,7 +65,8 @@ func (s *S3Storage) Read(identifier string) (io.Reader, error) {
} }
// IsPresent checks for the presence of an userfile identifier // IsPresent checks for the presence of an userfile identifier
func (s *S3Storage) IsPresent(identifier string) bool { func (s *S3Storage) IsPresent(ctx context.Context, identifier string) bool {
s.conn.Config.HTTPClient = getHTTPClient(ctx)
out, err := s.conn.HeadObject(&s3.HeadObjectInput{ out, err := s.conn.HeadObject(&s3.HeadObjectInput{
Bucket: aws.String(s.bucket), Bucket: aws.String(s.bucket),
Key: aws.String(path.Join(s.path, identifier)), Key: aws.String(path.Join(s.path, identifier)),
@ -72,12 +76,13 @@ func (s *S3Storage) IsPresent(identifier string) bool {
return false return false
} }
return *out.ContentLength > 0 return aws.Int64Value(out.ContentLength) > 0 || aws.StringValue(out.ContentType) == "binary/octet-stream"
} }
// Backup creates a backup of the old data // Backup creates a backup of the old data
func (s *S3Storage) Backup(identifier string) error { func (s *S3Storage) Backup(ctx context.Context, identifier string) error {
ts := strconv.FormatInt(time.Now().Unix(), 10) ts := strconv.FormatInt(time.Now().Unix(), 10)
s.conn.Config.HTTPClient = getHTTPClient(ctx)
_, err := s.conn.CopyObject(&s3.CopyObjectInput{ _, err := s.conn.CopyObject(&s3.CopyObjectInput{
Bucket: aws.String(s.bucket), Bucket: aws.String(s.bucket),
Key: aws.String(path.Join(s.path, "backup", fmt.Sprintf("%s.%s", identifier, ts))), Key: aws.String(path.Join(s.path, "backup", fmt.Sprintf("%s.%s", identifier, ts))),