Skip to content

Commit

Permalink
support extend http response status code other than oss server
Browse files Browse the repository at this point in the history
  • Loading branch information
taowei.wtw authored and kkuai committed Feb 18, 2022
1 parent 3dce9c8 commit 44431f5
Show file tree
Hide file tree
Showing 5 changed files with 238 additions and 66 deletions.
18 changes: 10 additions & 8 deletions oss/bucket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4268,11 +4268,13 @@ func (s *OssBucketSuite) TestVersioningAppendObject(c *C) {
objectName := objectNamePrefix + RandStr(8)
nextPos, err = bucket.AppendObject(objectName, strings.NewReader("123"), nextPos, GetResponseHeader(&respHeader))
c.Assert(err, IsNil)
c.Assert(GetVersionId(respHeader), Equals, NullVersion)
versionId := GetVersionId(respHeader)
c.Assert(versionId == NullVersion, Equals, false)

nextPos, err = bucket.AppendObject(objectName, strings.NewReader("456"), nextPos, GetResponseHeader(&respHeader))
c.Assert(err, IsNil)
c.Assert(GetVersionId(respHeader), Equals, NullVersion)
versionId = GetVersionId(respHeader)
c.Assert(versionId == NullVersion, Equals, false)

// delete object
err = bucket.DeleteObject(objectName, GetResponseHeader(&respHeader))
Expand All @@ -4282,16 +4284,16 @@ func (s *OssBucketSuite) TestVersioningAppendObject(c *C) {
_, err = bucket.GetObject(objectName)
c.Assert(err, NotNil)

// get null version success
body, err := bucket.GetObject(objectName, VersionId(NullVersion))
// get version success
body, err := bucket.GetObject(objectName, VersionId(versionId))
c.Assert(err, IsNil)
str, err := readBody(body)
c.Assert(err, IsNil)
c.Assert(str, Equals, "123456")

// append object again:failure
nextPos, err = bucket.AppendObject(objectName, strings.NewReader("789"), nextPos, GetResponseHeader(&respHeader))
c.Assert(err, NotNil)
// append object again:success
nextPos, err = bucket.AppendObject(objectName, strings.NewReader("789"), 0, GetResponseHeader(&respHeader))
c.Assert(err, IsNil)

// delete deletemark
options := []Option{VersionId(markVersionId), GetResponseHeader(&respHeader)}
Expand All @@ -4301,7 +4303,7 @@ func (s *OssBucketSuite) TestVersioningAppendObject(c *C) {
// append object again:success
nextPos, err = bucket.AppendObject(objectName, strings.NewReader("789"), nextPos, GetResponseHeader(&respHeader))
c.Assert(err, IsNil)
c.Assert(int(nextPos), Equals, 9)
c.Assert(int(nextPos), Equals, 6)

bucket.DeleteObject(objectName)
ForceDeleteBucket(client, bucketName, c)
Expand Down
96 changes: 90 additions & 6 deletions oss/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1004,10 +1004,10 @@ func (s *OssClientSuite) TestSetBucketLifecycleOverLap(c *C) {
err = client.SetBucketLifecycle(bucketNameTest, rules)
c.Assert(err, NotNil)

//enable overlap,success
//enable overlap,error
options := []Option{AllowSameActionOverLap(true)}
err = client.SetBucketLifecycle(bucketNameTest, rules, options...)
c.Assert(err, IsNil)
c.Assert(err, NotNil)
err = client.DeleteBucket(bucketNameTest)

}
Expand Down Expand Up @@ -1060,10 +1060,10 @@ func (s *OssClientSuite) TestSetBucketLifecycleXml(c *C) {
err = client.SetBucketLifecycleXml(bucketNameTest, xmlBody)
c.Assert(err, NotNil)

// enable overlap,success
// enable overlap,error
options := []Option{AllowSameActionOverLap(true)}
err = client.SetBucketLifecycleXml(bucketNameTest, xmlBody, options...)
c.Assert(err, IsNil)
c.Assert(err, NotNil)

err = client.DeleteBucket(bucketNameTest)
c.Assert(err, IsNil)
Expand Down Expand Up @@ -3738,6 +3738,8 @@ func (s *OssClientSuite) TestClientRedirect(c *C) {
svr.ListenAndServe()
}()

time.Sleep(3 * time.Second)

url := "http://" + httpAddr

// create client 1,redirect disable
Expand All @@ -3755,6 +3757,8 @@ func (s *OssClientSuite) TestClientRedirect(c *C) {
data, err := ioutil.ReadAll(resp.Body)
c.Assert(string(data), Equals, "You have been redirected here!")
resp.Body.Close()

svr.Close()
}

func verifyCertificatehandler(w http.ResponseWriter, req *http.Request) {
Expand Down Expand Up @@ -4495,14 +4499,94 @@ func (s *OssClientSuite) TestCreateBucketXml(c *C) {
<StorageClass>IA</StorageClass>
</CreateBucketConfiguration>
`
err = client.CreateBucketXml(bucketName,xmlBody)
err = client.CreateBucketXml(bucketName, xmlBody)
c.Assert(err, IsNil)

//check
bucketInfo,_:= client.GetBucketInfo(bucketName)
bucketInfo, _ := client.GetBucketInfo(bucketName)
c.Assert(bucketInfo.BucketInfo.StorageClass, Equals, "IA")
err = client.DeleteBucket(bucketName)
c.Assert(err, IsNil)
}

func emptyBodytargetHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set(HTTPHeaderOssRequestID, "123456")
w.WriteHeader(309)
fmt.Fprintf(w, "")
}

func serviceErrorBodytargetHandler(w http.ResponseWriter, r *http.Request) {
err := ServiceError{
Code: "510",
Message: "service response error",
RequestID: "ABCDEF",
HostID: "127.0.0.1",
Endpoint: "127.0.0.1",
StatusCode: 510,
}
data, _ := xml.MarshalIndent(&err, "", " ")
w.Header().Set(HTTPHeaderOssRequestID, "ABCDEF")
w.WriteHeader(510)
fmt.Fprintf(w, string(data))
}
func unkownErrorBodytargetHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(509)
fmt.Fprintf(w, "unkown response error")
}

func (s *OssClientSuite) TestExtendHttpResponseStatusCode(c *C) {
// get port
rand.Seed(time.Now().Unix())
port := 10000 + rand.Intn(10000)

// start http server
httpAddr := fmt.Sprintf("127.0.0.1:%d", port)
mux := http.NewServeMux()
mux.HandleFunc("/empty-body/empty-body", emptyBodytargetHandler)
mux.HandleFunc("/service-error/service-error", serviceErrorBodytargetHandler)
mux.HandleFunc("/unkown-error/unkown-error", unkownErrorBodytargetHandler)
svr := &http.Server{
Addr: httpAddr,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
Handler: mux,
}

go func() {
svr.ListenAndServe()
}()

time.Sleep(5 * time.Second)

testEndpoint := httpAddr
client, err := New(testEndpoint, accessID, accessKey)

//emptyBodytargetHandler
bucket, err := client.Bucket("empty-body")
_, err = bucket.GetObject("empty-body")
fmt.Println(err)
serviceErr, isSuc := err.(ServiceError)
c.Assert(isSuc, Equals, true)
c.Assert(serviceErr.StatusCode, Equals, 309)
c.Assert(serviceErr.RequestID, Equals, "123456")

//serviceErrorBodytargetHandler
bucket, err = client.Bucket("service-error")
_, err = bucket.GetObject("service-error")
serviceErr, isSuc = (err).(ServiceError)
c.Assert(isSuc, Equals, true)
c.Assert(serviceErr.StatusCode, Equals, 510)
c.Assert(serviceErr.RequestID, Equals, "ABCDEF")

//unkownErrorBodytargetHandler
bucket, err = client.Bucket("unkown-error")
_, err = bucket.GetObject("unkown-error")
serviceErr, isSuc = err.(ServiceError)
c.Assert(isSuc, Equals, false)
prefix := "unkown response body, status = 509"
ok := strings.Contains(err.Error(), prefix)
c.Assert(ok, Equals, true)

svr.Close()
}
134 changes: 83 additions & 51 deletions oss/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -471,67 +471,99 @@ func (conn Conn) handleResponse(resp *http.Response, crc hash.Hash64) (*Response
var srvCRC uint64

statusCode := resp.StatusCode
if statusCode >= 400 && statusCode <= 505 {
// 4xx and 5xx indicate that the operation has error occurred
var respBody []byte
respBody, err := readResponseBody(resp)
if err != nil {
return nil, err
}
if statusCode/100 != 2 {
if statusCode >= 400 && statusCode <= 505 {
// 4xx and 5xx indicate that the operation has error occurred
var respBody []byte
respBody, err := readResponseBody(resp)
if err != nil {
return nil, err
}

if len(respBody) == 0 {
err = ServiceError{
StatusCode: statusCode,
RequestID: resp.Header.Get(HTTPHeaderOssRequestID),
if len(respBody) == 0 {
err = ServiceError{
StatusCode: statusCode,
RequestID: resp.Header.Get(HTTPHeaderOssRequestID),
}
} else {
// Response contains storage service error object, unmarshal
srvErr, errIn := serviceErrFromXML(respBody, resp.StatusCode,
resp.Header.Get(HTTPHeaderOssRequestID))
if errIn != nil { // error unmarshaling the error response
err = fmt.Errorf("oss: service returned invalid response body, status = %s, RequestId = %s", resp.Status, resp.Header.Get(HTTPHeaderOssRequestID))
} else {
err = srvErr
}
}

return &Response{
StatusCode: resp.StatusCode,
Headers: resp.Header,
Body: ioutil.NopCloser(bytes.NewReader(respBody)), // restore the body
}, err
} else if statusCode >= 300 && statusCode <= 307 {
// OSS use 3xx, but response has no body
err := fmt.Errorf("oss: service returned %d,%s", resp.StatusCode, resp.Status)
return &Response{
StatusCode: resp.StatusCode,
Headers: resp.Header,
Body: resp.Body,
}, err
} else {
// Response contains storage service error object, unmarshal
srvErr, errIn := serviceErrFromXML(respBody, resp.StatusCode,
resp.Header.Get(HTTPHeaderOssRequestID))
if errIn != nil { // error unmarshaling the error response
err = fmt.Errorf("oss: service returned invalid response body, status = %s, RequestId = %s", resp.Status, resp.Header.Get(HTTPHeaderOssRequestID))
// (0,300) [308,400) [506,)
// Other extended http StatusCode
var respBody []byte
respBody, err := readResponseBody(resp)
if err != nil {
return &Response{StatusCode: resp.StatusCode, Headers: resp.Header, Body: ioutil.NopCloser(bytes.NewReader(respBody))}, err
}

if len(respBody) == 0 {
err = ServiceError{
StatusCode: statusCode,
RequestID: resp.Header.Get(HTTPHeaderOssRequestID),
}
} else {
err = srvErr
// Response contains storage service error object, unmarshal
srvErr, errIn := serviceErrFromXML(respBody, resp.StatusCode,
resp.Header.Get(HTTPHeaderOssRequestID))
if errIn != nil { // error unmarshaling the error response
err = fmt.Errorf("unkown response body, status = %s, RequestId = %s", resp.Status, resp.Header.Get(HTTPHeaderOssRequestID))
} else {
err = srvErr
}
}

return &Response{
StatusCode: resp.StatusCode,
Headers: resp.Header,
Body: ioutil.NopCloser(bytes.NewReader(respBody)), // restore the body
}, err
}
} else {
if conn.config.IsEnableCRC && crc != nil {
cliCRC = crc.Sum64()
}
srvCRC, _ = strconv.ParseUint(resp.Header.Get(HTTPHeaderOssCRC64), 10, 64)

realBody := resp.Body
if conn.isDownloadLimitResponse(resp) {
limitReader := &LimitSpeedReader{
reader: realBody,
ossLimiter: conn.config.DownloadLimiter,
}
realBody = limitReader
}

// 2xx, successful
return &Response{
StatusCode: resp.StatusCode,
Headers: resp.Header,
Body: ioutil.NopCloser(bytes.NewReader(respBody)), // restore the body
}, err
} else if statusCode >= 300 && statusCode <= 307 {
// OSS use 3xx, but response has no body
err := fmt.Errorf("oss: service returned %d,%s", resp.StatusCode, resp.Status)
return &Response{
StatusCode: resp.StatusCode,
Headers: resp.Header,
Body: resp.Body,
}, err
Body: realBody,
ClientCRC: cliCRC,
ServerCRC: srvCRC,
}, nil
}

if conn.config.IsEnableCRC && crc != nil {
cliCRC = crc.Sum64()
}
srvCRC, _ = strconv.ParseUint(resp.Header.Get(HTTPHeaderOssCRC64), 10, 64)

realBody := resp.Body
if conn.isDownloadLimitResponse(resp) {
limitReader := &LimitSpeedReader{
reader: realBody,
ossLimiter: conn.config.DownloadLimiter,
}
realBody = limitReader
}

// 2xx, successful
return &Response{
StatusCode: resp.StatusCode,
Headers: resp.Header,
Body: realBody,
ClientCRC: cliCRC,
ServerCRC: srvCRC,
}, nil
}

// isUploadLimitReq: judge limit upload speed or not
Expand All @@ -540,7 +572,7 @@ func (conn Conn) isDownloadLimitResponse(resp *http.Response) bool {
return false
}

if strings.EqualFold(resp.Request.Method,"GET") {
if strings.EqualFold(resp.Request.Method, "GET") {
return true
}
return false
Expand Down
2 changes: 1 addition & 1 deletion oss/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ const (

NullVersion = "null"

Version = "v2.2.0" // Go SDK version
Version = "v2.2.1" // Go SDK version
)

// FrameType
Expand Down
Loading

0 comments on commit 44431f5

Please sign in to comment.