HTTP协议header中Content-Disposition中⽂⽂件名乱码
从跟踪代码来看,content-disposition存放的是httprespon的rawheader。直到在HttpContentDisposition类的filename_成员才会存放转换了的编码。
这个转换编码的猜测流程:asc,utf,有指定编码,按指定;否则按系统的字符集。
参考:
/lc11535/article/details/100013653
⽐如:“中⽂”字符得编码:
Unicode中为:4E2D6587
GBK(gb2312gb18030)中为:D6D0CEC4
这是在内存中存放形式。chrome内部统⼀⽤Unicode在内存存放,所以会有⼀张gbk到unicode得对照表,将“中”的gbkD6D0转换为unicode的4E2D。
当需要把“中⽂”这两字保存到⽂件,或者⽹络传输时,直接保存需要两个字节,这样会浪费保存英⽂的存储空间,因为英⽂只需要⼀个字节。所以这时就有个编码的需求。⼀般
都是⽤utf8。英⽂直接还是⽤⼀个字节;中⽂就要⽤3个字节。utf8,utf16,utf32都是对unicode的编码存储。
“中⽂”的utf8存成⽂件为:
⽽“中⽂”的GBK存储时,直接就是按编码存储。
gb2312:
规定:⼀个⼩于127的字符的意义与原来相同,但两个⼤于127的字符连在⼀起时,就表⽰⼀个汉字,前⾯的⼀个字节(他称之为⾼字节)从0xA1⽤到0xF7,后⾯⼀个字节(低
字节)从0xA1到0xFE,这样我们就可以组合出⼤约7000多个简体汉字了
gbk:只要⾼位是1开始,即⼤于127;不再管地位。这样增加了2万汉字。
GB18030:加⼊了少数民族的字。
Unicode出现:所有字符都占两位
wchar_t*p=L"Hello!";//占10个字节
没有⼀种简单的算术⽅法可以把⽂本内容从UNICODE编码和另⼀种编码进⾏转换,这种转换必须通过查表来进⾏。如unicode到gbk。具体的符号对应表,可以查询,或者专门
的。
UNICODE("UniversalMultiple-OctetCodedCharacterSet",简称UCS,俗称"UNICODE"。)是⽤两个字节来表⽰为⼀个字符,组合出65535不同的字符,这⼤概已经可以覆
盖世界上所有⽂化的符号。
如果还不够也没有关系,ISO已经准备了UCS-4⽅案,说简单了就是四个字节来表⽰⼀个字符,这样我们就可以组合出21亿个不同的字符出来(最⾼位有其他⽤途)。
⾯向⽹络传输规范出现:UTF(UCSTransferFormat)顾名思义,UTF8就是每次8个位传输数据,⽽UTF16就是每次16个位,只不过为了传输时的可靠性,从UNICODE到
UTF时并不是直接的对应,⽽是要过⼀些算法和规则来转换。重复⼀遍,这⾥的关系是,UTF-8是Unicode的实现⽅式之⼀。
INTEL低位先发送"FEFF",否则⾼位,utf的⽂件头都有这个标志。
打开⽂件时EFBBBF,表⽰UTF-8
UnicodeUTF-8
0000-007F0xxxxxxx
0080-07FF110xxxxx10xxxxxx
0800-FFFF1110xxxx10xxxxxx10xxxxxx
记事本的编码默认是ANSI,如果你在ANSI的编码输⼊汉字,那么他实际就是GB系列的编码⽅式,在这种编码下,"联通"的内码是:
c111000001
aa10101010
cd11001101
a810101000
windows的记事本保存时选择编码格式:
⾥⾯有四个选项:ANSI,Unicode,Unicodebigendian和UTF-8。
1)ANSI是默认的编码⽅式。对于英⽂⽂件是ASCII编码,对于简体中⽂⽂件是GB2312编码(只针对Windows简体中⽂版,如果是繁体中⽂版会采⽤Big5码)。
2)Unicode编码指的是UCS-2编码⽅式,即直接⽤两个字节存⼊字符的Unicode码。这个选项⽤的littleendian格式。
3)Unicodebigendian编码与上⼀个选项相对应。我在下⼀节会解释littleendian和bigendian的涵义。
4)UTF-8编码,也就是上⼀节谈到的编码⽅法。
选择完”编码⽅式“后,点击”保存“按钮,⽂件的编码⽅式就⽴刻转换好了。
Unicode码可以采⽤UCS-2格式直接存储。以汉字”严“为例,Unicode码是4E25,需要⽤两个字节存储,⼀个字节是4E,另⼀个字节是25。存储的时候,4E在前,25在后,就是
Bigendian⽅式;25在前,4E在后,就是Littleendian⽅式。
Unicode规范中定义,每⼀个⽂件的最前⾯分别加⼊⼀个表⽰编码顺序的字符,这个字符的名字叫做”零宽度⾮换⾏空格“(ZEROWIDTHNO-BREAKSPACE),⽤FEFF表
⽰。这正好是两个字节,⽽且FF⽐FE⼤1。
如果⼀个⽂本⽂件的头两个字节是FEFF,就表⽰该⽂件采⽤⼤头⽅式;如果头两个字节是FFFE,就表⽰该⽂件采⽤⼩头⽅式。
这两个古怪的名称来⾃英国作家斯威夫特的《格列佛游记》。在该书中,⼩⼈国⾥爆发了内战,战争起因是⼈们争论,
吃鸡蛋时究竟是从⼤头(Big-Endian)敲开还是从⼩头(Little-Endian)敲开。为了这件事情,前后爆发了六次战争,
⼀个皇帝送了命,另⼀个皇帝丢了王位。
因此,第⼀个字节在前,就是”⼤头⽅式“(Bigendian),第⼆个字节在前就是”⼩头⽅式“(Littleendian)。
实例:
打开”记事本“程序,新建⼀个⽂本⽂件,内容就是⼀个”严“字,依次采⽤ANSI,Unicode,Unicodebigendian和UTF-8编码⽅式保存。
然后,⽤⽂本编辑软件UltraEdit中的”⼗六进制功能“,观察该⽂件的内部编码⽅式。
1)ANSI:⽂件的编码就是两个字节“D1CF”,这正是“严”的GB2312编码,这也暗⽰GB2312是采⽤⼤头⽅式存储的。
2)Unicode:编码是四个字节“FFFE254E”,其中“FFFE”表明是⼩头⽅式存储,真正的编码是4E25。
3)Unicodebigendian:编码是四个字节“FEFF4E25”,其中“FEFF”表明是⼤头⽅式存储。
4)UTF-8:编码是六个字节“EFBBBFE4B8A5”,
前三个字节“EFBBBF”表⽰这是UTF-8编码,
后三个“E4B8A5”就是“严”的具体编码,它的存储顺序与编码顺序是⼀致的。
Unicode和utf16是⼀⼀对应的。他俩都是2个字节。只是传输英⽂会浪费⼀倍空间。
打开⽂件FEFF表⽰UTF-16.
"汉"对应的unicode是6C49
UTF-16表⽰的话就是1001(共16bit,两个字节).UTF-16不需要⽤啥字符来做标志,所以两字节也就是2的16次能表⽰65536个字符.
⽽UTF-8由于⾥⾯有额外的标志信息,所有⼀个字节只能表⽰2的7次⽅128个字符,两个字节只能表⽰2的11次⽅2048个字符.⽽三个字节能表⽰2的16次⽅,65536个字符.
由于"汉"的编码27721⼤于2048了所有两个字节还不够,只能⽤三个字节来表⽰.
所有要⽤1110xxxx10xxxxxx10xxxxxx这种格式.把27721对应的⼆进制从左到右(littleendia从右到左)填充XXX符号.
Unicode版本2
前⾯说的都是unicode的第⼀个版本.但65536显然不算太多的数字,⽤它来表⽰常⽤的字符是没⼀点问题.⾜够了,但如果加上很多特殊的就也不够了.于是从1996年开始⼜来了第
⼆个版本.⽤四个字节表⽰所有字符.这样就出现了UTF-8,UTF16,UTF-32.原理和之前肯定是完全⼀样的,UTF-32就是把所有的字符都⽤32bit也就是4个字节来表⽰.然后UTF-
8,UTF-16就视情况⽽定了.UTF-8可以选择1⾄8个字节中的任⼀个来表⽰.⽽UTF-16只能是选两字节或四字节..由于unicode版本2的原理完全是⼀样的,就不多说了.
前⾯说了要知道具体是哪种编码⽅式,需要判断⽂本开头的标志,下⾯是所有编码对应的开头标志
EFBBBF UTF-8
FEFF UTF-16/UCS-2,littleendian
FFFE UTF-16/UCS-2,bigendian
FFFE0000 UTF-32/UCS-4,littleendian.
0000FEFF UTF-32/UCS-4,big-endian.
其中的UCS就是前⾯说的ISO制定的标准,和Unicode是完全⼀样的,只不过名字不⼀样.ucs-2对应utf-16,ucs-4对应-8是没有对应的UCS
UTF-16并不是⼀个完美的选择,它存在⼏个⽅⾯的问题:
-16能表⽰的字符数有6万多,看起来很多,但是实际上⽬前Unicode5.0收录的字符已经达到99024个字符,早已超过UTF-16的存储范围;这直接导致UTF-16地
位颇为尴尬——如果谁还在想着只要使⽤UTF-16就可以⾼枕⽆忧的话,恐怕要失望了
-16存在⼤⼩端字节序问题,这个问题在进⾏信息交换时特别突出——如果字节序未协商好,将导致乱码;如果协商好,但是双⽅⼀个采⽤⼤端⼀个采⽤⼩端,则必然
有⼀⽅要进⾏⼤⼩端转换,性能损失不可避免(⼤⼩端问题其实不像看起来那么简单,有时会涉及硬件、操作系统、上层软件多个层次,可能会进⾏多次转换)
3.另外,容错性低有时候也是⼀⼤问题——局部的字节错误,特别是丢失或增加可能导致所有后续字符全部错乱,错乱后要想恢复,可能很简单,也可能会⾮常困难。(这⼀
点在⽇常⽣活⾥⼤家感觉似乎⽆关紧要,但是在很多特殊环境下却是巨⼤的缺陷)
⽬前⽀撑我们继续使⽤UTF-16的理由主要是考虑到它是双字节的,在计算字符串长度、执⾏索引操作时速度很快。当然这些优点UTF-32都具有,但很多⼈毕竟还是觉得UTF-
32太占空间了。
反过来UTF-8也不完美,也存在⼀些问题:
1.⽂化上的不平衡——对于欧美地区⼀些以英语为母语的国家UTF-8简直是太棒了,因为它和ASCII⼀样,⼀个字符只占⼀个字节,没有任何额外的存储负担;但是对于中
⽇韩等国家来说,UTF-8实在是太冗余,⼀个字符竟然要占⽤3个字节,存储和传输的效率不但没有提升,反⽽下降了。所以欧美⼈民常常毫不犹豫的采⽤UTF-8,⽽我
们却⽼是要犹豫⼀会⼉
2.变长字节表⽰带来的效率问题——⼤家对UTF-8疑虑重重的⼀个问题就是在于其因为是变长字节表⽰,因此⽆论是计算字符数,还是执⾏索引操作效率都不⾼。为了解决
这个问题,常常会考虑把UTF-8先转换为UTF-16或者UTF-32后再操作,操作完毕后再转换回去。⽽这显然是⼀种性能负担。
当然,UTF-8的优点也不能忘了:
1.字符空间⾜够⼤,未来Unicode新标准收录更多字符,UTF-8也能妥妥的兼容,因此不会再出现UTF-16那样的尴尬
2.不存在⼤⼩端字节序问题,信息交换时⾮常便捷
3.容错性⾼,局部的字节错误(丢失、增加、改变)不会导致连锁性的错误,因为UTF-8的字符边界很容易检测出来,这是⼀个巨⼤的优点(正是为了实现这⼀点,咱们中
⽇韩⼈民不得不忍受3字节1个字符的苦⽇⼦)
那么到底该如何选择呢?
因为⽆论是UTF-8和UTF-16/32都各有优缺点,因此选择的时候应当⽴⾜于实际的应⽤场景。例如在我的习惯中,存储在磁盘上或进⾏⽹络交换时都会采⽤UTF-8,⽽在程序
内部进⾏处理时则转换为UTF-16/32。对于⼤多数简单的程序来说,这样做既可以保证信息交换时容易实现相互兼容,同时在内部处理时会⽐较简单,性能也还算不错。(基本
上只要你的程序不是I/O密集型的都可以这么⼲,当然这只是我粗浅的认识范围内的经验,很可能会被⽆情的反驳)
稍微再展开那么⼀点点……
在⼀些特殊的领域,字符编码的选择会成为⼀个很关键的问题。特别是⼀些⾼性能⽹络处理程序⾥更是如此。这时采⽤⼀些特殊的设计技巧,可以缓解性能和字符集选择之间的
⽭盾。例如对于内容检测/过滤系统,需要⾯对任何可能的字符编码,这时如果还采⽤把各种不同的编码都转换为同⼀种编码后再处理的⽅案,那么性能下降将会很显著。⽽如果
采⽤多字符编码⽀持的有限状态机⽅案,则既能够⽆需转换编码,同时⼜能够以极⾼的性能进⾏处理。当然如何从规则列表⽣成有限状态机,如何使得有限状态机⽀持多编码,
以及这将带来哪些限制,已经⼜成了另外的问题了。
转换编码:
/**中⽂字符串转UTF-8与GBK码⽰例
*/
publicstaticvoidtttt()throwsException{
Stringold="⼿机银⾏";
//中⽂转换成UTF-8编码(16进制字符串)
StringBufferutf8Str=newStringBuffer();
byte[]utf8Decode=es("utf-8");
for(byteb:utf8Decode){
(tring(b&0xFF));
}
//ng()=====e6898be69cbae993b6e8a18c
//n("UTF-8字符串e6898be69cbae993b6e8a18c转换成中⽂值======"+newString(utf8Decode,"utf-8"));//-------⼿机银⾏
//中⽂转换成GBK码(16进制字符串)
StringBuffergbkStr=newStringBuffer();
byte[]gbkDecode=es("gbk");
for(byteb:gbkDecode){
(tring(b&0xFF));
}
//ng()=====cad6bbfad2f8d0d0
//n("GBK字符串cad6bbfad2f8d0d0转换成中⽂值======"+newString(gbkDecode,"gbk"));//----------⼿机银⾏
//16进制字符串转换成中⽂
byte[]bb=HexString2Bytes(ng());
bb=HexString2Bytes("CAD6BBFAD2F8D0D0");
byte[]cc=hexToByte("CAD6BBFAD2F8D0D0",20);
Stringaa=newString(bb,"gbk");
n("aa===="+aa);
}
/**
*把16进制字符串转换成字节数组
*@paramhexstr
*@return
*/
publicstaticbyte[]HexString2Bytes(Stringhexstr){
byte[]b=newbyte[()/2];
intj=0;
for(inti=0;i<;i++){
charc0=(j++);
charc1=(j++);
b[i]=(byte)((par(c0)<<4)|par(c1));
}
returnb;
}
privatestaticintpar(charc){
if(c>='a')
return(c-'a'+10)&0x0f;
if(c>='A')
return(c-'A'+10)&0x0f;
return(c-'0')&0x0f;
}
处理content-dispositionhttpheader⾥⾯。
chrome内部使⽤utf8来处理。
if(!ba::IsStringASCII(encoded_word)){
//TryUTF-8,referrer_chartandthenativeOSdefaultchartinturn.
if(ba::IsStringUTF8(encoded_word)){
*output=encoded_word;//utf8直接返回
}el{
ba::string16utf16_output;
//对应未知编码,先转成utf16,在转成utf8输出。字符集chart没有设置,就⽤系统当前默认的。windows为GBK。windows10可以⾃⼰把默认字符集改为UTF8。
if(!referrer_()&&
ConvertToUTF16(encoded_word,referrer_chart.c_str(),
&utf16_output)){
*output=ba::UTF16ToUTF8(utf16_output);
}el{
*output=ba::WideToUTF8(ba::SysNativeMBToWide(encoded_word));
}
}
*par_result_flags|=HttpContentDisposition::HAS_NON_ASCII_STRINGS;
electron层:
d:develectron7srcelectronshellbrowrapiatom_api_download_
std::stringDownloadItem::GetFilename()const{
returnba::UTF16ToUTF8(
net::GenerateFileName(GetURL(),GetContentDisposition(),std::string(),
download_item_->GetSuggestedFilename(),
GetMimeType(),"download")
.LossyDisplayName());
}
std::stringDownloadItem::GetContentDisposition()const{
returndownload_item_->GetContentDisposition();
}
还是把上⾯的分析disposition跑了⼀遍,最终到net模块的:
ba::string16GetSuggestedFilenameImpl(
constGURL&url,
conststd::string&content_disposition,
conststd::string&referrer_chart,
conststd::string&suggested_name,
conststd::string&mime_type,
conststd::string&default_name,
boolshould_replace_extension,
ReplaceIllegalCharactersFunctionreplace_illegal_characters_function){
//TODO:thisfunctiontobeupdatedtomatchthehttpbisrecommendations.
//Talktoabarthforthelatestnews.
//Wedon'ttranslatethisfallbackstring,"download".Iflocalizationis
//needed,thecallershouldprovidelocalizedfallbackin|default_name|.
staticconstba::FilePath::CharTypekFinalFallbackName[]=
FILE_PATH_LITERAL("download");
std::stringfilename;//InUTF-8
booloverwrite_extension=fal;
boolis_name_from_content_disposition=fal;
//Trytoextractafilenamefromcontent-dispositionfirst.
if(!content_()){
HttpContentDispositionheader(content_disposition,referrer_chart);
filename=me();
if(!())
is_name_from_content_disposition=true;
}
//Thentrytouthesuggestedname.
if(()&&!suggested_())
filename=suggested_name;
//eNameFromURL()only
//looksatthelastcomponentoftheURLanddoesn'treturnthehostnameasa
//failover.
if(())
filename=GetFileNameFromURL(url,referrer_chart,&overwrite_extension);
//FinallytrytheURLhostname,butonlyifthere'snodefaultspecifiedin
//|default_name|.Someschemes(e.g.:file:,about:,data:)donothavea
//hostname.
if(()&&default_()&&_valid()&&
!().empty()){
//TODO(jungshik):Decodea'punycoded'IDNhostname.(bug1264451)
filename=();
}
boolreplace_trailing=fal;
ba::FilePath::StringTyperesult_str,default_name_str;
#ifdefined(OS_WIN)
replace_trailing=true;
result_str=ba::UTF8ToUTF16(filename);
default_name_str=ba::UTF8ToUTF16(default_name);
#elifdefined(OS_POSIX)||defined(OS_FUCHSIA)
result_str=filename;
default_name_str=default_name;
#el
#errorUnsupportedplatform
#endif
SanitizeGeneratedFileName(&result_str,replace_trailing);
if(result__last_not_of(FILE_PATH_LITERAL("-_"))==
ba::FilePath::StringType::npos){
result_str=!default_name_()
default_name_str
:ba::FilePath::StringType(kFinalFallbackName);
overwrite_extension=fal;
}
replace_illegal_characters_function(&result_str,'_');
ba::FilePathresult(result_str);
overwrite_extension|=should_replace_extension;
//extensionshouldnotappendedtofilenamederivedfrom
//content-disposition,ifitdoesnothaveone.
//Hencemimetypeandoverwrite_extensionvaluesarenotud.
if(is_name_from_content_disposition)
GenerateSafeFileName("",fal,&result);
el
GenerateSafeFileName(mime_type,overwrite_extension,&result);
ba::string16result16;
if(!FilePathToString16(result,&result16)){
result=ba::FilePath(default_name_str);
if(!FilePathToString16(result,&result16)){
result=ba::FilePath(kFinalFallbackName);
FilePathToString16(result,&result16);
}
}
returnresult16;
}
ba::FilePathGenerateFileNameImpl(
constGURL&url,
conststd::string&content_disposition,
conststd::string&referrer_chart,
conststd::string&suggested_name,
conststd::string&mime_type,
conststd::string&default_file_name,
boolshould_replace_extension,
ReplaceIllegalCharactersFunctionreplace_illegal_characters_function){
ba::string16file_name=GetSuggestedFilenameImpl(
url,content_disposition,referrer_chart,suggested_name,mime_type,
default_file_name,should_replace_extension,
replace_illegal_characters_function);
#ifdefined(OS_WIN)
ba::FilePathgenerated_name(file_name);
#elifdefined(OS_POSIX)||defined(OS_FUCHSIA)
ba::FilePathgenerated_name(
ba::SysWideToNativeMB(ba::UTF16ToWide(file_name)));
#endif
DCHECK(!generated_());
returngenerated_name;
}
http⽹页跳转时调⽤:
1,
2
3
4,这⾥把原始编码做转换,会调⽤HttpContentDisposition::HttpContentDisposition的par函数,调⽤到
boolDecodeWord(conststd::string&encoded_word
5,开始远程调⽤:
6posttask到
7,转到delegate_->StartDownloadItem
8,新的download⾛:
GetNextId(ba::BindOnce(&DownloadManagerImpl::CreateNewDownloadItemToStart,
weak_factory_.GetWeakPtr(),std::move(info),
on_started,std::move(callback)));
9,再到
download::DownloadItemImpl*download=CreateActiveItem(id,*info);
10,这⾥还是没转码的值:
从跟踪代码来看,content-disposition存放的是httprespon的rawheader。
在HttpContentDisposition类的filename_成员才会存放转换了的编码。
js⾥⾯全部是utf8编码,导致gbk的响应头⽆法输出
[17240:0923/170223.551:FATAL:(210)]Checkfailed:IsStringUTF8(string_value_).
Backtrace:
ba::debug::CollectStackTrace[0x00007FFC111911E0+48](D:develectron7srcbadebugstack_trace_:284)
ba::debug::StackTrace::StackTrace[0x00007FFC11191180+80](D:develectron7srcbadebugstack_:206)
ba::debug::StackTrace::StackTrace[0x00007FFC11183B58+40](D:develectron7srcbadebugstack_:203)
logging::LogMessage::~LogMessage[0x00007FFC11203D2F+143](D::629)
ba::Value::Value[0x00007FFC114714E2+290](D::211)
ba::Value::Value[0x00007FFC114719AE+62](D::206)
std::_Default_allocator_traits
std::vector
std::vector
electron::api::`anonymousnamespace'::HttpResponHeadersToV8[0x00007FF61263D3B8+392](D:develectron7srcelectronshellbrowrapiatom_api_web_request_:115)
electron::api::`anonymousnamespace'::ToDictionary[0x00007FF61263C880+1280](D:develectron7srcelectronshellbrowrapiatom_api_web_request_:138)
electron::api::`anonymousnamespace'::FillDetails
electron::api::WebRequestNS::HandleSimpleEvent
electron::api::WebRequestNS::OnResponStarted[0x00007FF61262B430+112](D:develectron7srcelectronshellbrowrapiatom_api_web_request_:316)
electron::ProxyingURLLoaderFactory::InProgressRequest::ContinueToResponStarted[0x00007FF612709917+1079](D:develectron7srcelectronshellbrowrnetproxying_url_loader_:512)
electron::ProxyingURLLoaderFactory::InProgressRequest::OnReceiveRespon[0x00007FF612709349+265](D:develectron7srcelectronshellbrowrnetproxying_url_loader_:208)
network::mojom::URLLoaderClientStubDispatch::Accept[0x00007FF612BE9A24+980](D:develectron7srcoutTestinggenrvicesnetworkpublicmojomurl_:1191)
network::mojom::URLLoaderClientStub
mojo::InterfaceEndpointClient::HandleValidatedMessage[0x00007FFC343B8EEF+1935](D:develectron7srcmojopubliccppbindingslibinterface_endpoint_:554)
mojo::InterfaceEndpointClient::HandleIncomingMessageThunk::Accept[0x00007FFC343B8751+33](D:develectron7srcmojopubliccppbindingslibinterface_endpoint_:140)
mojo::FilterChain::Accept[0x00007FFC343B73C9+393](D:develectron7srcmojopubliccppbindingslibfilter_:40)
mojo::InterfaceEndpointClient::HandleIncomingMessage[0x00007FFC343BBCD5+213](D:develectron7srcmojopubliccppbindingslibinterface_endpoint_:357)
mojo::internal::MultiplexRouter::ProcessIncomingMessage[0x00007FFC343CE6F2+1666](D:develectron7srcmojopubliccppbindingslibmultiplex_:876)
mojo::internal::MultiplexRouter::Accept[0x00007FFC343CDC41+673](D:develectron7srcmojopubliccppbindingslibmultiplex_:598)
mojo::FilterChain::Accept[0x00007FFC343B73C9+393](D:develectron7srcmojopubliccppbindingslibfilter_:40)
mojo::Connector::DispatchMessageW[0x00007FFC3439F6F4+1396](D::513)
mojo::Connector::ReadAllAvailableMessages[0x00007FFC343A0D53+675](D::589)
mojo::Connector::OnHandleReadyInternal[0x00007FFC343A088A+378](D::424)
mojo::Connector::OnWatcherHandleReady[0x00007FFC343A06FB+27](D::384)
ba::internal::FunctorTraits
ba::internal::InvokeHelper<0,void>::MakeItSo
ba::internal::Invoker
ba::internal::Invoker
ba::RepeatingCallback
mojo::SimpleWatcher::DiscardReadyState[0x00007FFC343A36B0+32](D:develectron7srcmojopubliccppsystemsimple_watcher.h:195)
ba::internal::FunctorTraits
ba::internal::InvokeHelper<0,void>::MakeItSo
ba::internal::Invoker
ba::internal::Invoker
ba::RepeatingCallback
mojo::SimpleWatcher::OnHandleReady[0x00007FFC34A9BE11+753](D:develectron7srcmojopubliccppsystemsimple_:293)
ba::internal::FunctorTraits
ba::internal::InvokeHelper<1,void>::MakeItSo
ba::internal::Invoker
ba::internal::Invoker
ba::OnceCallback
ba::TaskAnnotator::RunTask[0x00007FFC11341335+1605](D:develectron7srcbataskcommontask_:144)
ba::quence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl[0x00007FFC113794AC+1804](D:develectron7srcbataskquence_managerthread_controller_with_message_pump_:366)
ba::quence_manager::internal::ThreadControllerWithMessagePumpImpl::DoSomeWork[0x00007FFC11378B2F+191](D:develectron7srcbataskquence_managerthread_controller_with_message_pump_:221)
ba::MessagePumpForUI::DoRunLoop[0x00007FFC11220449+457](D:develectron7srcbamessage_loopmessage_pump_:217)
ba::MessagePumpWin::Run[0x00007FFC1121EBA4+292](D:develectron7srcbamessage_loopmessage_pump_:76)
ba::quence_manager::internal::ThreadControllerWithMessagePumpImpl::Run[0x00007FFC1137A87E+910](D:develectron7srcbataskquence_managerthread_controller_with_message_pump_:467)
ba::RunLoop::Run[0x00007FFC112DE335+901](D:develectron7srcbarun_:156)
content::BrowrMainLoop::MainMessageLoopRun[0x00007FFBFEC4AADD+157](D:develectron7srccontentbrowrbrowr_main_:1511)
content::BrowrMainLoop::RunMainMessageLoopParts[0x00007FFBFEC4A8D0+528](D:develectron7srccontentbrowrbrowr_main_:1031)
content::BrowrMainRunnerImpl::Run[0x00007FFBFEC500DF+335](D:develectron7srccontentbrowrbrowr_main_runner_:149)
content::BrowrMain[0x00007FFBFEC4357C+284](D:develectron7srccontentbrowrbrowr_:47)
content::RunBrowrProcessMain[0x00007FFC0145D468+168](D:develectron7srccontentappcontent_main_runner_:556)
content::ContentMainRunnerImpl::RunServiceManager[0x00007FFC0145EC76+1334](D:develectron7srccontentappcontent_main_runner_:963)
content::ContentMainRunnerImpl::Run[0x00007FFC0145E656+614](D:develectron7srccontentappcontent_main_runner_:871)
content::ContentServiceManagerMainDelegate::RunEmbedderProcess[0x00007FFC01459BA7+55](D:develectron7srccontentappcontent_rvice_manager_main_:52)
rvice_manager::Main[0x00007FFBDA202323+1731](D:develectron7srcrvicesrvice_:423)
content::ContentMain[0x00007FFC0145D32F+95](D:develectron7srccontentappcontent_:20)
wWinMain[0x00007FF6123C20BC+1244](D:develectron7srcelectronshellappatom_:168)
invoke_main[0x00007FF6150A6B42+50](d:agent_work4ssrcvctoolscrtvcstartupsrcstartupexe_:123)
__scrt_common_main_h[0x00007FF6150A6C7E+302](d:agent_work4ssrcvctoolscrtvcstartupsrcstartupexe_:288)
__scrt_common_main[0x00007FF6150A6CFE+14](d:agent_work4ssrcvctoolscrtvcstartupsrcstartupexe_:331)
wWinMainCRTStartup[0x00007FF6150A6D19+9](d:agent_work4ssrcvctoolscrtvcstartupsrcstartupexe_:17)
BaThreadInitThunk[0x00007FFC4B4C7BD4+20]
RtlUrThreadStart[0x00007FFC4C86CE51+33]
Tasktrace:
Backtrace:
mojo::SimpleWatcher::Context::Notify[0x00007FFC34A9C590+528](D:develectron7srcmojopubliccppsystemsimple_:120)
IPCmessagehandlercontext:0x51C3F41F
在electron中,当http服务器返回httpheader是gbk的content-disposition下载时,⽂件名保存乱码。在electron调⽤时注册了onHeadersReceived回调。(写在
ady().then(functionxx)⾥⾯)
//n.
ersReceived((details,callback)=>{
//(`onHeadersReceived:url:${},details:${ify(details)}`);
("=========electrononHeadersReceived====================")
/*
for(Headers){
constlowerKey=rCa();
switch(lowerKey){
ca'x-frame-options':
ca'content-curity-policy':
//(`Receivedheader${key}:${Headers[key]}`);
Headers[key];
break;
}
}
*/
//(`Responheaders:${ify(Headers)}`);
callback({
cancel:fal,
responHeaders:Headers,
statusLine:Line,
});
});
调查发现是这⾥会检查我们要做的编码为utf8:
它是这⾥上层调⽤的:
最后我们看到在做gin::ConvertToV8转码时,对String会⽤UTF8编码:
//Returnsthefilenamedeterminedfromthelastcomponentofthepathportion
//sanemptystringiftheURLdoesn'thaveapathoris
//eneratedfilenameisnotreliable,
//|should_overwrite_extension|willbettotrue,inwhichcaabetter
//extensionshouldbedeterminedbadonthecontenttype.
std::stringGetFileNameFromURL(constGURL&url,
conststd::string&referrer_chart,
bool*should_overwrite_extension){
//about:anddata:URLsdon'thavefilenames,:URLsmay
//containpartsthatlooklikeones(i.e.,containaslash).Thereforewe
//don'tattempttodivineafilenameoutofthem.
if(!_valid()||Is("about")||Is("data"))
returnstd::string();
std::stringunescaped_url_filename=
UnescapeBinaryURLComponent(tFileName(),UnescapeRule::NORMAL);
//TheURL'spathshouldbeescapedUTF-8,butmaynotbe.
std::stringdecoded_filename=unescaped_url_filename;
if(!ba::IsStringUTF8(decoded_filename)){
//TODO(jshin):re,weneed
//encodingdetection.
ba::string16utf16_output;
if(!referrer_()&&
ConvertToUTF16(unescaped_url_filename,referrer_chart.c_str(),
&utf16_output)){
decoded_filename=ba::UTF16ToUTF8(utf16_output);
}el{
decoded_filename=
ba::WideToUTF8(ba::SysNativeMBToWide(unescaped_url_filename));
}
}
//IftheURLcontainsa(possiblyempty)query,assumeitisagenerator,and
//allowthedeterminedextensiontobeoverwritten.
*should_overwrite_extension=!decoded_()&&_query();
returndecoded_filename;
}
去掉escape字串:D:develectron7srcnetbaescape.h
本文发布于:2022-12-29 01:37:53,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/90/50309.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |