mirror of https://github.com/minio/minio.git
Add audit logging for S3 and Web handlers (#6571)
This PR brings an additional logger implementation called AuditLog which logs to http targets The intention is to use AuditLog to log all incoming requests, this is used as a mechanism by external log collection entities for processing Minio requests.
This commit is contained in:
parent
143e7fe300
commit
b0c9ae7490
|
@ -21,6 +21,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/minio/minio/cmd/logger"
|
||||||
"github.com/minio/minio/pkg/policy"
|
"github.com/minio/minio/pkg/policy"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -56,6 +57,8 @@ type accessControlPolicy struct {
|
||||||
func (api objectAPIHandlers) GetBucketACLHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) GetBucketACLHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "GetBucketACL")
|
ctx := newContext(r, w, "GetBucketACL")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
|
||||||
|
@ -103,6 +106,8 @@ func (api objectAPIHandlers) GetBucketACLHandler(w http.ResponseWriter, r *http.
|
||||||
func (api objectAPIHandlers) GetObjectACLHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) GetObjectACLHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "GetObjectACL")
|
ctx := newContext(r, w, "GetObjectACL")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
object := vars["object"]
|
object := vars["object"]
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/minio/minio/cmd/crypto"
|
"github.com/minio/minio/cmd/crypto"
|
||||||
|
"github.com/minio/minio/cmd/logger"
|
||||||
|
|
||||||
"github.com/minio/minio/pkg/policy"
|
"github.com/minio/minio/pkg/policy"
|
||||||
)
|
)
|
||||||
|
@ -58,6 +59,8 @@ func validateListObjectsArgs(prefix, marker, delimiter string, maxKeys int) APIE
|
||||||
func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "ListObjectsV2")
|
ctx := newContext(r, w, "ListObjectsV2")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
|
||||||
|
@ -137,6 +140,8 @@ func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http
|
||||||
func (api objectAPIHandlers) ListObjectsV1Handler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) ListObjectsV1Handler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "ListObjectsV1")
|
ctx := newContext(r, w, "ListObjectsV1")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
|
||||||
|
|
|
@ -89,6 +89,8 @@ func initFederatorBackend(objLayer ObjectLayer) {
|
||||||
func (api objectAPIHandlers) GetBucketLocationHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) GetBucketLocationHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "GetBucketLocation")
|
ctx := newContext(r, w, "GetBucketLocation")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
|
||||||
|
@ -137,6 +139,8 @@ func (api objectAPIHandlers) GetBucketLocationHandler(w http.ResponseWriter, r *
|
||||||
func (api objectAPIHandlers) ListMultipartUploadsHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) ListMultipartUploadsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "ListMultipartUploads")
|
ctx := newContext(r, w, "ListMultipartUploads")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
|
||||||
|
@ -184,6 +188,8 @@ func (api objectAPIHandlers) ListMultipartUploadsHandler(w http.ResponseWriter,
|
||||||
func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "ListBuckets")
|
ctx := newContext(r, w, "ListBuckets")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
|
@ -384,6 +390,8 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter,
|
||||||
func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "PutBucket")
|
ctx := newContext(r, w, "PutBucket")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
|
@ -460,6 +468,8 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req
|
||||||
func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "PostPolicyBucket")
|
ctx := newContext(r, w, "PostPolicyBucket")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
|
@ -671,6 +681,12 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
|
||||||
default:
|
default:
|
||||||
writeSuccessNoContent(w)
|
writeSuccessNoContent(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for k, v := range objInfo.UserDefined {
|
||||||
|
logger.GetReqInfo(ctx).SetTags(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.GetReqInfo(ctx).SetTags("etag", objInfo.ETag)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HeadBucketHandler - HEAD Bucket
|
// HeadBucketHandler - HEAD Bucket
|
||||||
|
@ -682,6 +698,8 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
|
||||||
func (api objectAPIHandlers) HeadBucketHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) HeadBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "HeadBucket")
|
ctx := newContext(r, w, "HeadBucket")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
|
||||||
|
@ -712,6 +730,8 @@ func (api objectAPIHandlers) HeadBucketHandler(w http.ResponseWriter, r *http.Re
|
||||||
func (api objectAPIHandlers) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "DeleteBucket")
|
ctx := newContext(r, w, "DeleteBucket")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,8 @@ var errNoSuchNotifications = errors.New("The specified bucket does not have buck
|
||||||
func (api objectAPIHandlers) GetBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) GetBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "GetBucketNotification")
|
ctx := newContext(r, w, "GetBucketNotification")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucketName := vars["bucket"]
|
bucketName := vars["bucket"]
|
||||||
|
|
||||||
|
@ -96,6 +98,8 @@ func (api objectAPIHandlers) GetBucketNotificationHandler(w http.ResponseWriter,
|
||||||
func (api objectAPIHandlers) PutBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) PutBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "PutBucketNotification")
|
ctx := newContext(r, w, "PutBucketNotification")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
|
@ -156,6 +160,8 @@ func (api objectAPIHandlers) PutBucketNotificationHandler(w http.ResponseWriter,
|
||||||
func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "ListenBucketNotification")
|
ctx := newContext(r, w, "ListenBucketNotification")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
// Validate if bucket exists.
|
// Validate if bucket exists.
|
||||||
objAPI := api.ObjectAPI()
|
objAPI := api.ObjectAPI()
|
||||||
if objAPI == nil {
|
if objAPI == nil {
|
||||||
|
|
|
@ -40,6 +40,8 @@ const (
|
||||||
func (api objectAPIHandlers) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "PutBucketPolicy")
|
ctx := newContext(r, w, "PutBucketPolicy")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
objAPI := api.ObjectAPI()
|
objAPI := api.ObjectAPI()
|
||||||
if objAPI == nil {
|
if objAPI == nil {
|
||||||
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
|
@ -101,6 +103,8 @@ func (api objectAPIHandlers) PutBucketPolicyHandler(w http.ResponseWriter, r *ht
|
||||||
func (api objectAPIHandlers) DeleteBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) DeleteBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "DeleteBucketPolicy")
|
ctx := newContext(r, w, "DeleteBucketPolicy")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
objAPI := api.ObjectAPI()
|
objAPI := api.ObjectAPI()
|
||||||
if objAPI == nil {
|
if objAPI == nil {
|
||||||
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
|
@ -137,6 +141,8 @@ func (api objectAPIHandlers) DeleteBucketPolicyHandler(w http.ResponseWriter, r
|
||||||
func (api objectAPIHandlers) GetBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) GetBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "GetBucketPolicy")
|
ctx := newContext(r, w, "GetBucketPolicy")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
objAPI := api.ObjectAPI()
|
objAPI := api.ObjectAPI()
|
||||||
if objAPI == nil {
|
if objAPI == nil {
|
||||||
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
|
|
|
@ -49,10 +49,17 @@ func checkUpdate(mode string) {
|
||||||
|
|
||||||
// Load logger targets based on user's configuration
|
// Load logger targets based on user's configuration
|
||||||
func loadLoggers() {
|
func loadLoggers() {
|
||||||
|
if endpoint, ok := os.LookupEnv("MINIO_LOGGER_HTTP_ENDPOINT"); ok {
|
||||||
|
// Enable http logging through ENV, this is specifically added gateway audit logging.
|
||||||
|
logger.AddTarget(logger.NewHTTP(endpoint, NewCustomHTTPTransport()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if globalServerConfig.Logger.Console.Enabled {
|
if globalServerConfig.Logger.Console.Enabled {
|
||||||
// Enable console logging
|
// Enable console logging
|
||||||
logger.AddTarget(logger.NewConsole())
|
logger.AddTarget(logger.NewConsole())
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, l := range globalServerConfig.Logger.HTTP {
|
for _, l := range globalServerConfig.Logger.HTTP {
|
||||||
if l.Enabled {
|
if l.Enabled {
|
||||||
// Enable http logging
|
// Enable http logging
|
||||||
|
|
|
@ -224,7 +224,16 @@ func FromMinioClientListBucketResultToV2Info(bucket string, result minio.ListBuc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToMinioClientMetadata converts metadata to map[string][]string
|
// ToMinioClientObjectInfoMetadata convertes metadata to map[string][]string
|
||||||
|
func ToMinioClientObjectInfoMetadata(metadata map[string]string) map[string][]string {
|
||||||
|
mm := make(map[string][]string, len(metadata))
|
||||||
|
for k, v := range metadata {
|
||||||
|
mm[http.CanonicalHeaderKey(k)] = []string{v}
|
||||||
|
}
|
||||||
|
return mm
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToMinioClientMetadata converts metadata to map[string]string
|
||||||
func ToMinioClientMetadata(metadata map[string]string) map[string]string {
|
func ToMinioClientMetadata(metadata map[string]string) map[string]string {
|
||||||
mm := make(map[string]string)
|
mm := make(map[string]string)
|
||||||
for k, v := range metadata {
|
for k, v := range metadata {
|
||||||
|
|
|
@ -228,6 +228,12 @@ func StartGateway(ctx *cli.Context, gw Gateway) {
|
||||||
globalServerConfig = srvCfg
|
globalServerConfig = srvCfg
|
||||||
globalServerConfigMu.Unlock()
|
globalServerConfigMu.Unlock()
|
||||||
|
|
||||||
|
// Load logger subsystem
|
||||||
|
loadLoggers()
|
||||||
|
|
||||||
|
// This is only to uniquely identify each gateway deployments.
|
||||||
|
logger.SetDeploymentID(os.Getenv("MINIO_GATEWAY_DEPLOYMENT_ID"))
|
||||||
|
|
||||||
var cacheConfig = globalServerConfig.GetCacheConfig()
|
var cacheConfig = globalServerConfig.GetCacheConfig()
|
||||||
if len(cacheConfig.Drives) > 0 {
|
if len(cacheConfig.Drives) > 0 {
|
||||||
var err error
|
var err error
|
||||||
|
|
|
@ -71,6 +71,9 @@ ENVIRONMENT VARIABLES:
|
||||||
MINIO_CACHE_EXPIRY: Cache expiry duration in days.
|
MINIO_CACHE_EXPIRY: Cache expiry duration in days.
|
||||||
MINIO_CACHE_MAXUSE: Maximum permitted usage of the cache in percentage (0-100).
|
MINIO_CACHE_MAXUSE: Maximum permitted usage of the cache in percentage (0-100).
|
||||||
|
|
||||||
|
LOGGER:
|
||||||
|
MINIO_LOGGER_HTTP_ENDPOINT: HTTP endpoint URL to log all incoming requests.
|
||||||
|
|
||||||
EXAMPLES:
|
EXAMPLES:
|
||||||
1. Start minio gateway server for AWS S3 backend.
|
1. Start minio gateway server for AWS S3 backend.
|
||||||
$ export MINIO_ACCESS_KEY=accesskey
|
$ export MINIO_ACCESS_KEY=accesskey
|
||||||
|
@ -82,7 +85,13 @@ EXAMPLES:
|
||||||
$ export MINIO_SECRET_KEY=zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG
|
$ export MINIO_SECRET_KEY=zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG
|
||||||
$ {{.HelpName}} https://play.minio.io:9000
|
$ {{.HelpName}} https://play.minio.io:9000
|
||||||
|
|
||||||
3. Start minio gateway server for AWS S3 backend with edge caching enabled.
|
3. Start minio gateway server for AWS S3 backend logging all requests to http endpoint.
|
||||||
|
$ export MINIO_ACCESS_KEY=Q3AM3UQ867SPQQA43P2F
|
||||||
|
$ export MINIO_SECRET_KEY=zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG
|
||||||
|
$ export MINIO_LOGGER_HTTP_ENDPOINT="http://localhost:8000/"
|
||||||
|
$ {{.HelpName}} https://play.minio.io:9000
|
||||||
|
|
||||||
|
4. Start minio gateway server for AWS S3 backend with edge caching enabled.
|
||||||
$ export MINIO_ACCESS_KEY=accesskey
|
$ export MINIO_ACCESS_KEY=accesskey
|
||||||
$ export MINIO_SECRET_KEY=secretkey
|
$ export MINIO_SECRET_KEY=secretkey
|
||||||
$ export MINIO_CACHE_DRIVES="/mnt/drive1;/mnt/drive2;/mnt/drive3;/mnt/drive4"
|
$ export MINIO_CACHE_DRIVES="/mnt/drive1;/mnt/drive2;/mnt/drive3;/mnt/drive4"
|
||||||
|
@ -401,6 +410,9 @@ func (l *s3Objects) PutObject(ctx context.Context, bucket string, object string,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return objInfo, minio.ErrorRespToObjectError(err, bucket, object)
|
return objInfo, minio.ErrorRespToObjectError(err, bucket, object)
|
||||||
}
|
}
|
||||||
|
// On success, populate the key & metadata so they are present in the notification
|
||||||
|
oi.Key = object
|
||||||
|
oi.Metadata = minio.ToMinioClientObjectInfoMetadata(metadata)
|
||||||
|
|
||||||
return minio.FromMinioClientObjectInfo(bucket, oi), nil
|
return minio.FromMinioClientObjectInfo(bucket, oi), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,11 @@ import (
|
||||||
// in plain or json format to the standard output.
|
// in plain or json format to the standard output.
|
||||||
type ConsoleTarget struct{}
|
type ConsoleTarget struct{}
|
||||||
|
|
||||||
func (c *ConsoleTarget) send(entry logEntry) error {
|
func (c *ConsoleTarget) send(e interface{}) error {
|
||||||
|
entry, ok := e.(logEntry)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Uexpected log entry structure %#v", e)
|
||||||
|
}
|
||||||
if jsonFlag {
|
if jsonFlag {
|
||||||
logJSON, err := json.Marshal(&entry)
|
logJSON, err := json.Marshal(&entry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -32,7 +32,8 @@ import (
|
||||||
// is returned to the caller.
|
// is returned to the caller.
|
||||||
type HTTPTarget struct {
|
type HTTPTarget struct {
|
||||||
// Channel of log entries
|
// Channel of log entries
|
||||||
logCh chan logEntry
|
logCh chan interface{}
|
||||||
|
|
||||||
// HTTP(s) endpoint
|
// HTTP(s) endpoint
|
||||||
endpoint string
|
endpoint string
|
||||||
client http.Client
|
client http.Client
|
||||||
|
@ -72,14 +73,14 @@ func NewHTTP(endpoint string, transport *http.Transport) LoggingTarget {
|
||||||
client: http.Client{
|
client: http.Client{
|
||||||
Transport: transport,
|
Transport: transport,
|
||||||
},
|
},
|
||||||
logCh: make(chan logEntry, 10000),
|
logCh: make(chan interface{}, 10000),
|
||||||
}
|
}
|
||||||
|
|
||||||
h.startHTTPLogger()
|
h.startHTTPLogger()
|
||||||
return &h
|
return &h
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HTTPTarget) send(entry logEntry) error {
|
func (h *HTTPTarget) send(entry interface{}) error {
|
||||||
select {
|
select {
|
||||||
case h.logCh <- entry:
|
case h.logCh <- entry:
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/build"
|
"go/build"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -341,6 +342,55 @@ func logIf(ctx context.Context, err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type auditEntry struct {
|
||||||
|
DeploymentID string `json:"deploymentid,omitempty"`
|
||||||
|
Time string `json:"time"`
|
||||||
|
API *api `json:"api,omitempty"`
|
||||||
|
RemoteHost string `json:"remotehost,omitempty"`
|
||||||
|
RequestID string `json:"requestID,omitempty"`
|
||||||
|
UserAgent string `json:"userAgent,omitempty"`
|
||||||
|
Metadata map[string]string `json:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuditLog - logs audit logs to all targets.
|
||||||
|
func AuditLog(ctx context.Context, r *http.Request) {
|
||||||
|
if Disable {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req := GetReqInfo(ctx)
|
||||||
|
if req == nil {
|
||||||
|
req = &ReqInfo{API: "SYSTEM"}
|
||||||
|
}
|
||||||
|
|
||||||
|
API := "SYSTEM"
|
||||||
|
if req.API != "" {
|
||||||
|
API = req.API
|
||||||
|
}
|
||||||
|
|
||||||
|
tags := make(map[string]string)
|
||||||
|
for _, entry := range req.GetTags() {
|
||||||
|
tags[entry.Key] = entry.Val
|
||||||
|
}
|
||||||
|
|
||||||
|
entry := auditEntry{
|
||||||
|
DeploymentID: deploymentID,
|
||||||
|
RemoteHost: req.RemoteHost,
|
||||||
|
RequestID: req.RequestID,
|
||||||
|
UserAgent: req.UserAgent,
|
||||||
|
Time: time.Now().UTC().Format(time.RFC3339Nano),
|
||||||
|
API: &api{Name: API, Args: &args{Bucket: req.BucketName, Object: req.ObjectName}},
|
||||||
|
Metadata: tags,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send audit logs only to http targets.
|
||||||
|
for _, t := range Targets {
|
||||||
|
if _, ok := t.(*HTTPTarget); ok {
|
||||||
|
t.send(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ErrCritical is the value panic'd whenever CriticalIf is called.
|
// ErrCritical is the value panic'd whenever CriticalIf is called.
|
||||||
var ErrCritical struct{}
|
var ErrCritical struct{}
|
||||||
|
|
||||||
|
@ -450,10 +500,9 @@ func (f fatalMsg) pretty(msg string, args ...interface{}) {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
var info infoMsg
|
type infoMsg struct{}
|
||||||
|
|
||||||
type infoMsg struct {
|
var info infoMsg
|
||||||
}
|
|
||||||
|
|
||||||
func (i infoMsg) json(msg string, args ...interface{}) {
|
func (i infoMsg) json(msg string, args ...interface{}) {
|
||||||
logJSON, err := json.Marshal(&logEntry{
|
logJSON, err := json.Marshal(&logEntry{
|
||||||
|
|
|
@ -20,7 +20,7 @@ package logger
|
||||||
// a single log entry and send it to the log target
|
// a single log entry and send it to the log target
|
||||||
// e.g. send the log to a http server
|
// e.g. send the log to a http server
|
||||||
type LoggingTarget interface {
|
type LoggingTarget interface {
|
||||||
send(entry logEntry) error
|
send(entry interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Targets is the set of enabled loggers
|
// Targets is the set of enabled loggers
|
||||||
|
|
|
@ -448,6 +448,7 @@ func (sys *NotificationSys) Send(args eventArgs) []event.TargetIDErr {
|
||||||
sys.RLock()
|
sys.RLock()
|
||||||
targetIDSet := sys.bucketRulesMap[args.BucketName].Match(args.EventName, args.Object.Name)
|
targetIDSet := sys.bucketRulesMap[args.BucketName].Match(args.EventName, args.Object.Name)
|
||||||
sys.RUnlock()
|
sys.RUnlock()
|
||||||
|
|
||||||
if len(targetIDSet) == 0 {
|
if len(targetIDSet) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,8 @@ func setHeadGetRespHeaders(w http.ResponseWriter, reqParams url.Values) {
|
||||||
func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "SelectObject")
|
ctx := newContext(r, w, "SelectObject")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
// Fetch object stat info.
|
// Fetch object stat info.
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
|
@ -273,6 +275,12 @@ func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r
|
||||||
logger.LogIf(ctx, err)
|
logger.LogIf(ctx, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for k, v := range objInfo.UserDefined {
|
||||||
|
logger.GetReqInfo(ctx).SetTags(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.GetReqInfo(ctx).SetTags("etag", objInfo.ETag)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetObjectHandler - GET Object
|
// GetObjectHandler - GET Object
|
||||||
|
@ -282,6 +290,8 @@ func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r
|
||||||
func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "GetObject")
|
ctx := newContext(r, w, "GetObject")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
|
@ -437,6 +447,12 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
|
||||||
Host: host,
|
Host: host,
|
||||||
Port: port,
|
Port: port,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
for k, v := range objInfo.UserDefined {
|
||||||
|
logger.GetReqInfo(ctx).SetTags(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.GetReqInfo(ctx).SetTags("etag", objInfo.ETag)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HeadObjectHandler - HEAD Object
|
// HeadObjectHandler - HEAD Object
|
||||||
|
@ -445,6 +461,8 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
|
||||||
func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "HeadObject")
|
ctx := newContext(r, w, "HeadObject")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponseHeadersOnly(w, ErrServerNotInitialized)
|
writeErrorResponseHeadersOnly(w, ErrServerNotInitialized)
|
||||||
|
@ -578,6 +596,12 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re
|
||||||
Host: host,
|
Host: host,
|
||||||
Port: port,
|
Port: port,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
for k, v := range objInfo.UserDefined {
|
||||||
|
logger.GetReqInfo(ctx).SetTags(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.GetReqInfo(ctx).SetTags("etag", objInfo.ETag)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract metadata relevant for an CopyObject operation based on conditional
|
// Extract metadata relevant for an CopyObject operation based on conditional
|
||||||
|
@ -618,6 +642,8 @@ func getCpObjMetadataFromHeader(ctx context.Context, r *http.Request, userMeta m
|
||||||
func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "CopyObject")
|
ctx := newContext(r, w, "CopyObject")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
|
@ -951,6 +977,12 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
||||||
Host: host,
|
Host: host,
|
||||||
Port: port,
|
Port: port,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
for k, v := range objInfo.UserDefined {
|
||||||
|
logger.GetReqInfo(ctx).SetTags(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.GetReqInfo(ctx).SetTags("etag", objInfo.ETag)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutObjectHandler - PUT Object
|
// PutObjectHandler - PUT Object
|
||||||
|
@ -964,6 +996,8 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
||||||
func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "PutObject")
|
ctx := newContext(r, w, "PutObject")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
|
@ -1203,6 +1237,12 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
|
||||||
Host: host,
|
Host: host,
|
||||||
Port: port,
|
Port: port,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
for k, v := range objInfo.UserDefined {
|
||||||
|
logger.GetReqInfo(ctx).SetTags(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.GetReqInfo(ctx).SetTags("etag", objInfo.ETag)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Multipart objectAPIHandlers
|
/// Multipart objectAPIHandlers
|
||||||
|
@ -1216,6 +1256,8 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
|
||||||
func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "NewMultipartUpload")
|
ctx := newContext(r, w, "NewMultipartUpload")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
|
@ -1308,6 +1350,8 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r
|
||||||
func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "CopyObjectPart")
|
ctx := newContext(r, w, "CopyObjectPart")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
|
@ -1530,6 +1574,8 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
|
||||||
func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "PutObjectPart")
|
ctx := newContext(r, w, "PutObjectPart")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
objectAPI := api.ObjectAPI()
|
objectAPI := api.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
writeErrorResponse(w, ErrServerNotInitialized, r.URL)
|
||||||
|
@ -1770,6 +1816,8 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
|
||||||
func (api objectAPIHandlers) AbortMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) AbortMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "AbortMultipartUpload")
|
ctx := newContext(r, w, "AbortMultipartUpload")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
object := vars["object"]
|
object := vars["object"]
|
||||||
|
@ -1809,6 +1857,8 @@ func (api objectAPIHandlers) AbortMultipartUploadHandler(w http.ResponseWriter,
|
||||||
func (api objectAPIHandlers) ListObjectPartsHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) ListObjectPartsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "ListObjectParts")
|
ctx := newContext(r, w, "ListObjectParts")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
object := vars["object"]
|
object := vars["object"]
|
||||||
|
@ -1849,6 +1899,8 @@ func (api objectAPIHandlers) ListObjectPartsHandler(w http.ResponseWriter, r *ht
|
||||||
func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "CompleteMultipartUpload")
|
ctx := newContext(r, w, "CompleteMultipartUpload")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
object := vars["object"]
|
object := vars["object"]
|
||||||
|
@ -1955,6 +2007,12 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite
|
||||||
Host: host,
|
Host: host,
|
||||||
Port: port,
|
Port: port,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
for k, v := range objInfo.UserDefined {
|
||||||
|
logger.GetReqInfo(ctx).SetTags(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.GetReqInfo(ctx).SetTags("etag", objInfo.ETag)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete objectAPIHandlers
|
/// Delete objectAPIHandlers
|
||||||
|
@ -1963,6 +2021,8 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite
|
||||||
func (api objectAPIHandlers) DeleteObjectHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) DeleteObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "DeleteObject")
|
ctx := newContext(r, w, "DeleteObject")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
object := vars["object"]
|
object := vars["object"]
|
||||||
|
|
|
@ -391,7 +391,7 @@ func newContext(r *http.Request, w http.ResponseWriter, api string) context.Cont
|
||||||
reqInfo := &logger.ReqInfo{
|
reqInfo := &logger.ReqInfo{
|
||||||
RequestID: w.Header().Get(responseRequestIDKey),
|
RequestID: w.Header().Get(responseRequestIDKey),
|
||||||
RemoteHost: handlers.GetSourceIP(r),
|
RemoteHost: handlers.GetSourceIP(r),
|
||||||
UserAgent: r.Header.Get("user-agent"),
|
UserAgent: r.UserAgent(),
|
||||||
API: api,
|
API: api,
|
||||||
BucketName: bucket,
|
BucketName: bucket,
|
||||||
ObjectName: object,
|
ObjectName: object,
|
||||||
|
|
|
@ -640,6 +640,10 @@ func (web *webAPIHandlers) CreateURLToken(r *http.Request, args *WebGenericArgs,
|
||||||
|
|
||||||
// Upload - file upload handler.
|
// Upload - file upload handler.
|
||||||
func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) {
|
func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := newContext(r, w, "WebUpload")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
objectAPI := web.ObjectAPI()
|
objectAPI := web.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
writeWebErrorResponse(w, errServerNotInitialized)
|
writeWebErrorResponse(w, errServerNotInitialized)
|
||||||
|
@ -741,13 +745,13 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) {
|
||||||
opts := ObjectOptions{}
|
opts := ObjectOptions{}
|
||||||
// Deny if WORM is enabled
|
// Deny if WORM is enabled
|
||||||
if globalWORMEnabled {
|
if globalWORMEnabled {
|
||||||
if _, err = objectAPI.GetObjectInfo(context.Background(), bucket, object, opts); err == nil {
|
if _, err = objectAPI.GetObjectInfo(ctx, bucket, object, opts); err == nil {
|
||||||
writeWebErrorResponse(w, errMethodNotAllowed)
|
writeWebErrorResponse(w, errMethodNotAllowed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
objInfo, err := putObject(context.Background(), bucket, object, hashReader, metadata, opts)
|
objInfo, err := putObject(ctx, bucket, object, hashReader, metadata, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeWebErrorResponse(w, err)
|
writeWebErrorResponse(w, err)
|
||||||
return
|
return
|
||||||
|
@ -769,10 +773,20 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) {
|
||||||
Host: host,
|
Host: host,
|
||||||
Port: port,
|
Port: port,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
for k, v := range objInfo.UserDefined {
|
||||||
|
logger.GetReqInfo(ctx).SetTags(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.GetReqInfo(ctx).SetTags("etag", objInfo.ETag)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Download - file download handler.
|
// Download - file download handler.
|
||||||
func (web *webAPIHandlers) Download(w http.ResponseWriter, r *http.Request) {
|
func (web *webAPIHandlers) Download(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := newContext(r, w, "WebDownload")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
objectAPI := web.ObjectAPI()
|
objectAPI := web.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
|
@ -827,7 +841,7 @@ func (web *webAPIHandlers) Download(w http.ResponseWriter, r *http.Request) {
|
||||||
getObjectInfo = web.CacheAPI().GetObjectInfo
|
getObjectInfo = web.CacheAPI().GetObjectInfo
|
||||||
getObject = web.CacheAPI().GetObject
|
getObject = web.CacheAPI().GetObject
|
||||||
}
|
}
|
||||||
objInfo, err := getObjectInfo(context.Background(), bucket, object, opts)
|
objInfo, err := getObjectInfo(ctx, bucket, object, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeWebErrorResponse(w, err)
|
writeWebErrorResponse(w, err)
|
||||||
return
|
return
|
||||||
|
@ -897,7 +911,7 @@ func (web *webAPIHandlers) Download(w http.ResponseWriter, r *http.Request) {
|
||||||
// Add content disposition.
|
// Add content disposition.
|
||||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", path.Base(object)))
|
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", path.Base(object)))
|
||||||
|
|
||||||
if err = getObject(context.Background(), bucket, object, 0, -1, httpWriter, "", opts); err != nil {
|
if err = getObject(ctx, bucket, object, 0, -1, httpWriter, "", opts); err != nil {
|
||||||
httpWriter.Close()
|
httpWriter.Close()
|
||||||
if objInfo.IsCompressed() {
|
if objInfo.IsCompressed() {
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
@ -933,6 +947,12 @@ func (web *webAPIHandlers) Download(w http.ResponseWriter, r *http.Request) {
|
||||||
Host: host,
|
Host: host,
|
||||||
Port: port,
|
Port: port,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
for k, v := range objInfo.UserDefined {
|
||||||
|
logger.GetReqInfo(ctx).SetTags(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.GetReqInfo(ctx).SetTags("etag", objInfo.ETag)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DownloadZipArgs - Argument for downloading a bunch of files as a zip file.
|
// DownloadZipArgs - Argument for downloading a bunch of files as a zip file.
|
||||||
|
@ -952,6 +972,10 @@ func (web *webAPIHandlers) DownloadZip(w http.ResponseWriter, r *http.Request) {
|
||||||
host, port = "", ""
|
host, port = "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx := newContext(r, w, "WebDownloadZip")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, r)
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
objectAPI := web.ObjectAPI()
|
objectAPI := web.ObjectAPI()
|
||||||
if objectAPI == nil {
|
if objectAPI == nil {
|
||||||
|
@ -1030,7 +1054,7 @@ func (web *webAPIHandlers) DownloadZip(w http.ResponseWriter, r *http.Request) {
|
||||||
for _, object := range args.Objects {
|
for _, object := range args.Objects {
|
||||||
// Writes compressed object file to the response.
|
// Writes compressed object file to the response.
|
||||||
zipit := func(objectName string) error {
|
zipit := func(objectName string) error {
|
||||||
info, err := getObjectInfo(context.Background(), args.BucketName, objectName, opts)
|
info, err := getObjectInfo(ctx, args.BucketName, objectName, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1103,7 +1127,7 @@ func (web *webAPIHandlers) DownloadZip(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
httpWriter := ioutil.WriteOnClose(writer)
|
httpWriter := ioutil.WriteOnClose(writer)
|
||||||
if err = getObject(context.Background(), args.BucketName, objectName, 0, length, httpWriter, "", opts); err != nil {
|
if err = getObject(ctx, args.BucketName, objectName, 0, length, httpWriter, "", opts); err != nil {
|
||||||
httpWriter.Close()
|
httpWriter.Close()
|
||||||
if info.IsCompressed() {
|
if info.IsCompressed() {
|
||||||
// Wait for decompression go-routine to retire.
|
// Wait for decompression go-routine to retire.
|
||||||
|
|
Loading…
Reference in New Issue