LEFT | RIGHT |
1 // Copyright 2010 The Go Authors. All rights reserved. | 1 // Copyright 2010 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package multipart | 5 package multipart |
6 | 6 |
7 import ( | 7 import ( |
8 "bytes" | 8 "bytes" |
9 "encoding/json" | 9 "encoding/json" |
10 "fmt" | 10 "fmt" |
11 "io" | 11 "io" |
12 "io/ioutil" | 12 "io/ioutil" |
13 "net/textproto" | 13 "net/textproto" |
14 "os" | 14 "os" |
15 "reflect" | 15 "reflect" |
16 "strings" | 16 "strings" |
17 "testing" | 17 "testing" |
18 ) | 18 ) |
19 | |
20 func TestHorizontalWhitespace(t *testing.T) { | |
21 if !onlyHorizontalWhitespace([]byte(" \t")) { | |
22 t.Error("expected pass") | |
23 } | |
24 if onlyHorizontalWhitespace([]byte("foo bar")) { | |
25 t.Error("expected failure") | |
26 } | |
27 } | |
28 | 19 |
29 func TestBoundaryLine(t *testing.T) { | 20 func TestBoundaryLine(t *testing.T) { |
30 mr := NewReader(strings.NewReader(""), "myBoundary") | 21 mr := NewReader(strings.NewReader(""), "myBoundary") |
31 if !mr.isBoundaryDelimiterLine([]byte("--myBoundary\r\n")) { | 22 if !mr.isBoundaryDelimiterLine([]byte("--myBoundary\r\n")) { |
32 t.Error("expected") | 23 t.Error("expected") |
33 } | 24 } |
34 if !mr.isBoundaryDelimiterLine([]byte("--myBoundary \r\n")) { | 25 if !mr.isBoundaryDelimiterLine([]byte("--myBoundary \r\n")) { |
35 t.Error("expected") | 26 t.Error("expected") |
36 } | 27 } |
37 if !mr.isBoundaryDelimiterLine([]byte("--myBoundary \n")) { | 28 if !mr.isBoundaryDelimiterLine([]byte("--myBoundary \n")) { |
(...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
490 // Final part empty with newlines after final separator. | 481 // Final part empty with newlines after final separator. |
491 { | 482 { |
492 name: "final part empty then crlf", | 483 name: "final part empty then crlf", |
493 sep: "abc", | 484 sep: "abc", |
494 in: "--abc\r\nFoo: bar\r\n\r\n--abc--\r\n", | 485 in: "--abc\r\nFoo: bar\r\n\r\n--abc--\r\n", |
495 want: []headerBody{ | 486 want: []headerBody{ |
496 {textproto.MIMEHeader{"Foo": {"bar"}}, ""}, | 487 {textproto.MIMEHeader{"Foo": {"bar"}}, ""}, |
497 }, | 488 }, |
498 }, | 489 }, |
499 | 490 |
| 491 // Final part empty with lwsp-chars after final separator. |
| 492 { |
| 493 name: "final part empty then lwsp", |
| 494 sep: "abc", |
| 495 in: "--abc\r\nFoo: bar\r\n\r\n--abc-- \t", |
| 496 want: []headerBody{ |
| 497 {textproto.MIMEHeader{"Foo": {"bar"}}, ""}, |
| 498 }, |
| 499 }, |
| 500 |
500 // No parts (empty form as submitted by Chrome) | 501 // No parts (empty form as submitted by Chrome) |
501 { | 502 { |
502 name: "no parts", | 503 name: "no parts", |
503 sep: "----WebKitFormBoundaryQfEAfzFOiSemeHfA", | 504 sep: "----WebKitFormBoundaryQfEAfzFOiSemeHfA", |
504 in: "------WebKitFormBoundaryQfEAfzFOiSemeHfA--\r\n", | 505 in: "------WebKitFormBoundaryQfEAfzFOiSemeHfA--\r\n", |
505 want: []headerBody{}, | 506 want: []headerBody{}, |
506 }, | 507 }, |
507 | 508 |
508 // Part containing data starting with the boundary, but with additional
suffix. | 509 // Part containing data starting with the boundary, but with additional
suffix. |
509 { | 510 { |
510 name: "fake separator as data", | 511 name: "fake separator as data", |
511 sep: "sep", | 512 sep: "sep", |
512 in: "--sep\r\nFoo: bar\r\n\r\n--sepFAKE\r\n--sep--", | 513 in: "--sep\r\nFoo: bar\r\n\r\n--sepFAKE\r\n--sep--", |
513 want: []headerBody{ | 514 want: []headerBody{ |
514 {textproto.MIMEHeader{"Foo": {"bar"}}, "--sepFAKE"}, | 515 {textproto.MIMEHeader{"Foo": {"bar"}}, "--sepFAKE"}, |
| 516 }, |
| 517 }, |
| 518 |
| 519 // Part containing a boundary with whitespace following it. |
| 520 { |
| 521 name: "boundary with whitespace", |
| 522 sep: "sep", |
| 523 in: "--sep \r\nFoo: bar\r\n\r\ntext\r\n--sep--", |
| 524 want: []headerBody{ |
| 525 {textproto.MIMEHeader{"Foo": {"bar"}}, "text"}, |
515 }, | 526 }, |
516 }, | 527 }, |
517 | 528 |
518 // With ignored leading line. | 529 // With ignored leading line. |
519 { | 530 { |
520 name: "leading line", | 531 name: "leading line", |
521 sep: "MyBoundary", | 532 sep: "MyBoundary", |
522 in: strings.Replace(`This is a multi-part message. This line is
ignored. | 533 in: strings.Replace(`This is a multi-part message. This line is
ignored. |
523 --MyBoundary | 534 --MyBoundary |
524 foo: bar | 535 foo: bar |
525 | 536 |
526 | 537 |
527 --MyBoundary--`, "\n", "\r\n", -1), | 538 --MyBoundary--`, "\n", "\r\n", -1), |
528 want: []headerBody{ | 539 want: []headerBody{ |
529 {textproto.MIMEHeader{"Foo": {"bar"}}, ""}, | 540 {textproto.MIMEHeader{"Foo": {"bar"}}, ""}, |
530 }, | 541 }, |
531 }, | 542 }, |
532 | 543 |
533 roundTripParseTest(), | 544 roundTripParseTest(), |
534 } | 545 } |
535 | 546 |
536 func TestParse(t *testing.T) { | 547 func TestParse(t *testing.T) { |
| 548 Cases: |
537 for _, tt := range parseTests { | 549 for _, tt := range parseTests { |
538 r := NewReader(strings.NewReader(tt.in), tt.sep) | 550 r := NewReader(strings.NewReader(tt.in), tt.sep) |
539 got := []headerBody{} | 551 got := []headerBody{} |
540 for { | 552 for { |
541 p, err := r.NextPart() | 553 p, err := r.NextPart() |
542 if err == io.EOF { | 554 if err == io.EOF { |
543 break | 555 break |
544 } | 556 } |
545 if err != nil { | 557 if err != nil { |
546 » » » » t.Fatalf("in test %q, NextPart: %v", tt.name, er
r) | 558 » » » » t.Errorf("in test %q, NextPart: %v", tt.name, er
r) |
| 559 » » » » continue Cases |
547 } | 560 } |
548 pbody, err := ioutil.ReadAll(p) | 561 pbody, err := ioutil.ReadAll(p) |
549 if err != nil { | 562 if err != nil { |
550 » » » » t.Fatalf("in test %q, error reading part: %v", t
t.name, err) | 563 » » » » t.Errorf("in test %q, error reading part: %v", t
t.name, err) |
| 564 » » » » continue Cases |
551 } | 565 } |
552 got = append(got, headerBody{p.Header, string(pbody)}) | 566 got = append(got, headerBody{p.Header, string(pbody)}) |
553 } | 567 } |
554 if !reflect.DeepEqual(tt.want, got) { | 568 if !reflect.DeepEqual(tt.want, got) { |
555 t.Errorf("test %q:\n got: %v\nwant: %v", tt.name, got, t
t.want) | 569 t.Errorf("test %q:\n got: %v\nwant: %v", tt.name, got, t
t.want) |
556 if len(tt.want) != len(got) { | 570 if len(tt.want) != len(got) { |
557 t.Errorf("test %q: got %d parts, want %d", tt.na
me, len(got), len(tt.want)) | 571 t.Errorf("test %q: got %d parts, want %d", tt.na
me, len(got), len(tt.want)) |
558 » » » } else { | 572 » » » } else if len(got) > 1 { |
559 for pi, wantPart := range tt.want { | 573 for pi, wantPart := range tt.want { |
560 if !reflect.DeepEqual(wantPart, got[pi])
{ | 574 if !reflect.DeepEqual(wantPart, got[pi])
{ |
561 t.Errorf("test %q, part %d:\n go
t: %v\nwant: %v", tt.name, pi, got[pi], wantPart) | 575 t.Errorf("test %q, part %d:\n go
t: %v\nwant: %v", tt.name, pi, got[pi], wantPart) |
562 } | 576 } |
563 } | 577 } |
564 } | 578 } |
565 } | 579 } |
566 } | 580 } |
567 } | 581 } |
568 | 582 |
(...skipping 18 matching lines...) Expand all Loading... |
587 _, err = pw.Write([]byte(p.body)) | 601 _, err = pw.Write([]byte(p.body)) |
588 if err != nil { | 602 if err != nil { |
589 panic(err) | 603 panic(err) |
590 } | 604 } |
591 } | 605 } |
592 w.Close() | 606 w.Close() |
593 t.in = buf.String() | 607 t.in = buf.String() |
594 t.sep = w.Boundary() | 608 t.sep = w.Boundary() |
595 return t | 609 return t |
596 } | 610 } |
LEFT | RIGHT |