Bug 572570 - backed out changeset 90ade0c197ed due to linux m0 oranges

This commit is contained in:
Jonathan Griffin 2010-07-26 16:01:06 -07:00
parent e1a1e214a6
commit 889921576e
3 changed files with 90 additions and 120 deletions

View File

@ -60,6 +60,7 @@ _DEFAULT_WEB_SERVER = "127.0.0.1"
_DEFAULT_HTTP_PORT = 8888
_DEFAULT_SSL_PORT = 4443
_DEFAULT_WEBSOCKET_PORT = 9988
_DEFAULT_WEBSOCKET_PROXY_PORT = 7777
#expand _DIST_BIN = __XPC_BIN_PATH__
#expand _IS_WIN32 = len("__WIN32__") != 0
@ -154,6 +155,7 @@ class Automation(object):
DEFAULT_HTTP_PORT = _DEFAULT_HTTP_PORT
DEFAULT_SSL_PORT = _DEFAULT_SSL_PORT
DEFAULT_WEBSOCKET_PORT = _DEFAULT_WEBSOCKET_PORT
DEFAULT_WEBSOCKET_PROXY_PORT = _DEFAULT_WEBSOCKET_PROXY_PORT
def __init__(self):
self.log = _log
@ -163,11 +165,13 @@ class Automation(object):
webServer = _DEFAULT_WEB_SERVER,
httpPort = _DEFAULT_HTTP_PORT,
sslPort = _DEFAULT_SSL_PORT,
webSocketPort = _DEFAULT_WEBSOCKET_PORT):
webSocketPort = _DEFAULT_WEBSOCKET_PORT,
webSocketProxyPort = _DEFAULT_WEBSOCKET_PROXY_PORT):
self.webServer = webServer
self.httpPort = httpPort
self.sslPort = sslPort
self.webSocketPort = webSocketPort
self.webSocketProxyPort = webSocketProxyPort
@property
def __all__(self):
@ -402,13 +406,16 @@ function FindProxyForURL(url, host)
return 'DIRECT';
if (isHttp)
return 'PROXY %(remote)s:%(httpport)s';
if (isHttps || isWebSocket)
if (isHttps)
return 'PROXY %(remote)s:%(sslport)s';
if (isWebSocket)
return 'PROXY %(remote)s:%(websocketproxyport)s';
return 'DIRECT';
}""" % { "origins": origins,
"remote": self.webServer,
"httpport":self.httpPort,
"sslport": self.sslPort }
"sslport": self.sslPort,
"websocketproxyport": self.webSocketProxyPort }
pacURL = "".join(pacURL.splitlines())
part += """
@ -455,7 +462,8 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
sslTunnelConfig.write("httpproxy:1\n")
sslTunnelConfig.write("certdbdir:%s\n" % certPath)
sslTunnelConfig.write("forward:127.0.0.1:%s\n" % self.httpPort)
sslTunnelConfig.write("websocketserver:%s:%s\n" % (self.webServer, self.webSocketPort))
sslTunnelConfig.write("proxy:%s:%s:%s\n" %
(self.webSocketProxyPort, self.webServer, self.webSocketPort))
sslTunnelConfig.write("listen:*:%s:pgo server certificate\n" % self.sslPort)
# Configure automatic certificate and bind custom certificates, client authentication

View File

@ -267,6 +267,7 @@ See <http://mochikit.com/doc/html/MochiKit/Logging.html> for details on the logg
options.httpPort = self._automation.DEFAULT_HTTP_PORT
options.sslPort = self._automation.DEFAULT_SSL_PORT
options.webSocketPort = self._automation.DEFAULT_WEBSOCKET_PORT
options.webSocketProxyPort = self._automation.DEFAULT_WEBSOCKET_PROXY_PORT
if options.vmwareRecording:
if not self._automation.IS_WIN32:
@ -723,7 +724,8 @@ def main():
automation.setServerInfo(options.webServer,
options.httpPort,
options.sslPort,
options.webSocketPort)
options.webSocketPort,
options.webSocketProxyPort)
sys.exit(mochitest.runTests(options))
if __name__ == "__main__":

View File

@ -121,29 +121,26 @@ typedef struct {
string cert_nickname;
PLHashTable* host_cert_table;
PLHashTable* host_clientauth_table;
// If not empty, and this server is using HTTP CONNECT, connections
// will be proxied to this address.
PRNetAddr remote_addr;
// True if no SSL should be used for this server's connections.
bool http_proxy_only;
// The original host in the Host: header for the initial connection is
// stored here, for proxied connections.
string original_host;
} server_info_t;
typedef struct {
PRFileDesc* client_sock;
PRNetAddr client_addr;
server_info_t* server_info;
// the original host in the Host: header for this connection is
// stored here, for proxied connections
string original_host;
// true if no SSL should be used for this connection
bool http_proxy_only;
// true if this connection is for a WebSocket
bool iswebsocket;
} connection_info_t;
typedef struct {
string fullHost;
bool matched;
} server_match_t;
const PRInt32 BUF_SIZE = 16384;
const PRInt32 BUF_MARGIN = 1024;
const PRInt32 BUF_TOTAL = BUF_SIZE + BUF_MARGIN;
const char HEADER_HOST[] = "Host:";
struct relayBuffer
{
@ -220,7 +217,6 @@ const PRUint32 DEFAULT_STACKSIZE = (512 * 1024);
string nssconfigdir;
vector<server_info_t> servers;
PRNetAddr remote_addr;
PRNetAddr websocket_server;
PRThreadPool* threads = NULL;
PRLock* shutdown_lock = NULL;
PRCondVar* shutdown_condvar = NULL;
@ -241,14 +237,6 @@ PR_CALLBACK PRIntn ClientAuthValueComparator(const void *v1, const void *v2)
return -1;
}
static PRIntn match_hostname(PLHashEntry *he, PRIntn index, void* arg)
{
server_match_t *match = (server_match_t*)arg;
if (match->fullHost.find((char*)he->key) != string::npos)
match->matched = true;
return HT_ENUMERATE_NEXT;
}
/*
* Signal the main thread that the application should shut down.
*/
@ -366,15 +354,15 @@ bool ConfigureSSLServerSocket(PRFileDesc* socket, server_info_t* si, string &cer
* This function examines the buffer for a S5ec-WebSocket-Location: field,
* and if it's present, it replaces the hostname in that field with the
* value in the server's original_host field. This function works
* in the reverse direction as AdjustWebSocketHost(), replacing the real
* hostname of a response with the potentially fake hostname that is expected
* in the reverse direction as AdjustHost(), replacing the real hostname
* of a response with the potentially fake hostname that is expected
* by the browser (e.g., mochi.test).
*
* @return true if the header was adjusted successfully, or not found, false
* if the header is present but the url is not, which should indicate
* that more data needs to be read from the socket
*/
bool AdjustWebSocketLocation(relayBuffer& buffer, connection_info_t *ci)
bool AdjustWebSocketLocation(relayBuffer& buffer, server_info_t *si)
{
assert(buffer.margin());
buffer.buffertail[1] = '\0';
@ -394,16 +382,16 @@ bool AdjustWebSocketLocation(relayBuffer& buffer, connection_info_t *ci)
char *crlf = strstr(wsloc, "\r\n");
if (!crlf)
return false;
if (ci->original_host.empty())
if (si->original_host.empty())
return true;
int diff = ci->original_host.length() - (wslocend-wsloc);
int diff = si->original_host.length() - (wslocend-wsloc);
if (diff > 0)
assert(size_t(diff) <= buffer.margin());
memmove(wslocend + diff, wslocend, buffer.buffertail - wsloc - diff);
buffer.buffertail += diff;
memcpy(wsloc, ci->original_host.c_str(), ci->original_host.length());
memcpy(wsloc, si->original_host.c_str(), si->original_host.length());
return true;
}
@ -415,13 +403,10 @@ bool AdjustWebSocketLocation(relayBuffer& buffer, connection_info_t *ci)
* replaced with the host that the destination server is actually running
* on.
*/
bool AdjustWebSocketHost(relayBuffer& buffer, connection_info_t *ci)
bool AdjustHost(relayBuffer& buffer, server_info_t *si)
{
const char HEADER_UPGRADE[] = "Upgrade:";
const char HEADER_HOST[] = "Host:";
PRNetAddr inet_addr = (websocket_server.inet.port ? websocket_server :
remote_addr);
if (!si->remote_addr.inet.port)
return false;
assert(buffer.margin());
@ -429,16 +414,6 @@ bool AdjustWebSocketHost(relayBuffer& buffer, connection_info_t *ci)
// space left because we preserve a margin.
buffer.buffertail[1] = '\0';
// Verify this is a WebSocket header.
char* h1 = strstr(buffer.bufferhead, HEADER_UPGRADE);
if (!h1)
return false;
h1 += strlen(HEADER_UPGRADE);
h1 += strspn(h1, " \t");
char* h2 = strstr(h1, "WebSocket\r\n");
if (!h2)
return false;
char* host = strstr(buffer.bufferhead, HEADER_HOST);
if (!host)
return false;
@ -452,12 +427,12 @@ bool AdjustWebSocketHost(relayBuffer& buffer, connection_info_t *ci)
// Save the original host, so we can use it later on responses from the
// server.
ci->original_host.assign(host, endhost-host);
si->original_host.assign(host, endhost-host);
char newhost[40];
PR_NetAddrToString(&inet_addr, newhost, sizeof(newhost));
PR_NetAddrToString(&si->remote_addr, newhost, sizeof(newhost));
assert(strlen(newhost) < sizeof(newhost) - 7);
sprintf(newhost, "%s:%d", newhost, PR_ntohs(inet_addr.inet.port));
sprintf(newhost, "%s:%d", newhost, PR_ntohs(si->remote_addr.inet.port));
int diff = strlen(newhost) - (endhost-host);
if (diff > 0)
@ -557,7 +532,7 @@ void HandleConnection(void* data)
if (!do_http_proxy)
{
if (!ci->http_proxy_only &&
if (!ci->server_info->http_proxy_only &&
!ConfigureSSLServerSocket(ci->client_sock, ci->server_info, certificateToUse, caNone))
client_error = true;
else if (!ConnectSocket(other_sock, &remote_addr, connect_timeout))
@ -677,33 +652,12 @@ void HandleConnection(void* data)
if (!connect_accepted && ReadConnectRequest(ci->server_info, buffers[s],
&response, certificateToUse, &clientAuth, fullHost))
{
// 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
// cert or clientauth hostnames.
if (fullHost.find(":443") == string::npos)
{
server_match_t match;
match.fullHost = fullHost;
match.matched = false;
PL_HashTableEnumerateEntries(ci->server_info->host_cert_table,
match_hostname,
&match);
PL_HashTableEnumerateEntries(ci->server_info->host_clientauth_table,
match_hostname,
&match);
ci->http_proxy_only = !match.matched;
}
else
{
ci->http_proxy_only = false;
}
// Clean the request as it would be read
buffers[s].bufferhead = buffers[s].buffertail = buffers[s].buffer;
in_flags |= PR_POLL_WRITE;
connect_accepted = true;
// Store response to the opposite buffer
// Store response to the oposite buffer
if (response != 200)
{
printf(" could not read the connect request, closing connection with %d", response);
@ -716,6 +670,16 @@ void HandleConnection(void* data)
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);
PRNetAddr* addr = &remote_addr;
if (ci->server_info->remote_addr.inet.port > 0)
addr = &ci->server_info->remote_addr;
if (!ConnectSocket(other_sock, addr, connect_timeout))
{
printf(" could not open connection to the real server\n");
client_error = true;
break;
}
printf(" accepted CONNECT request, connected to the server, sending OK to the client\n");
// Send the response to the client socket
break;
@ -732,31 +696,14 @@ void HandleConnection(void* data)
{
if (s == 0 && expect_request_start)
{
if (!strstr(buffers[s].bufferhead, "\r\n\r\n"))
{
// We haven't received the complete header yet, so wait.
continue;
}
if (ci->server_info->http_proxy_only)
expect_request_start = !AdjustHost(buffers[s], ci->server_info);
else
{
ci->iswebsocket = AdjustWebSocketHost(buffers[s], ci);
expect_request_start = !(ci->iswebsocket ||
AdjustRequestURI(buffers[s], &fullHost));
PRNetAddr* addr = &remote_addr;
if (ci->iswebsocket && websocket_server.inet.port)
addr = &websocket_server;
if (!ConnectSocket(other_sock, addr, connect_timeout))
{
printf(" could not open connection to the real server\n");
client_error = true;
break;
}
printf("\n connected to remote server\n");
}
expect_request_start = !AdjustRequestURI(buffers[s], &fullHost);
}
else if (s == 1 && ci->iswebsocket)
else
{
if (!AdjustWebSocketLocation(buffers[s], ci))
if (!AdjustWebSocketLocation(buffers[s], ci->server_info))
continue;
}
@ -770,7 +717,7 @@ void HandleConnection(void* data)
if (out_flags & PR_POLL_WRITE)
{
printf(" :writing");
printf(" :writting");
PRInt32 bytesWrite = PR_Send(sockets[s].fd, buffers[s2].bufferhead,
buffers[s2].present(), 0, PR_INTERVAL_NO_TIMEOUT);
@ -806,7 +753,7 @@ void HandleConnection(void* data)
printf(" proxy response sent to the client");
// Proxy response has just been writen, update to ssl
ssl_updated = true;
if (!ci->http_proxy_only &&
if (!ci->server_info->http_proxy_only &&
!ConfigureSSLServerSocket(ci->client_sock, ci->server_info, certificateToUse, clientAuth))
{
printf(" but failed to config server socket\n");
@ -945,23 +892,6 @@ int processConfigLine(char* configLine)
return 0;
}
if (!strcmp(keyword, "websocketserver"))
{
char* ipstring = strtok2(_caret, ":", &_caret);
if (PR_StringToNetAddr(ipstring, &websocket_server) != PR_SUCCESS) {
fprintf(stderr, "Invalid IP address in proxy config: %s\n", ipstring);
return 1;
}
char* remoteport = strtok2(_caret, ":", &_caret);
int port = atoi(remoteport);
if (port <= 0) {
fprintf(stderr, "Invalid remote port in proxy config: %s\n", remoteport);
return 1;
}
websocket_server.inet.port = PR_htons(port);
return 0;
}
// Configure the forward address of the target server
if (!strcmp(keyword, "forward"))
{
@ -981,6 +911,35 @@ int processConfigLine(char* configLine)
return 0;
}
if (!strcmp(keyword, "proxy"))
{
server_info_t server;
server.host_cert_table = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, PL_CompareStrings, NULL, NULL);
server.host_clientauth_table = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, ClientAuthValueComparator, NULL, NULL);
server.http_proxy_only = true;
char* listenport = strtok2(_caret, ":", &_caret);
server.listen_port = atoi(listenport);
if (server.listen_port <= 0) {
fprintf(stderr, "Invalid listen port in proxy config: %s\n", listenport);
return 1;
}
char* ipstring = strtok2(_caret, ":", &_caret);
if (PR_StringToNetAddr(ipstring, &server.remote_addr) != PR_SUCCESS) {
fprintf(stderr, "Invalid IP address in proxy config: %s\n", ipstring);
return 1;
}
char* remoteport = strtok2(_caret, ":", &_caret);
int port = atoi(remoteport);
if (port <= 0) {
fprintf(stderr, "Invalid remote port in proxy config: %s\n", remoteport);
return 1;
}
server.remote_addr.inet.port = PR_htons(port);
servers.push_back(server);
return 0;
}
// Configure all listen sockets and port+certificate bindings
if (!strcmp(keyword, "listen"))
{
@ -1020,8 +979,10 @@ int processConfigLine(char* configLine)
else
{
server_info_t server;
memset(&server.remote_addr, 0, sizeof(PRNetAddr));
server.cert_nickname = certnick;
server.listen_port = port;
server.http_proxy_only = false;
server.host_cert_table = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, PL_CompareStrings, NULL, NULL);
if (!server.host_cert_table)
{
@ -1175,8 +1136,6 @@ int main(int argc, char** argv)
else
configFilePath = argv[1];
memset(&websocket_server, 0, sizeof(PRNetAddr));
if (parseConfigFile(configFilePath)) {
fprintf(stderr, "Error: config file \"%s\" missing or formating incorrect\n"
"Specify path to the config file as parameter to ssltunnel or \n"
@ -1204,9 +1163,10 @@ int main(int argc, char** argv)
" # specified. You also have to specify the tunnel listen port.\n"
" clientauth:requesting-client-cert.host.com:443:4443:request\n"
" clientauth:requiring-client-cert.host.com:443:4443:require\n"
" # Proxy WebSocket traffic to the server at 127.0.0.1:9999,\n"
" # instead of the server specified in the 'forward' option.\n"
" websocketserver:127.0.0.1:9999\n",
" # Act as a simple proxy for incoming connections on port 7777,\n"
" # tunneling them to the server at 127.0.0.1:9999. Not affected\n"
" # by the 'forward' option.\n"
" proxy:7777:127.0.0.1:9999\n",
configFilePath);
return 1;
}