Partially fix 34743. Handle 100 (Continue) responses. Add an exclusion list

for servers with broken 1.1/pipelining. Fire onstop in case of the error on
all queued up channels in the pipeline.
This commit is contained in:
ruslan%netscape.com 2000-04-13 20:48:19 +00:00
Родитель d2b46f5318
Коммит 39f7fc06c6
6 изменённых файлов: 144 добавлений и 47 удалений

Просмотреть файл

@ -47,6 +47,7 @@ interface nsIHTTPProtocolHandler : nsIProtocolHandler
const unsigned long ALLOW_PROXY_KEEPALIVE = 4;
const unsigned long ALLOW_PROXY_PIPELINING = 8;
const unsigned long DONTRECORD_CAPABILITIES = 16;
const unsigned long DONTALLOW_HTTP11 = 32;
/**
*
@ -152,6 +153,12 @@ interface nsIHTTPProtocolHandler : nsIProtocolHandler
readonly attribute unsigned long capabilities;
readonly attribute unsigned long keepAliveTimeout;
/**
* Check for bad server and return the capabilites supported by
* such server
*/
unsigned long Check4BrokenHTTPServers (in string serverHeader);
};
%{C++

Просмотреть файл

@ -1413,3 +1413,33 @@ nsHTTPHandler::ReleasePipelinedRequest (nsHTTPPipelinedRequest *pReq)
return NS_OK;
}
static BrokenServersTable brokenServers_well_known [] =
{
{ "Netscape-Enterprise 3.6", nsHTTPHandler::BAD_SERVERS_MATCH_EXACT , 0}, // 3.6 but not 3.6 SPx - keep-alive is broken
{ "Apache 1.2" , nsHTTPHandler::BAD_SERVERS_MATCH_ALL , nsIHTTPProtocolHandler::DONTALLOW_HTTP11} // chunk-encoding returns garbage sometimes
};
NS_IMETHODIMP
nsHTTPHandler::Check4BrokenHTTPServers (const char * a_Server, PRUint32 * a_Capabilities)
{
if (a_Capabilities == NULL)
return NS_ERROR_NULL_POINTER;
for (int i = 0; i < sizeof (brokenServers_well_known) / sizeof (BrokenServersTable); i++)
{
BrokenServersTable *tP = &brokenServers_well_known[i];
if (tP -> matchFlags == BAD_SERVERS_MATCH_EXACT && !PL_strcmp (tP -> serverHeader, a_Server))
{
*a_Capabilities = tP -> capabilities;
break;
}
else
if (tP -> matchFlags == BAD_SERVERS_MATCH_ALL && !PL_strncmp (tP -> serverHeader, a_Server, strlen (tP -> serverHeader)))
{
*a_Capabilities = tP -> capabilities;
break;
}
}
return NS_OK;
}

Просмотреть файл

@ -65,6 +65,14 @@ class nsHTTPChannel;
#define DEFAULT_HTTP_CONNECT_TIMEOUT 30
#define DEFAULT_MAX_ALLOWED_KEEPALIVES 30
typedef struct BrokenServersTable_s
{
const char *serverHeader;
PRUint32 matchFlags;
PRUint32 capabilities;
} BrokenServersTable;
class nsHTTPPipelinedRequest;
class nsIHTTPChannel;
@ -114,6 +122,10 @@ public:
nsresult GetPipelinedRequest (nsIHTTPChannel* i_Channel, nsHTTPPipelinedRequest ** o_Req);
nsresult ReleasePipelinedRequest (nsHTTPPipelinedRequest *pReq);
enum BrokenServerMatchFlags {
BAD_SERVERS_MATCH_EXACT, BAD_SERVERS_MATCH_ALL
};
protected:
virtual ~nsHTTPHandler();
nsresult InitUserAgentComponents();
@ -167,7 +179,6 @@ private:
PRUint32 getCapabilities (const char *host, PRInt32 port, PRUint32 cap);
void setCapabilities (nsIChannel* i_pTrans, PRUint32 aCapabilities);
};
#endif /* _nsHTTPHandler_h_ */

Просмотреть файл

@ -388,7 +388,7 @@ nsHTTPRequest::formHeaders (PRUint32 capabilities)
nsresult
nsHTTPRequest::formBuffer (nsCString * requestBuffer)
nsHTTPRequest::formBuffer (nsCString * requestBuffer, PRUint32 capabilities)
{
nsXPIDLCString autoBuffer;
nsresult rv;
@ -431,7 +431,8 @@ nsHTTPRequest::formBuffer (nsCString * requestBuffer)
httpVersion = " HTTP/0.9"CRLF;
break;
case HTTP_ONE_ONE:
httpVersion = " HTTP/1.1"CRLF;
if (! (capabilities & NS_STATIC_CAST (unsigned long, nsIHTTPProtocolHandler::DONTALLOW_HTTP11)) )
httpVersion = " HTTP/1.1"CRLF;
}
requestBuffer -> Append (httpVersion);
@ -617,7 +618,7 @@ nsHTTPPipelinedRequest::WriteRequest ()
for (index = mTotalWritten - mTotalProcessed; index < count; index++)
{
req = (nsHTTPRequest *) mRequests -> ElementAt (index);
req -> formBuffer (&mRequestBuffer);
req -> formBuffer (&mRequestBuffer, mCapabilities);
if (index == 0)
mTransport -> SetNotificationCallbacks (req -> mConnection);
@ -789,22 +790,29 @@ nsHTTPPipelinedRequest::OnStopRequest (nsIChannel* channel, nsISupports* i_Conte
}
}
// XXX/ruslan: we need to walk through all the requests !!!!!!!!!!!!!!
nsCOMPtr<nsIStreamListener> consumer;
req -> mConnection -> GetResponseDataListener (getter_AddRefs (consumer));
if (consumer)
req -> mConnection -> ResponseCompleted (consumer, rv, i_Msg);
// Notify the HTTPChannel that the request has finished
if (mTransport)
while (req)
{
nsIChannel *p = mTransport;
mTransport = null_nsCOMPtr ();
nsCOMPtr<nsIStreamListener> consumer;
req -> mConnection -> GetResponseDataListener (getter_AddRefs (consumer));
mHandler -> ReleaseTransport (p, nsIHTTPProtocolHandler::DONTRECORD_CAPABILITIES);
if (consumer)
req -> mConnection -> ResponseCompleted (consumer, rv, i_Msg);
// Notify the HTTPChannel that the request has finished
if (mTransport)
{
nsIChannel *p = mTransport;
mTransport = null_nsCOMPtr ();
mHandler -> ReleaseTransport (p, nsIHTTPProtocolHandler::DONTRECORD_CAPABILITIES);
}
NS_IF_RELEASE (req);
req = nsnull;
if (NS_SUCCEEDED (AdvanceToNextRequest ()))
GetCurrentRequest (&req);
}
}

Просмотреть файл

@ -127,7 +127,7 @@ public:
nsCOMPtr<nsIInputStream> mPostDataStream;
nsresult formHeaders (PRUint32 capabilities);
nsresult formBuffer (nsCString * reqBuffer);
nsresult formBuffer (nsCString * reqBuffer, PRUint32 capabilities);
nsHTTPPipelinedRequest* mPipelinedRequest;
nsHTTPChannel* mConnection;

Просмотреть файл

@ -281,39 +281,45 @@ nsHTTPServerListener::OnDataAvailable(nsIChannel* channel,
if (i_Length > 0)
mDataReceived = PR_TRUE;
if (!mResponse)
while (!mHeadersDone)
{
mResponse = new nsHTTPResponse ();
if (!mResponse) {
NS_ERROR("Failed to create the response object!");
return NS_ERROR_OUT_OF_MEMORY;
if (!mResponse)
{
mResponse = new nsHTTPResponse ();
if (!mResponse)
{
NS_ERROR("Failed to create the response object!");
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ADDREF (mResponse);
mChannel -> SetResponse (mResponse);
}
NS_ADDREF(mResponse);
mChannel->SetResponse(mResponse);
}
//
// Parse the status line and the response headers from the server
//
if (!mHeadersDone) {
//
// Parse the status line and the response headers from the server
//
//
// Parse the status line from the server. This is always the
// first line of the response...
//
if (!mFirstLineParsed) {
if (!mFirstLineParsed)
{
rv = ParseStatusLine(bufferInStream, i_Length, &actualBytesRead);
NS_ASSERTION(i_Length - actualBytesRead <= i_Length, "wrap around");
i_Length -= actualBytesRead;
}
PR_LOG(gHTTPLog, PR_LOG_ALWAYS,
("\tOnDataAvailable [this=%x]. Parsing Headers\n", this));
PR_LOG (gHTTPLog, PR_LOG_ALWAYS,
("\tOnDataAvailable [this=%x]. Parsing Headers\n", this));
//
// Parse the response headers as long as there is more data and
// the headers are not done...
//
while (NS_SUCCEEDED(rv) && i_Length && !mHeadersDone) {
while (NS_SUCCEEDED(rv) && i_Length && !mHeadersDone)
{
rv = ParseHTTPHeader(bufferInStream, i_Length, &actualBytesRead);
NS_ASSERTION(i_Length - actualBytesRead <= i_Length, "wrap around");
NS_ASSERTION (i_Length - actualBytesRead <= i_Length, "wrap around");
i_Length -= actualBytesRead;
}
@ -326,15 +332,18 @@ nsHTTPServerListener::OnDataAvailable(nsIChannel* channel,
//
// All the headers have been read.
//
rv = FinishedResponseHeaders ();
if (NS_FAILED(rv)) return rv;
if (mResponse)
{
PRUint32 statusCode = 0;
mResponse -> GetStatus (&statusCode);
if (statusCode == 304) // no content
{
rv = FinishedResponseHeaders ();
if (NS_FAILED (rv))
return rv;
rv = mPipelinedRequest -> AdvanceToNextRequest ();
if (NS_FAILED (rv))
{
@ -352,8 +361,30 @@ nsHTTPServerListener::OnDataAvailable(nsIChannel* channel,
OnStartRequest (nsnull, nsnull);
}
}
}
}
else
if (statusCode == 100) // Continue
{
mHeadersDone = PR_FALSE;
mFirstLineParsed = PR_FALSE;
mHeaderBuffer.Truncate ();
mChannel -> SetResponse (nsnull);
NS_RELEASE (mResponse);
mResponse = nsnull;
mBytesReceived = 0;
PR_LOG (gHTTPLog, PR_LOG_DEBUG,
("\tOnDataAvailable [this=%x]. (100) Continue\n", this));
}
else
{
rv = FinishedResponseHeaders ();
if (NS_FAILED (rv))
return rv;
}
} /* mResponse */
} /* while (!mHeadersDone) */
// At this point we've digested headers from the server and we're
// onto the actual data. If this transaction was initiated without
@ -455,17 +486,17 @@ nsHTTPServerListener::OnDataAvailable(nsIChannel* channel,
if (mPipelinedRequest
&& (cl != -1 && cl - mBodyBytesReceived == 0 || eof))
{
nsresult rv = mPipelinedRequest -> AdvanceToNextRequest ();
nsresult rv1 = mPipelinedRequest -> AdvanceToNextRequest ();
if (NS_FAILED (rv))
if (NS_FAILED (rv1))
{
mHandler -> ReleasePipelinedRequest (mPipelinedRequest);
mPipelinedRequest = nsnull;
nsCOMPtr<nsISocketTransport> trans = do_QueryInterface (channel, &rv);
nsCOMPtr<nsISocketTransport> trans = do_QueryInterface (channel, &rv1);
// XXX/ruslan: will be replaced with the new Cancel (code)
if (NS_SUCCEEDED (rv))
if (NS_SUCCEEDED (rv1))
trans -> SetBytesExpected (0);
}
@ -595,6 +626,7 @@ nsHTTPServerListener::OnStopRequest (nsIChannel* channel, nsISupports* i_pContex
if (status != 304 || !mChannel -> mCachedResponse)
{
mChannel -> ResponseCompleted (mResponseDataListener, i_Status, i_pMsg);
mChannel -> mHTTPServerListener = 0;
}
@ -620,17 +652,26 @@ nsHTTPServerListener::OnStopRequest (nsIChannel* channel, nsISupports* i_pContex
if (ver == HTTP_ONE_ONE )
{
// ruslan: some older incorrect 1.1 servers may do this
if (NS_SUCCEEDED (rv) && connectionHeader && !PL_strcmp (connectionHeader, "close" ))
if (NS_SUCCEEDED (rv) && connectionHeader && !PL_strcasecmp (connectionHeader, "close" ))
capabilities = 0;
else
{
capabilities = (usingProxy ? nsIHTTPProtocolHandler::ALLOW_PROXY_KEEPALIVE|nsIHTTPProtocolHandler::ALLOW_PROXY_PIPELINING : nsIHTTPProtocolHandler::ALLOW_KEEPALIVE|nsIHTTPProtocolHandler::ALLOW_PIPELINING);
nsXPIDLCString serverHeader;
rv = mResponse -> GetHeader (nsHTTPAtoms::Server, getter_Copies (serverHeader));
if (NS_SUCCEEDED (rv))
mHandler -> Check4BrokenHTTPServers (serverHeader, &capabilities);
}
}
else
if (ver == HTTP_ONE_ZERO)
{
if (NS_SUCCEEDED (rv) && connectionHeader && !PL_strcmp (connectionHeader, "keep-alive"))
if (NS_SUCCEEDED (rv) && connectionHeader && !PL_strcasecmp (connectionHeader, "keep-alive"))
capabilities = (usingProxy ? NS_STATIC_CAST (unsigned long, nsIHTTPProtocolHandler::ALLOW_PROXY_KEEPALIVE) : NS_STATIC_CAST (unsigned long, nsIHTTPProtocolHandler::ALLOW_KEEPALIVE));
}
}
}
@ -654,7 +695,7 @@ nsHTTPServerListener::OnStopRequest (nsIChannel* channel, nsISupports* i_pContex
NS_IF_RELEASE (mChannel );
NS_IF_RELEASE (mResponse);
return rv;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////