11// Copyright 2023-latest the httpland authors. All rights reserved. MIT license.
22// This module is browser compatible.
33
4- import { duplicate , parseList } from "./utils.ts" ;
5- import { head , isString , toLowerCase } from "./deps.ts" ;
4+ import { divideWhile , duplicate , isToken68 , trimStartBy } from "./utils.ts" ;
5+ import {
6+ head ,
7+ isString ,
8+ isToken ,
9+ parseListFields ,
10+ type QuotedString ,
11+ type Token ,
12+ toLowerCase ,
13+ } from "./deps.ts" ;
614import { Msg } from "./constants.ts" ;
715import type { Authorization , AuthParams } from "./types.ts" ;
816
9- /** Generate from _abnf.ts. */
10- const reAuthorization =
11- / ^ (?< authScheme > (? = ( [ \w ! # $ % & ' * + . ^ ` | ~ - ] + ) ) \2) (?: (? = ( + ) ) \3(?: (?< token68 > (? = ( (?: [ A - Z a - z ] | \d | [ + . / _ ~ - ] ) + ) ) \5(? = ( = * ) ) \6) | (?< authParam > (? = ( .* ) ) \8) ) ) ? $ / ;
12-
1317/** Parse string into {@link Authorization}.
1418 *
1519 * @example
@@ -39,28 +43,28 @@ const reAuthorization =
3943 * @throws {Error } If the auth param key is duplicated.
4044 */
4145export function parseAuthorization ( input : string ) : Authorization {
42- const result = reAuthorization . exec ( input ) ;
46+ const result = divideWhile ( input , isToken ) ;
4347
44- if ( ! result || ! result . groups ) throw SyntaxError ( Msg . InvalidSyntax ) ;
48+ if ( ! result ) throw new SyntaxError ( Msg . InvalidSyntax ) ;
4549
46- const groups = result . groups as ParsedGroups ;
47- const { authScheme } = groups ;
48- const params = isString ( groups . authParam )
49- ? parseAuthParams ( groups . authParam )
50- : groups . token68 ;
50+ const [ authScheme , rest ] = result ;
5151
52- return { authScheme, params : params ?? null } ;
53- }
52+ // challenge = auth-scheme
53+ if ( ! rest ) return { authScheme, params : null } ;
54+ if ( ! rest . startsWith ( " " ) ) throw new SyntaxError ( Msg . InvalidSyntax ) ;
5455
55- type ParsedGroups = {
56- readonly authScheme : string ;
57- readonly token68 : string | undefined ;
58- readonly authParam : string | undefined ;
59- } ;
56+ const maybeToken68OrAuthParam = trimStartBy ( rest , " " ) ;
6057
61- /** Generate from _abnf.ts. */
62- const reAuthParam =
63- / ^ (?< key > (? = ( [ \w ! # $ % & ' * + . ^ ` | ~ - ] + ) ) \2) [ \t ] * = [ \t ] * (?: (?< token > (? = ( [ \w ! # $ % & ' * + . ^ ` | ~ - ] + ) ) \4) | (?< quotedString > " (? = ( (?: \t | | ! | [ \x23 - \x5B \x5D - \x7E ] | [ \x80 - \xFF ] | \\ (?: \t | | [ \x21 - \x7E ] | [ \x80 - \xFF ] ) ) * ) ) \6" ) ) $ / ;
58+ // challenge = auth-scheme [ 1*SP ( token68 ) ]
59+ if ( isToken68 ( maybeToken68OrAuthParam ) ) {
60+ return { authScheme, params : maybeToken68OrAuthParam } ;
61+ }
62+
63+ // challenge = auth-scheme [ 1*SP ( #auth-param ) ]
64+ const params = parseAuthParams ( maybeToken68OrAuthParam ) ;
65+
66+ return { authScheme, params } ;
67+ }
6468
6569type AuthParamGroups =
6670 & { key : string }
@@ -69,26 +73,13 @@ type AuthParamGroups =
6973 quotedString : string ;
7074 } ) ;
7175
72- /** Parse string into {@link AuthParam }.
76+ /** Parse string into {@link AuthParams }.
7377 * @throws {SyntaxError } It the input is invalid [auth-param](https://www.rfc-editor.org/rfc/rfc9110.html#section-11.2-5).
7478 * @throws {Error } If the auth param key is duplicated.
7579 */
7680export function parseAuthParams ( input : string ) : AuthParams {
77- const list = parseList ( input ) ;
78-
79- const entries = list . map ( ( el ) => {
80- const result = reAuthParam . exec ( el ) ;
81-
82- if ( ! result || ! result . groups ) throw SyntaxError ( Msg . InvalidSyntax ) ;
83-
84- const groups = result . groups as AuthParamGroups ;
85- const value = isString ( groups . token )
86- ? groups . token
87- : groups . quotedString . replace ( / \\ ( .) / g, "$1" ) ;
88-
89- return [ groups . key , value ] as const ;
90- } ) ;
91-
81+ const list = parseListFields ( input ) ;
82+ const entries = list . map ( parseAuthParam ) ;
9283 const duplicates = duplicate (
9384 entries
9485 . map < string > ( head )
@@ -99,3 +90,25 @@ export function parseAuthParams(input: string): AuthParams {
9990
10091 return Object . fromEntries ( entries ) ;
10192}
93+
94+ type AuthParam = [ key : string , value : Token | QuotedString ] ;
95+
96+ /** Generate from _abnf.ts. */
97+ const reAuthParam =
98+ / ^ (?< key > [ \w ! # $ % & ' * + . ^ ` | ~ - ] + ?) [ \t ] * ?= [ \t ] * ?(?: (?< token > [ \w ! # $ % & ' * + . ^ ` | ~ - ] + ?) | (?< quotedString > " (?: [ \t ! \x23 - \x5B \x5D - \x7E \x80 - \xFF ] | \\ [ \t \x21 - \x7E \x80 - \xFF ] ) * ?" ) ) $ / ;
99+
100+ /** Parse string into {@link AuthParam}.
101+ * @throws {SyntaxError } It the input is invalid [auth-param](https://www.rfc-editor.org/rfc/rfc9110.html#section-11.2-5).
102+ */
103+ function parseAuthParam ( input : string ) : AuthParam {
104+ const result = reAuthParam . exec ( input ) ;
105+
106+ if ( ! result || ! result . groups ) throw new SyntaxError ( Msg . InvalidSyntax ) ;
107+
108+ const groups = result . groups as AuthParamGroups ;
109+ const value = isString ( groups . token )
110+ ? groups . token as Token
111+ : groups . quotedString . replace ( / \\ ( .) / g, "$1" ) as QuotedString ;
112+
113+ return [ groups . key as Token , value ] ;
114+ }
0 commit comments