185 lines
5.6 KiB
Python
185 lines
5.6 KiB
Python
#!/usr/bin/env python
|
|
|
|
"""
|
|
SSL server for Forge tests.
|
|
|
|
- The server changes to the directory of the server script.
|
|
- SSL uses "server.key" and "server.crt".
|
|
- Sever performs basic static file serving.
|
|
- Starts Flash cross domain policy file server.
|
|
- Defaults to HTTP/HTTPS port 19400.
|
|
- Defaults to Flash socket policy port 19945.
|
|
|
|
$ ./server.py [options]
|
|
|
|
If you just need a simple HTTP server, also consider:
|
|
$ python -m SimpleHTTPServer 19400
|
|
"""
|
|
|
|
from multiprocessing import Process
|
|
from optparse import OptionParser
|
|
import SimpleHTTPServer
|
|
import SocketServer
|
|
import os
|
|
import sys
|
|
import time
|
|
|
|
# Try to import special Forge SSL module with session cache support
|
|
# Using the built directory directly
|
|
python_version = "python" + sys.version[:3]
|
|
sys.path.insert(0, os.path.join(
|
|
os.path.dirname(os.path.realpath(__file__)),
|
|
"..", "dist", "forge_ssl", "lib", python_version, "site-packages"))
|
|
try:
|
|
from forge import ssl
|
|
have_ssl_sessions = True
|
|
have_ssl = True
|
|
except ImportError:
|
|
have_ssl_sessions = False
|
|
try:
|
|
import ssl
|
|
have_ssl = True
|
|
except ImportError:
|
|
have_ssl = False
|
|
|
|
# Set address reuse for all TCPServers
|
|
SocketServer.TCPServer.allow_reuse_address = True
|
|
|
|
# The policy file
|
|
# NOTE: This format is very strict. Edit with care.
|
|
policy_file = """\
|
|
<?xml version="1.0"?>\
|
|
<!DOCTYPE cross-domain-policy\
|
|
SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">\
|
|
<cross-domain-policy>\
|
|
<allow-access-from domain="*" to-ports="*"/>\
|
|
</cross-domain-policy>\0"""
|
|
|
|
|
|
class PolicyHandler(SocketServer.BaseRequestHandler):
|
|
"""
|
|
The RequestHandler class for our server.
|
|
|
|
Returns a policy file when requested.
|
|
"""
|
|
|
|
def handle(self):
|
|
# get some data
|
|
# TODO: make this more robust (while loop, etc)
|
|
self.data = self.request.recv(1024).rstrip('\0')
|
|
#print "%s wrote:" % self.client_address[0]
|
|
#print repr(self.data)
|
|
# if policy file request, send the file.
|
|
if self.data == "<policy-file-request/>":
|
|
print "Policy server request from %s." % (self.client_address[0])
|
|
self.request.send(policy_file)
|
|
else:
|
|
print "Policy server received junk from %s: \"%s\"" % \
|
|
(self.client_address[0], repr(self.data))
|
|
|
|
|
|
def create_policy_server(options):
|
|
"""Start a policy server"""
|
|
print "Policy serving from %d." % (options.policy_port)
|
|
policyd = SocketServer.TCPServer((options.host, options.policy_port), PolicyHandler)
|
|
return policyd
|
|
|
|
|
|
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
|
|
pass
|
|
|
|
|
|
def create_http_server(options, script_dir):
|
|
"""Start a static file server"""
|
|
# use UTF-8 encoding for javascript files
|
|
m = SimpleHTTPServer.SimpleHTTPRequestHandler.extensions_map
|
|
m['.js'] = 'application/javascript;charset=UTF-8'
|
|
|
|
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
|
|
# httpd = SocketServer.TCPServer((options.host, options.port), Handler)
|
|
httpd = ThreadedTCPServer((options.host, options.port), Handler)
|
|
if options.tls:
|
|
if not have_ssl:
|
|
raise Exception("SSL support from Python 2.7 or later is required.")
|
|
|
|
# setup session args if we session support
|
|
sess_args = {}
|
|
if have_ssl_sessions:
|
|
sess_args["sess_id_ctx"] = "forgetest"
|
|
else:
|
|
print "Forge SSL with session cache not available, using standard version."
|
|
|
|
httpd.socket = ssl.wrap_socket(
|
|
httpd.socket,
|
|
keyfile="server.key",
|
|
certfile="server.crt",
|
|
server_side=True,
|
|
**sess_args)
|
|
|
|
print "Serving from \"%s\"." % (script_dir)
|
|
print "%s://%s:%d/" % \
|
|
(("https" if options.tls else "http"),
|
|
httpd.server_address[0],
|
|
options.port)
|
|
return httpd
|
|
|
|
|
|
def serve_forever(server):
|
|
"""Serve until shutdown or keyboard interrupt."""
|
|
try:
|
|
server.serve_forever()
|
|
except KeyboardInterrupt:
|
|
return
|
|
|
|
|
|
def main():
|
|
"""Start static file and policy servers"""
|
|
usage = "Usage: %prog [options]"
|
|
parser = OptionParser(usage=usage)
|
|
parser.add_option("", "--host", dest="host", metavar="HOST",
|
|
default="localhost", help="bind to HOST")
|
|
parser.add_option("-p", "--port", dest="port", type="int",
|
|
help="serve on PORT", metavar="PORT", default=19400)
|
|
parser.add_option("-P", "--policy-port", dest="policy_port", type="int",
|
|
help="serve policy file on PORT", metavar="PORT", default=19945)
|
|
parser.add_option("", "--tls", dest="tls", action="store_true",
|
|
help="serve HTTPS", default=False)
|
|
(options, args) = parser.parse_args()
|
|
|
|
# Change to script dir so SSL and test files are in current dir.
|
|
script_dir = os.path.dirname(os.path.realpath(__file__))
|
|
os.chdir(script_dir)
|
|
|
|
print "Forge Test Server. Use ctrl-c to exit."
|
|
|
|
# create policy and http servers
|
|
httpd = create_http_server(options, script_dir)
|
|
policyd = create_policy_server(options)
|
|
|
|
# start servers
|
|
server_p = Process(target=serve_forever, args=(httpd,))
|
|
policy_p = Process(target=serve_forever, args=(policyd,))
|
|
server_p.start()
|
|
policy_p.start()
|
|
|
|
processes = [server_p, policy_p]
|
|
|
|
while len(processes) > 0:
|
|
try:
|
|
for p in processes:
|
|
if p.is_alive():
|
|
p.join(1)
|
|
else:
|
|
processes.remove(p)
|
|
except KeyboardInterrupt:
|
|
print "\nStopping test server..."
|
|
# processes each receive interrupt
|
|
# so no need to shutdown
|
|
#httpd.shutdown();
|
|
#policyd.shutdown();
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
|