Skip to content

Perf optimize cookie value validation - #285

Open
blakeembrey wants to merge 1 commit into
masterfrom
be/skip-validation-default-encoder
Open

Perf optimize cookie value validation#285
blakeembrey wants to merge 1 commit into
masterfrom
be/skip-validation-default-encoder

Conversation

@blakeembrey

Copy link
Copy Markdown
Member

Tweak encoder regex to be a negative class match (benchmark is slightly faster, but marginal, could undo if someone really disagrees) and skips validation of the value entirely when using the default encoder since it's already known valid.

@blakeembrey
blakeembreyforce-pushed the be/skip-validation-default-encoder branch from a7aa0f0 to 2824b73CompareJuly 8, 2026 18:36
@TeeAaTeeUu

TeeAaTeeUu commented Jul 14, 2026

Copy link
Copy Markdown

If more code is OK, an extra ~6% perf-increase can be achieved by replacing regex with a for-loop and individually checking charCode:

functiondefaultEncode(str: string): string{for(leti=0,c=0,len=str.length;i<len;i++){c=str.charCodeAt(i);// \u0000-\u0020 (<33), \u007F-\uFFFF (>126), "(34), %(37), ,(44), ;(59), \(92)if(c<33||c>126||c===34||c===37||c===44||c===59||c===92)returnencodeURIComponent(str);}returnstr;}

Runtime: node 26.4.0 (arm64-darwin)

casebefore hzafter hzSpeedup
empty25.380.759,3425.288.506,031,00x
simple12.159.813,1713.313.107,041,09x
rfc cookie-octets11.743.931,7411.103.105,490,95x
encode5.753.640,446.171.864,261,07x
undefined values5.754.738,966.303.222,051,10x
mixed encode3.422.381,203.702.327,761,08x
10 cookies1.567.005,951.722.698,911,10x
100 cookies134.028,73141.792,501,06x

I think with these we are getting into the "not so relevant speedup" territory, meaning code-readability should be prioritised instead. If you read and understand regex more easily, then that is preferable than above for-loop!

@TeeAaTeeUu

Copy link
Copy Markdown

And for completion, here also the other regexes in for-loop form, gaining ~10% more (at least with the current bench, we might want to test with longer strings):

functionvalidCookieName(str: string): boolean{for(leti=0,c=0,len=str.length;i<len;i++){c=str.charCodeAt(i);// ;(59) =(61)if(c<33||c>126||c===59||c===61)returnfalse;}returntrue;}functionvalidCookieValue(str: string): boolean{for(leti=0,c=0,len=str.length;i<len;i++){c=str.charCodeAt(i);// ;(59) if(c<33||c>126||c===59)returnfalse;}returntrue;}functionvalidCookiePath(str: string): boolean{for(leti=0,c=0,len=str.length;i<len;i++){c=str.charCodeAt(i);// ;(59) <(60)if(c<32||c>126||c===59||c===60)returnfalse;}returntrue;}

And in case wanted to add a bit more readability, we can generate the charCode values:

constEXLAMATION='!'.charCodeAt(0)constDOUBLEQUOTE='"'.charCodeAt(0)constPERCENT='%'.charCodeAt(0)constCOMMA=','.charCodeAt(0)constSEMICOLON=';'.charCodeAt(0)constLESS_THAN='<'.charCodeAt(0)constEQUAL='='.charCodeAt(0)constBACKSLASH='\\'.charCodeAt(0)constTILDE='~'.charCodeAt(0)

@TeeAaTeeUu

Copy link
Copy Markdown

Walking back on my suggestion...

For-loop perf improvement only happens when the invalid / encoding-required character is found within the first ~15 characters. By the time it's 512 chars, for-loop is twice as slow.

Meaning for-loop is still faster for longer strings, if for example ; semicolon is found early within the string.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@blakeembrey@TeeAaTeeUu