зеркало из https://github.com/mozilla/pjs.git
bug 87047. Handle keep-alives from http/1.1 servers properly. Patch by me
and darin, r=gagan, sr=dougt
This commit is contained in:
Родитель
914543da03
Коммит
30e033d985
|
@ -168,7 +168,11 @@ nsHttpChannel::Init(nsIURI *uri,
|
||||||
rv = mRequestHead.SetHeader(nsHttp::Host, hostLine);
|
rv = mRequestHead.SetHeader(nsHttp::Host, hostLine);
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
rv = nsHttpHandler::get()->AddStandardRequestHeaders(&mRequestHead.Headers(), caps);
|
PRBool useProxy = (proxyHost && !PL_strcmp(proxyType, "http"));
|
||||||
|
|
||||||
|
rv = nsHttpHandler::get()->AddStandardRequestHeaders(&mRequestHead.Headers(),
|
||||||
|
caps,
|
||||||
|
useProxy);
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
// check to see if authorization headers should be included
|
// check to see if authorization headers should be included
|
||||||
|
|
|
@ -39,6 +39,9 @@
|
||||||
|
|
||||||
static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID);
|
static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID);
|
||||||
|
|
||||||
|
// Default timeout in seconds, if the server doesn't give us one (eg http/1.1)
|
||||||
|
#define HTTP_DEFAULT_TIMEOUT 10
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// nsHttpConnection <public>
|
// nsHttpConnection <public>
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -146,32 +149,50 @@ nsHttpConnection::OnHeadersAvailable(nsHttpTransaction *trans, PRBool *reset)
|
||||||
const char *val = trans->ResponseHead()->PeekHeader(nsHttp::Connection);
|
const char *val = trans->ResponseHead()->PeekHeader(nsHttp::Connection);
|
||||||
if (!val)
|
if (!val)
|
||||||
val = trans->ResponseHead()->PeekHeader(nsHttp::Proxy_Connection);
|
val = trans->ResponseHead()->PeekHeader(nsHttp::Proxy_Connection);
|
||||||
if (val) {
|
|
||||||
// be pesimistic
|
|
||||||
mKeepAlive = PR_FALSE;
|
|
||||||
|
|
||||||
if (PL_strcasecmp(val, "keep-alive") == 0) {
|
if ((trans->ResponseHead()->Version() < NS_HTTP_VERSION_1_1) ||
|
||||||
|
(nsHttpHandler::get()->DefaultVersion() < NS_HTTP_VERSION_1_1)) {
|
||||||
|
// HTTP/1.0 connections are by default NOT persistent
|
||||||
|
if (val && !PL_strcasecmp(val, "keep-alive"))
|
||||||
mKeepAlive = PR_TRUE;
|
mKeepAlive = PR_TRUE;
|
||||||
|
else
|
||||||
|
mKeepAlive = PR_FALSE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// HTTP/1.1 connections are by default persistent
|
||||||
|
if (val && !PL_strcasecmp(val, "close"))
|
||||||
|
mKeepAlive = PR_FALSE;
|
||||||
|
else
|
||||||
|
mKeepAlive = PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
val = trans->ResponseHead()->PeekHeader(nsHttp::Keep_Alive);
|
// if this connection is persistent, then the server may send a "Keep-Alive"
|
||||||
|
// header specifying the maximum number of times the connection can be
|
||||||
|
// reused as well as the maximum amount of time the connection can be idle
|
||||||
|
// before the server will close it. If this header is not present, then we
|
||||||
|
// pick a suitably large number. Technically, any number > 0 will do, since
|
||||||
|
// we reset this each time, and with HTTP/1.1 connections continue until we
|
||||||
|
// get a {Proxy-,}Connection: close header. Don't just use 1 though, because
|
||||||
|
// of pipelining
|
||||||
|
if (mKeepAlive) {
|
||||||
|
val = trans->ResponseHead()->PeekHeader(nsHttp::Keep_Alive);
|
||||||
|
|
||||||
LOG(("val = [%s]\n", val));
|
LOG(("val = [%s]\n", val));
|
||||||
|
|
||||||
const char *cp = PL_strcasestr(val, "max=");
|
const char *cp = PL_strcasestr(val, "max=");
|
||||||
if (cp)
|
if (cp)
|
||||||
mMaxReuseCount = (PRUint32) atoi(cp + 4);
|
mMaxReuseCount = (PRUint32) atoi(cp + 4);
|
||||||
else
|
else
|
||||||
mMaxReuseCount = 100;
|
mMaxReuseCount = 100;
|
||||||
|
|
||||||
cp = PL_strcasestr(val, "timeout=");
|
cp = PL_strcasestr(val, "timeout=");
|
||||||
if (cp)
|
if (cp)
|
||||||
mIdleTimeout = (PRUint32) atoi(cp + 8);
|
mIdleTimeout = (PRUint32) atoi(cp + 8);
|
||||||
else
|
else
|
||||||
mIdleTimeout = 10;
|
mIdleTimeout = HTTP_DEFAULT_TIMEOUT;
|
||||||
|
|
||||||
LOG(("Connection can be reused [this=%x max-reuse=%u "
|
LOG(("Connection can be reused [this=%x max-reuse=%u "
|
||||||
"keep-alive-timeout=%u\n", this, mMaxReuseCount, mIdleTimeout));
|
"keep-alive-timeout=%u\n", this, mMaxReuseCount, mIdleTimeout));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we're doing an SSL proxy connect, then we need to check whether or not
|
// if we're doing an SSL proxy connect, then we need to check whether or not
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
* Christopher Blizzard <blizzard@mozilla.org>
|
* Christopher Blizzard <blizzard@mozilla.org>
|
||||||
* Adrian Havill <havill@redhat.com>
|
* Adrian Havill <havill@redhat.com>
|
||||||
* Gervase Markham <gerv@gerv.net>
|
* Gervase Markham <gerv@gerv.net>
|
||||||
|
* Bradley Baetz <bbaetz@netscape.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "nsHttp.h"
|
#include "nsHttp.h"
|
||||||
|
@ -242,46 +243,56 @@ nsHttpHandler::Init()
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsHttpHandler::AddStandardRequestHeaders(nsHttpHeaderArray *request,
|
nsHttpHandler::AddStandardRequestHeaders(nsHttpHeaderArray *request,
|
||||||
PRUint32 caps)
|
PRUint32 caps,
|
||||||
|
PRBool useProxy)
|
||||||
{
|
{
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
|
||||||
LOG(("nsHttpHandler::AddStandardRequestHeaders\n"));
|
LOG(("nsHttpHandler::AddStandardRequestHeaders\n"));
|
||||||
|
|
||||||
// Add the User-Agent header:
|
// Add the "User-Agent" header
|
||||||
rv = request->SetHeader(nsHttp::User_Agent, UserAgent());
|
rv = request->SetHeader(nsHttp::User_Agent, UserAgent());
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
// MIME based content negotiation lives!
|
// MIME based content negotiation lives!
|
||||||
// Add the Accept header:
|
// Add the "Accept" header
|
||||||
rv = request->SetHeader(nsHttp::Accept, mAccept.get());
|
rv = request->SetHeader(nsHttp::Accept, mAccept.get());
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
// Add the Accept-Language header:
|
// Add the "Accept-Language" header
|
||||||
rv = request->SetHeader(nsHttp::Accept_Language, mAcceptLanguages.get());
|
rv = request->SetHeader(nsHttp::Accept_Language, mAcceptLanguages.get());
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
// Add the Accept-Encoding header:
|
// Add the "Accept-Encoding" header
|
||||||
rv = request->SetHeader(nsHttp::Accept_Encoding, mAcceptEncodings.get());
|
rv = request->SetHeader(nsHttp::Accept_Encoding, mAcceptEncodings.get());
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
// Add the Accept-Charset header:
|
// Add the "Accept-Charset" header
|
||||||
rv = request->SetHeader(nsHttp::Accept_Charset, mAcceptCharsets.get());
|
rv = request->SetHeader(nsHttp::Accept_Charset, mAcceptCharsets.get());
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
// Add the Connection header:
|
// RFC2616 section 19.6.2 states that the "Connection: keep-alive"
|
||||||
const char *connectionType = "close";
|
// and "Keep-alive" request headers should not be sent by HTTP/1.1
|
||||||
if (caps && ALLOW_KEEPALIVE) {
|
// user-agents. Otherwise, problems with proxy servers (especially
|
||||||
|
// transparent proxies) can result.
|
||||||
|
// However, we need to send something so that we can use keepalive
|
||||||
|
// with HTTP/1.0 servers/proxies. We use Proxy-Connection: when we're
|
||||||
|
// talking to an http proxy, and Connection: otherwise
|
||||||
|
|
||||||
|
const char* connectionType = "close";
|
||||||
|
if (caps & ALLOW_KEEPALIVE) {
|
||||||
char buf[32];
|
char buf[32];
|
||||||
|
|
||||||
PR_snprintf(buf, sizeof(buf), "%d", mIdleTimeout);
|
PR_snprintf(buf, sizeof(buf), "%d", mIdleTimeout);
|
||||||
|
|
||||||
rv = request->SetHeader(nsHttp::Keep_Alive, buf);
|
rv = request->SetHeader(nsHttp::Keep_Alive, buf);
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
connectionType = "keep-alive";
|
connectionType = "keep-alive";
|
||||||
}
|
}
|
||||||
return request->SetHeader(nsHttp::Connection, connectionType);
|
|
||||||
|
const nsHttpAtom& connAtom = useProxy ? nsHttp::Proxy_Connection : nsHttp::Connection;
|
||||||
|
return request->SetHeader(connAtom, connectionType);
|
||||||
}
|
}
|
||||||
|
|
||||||
PRBool
|
PRBool
|
||||||
|
|
|
@ -81,7 +81,8 @@ public:
|
||||||
|
|
||||||
nsresult Init();
|
nsresult Init();
|
||||||
nsresult AddStandardRequestHeaders(nsHttpHeaderArray *,
|
nsresult AddStandardRequestHeaders(nsHttpHeaderArray *,
|
||||||
PRUint32 capabilities);
|
PRUint32 capabilities,
|
||||||
|
PRBool useProxy);
|
||||||
PRBool IsAcceptableEncoding(const char *encoding);
|
PRBool IsAcceptableEncoding(const char *encoding);
|
||||||
|
|
||||||
const char *UserAgent();
|
const char *UserAgent();
|
||||||
|
|
|
@ -390,6 +390,7 @@ nsHttpResponseHead::UpdateHeaders(nsHttpHeaderArray &headers)
|
||||||
|
|
||||||
// Ignore any hop-by-hop headers...
|
// Ignore any hop-by-hop headers...
|
||||||
if (header == nsHttp::Connection ||
|
if (header == nsHttp::Connection ||
|
||||||
|
header == nsHttp::Proxy_Connection ||
|
||||||
header == nsHttp::Keep_Alive ||
|
header == nsHttp::Keep_Alive ||
|
||||||
header == nsHttp::Proxy_Authenticate ||
|
header == nsHttp::Proxy_Authenticate ||
|
||||||
header == nsHttp::Proxy_Authorization || // not a response header!
|
header == nsHttp::Proxy_Authorization || // not a response header!
|
||||||
|
|
Загрузка…
Ссылка в новой задаче