Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: net/tools/testserver/testserver_base.py

Issue 11971025: [sync] Divorce python sync test server chromiumsync.py from testserver.py (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/tools/testserver/testserver.py ('k') | net/tools/testserver/xmppserver.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import BaseHTTPServer
6 import errno
5 import json 7 import json
6 import optparse 8 import optparse
7 import os 9 import os
10 import re
11 import socket
12 import SocketServer
8 import struct 13 import struct
9 import sys 14 import sys
10 import warnings 15 import warnings
11 16
12 # Ignore deprecation warnings, they make our output more cluttered. 17 # Ignore deprecation warnings, they make our output more cluttered.
13 warnings.filterwarnings("ignore", category=DeprecationWarning) 18 warnings.filterwarnings("ignore", category=DeprecationWarning)
14 19
15 if sys.platform == 'win32': 20 if sys.platform == 'win32':
16 import msvcrt 21 import msvcrt
17 22
23 # Using debug() seems to cause hangs on XP: see http://crbug.com/64515.
24 debug_output = sys.stderr
25 def debug(string):
26 debug_output.write(string + "\n")
27 debug_output.flush()
28
18 29
19 class Error(Exception): 30 class Error(Exception):
20 """Error class for this module.""" 31 """Error class for this module."""
21 32
22 33
23 class OptionError(Error): 34 class OptionError(Error):
24 """Error for bad command line options.""" 35 """Error for bad command line options."""
25 36
26 37
27 class FileMultiplexer(object): 38 class FileMultiplexer(object):
28 def __init__(self, fd1, fd2) : 39 def __init__(self, fd1, fd2) :
29 self.__fd1 = fd1 40 self.__fd1 = fd1
30 self.__fd2 = fd2 41 self.__fd2 = fd2
31 42
32 def __del__(self) : 43 def __del__(self) :
33 if self.__fd1 != sys.stdout and self.__fd1 != sys.stderr: 44 if self.__fd1 != sys.stdout and self.__fd1 != sys.stderr:
34 self.__fd1.close() 45 self.__fd1.close()
35 if self.__fd2 != sys.stdout and self.__fd2 != sys.stderr: 46 if self.__fd2 != sys.stdout and self.__fd2 != sys.stderr:
36 self.__fd2.close() 47 self.__fd2.close()
37 48
38 def write(self, text) : 49 def write(self, text) :
39 self.__fd1.write(text) 50 self.__fd1.write(text)
40 self.__fd2.write(text) 51 self.__fd2.write(text)
41 52
42 def flush(self) : 53 def flush(self) :
43 self.__fd1.flush() 54 self.__fd1.flush()
44 self.__fd2.flush() 55 self.__fd2.flush()
45 56
46 57
58 class ClientRestrictingServerMixIn:
59 """Implements verify_request to limit connections to our configured IP
60 address."""
61
62 def verify_request(self, _request, client_address):
63 return client_address[0] == self.server_address[0]
64
65
66 class BrokenPipeHandlerMixIn:
67 """Allows the server to deal with "broken pipe" errors (which happen if the
68 browser quits with outstanding requests, like for the favicon). This mix-in
69 requires the class to derive from SocketServer.BaseServer and not override its
70 handle_error() method. """
71
72 def handle_error(self, request, client_address):
73 value = sys.exc_info()[1]
74 if isinstance(value, socket.error):
75 err = value.args[0]
76 if sys.platform in ('win32', 'cygwin'):
77 # "An established connection was aborted by the software in your host."
78 pipe_err = 10053
79 else:
80 pipe_err = errno.EPIPE
81 if err == pipe_err:
82 print "testserver.py: Broken pipe"
83 return
84 SocketServer.BaseServer.handle_error(self, request, client_address)
85
86
87 class StoppableHTTPServer(BaseHTTPServer.HTTPServer):
88 """This is a specialization of BaseHTTPServer to allow it
89 to be exited cleanly (by setting its "stop" member to True)."""
90
91 def serve_forever(self):
92 self.stop = False
93 self.nonce_time = None
94 while not self.stop:
95 self.handle_request()
96 self.socket.close()
97
98
47 def MultiplexerHack(std_fd, log_fd): 99 def MultiplexerHack(std_fd, log_fd):
48 """Creates a FileMultiplexer that will write to both specified files. 100 """Creates a FileMultiplexer that will write to both specified files.
49 101
50 When running on Windows XP bots, stdout and stderr will be invalid file 102 When running on Windows XP bots, stdout and stderr will be invalid file
51 handles, so log_fd will be returned directly. (This does not occur if you 103 handles, so log_fd will be returned directly. (This does not occur if you
52 run the test suite directly from a console, but only if the output of the 104 run the test suite directly from a console, but only if the output of the
53 test executable is redirected.) 105 test executable is redirected.)
54 """ 106 """
55 if std_fd.fileno() <= 0: 107 if std_fd.fileno() <= 0:
56 return log_fd 108 return log_fd
57 return FileMultiplexer(std_fd, log_fd) 109 return FileMultiplexer(std_fd, log_fd)
58 110
59 111
112 class BasePageHandler(BaseHTTPServer.BaseHTTPRequestHandler):
113
114 def __init__(self, request, client_address, socket_server,
115 connect_handlers, get_handlers, head_handlers, post_handlers,
116 put_handlers):
117 self._connect_handlers = connect_handlers
118 self._get_handlers = get_handlers
119 self._head_handlers = head_handlers
120 self._post_handlers = post_handlers
121 self._put_handlers = put_handlers
122 BaseHTTPServer.BaseHTTPRequestHandler.__init__(
123 self, request, client_address, socket_server)
124
125 def log_request(self, *args, **kwargs):
126 # Disable request logging to declutter test log output.
127 pass
128
129 def _ShouldHandleRequest(self, handler_name):
130 """Determines if the path can be handled by the handler.
131
132 We consider a handler valid if the path begins with the
133 handler name. It can optionally be followed by "?*", "/*".
134 """
135
136 pattern = re.compile('%s($|\?|/).*' % handler_name)
137 return pattern.match(self.path)
138
139 def do_CONNECT(self):
140 for handler in self._connect_handlers:
141 if handler():
142 return
143
144 def do_GET(self):
145 for handler in self._get_handlers:
146 if handler():
147 return
148
149 def do_HEAD(self):
150 for handler in self._head_handlers:
151 if handler():
152 return
153
154 def do_POST(self):
155 for handler in self._post_handlers:
156 if handler():
157 return
158
159 def do_PUT(self):
160 for handler in self._put_handlers:
161 if handler():
162 return
163
164
60 class TestServerRunner(object): 165 class TestServerRunner(object):
61 """Runs a test server and communicates with the controlling C++ test code. 166 """Runs a test server and communicates with the controlling C++ test code.
62 167
63 Subclasses should override the create_server method to create their server 168 Subclasses should override the create_server method to create their server
64 object, and the add_options method to add their own options. 169 object, and the add_options method to add their own options.
65 """ 170 """
66 171
67 def __init__(self): 172 def __init__(self):
68 self.option_parser = optparse.OptionParser() 173 self.option_parser = optparse.OptionParser()
69 self.add_options() 174 self.add_options()
70 175
71 def main(self): 176 def main(self):
72 self.options, self.args = self.option_parser.parse_args() 177 self.options, self.args = self.option_parser.parse_args()
73 178
74 logfile = open('testserver.log', 'w') 179 logfile = open(self.options.log_file, 'w')
75 sys.stderr = MultiplexerHack(sys.stderr, logfile) 180 sys.stderr = MultiplexerHack(sys.stderr, logfile)
76 if self.options.log_to_console: 181 if self.options.log_to_console:
77 sys.stdout = MultiplexerHack(sys.stdout, logfile) 182 sys.stdout = MultiplexerHack(sys.stdout, logfile)
78 else: 183 else:
79 sys.stdout = logfile 184 sys.stdout = logfile
80 185
81 server_data = { 186 server_data = {
82 'host': self.options.host, 187 'host': self.options.host,
83 } 188 }
84 self.server = self.create_server(server_data) 189 self.server = self.create_server(server_data)
(...skipping 16 matching lines...) Expand all
101 206
102 def add_options(self): 207 def add_options(self):
103 self.option_parser.add_option('--startup-pipe', type='int', 208 self.option_parser.add_option('--startup-pipe', type='int',
104 dest='startup_pipe', 209 dest='startup_pipe',
105 help='File handle of pipe to parent process') 210 help='File handle of pipe to parent process')
106 self.option_parser.add_option('--log-to-console', action='store_const', 211 self.option_parser.add_option('--log-to-console', action='store_const',
107 const=True, default=False, 212 const=True, default=False,
108 dest='log_to_console', 213 dest='log_to_console',
109 help='Enables or disables sys.stdout logging ' 214 help='Enables or disables sys.stdout logging '
110 'to the console.') 215 'to the console.')
216 self.option_parser.add_option('--log-file', default='testserver.log',
217 dest='log_file',
218 help='The name of the server log file.')
111 self.option_parser.add_option('--port', default=0, type='int', 219 self.option_parser.add_option('--port', default=0, type='int',
112 help='Port used by the server. If ' 220 help='Port used by the server. If '
113 'unspecified, the server will listen on an ' 221 'unspecified, the server will listen on an '
114 'ephemeral port.') 222 'ephemeral port.')
115 self.option_parser.add_option('--host', default='127.0.0.1', 223 self.option_parser.add_option('--host', default='127.0.0.1',
116 dest='host', 224 dest='host',
117 help='Hostname or IP upon which the server ' 225 help='Hostname or IP upon which the server '
118 'will listen. Client connections will also ' 226 'will listen. Client connections will also '
119 'only be allowed from this address.') 227 'only be allowed from this address.')
228 self.option_parser.add_option('--data-dir', dest='data_dir',
229 help='Directory from which to read the '
230 'files.')
120 231
121 def _notify_startup_complete(self, server_data): 232 def _notify_startup_complete(self, server_data):
122 # Notify the parent that we've started. (BaseServer subclasses 233 # Notify the parent that we've started. (BaseServer subclasses
123 # bind their sockets on construction.) 234 # bind their sockets on construction.)
124 if self.options.startup_pipe is not None: 235 if self.options.startup_pipe is not None:
125 server_data_json = json.dumps(server_data) 236 server_data_json = json.dumps(server_data)
126 server_data_len = len(server_data_json) 237 server_data_len = len(server_data_json)
127 print 'sending server_data: %s (%d bytes)' % ( 238 print 'sending server_data: %s (%d bytes)' % (
128 server_data_json, server_data_len) 239 server_data_json, server_data_len)
129 if sys.platform == 'win32': 240 if sys.platform == 'win32':
130 fd = msvcrt.open_osfhandle(self.options.startup_pipe, 0) 241 fd = msvcrt.open_osfhandle(self.options.startup_pipe, 0)
131 else: 242 else:
132 fd = self.options.startup_pipe 243 fd = self.options.startup_pipe
133 startup_pipe = os.fdopen(fd, "w") 244 startup_pipe = os.fdopen(fd, "w")
134 # First write the data length as an unsigned 4-byte value. This 245 # First write the data length as an unsigned 4-byte value. This
135 # is _not_ using network byte ordering since the other end of the 246 # is _not_ using network byte ordering since the other end of the
136 # pipe is on the same machine. 247 # pipe is on the same machine.
137 startup_pipe.write(struct.pack('=L', server_data_len)) 248 startup_pipe.write(struct.pack('=L', server_data_len))
138 startup_pipe.write(server_data_json) 249 startup_pipe.write(server_data_json)
139 startup_pipe.close() 250 startup_pipe.close()
OLDNEW
« no previous file with comments | « net/tools/testserver/testserver.py ('k') | net/tools/testserver/xmppserver.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698