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): ...@@ -41,10 +41,19 @@ def issubpathof(subpath, path):
class Recipe(GenericBaseRecipe): 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): def install(self):
parameters = { parameters = {
'host': self.options['host'], 'address': self.options['address'],
'port': int(self.options['port']),
'cwd': self.options['base-path'], 'cwd': self.options['base-path'],
'log-file': self.options['log-file'], 'log-file': self.options['log-file'],
'cert-file': self.options.get('cert-file', ''), 'cert-file': self.options.get('cert-file', ''),
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from six.moves.SimpleHTTPServer import SimpleHTTPRequestHandler from six.moves.SimpleHTTPServer import SimpleHTTPRequestHandler
from six.moves.BaseHTTPServer import HTTPServer from six.moves.socketserver import TCPServer
import ssl import ssl
import os import os
import logging import logging
...@@ -93,8 +93,7 @@ class ServerHandler(SimpleHTTPRequestHandler): ...@@ -93,8 +93,7 @@ class ServerHandler(SimpleHTTPRequestHandler):
self.respond(200, type=self.headers['Content-Type']) self.respond(200, type=self.headers['Content-Type'])
self.wfile.write(b"Content written to %s" % str2bytes(filename)) self.wfile.write(b"Content written to %s" % str2bytes(filename))
class HTTPServerV6(HTTPServer):
address_family = socket.AF_INET6
def run(args): def run(args):
...@@ -104,8 +103,7 @@ def run(args): ...@@ -104,8 +103,7 @@ def run(args):
logging.basicConfig(format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", logging.basicConfig(format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
filename=args['log-file'] ,level=logging.INFO) filename=args['log-file'] ,level=logging.INFO)
port = args['port'] address = args['address']
host = args['host']
cwd = args['cwd'] cwd = args['cwd']
os.chdir(cwd) os.chdir(cwd)
...@@ -114,12 +112,17 @@ def run(args): ...@@ -114,12 +112,17 @@ def run(args):
Handler.base_path = cwd Handler.base_path = cwd
Handler.restrict_write = not args['allow-write'] Handler.restrict_write = not args['allow-write']
if valid_ipv6(host): try:
server = HTTPServerV6 host, port = address
else: family, _, _, _, _ = socket.getaddrinfo(host, port)[0]
server = HTTPServer 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' scheme = 'http'
if 'cert-file' in args and 'key-file' in args and \ if 'cert-file' in args and 'key-file' in args and \
os.path.exists(args['cert-file']) and os.path.exists(args['key-file']): os.path.exists(args['cert-file']) and os.path.exists(args['key-file']):
...@@ -129,5 +132,5 @@ def run(args): ...@@ -129,5 +132,5 @@ def run(args):
certfile=args['cert-file'], certfile=args['cert-file'],
keyfile=args['key-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() httpd.serve_forever()
...@@ -3,6 +3,7 @@ import os ...@@ -3,6 +3,7 @@ import os
import shutil import shutil
import tempfile import tempfile
import unittest import unittest
import socket
import subprocess import subprocess
import time import time
...@@ -24,12 +25,14 @@ class SimpleHTTPServerTest(unittest.TestCase): ...@@ -24,12 +25,14 @@ class SimpleHTTPServerTest(unittest.TestCase):
self.wrapper = os.path.join(self.install_dir, 'server') self.wrapper = os.path.join(self.install_dir, 'server')
self.process = None self.process = None
def setUpRecipe(self, opt=()): def setUpRecipe(self, opt=None):
host, port = os.environ['SLAPOS_TEST_IPV4'], 9999 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 = { options = {
'base-path': self.base_path, 'base-path': self.base_path,
'host': host,
'port': port,
'log-file': os.path.join(self.install_dir, 'simplehttpserver.log'), 'log-file': os.path.join(self.install_dir, 'simplehttpserver.log'),
'wrapper': self.wrapper, 'wrapper': self.wrapper,
} }
...@@ -39,7 +42,6 @@ class SimpleHTTPServerTest(unittest.TestCase): ...@@ -39,7 +42,6 @@ class SimpleHTTPServerTest(unittest.TestCase):
options=options, options=options,
name='simplehttpserver', name='simplehttpserver',
) )
self.server_url = 'http://{host}:{port}'.format(host=host, port=port)
def startServer(self): def startServer(self):
self.assertEqual(self.recipe.install(), self.wrapper) self.assertEqual(self.recipe.install(), self.wrapper)
...@@ -183,3 +185,37 @@ class SimpleHTTPServerTest(unittest.TestCase): ...@@ -183,3 +185,37 @@ class SimpleHTTPServerTest(unittest.TestCase):
self.assertEqual(resp.status_code, requests.codes.forbidden) self.assertEqual(resp.status_code, requests.codes.forbidden)
with open(indexpath) as f: with open(indexpath) as f:
self.assertEqual(f.read(), indexcontent) 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