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

  1. package s3api
  2. import (
  3. "fmt"
  4. "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
  5. "net/http"
  6. "reflect"
  7. "sort"
  8. "strings"
  9. "testing"
  10. )
  11. type H map[string]string
  12. func (h H) String() string {
  13. pairs := make([]string, 0, len(h))
  14. for k, v := range h {
  15. pairs = append(pairs, fmt.Sprintf("%s : %s", k, v))
  16. }
  17. sort.Strings(pairs)
  18. join := strings.Join(pairs, "\n")
  19. return "\n" + join + "\n"
  20. }
  21. var processMetadataTestCases = []struct {
  22. caseId int
  23. request H
  24. existing H
  25. getTags H
  26. want H
  27. }{
  28. {
  29. 201,
  30. H{
  31. "User-Agent": "firefox",
  32. "X-Amz-Meta-My-Meta": "request",
  33. "X-Amz-Tagging": "A=B&a=b&type=request",
  34. },
  35. H{
  36. "X-Amz-Meta-My-Meta": "existing",
  37. "X-Amz-Tagging-A": "B",
  38. "X-Amz-Tagging-Type": "existing",
  39. },
  40. H{
  41. "A": "B",
  42. "a": "b",
  43. "type": "existing",
  44. },
  45. H{
  46. "User-Agent": "firefox",
  47. "X-Amz-Meta-My-Meta": "existing",
  48. "X-Amz-Tagging": "A=B&a=b&type=existing",
  49. },
  50. },
  51. {
  52. 202,
  53. H{
  54. "User-Agent": "firefox",
  55. "X-Amz-Meta-My-Meta": "request",
  56. "X-Amz-Tagging": "A=B&a=b&type=request",
  57. s3_constants.AmzUserMetaDirective: DirectiveReplace,
  58. },
  59. H{
  60. "X-Amz-Meta-My-Meta": "existing",
  61. "X-Amz-Tagging-A": "B",
  62. "X-Amz-Tagging-Type": "existing",
  63. },
  64. H{
  65. "A": "B",
  66. "a": "b",
  67. "type": "existing",
  68. },
  69. H{
  70. "User-Agent": "firefox",
  71. "X-Amz-Meta-My-Meta": "request",
  72. "X-Amz-Tagging": "A=B&a=b&type=existing",
  73. s3_constants.AmzUserMetaDirective: DirectiveReplace,
  74. },
  75. },
  76. {
  77. 203,
  78. H{
  79. "User-Agent": "firefox",
  80. "X-Amz-Meta-My-Meta": "request",
  81. "X-Amz-Tagging": "A=B&a=b&type=request",
  82. s3_constants.AmzObjectTaggingDirective: DirectiveReplace,
  83. },
  84. H{
  85. "X-Amz-Meta-My-Meta": "existing",
  86. "X-Amz-Tagging-A": "B",
  87. "X-Amz-Tagging-Type": "existing",
  88. },
  89. H{
  90. "A": "B",
  91. "a": "b",
  92. "type": "existing",
  93. },
  94. H{
  95. "User-Agent": "firefox",
  96. "X-Amz-Meta-My-Meta": "existing",
  97. "X-Amz-Tagging": "A=B&a=b&type=request",
  98. s3_constants.AmzObjectTaggingDirective: DirectiveReplace,
  99. },
  100. },
  101. {
  102. 204,
  103. H{
  104. "User-Agent": "firefox",
  105. "X-Amz-Meta-My-Meta": "request",
  106. "X-Amz-Tagging": "A=B&a=b&type=request",
  107. s3_constants.AmzUserMetaDirective: DirectiveReplace,
  108. s3_constants.AmzObjectTaggingDirective: DirectiveReplace,
  109. },
  110. H{
  111. "X-Amz-Meta-My-Meta": "existing",
  112. "X-Amz-Tagging-A": "B",
  113. "X-Amz-Tagging-a": "b",
  114. "X-Amz-Tagging-Type": "existing",
  115. },
  116. H{
  117. "A": "B",
  118. "a": "b",
  119. "type": "existing",
  120. },
  121. H{
  122. "User-Agent": "firefox",
  123. "X-Amz-Meta-My-Meta": "request",
  124. "X-Amz-Tagging": "A=B&a=b&type=request",
  125. s3_constants.AmzUserMetaDirective: DirectiveReplace,
  126. s3_constants.AmzObjectTaggingDirective: DirectiveReplace,
  127. },
  128. },
  129. {
  130. 205,
  131. H{
  132. "User-Agent": "firefox",
  133. "X-Amz-Meta-My-Meta": "request",
  134. "X-Amz-Tagging": "A=B&a=b&type=request",
  135. s3_constants.AmzUserMetaDirective: DirectiveReplace,
  136. s3_constants.AmzObjectTaggingDirective: DirectiveReplace,
  137. },
  138. H{},
  139. H{},
  140. H{
  141. "User-Agent": "firefox",
  142. "X-Amz-Meta-My-Meta": "request",
  143. "X-Amz-Tagging": "A=B&a=b&type=request",
  144. s3_constants.AmzUserMetaDirective: DirectiveReplace,
  145. s3_constants.AmzObjectTaggingDirective: DirectiveReplace,
  146. },
  147. },
  148. {
  149. 206,
  150. H{
  151. "User-Agent": "firefox",
  152. s3_constants.AmzUserMetaDirective: DirectiveReplace,
  153. s3_constants.AmzObjectTaggingDirective: DirectiveReplace,
  154. },
  155. H{
  156. "X-Amz-Meta-My-Meta": "existing",
  157. "X-Amz-Tagging-A": "B",
  158. "X-Amz-Tagging-a": "b",
  159. "X-Amz-Tagging-Type": "existing",
  160. },
  161. H{
  162. "A": "B",
  163. "a": "b",
  164. "type": "existing",
  165. },
  166. H{
  167. "User-Agent": "firefox",
  168. s3_constants.AmzUserMetaDirective: DirectiveReplace,
  169. s3_constants.AmzObjectTaggingDirective: DirectiveReplace,
  170. },
  171. },
  172. {
  173. 207,
  174. H{
  175. "User-Agent": "firefox",
  176. "X-Amz-Meta-My-Meta": "request",
  177. s3_constants.AmzUserMetaDirective: DirectiveReplace,
  178. s3_constants.AmzObjectTaggingDirective: DirectiveReplace,
  179. },
  180. H{
  181. "X-Amz-Meta-My-Meta": "existing",
  182. "X-Amz-Tagging-A": "B",
  183. "X-Amz-Tagging-a": "b",
  184. "X-Amz-Tagging-Type": "existing",
  185. },
  186. H{
  187. "A": "B",
  188. "a": "b",
  189. "type": "existing",
  190. },
  191. H{
  192. "User-Agent": "firefox",
  193. "X-Amz-Meta-My-Meta": "request",
  194. s3_constants.AmzUserMetaDirective: DirectiveReplace,
  195. s3_constants.AmzObjectTaggingDirective: DirectiveReplace,
  196. },
  197. },
  198. }
  199. var processMetadataBytesTestCases = []struct {
  200. caseId int
  201. request H
  202. existing H
  203. want H
  204. }{
  205. {
  206. 101,
  207. H{
  208. "User-Agent": "firefox",
  209. "X-Amz-Meta-My-Meta": "request",
  210. "X-Amz-Tagging": "A=B&a=b&type=request",
  211. },
  212. H{
  213. "X-Amz-Meta-My-Meta": "existing",
  214. "X-Amz-Tagging-A": "B",
  215. "X-Amz-Tagging-a": "b",
  216. "X-Amz-Tagging-type": "existing",
  217. },
  218. H{
  219. "X-Amz-Meta-My-Meta": "existing",
  220. "X-Amz-Tagging-A": "B",
  221. "X-Amz-Tagging-a": "b",
  222. "X-Amz-Tagging-type": "existing",
  223. },
  224. },
  225. {
  226. 102,
  227. H{
  228. "User-Agent": "firefox",
  229. "X-Amz-Meta-My-Meta": "request",
  230. "X-Amz-Tagging": "A=B&a=b&type=request",
  231. s3_constants.AmzUserMetaDirective: DirectiveReplace,
  232. },
  233. H{
  234. "X-Amz-Meta-My-Meta": "existing",
  235. "X-Amz-Tagging-A": "B",
  236. "X-Amz-Tagging-a": "b",
  237. "X-Amz-Tagging-type": "existing",
  238. },
  239. H{
  240. "X-Amz-Meta-My-Meta": "request",
  241. "X-Amz-Tagging-A": "B",
  242. "X-Amz-Tagging-a": "b",
  243. "X-Amz-Tagging-type": "existing",
  244. },
  245. },
  246. {
  247. 103,
  248. H{
  249. "User-Agent": "firefox",
  250. "X-Amz-Meta-My-Meta": "request",
  251. "X-Amz-Tagging": "A=B&a=b&type=request",
  252. s3_constants.AmzObjectTaggingDirective: DirectiveReplace,
  253. },
  254. H{
  255. "X-Amz-Meta-My-Meta": "existing",
  256. "X-Amz-Tagging-A": "B",
  257. "X-Amz-Tagging-a": "b",
  258. "X-Amz-Tagging-type": "existing",
  259. },
  260. H{
  261. "X-Amz-Meta-My-Meta": "existing",
  262. "X-Amz-Tagging-A": "B",
  263. "X-Amz-Tagging-a": "b",
  264. "X-Amz-Tagging-type": "request",
  265. },
  266. },
  267. {
  268. 104,
  269. H{
  270. "User-Agent": "firefox",
  271. "X-Amz-Meta-My-Meta": "request",
  272. "X-Amz-Tagging": "A=B&a=b&type=request",
  273. s3_constants.AmzUserMetaDirective: DirectiveReplace,
  274. s3_constants.AmzObjectTaggingDirective: DirectiveReplace,
  275. },
  276. H{
  277. "X-Amz-Meta-My-Meta": "existing",
  278. "X-Amz-Tagging-A": "B",
  279. "X-Amz-Tagging-a": "b",
  280. "X-Amz-Tagging-type": "existing",
  281. },
  282. H{
  283. "X-Amz-Meta-My-Meta": "request",
  284. "X-Amz-Tagging-A": "B",
  285. "X-Amz-Tagging-a": "b",
  286. "X-Amz-Tagging-type": "request",
  287. },
  288. },
  289. {
  290. 105,
  291. H{
  292. "User-Agent": "firefox",
  293. s3_constants.AmzUserMetaDirective: DirectiveReplace,
  294. s3_constants.AmzObjectTaggingDirective: DirectiveReplace,
  295. },
  296. H{
  297. "X-Amz-Meta-My-Meta": "existing",
  298. "X-Amz-Tagging-A": "B",
  299. "X-Amz-Tagging-a": "b",
  300. "X-Amz-Tagging-type": "existing",
  301. },
  302. H{},
  303. },
  304. {
  305. 107,
  306. H{
  307. "User-Agent": "firefox",
  308. "X-Amz-Meta-My-Meta": "request",
  309. "X-Amz-Tagging": "A=B&a=b&type=request",
  310. s3_constants.AmzUserMetaDirective: DirectiveReplace,
  311. s3_constants.AmzObjectTaggingDirective: DirectiveReplace,
  312. },
  313. H{},
  314. H{
  315. "X-Amz-Meta-My-Meta": "request",
  316. "X-Amz-Tagging-A": "B",
  317. "X-Amz-Tagging-a": "b",
  318. "X-Amz-Tagging-type": "request",
  319. },
  320. },
  321. {
  322. 108,
  323. H{
  324. "User-Agent": "firefox",
  325. "X-Amz-Meta-My-Meta": "request",
  326. "X-Amz-Tagging": "A=B&a=b&type=request*",
  327. s3_constants.AmzUserMetaDirective: DirectiveReplace,
  328. s3_constants.AmzObjectTaggingDirective: DirectiveReplace,
  329. },
  330. H{},
  331. H{},
  332. },
  333. }
  334. func TestProcessMetadata(t *testing.T) {
  335. for _, tc := range processMetadataTestCases {
  336. reqHeader := transferHToHeader(tc.request)
  337. existing := transferHToHeader(tc.existing)
  338. replaceMeta, replaceTagging := replaceDirective(reqHeader)
  339. err := processMetadata(reqHeader, existing, replaceMeta, replaceTagging, func(_ string, _ string) (tags map[string]string, err error) {
  340. return tc.getTags, nil
  341. }, "", "")
  342. if err != nil {
  343. t.Error(err)
  344. }
  345. result := transferHeaderToH(reqHeader)
  346. fmtTagging(result, tc.want)
  347. if !reflect.DeepEqual(result, tc.want) {
  348. t.Error(fmt.Errorf("\n### CaseID: %d ###"+
  349. "\nRequest:%v"+
  350. "\nExisting:%v"+
  351. "\nGetTags:%v"+
  352. "\nWant:%v"+
  353. "\nActual:%v",
  354. tc.caseId, tc.request, tc.existing, tc.getTags, tc.want, result))
  355. }
  356. }
  357. }
  358. func TestProcessMetadataBytes(t *testing.T) {
  359. for _, tc := range processMetadataBytesTestCases {
  360. reqHeader := transferHToHeader(tc.request)
  361. existing := transferHToBytesArr(tc.existing)
  362. replaceMeta, replaceTagging := replaceDirective(reqHeader)
  363. extends, _ := processMetadataBytes(reqHeader, existing, replaceMeta, replaceTagging)
  364. result := transferBytesArrToH(extends)
  365. fmtTagging(result, tc.want)
  366. if !reflect.DeepEqual(result, tc.want) {
  367. t.Error(fmt.Errorf("\n### CaseID: %d ###"+
  368. "\nRequest:%v"+
  369. "\nExisting:%v"+
  370. "\nWant:%v"+
  371. "\nActual:%v",
  372. tc.caseId, tc.request, tc.existing, tc.want, result))
  373. }
  374. }
  375. }
  376. func fmtTagging(maps ...map[string]string) {
  377. for _, m := range maps {
  378. if tagging := m[s3_constants.AmzObjectTagging]; len(tagging) > 0 {
  379. split := strings.Split(tagging, "&")
  380. sort.Strings(split)
  381. m[s3_constants.AmzObjectTagging] = strings.Join(split, "&")
  382. }
  383. }
  384. }
  385. func transferHToHeader(data map[string]string) http.Header {
  386. header := http.Header{}
  387. for k, v := range data {
  388. header.Add(k, v)
  389. }
  390. return header
  391. }
  392. func transferHToBytesArr(data map[string]string) map[string][]byte {
  393. m := make(map[string][]byte, len(data))
  394. for k, v := range data {
  395. m[k] = []byte(v)
  396. }
  397. return m
  398. }
  399. func transferBytesArrToH(data map[string][]byte) H {
  400. m := make(map[string]string, len(data))
  401. for k, v := range data {
  402. m[k] = string(v)
  403. }
  404. return m
  405. }
  406. func transferHeaderToH(data map[string][]string) H {
  407. m := make(map[string]string, len(data))
  408. for k, v := range data {
  409. m[k] = v[len(v)-1]
  410. }
  411. return m
  412. }