This repository has been archived by the owner on Mar 29, 2023. It is now read-only.
forked from jessfraz/s3server
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy paths3.go
122 lines (107 loc) · 2.92 KB
/
s3.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package main
import (
"context"
"fmt"
"io"
"log"
"mime"
"net/http"
"path"
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/sirupsen/logrus"
)
type s3Provider struct {
bucket string
prefix string
client *s3.S3
ctx context.Context
proxyPath string
}
// Prefix returns the prefix in an s3 bucket.
func (c *s3Provider) Prefix() string {
return c.prefix
}
// ProxyPath returns the proxyPath in an s3 bucket.
func (c *s3Provider) ProxyPath() string {
return c.proxyPath
}
// List returns the files in an s3 bucket.
func (c *s3Provider) List(ctx context.Context, prefix string) (files []object, err error) {
err = c.client.ListObjectsPagesWithContext(ctx, &s3.ListObjectsInput{
Bucket: aws.String(c.bucket),
Prefix: aws.String(prefix),
}, func(p *s3.ListObjectsOutput, lastPage bool) bool {
for _, o := range p.Contents {
files = append(files, object{
Name: aws.StringValue(o.Key),
Size: aws.Int64Value(o.Size),
ProxyPath: c.proxyPath,
})
}
return true // continue paging
})
if err != nil {
panic(fmt.Sprintf("failed to list objects for bucket, %s, %v", c.bucket, err))
}
return files, nil
}
// ServeHTTP gets files for the c.proxyPath from the S3 bucket instead of through staticFileHandler
func (c *s3Provider) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
key := strings.TrimPrefix(req.URL.Path, c.proxyPath)
logrus.Infof("Proxying: %q from %q", key, c.bucket)
input := &s3.GetObjectInput{
Bucket: aws.String(c.bucket),
Key: aws.String(key),
}
if v := req.Header.Get("If-None-Match"); v != "" {
input.IfNoneMatch = aws.String(v)
}
var is304 bool
resp, err := c.client.GetObjectWithContext(req.Context(), input)
if awsErr, ok := err.(awserr.Error); ok {
switch awsErr.Code() {
case s3.ErrCodeNoSuchKey:
http.Error(rw, "Page Not Found", 404)
return
case "NotModified":
is304 = true
// continue so other headers get set appropriately
default:
log.Printf("Error: %v %v", awsErr.Code(), awsErr.Message())
http.Error(rw, "Internal Error", 500)
return
}
} else if err != nil {
log.Printf("not aws error %v %s", err, err)
http.Error(rw, "Internal Error", 500)
return
}
var contentType string
// if resp.ContentType != nil {
// contentType = *resp.ContentType
// log.Printf("resp.contentType: %v ", contentType)
// }
if contentType == "" {
ext := path.Ext(key)
contentType = mime.TypeByExtension(ext)
log.Printf("mime.contentType: %v ", contentType)
}
if resp.ETag != nil && *resp.ETag != "" {
rw.Header().Set("Etag", *resp.ETag)
}
if contentType != "" {
rw.Header().Set("Content-Type", contentType)
}
if resp.ContentLength != nil && *resp.ContentLength > 0 {
rw.Header().Set("Content-Length", fmt.Sprintf("%d", *resp.ContentLength))
}
if is304 {
rw.WriteHeader(304)
} else {
io.Copy(rw, resp.Body)
resp.Body.Close()
}
}