Skip to content

Commit

Permalink
Forward HTTP headers
Browse files Browse the repository at this point in the history
  • Loading branch information
relvacode committed Dec 29, 2022
1 parent e9fb24f commit 3c2d9dc
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 21 deletions.
56 changes: 39 additions & 17 deletions pkg/s3dir/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import (
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/aws/smithy-go/middleware"
http2 "github.com/aws/smithy-go/transport/http"
"golang.org/x/exp/slices"
"io"
"net/http"
"net/textproto"
"net/url"
"path"
"strings"
Expand Down Expand Up @@ -40,20 +43,40 @@ func trimPathSegments(path string) (segments []string) {
return segments
}

func New(s3Client *s3.Client, rd *Renderer) *Server {
func New(s3Client *s3.Client, rd *Renderer, forwardHeaders []string) *Server {
return &Server{
s3: s3Client,
rd: rd,
s3: s3Client,
rd: rd,
forwardHeaders: forwardHeaders,
}
}

type Server struct {
s3 *s3.Client
rd *Renderer
s3 *s3.Client
rd *Renderer
forwardHeaders []string
}

// apiOptionsForRequest creates an AWS SDK Go option to inject HTTP header values by copying them from the HTTP request.
func (s *Server) apiOptionsForRequest(r *http.Request) func(options *s3.Options) {
return func(options *s3.Options) {
var apiOptions []func(stack *middleware.Stack) error

for _, header := range s.forwardHeaders {
var headerKey = textproto.CanonicalMIMEHeaderKey(header)
for _, headerValue := range r.Header[headerKey] {
apiOptions = append(apiOptions, http2.AddHeaderValue(headerKey, headerValue))
}
}

if len(apiOptions) > 0 {
options.APIOptions = apiOptions
}
}
}

func (s *Server) ListBuckets(rw http.ResponseWriter, r *http.Request) {
response, err := s.s3.ListBuckets(r.Context(), new(s3.ListBucketsInput))
response, err := s.s3.ListBuckets(r.Context(), new(s3.ListBucketsInput), s.apiOptionsForRequest(r))
if err != nil {
s.rd.RenderError(rw, r, err)
return
Expand Down Expand Up @@ -124,7 +147,7 @@ func (s *Server) ListBucketObjects(rw http.ResponseWriter, r *http.Request, buck
var prefixKnown = make(map[string]struct{})

for {
response, err := s.s3.ListObjectsV2(r.Context(), &params)
response, err := s.s3.ListObjectsV2(r.Context(), &params, s.apiOptionsForRequest(r))
if err != nil {
s.rd.RenderError(rw, r, err, append([]string{bucket}, segments...)...)
return
Expand Down Expand Up @@ -236,7 +259,7 @@ func (s *Server) BucketObject(rw http.ResponseWriter, r *http.Request, bucket st
response, err := s.s3.HeadObject(r.Context(), &s3.HeadObjectInput{
Bucket: &bucket,
Key: &key,
})
}, s.apiOptionsForRequest(r))

if err != nil {
s.rd.RenderError(rw, r, err, append([]string{bucket}, segments...)...)
Expand Down Expand Up @@ -272,7 +295,7 @@ func (s *Server) ZipArchive(rw http.ResponseWriter, r *http.Request, bucket stri
var zw = zip.NewWriter(sw)

for {
response, err := s.s3.ListObjectsV2(r.Context(), &params)
response, err := s.s3.ListObjectsV2(r.Context(), &params, s.apiOptionsForRequest(r))
if err != nil {
sw.Abort(func(rw http.ResponseWriter) {
s.rd.RenderError(rw, r, err, append([]string{bucket}, segments...)...)
Expand All @@ -284,24 +307,23 @@ func (s *Server) ZipArchive(rw http.ResponseWriter, r *http.Request, bucket stri
objectKeySegments := trimPathSegments(*object.Key)
objectKeySegments = objectKeySegments[len(segments):]

signedUrl, _ := s3.NewPresignClient(s.s3).PresignGetObject(r.Context(), &s3.GetObjectInput{
resp, err := s.s3.GetObject(r.Context(), &s3.GetObjectInput{
Bucket: &bucket,
Key: object.Key,
})
}, s.apiOptionsForRequest(r))

w, err := zw.CreateHeader(&zip.FileHeader{
Name: strings.Join(objectKeySegments, "/"),
Modified: *object.LastModified,
Method: zip.Deflate,
})
if err != nil {
sw.Abort(func(rw http.ResponseWriter) {
s.rd.RenderError(rw, r, err, append([]string{bucket}, segments...)...)
})
return
}

resp, err := http.DefaultClient.Get(signedUrl.URL)
w, err := zw.CreateHeader(&zip.FileHeader{
Name: strings.Join(objectKeySegments, "/"),
Modified: *resp.LastModified,
Method: zip.Deflate,
})
if err != nil {
sw.Abort(func(rw http.ResponseWriter) {
s.rd.RenderError(rw, r, err, append([]string{bucket}, segments...)...)
Expand Down
9 changes: 5 additions & 4 deletions s3dir.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import (
)

type CLI struct {
ListenAddress string `long:"listen-address" env:"LISTEN_ADDRESS" default:"127.0.0.1:9001" description:"Listen on this address"`
Endpoint string `long:"endpoint" env:"ENDPOINT" description:"AWS S3 endpoint"`
Application string `long:"application" env:"APPLICATION" default:"S3" description:"Your application name. Used to configure the page title."`
ListenAddress string `long:"listen-address" env:"LISTEN_ADDRESS" default:"127.0.0.1:9001" description:"Listen on this address"`
Endpoint string `long:"endpoint" env:"ENDPOINT" description:"AWS S3 endpoint"`
Application string `long:"application" env:"APPLICATION" default:"S3" description:"Your application name. Used to configure the page title"`
ForwardHTTPHeaders []string `long:"forward-http-header" env:"FORWARD_HTTP_HEADERS" description:"Forward these incoming HTTP headers to the S3 server"`
}

func Main() error {
Expand Down Expand Up @@ -49,7 +50,7 @@ func Main() error {

httpServer := &http.Server{
Addr: cli.ListenAddress,
Handler: s3dir.New(s3.NewFromConfig(cfg), &s3dir.Renderer{Title: cli.Application}),
Handler: s3dir.New(s3.NewFromConfig(cfg), &s3dir.Renderer{Title: cli.Application}, cli.ForwardHTTPHeaders),
}

return httpServer.ListenAndServe()
Expand Down

0 comments on commit 3c2d9dc

Please sign in to comment.