// advanceParam attempts to advance to the start of the next // parameter and returns true if the advance succeeded, otherwise // false if the lexer is at EOF or if unexpected characters were // found. func advanceParam(l *lexrec.Lexer) bool { if l.Peek() == lexrec.EOF { return false } l.AcceptRun(whitespace) if l.Next() != ',' { l.Errorf("advanceParam: expected comma, got %q", l.Peek()) return false } l.AcceptRun(whitespace) l.Skip() return true }
// advanceChallenge skips over an unrecognized WWW-Authenticate challenge. func advanceChallenge(l *lexrec.Lexer) { if l.AcceptRun(whitespace) { l.Skip() } expectParam := true for expectParam { if l.ExceptRun(nontoken) { r := l.Peek() if r == '=' { l.Accept("=") l.Skip() if l.Peek() == '"' { if lexrec.Quote(l, ItemAuthParam, false) { l.Skip() } } else { if l.ExceptRun(nontoken) { l.Skip() } else { l.Errorf("advanceChallenge: expected a token character, got %q", l.Peek()) } } } else if isSpace(r) { return } else { l.Errorf("advanceChallenge: expected either whitespace or '=', got %q", l.Peek()) return } expectParam = advanceParam(l) } else { return } } }
// emitWWWAuthenticate drives a lexer to parse an RFC 2617 // Basic or Digest authentication challenge // // The specification defines a Basic authentication challenge as: // // challenge = "Basic" realm // // realm = "realm" "=" realm-value // realm-value = quoted-string // // The specification defines a Digest authentication challenge as: // // challenge = "Digest" digest-challenge // // digest-challenge = 1#( realm | [ domain ] | nonce | [ opaque ] |[ stale ] // | [ algorithm ] | [ qop-options ] | [auth-param] ) // // The BNF for these constructs: // // domain = "domain" "=" <"> URI ( 1*SP URI ) <"> // URI = absoluteURI | abs_path // nonce = "nonce" "=" nonce-value // nonce-value = quoted-string // opaque = "opaque" "=" quoted-string // stale = "stale" "=" ( "true" | "false" ) // algorithm = "algorithm" "=" ( "MD5" | "MD5-sess" | token ) // qop-options = "qop" "=" <"> 1#qop-value <"> // qop-value = "auth" | "auth-int" | token // auth-param = token "=" ( token | quoted-string ) // // token = 1*<any CHAR except CTLs or separators> // separators = "(" | ")" | "<" | ">" | "@" // | "," | ";" | ":" | "\" | <"> // | "/" | "[" | "]" | "?" | "=" // | "{" | "}" | SP | HT // // quoted-string = ( <"> *(qdtext | quoted-pair ) <"> ) // qdtext = <any TEXT except <">> // quoted-pair = "\" CHAR // // An example challenge: // // Digest realm="Sample Digest Realm", // nonce="nWjG15v1BAA=744a97693b14ea8805cadf32fcc3f57f245d08eb", // algorithm=MD5, domain="/", qop="auth" // func emitWWWAuthenticate(l *lexrec.Lexer) { defer l.Emit(lexrec.ItemEOF) if l.Peek() == lexrec.EOF { l.Errorf("emitWWWAuthenticate: expected token character, got EOF") return } if l.AcceptRun(whitespace) { l.Skip() } if !l.ExceptRun(nontoken) { l.Errorf("emitWWWAuthenticate: expected token character, got %q", l.Peek()) return } for { if l.Peek() == lexrec.EOF { return } switch strings.ToLower(string(l.Bytes())) { case "basic": l.Emit(ItemBasic) if l.AcceptRun(whitespace) { l.Skip() } else { l.Errorf("expected whitespace after 'Basic', got %q", l.Peek()) return } emitBasicParams(l) case "digest": l.Emit(ItemDigest) if l.AcceptRun(whitespace) { l.Skip() } else { l.Errorf("expected whitespace after 'Digest', got %q", l.Peek()) return } emitDigestParams(l) default: advanceChallenge(l) } } }