http.py
Go to the documentation of this file.
00001 # -*- coding: utf-8 -*-
00002 """
00003 This module contains some helpers to deal with the real http
00004 world.
00005 """
00006 
00007 import threading
00008 import logging
00009 import select
00010 import socket
00011 import time
00012 import os
00013 
00014 import six
00015 import webob
00016 from six.moves import http_client
00017 from waitress.server import TcpWSGIServer
00018 
00019 
00020 def get_free_port():
00021     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
00022     s.bind(('', 0))
00023     ip, port = s.getsockname()
00024     s.close()
00025     ip = os.environ.get('WEBTEST_SERVER_BIND', '127.0.0.1')
00026     return ip, port
00027 
00028 
00029 def check_server(host, port, path_info='/', timeout=3, retries=30):
00030     """Perform a request until the server reply"""
00031     if retries < 0:
00032         return 0
00033     time.sleep(.3)
00034     for i in range(retries):
00035         try:
00036             conn = http_client.HTTPConnection(host, int(port), timeout=timeout)
00037             conn.request('GET', path_info)
00038             res = conn.getresponse()
00039             return res.status
00040         except (socket.error, http_client.HTTPException):
00041             time.sleep(.3)
00042     return 0
00043 
00044 
00045 class StopableWSGIServer(TcpWSGIServer):
00046     """StopableWSGIServer is a TcpWSGIServer which run in a separated thread.
00047     This allow to use tools like casperjs or selenium.
00048 
00049     Server instance have an ``application_url`` attribute formated with the
00050     server host and port.
00051     """
00052 
00053     was_shutdown = False
00054 
00055     def __init__(self, application, *args, **kwargs):
00056         super(StopableWSGIServer, self).__init__(self.wrapper, *args, **kwargs)
00057         self.runner = None
00058         self.test_app = application
00059         self.application_url = 'http://%s:%s/' % (self.adj.host, self.adj.port)
00060 
00061     def wrapper(self, environ, start_response):
00062         """Wrap the wsgi application to override some path:
00063 
00064         ``/__application__``: allow to ping the server.
00065 
00066         ``/__file__?__file__={path}``: serve the file found at ``path``
00067         """
00068         if '__file__' in environ['PATH_INFO']:
00069             req = webob.Request(environ)
00070             resp = webob.Response()
00071             resp.content_type = 'text/html; charset=UTF-8'
00072             filename = req.params.get('__file__')
00073             if os.path.isfile(filename):
00074                 body = open(filename, 'rb').read()
00075                 body = body.replace(six.b('http://localhost/'),
00076                                     six.b('http://%s/' % req.host))
00077                 resp.body = body
00078             else:
00079                 resp.status = '404 Not Found'
00080             return resp(environ, start_response)
00081         elif '__application__' in environ['PATH_INFO']:
00082             return webob.Response('server started')(environ, start_response)
00083         return self.test_app(environ, start_response)
00084 
00085     def run(self):
00086         """Run the server"""
00087         try:
00088             self.asyncore.loop(.5, map=self._map)
00089         except select.error:  # pragma: no cover
00090             if not self.was_shutdown:
00091                 raise
00092 
00093     def shutdown(self):
00094         """Shutdown the server"""
00095         # avoid showing traceback related to asyncore
00096         self.was_shutdown = True
00097         self.logger.setLevel(logging.FATAL)
00098         while self._map:
00099             triggers = list(self._map.values())
00100             for trigger in triggers:
00101                 trigger.handle_close()
00102         self.maintenance(0)
00103         self.task_dispatcher.shutdown()
00104         return True
00105 
00106     @classmethod
00107     def create(cls, application, **kwargs):
00108         """Start a server to serve ``application``. Return a server
00109         instance."""
00110         host, port = get_free_port()
00111         if 'port' not in kwargs:
00112             kwargs['port'] = port
00113         if 'host' not in kwargs:
00114             kwargs['host'] = host
00115         if 'expose_tracebacks' not in kwargs:
00116             kwargs['expose_tracebacks'] = True
00117         server = cls(application, **kwargs)
00118         server.runner = threading.Thread(target=server.run)
00119         server.runner.daemon = True
00120         server.runner.start()
00121         return server
00122 
00123     def wait(self, retries=30):
00124         """Wait until the server is started"""
00125         running = check_server(self.adj.host, self.adj.port,
00126                                '/__application__', retries=retries)
00127         if running:
00128             return True
00129         try:
00130             self.shutdown()
00131         finally:
00132             return False


webtest
Author(s): AlexV
autogenerated on Sat Mar 25 2017 03:32:05