1 package httpencoding 2 3 import "vimagination.zapto.org/parser" 4 5 const ( 6 alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 7 digit = "0123456789" 8 tchar = "!#$%&'*+-.^_`|~" + digit + alpha 9 ows = " \t" 10 delim = "," 11 weightDelim = ";" 12 qvalPrefix = "q=" 13 ) 14 15 const ( 16 tokenCoding parser.TokenType = iota 17 tokenWeight 18 tokenInvalidWeight 19 ) 20 21 func parseAccept(accept string) *parser.Parser { 22 t := parser.New(parser.NewStringTokeniser(accept)) 23 24 t.TokeniserState(parseList) 25 26 return &t 27 } 28 29 func parseList(t *parser.Tokeniser) (parser.Token, parser.TokenFunc) { 30 for { 31 t.AcceptRun(ows) 32 t.Get() 33 34 if t.Accept(tchar) { 35 t.AcceptRun(tchar) 36 37 return t.Return(tokenCoding, parseQVal) 38 } else if t.Peek() == -1 { 39 return t.Done() 40 } 41 42 t.ExceptRun(delim) 43 t.Accept(delim) 44 } 45 } 46 47 func parseQVal(t *parser.Tokeniser) (parser.Token, parser.TokenFunc) { 48 t.AcceptRun(ows) 49 t.Get() 50 51 if !t.Accept(weightDelim) { 52 t.ExceptRun(delim) 53 t.Accept(delim) 54 55 return parseList(t) 56 } 57 58 t.AcceptRun(ows) 59 t.Get() 60 61 if t.AcceptString(qvalPrefix, false) == len(qvalPrefix) { 62 t.Get() 63 64 if t.Accept("0") { 65 return parse0(t) 66 } else if t.AcceptString("1.000", false) > 0 { 67 return parseWeightEnd(t) 68 } 69 } 70 71 t.ExceptRun(delim) 72 t.Accept(delim) 73 74 return t.Return(tokenInvalidWeight, parseList) 75 } 76 77 func parse0(t *parser.Tokeniser) (parser.Token, parser.TokenFunc) { 78 if t.Accept(".") { 79 t.Accept(digit) 80 t.Accept(digit) 81 t.Accept(digit) 82 } 83 84 return parseWeightEnd(t) 85 } 86 87 func parseWeightEnd(t *parser.Tokeniser) (parser.Token, parser.TokenFunc) { 88 data := t.Get() 89 90 t.AcceptRun(ows) 91 92 if t.Accept(delim) || t.Peek() == -1 { 93 return parser.Token{Type: tokenWeight, Data: data}, parseList 94 } 95 96 t.ExceptRun(delim) 97 t.Accept(delim) 98 t.Get() 99 100 return t.Return(tokenInvalidWeight, parseList) 101 } 102