Commit 3562d3d1 authored by Xavier Thompson's avatar Xavier Thompson

simplehttpserver: Add options for unix socket

Add 'socketpath' and 'abstract' options for path based unix sockets
and abstract unix sockets respectively.
parent d3940b31
......@@ -41,10 +41,19 @@ def issubpathof(subpath, path):
class Recipe(GenericBaseRecipe):
def __init__(self, buildout, name, options):
host, port, socketpath, abstract = (
options.get(k) for k in ('host', 'port', 'socketpath', 'abstract'))
oneof = host, socketpath, abstract
if sum(bool(v) for v in oneof) != 1 or bool(host) != bool(port):
raise UserError("Specify one of (host, port) | socketpath | abstract")
address = (host, int(port)) if host else socketpath or '\0' + abstract
options['address'] = address
return GenericBaseRecipe.__init__(self, buildout, name, options)
def install(self):
parameters = {
'host': self.options['host'],
'port': int(self.options['port']),
'address': self.options['address'],
'cwd': self.options['base-path'],
'log-file': self.options['log-file'],
'cert-file': self.options.get('cert-file', ''),
......
# -*- coding: utf-8 -*-
from six.moves.SimpleHTTPServer import SimpleHTTPRequestHandler
from six.moves.BaseHTTPServer import HTTPServer
from six.moves.socketserver import TCPServer
import ssl
import os
import logging
......@@ -93,8 +93,7 @@ class ServerHandler(SimpleHTTPRequestHandler):
self.respond(200, type=self.headers['Content-Type'])
self.wfile.write(b"Content written to %s" % str2bytes(filename))
class HTTPServerV6(HTTPServer):
address_family = socket.AF_INET6
def run(args):
......@@ -104,8 +103,7 @@ def run(args):
logging.basicConfig(format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
filename=args['log-file'] ,level=logging.INFO)
port = args['port']
host = args['host']
address = args['address']
cwd = args['cwd']
os.chdir(cwd)
......@@ -114,12 +112,17 @@ def run(args):
Handler.base_path = cwd
Handler.restrict_write = not args['allow-write']
if valid_ipv6(host):
server = HTTPServerV6
else:
server = HTTPServer
try:
host, port = address
family, _, _, _, _ = socket.getaddrinfo(host, port)[0]
except ValueError:
family = socket.AF_UNIX
class Server(TCPServer):
allow_reuse_address = 1 # for tests, HTTPServer in stdlib sets it too
address_family = family
httpd = server((host, port), Handler)
httpd = Server(address, Handler)
scheme = 'http'
if 'cert-file' in args and 'key-file' in args and \
os.path.exists(args['cert-file']) and os.path.exists(args['key-file']):
......@@ -129,5 +132,5 @@ def run(args):
certfile=args['cert-file'],
keyfile=args['key-file'])
logging.info("Starting simple http server at %s://%s:%s" % (scheme, host, port))
# logging.info("Starting simple http server at %s://%s:%s" % (scheme, host, port))
httpd.serve_forever()
......@@ -3,6 +3,7 @@ import os
import shutil
import tempfile
import unittest
import socket
import subprocess
import time
......@@ -24,12 +25,14 @@ class SimpleHTTPServerTest(unittest.TestCase):
self.wrapper = os.path.join(self.install_dir, 'server')
self.process = None
def setUpRecipe(self, opt=()):
host, port = os.environ['SLAPOS_TEST_IPV4'], 9999
def setUpRecipe(self, opt=None):
opt = opt or {}
if not 'socketpath' in opt and not 'abstract' in opt:
opt['host'] = host = os.environ['SLAPOS_TEST_IPV4']
opt['port'] = port = 9999
self.server_url = 'http://{host}:{port}'.format(host=host, port=port)
options = {
'base-path': self.base_path,
'host': host,
'port': port,
'log-file': os.path.join(self.install_dir, 'simplehttpserver.log'),
'wrapper': self.wrapper,
}
......@@ -39,7 +42,6 @@ class SimpleHTTPServerTest(unittest.TestCase):
options=options,
name='simplehttpserver',
)
self.server_url = 'http://{host}:{port}'.format(host=host, port=port)
def startServer(self):
self.assertEqual(self.recipe.install(), self.wrapper)
......@@ -183,3 +185,37 @@ class SimpleHTTPServerTest(unittest.TestCase):
self.assertEqual(resp.status_code, requests.codes.forbidden)
with open(indexpath) as f:
self.assertEqual(f.read(), indexcontent)
def startSocketServer(self):
self.assertEqual(self.recipe.install(), self.wrapper)
self.process = subprocess.Popen(
self.wrapper,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
address = self.recipe.options['address']
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
for i in range(16):
try:
s.connect(address)
break
except socket.error as e:
time.sleep(i * .1)
else:
self.fail("Unable to connect to socketpath")
finally:
s.close()
def test_socketpath(self):
socketpath = os.path.join(self.install_dir, 'http.sock')
self.setUpRecipe({'socketpath': socketpath})
self.assertEqual(socketpath, self.recipe.options['address'])
self.startSocketServer()
def test_abstract(self):
abstract = os.path.join(self.install_dir, 'abstract.http')
self.setUpRecipe({'abstract': abstract})
self.assertEqual('\0' + abstract, self.recipe.options['address'])
self.startSocketServer()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment