@@ -540,11 +540,16 @@ func (r *Reader) upcomingHeaderNewlines() (n int) {
540
540
// the rest are converted to lowercase. For example, the
541
541
// canonical key for "accept-encoding" is "Accept-Encoding".
542
542
// MIME header keys are assumed to be ASCII only.
543
+ // If s contains a space or invalid header field bytes, it is
544
+ // returned without modifications.
543
545
func CanonicalMIMEHeaderKey (s string ) string {
544
546
// Quick check for canonical encoding.
545
547
upper := true
546
548
for i := 0 ; i < len (s ); i ++ {
547
549
c := s [i ]
550
+ if ! validHeaderFieldByte (c ) {
551
+ return s
552
+ }
548
553
if upper && 'a' <= c && c <= 'z' {
549
554
return canonicalMIMEHeaderKey ([]byte (s ))
550
555
}
@@ -558,19 +563,44 @@ func CanonicalMIMEHeaderKey(s string) string {
558
563
559
564
const toLower = 'a' - 'A'
560
565
566
+ // validHeaderFieldByte reports whether b is a valid byte in a header
567
+ // field key. This is actually stricter than RFC 7230, which says:
568
+ // tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
569
+ // "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
570
+ // token = 1*tchar
571
+ // TODO: revisit in Go 1.6+ and possibly expand this. But note that many
572
+ // servers have historically dropped '_' to prevent ambiguities when mapping
573
+ // to CGI environment variables.
574
+ func validHeaderFieldByte (b byte ) bool {
575
+ return ('A' <= b && b <= 'Z' ) ||
576
+ ('a' <= b && b <= 'z' ) ||
577
+ ('0' <= b && b <= '9' ) ||
578
+ b == '-'
579
+ }
580
+
561
581
// canonicalMIMEHeaderKey is like CanonicalMIMEHeaderKey but is
562
582
// allowed to mutate the provided byte slice before returning the
563
583
// string.
584
+ //
585
+ // For invalid inputs (if a contains spaces or non-token bytes), a
586
+ // is unchanged and a string copy is returned.
564
587
func canonicalMIMEHeaderKey (a []byte ) string {
588
+ // See if a looks like a header key. If not, return it unchanged.
589
+ for _ , c := range a {
590
+ if validHeaderFieldByte (c ) {
591
+ continue
592
+ }
593
+ // Don't canonicalize.
594
+ return string (a )
595
+ }
596
+
565
597
upper := true
566
598
for i , c := range a {
567
599
// Canonicalize: first letter upper case
568
600
// and upper case after each dash.
569
601
// (Host, User-Agent, If-Modified-Since).
570
602
// MIME headers are ASCII only, so no Unicode issues.
571
- if c == ' ' {
572
- c = '-'
573
- } else if upper && 'a' <= c && c <= 'z' {
603
+ if upper && 'a' <= c && c <= 'z' {
574
604
c -= toLower
575
605
} else if ! upper && 'A' <= c && c <= 'Z' {
576
606
c += toLower
0 commit comments