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