зеркало из https://github.com/mozilla/gecko-dev.git
bug 599295 r=jduell
--HG-- extra : rebase_source : b376fd42a37c8b92389b43fac2e253a8466c3349
This commit is contained in:
Родитель
3f07ab58a4
Коммит
637ad95bfd
|
@ -584,6 +584,7 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
|
|||
if loc.scheme == "https" and "nocert" not in loc.options:
|
||||
customCertRE = re.compile("^cert=(?P<nickname>[0-9a-zA-Z_ ]+)")
|
||||
clientAuthRE = re.compile("^clientauth=(?P<clientauth>[a-z]+)")
|
||||
redirRE = re.compile("^redir=(?P<redirhost>[0-9a-zA-Z_ .]+)")
|
||||
for option in loc.options:
|
||||
match = customCertRE.match(option)
|
||||
if match:
|
||||
|
@ -597,6 +598,12 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
|
|||
sslTunnelConfig.write("clientauth:%s:%s:%s:%s\n" %
|
||||
(loc.host, loc.port, self.sslPort, clientauth))
|
||||
|
||||
match = redirRE.match(option)
|
||||
if match:
|
||||
redirhost = match.group("redirhost")
|
||||
sslTunnelConfig.write("redirhost:%s:%s:%s:%s\n" %
|
||||
(loc.host, loc.port, self.sslPort, redirhost))
|
||||
|
||||
sslTunnelConfig.close()
|
||||
|
||||
# Pre-create the certification database for the profile
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
# number is the default for the protocol.
|
||||
#
|
||||
# Unrecognized options are ignored. Recognized options are "primary" and
|
||||
# "privileged", "nocert", "cert=some_cert_nickname".
|
||||
# "privileged", "nocert", "cert=some_cert_nickname", "redir=hostname".
|
||||
#
|
||||
# "primary" denotes a location which is the canonical location of
|
||||
# the server; this location is the one assumed for requests which don't
|
||||
|
@ -71,6 +71,12 @@
|
|||
# directory. When new certificate is added to this dir pgo/ssltunnel
|
||||
# must be builded then.
|
||||
#
|
||||
# "redir=hostname" tells the pgo server is only used for https://
|
||||
# hosts while processing the CONNECT tunnel request. It responds
|
||||
# to the CONNECT with a 302 and redirection to the hostname instead
|
||||
# of connecting to the real back end and replying with a 200. This
|
||||
# mode exists primarily to ensure we don't allow a proxy to do that.
|
||||
#
|
||||
|
||||
#
|
||||
# This is the primary location from which tests run.
|
||||
|
@ -175,3 +181,10 @@ http://malware.example.com:80
|
|||
# Bug 483437, 484111
|
||||
https://www.bank1.com:443 privileged,cert=escapeattack1
|
||||
https://www.bank2.com:443 privileged,cert=escapeattack2
|
||||
|
||||
#
|
||||
# CONNECT for redirproxy results in a 302 redirect to
|
||||
# test1.example.com
|
||||
#
|
||||
https://redirproxy.example.com:443 privileged,redir=test1.example.com
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ _CHROME_FILES = \
|
|||
test_bug571390.xul \
|
||||
test_bug574596.html \
|
||||
test_bug683852.xul \
|
||||
test_bug599295.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=599295
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 599295</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=599295">Mozilla Bug 599295</a>
|
||||
<style type="text/css">
|
||||
#link1 a { -moz-user-select:none; }
|
||||
</style>
|
||||
<div id="link1"><a href="http://www.mozilla.org/">link1</a></div>
|
||||
<div id="link2"><a href="http://www.mozilla.org/">link2</a></div>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 599295 **/
|
||||
|
||||
/* Do not allow a response to a CONNECT method, used to establish an
|
||||
SSL tunnel over an HTTP proxy, to contain a redirect */
|
||||
|
||||
const BinaryInputStream =
|
||||
Components.Constructor("@mozilla.org/binaryinputstream;1",
|
||||
"nsIBinaryInputStream",
|
||||
"setInputStream");
|
||||
var listener = {
|
||||
_httpstatus : 0,
|
||||
|
||||
onStartRequest: function(request, context) {
|
||||
request.QueryInterface(Components.interfaces.nsIHttpChannel);
|
||||
_httpstatus = request.responseStatus;
|
||||
},
|
||||
|
||||
onDataAvailable: function(request, context, stream, offset, count) {
|
||||
new BinaryInputStream(stream).readByteArray(count);
|
||||
},
|
||||
|
||||
onStopRequest: function(request, context, status) {
|
||||
/* testing here that the redirect was not followed. If it was followed
|
||||
we would see a http status of 200 and status of NS_OK */
|
||||
|
||||
is(_httpstatus, 302, "http status 302");
|
||||
is(status, Components.results.NS_ERROR_CONNECTION_REFUSED, "raised refused");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
|
||||
function runTest() {
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
var uri = ios.newURI("https://redirproxy.example.com/test", "", null);
|
||||
var channel = ios.newChannelFromURI(uri);
|
||||
|
||||
/* Previously, necko would allow a 302 as part of a CONNECT response
|
||||
if the LOAD_DOCUMENT_URI flag was set and the original document
|
||||
URI had not yet been changed. */
|
||||
|
||||
channel.loadFlags |= Components.interfaces.nsIChannel.LOAD_DOCUMENT_URI;
|
||||
channel.QueryInterface(Components.interfaces.nsIHttpChannelInternal);
|
||||
channel.documentURI = uri;
|
||||
channel.asyncOpen(listener, null);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(runTest);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -863,18 +863,8 @@ bool
|
|||
nsHttpChannel::ShouldSSLProxyResponseContinue(PRUint32 httpStatus)
|
||||
{
|
||||
// When SSL connect has failed, allow proxy reply to continue only if it's
|
||||
// an auth request, or a redirect of a non-POST top-level document load.
|
||||
switch (httpStatus) {
|
||||
case 407:
|
||||
return true;
|
||||
case 300: case 301: case 302: case 303: case 307:
|
||||
{
|
||||
return ( (mLoadFlags & nsIChannel::LOAD_DOCUMENT_URI) &&
|
||||
mURI == mDocumentURI &&
|
||||
mRequestHead.Method() != nsHttp::Post);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
// a 407 (proxy authentication required) response
|
||||
return (httpStatus == 407);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -186,6 +186,7 @@ typedef struct {
|
|||
string cert_nickname;
|
||||
PLHashTable* host_cert_table;
|
||||
PLHashTable* host_clientauth_table;
|
||||
PLHashTable* host_redir_table;
|
||||
} server_info_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -330,7 +331,7 @@ void SignalShutdown()
|
|||
|
||||
bool ReadConnectRequest(server_info_t* server_info,
|
||||
relayBuffer& buffer, PRInt32* result, string& certificate,
|
||||
client_auth_option* clientauth, string& host)
|
||||
client_auth_option* clientauth, string& host, string& location)
|
||||
{
|
||||
if (buffer.present() < 4) {
|
||||
LOG_DEBUG((" !! only %d bytes present in the buffer", (int)buffer.present()));
|
||||
|
@ -375,13 +376,17 @@ bool ReadConnectRequest(server_info_t* server_info,
|
|||
else
|
||||
*clientauth = caNone;
|
||||
|
||||
void *redir = PL_HashTableLookup(server_info->host_redir_table, token);
|
||||
if (redir)
|
||||
location = static_cast<char*>(redir);
|
||||
|
||||
token = strtok2(_caret, "/", &_caret);
|
||||
if (strcmp(token, "HTTP")) {
|
||||
LOG_ERRORD((" not tailed with HTTP but with %s", token));
|
||||
return true;
|
||||
}
|
||||
|
||||
*result = 200;
|
||||
*result = (redir) ? 302 : 200;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -613,6 +618,7 @@ void HandleConnection(void* data)
|
|||
bool ssl_updated = !do_http_proxy;
|
||||
bool expect_request_start = do_http_proxy;
|
||||
string certificateToUse;
|
||||
string locationHeader;
|
||||
client_auth_option clientAuth;
|
||||
string fullHost;
|
||||
|
||||
|
@ -747,7 +753,7 @@ void HandleConnection(void* data)
|
|||
// We have to accept and handle the initial CONNECT request here
|
||||
PRInt32 response;
|
||||
if (!connect_accepted && ReadConnectRequest(ci->server_info, buffers[s],
|
||||
&response, certificateToUse, &clientAuth, fullHost))
|
||||
&response, certificateToUse, &clientAuth, fullHost, locationHeader))
|
||||
{
|
||||
// Mark this as a proxy-only connection (no SSL) if the CONNECT
|
||||
// request didn't come for port 443 or from any of the server's
|
||||
|
@ -776,19 +782,33 @@ void HandleConnection(void* data)
|
|||
connect_accepted = true;
|
||||
|
||||
// Store response to the oposite buffer
|
||||
if (response != 200)
|
||||
if (response == 200)
|
||||
{
|
||||
LOG_DEBUG((" accepted CONNECT request, connected to the server, sending OK to the client\n"));
|
||||
strcpy(buffers[s2].buffer, "HTTP/1.1 200 Connected\r\nConnection: keep-alive\r\n\r\n");
|
||||
}
|
||||
else if (response == 302)
|
||||
{
|
||||
LOG_DEBUG((" accepted CONNECT request with redirection, "
|
||||
"sending location and 302 to the client\n"));
|
||||
client_done = true;
|
||||
sprintf(buffers[s2].buffer,
|
||||
"HTTP/1.1 302 Moved\r\n"
|
||||
"Location: https://%s/\r\n"
|
||||
"Connection: close\r\n\r\n",
|
||||
locationHeader.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERRORD((" could not read the connect request, closing connection with %d", response));
|
||||
client_done = true;
|
||||
sprintf(buffers[s2].buffer, "HTTP/1.1 %d ERROR\r\nConnection: close\r\n\r\n", response);
|
||||
buffers[s2].buffertail = buffers[s2].buffer + strlen(buffers[s2].buffer);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
strcpy(buffers[s2].buffer, "HTTP/1.1 200 Connected\r\nConnection: keep-alive\r\n\r\n");
|
||||
buffers[s2].buffertail = buffers[s2].buffer + strlen(buffers[s2].buffer);
|
||||
|
||||
LOG_DEBUG((" accepted CONNECT request, connected to the server, sending OK to the client\n"));
|
||||
// Send the response to the client socket
|
||||
break;
|
||||
} // end of CONNECT handling
|
||||
|
@ -1106,6 +1126,12 @@ int processConfigLine(char* configLine)
|
|||
LOG_ERROR(("Internal, could not create hash table\n"));
|
||||
return 1;
|
||||
}
|
||||
server.host_redir_table = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, PL_CompareStrings, NULL, NULL);
|
||||
if (!server.host_redir_table)
|
||||
{
|
||||
LOG_ERROR(("Internal, could not create hash table\n"));
|
||||
return 1;
|
||||
}
|
||||
servers.push_back(server);
|
||||
}
|
||||
|
||||
|
@ -1172,6 +1198,51 @@ int processConfigLine(char* configLine)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(keyword, "redirhost"))
|
||||
{
|
||||
char* hostname = strtok2(_caret, ":", &_caret);
|
||||
char* hostportstring = strtok2(_caret, ":", &_caret);
|
||||
char* serverportstring = strtok2(_caret, ":", &_caret);
|
||||
|
||||
int port = atoi(serverportstring);
|
||||
if (port <= 0) {
|
||||
LOG_ERROR(("Invalid port specified: %s\n", serverportstring));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (server_info_t* existingServer = findServerInfo(port))
|
||||
{
|
||||
char* redirhoststring = strtok2(_caret, ":", &_caret);
|
||||
|
||||
any_host_spec_config = true;
|
||||
|
||||
char *hostname_copy = new char[strlen(hostname)+strlen(hostportstring)+2];
|
||||
if (!hostname_copy) {
|
||||
LOG_ERROR(("Out of memory"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
strcpy(hostname_copy, hostname);
|
||||
strcat(hostname_copy, ":");
|
||||
strcat(hostname_copy, hostportstring);
|
||||
|
||||
char *redir_copy = new char[strlen(redirhoststring)+1];
|
||||
strcpy(redir_copy, redirhoststring);
|
||||
PLHashEntry* entry = PL_HashTableAdd(existingServer->host_redir_table, hostname_copy, redir_copy);
|
||||
if (!entry) {
|
||||
LOG_ERROR(("Out of memory"));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(("Server on port %d for redirhost option is not defined, use 'listen' option first", port));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Configure the NSS certificate database directory
|
||||
if (!strcmp(keyword, "certdbdir"))
|
||||
{
|
||||
|
@ -1232,6 +1303,13 @@ PRIntn freeHostCertHashItems(PLHashEntry *he, PRIntn i, void *arg)
|
|||
return HT_ENUMERATE_REMOVE;
|
||||
}
|
||||
|
||||
PRIntn freeHostRedirHashItems(PLHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
delete [] (char*)he->key;
|
||||
delete [] (char*)he->value;
|
||||
return HT_ENUMERATE_REMOVE;
|
||||
}
|
||||
|
||||
PRIntn freeClientAuthHashItems(PLHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
delete [] (char*)he->key;
|
||||
|
@ -1370,8 +1448,10 @@ int main(int argc, char** argv)
|
|||
{
|
||||
PL_HashTableEnumerateEntries(it->host_cert_table, freeHostCertHashItems, NULL);
|
||||
PL_HashTableEnumerateEntries(it->host_clientauth_table, freeClientAuthHashItems, NULL);
|
||||
PL_HashTableEnumerateEntries(it->host_redir_table, freeHostRedirHashItems, NULL);
|
||||
PL_HashTableDestroy(it->host_cert_table);
|
||||
PL_HashTableDestroy(it->host_clientauth_table);
|
||||
PL_HashTableDestroy(it->host_redir_table);
|
||||
}
|
||||
|
||||
PR_Cleanup();
|
||||
|
|
Загрузка…
Ссылка в новой задаче