accept_header.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. package context
  2. import "strings"
  3. func negotiationMatch(in []string, priorities []string) string {
  4. // e.g.
  5. // match json:
  6. // in: text/html, application/json
  7. // priorities: application/json
  8. // not match:
  9. // in: text/html, application/json
  10. // priorities: text/xml
  11. // match html:
  12. // in: text/html, application/json
  13. // priorities: */*
  14. // not match:
  15. // in: application/json
  16. // priorities: text/xml
  17. // match json:
  18. // in: text/html, application/*
  19. // priorities: application/json
  20. if len(priorities) == 0 {
  21. return ""
  22. }
  23. if len(in) == 0 {
  24. return priorities[0]
  25. }
  26. for _, accepted := range in {
  27. for _, p := range priorities {
  28. // wildcard is */* or text/* and etc.
  29. // so loop through each char.
  30. for i, n := 0, len(accepted); i < n; i++ {
  31. if accepted[i] != p[i] {
  32. break
  33. }
  34. if accepted[i] == '*' || p[i] == '*' {
  35. return p
  36. }
  37. if i == n-1 {
  38. return p
  39. }
  40. }
  41. }
  42. }
  43. return ""
  44. }
  45. func negotiateAcceptHeader(in []string, offers []string, bestOffer string) string {
  46. if bestOffer == "" {
  47. bestOffer = IDENTITY
  48. }
  49. bestQ := -1.0
  50. specs := parseAccept(in)
  51. for _, offer := range offers {
  52. for _, spec := range specs {
  53. if spec.Q > bestQ &&
  54. (spec.Value == "*" || spec.Value == offer) {
  55. bestQ = spec.Q
  56. bestOffer = offer
  57. }
  58. }
  59. }
  60. if bestQ == 0 {
  61. bestOffer = ""
  62. }
  63. return bestOffer
  64. }
  65. // acceptSpec describes an Accept* header.
  66. type acceptSpec struct {
  67. Value string
  68. Q float64
  69. }
  70. // parseAccept parses Accept* headers.
  71. func parseAccept(in []string) (specs []acceptSpec) {
  72. loop:
  73. for _, s := range in {
  74. for {
  75. var spec acceptSpec
  76. spec.Value, s = expectTokenSlash(s)
  77. if spec.Value == "" {
  78. continue loop
  79. }
  80. spec.Q = 1.0
  81. s = skipSpace(s)
  82. if strings.HasPrefix(s, ";") {
  83. s = skipSpace(s[1:])
  84. if !strings.HasPrefix(s, "q=") {
  85. continue loop
  86. }
  87. spec.Q, s = expectQuality(s[2:])
  88. if spec.Q < 0.0 {
  89. continue loop
  90. }
  91. }
  92. specs = append(specs, spec)
  93. s = skipSpace(s)
  94. if !strings.HasPrefix(s, ",") {
  95. continue loop
  96. }
  97. s = skipSpace(s[1:])
  98. }
  99. }
  100. return
  101. }
  102. func skipSpace(s string) (rest string) {
  103. i := 0
  104. for ; i < len(s); i++ {
  105. if octetTypes[s[i]]&isSpace == 0 {
  106. break
  107. }
  108. }
  109. return s[i:]
  110. }
  111. func expectTokenSlash(s string) (token, rest string) {
  112. i := 0
  113. for ; i < len(s); i++ {
  114. b := s[i]
  115. if (octetTypes[b]&isToken == 0) && b != '/' {
  116. break
  117. }
  118. }
  119. return s[:i], s[i:]
  120. }
  121. func expectQuality(s string) (q float64, rest string) {
  122. switch {
  123. case s == "":
  124. return -1, ""
  125. case s[0] == '0':
  126. q = 0
  127. case s[0] == '1':
  128. q = 1
  129. default:
  130. return -1, ""
  131. }
  132. s = s[1:]
  133. if !strings.HasPrefix(s, ".") {
  134. return q, s
  135. }
  136. s = s[1:]
  137. i := 0
  138. n := 0
  139. d := 1
  140. for ; i < len(s); i++ {
  141. b := s[i]
  142. if b < '0' || b > '9' {
  143. break
  144. }
  145. n = n*10 + int(b) - '0'
  146. d *= 10
  147. }
  148. return q + float64(n)/float64(d), s[i:]
  149. }
  150. // Octet types from RFC 2616.
  151. var octetTypes [256]octetType
  152. type octetType byte
  153. const (
  154. isToken octetType = 1 << iota
  155. isSpace
  156. )
  157. func init() {
  158. // OCTET = <any 8-bit sequence of data>
  159. // CHAR = <any US-ASCII character (octets 0 - 127)>
  160. // CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
  161. // CR = <US-ASCII CR, carriage return (13)>
  162. // LF = <US-ASCII LF, linefeed (10)>
  163. // SP = <US-ASCII SP, space (32)>
  164. // HT = <US-ASCII HT, horizontal-tab (9)>
  165. // <"> = <US-ASCII double-quote mark (34)>
  166. // CRLF = CR LF
  167. // LWS = [CRLF] 1*( SP | HT )
  168. // TEXT = <any OCTET except CTLs, but including LWS>
  169. // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <">
  170. // | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
  171. // token = 1*<any CHAR except CTLs or separators>
  172. // qdtext = <any TEXT except <">>
  173. for c := 0; c < 256; c++ {
  174. var t octetType
  175. isCtl := c <= 31 || c == 127
  176. isChar := 0 <= c && c <= 127
  177. isSeparator := strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", rune(c))
  178. if strings.ContainsRune(" \t\r\n", rune(c)) {
  179. t |= isSpace
  180. }
  181. if isChar && !isCtl && !isSeparator {
  182. t |= isToken
  183. }
  184. octetTypes[c] = t
  185. }
  186. }