You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							438 lines
						
					
					
						
							11 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							438 lines
						
					
					
						
							11 KiB
						
					
					
				| package s3api | |
| 
 | |
| import ( | |
| 	"fmt" | |
| 	"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants" | |
| 	"net/http" | |
| 	"reflect" | |
| 	"sort" | |
| 	"strings" | |
| 	"testing" | |
| ) | |
| 
 | |
| type H map[string]string | |
| 
 | |
| func (h H) String() string { | |
| 	pairs := make([]string, 0, len(h)) | |
| 	for k, v := range h { | |
| 		pairs = append(pairs, fmt.Sprintf("%s : %s", k, v)) | |
| 	} | |
| 	sort.Strings(pairs) | |
| 	join := strings.Join(pairs, "\n") | |
| 	return "\n" + join + "\n" | |
| } | |
| 
 | |
| var processMetadataTestCases = []struct { | |
| 	caseId   int | |
| 	request  H | |
| 	existing H | |
| 	getTags  H | |
| 	want     H | |
| }{ | |
| 	{ | |
| 		201, | |
| 		H{ | |
| 			"User-Agent":         "firefox", | |
| 			"X-Amz-Meta-My-Meta": "request", | |
| 			"X-Amz-Tagging":      "A=B&a=b&type=request", | |
| 		}, | |
| 		H{ | |
| 			"X-Amz-Meta-My-Meta": "existing", | |
| 			"X-Amz-Tagging-A":    "B", | |
| 			"X-Amz-Tagging-Type": "existing", | |
| 		}, | |
| 		H{ | |
| 			"A":    "B", | |
| 			"a":    "b", | |
| 			"type": "existing", | |
| 		}, | |
| 		H{ | |
| 			"User-Agent":         "firefox", | |
| 			"X-Amz-Meta-My-Meta": "existing", | |
| 			"X-Amz-Tagging":      "A=B&a=b&type=existing", | |
| 		}, | |
| 	}, | |
| 	{ | |
| 		202, | |
| 		H{ | |
| 			"User-Agent":                      "firefox", | |
| 			"X-Amz-Meta-My-Meta":              "request", | |
| 			"X-Amz-Tagging":                   "A=B&a=b&type=request", | |
| 			s3_constants.AmzUserMetaDirective: DirectiveReplace, | |
| 		}, | |
| 		H{ | |
| 			"X-Amz-Meta-My-Meta": "existing", | |
| 			"X-Amz-Tagging-A":    "B", | |
| 			"X-Amz-Tagging-Type": "existing", | |
| 		}, | |
| 		H{ | |
| 			"A":    "B", | |
| 			"a":    "b", | |
| 			"type": "existing", | |
| 		}, | |
| 		H{ | |
| 			"User-Agent":                      "firefox", | |
| 			"X-Amz-Meta-My-Meta":              "request", | |
| 			"X-Amz-Tagging":                   "A=B&a=b&type=existing", | |
| 			s3_constants.AmzUserMetaDirective: DirectiveReplace, | |
| 		}, | |
| 	}, | |
| 
 | |
| 	{ | |
| 		203, | |
| 		H{ | |
| 			"User-Agent":                           "firefox", | |
| 			"X-Amz-Meta-My-Meta":                   "request", | |
| 			"X-Amz-Tagging":                        "A=B&a=b&type=request", | |
| 			s3_constants.AmzObjectTaggingDirective: DirectiveReplace, | |
| 		}, | |
| 		H{ | |
| 			"X-Amz-Meta-My-Meta": "existing", | |
| 			"X-Amz-Tagging-A":    "B", | |
| 			"X-Amz-Tagging-Type": "existing", | |
| 		}, | |
| 		H{ | |
| 			"A":    "B", | |
| 			"a":    "b", | |
| 			"type": "existing", | |
| 		}, | |
| 		H{ | |
| 			"User-Agent":                           "firefox", | |
| 			"X-Amz-Meta-My-Meta":                   "existing", | |
| 			"X-Amz-Tagging":                        "A=B&a=b&type=request", | |
| 			s3_constants.AmzObjectTaggingDirective: DirectiveReplace, | |
| 		}, | |
| 	}, | |
| 
 | |
| 	{ | |
| 		204, | |
| 		H{ | |
| 			"User-Agent":                           "firefox", | |
| 			"X-Amz-Meta-My-Meta":                   "request", | |
| 			"X-Amz-Tagging":                        "A=B&a=b&type=request", | |
| 			s3_constants.AmzUserMetaDirective:      DirectiveReplace, | |
| 			s3_constants.AmzObjectTaggingDirective: DirectiveReplace, | |
| 		}, | |
| 		H{ | |
| 			"X-Amz-Meta-My-Meta": "existing", | |
| 			"X-Amz-Tagging-A":    "B", | |
| 			"X-Amz-Tagging-a":    "b", | |
| 			"X-Amz-Tagging-Type": "existing", | |
| 		}, | |
| 		H{ | |
| 			"A":    "B", | |
| 			"a":    "b", | |
| 			"type": "existing", | |
| 		}, | |
| 		H{ | |
| 			"User-Agent":                           "firefox", | |
| 			"X-Amz-Meta-My-Meta":                   "request", | |
| 			"X-Amz-Tagging":                        "A=B&a=b&type=request", | |
| 			s3_constants.AmzUserMetaDirective:      DirectiveReplace, | |
| 			s3_constants.AmzObjectTaggingDirective: DirectiveReplace, | |
| 		}, | |
| 	}, | |
| 
 | |
| 	{ | |
| 		205, | |
| 		H{ | |
| 			"User-Agent":                           "firefox", | |
| 			"X-Amz-Meta-My-Meta":                   "request", | |
| 			"X-Amz-Tagging":                        "A=B&a=b&type=request", | |
| 			s3_constants.AmzUserMetaDirective:      DirectiveReplace, | |
| 			s3_constants.AmzObjectTaggingDirective: DirectiveReplace, | |
| 		}, | |
| 		H{}, | |
| 		H{}, | |
| 		H{ | |
| 			"User-Agent":                           "firefox", | |
| 			"X-Amz-Meta-My-Meta":                   "request", | |
| 			"X-Amz-Tagging":                        "A=B&a=b&type=request", | |
| 			s3_constants.AmzUserMetaDirective:      DirectiveReplace, | |
| 			s3_constants.AmzObjectTaggingDirective: DirectiveReplace, | |
| 		}, | |
| 	}, | |
| 
 | |
| 	{ | |
| 		206, | |
| 		H{ | |
| 			"User-Agent":                           "firefox", | |
| 			s3_constants.AmzUserMetaDirective:      DirectiveReplace, | |
| 			s3_constants.AmzObjectTaggingDirective: DirectiveReplace, | |
| 		}, | |
| 		H{ | |
| 			"X-Amz-Meta-My-Meta": "existing", | |
| 			"X-Amz-Tagging-A":    "B", | |
| 			"X-Amz-Tagging-a":    "b", | |
| 			"X-Amz-Tagging-Type": "existing", | |
| 		}, | |
| 		H{ | |
| 			"A":    "B", | |
| 			"a":    "b", | |
| 			"type": "existing", | |
| 		}, | |
| 		H{ | |
| 			"User-Agent":                           "firefox", | |
| 			s3_constants.AmzUserMetaDirective:      DirectiveReplace, | |
| 			s3_constants.AmzObjectTaggingDirective: DirectiveReplace, | |
| 		}, | |
| 	}, | |
| 
 | |
| 	{ | |
| 		207, | |
| 		H{ | |
| 			"User-Agent":                           "firefox", | |
| 			"X-Amz-Meta-My-Meta":                   "request", | |
| 			s3_constants.AmzUserMetaDirective:      DirectiveReplace, | |
| 			s3_constants.AmzObjectTaggingDirective: DirectiveReplace, | |
| 		}, | |
| 		H{ | |
| 			"X-Amz-Meta-My-Meta": "existing", | |
| 			"X-Amz-Tagging-A":    "B", | |
| 			"X-Amz-Tagging-a":    "b", | |
| 			"X-Amz-Tagging-Type": "existing", | |
| 		}, | |
| 		H{ | |
| 			"A":    "B", | |
| 			"a":    "b", | |
| 			"type": "existing", | |
| 		}, | |
| 		H{ | |
| 			"User-Agent":                           "firefox", | |
| 			"X-Amz-Meta-My-Meta":                   "request", | |
| 			s3_constants.AmzUserMetaDirective:      DirectiveReplace, | |
| 			s3_constants.AmzObjectTaggingDirective: DirectiveReplace, | |
| 		}, | |
| 	}, | |
| } | |
| var processMetadataBytesTestCases = []struct { | |
| 	caseId   int | |
| 	request  H | |
| 	existing H | |
| 	want     H | |
| }{ | |
| 	{ | |
| 		101, | |
| 		H{ | |
| 			"User-Agent":         "firefox", | |
| 			"X-Amz-Meta-My-Meta": "request", | |
| 			"X-Amz-Tagging":      "A=B&a=b&type=request", | |
| 		}, | |
| 		H{ | |
| 			"X-Amz-Meta-My-Meta": "existing", | |
| 			"X-Amz-Tagging-A":    "B", | |
| 			"X-Amz-Tagging-a":    "b", | |
| 			"X-Amz-Tagging-type": "existing", | |
| 		}, | |
| 		H{ | |
| 			"X-Amz-Meta-My-Meta": "existing", | |
| 			"X-Amz-Tagging-A":    "B", | |
| 			"X-Amz-Tagging-a":    "b", | |
| 			"X-Amz-Tagging-type": "existing", | |
| 		}, | |
| 	}, | |
| 
 | |
| 	{ | |
| 		102, | |
| 		H{ | |
| 			"User-Agent":                      "firefox", | |
| 			"X-Amz-Meta-My-Meta":              "request", | |
| 			"X-Amz-Tagging":                   "A=B&a=b&type=request", | |
| 			s3_constants.AmzUserMetaDirective: DirectiveReplace, | |
| 		}, | |
| 		H{ | |
| 			"X-Amz-Meta-My-Meta": "existing", | |
| 			"X-Amz-Tagging-A":    "B", | |
| 			"X-Amz-Tagging-a":    "b", | |
| 			"X-Amz-Tagging-type": "existing", | |
| 		}, | |
| 		H{ | |
| 			"X-Amz-Meta-My-Meta": "request", | |
| 			"X-Amz-Tagging-A":    "B", | |
| 			"X-Amz-Tagging-a":    "b", | |
| 			"X-Amz-Tagging-type": "existing", | |
| 		}, | |
| 	}, | |
| 
 | |
| 	{ | |
| 		103, | |
| 		H{ | |
| 			"User-Agent":                           "firefox", | |
| 			"X-Amz-Meta-My-Meta":                   "request", | |
| 			"X-Amz-Tagging":                        "A=B&a=b&type=request", | |
| 			s3_constants.AmzObjectTaggingDirective: DirectiveReplace, | |
| 		}, | |
| 		H{ | |
| 			"X-Amz-Meta-My-Meta": "existing", | |
| 			"X-Amz-Tagging-A":    "B", | |
| 			"X-Amz-Tagging-a":    "b", | |
| 			"X-Amz-Tagging-type": "existing", | |
| 		}, | |
| 		H{ | |
| 			"X-Amz-Meta-My-Meta": "existing", | |
| 			"X-Amz-Tagging-A":    "B", | |
| 			"X-Amz-Tagging-a":    "b", | |
| 			"X-Amz-Tagging-type": "request", | |
| 		}, | |
| 	}, | |
| 
 | |
| 	{ | |
| 		104, | |
| 		H{ | |
| 			"User-Agent":                           "firefox", | |
| 			"X-Amz-Meta-My-Meta":                   "request", | |
| 			"X-Amz-Tagging":                        "A=B&a=b&type=request", | |
| 			s3_constants.AmzUserMetaDirective:      DirectiveReplace, | |
| 			s3_constants.AmzObjectTaggingDirective: DirectiveReplace, | |
| 		}, | |
| 		H{ | |
| 			"X-Amz-Meta-My-Meta": "existing", | |
| 			"X-Amz-Tagging-A":    "B", | |
| 			"X-Amz-Tagging-a":    "b", | |
| 			"X-Amz-Tagging-type": "existing", | |
| 		}, | |
| 		H{ | |
| 			"X-Amz-Meta-My-Meta": "request", | |
| 			"X-Amz-Tagging-A":    "B", | |
| 			"X-Amz-Tagging-a":    "b", | |
| 			"X-Amz-Tagging-type": "request", | |
| 		}, | |
| 	}, | |
| 
 | |
| 	{ | |
| 		105, | |
| 		H{ | |
| 			"User-Agent":                           "firefox", | |
| 			s3_constants.AmzUserMetaDirective:      DirectiveReplace, | |
| 			s3_constants.AmzObjectTaggingDirective: DirectiveReplace, | |
| 		}, | |
| 		H{ | |
| 			"X-Amz-Meta-My-Meta": "existing", | |
| 			"X-Amz-Tagging-A":    "B", | |
| 			"X-Amz-Tagging-a":    "b", | |
| 			"X-Amz-Tagging-type": "existing", | |
| 		}, | |
| 		H{}, | |
| 	}, | |
| 
 | |
| 	{ | |
| 		107, | |
| 		H{ | |
| 			"User-Agent":                           "firefox", | |
| 			"X-Amz-Meta-My-Meta":                   "request", | |
| 			"X-Amz-Tagging":                        "A=B&a=b&type=request", | |
| 			s3_constants.AmzUserMetaDirective:      DirectiveReplace, | |
| 			s3_constants.AmzObjectTaggingDirective: DirectiveReplace, | |
| 		}, | |
| 		H{}, | |
| 		H{ | |
| 			"X-Amz-Meta-My-Meta": "request", | |
| 			"X-Amz-Tagging-A":    "B", | |
| 			"X-Amz-Tagging-a":    "b", | |
| 			"X-Amz-Tagging-type": "request", | |
| 		}, | |
| 	}, | |
| 
 | |
| 	{ | |
| 		108, | |
| 		H{ | |
| 			"User-Agent":                           "firefox", | |
| 			"X-Amz-Meta-My-Meta":                   "request", | |
| 			"X-Amz-Tagging":                        "A=B&a=b&type=request*", | |
| 			s3_constants.AmzUserMetaDirective:      DirectiveReplace, | |
| 			s3_constants.AmzObjectTaggingDirective: DirectiveReplace, | |
| 		}, | |
| 		H{}, | |
| 		H{}, | |
| 	}, | |
| } | |
| 
 | |
| func TestProcessMetadata(t *testing.T) { | |
| 	for _, tc := range processMetadataTestCases { | |
| 		reqHeader := transferHToHeader(tc.request) | |
| 		existing := transferHToHeader(tc.existing) | |
| 		replaceMeta, replaceTagging := replaceDirective(reqHeader) | |
| 		err := processMetadata(reqHeader, existing, replaceMeta, replaceTagging, func(_ string, _ string) (tags map[string]string, err error) { | |
| 			return tc.getTags, nil | |
| 		}, "", "") | |
| 		if err != nil { | |
| 			t.Error(err) | |
| 		} | |
| 
 | |
| 		result := transferHeaderToH(reqHeader) | |
| 		fmtTagging(result, tc.want) | |
| 
 | |
| 		if !reflect.DeepEqual(result, tc.want) { | |
| 			t.Error(fmt.Errorf("\n### CaseID: %d ###"+ | |
| 				"\nRequest:%v"+ | |
| 				"\nExisting:%v"+ | |
| 				"\nGetTags:%v"+ | |
| 				"\nWant:%v"+ | |
| 				"\nActual:%v", | |
| 				tc.caseId, tc.request, tc.existing, tc.getTags, tc.want, result)) | |
| 		} | |
| 	} | |
| } | |
| 
 | |
| func TestProcessMetadataBytes(t *testing.T) { | |
| 	for _, tc := range processMetadataBytesTestCases { | |
| 		reqHeader := transferHToHeader(tc.request) | |
| 		existing := transferHToBytesArr(tc.existing) | |
| 		replaceMeta, replaceTagging := replaceDirective(reqHeader) | |
| 		extends, _ := processMetadataBytes(reqHeader, existing, replaceMeta, replaceTagging) | |
| 
 | |
| 		result := transferBytesArrToH(extends) | |
| 		fmtTagging(result, tc.want) | |
| 
 | |
| 		if !reflect.DeepEqual(result, tc.want) { | |
| 			t.Error(fmt.Errorf("\n### CaseID: %d ###"+ | |
| 				"\nRequest:%v"+ | |
| 				"\nExisting:%v"+ | |
| 				"\nWant:%v"+ | |
| 				"\nActual:%v", | |
| 				tc.caseId, tc.request, tc.existing, tc.want, result)) | |
| 		} | |
| 	} | |
| } | |
| 
 | |
| func fmtTagging(maps ...map[string]string) { | |
| 	for _, m := range maps { | |
| 		if tagging := m[s3_constants.AmzObjectTagging]; len(tagging) > 0 { | |
| 			split := strings.Split(tagging, "&") | |
| 			sort.Strings(split) | |
| 			m[s3_constants.AmzObjectTagging] = strings.Join(split, "&") | |
| 		} | |
| 	} | |
| } | |
| 
 | |
| func transferHToHeader(data map[string]string) http.Header { | |
| 	header := http.Header{} | |
| 	for k, v := range data { | |
| 		header.Add(k, v) | |
| 	} | |
| 	return header | |
| } | |
| 
 | |
| func transferHToBytesArr(data map[string]string) map[string][]byte { | |
| 	m := make(map[string][]byte, len(data)) | |
| 	for k, v := range data { | |
| 		m[k] = []byte(v) | |
| 	} | |
| 	return m | |
| } | |
| 
 | |
| func transferBytesArrToH(data map[string][]byte) H { | |
| 	m := make(map[string]string, len(data)) | |
| 	for k, v := range data { | |
| 		m[k] = string(v) | |
| 	} | |
| 	return m | |
| } | |
| 
 | |
| func transferHeaderToH(data map[string][]string) H { | |
| 	m := make(map[string]string, len(data)) | |
| 	for k, v := range data { | |
| 		m[k] = v[len(v)-1] | |
| 	} | |
| 	return m | |
| }
 |