@@ -20,22 +20,13 @@ internal static class HttpEncoder
20
20
private static readonly SearchValues < byte > s_urlSafeBytes = SearchValues . Create (
21
21
"!()*-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"u8 ) ;
22
22
23
- private static void AppendCharAsUnicodeJavaScript ( StringBuilder builder , char c )
24
- {
25
- builder . Append ( $ "\\ u{ ( int ) c : x4} ") ;
26
- }
27
-
28
- private static bool CharRequiresJavaScriptEncoding ( char c ) =>
29
- c < 0x20 // control chars always have to be encoded
30
- || c == '\" ' // chars which must be encoded per JSON spec
31
- || c == '\\ '
32
- || c == '\' ' // HTML-sensitive chars encoded for safety
33
- || c == '<'
34
- || c == '>'
35
- || ( c == '&' )
36
- || c == '\u0085 ' // newline chars (see Unicode 6.2, Table 5-1 [http://www.unicode.org/versions/Unicode6.2.0/ch05.pdf]) have to be encoded
37
- || c == '\u2028 '
38
- || c == '\u2029 ' ;
23
+ private static readonly SearchValues < char > s_invalidJavaScriptChars = SearchValues . Create (
24
+ // Any Control, < 32 (' ')
25
+ "\u0000 \u0001 \u0002 \u0003 \u0004 \u0005 \u0006 \u0007 \u0008 \u0009 \u000A \u000B \u000C \u000D \u000E \u000F \u0010 \u0011 \u0012 \u0013 \u0014 \u0015 \u0016 \u0017 \u0018 \u0019 \u001A \u001B \u001C \u001D \u001E \u001F " +
26
+ // Chars which must be encoded per JSON spec / HTML-sensitive chars encoded for safety
27
+ "\" &'<>\\ " +
28
+ // newline chars (see Unicode 6.2, Table 5-1 [http://www.unicode.org/versions/Unicode6.2.0/ch05.pdf]) have to be encoded
29
+ "\u0085 \u2028 \u2029 " ) ;
39
30
40
31
[ return : NotNullIfNotNull ( nameof ( value ) ) ]
41
32
internal static string ? HtmlAttributeEncode ( string ? value )
@@ -137,79 +128,71 @@ private static int IndexOfHtmlAttributeEncodingChars(string s) =>
137
128
138
129
private static bool IsNonAsciiByte ( byte b ) => b >= 0x7F || b < 0x20 ;
139
130
140
- internal static string JavaScriptStringEncode ( string ? value )
131
+ internal static string JavaScriptStringEncode ( string ? value , bool addDoubleQuotes )
141
132
{
142
- if ( string . IsNullOrEmpty ( value ) )
133
+ int i = value . AsSpan ( ) . IndexOfAny ( s_invalidJavaScriptChars ) ;
134
+ if ( i < 0 )
143
135
{
144
- return string . Empty ;
136
+ return addDoubleQuotes ? $ " \" { value } \" " : value ?? string . Empty ;
145
137
}
146
138
147
- StringBuilder ? b = null ;
148
- int startIndex = 0 ;
149
- int count = 0 ;
150
- for ( int i = 0 ; i < value . Length ; i ++ )
151
- {
152
- char c = value [ i ] ;
139
+ return EncodeCore ( value , i , addDoubleQuotes ) ;
153
140
154
- // Append the unhandled characters (that do not require special treament)
155
- // to the string builder when special characters are detected.
156
- if ( CharRequiresJavaScriptEncoding ( c ) )
141
+ static string EncodeCore ( ReadOnlySpan < char > value , int i , bool addDoubleQuotes )
142
+ {
143
+ var vsb = new ValueStringBuilder ( stackalloc char [ StackallocThreshold ] ) ;
144
+ if ( addDoubleQuotes )
157
145
{
158
- b ??= new StringBuilder ( value . Length + 5 ) ;
159
-
160
- if ( count > 0 )
161
- {
162
- b . Append ( value , startIndex , count ) ;
163
- }
164
-
165
- startIndex = i + 1 ;
166
- count = 0 ;
146
+ vsb . Append ( '"' ) ;
147
+ }
167
148
149
+ ReadOnlySpan < char > chars = value ;
150
+ do
151
+ {
152
+ vsb . Append ( chars . Slice ( 0 , i ) ) ;
153
+ char c = chars [ i ] ;
154
+ chars = chars . Slice ( i + 1 ) ;
168
155
switch ( c )
169
156
{
170
157
case '\r ' :
171
- b . Append ( "\\ r" ) ;
158
+ vsb . Append ( "\\ r" ) ;
172
159
break ;
173
160
case '\t ' :
174
- b . Append ( "\\ t" ) ;
161
+ vsb . Append ( "\\ t" ) ;
175
162
break ;
176
163
case '\" ' :
177
- b . Append ( "\\ \" " ) ;
164
+ vsb . Append ( "\\ \" " ) ;
178
165
break ;
179
166
case '\\ ' :
180
- b . Append ( "\\ \\ " ) ;
167
+ vsb . Append ( "\\ \\ " ) ;
181
168
break ;
182
169
case '\n ' :
183
- b . Append ( "\\ n" ) ;
170
+ vsb . Append ( "\\ n" ) ;
184
171
break ;
185
172
case '\b ' :
186
- b . Append ( "\\ b" ) ;
173
+ vsb . Append ( "\\ b" ) ;
187
174
break ;
188
175
case '\f ' :
189
- b . Append ( "\\ f" ) ;
176
+ vsb . Append ( "\\ f" ) ;
190
177
break ;
191
178
default :
192
- AppendCharAsUnicodeJavaScript ( b , c ) ;
179
+ vsb . Append ( "\\ u" ) ;
180
+ vsb . AppendSpanFormattable ( ( int ) c , "x4" ) ;
193
181
break ;
194
182
}
195
- }
196
- else
183
+
184
+ i = chars . IndexOfAny ( s_invalidJavaScriptChars ) ;
185
+ } while ( i >= 0 ) ;
186
+
187
+ vsb . Append ( chars ) ;
188
+
189
+ if ( addDoubleQuotes )
197
190
{
198
- count ++ ;
191
+ vsb . Append ( '"' ) ;
199
192
}
200
- }
201
193
202
- if ( b == null )
203
- {
204
- return value ;
205
- }
206
-
207
- if ( count > 0 )
208
- {
209
- b . Append ( value , startIndex , count ) ;
194
+ return vsb . ToString ( ) ;
210
195
}
211
-
212
- return b . ToString ( ) ;
213
196
}
214
197
215
198
[ return : NotNullIfNotNull ( nameof ( bytes ) ) ]
0 commit comments