Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

Changeset 2068

Show
Ignore:
Timestamp:
11/08/08 12:22:41
Author:
fumanchu
Message:

Merging [2007] to [2051] from trunk in prep for releasing 3.1.1.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/cherrypy-3.1.x/cherrypy/_cpconfig.py

    r1989 r2068  
    304304        engine.autoreload.match = v 
    305305    elif k == 'reload_files': 
    306         engine.autoreload.files = v 
     306        engine.autoreload.files = set(v) 
    307307    elif k == 'deadlock_poll_freq': 
    308308        engine.timeout_monitor.frequency = v 
     
    311311    elif k == 'SIGTERM': 
    312312        engine.listeners['SIGTERM'] = set([v]) 
     313    elif "." in k: 
     314        plugin, attrname = k.split(".", 1) 
     315        plugin = getattr(engine, plugin) 
     316        if attrname == 'on': 
     317            if v and callable(getattr(plugin, 'subscribe', None)): 
     318                plugin.subscribe() 
     319                return 
     320            elif (not v) and callable(getattr(plugin, 'unsubscribe', None)): 
     321                plugin.unsubscribe() 
     322                return 
     323        setattr(plugin, attrname, v) 
     324    else: 
     325        setattr(engine, k, v) 
    313326Config.namespaces["engine"] = _engine_namespace_handler 
    314327 
  • branches/cherrypy-3.1.x/cherrypy/_cpdispatch.py

    r1893 r2068  
    2222     
    2323    def __call__(self): 
    24         return self.callable(*self.args, **self.kwargs) 
     24        try: 
     25            return self.callable(*self.args, **self.kwargs) 
     26        except TypeError, x: 
     27            test_callable_spec(self.callable, self.args, self.kwargs) 
     28            raise 
     29 
     30def test_callable_spec(callable, callable_args, callable_kwargs): 
     31    """ 
     32    Inspect callable and test to see if the given args are suitable for it. 
     33 
     34    When an error occurs during the handler's invoking stage there are 2 
     35    erroneous cases: 
     36    1.  Too many parameters passed to a function which doesn't define 
     37        one of *args or **kwargs. 
     38    2.  Too little parameters are passed to the function. 
     39 
     40    There are 3 sources of parameters to a cherrypy handler. 
     41    1.  query string parameters are passed as keyword parameters to the handler. 
     42    2.  body parameters are also passed as keyword parameters. 
     43    3.  when partial matching occurs, the final path atoms are passed as 
     44        positional args. 
     45    Both the query string and path atoms are part of the URI.  If they are 
     46    incorrect, then a 404 Not Found should be raised. Conversely the body 
     47    parameters are part of the request; if they are invalid a 400 Bad Request. 
     48    """ 
     49    (args, varargs, varkw, defaults) = inspect.getargspec(callable) 
     50 
     51    if args and args[0] == 'self': 
     52        args = args[1:] 
     53 
     54    arg_usage = dict([(arg, 0,) for arg in args]) 
     55    vararg_usage = 0 
     56    varkw_usage = 0 
     57    extra_kwargs = set() 
     58 
     59    for i, value in enumerate(callable_args): 
     60        try: 
     61            arg_usage[args[i]] += 1 
     62        except IndexError: 
     63            vararg_usage += 1 
     64 
     65    for key in callable_kwargs.keys(): 
     66        try: 
     67            arg_usage[key] += 1 
     68        except KeyError: 
     69            varkw_usage += 1 
     70            extra_kwargs.add(key) 
     71 
     72    for i, val in enumerate(defaults or []): 
     73        # Defaults take effect only when the arg hasn't been used yet. 
     74        if arg_usage[args[i]] == 0: 
     75            arg_usage[args[i]] += 1 
     76 
     77    missing_args = [] 
     78    multiple_args = [] 
     79    for key, usage in arg_usage.iteritems(): 
     80        if usage == 0: 
     81            missing_args.append(key) 
     82        elif usage > 1: 
     83            multiple_args.append(key) 
     84 
     85    if missing_args: 
     86        # In the case where the method allows body arguments 
     87        # there are 3 potential errors: 
     88        # 1. not enough query string parameters -> 404 
     89        # 2. not enough body parameters -> 400 
     90        # 3. not enough path parts (partial matches) -> 404 
     91        # 
     92        # We can't actually tell which case it is,  
     93        # so I'm raising a 404 because that covers 2/3 of the 
     94        # possibilities 
     95        #  
     96        # In the case where the method does not allow body 
     97        # arguments it's definitely a 404. 
     98        raise cherrypy.HTTPError(404, 
     99                message="Missing parameters: %s" % ",".join(missing_args)) 
     100 
     101    # the extra positional arguments come from the path - 404 Not Found 
     102    if not varargs and vararg_usage > 0: 
     103        raise cherrypy.HTTPError(404) 
     104 
     105    body_params = cherrypy.request.body_params or {} 
     106    body_params = set(body_params.keys()) 
     107    qs_params = set(callable_kwargs.keys()) - body_params 
     108 
     109    if multiple_args: 
     110 
     111        if qs_params.intersection(set(multiple_args)): 
     112            # If any of the multiple parameters came from the query string then 
     113            # it's a 404 Not Found 
     114            error = 404 
     115        else: 
     116            # Otherwise it's a 400 Bad Request 
     117            error = 400 
     118 
     119        raise cherrypy.HTTPError(error, 
     120                message="Multiple values for parameters: "\ 
     121                        "%s" % ",".join(multiple_args)) 
     122 
     123    if not varkw and varkw_usage > 0: 
     124 
     125        # If there were extra query string parameters, it's a 404 Not Found 
     126        extra_qs_params = set(qs_params).intersection(extra_kwargs) 
     127        if extra_qs_params: 
     128            raise cherrypy.HTTPError(404, 
     129                message="Unexpected query string "\ 
     130                        "parameters: %s" % ", ".join(extra_qs_params)) 
     131 
     132        # If there were any extra body parameters, it's a 400 Not Found 
     133        extra_body_params = set(body_params).intersection(extra_kwargs) 
     134        if extra_body_params: 
     135            raise cherrypy.HTTPError(400, 
     136                message="Unexpected body parameters: "\ 
     137                        "%s" % ", ".join(extra_body_params)) 
     138 
     139 
     140try: 
     141    import inspect 
     142except ImportError: 
     143    test_callable_spec = lambda callable, args, kwargs: None 
     144 
    25145 
    26146 
  • branches/cherrypy-3.1.x/cherrypy/_cplogging.py

    r1984 r2068  
    127127                    stream=sys.stderr 
    128128                h = logging.StreamHandler(stream) 
    129                 h.setLevel(logging.DEBUG) 
    130129                h.setFormatter(logfmt) 
    131130                h._cpbuiltin = "screen" 
     
    150149    def _add_builtin_file_handler(self, log, fname): 
    151150        h = logging.FileHandler(fname) 
    152         h.setLevel(logging.DEBUG) 
    153151        h.setFormatter(logfmt) 
    154152        h._cpbuiltin = "file" 
     
    198196            if not h: 
    199197                h = WSGIErrorHandler() 
    200                 h.setLevel(logging.DEBUG) 
    201198                h.setFormatter(logfmt) 
    202199                h._cpbuiltin = "wsgi" 
  • branches/cherrypy-3.1.x/cherrypy/_cprequest.py

    r1994 r2068  
    99from cherrypy import _cpcgifs, _cpconfig 
    1010from cherrypy._cperror import format_exc, bare_error 
    11 from cherrypy.lib import http 
     11from cherrypy.lib import http, file_generator 
    1212 
    1313 
     
    748748 
    749749 
    750 def file_generator(input, chunkSize=65536): 
    751     """Yield the given input (a file object) in chunks (default 64k). (Core)""" 
    752     chunk = input.read(chunkSize) 
    753     while chunk: 
    754         yield chunk 
    755         chunk = input.read(chunkSize) 
    756     input.close() 
    757  
    758  
    759750class Body(object): 
    760751    """The body of the HTTP response (the response entity).""" 
  • branches/cherrypy-3.1.x/cherrypy/_cpserver.py

    r1994 r2068  
    5050    reverse_dns = False 
    5151    thread_pool = 10 
     52    thread_pool_max = -1 
    5253    max_request_header_size = 500 * 1024 
    5354    max_request_body_size = 100 * 1024 * 1024 
  • branches/cherrypy-3.1.x/cherrypy/_cptree.py

    r1989 r2068  
    154154        root: an instance of a "controller class" (a collection of page 
    155155            handler methods) which represents the root of the application. 
     156            This may also be an Application instance, or None if using 
     157            a dispatcher other than the default. 
    156158        script_name: a string containing the "mount point" of the application. 
    157159            This should start with a slash, and be the path portion of the 
     
    169171        if isinstance(root, Application): 
    170172            app = root 
     173            if script_name != "" and script_name != app.script_name: 
     174                raise ValueError, "Cannot specify a different script name and pass an Application instance to cherrypy.mount" 
     175            script_name = app.script_name 
    171176        else: 
    172177            app = Application(root, script_name) 
    173178             
    174179            # If mounted at "", add favicon.ico 
    175             if script_name == "" and root and not hasattr(root, "favicon_ico"): 
     180            if (script_name == "" and root is not None 
     181                    and not hasattr(root, "favicon_ico")): 
    176182                favicon = os.path.join(os.getcwd(), os.path.dirname(__file__), 
    177183                                       "favicon.ico") 
  • branches/cherrypy-3.1.x/cherrypy/_cpwsgi_server.py

    r1994 r2068  
    4444                   server.thread_pool, 
    4545                   server.socket_host, 
     46                   max = server.thread_pool_max, 
    4647                   request_queue_size = server.socket_queue_size, 
    4748                   timeout = server.socket_timeout, 
  • branches/cherrypy-3.1.x/cherrypy/cherryd

    r2067 r2068  
    99 
    1010def start(configfiles=None, daemonize=False, environment=None, 
    11           fastcgi=False, pidfile=None, imports=None): 
     11          fastcgi=False, scgi=False, pidfile=None, imports=None): 
    1212    """Subscribe all engine plugins and start the engine.""" 
     13    sys.path = [''] + sys.path 
    1314    for i in imports or []: 
    1415        exec "import %s" % i 
     
    3637        engine.console_control_handler.subscribe() 
    3738     
    38     if fastcgi: 
    39         # turn off autoreload when using fastcgi 
    40         cherrypy.config.update({'autoreload.on': False}) 
    41          
     39    if fastcgi and scgi: 
     40        # fastcgi and scgi aren't allowed together. 
     41        cherrypy.log.error("fastcgi and scgi aren't allowed together.", 'ENGINE') 
     42        sys.exit(1) 
     43    elif fastcgi or scgi: 
     44        # Turn off autoreload when using fastcgi or scgi. 
     45        cherrypy.config.update({'engine.autoreload_on': False}) 
     46        # Turn off the default HTTP server (which is subscribed by default). 
    4247        cherrypy.server.unsubscribe() 
    4348         
    44         fastcgi_port = cherrypy.config.get('server.socket_port', 4000) 
    45         fastcgi_bindaddr = cherrypy.config.get('server.socket_host', '0.0.0.0') 
    46         bindAddress = (fastcgi_bindaddr, fastcgi_port) 
    47         f = servers.FlupFCGIServer(application=cherrypy.tree, bindAddress=bindAddress) 
     49        sock_file = cherrypy.config.get('server.socket_file', None) 
     50        if sock_file: 
     51            bindAddress = sock_file 
     52        else: 
     53            flup_port = cherrypy.config.get('server.socket_port', 4000) 
     54            flup_bindaddr = cherrypy.config.get('server.socket_host', '0.0.0.0') 
     55            bindAddress = (flup_bindaddr, flup_port) 
     56        if fastcgi: 
     57            f = servers.FlupFCGIServer(application=cherrypy.tree, bindAddress=bindAddress) 
     58        else: 
     59            f = servers.FlupSCGIServer(application=cherrypy.tree, bindAddress=bindAddress) 
    4860        s = servers.ServerAdapter(engine, httpserver=f, bind_addr=bindAddress) 
    4961        s.subscribe() 
     
    7183    p.add_option('-f', action="store_true", dest='fastcgi', 
    7284                 help="start a fastcgi server instead of the default HTTP server") 
     85    p.add_option('-s', action="store_true", dest='scgi', 
     86                 help="start a scgi server instead of the default HTTP server") 
    7387    p.add_option('-i', '--import', action="append", dest='imports', 
    7488                 help="specify modules to import") 
     
    7892     
    7993    start(options.config, options.daemonize, 
    80           options.environment, options.fastcgi, options.pidfile, 
     94          options.environment, options.fastcgi, options.scgi, options.pidfile, 
    8195          options.imports) 
    8296 
  • branches/cherrypy-3.1.x/cherrypy/lib/__init__.py

    r1794 r2068  
    134134    return _Builder().build(obj) 
    135135 
     136 
     137def file_generator(input, chunkSize=65536): 
     138    """Yield the given input (a file object) in chunks (default 64k). (Core)""" 
     139    chunk = input.read(chunkSize) 
     140    while chunk: 
     141        yield chunk 
     142        chunk = input.read(chunkSize) 
     143    input.close() 
     144 
     145 
     146def file_generator_limited(fileobj, count, chunk_size=65536): 
     147    """Yield the given file object in chunks, stopping after `count` 
     148    bytes has been emitted.  Default chunk size is 64kB. (Core) 
     149    """ 
     150    remaining = count 
     151    while remaining > 0: 
     152        chunk = fileobj.read(min(chunk_size, remaining)) 
     153        chunklen = len(chunk) 
     154        if chunklen == 0: 
     155            return 
     156        remaining -= chunklen 
     157        yield chunk 
     158 
  • branches/cherrypy-3.1.x/cherrypy/lib/cptools.py

    r1980 r2068  
    213213        pass 
    214214     
    215     def login_screen(self, from_page='..', username='', error_msg=''): 
     215    def login_screen(self, from_page='..', username='', error_msg='', **kwargs): 
    216216        return """<html><body> 
    217217Message: %(error_msg)s 
     
    225225                     'error_msg': error_msg} 
    226226     
    227     def do_login(self, username, password, from_page='..'): 
     227    def do_login(self, username, password, from_page='..', **kwargs): 
    228228        """Login. May raise redirect, or return True if request handled.""" 
    229229        error_msg = self.check_username_and_password(username, password) 
     
    240240            raise cherrypy.HTTPRedirect(from_page or "/") 
    241241     
    242     def do_logout(self, from_page='..'): 
     242    def do_logout(self, from_page='..', **kwargs): 
    243243        """Logout. May raise redirect, or return True if request handled.""" 
    244244        sess = cherrypy.session 
  • branches/cherrypy-3.1.x/cherrypy/lib/http.py

    r1994 r2068  
    252252 
    253253def parse_query_string(query_string, keep_blank_values=True): 
    254     """Build a params dictionary from a query_string.""" 
     254    """Build a params dictionary from a query_string. 
     255     
     256    Duplicate key/value pairs in the provided query_string will be 
     257    returned as {'key': [val1, val2, ...]}. Single key/values will 
     258    be returned as strings: {'key': 'value'}. 
     259    """ 
    255260    if image_map_pattern.match(query_string): 
    256261        # Server-side image map. Map the coords to 'x' and 'y' 
  • branches/cherrypy-3.1.x/cherrypy/lib/httpauth.py

    r1891 r2068  
    276276        H_A1 = H(_A1(params, password)) 
    277277 
    278     if qop == "auth" or aop == "auth-int"
     278    if qop in ("auth", "auth-int")
    279279        # If the "qop" value is "auth" or "auth-int": 
    280280        # request-digest  = <"> < KD ( H(A1),     unq(nonce-value) 
     
    291291            H_A2, 
    292292        ) 
    293  
    294293    elif qop is None: 
    295294        # If the "qop" directive is not present (this construction is 
  • branches/cherrypy-3.1.x/cherrypy/lib/profiler.py

    r1985 r2068  
    161161class make_app: 
    162162    def __init__(self, nextapp, path=None, aggregate=False): 
    163         """Make a WSGI middleware app which wraps 'nextapp' with profiling.""" 
     163        """Make a WSGI middleware app which wraps 'nextapp' with profiling. 
     164         
     165        nextapp: the WSGI application to wrap, usually an instance of 
     166            cherrypy.Application. 
     167        path: where to dump the profiling output. 
     168        aggregate: if True, profile data for all HTTP requests will go in 
     169            a single file. If False (the default), each HTTP request will 
     170            dump its profile data into a separate file. 
     171        """ 
    164172        self.nextapp = nextapp 
    165173        self.aggregate = aggregate 
  • branches/cherrypy-3.1.x/cherrypy/lib/sessions.py

    r1932 r2068  
    144144        # The instances are created and destroyed per-request. 
    145145        cls = self.__class__ 
    146         if not cls.clean_thread: 
     146        if self.clean_freq and not cls.clean_thread: 
    147147            # clean_up is in instancemethod and not a classmethod, 
    148148            # so that tool config can be accessed inside the method. 
     
    283283    LOCK_SUFFIX = '.lock' 
    284284     
     285    def __init__(self, id=None, **kwargs): 
     286        # The 'storage_path' arg is required for file-based sessions. 
     287        kwargs['storage_path'] = os.path.abspath(kwargs['storage_path']) 
     288        Session.__init__(self, id=id, **kwargs) 
     289     
    285290    def setup(cls, **kwargs): 
    286291        """Set up the storage system for file-based sessions. 
     
    289294        automatically when using sessions.init (as the built-in Tool does). 
    290295        """ 
    291         if 'storage_path' in kwargs: 
    292             kwargs['storage_path'] = os.path.abspath(kwargs['storage_path']) 
     296        # The 'storage_path' arg is required for file-based sessions. 
     297        kwargs['storage_path'] = os.path.abspath(kwargs['storage_path']) 
    293298         
    294299        for k, v in kwargs.iteritems(): 
  • branches/cherrypy-3.1.x/cherrypy/lib/static.py

    r1975 r2068  
    1111 
    1212import cherrypy 
    13 from cherrypy.lib import cptools, http 
     13from cherrypy.lib import cptools, http, file_generator_limited 
    1414 
    1515 
     
    8484                # Return a single-part response. 
    8585                start, stop = r[0] 
     86                if stop > c_len: 
     87                    stop = c_len 
    8688                r_len = stop - start 
    8789                response.status = "206 Partial Content" 
     
    9092                response.headers['Content-Length'] = r_len 
    9193                bodyfile.seek(start) 
    92                 response.body = bodyfile.read(r_len) 
     94                response.body = file_generator_limited(bodyfile, r_len) 
    9395            else: 
    9496                # Return a multipart/byteranges response. 
     
    112114                               % (start, stop - 1, c_len)) 
    113115                        bodyfile.seek(start) 
    114                         yield bodyfile.read(stop - start) 
     116                        for chunk in file_generator_limited(bodyfile, stop-start): 
     117                            yield chunk 
    115118                        yield "\r\n" 
    116119                    # Final boundary 
  • branches/cherrypy-3.1.x/cherrypy/lib/xmlrpc.py

    r1955 r2068  
    4343                                  allow_none=allow_none)) 
    4444 
    45 def on_error(): 
     45def on_error(*args, **kwargs): 
    4646    body = str(sys.exc_info()[1]) 
    4747    import xmlrpclib 
  • branches/cherrypy-3.1.x/cherrypy/process/plugins.py

    r2006 r2068  
    2222        """Register this object as a (multi-channel) listener on the bus.""" 
    2323        for channel in self.bus.listeners: 
     24            # Subscribe self.start, self.exit, etc. if present. 
    2425            method = getattr(self, channel, None) 
    2526            if method is not None: 
     
    2930        """Unregister this object as a listener on the bus.""" 
    3031        for channel in self.bus.listeners: 
     32            # Unsubscribe self.start, self.exit, etc. if present. 
    3133            method = getattr(self, channel, None) 
    3234            if method is not None: 
     
    214216                self.bus.log('Started as uid: %r gid: %r' % current_ids()) 
    215217                if self.gid is not None: 
    216                     os.setgid(gid) 
     218                    os.setgid(self.gid) 
    217219                if self.uid is not None: 
    218                     os.setuid(uid) 
     220                    os.setuid(self.uid) 
    219221                self.bus.log('Running as uid: %r gid: %r' % current_ids()) 
    220222         
     
    232234         
    233235        self.finalized = True 
    234     start.priority = 75 
     236    # This is slightly higher than the priority for server.start 
     237    # in order to facilitate the most common use: starting on a low 
     238    # port (which requires root) and then dropping to another user. 
     239    start.priority = 77 
    235240 
    236241 
  • branches/cherrypy-3.1.x/cherrypy/process/servers.py

    r1974 r2068  
    125125     
    126126    def __init__(self, *args, **kwargs): 
     127        self.args = args 
     128        self.kwargs = kwargs 
     129        self.ready = False 
     130     
     131    def start(self): 
     132        """Start the FCGI server.""" 
     133        # We have to instantiate the server class here because its __init__ 
     134        # starts a threadpool. If we do it too early, daemonize won't work. 
    127135        from flup.server.fcgi import WSGIServer 
    128         self.fcgiserver = WSGIServer(*args, **kwargs) 
     136        self.fcgiserver = WSGIServer(*self.args, **self.kwargs) 
    129137        # TODO: report this bug upstream to flup. 
    130138        # If we don't set _oldSIGs on Windows, we get: 
     
    136144        #     for signum,handler in self._oldSIGs: 
    137145        #   AttributeError: 'WSGIServer' object has no attribute '_oldSIGs' 
     146        self.fcgiserver._installSignalHandlers = lambda: None 
    138147        self.fcgiserver._oldSIGs = [] 
    139         self.ready = False 
    140      
    141     def start(self): 
    142         """Start the FCGI server.""" 
    143148        self.ready = True 
    144149        self.fcgiserver.run() 
     
    151156        # Force all worker threads to die off. 
    152157        self.fcgiserver._threadPool.maxSpare = 0 
     158 
     159 
     160class FlupSCGIServer(object): 
     161    """Adapter for a flup.server.scgi.WSGIServer.""" 
     162     
     163    def __init__(self, *args, **kwargs): 
     164        self.args = args 
     165        self.kwargs = kwargs 
     166        self.ready = False 
     167     
     168    def start(self): 
     169        """Start the SCGI server.""" 
     170        # We have to instantiate the server class here because its __init__ 
     171        # starts a threadpool. If we do it too early, daemonize won't work. 
     172        from flup.server.scgi import WSGIServer 
     173        self.scgiserver = WSGIServer(*self.args, **self.kwargs) 
     174        # TODO: report this bug upstream to flup. 
     175        # If we don't set _oldSIGs on Windows, we get: 
     176        #   File "C:\Python24\Lib\site-packages\flup\server\threadedserver.py", 
     177        #   line 108, in run 
     178        #     self._restoreSignalHandlers() 
     179        #   File "C:\Python24\Lib\site-packages\flup\server\threadedserver.py", 
     180        #   line 156, in _restoreSignalHandlers 
     181        #     for signum,handler in self._oldSIGs: 
     182        #   AttributeError: 'WSGIServer' object has no attribute '_oldSIGs' 
     183        self.scgiserver._installSignalHandlers = lambda: None 
     184        self.scgiserver._oldSIGs = [] 
     185        self.ready = True 
     186        self.scgiserver.run() 
     187     
     188    def stop(self): 
     189        """Stop the HTTP server.""" 
     190        self.ready = False 
     191        # Forcibly stop the scgi server main event loop. 
     192        self.scgiserver._keepGoing = False 
     193        # Force all worker threads to die off. 
     194        self.scgiserver._threadPool.maxSpare = 0 
    153195 
    154196 
  • branches/cherrypy-3.1.x/cherrypy/process/win32.py

    r1989 r2068  
    7272    """A Web Site Process Bus implementation for Win32. 
    7373     
    74     Instead of using time.sleep for blocking, this bus uses native 
    75     win32event objects. It also responds to console events. 
     74    Instead of time.sleep, this bus blocks using native win32event objects. 
    7675    """ 
    7776     
     
    10099     
    101100    def wait(self, state, interval=0.1): 
    102         """Wait for the given state, KeyboardInterrupt or SystemExit. 
     101        """Wait for the given state(s), KeyboardInterrupt or SystemExit. 
    103102         
    104103        Since this class uses native win32event objects, the interval 
    105104        argument is ignored. 
    106105        """ 
    107         # Don't wait for an event that beat us to the punch ;) 
    108         if self.state != state: 
    109             event = self._get_state_event(state) 
    110             win32event.WaitForSingleObject(event, win32event.INFINITE) 
     106        if isinstance(state, (tuple, list)): 
     107            # Don't wait for an event that beat us to the punch ;) 
     108            if self.state not in state: 
     109                events = tuple([self._get_state_event(s) for s in state]) 
     110                win32event.WaitForMultipleObjects(events, 0, win32event.INFINITE) 
     111        else: 
     112            # Don't wait for an event that beat us to the punch ;) 
     113            if self.state != state: 
     114                event = self._get_state_event(state) 
     115                win32event.WaitForSingleObject(event, win32event.INFINITE) 
    111116 
    112117 
  • branches/cherrypy-3.1.x/cherrypy/process/wspbus.py

    r1989 r2068  
    154154                raise 
    155155            except: 
    156                 self.log("Error in %r listener %r" % (channel, listener), 
    157                          level=40, traceback=True) 
    158156                exc = sys.exc_info()[1] 
     157                if channel == 'log': 
     158                    # Assume any further messages to 'log' will fail. 
     159                    pass 
     160                else: 
     161                    self.log("Error in %r listener %r" % (channel, listener), 
     162                             level=40, traceback=True) 
    159163        if exc: 
    160164            raise 
     
    249253     
    250254    def wait(self, state, interval=0.1): 
    251         """Wait for the given state.""" 
     255        """Wait for the given state(s).""" 
     256        if isinstance(state, (tuple, list)): 
     257            states = state 
     258        else: 
     259            states = [state] 
     260         
    252261        def _wait(): 
    253             while self.state != state
     262            while self.state not in states
    254263                time.sleep(interval) 
    255264         
  • branches/cherrypy-3.1.x/cherrypy/test/helper.py

    r2004 r2068  
    148148        else: 
    149149            app = validate.validator(app) 
    150     cherrypy.server.httpserver.wsgi_app = app 
     150     
     151    h = cherrypy.server.httpserver 
     152    if hasattr(h, 'wsgi_app'): 
     153        # CherryPy's wsgiserver 
     154        h.wsgi_app = app 
     155    elif hasattr(h, 'fcgiserver'): 
     156        # flup's WSGIServer 
     157        h.fcgiserver.application = app 
     158    elif hasattr(h, 'scgiserver'): 
     159        # flup's WSGIServer 
     160        h.scgiserver.application = app 
    151161 
    152162def _run_test_suite_thread(moduleNames, conf): 
  • branches/cherrypy-3.1.x/cherrypy/test/modwsgi.py

    r1824 r2068  
    3434 
    3535import os 
    36 curdir = os.path.join(os.getcwd(), os.path.dirname(__file__)) 
     36curdir = os.path.abspath(os.path.dirname(__file__)) 
    3737import re 
     38import sys 
    3839import time 
    3940 
    40 from cherrypy.test import test 
     41import cherrypy 
     42from cherrypy.test import test, webtest 
    4143 
    4244 
     
    5456 
    5557 
    56 APACHE_PATH = "apache" 
     58if sys.platform == 'win32': 
     59    APACHE_PATH = "httpd" 
     60else: 
     61    APACHE_PATH = "apache" 
     62 
    5763CONF_PATH = "test_mw.conf" 
    5864 
    59 conf_modwsgi = """ 
     65conf_modwsgi = r""" 
    6066# Apache2 server conf file for testing CherryPy with modpython_gateway. 
    6167 
     68ServerName 127.0.0.1 
    6269DocumentRoot "/" 
    63 Listen %%s 
     70Listen %(port)s 
     71 
     72AllowEncodedSlashes On 
     73LoadModule rewrite_module modules/mod_rewrite.so 
     74RewriteEngine on 
     75RewriteMap escaping int:escape 
     76 
     77LoadModule log_config_module modules/mod_log_config.so 
     78LogFormat "%%h %%l %%u %%t \"%%r\" %%>s %%b \"%%{Referer}i\" \"%%{User-agent}i\"" combined 
     79CustomLog "%(curdir)s/apache.access.log" combined 
     80ErrorLog "%(curdir)s/apache.error.log" 
     81LogLevel debug 
     82 
    6483LoadModule wsgi_module modules/mod_wsgi.so 
    6584LoadModule env_module modules/mod_env.so 
    6685 
    67 WSGIScriptAlias / %s 
    68 SetEnv testmod %%
    69 """ % os.path.join(curdir, 'modwsgi.py') 
     86WSGIScriptAlias / "%(curdir)s/modwsgi.py" 
     87SetEnv testmod %(testmod)
     88""" 
    7089 
    7190 
     
    7796    f = open(mpconf, 'wb') 
    7897    try: 
    79         f.write(conf_template % (port, testmod)) 
     98        output = (conf_template % 
     99                  {'port': port, 'testmod': testmod, 'curdir': curdir}) 
     100        f.write(output) 
    80101    finally: 
    81102        f.close() 
     
    114135            try: 
    115136                start(testmod, self.port, conf_template) 
     137                cherrypy._cpserver.wait_for_occupied_port("127.0.0.1", self.port) 
    116138                suite = webtest.ReloadingTestLoader().loadTestsFromName(testmod) 
     139                # Make a request so mod_wsgi starts up our app. 
     140                # If we don't, concurrent initial requests will 404. 
     141                webtest.openURL('/ihopetheresnodefault', port=self.port) 
     142                time.sleep(1) 
    117143                result = webtest.TerseTestRunner(verbosity=2).run(suite) 
    118144                success &= result.wasSuccessful() 
     
    136162         
    137163        cherrypy.config.update({ 
    138             "log.error_file": os.path.join(curdir, "test.log"), 
     164            "log.error_file": os.path.join(curdir, "test.error.log"), 
     165            "log.access_file": os.path.join(curdir, "test.access.log"), 
    139166            "environment": "test_suite", 
    140167            "engine.SIGHUP": None, 
    141168            "engine.SIGTERM": None, 
    142169            }) 
    143         cherrypy.server.unsubscribe() 
    144         cherrypy.engine.start(blocking=False) 
    145170    return cherrypy.tree(environ, start_response) 
    146171 
  • branches/cherrypy-3.1.x/cherrypy/test/test.py

    r2003 r2068  
    9191                         'modpygw': "modpygw", 
    9292                         'modwsgi': "modwsgi", 
     93                         'modfcgid': "modfcgid", 
    9394                         } 
    9495    default_server = "wsgi" 
     
    333334                                           "http", self.interactive) 
    334335            h.use_wsgi = True 
     336        elif self.server == 'modfcgid': 
     337            from cherrypy.test import modfcgid 
     338            h = modfcgid.FCGITestHarness(self.tests, self.server, 
     339                                         self.protocol, self.port, 
     340                                         "http", self.interactive) 
    335341        else: 
    336342            h = TestHarness(self.tests, self.server, self.protocol, 
  • branches/cherrypy-3.1.x/cherrypy/test/test_core.py

    r1992 r2068  
    9999            return "args: %s kwargs: %s" % (args, kwargs) 
    100100 
     101    class ParamErrors(Test): 
     102 
     103        def one_positional(self, param1): 
     104            return "data" 
     105        one_positional.exposed = True 
     106 
     107        def one_positional_args(self, param1, *args): 
     108            return "data" 
     109        one_positional_args.exposed = True 
     110 
     111        def one_positional_args_kwargs(self, param1, *args, **kwargs): 
     112            return "data" 
     113        one_positional_args_kwargs.exposed = True 
     114 
     115        def one_positional_kwargs(self, param1, **kwargs): 
     116            return "data" 
     117        one_positional_kwargs.exposed = True 
     118 
     119        def no_positional(self): 
     120            return "data" 
     121        no_positional.exposed = True 
     122 
     123        def no_positional_args(self, *args): 
     124            return "data" 
     125        no_positional_args.exposed = True 
     126 
     127        def no_positional_args_kwargs(self, *args, **kwargs): 
     128            return "data" 
     129        no_positional_args_kwargs.exposed = True 
     130 
     131        def no_positional_kwargs(self, **kwargs): 
     132            return "data" 
     133        no_positional_kwargs.exposed = True 
     134 
    101135 
    102136    class Status(Test): 
     
    444478        self.getPage("/params/?thing=a&thing=b&thing=c") 
    445479        self.assertBody("['a', 'b', 'c']") 
    446          
     480 
    447481        # Test friendly error message when given params are not accepted. 
    448         ignore = helper.webtest.ignored_exceptions 
    449         ignore.append(TypeError) 
    450         try: 
    451             self.getPage("/params/?notathing=meeting") 
    452             self.assertInBody("index() got an unexpected keyword argument 'notathing'") 
    453         finally: 
    454             ignore.pop() 
     482        self.getPage("/params/?notathing=meeting") 
     483        self.assertInBody("Missing parameters: thing") 
     484        self.getPage("/params/?thing=meeting&notathing=meeting") 
     485        self.assertInBody("Unexpected query string parameters: notathing") 
    455486         
    456487        # Test "% HEX HEX"-encoded URL, param keys, and values 
     
    467498        self.getPage("/params/ismap?223,114") 
    468499        self.assertBody("Coordinates: 223, 114") 
    469      
     500 
     501    def testParamErrors(self): 
     502 
     503        # test that all of the handlers work when given  
     504        # the correct parameters in order to ensure that the 
     505        # errors below aren't coming from some other source. 
     506        for uri in ( 
     507                '/paramerrors/one_positional?param1=foo', 
     508                '/paramerrors/one_positional_args?param1=foo', 
     509                '/paramerrors/one_positional_args/foo', 
     510                '/paramerrors/one_positional_args/foo/bar/baz', 
     511                '/paramerrors/one_positional_args_kwargs?param1=foo&param2=bar', 
     512                '/paramerrors/one_positional_args_kwargs/foo?param2=bar&param3=baz', 
     513                '/paramerrors/one_positional_args_kwargs/foo/bar/baz?param2=bar&param3=baz', 
     514                '/paramerrors/one_positional_kwargs?param1=foo&param2=bar&param3=baz', 
     515                '/paramerrors/one_positional_kwargs/foo?param4=foo&param2=bar&param3=baz', 
     516                '/paramerrors/no_positional', 
     517                '/paramerrors/no_positional_args/foo', 
     518                '/paramerrors/no_positional_args/foo/bar/baz', 
     519                '/paramerrors/no_positional_args_kwargs?param1=foo&param2=bar', 
     520                '/paramerrors/no_positional_args_kwargs/foo?param2=bar', 
     521                '/paramerrors/no_positional_args_kwargs/foo/bar/baz?param2=bar&param3=baz', 
     522                '/paramerrors/no_positional_kwargs?param1=foo&param2=bar', 
     523            ): 
     524            self.getPage(uri) 
     525            self.assertStatus(200) 
     526 
     527        # query string parameters are part of the URI, so if they are wrong 
     528        # for a particular handler, the status MUST be a 404. 
     529        for uri in ( 
     530                '/paramerrors/one_positional', 
     531                '/paramerrors/one_positional?foo=foo', 
     532                '/paramerrors/one_positional/foo/bar/baz', 
     533                '/paramerrors/one_positional/foo?param1=foo', 
     534                '/paramerrors/one_positional/foo?param1=foo&param2=foo', 
     535                '/paramerrors/one_positional_args/foo?param1=foo&param2=foo', 
     536                '/paramerrors/one_positional_args/foo/bar/baz?param2=foo', 
     537                '/paramerrors/one_positional_args_kwargs/foo/bar/baz?param1=bar&param3=baz', 
     538                '/paramerrors/one_positional_kwargs/foo?param1=foo&param2=bar&param3=baz', 
     539                '/paramerrors/no_positional/boo', 
     540                '/paramerrors/no_positional?param1=foo', 
     541                '/paramerrors/no_positional_args/boo?param1=foo', 
     542                '/paramerrors/no_positional_kwargs/boo?param1=foo', 
     543            ): 
     544            self.getPage(uri) 
     545            self.assertStatus(404) 
     546 
     547        # if body parameters are wrong, a 400 must be returned. 
     548        for uri, body in ( 
     549                ('/paramerrors/one_positional/foo', 'param1=foo',), 
     550                ('/paramerrors/one_positional/foo', 'param1=foo&param2=foo',), 
     551                ('/paramerrors/one_positional_args/foo', 'param1=foo&param2=foo',), 
     552                ('/paramerrors/one_positional_args/foo/bar/baz', 'param2=foo',), 
     553                ('/paramerrors/one_positional_args_kwargs/foo/bar/baz', 'param1=bar&param3=baz',), 
     554                ('/paramerrors/one_positional_kwargs/foo', 'param1=foo&param2=bar&param3=baz',), 
     555                ('/paramerrors/no_positional', 'param1=foo',), 
     556                ('/paramerrors/no_positional_args/boo', 'param1=foo',), 
     557            ): 
     558            self.getPage(uri, method='POST', body=body) 
     559            self.assertStatus(400) 
     560 
     561 
     562        # even if body parameters are wrong, if we get the uri wrong, then  
     563        # it's a 404 
     564        for uri, body in ( 
     565                ('/paramerrors/one_positional?param2=foo', 'param1=foo',), 
     566                ('/paramerrors/one_positional/foo/bar', 'param2=foo',), 
     567                ('/paramerrors/one_positional_args/foo/bar?param2=foo', 'param3=foo',), 
     568                ('/paramerrors/one_positional_kwargs/foo/bar', 'param2=bar&param3=baz',), 
     569                ('/paramerrors/no_positional?param1=foo', 'param2=foo',), 
     570                ('/paramerrors/no_positional_args/boo?param2=foo', 'param1=foo',), 
     571            ): 
     572            self.getPage(uri, method='POST', body=body) 
     573            self.assertStatus(404) 
     574 
     575 
    470576    def testStatus(self): 
    471577        self.getPage("/status/") 
     
    10531159        self.getPage('/url/leaf?path_info=/page1&relative=True') 
    10541160        self.assertBody('../page1') 
     1161        self.getPage('/url/leaf?path_info=page1&relative=True') 
     1162        self.assertBody('page1') 
     1163        self.getPage('/url/leaf?path_info=leaf/page1&relative=True') 
     1164        self.assertBody('leaf/page1') 
    10551165        self.getPage('/url/leaf?path_info=../page1&relative=True') 
    10561166        self.assertBody('../page1') 
  • branches/cherrypy-3.1.x/cherrypy/test/test_http.py

    r1915 r2068  
    104104                          response_body) 
    105105 
     106    def test_malformed_request_line(self): 
     107        # Test missing version in Request-Line 
     108        if self.scheme == 'https': 
     109            c = httplib.HTTPSConnection('127.0.0.1:%s' % self.PORT) 
     110        else: 
     111            c = httplib.HTTPConnection('127.0.0.1:%s' % self.PORT) 
     112        c._output('GET /') 
     113        c._send_output() 
     114        response = c.response_class(c.sock, strict=c.strict, method='GET') 
     115        response.begin() 
     116        self.assertEqual(response.status, 400) 
     117        self.assertEqual(response.fp.read(), "Malformed Request-Line") 
     118        c.close() 
     119 
    106120 
    107121if __name__ == '__main__': 
  • branches/cherrypy-3.1.x/cherrypy/test/test_objectmapping.py

    r1767 r2068  
    11from cherrypy.test import test 
     2from cherrypy._cptree import Application 
    23test.prefer_parent_path() 
    34 
     
    269270        self.assertBody("default for dir1, param is:('dir2', '5', '3', 'sir')") 
    270271         
    271         # test that extra positional args raises an error. 
    272         # 500 for now, maybe 404 in the future. 
     272        # test that extra positional args raises an 404 Not Found 
    273273        # See http://www.cherrypy.org/ticket/733. 
    274274        self.getPage("/dir1/dir2/script_name/extra/stuff") 
    275         self.assertStatus(500
     275        self.assertStatus(404
    276276     
    277277    def testExpose(self): 
     
    325325        self.assertBody("milk") 
    326326 
     327    def testTreeMounting(self): 
     328 
     329        # When mounting an application instance,  
     330        # we can't specify a script name in the call to mount. 
     331        a = Application(object(), '/somewhere') 
     332        self.assertRaises(ValueError, cherrypy.tree.mount, a, '/somewhereelse') 
     333 
     334        # When mounting an application instance,  
     335        # we can't specify a script name in the call to mount. 
     336        a = Application(object(), '/somewhere') 
     337        try: 
     338            cherrypy.tree.mount(a, '/somewhere') 
     339        except ValueError: 
     340            self.fail("tree.mount must allow script_names which are the same") 
     341 
     342        try: 
     343            cherrypy.tree.mount(a) 
     344        except ValueError: 
     345            self.fail("cherrypy.tree.mount incorrectly raised a ValueError") 
     346 
     347 
     348 
     349 
    327350 
    328351if __name__ == "__main__": 
  • branches/cherrypy-3.1.x/cherrypy/test/test_sessionauthenticate.py

    r1614 r2068  
    1111            return u'Wrong login/password' 
    1212     
     13    def augment_params(): 
     14        # A simple tool to add some things to request.params 
     15        # This is to check to make sure that session_auth can handle request 
     16        # params (ticket #780) 
     17        cherrypy.request.params["test"] = "test" 
     18 
     19    cherrypy.tools.augment_params = cherrypy.Tool('before_handler', 
     20             augment_params, None, priority=30) 
     21 
    1322    class Test: 
    1423         
     
    1625                      'tools.session_auth.on': True, 
    1726                      'tools.session_auth.check_username_and_password': check, 
     27                      'tools.augment_params.on': True, 
    1828                      } 
    1929         
    20         def index(self): 
     30        def index(self, **kwargs): 
    2131            return "Hi %s, you are logged in" % cherrypy.request.login 
    2232        index.exposed = True 
  • branches/cherrypy-3.1.x/cherrypy/test/test_xmlrpc.py

    r1955 r2068  
    6969    cherrypy.tree.mount(root, config={'/': { 
    7070        'request.dispatch': cherrypy.dispatch.XMLRPCDispatcher(), 
     71        'tools.xmlrpc.allow_none': 0, 
    7172        }}) 
    7273    cherrypy.config.update({'environment': 'test_suite'}) 
  • branches/cherrypy-3.1.x/cherrypy/wsgiserver/__init__.py

    r2007 r2068  
    333333        environ = self.environ 
    334334         
    335         method, path, req_protocol = request_line.strip().split(" ", 2) 
     335        try: 
     336            method, path, req_protocol = request_line.strip().split(" ", 2) 
     337        except ValueError: 
     338            self.simple_response(400, "Malformed Request-Line") 
     339            return 
     340         
    336341        environ["REQUEST_METHOD"] = method 
    337342         
     
    402407            self.simple_response("413 Request Entity Too Large") 
    403408            return 
    404          
    405         # Set AUTH_TYPE, REMOTE_USER 
    406         creds = environ.get("HTTP_AUTHORIZATION", "").split(" ", 1) 
    407         environ["AUTH_TYPE"] = creds[0] 
    408         if creds[0].lower() == 'basic': 
    409             user, pw = base64.decodestring(creds[1]).split(":", 1) 
    410             environ["REMOTE_USER"] = user 
    411409         
    412410        # Persistent connection support 
     
    589587        if msg: 
    590588            buf.append(msg) 
    591         self.wfile.sendall("".join(buf)) 
     589         
     590        try: 
     591            self.wfile.sendall("".join(buf)) 
     592        except socket.error, x: 
     593            if x.args[0] not in socket_errors_to_ignore: 
     594                raise 
    592595     
    593596    def start_response(self, status, headers, exc_info = None): 
     
    12041207 
    12051208 
     1209try: 
     1210    import fcntl 
     1211except ImportError: 
     1212    try: 
     1213        from ctypes import windll, WinError 
     1214    except ImportError: 
     1215        def prevent_socket_inheritance(sock): 
     1216            """Dummy function, since neither fcntl nor ctypes are available.""" 
     1217            pass 
     1218    else: 
     1219        def prevent_socket_inheritance(sock): 
     1220            """Mark the given socket fd as non-inheritable (Windows).""" 
     1221            if not windll.kernel32.SetHandleInformation(sock.fileno(), 1, 0): 
     1222                raise WinError() 
     1223else: 
     1224    def prevent_socket_inheritance(sock): 
     1225        """Mark the given socket fd as non-inheritable (POSIX).""" 
     1226        fd = sock.fileno() 
     1227        old_flags = fcntl.fcntl(fd, fcntl.F_GETFD) 
     1228        fcntl.fcntl(fd, fcntl.F_SETFD, old_flags | fcntl.FD_CLOEXEC) 
     1229 
    12061230 
    12071231class CherryPyWSGIServer(object): 
     
    13971421        """Create (or recreate) the actual socket object.""" 
    13981422        self.socket = socket.socket(family, type, proto) 
     1423        prevent_socket_inheritance(self.socket) 
    13991424        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
    14001425        if self.nodelay: 
     
    14161441        try: 
    14171442            s, addr = self.socket.accept() 
     1443            prevent_socket_inheritance(s) 
    14181444            if not self.ready: 
    14191445                return 
     
    14241450            # SERVER_SOFTWARE is common for IIS. It's also helpful for 
    14251451            # us to pass a default value for the "Server" response header. 
    1426             environ["SERVER_SOFTWARE"] = "%s WSGI Server" % self.version 
     1452            if environ.get("SERVER_SOFTWARE") is None: 
     1453                environ["SERVER_SOFTWARE"] = "%s WSGI Server" % self.version 
    14271454            # set a non-standard environ entry so the WSGI app can know what 
    14281455            # the *real* server protocol is (and what features to support). 
  • branches/cherrypy-3.1.x/ez_setup.py

    r614 r2068  
    1919 
    2020import sys, os 
    21  
    22  
    23  
    24  
    25  
    26  
    27  
    28  
    29  
    30  
    31  
    32  
    33  
    34  
    35  
    36  
    37  
    38  
    39  
    40  
    4121 
    4222def use_setuptools( 
     
    11292    return os.path.realpath(saveto) 
    11393 
    114  
    115  
    116  
    117  
    118  
    119  
    120  
    121  
    122  
    123  
    12494def main(argv, version=DEFAULT_VERSION): 
    12595    """Install or upgrade setuptools and EasyInstall""" 
     
    162132if __name__=='__main__': 
    163133    main(sys.argv[1:]) 
    164  

Hosted by WebFaction

Log in as guest/cpguest to create tickets