Waitress - A WSGI server for Python 2 and 3

Overview

Waitress

latest version of waitress on PyPI master Documentation Status IRC Freenode

Waitress is a production-quality pure-Python WSGI server with very acceptable performance. It has no dependencies except ones which live in the Python standard library. It runs on CPython on Unix and Windows under Python 3.6+. It is also known to run on PyPy (version 3.6 compatible) on UNIX. It supports HTTP/1.0 and HTTP/1.1.

For more information, see the "docs" directory of the Waitress package or visit https://docs.pylonsproject.org/projects/waitress/en/latest/

Comments
  • Notify client close

    Notify client close

    Implementation of the idea discussed in #308. The tests don't pass yet and I should also implement additional tests for this, but hopefully this helps with the discussion.

    opened by viktordick 31
  • Double slash at the end of url combined with proxy-prefix middleware causes redirection loop

    Double slash at the end of url combined with proxy-prefix middleware causes redirection loop

    So just discovered funny case, i have my pylons app served with proxy prefix middleware. i set in my ini file

    [filter:proxy-prefix]
    use = egg:PasteDeploy#prefix
    prefix = /pref
    ...
    [app:main]
    filter-with = proxy-prefix
    

    now entering an url server/pref/ works as expected but server/pref// causes waitress to trigger a 301 redirect to /pref/// that triggers another redirect and we end up in a loop.

    good old Paste#http server works as expected in such case.

    sprintable 
    opened by marcinkuzminski 21
  • WIP: Use Forwarded/X-Forwarded-{For,Host,By,Port,Proto} to fixup WSGI environ

    WIP: Use Forwarded/X-Forwarded-{For,Host,By,Port,Proto} to fixup WSGI environ

    If we are in a trusted proxy situation whereby waitress is running behind nginx/haproxy/any other reverse proxy (whose IP matches what is configured, or if the socket we receive the connection on is a unix socket) then we want to pull a variety of information from the X-Forwarded-* headers or Forwarded which has superseded it.

    The algorithm will pull X-Forwarded-* headers, unless there is a Forwarded header present and trusted_proxy_headers is set to just forwarded, in which case it takes priority.

    By default we will use the proxy Forwarded header to set the following:

    • wsgi.url_scheme (Proto)
    • SERVER_NAME (Using Host param)
    • SERVER_PORT (Using Proto param to set a default, overriden by Host param)
    • HTTP_HOST (Using Host param, adding the SERVER_PORT as necessary)
    • REMOTE_ADDR (Using For param, first For is used as it is client IP address)
    • REMOTE_PORT (Using For param, as above, if a port is available)

    This off course also means that Waitress now supports https://tools.ietf.org/html/rfc7239 's Forwarded header! Yay for being standards compliant.

    Waitress also now knows how to clean up the headers and thus the WSGI environment, so that untrusted headers are no longer passed through to downstream WSGI applications using clear_untrusted_proxy_headers.

    Closes https://github.com/Pylons/waitress/issues/207

    opened by bertjwregeer 20
  • Waitress 2.1.0 Performance Issue

    Waitress 2.1.0 Performance Issue

    My organization runs a Pyramid web application that we deploy to AWS Elastic Container Service (Fargate). Waitress serves the Pyramid application with nginx as a reverse proxy on a Debian buster image. We found upon taking waitress 2.1.0 we saw an immediate performance degradation. Specifically for response sizes above ~50kb (compressed by nginx), we see a ~5-10x slowdown on responses, resulting in numerous 504s for our various APIs. Upon rolling back to version 2.0.0, performance is restored. This is on Python 3.7.12.

    I use locust to run performance tests on the web application, which allows me to quickly isolate and identify the root cause of such dramatic performance changes. All system level dependencies are identical (those installed by apt), as are other Python libraries.

    Pre-update (waitress 2.0.0):

    Response time percentiles (approximated in ms)
     Type     Name            50%    66%    75%    80%    90%    95%    98%    99%   99.9%  99.99%   100%
    --------|------------|---------|------|------|------|------|------|------|------|------|------|------|
     All     Aggregated       750    980   1200   1400   1800   2300   4000   4600   6500   6500   6500 
    

    Post update (waitress 2.1.0):

    Response time percentiles (approximated in ms)
     Type     Name             50%    66%    75%    80%    90%    95%    98%    99%  99.9% 99.99%   100%
    -------|------------|---------|------|------|------|------|------|------|------|------|------|------|
     All     Aggregated      780    1500   2600   5300  21000  57000  60000  61000  61000  61000  61000
    

    This test was run on the same environment - only difference is the waitress version. Most routes that return small responses are not affected, but as soon as response size gets beyond a certain threshold the performance falls off a cliff.

    Any thoughts why this might be? Something obvious I am missing? It is entirely possible there is a mistake or misconfiguration on my end, but such a slowdown is very suspicious and I believe isolated to this version.

    Dockerfile

    nginx.conf

    opened by willronchetti 18
  • Allow passing of sockets for socket activation

    Allow passing of sockets for socket activation

    As discussed in issue #204, the pull request adds the new parameter sockets to serve and create_server which can be used to create waitress instances using already existing and bound sockets, e.g. for socket activation with systemd or launchd.

    The changes are tested with several additional test cases.

    In addition to the code changes, it adds a new page to the documentation and a new entry to describe the new parameter sockets in the page for arguments. Adding the entry in arguments is done under the assumption that the next version will be 1.1.1 to supply the version number for versionadded.

    The changes only add the parameter, they do not handle init system specific tasks like creating sockets from file descriptors because we want to avoid dependencies to init systems.

    Closes #204


    This change is Reviewable

    opened by Frank-Krick 17
  • Possible race condition leading to the main loop dying?

    Possible race condition leading to the main loop dying?

    I just might be wrong because if this indeed a race condition it should be breaking more things. Anyway, I got this exception (line numbers might be wrong due to debug statements):

    Traceback (most recent call last):
      File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
        self.run()
      File "/.../lib/python3.8/site-packages/aqt/mediasrv.py", line 89, in run
        self.server.run()
      File "/.../lib/python3.8/site-packages/waitress/server.py", line 323, in run
        self.asyncore.loop(
      File "/.../lib/python3.8/site-packages/waitress/wasyncore.py", line 285, in loop
        poll_fun(timeout, map)
      File "/.../lib/python3.8/site-packages/waitress/wasyncore.py", line 211, in poll
        r, w, e = select.select(r, w, e, timeout)
    OSError: [Errno 9] Bad file descriptor
    

    This error was extremely rare but since I was getting it while running tests I could just run a lot of them until one failed, which I did, and I think the problem is a follows.

    1. First, thread Thread-1 that the app I'm testing is launching, one that runs waitress server, assembles the descriptor lists for select: https://github.com/Pylons/waitress/blob/603d2c12ce09fcd1be0b7a5734b4fca339820286/src/waitress/wasyncore.py#L154-L166

    2. Then, thread waitress-0 deletes one of the channels, in my case it was <waitress.channel.HTTPChannel 127.0.0.1:54044 at 0x7f10ec052400>, and immediately closes the socket: https://github.com/Pylons/waitress/blob/603d2c12ce09fcd1be0b7a5734b4fca339820286/src/waitress/wasyncore.py#L460-L470

      Stack of waitiress-0 at the moment:

        File "/usr/lib/python3.8/threading.py", line 890, in _bootstrap
          self._bootstrap_inner()
        File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
          self.run()
        File "/usr/lib/python3.8/threading.py", line 870, in run
          self._target(*self._args, **self._kwargs)
        File "/.../lib/python3.8/site-packages/waitress/task.py", line 84, in handler_thread
          task.service()
        File "/.../lib/python3.8/site-packages/waitress/channel.py", line 426, in service
          task.service()
        File "/.../lib/python3.8/site-packages/waitress/task.py", line 168, in service
          self.execute()
        File "/.../lib/python3.8/site-packages/waitress/task.py", line 451, in execute
          self.channel.write_soon(app_iter)
        File "/.../lib/python3.8/site-packages/waitress/channel.py", line 377, in write_soon
          (flushed, exception) = self._flush_exception(self._flush_some)
        File "/.../lib/python3.8/site-packages/waitress/channel.py", line 132, in _flush_exception
          return (flush(), False)
        File "/.../lib/python3.8/site-packages/waitress/channel.py", line 270, in _flush_some
          num_sent = self.send(chunk)
        File "/.../lib/python3.8/site-packages/waitress/wasyncore.py", line 479, in send
          self.handle_close()
        File "/.../lib/python3.8/site-packages/waitress/channel.py", line 317, in handle_close
          wasyncore.dispatcher.close(self)
        File "/.../lib/python3.8/site-packages/waitress/wasyncore.py", line 519, in close
          traceback.print_stack()
      
    3. Then, thread Thread-1 is trying to see if the file descriptor of the socked closed above is writable, which leads to the the exception above: https://github.com/Pylons/waitress/blob/603d2c12ce09fcd1be0b7a5734b4fca339820286/src/waitress/wasyncore.py#L171-L177

    Python 3.8.10, waitress 2.1.1, Ubuntu 20.04 LTS focal @ WSL2

    bug 
    opened by oakkitten 16
  • adding ssl support to waitress

    adding ssl support to waitress

    hi, if waitress provide a way to specify public and private keys for ssl it would be cool using ssl_context, or ssl_context='adhoc' which werkzeug provide by generating a certificate.

    opened by brightening-eyes 16
  • Let the possibility to specify a wildcard for the truted_proxy var

    Let the possibility to specify a wildcard for the truted_proxy var

    Here is a suggestion to use the X_FORWARDED_PROTO on cloud based reversed proxies with no fixed ip.

    I don't see any personal objection on allowing the wildcard if it is documented well enough for this particular case.

    Cheers

    opened by dulacp 16
  • Invalid host/port specified error on Windows

    Invalid host/port specified error on Windows

    We use waitress in devpi like this:

      serve(app, host=host, port=port, threads=50)
    

    and on Windows got #138 with waitress 1.0. To work around that I tried to change to the following:

      serve(app, listen="%s:%s" % (host, port), threads=50)
    

    But then I got ValueError: Invalid host/port specified.

    This only happens on Windows, Linux and OS X is fine. For now we pinned to waitress<1.

    opened by fschulze 15
  • Memory/Resource leak

    Memory/Resource leak

    With devpi-server I can now confirm a memory leak somehow related to waitress. I observed it on Debian and FreeBSD, but not on macOS. The last test I did was replacing waitress with cheroot and the leak is completely gone with that. I'm currently working on creating a minimal example for reproduction, but wanted to give a heads up in case someone else noticed something and started investigating. It is certainly possible it is related in how we use waitress in devpi-server, but I don't think we do anything special. I don't want to switch to cheroot, because it lacks some features and seems to be less performant.

    opened by fschulze 14
  • Command line runner

    Command line runner

    This is something of a selfish pull request.

    At my work, we often use waitress by itself without the likes of Paste acting as the runner as we generally delegate serving static assets and the like to the reverse proxy server sitting in front of the application. For applications like that, we use a simple command line runner specific to waitress, effectively a thin wrapper around waitress.serve. I wrote it as it simplified our deployment story quite a bit.

    This pull request adapts that code to integrate with waitress properly. Just so as you know, this code and the original runner were written on my own time, not the company's time, so there are no copyright complications involved in merging it into waitress if you think it's worthwhile.

    opened by kgaughan 14
  • test_gardenpath fails on OpenIndiana

    test_gardenpath fails on OpenIndiana

    The test_gardenpath test fails on OpenIndiana because the string returned from strerror() is implementation specific.

    Simple test case in C:

    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    
    int main(void)
    {
            printf("%s\n", strerror(EPERM));
            return 0;
    }
    

    On linux it prints: Operation not permitted, but on OpenIndiana (and thus on all illumos based distros, and likely Solaris too) it prints: Not owner.

    Here is the test failure:

    ________________________ Test__strerror.test_gardenpath ________________________
    
    self = <tests.test_wasyncore.Test__strerror testMethod=test_gardenpath>
    
        def test_gardenpath(self):
    >       self.assertEqual(self._callFUT(1), "Operation not permitted")
    
    tests/test_wasyncore.py:1199:
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    /usr/lib/python3.9/vendor-packages/teamcity/diff_tools.py:33: in _patched_equals
        old(self, first, second, msg)
    E   AssertionError: 'Not owner' != 'Operation not permitted'
    E   - Not owner
    E   + Operation not permitted
    
    opened by mtelka 0
  • Switch to pytest-cov

    Switch to pytest-cov

    According to setup.cfg the pytest-cover package is required for testing. This is unfortunate since pytest-cover was merged back to pytest-cov and is no longer maintained. Please switch waitress to use pytest-cov instead of pytest-cover.

    opened by mtelka 1
  • Backport CVE-2022-24761 for tag v1.4.4

    Backport CVE-2022-24761 for tag v1.4.4

    Hi Folks, We have a BZ to get the fix done in 2.1.1 https://github.com/Pylons/waitress/commit/9e0b8c801e4d505c2ffc91b891af4ba48af715e0 to the old versions available in EPEL

    This backport was done for RHEL7 via CVE-2022-24761.

    I created this FORK with an initial backport to v1.4.4. I wonder if we can create a new tag as v1.4.5 including this fix, + some help to validate it

    opened by ravanelli 1
  • uncaptured python exception repeatedly crashing server

    uncaptured python exception repeatedly crashing server

    One particular user keeps submitting a request to my server that causes it to crash with an uncaptured python exception. Below is the request and corresponding error:

    [2022-Jul-03 01:05] XXX.XX.XX.XXX  http /? 405 METHOD NOT ALLOWED
    [2022-Jul-03 01:06] XXX.XX.XX.XXX GET http /nice ports,/Trinity.txt.bak? 404 NOT FOUND
    [2022-Jul-03 01:06] XXX.XX.XX.XXX  http /? 405 METHOD NOT ALLOWED
    ERROR:waitress:uncaptured python exception, closing channel <waitress.server.TcpWSGIServer listening XXX.XX.XXX.XX at XXXXXXXX> (<class 'OSError'>:[Errno 22] Invalid argument [/XXXX/XXXX/XXXX/waitress/wasyncore.py|read|104] /XXXX/XXXX/XXXX/waitress/wasyncore.py|handle_read_event|492] /XXXX/XXXX/XXXX/waitress/server.py|handle_accept|316] [/XXXX/XXXX/XXXX/waitress/server.py|set_socket_options|372])
    WARNING:waitress:unhandled close event
    

    My server is a Flask app running on a Mac OS with waitress 2.1.2. I glanced into the server.py code and it looks like an exception handler is supposed to catch this situation (at least for Linux), but it doesn't seem to be working (or more likely, I don't fully understand how it should work). The other odd thing is that the same request from the same user does not always trigger the error: sometimes the server continues even after receiving the 3 identical requests that precede the error message. I haven't yet figured out how to trigger the error myself, but it looks like the method is just an empty string (note the extra space after the IP address).

    Thanks in advance!

    bug 
    opened by ThisIsJustTemporary 0
  • Make use of ident while showing server error (generated by waitress)

    Make use of ident while showing server error (generated by waitress)

    this will help users to hide the server details from waitress generated error response with the help of ident value. Some organization don't want to expose there server details to user, since it will help the attackers perform attacks based on the known vulnerability of the server. So instead of showing generated by waitress, we can show a generic text.

    opened by AkhilmsAchu 1
  • RFE: Replace use of `pkg_resources` with `importlib.metadata`

    RFE: Replace use of `pkg_resources` with `importlib.metadata`

    See discussions: astropy/astropy#11091 pypa/pip#7413

    [tkloczko@devel-g2v waitress-2.1.2]$ grep -r pkg_resources
    docs/conf.py:import pkg_resources
    docs/conf.py:version = pkg_resources.get_distribution("waitress").version
    
    opened by kloczek 4
Releases(v2.1.2)
Owner
Pylons Project
The Pylons Project is composed of a disparate group of project leaders with experience going back to the very start of Python web frameworks.
Pylons Project
gunicorn 'Green Unicorn' is a WSGI HTTP Server for UNIX, fast clients and sleepy applications.

Gunicorn Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for UNIX. It's a pre-fork worker model ported from Ruby's Unicorn project. The Gunicorn

Benoit Chesneau 8.7k Jan 1, 2023
Meinheld is a high performance asynchronous WSGI Web Server (based on picoev)

What's this This is a high performance python wsgi web server. And Meinheld is a WSGI compliant web server. (PEP333 and PEP3333 supported) You can als

Yutaka Matsubara 1.4k Jan 1, 2023
livereload server in python (MAINTAINERS NEEDED)

LiveReload Reload webpages on changes, without hitting refresh in your browser. Installation python-livereload is for web developers who know Python,

Hsiaoming Yang 977 Dec 14, 2022
Python HTTP Server

Python HTTP Server Preview Languange and Code Editor: How to run? Download the zip first. Open the http.py and wait 1-2 seconds. You will see __pycach

SonLyte 16 Oct 21, 2021
Robyn is an async Python backend server with a runtime written in Rust, btw.

Robyn is an async Python backend server with a runtime written in Rust, btw. Python server running on top of of Rust Async RunTime. Installation

Sanskar Jethi 1.8k Dec 30, 2022
An HTTP server to easily download and upload files.

httpsweet An HTTP server to easily download and upload files. It was created with flexibility in mind, allowing be used in many different situations,

Eloy 17 Dec 23, 2022
The lightning-fast ASGI server. 🦄

The lightning-fast ASGI server. Documentation: https://www.uvicorn.org Community: https://discuss.encode.io/c/uvicorn Requirements: Python 3.6+ (For P

Encode 6k Jan 3, 2023
Mixer -- Is a fixtures replacement. Supported Django, Flask, SqlAlchemy and custom python objects.

The Mixer is a helper to generate instances of Django or SQLAlchemy models. It's useful for testing and fixture replacement. Fast and convenient test-

Kirill Klenov 871 Dec 25, 2022
Green is a clean, colorful, fast python test runner.

Green -- A clean, colorful, fast python test runner. Features Clean - Low redundancy in output. Result statistics for each test is vertically aligned.

Nathan Stocks 756 Dec 22, 2022
Scalable user load testing tool written in Python

Locust Locust is an easy to use, scriptable and scalable performance testing tool. You define the behaviour of your users in regular Python code, inst

Locust.io 20.4k Jan 8, 2023
A cross-platform GUI automation Python module for human beings. Used to programmatically control the mouse & keyboard.

PyAutoGUI PyAutoGUI is a cross-platform GUI automation Python module for human beings. Used to programmatically control the mouse & keyboard. pip inst

Al Sweigart 7.6k Jan 1, 2023
splinter - python test framework for web applications

splinter - python tool for testing web applications splinter is an open source tool for testing web applications using Python. It lets you automate br

Cobra Team 2.6k Dec 27, 2022
Let your Python tests travel through time

FreezeGun: Let your Python tests travel through time FreezeGun is a library that allows your Python tests to travel through time by mocking the dateti

Steve Pulec 3.5k Jan 9, 2023
HTTP client mocking tool for Python - inspired by Fakeweb for Ruby

HTTPretty 1.0.5 HTTP Client mocking tool for Python created by Gabriel Falcão . It provides a full fake TCP socket module. Inspired by FakeWeb Github

Gabriel Falcão 2k Jan 6, 2023
A utility for mocking out the Python Requests library.

Responses A utility library for mocking out the requests Python library. Note Responses requires Python 2.7 or newer, and requests >= 2.0 Installing p

Sentry 3.8k Jan 2, 2023
A test fixtures replacement for Python

factory_boy factory_boy is a fixtures replacement based on thoughtbot's factory_bot. As a fixtures replacement tool, it aims to replace static, hard t

FactoryBoy project 3k Jan 5, 2023
Faker is a Python package that generates fake data for you.

Faker is a Python package that generates fake data for you. Whether you need to bootstrap your database, create good-looking XML documents, fill-in yo

Daniele Faraglia 15.2k Jan 1, 2023
Mimesis is a high-performance fake data generator for Python, which provides data for a variety of purposes in a variety of languages.

Mimesis - Fake Data Generator Description Mimesis is a high-performance fake data generator for Python, which provides data for a variety of purposes

Isaak Uchakaev 3.8k Jan 1, 2023
Coroutine-based concurrency library for Python

gevent Read the documentation online at http://www.gevent.org. Post issues on the bug tracker, discuss and ask open ended questions on the mailing lis

gevent 5.9k Dec 28, 2022