mirror of https://github.com/minio/minio.git
use new xxml for XML responses to support rare control characters (#15511)
use new xxml/XML responses to support rare control characters fixes #15023
This commit is contained in:
parent
a67116b5bc
commit
8902561f3c
|
@ -120,7 +120,7 @@ function start_minio_16drive() {
|
||||||
cat "${WORK_DIR}/server1.log"
|
cat "${WORK_DIR}/server1.log"
|
||||||
echo "FAILED"
|
echo "FAILED"
|
||||||
mkdir -p inspects
|
mkdir -p inspects
|
||||||
(cd inspects; "${WORK_DIR}/mc" admin inspect minio/healing-shard-bucket/unaligned/**)
|
(cd inspects; "${WORK_DIR}/mc" support inspect minio/healing-shard-bucket/unaligned/**)
|
||||||
|
|
||||||
"${WORK_DIR}/mc" mb play/inspects
|
"${WORK_DIR}/mc" mb play/inspects
|
||||||
"${WORK_DIR}/mc" mirror inspects play/inspects
|
"${WORK_DIR}/mc" mirror inspects play/inspects
|
||||||
|
@ -140,7 +140,7 @@ function start_minio_16drive() {
|
||||||
cat "${WORK_DIR}/server1.log"
|
cat "${WORK_DIR}/server1.log"
|
||||||
echo "FAILED"
|
echo "FAILED"
|
||||||
mkdir -p inspects
|
mkdir -p inspects
|
||||||
(cd inspects; "${WORK_DIR}/mc" admin inspect minio/healing-shard-bucket/unaligned/**)
|
(cd inspects; "${WORK_DIR}/mc" support inspect minio/healing-shard-bucket/unaligned/**)
|
||||||
|
|
||||||
"${WORK_DIR}/mc" mb play/inspects
|
"${WORK_DIR}/mc" mb play/inspects
|
||||||
"${WORK_DIR}/mc" mirror inspects play/inspects
|
"${WORK_DIR}/mc" mirror inspects play/inspects
|
||||||
|
|
|
@ -20,7 +20,6 @@ package cmd
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/xml"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -30,6 +29,8 @@ import (
|
||||||
|
|
||||||
"github.com/minio/minio/internal/crypto"
|
"github.com/minio/minio/internal/crypto"
|
||||||
xhttp "github.com/minio/minio/internal/http"
|
xhttp "github.com/minio/minio/internal/http"
|
||||||
|
"github.com/minio/minio/internal/logger"
|
||||||
|
xxml "github.com/minio/xxml"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Returns a hexadecimal representation of time at the
|
// Returns a hexadecimal representation of time at the
|
||||||
|
@ -64,9 +65,13 @@ func setCommonHeaders(w http.ResponseWriter) {
|
||||||
// Encodes the response headers into XML format.
|
// Encodes the response headers into XML format.
|
||||||
func encodeResponse(response interface{}) []byte {
|
func encodeResponse(response interface{}) []byte {
|
||||||
var bytesBuffer bytes.Buffer
|
var bytesBuffer bytes.Buffer
|
||||||
bytesBuffer.WriteString(xml.Header)
|
bytesBuffer.WriteString(xxml.Header)
|
||||||
e := xml.NewEncoder(&bytesBuffer)
|
buf, err := xxml.Marshal(response)
|
||||||
e.Encode(response)
|
if err != nil {
|
||||||
|
logger.LogIf(GlobalContext, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
bytesBuffer.Write(buf)
|
||||||
return bytesBuffer.Bytes()
|
return bytesBuffer.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,8 @@ type ListVersionsResponse struct {
|
||||||
IsTruncated bool
|
IsTruncated bool
|
||||||
|
|
||||||
CommonPrefixes []CommonPrefix
|
CommonPrefixes []CommonPrefix
|
||||||
Versions []ObjectVersion
|
DeleteMarkers []DeleteMarkerVersion `xml:"DeleteMarker,omitempty"`
|
||||||
|
Versions []ObjectVersion `xml:"Version,omitempty"`
|
||||||
|
|
||||||
// Encoding type used to encode object keys in the response.
|
// Encoding type used to encode object keys in the response.
|
||||||
EncodingType string `xml:"EncodingType,omitempty"`
|
EncodingType string `xml:"EncodingType,omitempty"`
|
||||||
|
@ -247,50 +248,80 @@ type ObjectVersion struct {
|
||||||
Object
|
Object
|
||||||
IsLatest bool
|
IsLatest bool
|
||||||
VersionID string `xml:"VersionId"`
|
VersionID string `xml:"VersionId"`
|
||||||
|
|
||||||
isDeleteMarker bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalXML - marshal ObjectVersion
|
// DeleteMarkerVersion container for delete marker metadata
|
||||||
func (o ObjectVersion) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
type DeleteMarkerVersion struct {
|
||||||
if o.isDeleteMarker {
|
Key string
|
||||||
start.Name.Local = "DeleteMarker"
|
LastModified string // time string of format "2006-01-02T15:04:05.000Z"
|
||||||
} else {
|
|
||||||
start.Name.Local = "Version"
|
// Owner of the object.
|
||||||
|
Owner Owner
|
||||||
|
|
||||||
|
IsLatest bool
|
||||||
|
VersionID string `xml:"VersionId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metadata metadata items implemented to ensure XML marshaling works.
|
||||||
|
type Metadata struct {
|
||||||
|
Items []struct {
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
}
|
}
|
||||||
|
|
||||||
type objectVersionWrapper ObjectVersion
|
|
||||||
return e.EncodeElement(objectVersionWrapper(o), start)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StringMap is a map[string]string
|
// Set add items, duplicate items get replaced.
|
||||||
type StringMap map[string]string
|
func (s *Metadata) Set(k, v string) {
|
||||||
|
for i, item := range s.Items {
|
||||||
|
if item.Key == k {
|
||||||
|
s.Items[i] = struct {
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
}{
|
||||||
|
Key: k,
|
||||||
|
Value: v,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.Items = append(s.Items, struct {
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
}{
|
||||||
|
Key: k,
|
||||||
|
Value: v,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type xmlKeyEntry struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
Value string `xml:",chardata"`
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalXML - StringMap marshals into XML.
|
// MarshalXML - StringMap marshals into XML.
|
||||||
func (s StringMap) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
func (s *Metadata) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||||
tokens := []xml.Token{start}
|
if s == nil {
|
||||||
|
return nil
|
||||||
for key, value := range s {
|
|
||||||
t := xml.StartElement{}
|
|
||||||
t.Name = xml.Name{
|
|
||||||
Space: "",
|
|
||||||
Local: key,
|
|
||||||
}
|
|
||||||
tokens = append(tokens, t, xml.CharData(value), xml.EndElement{Name: t.Name})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens = append(tokens, xml.EndElement{
|
if len(s.Items) == 0 {
|
||||||
Name: start.Name,
|
return nil
|
||||||
})
|
}
|
||||||
|
|
||||||
for _, t := range tokens {
|
if err := e.EncodeToken(start); err != nil {
|
||||||
if err := e.EncodeToken(t); err != nil {
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range s.Items {
|
||||||
|
if err := e.Encode(xmlKeyEntry{
|
||||||
|
XMLName: xml.Name{Local: item.Key},
|
||||||
|
Value: item.Value,
|
||||||
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// flush to ensure tokens are written
|
return e.EncodeToken(start.End())
|
||||||
return e.Flush()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Object container for object metadata
|
// Object container for object metadata
|
||||||
|
@ -307,7 +338,7 @@ type Object struct {
|
||||||
StorageClass string
|
StorageClass string
|
||||||
|
|
||||||
// UserMetadata user-defined metadata
|
// UserMetadata user-defined metadata
|
||||||
UserMetadata StringMap `xml:"UserMetadata,omitempty"`
|
UserMetadata *Metadata `xml:"UserMetadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CopyObjectResponse container returns ETag and LastModified of the successfully copied object
|
// CopyObjectResponse container returns ETag and LastModified of the successfully copied object
|
||||||
|
@ -438,6 +469,8 @@ func generateListBucketsResponse(buckets []BucketInfo) ListBucketsResponse {
|
||||||
// generates an ListBucketVersions response for the said bucket with other enumerated options.
|
// generates an ListBucketVersions response for the said bucket with other enumerated options.
|
||||||
func generateListVersionsResponse(bucket, prefix, marker, versionIDMarker, delimiter, encodingType string, maxKeys int, resp ListObjectVersionsInfo) ListVersionsResponse {
|
func generateListVersionsResponse(bucket, prefix, marker, versionIDMarker, delimiter, encodingType string, maxKeys int, resp ListObjectVersionsInfo) ListVersionsResponse {
|
||||||
versions := make([]ObjectVersion, 0, len(resp.Objects))
|
versions := make([]ObjectVersion, 0, len(resp.Objects))
|
||||||
|
deleteMarkers := make([]DeleteMarkerVersion, 0, len(resp.Objects))
|
||||||
|
|
||||||
owner := Owner{
|
owner := Owner{
|
||||||
ID: globalMinioDefaultOwnerID,
|
ID: globalMinioDefaultOwnerID,
|
||||||
DisplayName: "minio",
|
DisplayName: "minio",
|
||||||
|
@ -445,10 +478,25 @@ func generateListVersionsResponse(bucket, prefix, marker, versionIDMarker, delim
|
||||||
data := ListVersionsResponse{}
|
data := ListVersionsResponse{}
|
||||||
|
|
||||||
for _, object := range resp.Objects {
|
for _, object := range resp.Objects {
|
||||||
content := ObjectVersion{}
|
|
||||||
if object.Name == "" {
|
if object.Name == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if object.DeleteMarker {
|
||||||
|
deleteMarker := DeleteMarkerVersion{
|
||||||
|
Key: s3EncodeName(object.Name, encodingType),
|
||||||
|
LastModified: object.ModTime.UTC().Format(iso8601TimeFormat),
|
||||||
|
Owner: owner,
|
||||||
|
VersionID: object.VersionID,
|
||||||
|
}
|
||||||
|
if deleteMarker.VersionID == "" {
|
||||||
|
deleteMarker.VersionID = nullVersionID
|
||||||
|
}
|
||||||
|
deleteMarker.IsLatest = object.IsLatest
|
||||||
|
deleteMarkers = append(deleteMarkers, deleteMarker)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
content := ObjectVersion{}
|
||||||
content.Key = s3EncodeName(object.Name, encodingType)
|
content.Key = s3EncodeName(object.Name, encodingType)
|
||||||
content.LastModified = object.ModTime.UTC().Format(iso8601TimeFormat)
|
content.LastModified = object.ModTime.UTC().Format(iso8601TimeFormat)
|
||||||
if object.ETag != "" {
|
if object.ETag != "" {
|
||||||
|
@ -466,12 +514,12 @@ func generateListVersionsResponse(bucket, prefix, marker, versionIDMarker, delim
|
||||||
content.VersionID = nullVersionID
|
content.VersionID = nullVersionID
|
||||||
}
|
}
|
||||||
content.IsLatest = object.IsLatest
|
content.IsLatest = object.IsLatest
|
||||||
content.isDeleteMarker = object.DeleteMarker
|
|
||||||
versions = append(versions, content)
|
versions = append(versions, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
data.Name = bucket
|
data.Name = bucket
|
||||||
data.Versions = versions
|
data.Versions = versions
|
||||||
|
data.DeleteMarkers = deleteMarkers
|
||||||
data.EncodingType = encodingType
|
data.EncodingType = encodingType
|
||||||
data.Prefix = s3EncodeName(prefix, encodingType)
|
data.Prefix = s3EncodeName(prefix, encodingType)
|
||||||
data.KeyMarker = s3EncodeName(marker, encodingType)
|
data.KeyMarker = s3EncodeName(marker, encodingType)
|
||||||
|
@ -569,14 +617,14 @@ func generateListObjectsV2Response(bucket, prefix, token, nextToken, startAfter,
|
||||||
}
|
}
|
||||||
content.Owner = owner
|
content.Owner = owner
|
||||||
if metadata {
|
if metadata {
|
||||||
content.UserMetadata = make(StringMap)
|
content.UserMetadata = &Metadata{}
|
||||||
switch kind, _ := crypto.IsEncrypted(object.UserDefined); kind {
|
switch kind, _ := crypto.IsEncrypted(object.UserDefined); kind {
|
||||||
case crypto.S3:
|
case crypto.S3:
|
||||||
content.UserMetadata[xhttp.AmzServerSideEncryption] = xhttp.AmzEncryptionAES
|
content.UserMetadata.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionAES)
|
||||||
case crypto.S3KMS:
|
case crypto.S3KMS:
|
||||||
content.UserMetadata[xhttp.AmzServerSideEncryption] = xhttp.AmzEncryptionKMS
|
content.UserMetadata.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionKMS)
|
||||||
case crypto.SSEC:
|
case crypto.SSEC:
|
||||||
content.UserMetadata[xhttp.AmzServerSideEncryptionCustomerAlgorithm] = xhttp.AmzEncryptionAES
|
content.UserMetadata.Set(xhttp.AmzServerSideEncryptionCustomerAlgorithm, xhttp.AmzEncryptionAES)
|
||||||
}
|
}
|
||||||
for k, v := range CleanMinioInternalMetadataKeys(object.UserDefined) {
|
for k, v := range CleanMinioInternalMetadataKeys(object.UserDefined) {
|
||||||
if strings.HasPrefix(strings.ToLower(k), ReservedMetadataPrefixLower) {
|
if strings.HasPrefix(strings.ToLower(k), ReservedMetadataPrefixLower) {
|
||||||
|
@ -588,7 +636,7 @@ func generateListObjectsV2Response(bucket, prefix, token, nextToken, startAfter,
|
||||||
if equals(k, xhttp.AmzMetaUnencryptedContentLength, xhttp.AmzMetaUnencryptedContentMD5) {
|
if equals(k, xhttp.AmzMetaUnencryptedContentLength, xhttp.AmzMetaUnencryptedContentMD5) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
content.UserMetadata[k] = v
|
content.UserMetadata.Set(k, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
contents = append(contents, content)
|
contents = append(contents, content)
|
||||||
|
|
|
@ -20,6 +20,7 @@ package cmd
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"encoding/xml"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -3066,6 +3067,16 @@ func (api objectAPIHandlers) GetObjectRetentionHandler(w http.ResponseWriter, r
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ObjectTagSet key value tags
|
||||||
|
type ObjectTagSet struct {
|
||||||
|
Tags []tags.Tag `xml:"Tag"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type objectTagging struct {
|
||||||
|
XMLName xml.Name `xml:"Tagging"`
|
||||||
|
TagSet *ObjectTagSet `xml:"TagSet"`
|
||||||
|
}
|
||||||
|
|
||||||
// GetObjectTaggingHandler - GET object tagging
|
// GetObjectTaggingHandler - GET object tagging
|
||||||
func (api objectAPIHandlers) GetObjectTaggingHandler(w http.ResponseWriter, r *http.Request) {
|
func (api objectAPIHandlers) GetObjectTaggingHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "GetObjectTagging")
|
ctx := newContext(r, w, "GetObjectTagging")
|
||||||
|
@ -3103,7 +3114,7 @@ func (api objectAPIHandlers) GetObjectTaggingHandler(w http.ResponseWriter, r *h
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get object tags
|
// Get object tags
|
||||||
tags, err := objAPI.GetObjectTags(ctx, bucket, object, opts)
|
ot, err := objAPI.GetObjectTags(ctx, bucket, object, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL)
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL)
|
||||||
return
|
return
|
||||||
|
@ -3113,7 +3124,20 @@ func (api objectAPIHandlers) GetObjectTaggingHandler(w http.ResponseWriter, r *h
|
||||||
w.Header()[xhttp.AmzVersionID] = []string{opts.VersionID}
|
w.Header()[xhttp.AmzVersionID] = []string{opts.VersionID}
|
||||||
}
|
}
|
||||||
|
|
||||||
writeSuccessResponseXML(w, encodeResponse(tags))
|
otags := &objectTagging{
|
||||||
|
TagSet: &ObjectTagSet{},
|
||||||
|
}
|
||||||
|
|
||||||
|
var list []tags.Tag
|
||||||
|
for k, v := range ot.ToMap() {
|
||||||
|
list = append(list, tags.Tag{
|
||||||
|
Key: k,
|
||||||
|
Value: v,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
otags.TagSet.Tags = list
|
||||||
|
|
||||||
|
writeSuccessResponseXML(w, encodeResponse(otags))
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutObjectTaggingHandler - PUT object tagging
|
// PutObjectTaggingHandler - PUT object tagging
|
||||||
|
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -1636,6 +1637,81 @@ func (s *TestSuiteCommon) TestListObjectsHandler(c *check) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestListObjectsSpecialCharactersHandler - Setting valid parameters to List Objects
|
||||||
|
// and then asserting the response with the expected one.
|
||||||
|
func (s *TestSuiteCommon) TestListObjectsSpecialCharactersHandler(c *check) {
|
||||||
|
if runtime.GOOS == globalWindowsOSName {
|
||||||
|
c.Skip("skip special character test for windows")
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate a random bucket name.
|
||||||
|
bucketName := getRandomBucketName()
|
||||||
|
// HTTP request to create the bucket.
|
||||||
|
request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
|
||||||
|
0, nil, s.accessKey, s.secretKey, s.signer)
|
||||||
|
c.Assert(err, nil)
|
||||||
|
|
||||||
|
// execute the HTTP request to create bucket.
|
||||||
|
response, err := s.client.Do(request)
|
||||||
|
c.Assert(err, nil)
|
||||||
|
c.Assert(response.StatusCode, http.StatusOK)
|
||||||
|
|
||||||
|
for _, objectName := range []string{"foo bar 1", "foo bar 2", "foo \x01 bar"} {
|
||||||
|
buffer := bytes.NewReader([]byte("Hello World"))
|
||||||
|
request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
|
||||||
|
int64(buffer.Len()), buffer, s.accessKey, s.secretKey, s.signer)
|
||||||
|
c.Assert(err, nil)
|
||||||
|
|
||||||
|
response, err = s.client.Do(request)
|
||||||
|
c.Assert(err, nil)
|
||||||
|
c.Assert(response.StatusCode, http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
getURL string
|
||||||
|
expectedStrings []string
|
||||||
|
}{
|
||||||
|
{getListObjectsV1URL(s.endPoint, bucketName, "", "1000", ""), []string{"<Key>foo bar 1</Key>", "<Key>foo bar 2</Key>", "<Key>foo  bar</Key>"}},
|
||||||
|
{getListObjectsV1URL(s.endPoint, bucketName, "", "1000", "url"), []string{"<Key>foo+bar+1</Key>", "<Key>foo+bar+2</Key>", "<Key>foo+%01+bar</Key>"}},
|
||||||
|
{
|
||||||
|
getListObjectsV2URL(s.endPoint, bucketName, "", "1000", "", ""),
|
||||||
|
[]string{
|
||||||
|
"<Key>foo bar 1</Key>",
|
||||||
|
"<Key>foo bar 2</Key>",
|
||||||
|
"<Key>foo  bar</Key>",
|
||||||
|
fmt.Sprintf("<Owner><ID>%s</ID><DisplayName>minio</DisplayName></Owner>", globalMinioDefaultOwnerID),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
getListObjectsV2URL(s.endPoint, bucketName, "", "1000", "true", ""),
|
||||||
|
[]string{
|
||||||
|
"<Key>foo bar 1</Key>",
|
||||||
|
"<Key>foo bar 2</Key>",
|
||||||
|
"<Key>foo  bar</Key>",
|
||||||
|
fmt.Sprintf("<Owner><ID>%s</ID><DisplayName>minio</DisplayName></Owner>", globalMinioDefaultOwnerID),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{getListObjectsV2URL(s.endPoint, bucketName, "", "1000", "", "url"), []string{"<Key>foo+bar+1</Key>", "<Key>foo+bar+2</Key>", "<Key>foo+%01+bar</Key>"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
// create listObjectsV1 request with valid parameters
|
||||||
|
request, err = newTestSignedRequest(http.MethodGet, testCase.getURL, 0, nil, s.accessKey, s.secretKey, s.signer)
|
||||||
|
c.Assert(err, nil)
|
||||||
|
// execute the HTTP request.
|
||||||
|
response, err = s.client.Do(request)
|
||||||
|
c.Assert(err, nil)
|
||||||
|
c.Assert(response.StatusCode, http.StatusOK)
|
||||||
|
|
||||||
|
getContent, err := ioutil.ReadAll(response.Body)
|
||||||
|
c.Assert(err, nil)
|
||||||
|
|
||||||
|
for _, expectedStr := range testCase.expectedStrings {
|
||||||
|
c.Assert(strings.Contains(string(getContent), expectedStr), true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestListObjectsHandlerErrors - Setting invalid parameters to List Objects
|
// TestListObjectsHandlerErrors - Setting invalid parameters to List Objects
|
||||||
// and then asserting the error response with the expected one.
|
// and then asserting the error response with the expected one.
|
||||||
func (s *TestSuiteCommon) TestListObjectsHandlerErrors(c *check) {
|
func (s *TestSuiteCommon) TestListObjectsHandlerErrors(c *check) {
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -55,6 +55,7 @@ require (
|
||||||
github.com/minio/sha256-simd v1.0.0
|
github.com/minio/sha256-simd v1.0.0
|
||||||
github.com/minio/simdjson-go v0.4.2
|
github.com/minio/simdjson-go v0.4.2
|
||||||
github.com/minio/sio v0.3.0
|
github.com/minio/sio v0.3.0
|
||||||
|
github.com/minio/xxml v0.0.3
|
||||||
github.com/minio/zipindex v0.2.1
|
github.com/minio/zipindex v0.2.1
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/nats-io/nats-server/v2 v2.7.4
|
github.com/nats-io/nats-server/v2 v2.7.4
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -645,6 +645,8 @@ github.com/minio/simdjson-go v0.4.2 h1:+5rVznvslY/oLIGOO0M7y2g0D8DnFbFZyF2Nr+KT5
|
||||||
github.com/minio/simdjson-go v0.4.2/go.mod h1:w6ptSSCcUPtqAOOdDVywJkX+8CyYzCdjrTCir0l6BVg=
|
github.com/minio/simdjson-go v0.4.2/go.mod h1:w6ptSSCcUPtqAOOdDVywJkX+8CyYzCdjrTCir0l6BVg=
|
||||||
github.com/minio/sio v0.3.0 h1:syEFBewzOMOYVzSTFpp1MqpSZk8rUNbz8VIIc+PNzus=
|
github.com/minio/sio v0.3.0 h1:syEFBewzOMOYVzSTFpp1MqpSZk8rUNbz8VIIc+PNzus=
|
||||||
github.com/minio/sio v0.3.0/go.mod h1:8b0yPp2avGThviy/+OCJBI6OMpvxoUuiLvE6F1lebhw=
|
github.com/minio/sio v0.3.0/go.mod h1:8b0yPp2avGThviy/+OCJBI6OMpvxoUuiLvE6F1lebhw=
|
||||||
|
github.com/minio/xxml v0.0.3 h1:ZIpPQpfyG5uZQnqqC0LZuWtPk/WT8G/qkxvO6jb7zMU=
|
||||||
|
github.com/minio/xxml v0.0.3/go.mod h1:wcXErosl6IezQIMEWSK/LYC2VS7LJ1dAkgvuyIN3aH4=
|
||||||
github.com/minio/zipindex v0.2.1 h1:A37vDQJ7Uyp4RHpQEEpintgiIxg0t3npH2CWjLT//u4=
|
github.com/minio/zipindex v0.2.1 h1:A37vDQJ7Uyp4RHpQEEpintgiIxg0t3npH2CWjLT//u4=
|
||||||
github.com/minio/zipindex v0.2.1/go.mod h1:s+b/Qyw9JtSEnYfaM4ASOWNO2xGnXCfzQ+SWAzVkVZc=
|
github.com/minio/zipindex v0.2.1/go.mod h1:s+b/Qyw9JtSEnYfaM4ASOWNO2xGnXCfzQ+SWAzVkVZc=
|
||||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||||
|
|
Loading…
Reference in New Issue