Skip to content

Commit 9e6fcbb

Browse files
TimothyGuMylesBorins
authored andcommitted
url: fix surrogate handling in encodeAuth()
Currently, the legacy URL stringifier miscalculates the offset of an extra surrogate, causing the high surrogate to be included unescaped: > url.format({ auth: '\uD83D\uDE00', hostname: 'a' }) '//%F0%9F%98%80�@A' PR-URL: #11387 Backport-of: #11161
1 parent da87459 commit 9e6fcbb

2 files changed

Lines changed: 42 additions & 21 deletions

File tree

‎lib/url.js‎

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -948,44 +948,53 @@ function spliceOne(list, index) {
948948
varhexTable=newArray(256);
949949
for(vari=0;i<256;++i)
950950
hexTable[i]='%'+((i<16 ? '0' : '')+i.toString(16)).toUpperCase();
951+
952+
// These characters do not need escaping:
953+
// ! - . _ ~
954+
// ' ( ) * :
955+
// digits
956+
// alpha (uppercase)
957+
// alpha (lowercase)
958+
constnoEscapeAuth=[
959+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,// 0x00 - 0x0F
960+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,// 0x10 - 0x1F
961+
0,1,0,0,0,0,0,1,1,1,1,0,0,1,1,0,// 0x20 - 0x2F
962+
1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,// 0x30 - 0x3F
963+
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x40 - 0x4F
964+
1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,// 0x50 - 0x5F
965+
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x60 - 0x6F
966+
1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,0// 0x70 - 0x7F
967+
];
968+
951969
functionencodeAuth(str){
952970
// faster encodeURIComponent alternative for encoding auth uri components
953971
varout='';
954972
varlastPos=0;
955973
for(vari=0;i<str.length;++i){
956974
varc=str.charCodeAt(i);
957975

958-
// These characters do not need escaping:
959-
// ! - . _ ~
960-
// ' ( ) * :
961-
// digits
962-
// alpha (uppercase)
963-
// alpha (lowercase)
964-
if(c===0x21||c===0x2D||c===0x2E||c===0x5F||c===0x7E||
965-
(c>=0x27&&c<=0x2A)||
966-
(c>=0x30&&c<=0x3A)||
967-
(c>=0x41&&c<=0x5A)||
968-
(c>=0x61&&c<=0x7A)){
969-
continue;
970-
}
971-
972-
if(i-lastPos>0)
973-
out+=str.slice(lastPos,i);
974-
975-
lastPos=i+1;
976-
977-
// Other ASCII characters
976+
// ASCII
978977
if(c<0x80){
978+
if(noEscapeAuth[c]===1)
979+
continue;
980+
if(lastPos<i)
981+
out+=str.slice(lastPos,i);
982+
lastPos=i+1;
979983
out+=hexTable[c];
980984
continue;
981985
}
982986

987+
if(lastPos<i)
988+
out+=str.slice(lastPos,i);
989+
983990
// Multi-byte characters ...
984991
if(c<0x800){
992+
lastPos=i+1;
985993
out+=hexTable[0xC0|(c>>6)]+hexTable[0x80|(c&0x3F)];
986994
continue;
987995
}
988996
if(c<0xD800||c>=0xE000){
997+
lastPos=i+1;
989998
out+=hexTable[0xE0|(c>>12)]+
990999
hexTable[0x80|((c>>6)&0x3F)]+
9911000
hexTable[0x80|(c&0x3F)];
@@ -998,6 +1007,7 @@ function encodeAuth(str) {
9981007
c2=str.charCodeAt(i)&0x3FF;
9991008
else
10001009
c2=0;
1010+
lastPos=i+1;
10011011
c=0x10000+(((c&0x3FF)<<10)|c2);
10021012
out+=hexTable[0xF0|(c>>18)]+
10031013
hexTable[0x80|((c>>12)&0x3F)]+

‎test/parallel/test-url.js‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -891,8 +891,19 @@ var parseTests = {
891891
pathname: '/*',
892892
path: '/*',
893893
href: 'https:///*'
894-
}
894+
},
895895

896+
// surrogate in auth
897+
'http://%F0%9F%98%80@www.example.com/': {
898+
href: 'http://%F0%9F%98%80@www.example.com/',
899+
slashes: true,
900+
protocol: 'http:',
901+
auth: '\uD83D\uDE00',
902+
host: 'www.example.com',
903+
hostname: 'www.example.com',
904+
pathname: '/',
905+
path: '/'
906+
}
896907
};
897908

898909
for(constuinparseTests){

0 commit comments

Comments
 (0)