将 http 压缩响应的精确副本复制到字符串中
Exact copy of http gzipped response into a string
我需要帮助。
我正在尝试获取网站内容,其中 Content-encoding 是 gzip,dmd v2.066.1 在 Windows 上。
这是我的测试网址:“http://diaboli.pl/test2.html
”。
我的 HTTP 请求是:
GET /test2.html HTTP/1.1
Host: diaboli.pl
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: pl,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
User-Agent: My Browser
Referer: http://google.pl
DNT: 1
服务器响应是:
HTTP/1.1 200 OK
Date: Sat, 24 Jan 2015 23:02:00 GMT
Server: Apache
Last-Modified: Sat, 24 Jan 2015 22:48:44 GMT
ETag: "5c468ad-83f-50d6db511eb00"
Accept-Ranges: bytes
Vary: Accept-Encoding,User-Agent
Content-Encoding: gzip
Content-Length: 942
Content-Type: text/html
.)┘R!SĽ╣ň┌KRB:éş^»{█ĺ.ç}aOě_DźŢ░▼'dĘ$ëĚk\|j\pý§Ěí▀k║Ź■ß♠┐}ú2žŢ ´dĹĺńMłÎ▒└╚‼/§B⌂Ĺ▬°'˘uŕNá☺■█Ór↓m(┘đ▬Ţ┼ńĺ╦⌂
§gŰůqýä╗˘%p▬■&B♂M]§Üú3ý^ý-ÎD`x!Ő╔&M♥~╣y╬uşëňZ@▒]˘ä2}Ś╣xdÄyWüm§?ąě░Äd4,d‼î-▬
┬♣Bön°6{őu└♀☺█UĂ└,aF˘├☼☻OŔ˛mţË▄▀Čó¸ö31ÎňEÖKŮţĄîÔŐ←ôň¸HÉ┌bŤ}Dnń'ń9┌
Îă♠¶U♣VI^▲hËőŃ└_zďĆ6┬6█¨}{╝╦ÄřeđŠoŤčů¤űU´öěŁ*ŠxĂ☻(,─AôlZ»Ú^ß溸ő╬↓M`¬PË═qí¨Ýç▼7╣§y♫<J╬ÓŇëb#PćR§bˇĽ>Ěz╣┴âž7uř┐ `$SřítR¶╗u ź☻‼ĘXçf☺°NH▄˛☻ şp─RĄ►¬w╬8GN║K) ;ĺ\ÝŇľ♫╩┼╬|ABYÍţ∟═Yů+╔y?ťkVĐ┼
nş║☼jv¶ĐSô9Dů♠▓Ç˙üK╬2\˝d[☼ <ľ┘Ń↓ü╠âG ˇ¸
ľyŇđd■ß▲e☼¸♣e_ÂśúQ÷śń,ÖŬ[N╝b┼Ř└ŕ↓ÚcS┴3╗╠w▀[ş↕ĺŽCňđś↕⌂═őç˛ţHW∟d=╩║Y►│Ô]sČšX§_ˇ↔ĹCČŤI┬y┤ŕ▲╬Ő↕╩§┌}í m\∟Öç#<W*Ű┐h˘g2SęćĐqš►EËý üXđ.S▀kš2←↑►â☼Ň5Ę╬♀6∟\←B|fđşÚ*ZŽ%▀Î↓@ěEŕ♦TNgcż,→‼│→p-←î˘ă☻p$Ř%ôe
♠♀ŻýŁ8JiŔ▒"L■♀óą↨Č┘´☻«┌:ŰńĹ>♣§╝×░♂öĄT`=BÂ|5mˇ|Ňs)ŐRĹ═▒é┴\yru▬ć=Rďĺ]↔ŰýÉĆ☼─ć↑¬pZÇ▓9PC§ę4 ×@ş Ź☺╬ňLj█Á¨uĄ:│§Bšš∟ďŃ?▼nvO!0↔}î*╠aŢ ţh
Ľ*7Îĺ$vn ŔIŘM¸♀˙¶ÎŞŞb⌂♫äý"´♂çK}⌂Y♀ ♣XŽëM
如您所见,它是一个 gzip 编码的内容。服务器响应使用 write() 函数逐个字符地打印出 cmd 控制台。
问题是,我无法准确复制响应字符串。如果我尝试,我得到了这个结果:
HTTP/1.1 200 OK
Date: Sat, 24 Jan 2015 23:02:00 GMT
Server: Apache
Last-Modified: Sat, 24 Jan 2015 22:48:44 GMT
ETag: "5c468ad-83f-50d6db511eb00"
Accept-Ranges: bytes
Vary: Accept-Encoding,User-Agent
Content-Encoding: gzip
Content-Length: 942
Content-Type: text/html
▼ő
我可以确定内容的长度,它与HTTP Content-Length header 值相等,但我可以看到,它与一个一个的原始字符串不同。
同样有趣的是,我可以使用 zlib uncompress() 函数解压缩那个错误的内容字符串,它不会 return zlib 数据错误,而是剪切解压缩的内容。
当然,FF、IE等浏览器显示完整的解压内容是没有问题的。
我是这样连接到服务器的:
import std.stdio, import std.string, std.conv, std.socket, std.stream, std.socketstream, std.zlib;
ushort port=80; string domain="diaboli.pl";
string request_uri; int[] pos; string request; string buffer; string znak; string line;
int contentlength=-1; int[] postab; string bodybuffer; string headerbuffer; int readingbody=0;
std.zlib.UnCompress u; const(void)[] udata;
Socket sock = new TcpSocket(new InternetAddress(domain, port));
Stream ss = new SocketStream(sock);
request="GET " ~ request_uri ~ " HTTP/1.1\r\n";
request~="Host: " ~ domain ~ "\r\n";
request~="Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
request~="Accept-Language: pl,en-US;q=0.7,en;q=0.3\r\n";
request~="Accept-Encoding: gzip, deflate\r\n";
request~="User-Agent: My Browser\r\n";
request~="Referer: http://google.pl\r\n";
request~="DNT: 1\r\n";
request~="\r\n";
writeln("HTTP request:\n---");
writeln(request);
writeln("---");
ss.writeString(request);
writeln("\nAll response from the server character by character:\n---");
line="";
while (1)
{
if (readingbody==1) readingbody=2; //the way to separate headers and the content - first part.
znak = to!string(ss.getc());
if (ss.eof()) break;
line~=znak;
//if (readingbody==2)
write(znak);
if (znak=="\n")
{
if (strpos(line,"Content-Length: ")>-1)
{
postab ~= strpos(line,"\r");
postab ~= strpos(line,"\n");
contentlength=to!int(substr(line,16,postab.sort[0]-16));
}
if (readingbody==0 && line=="\r\n") readingbody=1;
line="";
}
buffer ~= znak;
//the way to separate headers and the content - second part.
if (readingbody==0 && line=="\r\n") readingbody=1;
if (readingbody==2) bodybuffer ~= znak;
else headerbuffer ~= znak;
}
sock.close();
writeln("\n---");
write("Content-Length="); writeln(contentlength); //This is the Content-Length determined from the HTTP Content-Length header.
write("bodybuffer.length="); writeln(bodybuffer.length); //This the length of the content string
writeln("\nAll response copied into the string:\n---");
writeln(buffer);
writeln("---\nOnly content:\n---");
writeln(bodybuffer);
writeln("---\nUncompressed:\n---");
u = new UnCompress(HeaderFormat.determineFromData);
udata = u.uncompress(bodybuffer);
writeln(cast(string)udata);
//These are my simple text processing functions similar to php.
int strpos(string str,string tofind,int caseinsensitive=0)
{
int pos=-1;
if (caseinsensitive==1)
{
str=toUpper(str);
tofind=toUpper(tofind);
}
if (str.length>=tofind.length)
{
for(int i=0;i<str.length;i++)
{
if (i+tofind.length>str.length) break;
if (str[i..i+tofind.length]==tofind)
{
pos=i;
break;
}
}
}
return pos;
}
string substr(string str,int pos, int offset)
{
string substring="";
if (str.length>0 && pos>-1 && offset>0)
{
substring=str[pos..pos+offset];
}
return substring;
}
您的代码存在三个问题:
您使用 Stream.getc
,它会进行换行转换。这会破坏二进制数据。您可以通过替换来解决此问题:
znak = to!string(ss.getc());
与:
char c; ss.readBlock(&c, 1); znak = to!string(c);
虽然最好完全避免std.stream
,但它是等待被替换的古老代码。
您指定的 HTTP 版本为 1.1,因此服务器发回带有 Transfer-Encoding: chunked
的内容。您的程序无法处理此传输编码。您可以将协议版本更改为 1.0.
当使用 std.zlib
类 时,您必须在管道传输所有数据后调用 flush
。添加此行:
udata ~= u.flush();
经过这些更改,您的程序对我来说工作正常。
我需要帮助。
我正在尝试获取网站内容,其中 Content-encoding 是 gzip,dmd v2.066.1 在 Windows 上。
这是我的测试网址:“http://diaboli.pl/test2.html
”。
我的 HTTP 请求是:
GET /test2.html HTTP/1.1
Host: diaboli.pl
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: pl,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
User-Agent: My Browser
Referer: http://google.pl
DNT: 1
服务器响应是:
HTTP/1.1 200 OK
Date: Sat, 24 Jan 2015 23:02:00 GMT
Server: Apache
Last-Modified: Sat, 24 Jan 2015 22:48:44 GMT
ETag: "5c468ad-83f-50d6db511eb00"
Accept-Ranges: bytes
Vary: Accept-Encoding,User-Agent
Content-Encoding: gzip
Content-Length: 942
Content-Type: text/html
.)┘R!SĽ╣ň┌KRB:éş^»{█ĺ.ç}aOě_DźŢ░▼'dĘ$ëĚk\|j\pý§Ěí▀k║Ź■ß♠┐}ú2žŢ ´dĹĺńMłÎ▒└╚‼/§B⌂Ĺ▬°'˘uŕNá☺■█Ór↓m(┘đ▬Ţ┼ńĺ╦⌂
§gŰůqýä╗˘%p▬■&B♂M]§Üú3ý^ý-ÎD`x!Ő╔&M♥~╣y╬uşëňZ@▒]˘ä2}Ś╣xdÄyWüm§?ąě░Äd4,d‼î-▬
┬♣Bön°6{őu└♀☺█UĂ└,aF˘├☼☻OŔ˛mţË▄▀Čó¸ö31ÎňEÖKŮţĄîÔŐ←ôň¸HÉ┌bŤ}Dnń'ń9┌
Îă♠¶U♣VI^▲hËőŃ└_zďĆ6┬6█¨}{╝╦ÄřeđŠoŤčů¤űU´öěŁ*ŠxĂ☻(,─AôlZ»Ú^ß溸ő╬↓M`¬PË═qí¨Ýç▼7╣§y♫<J╬ÓŇëb#PćR§bˇĽ>Ěz╣┴âž7uř┐ `$SřítR¶╗u ź☻‼ĘXçf☺°NH▄˛☻ şp─RĄ►¬w╬8GN║K) ;ĺ\ÝŇľ♫╩┼╬|ABYÍţ∟═Yů+╔y?ťkVĐ┼
nş║☼jv¶ĐSô9Dů♠▓Ç˙üK╬2\˝d[☼ <ľ┘Ń↓ü╠âG ˇ¸
ľyŇđd■ß▲e☼¸♣e_ÂśúQ÷śń,ÖŬ[N╝b┼Ř└ŕ↓ÚcS┴3╗╠w▀[ş↕ĺŽCňđś↕⌂═őç˛ţHW∟d=╩║Y►│Ô]sČšX§_ˇ↔ĹCČŤI┬y┤ŕ▲╬Ő↕╩§┌}í m\∟Öç#<W*Ű┐h˘g2SęćĐqš►EËý üXđ.S▀kš2←↑►â☼Ň5Ę╬♀6∟\←B|fđşÚ*ZŽ%▀Î↓@ěEŕ♦TNgcż,→‼│→p-←î˘ă☻p$Ř%ôe
♠♀ŻýŁ8JiŔ▒"L■♀óą↨Č┘´☻«┌:ŰńĹ>♣§╝×░♂öĄT`=BÂ|5mˇ|Ňs)ŐRĹ═▒é┴\yru▬ć=Rďĺ]↔ŰýÉĆ☼─ć↑¬pZÇ▓9PC§ę4 ×@ş Ź☺╬ňLj█Á¨uĄ:│§Bšš∟ďŃ?▼nvO!0↔}î*╠aŢ ţh
Ľ*7Îĺ$vn ŔIŘM¸♀˙¶ÎŞŞb⌂♫äý"´♂çK}⌂Y♀ ♣XŽëM
如您所见,它是一个 gzip 编码的内容。服务器响应使用 write() 函数逐个字符地打印出 cmd 控制台。 问题是,我无法准确复制响应字符串。如果我尝试,我得到了这个结果:
HTTP/1.1 200 OK
Date: Sat, 24 Jan 2015 23:02:00 GMT
Server: Apache
Last-Modified: Sat, 24 Jan 2015 22:48:44 GMT
ETag: "5c468ad-83f-50d6db511eb00"
Accept-Ranges: bytes
Vary: Accept-Encoding,User-Agent
Content-Encoding: gzip
Content-Length: 942
Content-Type: text/html
▼ő
我可以确定内容的长度,它与HTTP Content-Length header 值相等,但我可以看到,它与一个一个的原始字符串不同。
同样有趣的是,我可以使用 zlib uncompress() 函数解压缩那个错误的内容字符串,它不会 return zlib 数据错误,而是剪切解压缩的内容。 当然,FF、IE等浏览器显示完整的解压内容是没有问题的。
我是这样连接到服务器的:
import std.stdio, import std.string, std.conv, std.socket, std.stream, std.socketstream, std.zlib;
ushort port=80; string domain="diaboli.pl";
string request_uri; int[] pos; string request; string buffer; string znak; string line;
int contentlength=-1; int[] postab; string bodybuffer; string headerbuffer; int readingbody=0;
std.zlib.UnCompress u; const(void)[] udata;
Socket sock = new TcpSocket(new InternetAddress(domain, port));
Stream ss = new SocketStream(sock);
request="GET " ~ request_uri ~ " HTTP/1.1\r\n";
request~="Host: " ~ domain ~ "\r\n";
request~="Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
request~="Accept-Language: pl,en-US;q=0.7,en;q=0.3\r\n";
request~="Accept-Encoding: gzip, deflate\r\n";
request~="User-Agent: My Browser\r\n";
request~="Referer: http://google.pl\r\n";
request~="DNT: 1\r\n";
request~="\r\n";
writeln("HTTP request:\n---");
writeln(request);
writeln("---");
ss.writeString(request);
writeln("\nAll response from the server character by character:\n---");
line="";
while (1)
{
if (readingbody==1) readingbody=2; //the way to separate headers and the content - first part.
znak = to!string(ss.getc());
if (ss.eof()) break;
line~=znak;
//if (readingbody==2)
write(znak);
if (znak=="\n")
{
if (strpos(line,"Content-Length: ")>-1)
{
postab ~= strpos(line,"\r");
postab ~= strpos(line,"\n");
contentlength=to!int(substr(line,16,postab.sort[0]-16));
}
if (readingbody==0 && line=="\r\n") readingbody=1;
line="";
}
buffer ~= znak;
//the way to separate headers and the content - second part.
if (readingbody==0 && line=="\r\n") readingbody=1;
if (readingbody==2) bodybuffer ~= znak;
else headerbuffer ~= znak;
}
sock.close();
writeln("\n---");
write("Content-Length="); writeln(contentlength); //This is the Content-Length determined from the HTTP Content-Length header.
write("bodybuffer.length="); writeln(bodybuffer.length); //This the length of the content string
writeln("\nAll response copied into the string:\n---");
writeln(buffer);
writeln("---\nOnly content:\n---");
writeln(bodybuffer);
writeln("---\nUncompressed:\n---");
u = new UnCompress(HeaderFormat.determineFromData);
udata = u.uncompress(bodybuffer);
writeln(cast(string)udata);
//These are my simple text processing functions similar to php.
int strpos(string str,string tofind,int caseinsensitive=0)
{
int pos=-1;
if (caseinsensitive==1)
{
str=toUpper(str);
tofind=toUpper(tofind);
}
if (str.length>=tofind.length)
{
for(int i=0;i<str.length;i++)
{
if (i+tofind.length>str.length) break;
if (str[i..i+tofind.length]==tofind)
{
pos=i;
break;
}
}
}
return pos;
}
string substr(string str,int pos, int offset)
{
string substring="";
if (str.length>0 && pos>-1 && offset>0)
{
substring=str[pos..pos+offset];
}
return substring;
}
您的代码存在三个问题:
您使用
Stream.getc
,它会进行换行转换。这会破坏二进制数据。您可以通过替换来解决此问题:znak = to!string(ss.getc());
与:
char c; ss.readBlock(&c, 1); znak = to!string(c);
虽然最好完全避免
std.stream
,但它是等待被替换的古老代码。您指定的 HTTP 版本为 1.1,因此服务器发回带有
Transfer-Encoding: chunked
的内容。您的程序无法处理此传输编码。您可以将协议版本更改为 1.0.当使用
std.zlib
类 时,您必须在管道传输所有数据后调用flush
。添加此行:udata ~= u.flush();
经过这些更改,您的程序对我来说工作正常。