testserver.py listens on ephemeral ports by default.

If --port is specified on the command line, testserver.py will listen on that port, otherwise it will listen on an ephemeral port. If --startup_pipe is specified, the port number is written to the pipe as a 2 byte unsigned int in host order.

TestServer spawns testserver.py to listen on an ephemeral port and reads the port value from the pipe. A fixed port can not be specified.

BUG=56814
TEST=try bots pass

Review URL: http://codereview.chromium.org/4136008

git-svn-id: http://src.chromium.org/svn/trunk/src/net/tools/testserver@65465 4ff67af0-8c30-449e-8e8b-ad334ec8d88c
diff --git a/testserver.py b/testserver.py
index 55aa6a9..0e1445b 100755
--- a/testserver.py
+++ b/testserver.py
@@ -6,7 +6,9 @@
 """This is a simple HTTP server used for testing Chrome.
 
 It supports several test URLs, as specified by the handlers in TestPageHandler.
-It defaults to living on localhost:8888.
+By default, it listens on an ephemeral port and sends the port number back to
+the originating process over a pipe. The originating process can specify an
+explicit port if necessary.
 It can use https if you specify the flag --https=CERT where CERT is the path
 to a pem file containing the certificate and private key that should be used.
 """
@@ -20,6 +22,7 @@
 import shutil
 import SocketServer
 import sys
+import struct
 import time
 import urlparse
 import warnings
@@ -500,7 +503,7 @@
       'pre { border: 1px solid black; margin: 5px; padding: 5px }'
       '</style></head><body>'
       '<div style="float: right">'
-      '<a href="http://localhost:8888/echo">back to referring page</a></div>'
+      '<a href="/echo">back to referring page</a></div>'
       '<h1>Request Body:</h1><pre>')
 
     if self.command == 'POST' or self.command == 'PUT':
@@ -1191,15 +1194,15 @@
       server = HTTPSServer(('127.0.0.1', port), TestPageHandler, options.cert,
                            options.ssl_client_auth, options.ssl_client_ca,
                            options.ssl_bulk_cipher)
-      print 'HTTPS server started on port %d...' % port
+      print 'HTTPS server started on port %d...' % server.server_port
     else:
       server = StoppableHTTPServer(('127.0.0.1', port), TestPageHandler)
-      print 'HTTP server started on port %d...' % port
+      print 'HTTP server started on port %d...' % server.server_port
 
     server.data_dir = MakeDataDir()
     server.file_root_url = options.file_root_url
     server._sync_handler = None
-
+    listen_port = server.server_port
   # means FTP Server
   else:
     my_data_dir = MakeDataDir()
@@ -1224,7 +1227,8 @@
     # Instantiate FTP server class and listen to 127.0.0.1:port
     address = ('127.0.0.1', port)
     server = pyftpdlib.ftpserver.FTPServer(address, ftp_handler)
-    print 'FTP server started on port %d...' % port
+    listen_port = server.socket.getsockname()[1]
+    print 'FTP server started on port %d...' % listen_port
 
   # Notify the parent that we've started. (BaseServer subclasses
   # bind their sockets on construction.)
@@ -1234,7 +1238,10 @@
     else:
       fd = options.startup_pipe
     startup_pipe = os.fdopen(fd, "w")
-    startup_pipe.write("READY")
+    # Write the listening port as a 2 byte value. This is _not_ using
+    # network byte ordering since the other end of the pipe is on the same
+    # machine.
+    startup_pipe.write(struct.pack('@H', listen_port))
     startup_pipe.close()
 
   try:
@@ -1249,8 +1256,9 @@
                            const=SERVER_FTP, default=SERVER_HTTP,
                            dest='server_type',
                            help='FTP or HTTP server: default is HTTP.')
-  option_parser.add_option('', '--port', default='8888', type='int',
-                           help='Port used by the server.')
+  option_parser.add_option('', '--port', default='0', type='int',
+                           help='Port used by the server. If unspecified, the '
+                           'server will listen on an ephemeral port.')
   option_parser.add_option('', '--data-dir', dest='data_dir',
                            help='Directory from which to read the files.')
   option_parser.add_option('', '--https', dest='cert',