parseExtensions parses WebSocket extensions from a header.
(header http.Header)
| 226 | |
| 227 | // parseExtensions parses WebSocket extensions from a header. |
| 228 | func parseExtensions(header http.Header) []map[string]string { |
| 229 | // From RFC 6455: |
| 230 | // |
| 231 | // Sec-WebSocket-Extensions = extension-list |
| 232 | // extension-list = 1#extension |
| 233 | // extension = extension-token *( ";" extension-param ) |
| 234 | // extension-token = registered-token |
| 235 | // registered-token = token |
| 236 | // extension-param = token [ "=" (token | quoted-string) ] |
| 237 | // ;When using the quoted-string syntax variant, the value |
| 238 | // ;after quoted-string unescaping MUST conform to the |
| 239 | // ;'token' ABNF. |
| 240 | |
| 241 | var result []map[string]string |
| 242 | headers: |
| 243 | for _, s := range header["Sec-Websocket-Extensions"] { |
| 244 | for { |
| 245 | var t string |
| 246 | t, s = nextToken(skipSpace(s)) |
| 247 | if t == "" { |
| 248 | continue headers |
| 249 | } |
| 250 | ext := map[string]string{"": t} |
| 251 | for { |
| 252 | s = skipSpace(s) |
| 253 | if !strings.HasPrefix(s, ";") { |
| 254 | break |
| 255 | } |
| 256 | var k string |
| 257 | k, s = nextToken(skipSpace(s[1:])) |
| 258 | if k == "" { |
| 259 | continue headers |
| 260 | } |
| 261 | s = skipSpace(s) |
| 262 | var v string |
| 263 | if strings.HasPrefix(s, "=") { |
| 264 | v, s = nextTokenOrQuoted(skipSpace(s[1:])) |
| 265 | s = skipSpace(s) |
| 266 | } |
| 267 | if s != "" && s[0] != ',' && s[0] != ';' { |
| 268 | continue headers |
| 269 | } |
| 270 | ext[k] = v |
| 271 | } |
| 272 | if s != "" && s[0] != ',' { |
| 273 | continue headers |
| 274 | } |
| 275 | result = append(result, ext) |
| 276 | if s == "" { |
| 277 | continue headers |
| 278 | } |
| 279 | s = s[1:] |
| 280 | } |
| 281 | } |
| 282 | return result |
| 283 | } |
| 284 | |
| 285 | // isValidChallengeKey checks if the argument meets RFC6455 specification. |