Ajuda a eliminar o loop no receptor assíncrono devido ao comprimento do conteúdo = 0 na resposta HTTP
-
20-09-2019 - |
Pergunta
Alguns servidores da Web retornam o comprimento de conteúdo definido como zero nos cabeçalhos de resposta HTTP. Eu gostaria de uma solução determinística e de desempenho para receber todos os dados nessa situação.
URL conhecido por exibir esse comportamento (URLs adicionais abaixo):
http://www.washingtonpost.com/wp-dyn/content/article/2010/02/12/ar2010021204894.html?hpid=topNews
Cabeçalhos:
Cache-control:no-cache
Connection:close
Content-Encoding:gzip
Content-type:text/html
Server:Web Server
Transfer-encoding:chunked
Minha solução atual não é garantida para obter todos os dados devido à constante maxtries e é lenta devido ao Thread.Sleep ()
private bool MoreDataIsAvailable()
{
int avail = _socket.Available;
if (avail == 0 &&
_contentLength != null && _contentLength == 0)
{
int tries = 0;
while (avail == 0 && tries < MaxTries)
{
Thread.Sleep(5);
_socket.Poll(1000, SelectMode.SelectRead);
avail = _socket.Available;
tries++;
if (avail > 0)
{
Console.WriteLine(_socket.Handle + " avail = " + avail + " received = " + _bytes.Length + " && tries = " + tries);
}
}
}
return avail > 0;
}
Uso no contexto:
private void ReceiveCallback(object sender, SocketAsyncEventArgs e)
{
if (ConnectionWasClosed(e) || HadSocketError(e))
{
_receiveDone.Set();
return;
}
StoreReceivedBytes(e);
if (AllBytesReceived())
{
_receiveDone.Set();
return;
}
if (MoreDataIsExpected() || MoreDataIsAvailable())
{
WaitForBytes(e);
}
else
{
_receiveDone.Set();
}
}
Saída de amostra:
1436 avail = 3752 received = 1704 && tries = 9
1436 avail = 3752 received = 9208 && tries = 8
1436 avail = 3752 received = 12960 && tries = 9
1436 avail = 3752 received = 20464 && tries = 8
1436 avail = 3752 received = 27968 && tries = 7
1436 avail = 7504 received = 31720 && tries = 1
1436 avail = 3752 received = 39224 && tries = 6
editar:
Nikolai observou que as respostas com um Codificação de transferência: rasgo O cabeçalho precisa de manuseio especial, mas seus fins podem ser detectados deterministicamente.
Excluindo as respostas roladas, no entanto, ainda existem outros URLs que acabam no meu método de captura, exemplos:
http://www.biomedcentral.com/1471-2105/6/197
Cabeçalhos:
Cache-control:private
Connection:close
Content-Type:text/html
P3P:policyref="/w3c/p3p.xml", CP="NOI DSP COR CURa ADMa DEVa TAIa OUR BUS PHY ONL UNI COM NAV INT DEM PRE"
Server:Microsoft-IIS/5.0
X-Powered-By:ASP.NET
http://slampp.abangadek.com/info/
Cabeçalhos:
Connection:close
Content-Type:text/html
Server:Apache/2.2.8 (Ubuntu) DAV/2 PHP/5.2.4-2ubuntu5.3 with Suhosin-Patch mod_ruby/1.2.6 Ruby/1.8.6(2007-09-24) mod_ssl/2.2.8 OpenSSL/0.9.8g
X-Cache:MISS from server03.abangadek.com
X-Powered-By:PHP/5.2.4-2ubuntu5.3
http://video.forbes.com/embedvideo/?format=frame&height=515&width=336&mode=render&networklink=1
Cabeçalhos:
Connection:close
Content-Language:en-US
Content-Type:text/html;charset=ISO-8859-1
Server:Apache-Coyote/1.1
Gostaria de saber o que posso procurar nessas respostas que, como o cabeçalho de codificação de transferência, o primeiro URL, dá uma pista para a leitura de toda a resposta deterministicamente, para que a chamada para o meu método possa ser evitada.
Solução
Do URL, pois parece que você está olhando Codificação de transferência em chunked http, o que permite que o servidor comece a transmitir a resposta antes que o comprimento total seja conhecido enquanto ainda permite que o cliente determine de maneira confiável o final da resposta.
Veja também RFC 2616, Seção 3.6.1.