1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
package digest
import (
"fmt"
"io"
"log"
"strings"
"testing"
)
// Tear apart the Authorization header value.
// PAY ATTENTION: this is large and complicated relative to other ones I've seen
// based on Split() using ',', ' ', and '=' in various orders. It is also probably
// correct even if the realm contains a '=', ' ', or '"' character, or if the
// sender uses HT, CR, or LF in their whitespace.
//
// The map that comes back looks like { "qop": "auth", "ns":"00000001", etc... }
func parseAuthorization(auth *strings.Reader) (map[string]string, error) {
parts := map[string]string{}
skipLWS := func(r *strings.Reader) error {
for {
ch, err := r.ReadByte()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
if ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' {
// its white, we skip it and stay in loop
} else {
if err := r.UnreadByte(); err != nil {
return err
}
break
}
}
return nil
}
readName := func(r *strings.Reader) (string, error) {
name := []byte{}
for {
ch, err := r.ReadByte()
if err == io.EOF {
break
}
if err != nil {
return "", err
}
if (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '-' {
name = append(name, ch)
} else {
if err := r.UnreadByte(); err != nil {
return "", err
}
break
}
}
if len(name) == 0 {
return "", fmt.Errorf("expected name, got didn't get one")
}
return string(name), nil
}
readValue := func(r *strings.Reader) (string, error) {
ch, err := r.ReadByte()
if err != nil {
return "", err
}
if ch == '"' {
v := []byte{}
for {
ch, err := r.ReadByte()
if err != nil {
return "", fmt.Errorf("premature end of value: %s", err.Error())
}
if ch == '\\' {
ch2, err := r.ReadByte()
if err != nil {
return "", fmt.Errorf("premature end of value: %s", err.Error())
}
v = append(v, ch2)
} else if ch == '"' {
break
} else {
v = append(v, ch)
}
}
return string(v), nil
} else {
r.UnreadByte()
return readName(r) // handles unquoted values, like true/false in the "stale" paramter
}
}
for {
name, err := readName(auth)
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
if err := skipLWS(auth); err != nil {
return nil, err
}
eq, err := auth.ReadByte()
if err == io.EOF || eq != '=' {
return nil, fmt.Errorf("Malformed %s parameter, no equals", name)
}
if err := skipLWS(auth); err != nil {
return nil, err
}
val, err := readValue(auth)
if err != nil {
return nil, err
}
parts[name] = val
comma, err := auth.ReadByte()
if err == io.EOF {
break // our exit
}
if err != nil {
return nil, err
}
if comma != ',' {
return nil, fmt.Errorf("expected comma, got %v", comma)
}
if err := skipLWS(auth); err != nil {
if err == io.EOF {
break // our exit, finding an EOF after a value and some whitespace
}
return nil, err
}
}
if testing.Verbose() {
log.Printf("auth header = %#v", parts)
}
return parts, nil
}
|