1
2
3
4
5 package textproto
6
7 import (
8 "bufio"
9 "bytes"
10 "io"
11 "io/ioutil"
12 "strconv"
13 "strings"
14 )
15
16
17
18 type Reader struct {
19 R *bufio.Reader
20 dot *dotReader
21 buf []byte
22 }
23
24
25
26
27
28
29 func NewReader(r *bufio.Reader) *Reader {
30 return &Reader{R: r}
31 }
32
33
34
35 func (r *Reader) ReadLine() (string, error) {
36 line, err := r.readLineSlice()
37 return string(line), err
38 }
39
40
41 func (r *Reader) ReadLineBytes() ([]byte, error) {
42 line, err := r.readLineSlice()
43 if line != nil {
44 buf := make([]byte, len(line))
45 copy(buf, line)
46 line = buf
47 }
48 return line, err
49 }
50
51 func (r *Reader) readLineSlice() ([]byte, error) {
52 r.closeDot()
53 var line []byte
54 for {
55 l, more, err := r.R.ReadLine()
56 if err != nil {
57 return nil, err
58 }
59
60 if line == nil && !more {
61 return l, nil
62 }
63 line = append(line, l...)
64 if !more {
65 break
66 }
67 }
68 return line, nil
69 }
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 func (r *Reader) ReadContinuedLine() (string, error) {
91 line, err := r.readContinuedLineSlice()
92 return string(line), err
93 }
94
95
96
97 func trim(s []byte) []byte {
98 i := 0
99 for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
100 i++
101 }
102 n := len(s)
103 for n > i && (s[n-1] == ' ' || s[n-1] == '\t') {
104 n--
105 }
106 return s[i:n]
107 }
108
109
110
111 func (r *Reader) ReadContinuedLineBytes() ([]byte, error) {
112 line, err := r.readContinuedLineSlice()
113 if line != nil {
114 buf := make([]byte, len(line))
115 copy(buf, line)
116 line = buf
117 }
118 return line, err
119 }
120
121 func (r *Reader) readContinuedLineSlice() ([]byte, error) {
122
123 line, err := r.readLineSlice()
124 if err != nil {
125 return nil, err
126 }
127 if len(line) == 0 {
128 return line, nil
129 }
130
131
132
133
134
135 if r.R.Buffered() > 1 {
136 peek, err := r.R.Peek(1)
137 if err == nil && isASCIILetter(peek[0]) {
138 return trim(line), nil
139 }
140 }
141
142
143
144 r.buf = append(r.buf[:0], trim(line)...)
145
146
147 for r.skipSpace() > 0 {
148 line, err := r.readLineSlice()
149 if err != nil {
150 break
151 }
152 r.buf = append(r.buf, ' ')
153 r.buf = append(r.buf, trim(line)...)
154 }
155 return r.buf, nil
156 }
157
158
159 func (r *Reader) skipSpace() int {
160 n := 0
161 for {
162 c, err := r.R.ReadByte()
163 if err != nil {
164
165 break
166 }
167 if c != ' ' && c != '\t' {
168 r.R.UnreadByte()
169 break
170 }
171 n++
172 }
173 return n
174 }
175
176 func (r *Reader) readCodeLine(expectCode int) (code int, continued bool, message string, err error) {
177 line, err := r.ReadLine()
178 if err != nil {
179 return
180 }
181 return parseCodeLine(line, expectCode)
182 }
183
184 func parseCodeLine(line string, expectCode int) (code int, continued bool, message string, err error) {
185 if len(line) < 4 || line[3] != ' ' && line[3] != '-' {
186 err = ProtocolError("short response: " + line)
187 return
188 }
189 continued = line[3] == '-'
190 code, err = strconv.Atoi(line[0:3])
191 if err != nil || code < 100 {
192 err = ProtocolError("invalid response code: " + line)
193 return
194 }
195 message = line[4:]
196 if 1 <= expectCode && expectCode < 10 && code/100 != expectCode ||
197 10 <= expectCode && expectCode < 100 && code/10 != expectCode ||
198 100 <= expectCode && expectCode < 1000 && code != expectCode {
199 err = &Error{code, message}
200 }
201 return
202 }
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219 func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err error) {
220 code, continued, message, err := r.readCodeLine(expectCode)
221 if err == nil && continued {
222 err = ProtocolError("unexpected multi-line response: " + message)
223 }
224 return
225 }
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254 func (r *Reader) ReadResponse(expectCode int) (code int, message string, err error) {
255 code, continued, message, err := r.readCodeLine(expectCode)
256 multi := continued
257 for continued {
258 line, err := r.ReadLine()
259 if err != nil {
260 return 0, "", err
261 }
262
263 var code2 int
264 var moreMessage string
265 code2, continued, moreMessage, err = parseCodeLine(line, 0)
266 if err != nil || code2 != code {
267 message += "\n" + strings.TrimRight(line, "\r\n")
268 continued = true
269 continue
270 }
271 message += "\n" + moreMessage
272 }
273 if err != nil && multi && message != "" {
274
275 err = &Error{code, message}
276 }
277 return
278 }
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296 func (r *Reader) DotReader() io.Reader {
297 r.closeDot()
298 r.dot = &dotReader{r: r}
299 return r.dot
300 }
301
302 type dotReader struct {
303 r *Reader
304 state int
305 }
306
307
308 func (d *dotReader) Read(b []byte) (n int, err error) {
309
310
311
312 const (
313 stateBeginLine = iota
314 stateDot
315 stateDotCR
316 stateCR
317 stateData
318 stateEOF
319 )
320 br := d.r.R
321 for n < len(b) && d.state != stateEOF {
322 var c byte
323 c, err = br.ReadByte()
324 if err != nil {
325 if err == io.EOF {
326 err = io.ErrUnexpectedEOF
327 }
328 break
329 }
330 switch d.state {
331 case stateBeginLine:
332 if c == '.' {
333 d.state = stateDot
334 continue
335 }
336 if c == '\r' {
337 d.state = stateCR
338 continue
339 }
340 d.state = stateData
341
342 case stateDot:
343 if c == '\r' {
344 d.state = stateDotCR
345 continue
346 }
347 if c == '\n' {
348 d.state = stateEOF
349 continue
350 }
351 d.state = stateData
352
353 case stateDotCR:
354 if c == '\n' {
355 d.state = stateEOF
356 continue
357 }
358
359
360 br.UnreadByte()
361 c = '\r'
362 d.state = stateData
363
364 case stateCR:
365 if c == '\n' {
366 d.state = stateBeginLine
367 break
368 }
369
370 br.UnreadByte()
371 c = '\r'
372 d.state = stateData
373
374 case stateData:
375 if c == '\r' {
376 d.state = stateCR
377 continue
378 }
379 if c == '\n' {
380 d.state = stateBeginLine
381 }
382 }
383 b[n] = c
384 n++
385 }
386 if err == nil && d.state == stateEOF {
387 err = io.EOF
388 }
389 if err != nil && d.r.dot == d {
390 d.r.dot = nil
391 }
392 return
393 }
394
395
396
397 func (r *Reader) closeDot() {
398 if r.dot == nil {
399 return
400 }
401 buf := make([]byte, 128)
402 for r.dot != nil {
403
404
405 r.dot.Read(buf)
406 }
407 }
408
409
410
411
412 func (r *Reader) ReadDotBytes() ([]byte, error) {
413 return ioutil.ReadAll(r.DotReader())
414 }
415
416
417
418
419
420 func (r *Reader) ReadDotLines() ([]string, error) {
421
422
423
424 var v []string
425 var err error
426 for {
427 var line string
428 line, err = r.ReadLine()
429 if err != nil {
430 if err == io.EOF {
431 err = io.ErrUnexpectedEOF
432 }
433 break
434 }
435
436
437 if len(line) > 0 && line[0] == '.' {
438 if len(line) == 1 {
439 break
440 }
441 line = line[1:]
442 }
443 v = append(v, line)
444 }
445 return v, err
446 }
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468 func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) {
469
470
471
472 var strs []string
473 hint := r.upcomingHeaderNewlines()
474 if hint > 0 {
475 strs = make([]string, hint)
476 }
477
478 m := make(MIMEHeader, hint)
479
480
481 if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') {
482 line, err := r.readLineSlice()
483 if err != nil {
484 return m, err
485 }
486 return m, ProtocolError("malformed MIME header initial line: " + string(line))
487 }
488
489 for {
490 kv, err := r.readContinuedLineSlice()
491 if len(kv) == 0 {
492 return m, err
493 }
494
495
496
497
498 i := bytes.IndexByte(kv, ':')
499 if i < 0 {
500 return m, ProtocolError("malformed MIME header line: " + string(kv))
501 }
502 endKey := i
503 for endKey > 0 && kv[endKey-1] == ' ' {
504 endKey--
505 }
506 key := canonicalMIMEHeaderKey(kv[:endKey])
507
508
509
510
511 if key == "" {
512 continue
513 }
514
515
516 i++
517 for i < len(kv) && (kv[i] == ' ' || kv[i] == '\t') {
518 i++
519 }
520 value := string(kv[i:])
521
522 vv := m[key]
523 if vv == nil && len(strs) > 0 {
524
525
526
527
528 vv, strs = strs[:1:1], strs[1:]
529 vv[0] = value
530 m[key] = vv
531 } else {
532 m[key] = append(vv, value)
533 }
534
535 if err != nil {
536 return m, err
537 }
538 }
539 }
540
541
542
543 func (r *Reader) upcomingHeaderNewlines() (n int) {
544
545 r.R.Peek(1)
546 s := r.R.Buffered()
547 if s == 0 {
548 return
549 }
550 peek, _ := r.R.Peek(s)
551 for len(peek) > 0 {
552 i := bytes.IndexByte(peek, '\n')
553 if i < 3 {
554
555
556 return
557 }
558 n++
559 peek = peek[i+1:]
560 }
561 return
562 }
563
564
565
566
567
568
569
570
571
572 func CanonicalMIMEHeaderKey(s string) string {
573
574 upper := true
575 for i := 0; i < len(s); i++ {
576 c := s[i]
577 if !validHeaderFieldByte(c) {
578 return s
579 }
580 if upper && 'a' <= c && c <= 'z' {
581 return canonicalMIMEHeaderKey([]byte(s))
582 }
583 if !upper && 'A' <= c && c <= 'Z' {
584 return canonicalMIMEHeaderKey([]byte(s))
585 }
586 upper = c == '-'
587 }
588 return s
589 }
590
591 const toLower = 'a' - 'A'
592
593
594
595
596
597
598
599
600 func validHeaderFieldByte(b byte) bool {
601 return int(b) < len(isTokenTable) && isTokenTable[b]
602 }
603
604
605
606
607
608
609
610 func canonicalMIMEHeaderKey(a []byte) string {
611
612 for _, c := range a {
613 if validHeaderFieldByte(c) {
614 continue
615 }
616
617 return string(a)
618 }
619
620 upper := true
621 for i, c := range a {
622
623
624
625
626 if upper && 'a' <= c && c <= 'z' {
627 c -= toLower
628 } else if !upper && 'A' <= c && c <= 'Z' {
629 c += toLower
630 }
631 a[i] = c
632 upper = c == '-'
633 }
634
635
636
637 if v := commonHeader[string(a)]; v != "" {
638 return v
639 }
640 return string(a)
641 }
642
643
644 var commonHeader = make(map[string]string)
645
646 func init() {
647 for _, v := range []string{
648 "Accept",
649 "Accept-Charset",
650 "Accept-Encoding",
651 "Accept-Language",
652 "Accept-Ranges",
653 "Cache-Control",
654 "Cc",
655 "Connection",
656 "Content-Id",
657 "Content-Language",
658 "Content-Length",
659 "Content-Transfer-Encoding",
660 "Content-Type",
661 "Cookie",
662 "Date",
663 "Dkim-Signature",
664 "Etag",
665 "Expires",
666 "From",
667 "Host",
668 "If-Modified-Since",
669 "If-None-Match",
670 "In-Reply-To",
671 "Last-Modified",
672 "Location",
673 "Message-Id",
674 "Mime-Version",
675 "Pragma",
676 "Received",
677 "Return-Path",
678 "Server",
679 "Set-Cookie",
680 "Subject",
681 "To",
682 "User-Agent",
683 "Via",
684 "X-Forwarded-For",
685 "X-Imforwards",
686 "X-Powered-By",
687 } {
688 commonHeader[v] = v
689 }
690 }
691
692
693
694 var isTokenTable = [127]bool{
695 '!': true,
696 '#': true,
697 '$': true,
698 '%': true,
699 '&': true,
700 '\'': true,
701 '*': true,
702 '+': true,
703 '-': true,
704 '.': true,
705 '0': true,
706 '1': true,
707 '2': true,
708 '3': true,
709 '4': true,
710 '5': true,
711 '6': true,
712 '7': true,
713 '8': true,
714 '9': true,
715 'A': true,
716 'B': true,
717 'C': true,
718 'D': true,
719 'E': true,
720 'F': true,
721 'G': true,
722 'H': true,
723 'I': true,
724 'J': true,
725 'K': true,
726 'L': true,
727 'M': true,
728 'N': true,
729 'O': true,
730 'P': true,
731 'Q': true,
732 'R': true,
733 'S': true,
734 'T': true,
735 'U': true,
736 'W': true,
737 'V': true,
738 'X': true,
739 'Y': true,
740 'Z': true,
741 '^': true,
742 '_': true,
743 '`': true,
744 'a': true,
745 'b': true,
746 'c': true,
747 'd': true,
748 'e': true,
749 'f': true,
750 'g': true,
751 'h': true,
752 'i': true,
753 'j': true,
754 'k': true,
755 'l': true,
756 'm': true,
757 'n': true,
758 'o': true,
759 'p': true,
760 'q': true,
761 'r': true,
762 's': true,
763 't': true,
764 'u': true,
765 'v': true,
766 'w': true,
767 'x': true,
768 'y': true,
769 'z': true,
770 '|': true,
771 '~': true,
772 }
773
View as plain text