Make HTTP->HTTPS redirection more robust

This commit is contained in:
fgenesis 2015-10-01 21:16:52 +02:00
parent 0060208acb
commit 238a7f3208

View file

@ -307,6 +307,8 @@ void TcpSocket::close(void)
if(!SOCKETVALID(_s)) if(!SOCKETVALID(_s))
return; return;
traceprint("TcpSocket::close\n");
_OnCloseInternal(); _OnCloseInternal();
#ifdef MINIHTTP_USE_POLARSSL #ifdef MINIHTTP_USE_POLARSSL
@ -659,6 +661,7 @@ bool TcpSocket::update(void)
SetBufsizeIn(DEFAULT_BUFSIZE); SetBufsizeIn(DEFAULT_BUFSIZE);
int bytes = _readBytes((unsigned char*)_writeptr, _writeSize); int bytes = _readBytes((unsigned char*)_writeptr, _writeSize);
traceprint("TcpSocket::update: _readBytes() result %d\n", bytes);
if(bytes > 0) // we received something if(bytes > 0) // we received something
{ {
_inbuf[bytes] = 0; _inbuf[bytes] = 0;
@ -677,8 +680,7 @@ bool TcpSocket::update(void)
} }
else // whoops, error? else // whoops, error?
{ {
int e = _GetError(); switch(bytes)
switch(e)
{ {
case EWOULDBLOCK: case EWOULDBLOCK:
#if defined(EAGAIN) && (EWOULDBLOCK != EAGAIN) #if defined(EAGAIN) && (EWOULDBLOCK != EAGAIN)
@ -686,17 +688,19 @@ bool TcpSocket::update(void)
#endif #endif
return false; return false;
#ifdef MINIHTTP_USE_POLARSSL
case POLARSSL_ERR_NET_WANT_READ:
break; // Try again later
#endif
default: default:
traceprint("SOCKET UPDATE ERROR: (%d): %s\n", e, _GetErrorStr(e).c_str()); traceprint("SOCKET UPDATE ERROR: (%d): %s\n", bytes, _GetErrorStr(bytes).c_str());
case ECONNRESET: case ECONNRESET:
case ENOTCONN: case ENOTCONN:
case ETIMEDOUT: case ETIMEDOUT:
#ifdef _WIN32 #ifdef _WIN32
case WSAECONNABORTED: case WSAECONNABORTED:
case WSAESHUTDOWN: case WSAESHUTDOWN:
#endif
#ifdef MINIHTTP_USE_POLARSSL
case 0: // no error from the network API, but notification that the SSL connection was terminated
#endif #endif
close(); close();
break; break;
@ -731,6 +735,7 @@ void HttpSocket::_OnOpen()
{ {
TcpSocket::_OnOpen(); TcpSocket::_OnOpen();
_chunkedTransfer = false; _chunkedTransfer = false;
_mustClose = true;
} }
void HttpSocket::_OnCloseInternal() void HttpSocket::_OnCloseInternal()
@ -747,6 +752,8 @@ bool HttpSocket::_OnUpdate()
if(_inProgress && !_chunkedTransfer && !_remaining && _status) if(_inProgress && !_chunkedTransfer && !_remaining && _status)
_FinishRequest(); _FinishRequest();
traceprint("HttpSocket::_OnUpdate, Q = %d\n", (unsigned)_requestQ.size());
// initiate transfer if queue is not empty, but the socket somehow forgot to proceed // initiate transfer if queue is not empty, but the socket somehow forgot to proceed
if(_requestQ.size() && !_remaining && !_chunkedTransfer && !_inProgress) if(_requestQ.size() && !_remaining && !_chunkedTransfer && !_inProgress)
_DequeueMore(); _DequeueMore();
@ -759,6 +766,8 @@ bool HttpSocket::Download(const std::string& url, const char *extraRequest /*=
Request req; Request req;
req.user = user; req.user = user;
SplitURI(url, req.host, req.resource, req.port, req.useSSL); SplitURI(url, req.host, req.resource, req.port, req.useSSL);
if(req.host.empty()) // if we're following a redirection to the same host, the server is likely to omit its hostname
req.host = _curRequest.host;
if(req.port < 0) if(req.port < 0)
req.port = req.useSSL ? 443 : 80; req.port = req.useSSL ? 443 : 80;
if(extraRequest) if(extraRequest)
@ -821,22 +830,26 @@ bool HttpSocket::SendGet(Request& req, bool enqueue)
bool HttpSocket::_EnqueueOrSend(const Request& req, bool forceQueue /* = false */) bool HttpSocket::_EnqueueOrSend(const Request& req, bool forceQueue /* = false */)
{ {
traceprint("HttpSocket::_EnqueueOrSend, forceQueue = %d\n", forceQueue);
if(_inProgress || forceQueue) // do not send while receiving other data if(_inProgress || forceQueue) // do not send while receiving other data
{ {
traceprint("HTTP: Transfer pending; putting into queue. Now %u waiting.\n", (unsigned int)_requestQ.size()); // DEBUG traceprint("HTTP: Transfer pending; putting into queue. Now %u waiting.\n", (unsigned int)_requestQ.size());
_requestQ.push(req); _requestQ.push(req);
return true; return true;
} }
// ok, we can send directly // ok, we can send directly
traceprint("HTTP: Open request for immediate send.\n");
if(!_OpenRequest(req)) if(!_OpenRequest(req))
return false; return false;
_inProgress = SendBytes(req.header.c_str(), req.header.length()); bool sent = SendBytes(req.header.c_str(), req.header.length());
return _inProgress; _inProgress = sent;
return sent;
} }
// called whenever a request is finished completely and the socket checks for more things to send // called whenever a request is finished completely and the socket checks for more things to send
void HttpSocket::_DequeueMore(void) void HttpSocket::_DequeueMore(void)
{ {
traceprint("HttpSocket::_DequeueMore, Q = %u\n", (unsigned)_requestQ.size());
_FinishRequest(); // In case this was not done yet. _FinishRequest(); // In case this was not done yet.
// _inProgress is known to be false here // _inProgress is known to be false here
@ -869,12 +882,16 @@ bool HttpSocket::_OpenRequest(const Request& req)
void HttpSocket::_FinishRequest(void) void HttpSocket::_FinishRequest(void)
{ {
traceprint("HttpSocket::_FinishRequest\n");
if(_inProgress) if(_inProgress)
{ {
traceprint("... in progress. redirecting = %d\n", IsRedirecting());
if(!IsRedirecting() || _alwaysHandle) if(!IsRedirecting() || _alwaysHandle)
_OnRequestDone(); // notify about finished request _OnRequestDone(); // notify about finished request
_inProgress = false; _inProgress = false;
_hdrs.clear(); _hdrs.clear();
if(_mustClose)
close();
} }
} }
@ -994,6 +1011,8 @@ bool HttpSocket::_HandleStatus()
if(!(_chunkedTransfer || _contentLen) && _status == 200) if(!(_chunkedTransfer || _contentLen) && _status == 200)
traceprint("_ParseHeader: Not chunked transfer and content-length==0, this will go fail"); traceprint("_ParseHeader: Not chunked transfer and content-length==0, this will go fail");
traceprint("Got HTTP Status %d\n", _status);
switch(_status) switch(_status)
{ {
case 200: case 200:
@ -1152,6 +1171,7 @@ bool SocketSet::update(void)
interesting = sock->update() || interesting; interesting = sock->update() || interesting;
if(sdata.deleteWhenDone && !sock->isOpen() && !sock->HasPendingTask()) if(sdata.deleteWhenDone && !sock->isOpen() && !sock->HasPendingTask())
{ {
traceprint("Delete socket\n");
delete sock; delete sock;
_store.erase(it++); _store.erase(it++);
} }