Chris Lu
7 years ago
11 changed files with 2139 additions and 17 deletions
-
1weed/command/command.go
-
40weed/command/mount_std.go
-
73weed/command/s3.go
-
692weed/s3api/AmazonS3.xsd
-
7weed/s3api/README.txt
-
58weed/s3api/s3api_bucket_handlers.go
-
76weed/s3api/s3api_errors.go
-
67weed/s3api/s3api_handlers.go
-
31weed/s3api/s3api_headers.go
-
109weed/s3api/s3api_server.go
-
1002weed/s3api/s3api_xsd_generated.go
@ -0,0 +1,73 @@ |
|||||
|
package command |
||||
|
|
||||
|
import ( |
||||
|
"net/http" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/chrislusf/seaweedfs/weed/glog" |
||||
|
"github.com/chrislusf/seaweedfs/weed/util" |
||||
|
"github.com/gorilla/mux" |
||||
|
"fmt" |
||||
|
"github.com/chrislusf/seaweedfs/weed/s3api" |
||||
|
) |
||||
|
|
||||
|
var ( |
||||
|
s3options S3Options |
||||
|
) |
||||
|
|
||||
|
type S3Options struct { |
||||
|
filer *string |
||||
|
filerGrpcPort *int |
||||
|
port *int |
||||
|
domainName *string |
||||
|
} |
||||
|
|
||||
|
func init() { |
||||
|
cmdS3.Run = runS3 // break init cycle
|
||||
|
s3options.filer = cmdS3.Flag.String("filer", "localhost:8888", "filer server address") |
||||
|
s3options.filerGrpcPort = cmdS3.Flag.Int("filer.grpcPort", 0, "filer server grpc port, default to filer http port plus 10000") |
||||
|
s3options.port = cmdS3.Flag.Int("port", 8333, "s3options server http listen port") |
||||
|
s3options.domainName = cmdS3.Flag.String("domainName", "", "suffix of the host name, {bucket}.{domainName}") |
||||
|
} |
||||
|
|
||||
|
var cmdS3 = &Command{ |
||||
|
UsageLine: "s3 -port=8333 -filer=<ip:port>", |
||||
|
Short: "start a s3 API compatible server that is backed by a filer", |
||||
|
Long: `start a s3 API compatible server that is backed by a filer. |
||||
|
|
||||
|
`, |
||||
|
} |
||||
|
|
||||
|
func runS3(cmd *Command, args []string) bool { |
||||
|
|
||||
|
filerGrpcAddress, err := parseFilerGrpcAddress(*s3options.filer, *s3options.filerGrpcPort) |
||||
|
if err != nil { |
||||
|
glog.Fatal(err) |
||||
|
return false |
||||
|
} |
||||
|
|
||||
|
router := mux.NewRouter().SkipClean(true) |
||||
|
|
||||
|
_, s3ApiServer_err := s3api.NewS3ApiServer(router, &s3api.S3ApiServerOption{ |
||||
|
Filer: *s3options.filer, |
||||
|
FilerGrpcAddress: filerGrpcAddress, |
||||
|
DomainName: *s3options.domainName, |
||||
|
}) |
||||
|
if s3ApiServer_err != nil { |
||||
|
glog.Fatalf("S3 API Server startup error: %v", s3ApiServer_err) |
||||
|
} |
||||
|
|
||||
|
glog.V(0).Infof("Start Seaweed S3 API Server %s at port %d", util.VERSION, *s3options.port) |
||||
|
s3ApiListener, e := util.NewListener(fmt.Sprintf(":%d", *s3options.port), time.Duration(10)*time.Second) |
||||
|
if e != nil { |
||||
|
glog.Fatalf("S3 API Server listener error: %v", e) |
||||
|
} |
||||
|
|
||||
|
httpS := &http.Server{Handler: router} |
||||
|
if err := httpS.Serve(s3ApiListener); err != nil { |
||||
|
glog.Fatalf("S3 API Server Fail to serve: %v", e) |
||||
|
} |
||||
|
|
||||
|
return true |
||||
|
|
||||
|
} |
@ -0,0 +1,692 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<xsd:schema |
||||
|
xmlns:tns="http://s3.amazonaws.com/doc/2006-03-01/" |
||||
|
xmlns:xsd="http://www.w3.org/2001/XMLSchema" |
||||
|
elementFormDefault="qualified" |
||||
|
targetNamespace="http://s3.amazonaws.com/doc/2006-03-01/"> |
||||
|
|
||||
|
<xsd:element name="CreateBucket"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Bucket" type="xsd:string"/> |
||||
|
<xsd:element name="AccessControlList" type="tns:AccessControlList" minOccurs="0"/> |
||||
|
<xsd:element name="AWSAccessKeyId" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Timestamp" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="Signature" type="xsd:string" minOccurs="0"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:complexType name="MetadataEntry"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Name" type="xsd:string"/> |
||||
|
<xsd:element name="Value" type="xsd:string"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:element name="CreateBucketResponse"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="CreateBucketReturn" type="tns:CreateBucketResult"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:complexType name="Status"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Code" type="xsd:int"/> |
||||
|
<xsd:element name="Description" type="xsd:string"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:complexType name="Result"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Status" type="tns:Status"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:complexType name="CreateBucketResult"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="BucketName" type="xsd:string"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:element name="DeleteBucket"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Bucket" type="xsd:string"/> |
||||
|
<xsd:element name="AWSAccessKeyId" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Timestamp" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="Signature" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Credential" type="xsd:string" minOccurs="0"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
<xsd:element name="DeleteBucketResponse"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="DeleteBucketResponse" type="tns:Status"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:complexType name="BucketLoggingStatus"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="LoggingEnabled" type="tns:LoggingSettings" minOccurs="0"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:complexType name="LoggingSettings"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="TargetBucket" type="xsd:string"/> |
||||
|
<xsd:element name="TargetPrefix" type="xsd:string"/> |
||||
|
<xsd:element name="TargetGrants" type="tns:AccessControlList" minOccurs="0"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:element name="GetBucketLoggingStatus"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Bucket" type="xsd:string"/> |
||||
|
<xsd:element name="AWSAccessKeyId" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Timestamp" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="Signature" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Credential" type="xsd:string" minOccurs="0"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="GetBucketLoggingStatusResponse"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="GetBucketLoggingStatusResponse" type="tns:BucketLoggingStatus"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="SetBucketLoggingStatus"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Bucket" type="xsd:string"/> |
||||
|
<xsd:element name="AWSAccessKeyId" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Timestamp" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="Signature" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Credential" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="BucketLoggingStatus" type="tns:BucketLoggingStatus"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="SetBucketLoggingStatusResponse"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence/> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="GetObjectAccessControlPolicy"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Bucket" type="xsd:string"/> |
||||
|
<xsd:element name="Key" type="xsd:string"/> |
||||
|
<xsd:element name="AWSAccessKeyId" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Timestamp" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="Signature" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Credential" type="xsd:string" minOccurs="0"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="GetObjectAccessControlPolicyResponse"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="GetObjectAccessControlPolicyResponse" type="tns:AccessControlPolicy"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="GetBucketAccessControlPolicy"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Bucket" type="xsd:string"/> |
||||
|
<xsd:element name="AWSAccessKeyId" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Timestamp" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="Signature" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Credential" type="xsd:string" minOccurs="0"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="GetBucketAccessControlPolicyResponse"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="GetBucketAccessControlPolicyResponse" type="tns:AccessControlPolicy"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:complexType abstract="true" name="Grantee"/> |
||||
|
|
||||
|
<xsd:complexType name="User" abstract="true"> |
||||
|
<xsd:complexContent> |
||||
|
<xsd:extension base="tns:Grantee"/> |
||||
|
</xsd:complexContent> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:complexType name="AmazonCustomerByEmail"> |
||||
|
<xsd:complexContent> |
||||
|
<xsd:extension base="tns:User"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="EmailAddress" type="xsd:string"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:extension> |
||||
|
</xsd:complexContent> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:complexType name="CanonicalUser"> |
||||
|
<xsd:complexContent> |
||||
|
<xsd:extension base="tns:User"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="ID" type="xsd:string"/> |
||||
|
<xsd:element name="DisplayName" type="xsd:string" minOccurs="0"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:extension> |
||||
|
</xsd:complexContent> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:complexType name="Group"> |
||||
|
<xsd:complexContent> |
||||
|
<xsd:extension base="tns:Grantee"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="URI" type="xsd:string"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:extension> |
||||
|
</xsd:complexContent> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:simpleType name="Permission"> |
||||
|
<xsd:restriction base="xsd:string"> |
||||
|
<xsd:enumeration value="READ"/> |
||||
|
<xsd:enumeration value="WRITE"/> |
||||
|
<xsd:enumeration value="READ_ACP"/> |
||||
|
<xsd:enumeration value="WRITE_ACP"/> |
||||
|
<xsd:enumeration value="FULL_CONTROL"/> |
||||
|
</xsd:restriction> |
||||
|
</xsd:simpleType> |
||||
|
|
||||
|
<xsd:simpleType name="StorageClass"> |
||||
|
<xsd:restriction base="xsd:string"> |
||||
|
<xsd:enumeration value="STANDARD"/> |
||||
|
<xsd:enumeration value="REDUCED_REDUNDANCY"/> |
||||
|
<xsd:enumeration value="GLACIER"/> |
||||
|
<xsd:enumeration value="UNKNOWN"/> |
||||
|
</xsd:restriction> |
||||
|
</xsd:simpleType> |
||||
|
|
||||
|
<xsd:complexType name="Grant"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Grantee" type="tns:Grantee"/> |
||||
|
<xsd:element name="Permission" type="tns:Permission"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:complexType name="AccessControlList"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Grant" type="tns:Grant" minOccurs="0" maxOccurs="100"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:complexType name="CreateBucketConfiguration"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="LocationConstraint" type="tns:LocationConstraint"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:complexType name="LocationConstraint"> |
||||
|
<xsd:simpleContent> |
||||
|
<xsd:extension base="xsd:string"/> |
||||
|
</xsd:simpleContent> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:complexType name="AccessControlPolicy"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Owner" type="tns:CanonicalUser"/> |
||||
|
<xsd:element name="AccessControlList" type="tns:AccessControlList"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:element name="SetObjectAccessControlPolicy"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Bucket" type="xsd:string"/> |
||||
|
<xsd:element name="Key" type="xsd:string"/> |
||||
|
<xsd:element name="AccessControlList" type="tns:AccessControlList"/> |
||||
|
<xsd:element name="AWSAccessKeyId" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Timestamp" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="Signature" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Credential" type="xsd:string" minOccurs="0"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="SetObjectAccessControlPolicyResponse"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence/> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="SetBucketAccessControlPolicy"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Bucket" type="xsd:string"/> |
||||
|
<xsd:element name="AccessControlList" type="tns:AccessControlList" minOccurs="0"/> |
||||
|
<xsd:element name="AWSAccessKeyId" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Timestamp" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="Signature" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Credential" type="xsd:string" minOccurs="0"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="SetBucketAccessControlPolicyResponse"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence/> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="GetObject"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Bucket" type="xsd:string"/> |
||||
|
<xsd:element name="Key" type="xsd:string"/> |
||||
|
<xsd:element name="GetMetadata" type="xsd:boolean"/> |
||||
|
<xsd:element name="GetData" type="xsd:boolean"/> |
||||
|
<xsd:element name="InlineData" type="xsd:boolean"/> |
||||
|
<xsd:element name="AWSAccessKeyId" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Timestamp" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="Signature" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Credential" type="xsd:string" minOccurs="0"/> |
||||
|
|
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="GetObjectResponse"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="GetObjectResponse" type="tns:GetObjectResult"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:complexType name="GetObjectResult"> |
||||
|
<xsd:complexContent> |
||||
|
<xsd:extension base="tns:Result"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Metadata" type="tns:MetadataEntry" minOccurs="0" maxOccurs="unbounded"/> |
||||
|
<xsd:element name="Data" type="xsd:base64Binary" nillable="true"/> |
||||
|
<xsd:element name="LastModified" type="xsd:dateTime"/> |
||||
|
<xsd:element name="ETag" type="xsd:string"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:extension> |
||||
|
</xsd:complexContent> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:element name="GetObjectExtended"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Bucket" type="xsd:string"/> |
||||
|
<xsd:element name="Key" type="xsd:string"/> |
||||
|
<xsd:element name="GetMetadata" type="xsd:boolean"/> |
||||
|
<xsd:element name="GetData" type="xsd:boolean"/> |
||||
|
<xsd:element name="InlineData" type="xsd:boolean"/> |
||||
|
<xsd:element name="ByteRangeStart" type="xsd:long" minOccurs="0"/> |
||||
|
<xsd:element name="ByteRangeEnd" type="xsd:long" minOccurs="0"/> |
||||
|
<xsd:element name="IfModifiedSince" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="IfUnmodifiedSince" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="IfMatch" type="xsd:string" minOccurs="0" maxOccurs="100"/> |
||||
|
<xsd:element name="IfNoneMatch" type="xsd:string" minOccurs="0" maxOccurs="100"/> |
||||
|
<xsd:element name="ReturnCompleteObjectOnConditionFailure" type="xsd:boolean" minOccurs="0"/> |
||||
|
<xsd:element name="AWSAccessKeyId" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Timestamp" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="Signature" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Credential" type="xsd:string" minOccurs="0"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="GetObjectExtendedResponse"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="GetObjectResponse" type="tns:GetObjectResult"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="PutObject"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Bucket" type="xsd:string"/> |
||||
|
<xsd:element name="Key" type="xsd:string"/> |
||||
|
<xsd:element name="Metadata" type="tns:MetadataEntry" minOccurs="0" maxOccurs="100"/> |
||||
|
<xsd:element name="ContentLength" type="xsd:long"/> |
||||
|
<xsd:element name="AccessControlList" type="tns:AccessControlList" minOccurs="0"/> |
||||
|
<xsd:element name="StorageClass" type="tns:StorageClass" minOccurs="0"/> |
||||
|
<xsd:element name="AWSAccessKeyId" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Timestamp" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="Signature" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Credential" type="xsd:string" minOccurs="0"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="PutObjectResponse"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="PutObjectResponse" type="tns:PutObjectResult"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:complexType name="PutObjectResult"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="ETag" type="xsd:string"/> |
||||
|
<xsd:element name="LastModified" type="xsd:dateTime"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:element name="PutObjectInline"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Bucket" type="xsd:string"/> |
||||
|
<xsd:element name="Key" type="xsd:string"/> |
||||
|
<xsd:element minOccurs="0" maxOccurs="100" name="Metadata" type="tns:MetadataEntry"/> |
||||
|
<xsd:element name="Data" type="xsd:base64Binary"/> |
||||
|
<xsd:element name="ContentLength" type="xsd:long"/> |
||||
|
<xsd:element name="AccessControlList" type="tns:AccessControlList" minOccurs="0"/> |
||||
|
<xsd:element name="StorageClass" type="tns:StorageClass" minOccurs="0"/> |
||||
|
<xsd:element name="AWSAccessKeyId" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Timestamp" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="Signature" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Credential" type="xsd:string" minOccurs="0"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="PutObjectInlineResponse"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="PutObjectInlineResponse" type="tns:PutObjectResult"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="DeleteObject"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Bucket" type="xsd:string"/> |
||||
|
<xsd:element name="Key" type="xsd:string"/> |
||||
|
<xsd:element name="AWSAccessKeyId" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Timestamp" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="Signature" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Credential" type="xsd:string" minOccurs="0"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="DeleteObjectResponse"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="DeleteObjectResponse" type="tns:Status"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="ListBucket"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Bucket" type="xsd:string"/> |
||||
|
<xsd:element name="Prefix" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Marker" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="MaxKeys" type="xsd:int" minOccurs="0"/> |
||||
|
<xsd:element name="Delimiter" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="AWSAccessKeyId" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Timestamp" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="Signature" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Credential" type="xsd:string" minOccurs="0"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="ListBucketResponse"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="ListBucketResponse" type="tns:ListBucketResult"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="ListVersionsResponse"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="ListVersionsResponse" type="tns:ListVersionsResult"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:complexType name="ListEntry"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Key" type="xsd:string"/> |
||||
|
<xsd:element name="LastModified" type="xsd:dateTime"/> |
||||
|
<xsd:element name="ETag" type="xsd:string"/> |
||||
|
<xsd:element name="Size" type="xsd:long"/> |
||||
|
<xsd:element name="Owner" type="tns:CanonicalUser" minOccurs="0"/> |
||||
|
<xsd:element name="StorageClass" type="tns:StorageClass"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:complexType name="VersionEntry"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Key" type="xsd:string"/> |
||||
|
<xsd:element name="VersionId" type="xsd:string"/> |
||||
|
<xsd:element name="IsLatest" type="xsd:boolean"/> |
||||
|
<xsd:element name="LastModified" type="xsd:dateTime"/> |
||||
|
<xsd:element name="ETag" type="xsd:string"/> |
||||
|
<xsd:element name="Size" type="xsd:long"/> |
||||
|
<xsd:element name="Owner" type="tns:CanonicalUser" minOccurs="0"/> |
||||
|
<xsd:element name="StorageClass" type="tns:StorageClass"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:complexType name="DeleteMarkerEntry"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Key" type="xsd:string"/> |
||||
|
<xsd:element name="VersionId" type="xsd:string"/> |
||||
|
<xsd:element name="IsLatest" type="xsd:boolean"/> |
||||
|
<xsd:element name="LastModified" type="xsd:dateTime"/> |
||||
|
<xsd:element name="Owner" type="tns:CanonicalUser" minOccurs="0"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:complexType name="PrefixEntry"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Prefix" type="xsd:string"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:complexType name="ListBucketResult"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Metadata" type="tns:MetadataEntry" minOccurs="0" maxOccurs="unbounded"/> |
||||
|
<xsd:element name="Name" type="xsd:string"/> |
||||
|
<xsd:element name="Prefix" type="xsd:string"/> |
||||
|
<xsd:element name="Marker" type="xsd:string"/> |
||||
|
<xsd:element name="NextMarker" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="MaxKeys" type="xsd:int"/> |
||||
|
<xsd:element name="Delimiter" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="IsTruncated" type="xsd:boolean"/> |
||||
|
<xsd:element name="Contents" type="tns:ListEntry" minOccurs="0" maxOccurs="unbounded"/> |
||||
|
<xsd:element name="CommonPrefixes" type="tns:PrefixEntry" minOccurs="0" maxOccurs="unbounded"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:complexType name="ListVersionsResult"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Metadata" type="tns:MetadataEntry" minOccurs="0" maxOccurs="unbounded"/> |
||||
|
<xsd:element name="Name" type="xsd:string"/> |
||||
|
<xsd:element name="Prefix" type="xsd:string"/> |
||||
|
<xsd:element name="KeyMarker" type="xsd:string"/> |
||||
|
<xsd:element name="VersionIdMarker" type="xsd:string"/> |
||||
|
<xsd:element name="NextKeyMarker" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="NextVersionIdMarker" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="MaxKeys" type="xsd:int"/> |
||||
|
<xsd:element name="Delimiter" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="IsTruncated" type="xsd:boolean"/> |
||||
|
<xsd:choice minOccurs="0" maxOccurs="unbounded"> |
||||
|
<xsd:element name="Version" type="tns:VersionEntry"/> |
||||
|
<xsd:element name="DeleteMarker" type="tns:DeleteMarkerEntry"/> |
||||
|
</xsd:choice> |
||||
|
<xsd:element name="CommonPrefixes" type="tns:PrefixEntry" minOccurs="0" maxOccurs="unbounded"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:element name="ListAllMyBuckets"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="AWSAccessKeyId" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Timestamp" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="Signature" type="xsd:string" minOccurs="0"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="ListAllMyBucketsResponse"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="ListAllMyBucketsResponse" type="tns:ListAllMyBucketsResult"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:complexType name="ListAllMyBucketsEntry"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Name" type="xsd:string"/> |
||||
|
<xsd:element name="CreationDate" type="xsd:dateTime"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:complexType name="ListAllMyBucketsResult"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Owner" type="tns:CanonicalUser"/> |
||||
|
<xsd:element name="Buckets" type="tns:ListAllMyBucketsList"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:complexType name="ListAllMyBucketsList"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Bucket" type="tns:ListAllMyBucketsEntry" minOccurs="0" maxOccurs="unbounded"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:element name="PostResponse"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Location" type="xsd:anyURI"/> |
||||
|
<xsd:element name="Bucket" type="xsd:string"/> |
||||
|
<xsd:element name="Key" type="xsd:string"/> |
||||
|
<xsd:element name="ETag" type="xsd:string"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:simpleType name="MetadataDirective"> |
||||
|
<xsd:restriction base="xsd:string"> |
||||
|
<xsd:enumeration value="COPY"/> |
||||
|
<xsd:enumeration value="REPLACE"/> |
||||
|
</xsd:restriction> |
||||
|
</xsd:simpleType> |
||||
|
|
||||
|
<xsd:element name="CopyObject"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="SourceBucket" type="xsd:string"/> |
||||
|
<xsd:element name="SourceKey" type="xsd:string"/> |
||||
|
<xsd:element name="DestinationBucket" type="xsd:string"/> |
||||
|
<xsd:element name="DestinationKey" type="xsd:string"/> |
||||
|
<xsd:element name="MetadataDirective" type="tns:MetadataDirective" minOccurs="0"/> |
||||
|
<xsd:element name="Metadata" type="tns:MetadataEntry" minOccurs="0" maxOccurs="100"/> |
||||
|
<xsd:element name="AccessControlList" type="tns:AccessControlList" minOccurs="0"/> |
||||
|
<xsd:element name="CopySourceIfModifiedSince" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="CopySourceIfUnmodifiedSince" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="CopySourceIfMatch" type="xsd:string" minOccurs="0" maxOccurs="100"/> |
||||
|
<xsd:element name="CopySourceIfNoneMatch" type="xsd:string" minOccurs="0" maxOccurs="100"/> |
||||
|
<xsd:element name="StorageClass" type="tns:StorageClass" minOccurs="0"/> |
||||
|
<xsd:element name="AWSAccessKeyId" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Timestamp" type="xsd:dateTime" minOccurs="0"/> |
||||
|
<xsd:element name="Signature" type="xsd:string" minOccurs="0"/> |
||||
|
<xsd:element name="Credential" type="xsd:string" minOccurs="0"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:element name="CopyObjectResponse"> |
||||
|
<xsd:complexType> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="CopyObjectResult" type="tns:CopyObjectResult" /> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
</xsd:element> |
||||
|
|
||||
|
<xsd:complexType name="CopyObjectResult"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="LastModified" type="xsd:dateTime"/> |
||||
|
<xsd:element name="ETag" type="xsd:string"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:complexType name="RequestPaymentConfiguration"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Payer" type="tns:Payer" minOccurs="1" maxOccurs="1"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:simpleType name="Payer"> |
||||
|
<xsd:restriction base="xsd:string"> |
||||
|
<xsd:enumeration value="BucketOwner"/> |
||||
|
<xsd:enumeration value="Requester"/> |
||||
|
</xsd:restriction> |
||||
|
</xsd:simpleType> |
||||
|
|
||||
|
<xsd:complexType name="VersioningConfiguration"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Status" type="tns:VersioningStatus" minOccurs="0"/> |
||||
|
<xsd:element name="MfaDelete" type="tns:MfaDeleteStatus" minOccurs="0"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:simpleType name="MfaDeleteStatus"> |
||||
|
<xsd:restriction base="xsd:string"> |
||||
|
<xsd:enumeration value="Enabled"/> |
||||
|
<xsd:enumeration value="Disabled"/> |
||||
|
</xsd:restriction> |
||||
|
</xsd:simpleType> |
||||
|
|
||||
|
<xsd:simpleType name="VersioningStatus"> |
||||
|
<xsd:restriction base="xsd:string"> |
||||
|
<xsd:enumeration value="Enabled"/> |
||||
|
<xsd:enumeration value="Suspended"/> |
||||
|
</xsd:restriction> |
||||
|
</xsd:simpleType> |
||||
|
|
||||
|
<xsd:complexType name="NotificationConfiguration"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="TopicConfiguration" minOccurs="0" maxOccurs="unbounded" type="tns:TopicConfiguration"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
<xsd:complexType name="TopicConfiguration"> |
||||
|
<xsd:sequence> |
||||
|
<xsd:element name="Topic" minOccurs="1" maxOccurs="1" type="xsd:string"/> |
||||
|
<xsd:element name="Event" minOccurs="1" maxOccurs="unbounded" type="xsd:string"/> |
||||
|
</xsd:sequence> |
||||
|
</xsd:complexType> |
||||
|
|
||||
|
</xsd:schema> |
@ -0,0 +1,7 @@ |
|||||
|
see https://blog.aqwari.net/xml-schema-go/ |
||||
|
|
||||
|
1. go get aqwari.net/xml/cmd/xsdgen |
||||
|
2. xsdgen -o s3api_xsd_generated.go -pkg s3api AmazonS3.xsd |
||||
|
|
||||
|
|
||||
|
|
@ -0,0 +1,58 @@ |
|||||
|
package s3api |
||||
|
|
||||
|
import ( |
||||
|
"net/http" |
||||
|
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb" |
||||
|
"github.com/chrislusf/seaweedfs/weed/glog" |
||||
|
"time" |
||||
|
"context" |
||||
|
"fmt" |
||||
|
) |
||||
|
|
||||
|
func (s3a *S3ApiServer) ListBucketsHandler(w http.ResponseWriter, r *http.Request) { |
||||
|
|
||||
|
var response ListAllMyBucketsResponse |
||||
|
err := s3a.withFilerClient(func(client filer_pb.SeaweedFilerClient) error { |
||||
|
|
||||
|
request := &filer_pb.ListEntriesRequest{ |
||||
|
Directory: "/buckets", |
||||
|
} |
||||
|
|
||||
|
glog.V(4).Infof("read directory: %v", request) |
||||
|
resp, err := client.ListEntries(context.Background(), request) |
||||
|
if err != nil { |
||||
|
return fmt.Errorf("list buckets: %v", err) |
||||
|
} |
||||
|
|
||||
|
var buckets []ListAllMyBucketsEntry |
||||
|
for _, entry := range resp.Entries { |
||||
|
if entry.IsDirectory { |
||||
|
buckets = append(buckets, ListAllMyBucketsEntry{ |
||||
|
Name: entry.Name, |
||||
|
CreationDate: time.Unix(entry.Attributes.Crtime, 0), |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
response = ListAllMyBucketsResponse{ |
||||
|
ListAllMyBucketsResponse: ListAllMyBucketsResult{ |
||||
|
Owner: CanonicalUser{ |
||||
|
ID: "", |
||||
|
DisplayName: "", |
||||
|
}, |
||||
|
Buckets: ListAllMyBucketsList{ |
||||
|
Bucket: buckets, |
||||
|
}, |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
}) |
||||
|
|
||||
|
if err != nil { |
||||
|
writeErrorResponse(w, ErrInternalError, r.URL) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
writeSuccessResponseXML(w, encodeResponse(response)) |
||||
|
} |
@ -0,0 +1,76 @@ |
|||||
|
package s3api |
||||
|
|
||||
|
import ( |
||||
|
"encoding/xml" |
||||
|
"net/http" |
||||
|
) |
||||
|
|
||||
|
// APIError structure
|
||||
|
type APIError struct { |
||||
|
Code string |
||||
|
Description string |
||||
|
HTTPStatusCode int |
||||
|
} |
||||
|
|
||||
|
// RESTErrorResponse - error response format
|
||||
|
type RESTErrorResponse struct { |
||||
|
XMLName xml.Name `xml:"Error" json:"-"` |
||||
|
Code string `xml:"Code" json:"Code"` |
||||
|
Message string `xml:"Message" json:"Message"` |
||||
|
Resource string `xml:"Resource" json:"Resource"` |
||||
|
RequestID string `xml:"RequestId" json:"RequestId"` |
||||
|
} |
||||
|
|
||||
|
// ErrorCode type of error status.
|
||||
|
type ErrorCode int |
||||
|
|
||||
|
// Error codes, see full list at http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
|
||||
|
const ( |
||||
|
ErrNone ErrorCode = iota |
||||
|
ErrMethodNotAllowed |
||||
|
ErrBucketNotEmpty |
||||
|
ErrBucketAlreadyExists |
||||
|
ErrBucketAlreadyOwnedByYou |
||||
|
ErrInvalidBucketName |
||||
|
ErrInternalError |
||||
|
) |
||||
|
|
||||
|
// error code to APIError structure, these fields carry respective
|
||||
|
// descriptions for all the error responses.
|
||||
|
var errorCodeResponse = map[ErrorCode]APIError{ |
||||
|
ErrMethodNotAllowed: { |
||||
|
Code: "MethodNotAllowed", |
||||
|
Description: "The specified method is not allowed against this resource.", |
||||
|
HTTPStatusCode: http.StatusMethodNotAllowed, |
||||
|
}, |
||||
|
ErrBucketNotEmpty: { |
||||
|
Code: "BucketNotEmpty", |
||||
|
Description: "The bucket you tried to delete is not empty", |
||||
|
HTTPStatusCode: http.StatusConflict, |
||||
|
}, |
||||
|
ErrBucketAlreadyExists: { |
||||
|
Code: "BucketAlreadyExists", |
||||
|
Description: "The requested bucket name is not available. The bucket namespace is shared by all users of the system. Please select a different name and try again.", |
||||
|
HTTPStatusCode: http.StatusConflict, |
||||
|
}, |
||||
|
ErrBucketAlreadyOwnedByYou: { |
||||
|
Code: "BucketAlreadyOwnedByYou", |
||||
|
Description: "Your previous request to create the named bucket succeeded and you already own it.", |
||||
|
HTTPStatusCode: http.StatusConflict, |
||||
|
}, |
||||
|
ErrInvalidBucketName: { |
||||
|
Code: "InvalidBucketName", |
||||
|
Description: "The specified bucket is not valid.", |
||||
|
HTTPStatusCode: http.StatusBadRequest, |
||||
|
}, |
||||
|
ErrInternalError: { |
||||
|
Code: "InternalError", |
||||
|
Description: "We encountered an internal error, please try again.", |
||||
|
HTTPStatusCode: http.StatusInternalServerError, |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
// getAPIError provides API Error for input API error code.
|
||||
|
func getAPIError(code ErrorCode) APIError { |
||||
|
return errorCodeResponse[code] |
||||
|
} |
@ -0,0 +1,67 @@ |
|||||
|
package s3api |
||||
|
|
||||
|
import ( |
||||
|
"net/http" |
||||
|
"net/url" |
||||
|
"fmt" |
||||
|
"time" |
||||
|
"github.com/gorilla/mux" |
||||
|
"context" |
||||
|
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb" |
||||
|
"github.com/chrislusf/seaweedfs/weed/util" |
||||
|
) |
||||
|
|
||||
|
func newContext(r *http.Request, api string) context.Context { |
||||
|
vars := mux.Vars(r) |
||||
|
return context.WithValue(context.Background(), "bucket", vars["bucket"]) |
||||
|
} |
||||
|
|
||||
|
func (s3a *S3ApiServer) withFilerClient(fn func(filer_pb.SeaweedFilerClient) error) error { |
||||
|
|
||||
|
grpcConnection, err := util.GrpcDial(s3a.option.FilerGrpcAddress) |
||||
|
if err != nil { |
||||
|
return fmt.Errorf("fail to dial %s: %v", s3a.option.FilerGrpcAddress, err) |
||||
|
} |
||||
|
defer grpcConnection.Close() |
||||
|
|
||||
|
client := filer_pb.NewSeaweedFilerClient(grpcConnection) |
||||
|
|
||||
|
return fn(client) |
||||
|
} |
||||
|
|
||||
|
// If none of the http routes match respond with MethodNotAllowed
|
||||
|
func notFoundHandler(w http.ResponseWriter, r *http.Request) { |
||||
|
writeErrorResponse(w, ErrMethodNotAllowed, r.URL) |
||||
|
} |
||||
|
|
||||
|
func writeErrorResponse(w http.ResponseWriter, errorCode ErrorCode, reqURL *url.URL) { |
||||
|
apiError := getAPIError(errorCode) |
||||
|
errorResponse := getRESTErrorResponse(apiError, reqURL.Path) |
||||
|
encodedErrorResponse := encodeResponse(errorResponse) |
||||
|
writeResponse(w, apiError.HTTPStatusCode, encodedErrorResponse, mimeXML) |
||||
|
} |
||||
|
|
||||
|
func getRESTErrorResponse(err APIError, resource string) RESTErrorResponse { |
||||
|
return RESTErrorResponse{ |
||||
|
Code: err.Code, |
||||
|
Message: err.Description, |
||||
|
Resource: resource, |
||||
|
RequestID: fmt.Sprintf("%d", time.Now().UnixNano()), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func writeResponse(w http.ResponseWriter, statusCode int, response []byte, mType mimeType) { |
||||
|
setCommonHeaders(w) |
||||
|
if mType != mimeNone { |
||||
|
w.Header().Set("Content-Type", string(mType)) |
||||
|
} |
||||
|
w.WriteHeader(statusCode) |
||||
|
if response != nil { |
||||
|
w.Write(response) |
||||
|
w.(http.Flusher).Flush() |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func writeSuccessResponseXML(w http.ResponseWriter, response []byte) { |
||||
|
writeResponse(w, http.StatusOK, response, mimeXML) |
||||
|
} |
@ -0,0 +1,31 @@ |
|||||
|
package s3api |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"encoding/xml" |
||||
|
"fmt" |
||||
|
"net/http" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
type mimeType string |
||||
|
|
||||
|
const ( |
||||
|
mimeNone mimeType = "" |
||||
|
mimeJSON mimeType = "application/json" |
||||
|
mimeXML mimeType = "application/xml" |
||||
|
) |
||||
|
|
||||
|
func setCommonHeaders(w http.ResponseWriter) { |
||||
|
w.Header().Set("x-amz-request-id", fmt.Sprintf("%d", time.Now().UnixNano())) |
||||
|
w.Header().Set("Accept-Ranges", "bytes") |
||||
|
} |
||||
|
|
||||
|
// Encodes the response headers into XML format.
|
||||
|
func encodeResponse(response interface{}) []byte { |
||||
|
var bytesBuffer bytes.Buffer |
||||
|
bytesBuffer.WriteString(xml.Header) |
||||
|
e := xml.NewEncoder(&bytesBuffer) |
||||
|
e.Encode(response) |
||||
|
return bytesBuffer.Bytes() |
||||
|
} |
@ -0,0 +1,109 @@ |
|||||
|
package s3api |
||||
|
|
||||
|
import ( |
||||
|
_ "github.com/chrislusf/seaweedfs/weed/filer2/cassandra" |
||||
|
_ "github.com/chrislusf/seaweedfs/weed/filer2/leveldb" |
||||
|
_ "github.com/chrislusf/seaweedfs/weed/filer2/memdb" |
||||
|
_ "github.com/chrislusf/seaweedfs/weed/filer2/mysql" |
||||
|
_ "github.com/chrislusf/seaweedfs/weed/filer2/postgres" |
||||
|
_ "github.com/chrislusf/seaweedfs/weed/filer2/redis" |
||||
|
"github.com/gorilla/mux" |
||||
|
"net/http" |
||||
|
) |
||||
|
|
||||
|
type S3ApiServerOption struct { |
||||
|
Filer string |
||||
|
FilerGrpcAddress string |
||||
|
DomainName string |
||||
|
} |
||||
|
|
||||
|
type S3ApiServer struct { |
||||
|
option *S3ApiServerOption |
||||
|
} |
||||
|
|
||||
|
func NewS3ApiServer(router *mux.Router, option *S3ApiServerOption) (s3ApiServer *S3ApiServer, err error) { |
||||
|
s3ApiServer = &S3ApiServer{ |
||||
|
option: option, |
||||
|
} |
||||
|
|
||||
|
s3ApiServer.registerRouter(router) |
||||
|
|
||||
|
return s3ApiServer, nil |
||||
|
} |
||||
|
|
||||
|
func (s3a *S3ApiServer) registerRouter(router *mux.Router) { |
||||
|
// API Router
|
||||
|
apiRouter := router.PathPrefix("/").Subrouter() |
||||
|
var routers []*mux.Router |
||||
|
if s3a.option.DomainName != "" { |
||||
|
routers = append(routers, apiRouter.Host("{bucket:.+}." + s3a.option.DomainName).Subrouter()) |
||||
|
} |
||||
|
routers = append(routers, apiRouter.PathPrefix("/{bucket}").Subrouter()) |
||||
|
|
||||
|
/* |
||||
|
for _, bucket := range routers { |
||||
|
// HeadObject
|
||||
|
bucket.Methods("HEAD").Path("/{object:.+}").HandlerFunc(s3a.HeadObjectHandler) |
||||
|
// GetObject
|
||||
|
bucket.Methods("GET").Path("/{object:.+}").HandlerFunc(s3a.GetObjectHandler) |
||||
|
// CopyObject
|
||||
|
bucket.Methods("PUT").Path("/{object:.+}").HeadersRegexp("X-Amz-Copy-Source", ".*?(\\/|%2F).*?").HandlerFunc(s3a.CopyObjectHandler) |
||||
|
// PutObject
|
||||
|
bucket.Methods("PUT").Path("/{object:.+}").HandlerFunc(s3a.PutObjectHandler) |
||||
|
// DeleteObject
|
||||
|
bucket.Methods("DELETE").Path("/{object:.+}").HandlerFunc(s3a.DeleteObjectHandler) |
||||
|
|
||||
|
// CopyObjectPart
|
||||
|
bucket.Methods("PUT").Path("/{object:.+}").HeadersRegexp("X-Amz-Copy-Source", ".*?(\\/|%2F).*?").HandlerFunc(s3a.CopyObjectPartHandler).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}") |
||||
|
// PutObjectPart
|
||||
|
bucket.Methods("PUT").Path("/{object:.+}").HandlerFunc(s3a.PutObjectPartHandler).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}") |
||||
|
// ListObjectPxarts
|
||||
|
bucket.Methods("GET").Path("/{object:.+}").HandlerFunc(s3a.ListObjectPartsHandler).Queries("uploadId", "{uploadId:.*}") |
||||
|
// CompleteMultipartUpload
|
||||
|
bucket.Methods("POST").Path("/{object:.+}").HandlerFunc(s3a.CompleteMultipartUploadHandler).Queries("uploadId", "{uploadId:.*}") |
||||
|
// NewMultipartUpload
|
||||
|
bucket.Methods("POST").Path("/{object:.+}").HandlerFunc(s3a.NewMultipartUploadHandler).Queries("uploads", "") |
||||
|
// AbortMultipartUpload
|
||||
|
bucket.Methods("DELETE").Path("/{object:.+}").HandlerFunc(s3a.AbortMultipartUploadHandler).Queries("uploadId", "{uploadId:.*}") |
||||
|
|
||||
|
// ListMultipartUploads
|
||||
|
bucket.Methods("GET").HandlerFunc(s3a.ListMultipartUploadsHandler).Queries("uploads", "") |
||||
|
// ListObjectsV2
|
||||
|
bucket.Methods("GET").HandlerFunc(s3a.ListObjectsV2Handler).Queries("list-type", "2") |
||||
|
// ListObjectsV1 (Legacy)
|
||||
|
bucket.Methods("GET").HandlerFunc(s3a.ListObjectsV1Handler) |
||||
|
// PutBucket
|
||||
|
bucket.Methods("PUT").HandlerFunc(s3a.PutBucketHandler) |
||||
|
// HeadBucket
|
||||
|
bucket.Methods("HEAD").HandlerFunc(s3a.HeadBucketHandler) |
||||
|
// DeleteMultipleObjects
|
||||
|
bucket.Methods("POST").HandlerFunc(s3a.DeleteMultipleObjectsHandler).Queries("delete", "") |
||||
|
// DeleteBucket
|
||||
|
bucket.Methods("DELETE").HandlerFunc(s3a.DeleteBucketHandler) |
||||
|
|
||||
|
// not implemented
|
||||
|
// GetBucketLocation
|
||||
|
bucket.Methods("GET").HandlerFunc(s3a.GetBucketLocationHandler).Queries("location", "") |
||||
|
// GetBucketPolicy
|
||||
|
bucket.Methods("GET").HandlerFunc(s3a.GetBucketPolicyHandler).Queries("policy", "") |
||||
|
// GetObjectACL
|
||||
|
bucket.Methods("GET").Path("/{object:.+}").HandlerFunc(s3a.GetObjectACLHandler).Queries("acl", "") |
||||
|
// GetBucketACL
|
||||
|
bucket.Methods("GET").HandlerFunc(s3a.GetBucketACLHandler).Queries("acl", "") |
||||
|
// PutBucketPolicy
|
||||
|
bucket.Methods("PUT").HandlerFunc(s3a.PutBucketPolicyHandler).Queries("policy", "") |
||||
|
// DeleteBucketPolicy
|
||||
|
bucket.Methods("DELETE").HandlerFunc(s3a.DeleteBucketPolicyHandler).Queries("policy", "") |
||||
|
// PostPolicy
|
||||
|
bucket.Methods("POST").HeadersRegexp("Content-Type", "multipart/form-data*").HandlerFunc(s3a.PostPolicyBucketHandler) |
||||
|
|
||||
|
} |
||||
|
*/ |
||||
|
|
||||
|
// ListBuckets
|
||||
|
apiRouter.Methods("GET").Path("/").HandlerFunc(s3a.ListBucketsHandler) |
||||
|
|
||||
|
// NotFound
|
||||
|
apiRouter.NotFoundHandler = http.HandlerFunc(notFoundHandler) |
||||
|
|
||||
|
} |
1002
weed/s3api/s3api_xsd_generated.go
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue