Giter Site home page Giter Site logo

waitress's Introduction

Waitress

latest version of waitress on PyPI main Documentation Status

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.8+. It is also known to run on PyPy 3 (version 3.8 compatible python and above) 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/

waitress's People

Contributors

agroszer avatar akhilmsachu avatar alexanderlukanin13 avatar aodag avatar bwarren2 avatar davisagli avatar dbaty avatar dependabot[bot] avatar digitalresistor avatar domruf avatar estartu avatar flimm avatar frank-krick avatar gforcada avatar hathawsh avatar j4mie avatar jvanasco avatar kgaughan avatar madjar avatar marcinkuzminski avatar mcdonc avatar mmerickel avatar notbobthebuilder avatar stevepiercy avatar timgates42 avatar tseaver avatar tshepang avatar yourun-proger avatar yuzhougit avatar zanieb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

waitress's Issues

Transfer-Encoding : chunked

An application that runs in the server tries to use T-E : chunked. When I set the header to it I get a hop-by-hop error message. The documentation seems to indicate that I ought to be able to do it.

Is there something that needs to be done?

Chuck

comparison with uwsgi on heroku

there are some comments comparing waitress and gunicorn when deploying to heroku.
any comments on waitress vs. uwsgi for deployment on heroku?

Supporting generator responses

I'm trying to yield a textual log back to the client through app iter on a pyramid.Response object. This might advance as slowly as a few characters every minute. It is vital that the log goes back to the client as soon as yield is called.

As @cesarkawakami in this IRC log, I expected it to "just work". I was convinced that the problem must be downstream of waitress (with my nginx configuration or somewhere like that) until I finally found out that waitress does buffering and apparently there is no obvious way to turn it off on a response-by-response basis.

It also appears that this issue is poorly documented. I only found the IRC conversation after 30 minutes with duckduckgo searching for every combination of app_iter, waitress, nginx, pyramid, buffering, slow, buffered response, etc, I could think of.

IPv6?

IPv6 is listed as a TODO. What are some of the difficulties in enabling IPv6 support? I assume it's not as simple as setting the address_family to socket.AF_INET6 like you can do with wsgiref.simple_server.

failures in test from wsgiproxy2-0.4.2 under py3 sourced to waitress

In testsuite of wsgiproxy2-0.4.2 under py3. there are errorsX3;

test_quoted_utf8_url, test_quoted_utf8_url & test_quoted_utf8_url.

Firstly, I cannot find a source repo and issue tracker for wsgiproxy2 hence why I resort to reporting it here. Secondly, waitress is not even clearly listed as a dep for the tests by this package's source however it fails with missing module once uninstalled from the system.

Feel free to pass it onto their tracker which comes up as a dead link in their web page.

======================================================================
ERROR: test_quoted_utf8_url (wsgiproxy.tests.TestHttplib)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/mnt/gen2/TmpDir/portage/dev-python/wsgiproxy2-0.4.2/work/WSGIProxy2-0.4.2/wsgiproxy/tests.py", line 103, in test_quoted_utf8_url
    resp = self.app.get(path)
  File "/usr/lib64/python3.4/site-packages/webtest/app.py", line 286, in get
    expect_errors=expect_errors)
  File "/usr/lib64/python3.4/site-packages/webtest/app.py", line 595, in do_request
    self._check_status(status, res)
  File "/usr/lib64/python3.4/site-packages/webtest/app.py", line 624, in _check_status
    res)
webtest.app.AppError: Bad response: 500 Internal Server Error (not 200 OK or 3xx redirect for http://127.0.0.1:50200/targets/NR2F1%C3%82-human/)
b'Internal Server Error\r\n\r\nTraceback (most recent call last):\n  File "/usr/lib64/python3.4/site-packages/waitress/channel.py", line 337, in service\n    task.service()\n  File "/usr/lib64/python3.4/site-packages/waitress/task.py", line 173, in service\n    self.execute()\n  File "/usr/lib64/python3.4/site-packages/waitress/task.py", line 392, in execute\n    app_iter = self.channel.server.application(env, start_response)\n  File "/usr/lib64/python3.4/site-packages/webtest/http.py", line 83, in wrapper\n    return self.test_app(environ, start_response)\n  File "/usr/lib64/python3.4/site-packages/webtest/debugapp.py", line 49, in __call__\n    body = body.encode(\'ascii\')\nUnicodeEncodeError: \'ascii\' codec can\'t encode characters in position 151-152: ordinal not in range(128)\n\r\n\r\n(generated by waitress)'

======================================================================
ERROR: test_quoted_utf8_url (wsgiproxy.tests.TestRequests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/mnt/gen2/TmpDir/portage/dev-python/wsgiproxy2-0.4.2/work/WSGIProxy2-0.4.2/wsgiproxy/tests.py", line 103, in test_quoted_utf8_url
    resp = self.app.get(path)
  File "/usr/lib64/python3.4/site-packages/webtest/app.py", line 286, in get
    expect_errors=expect_errors)
  File "/usr/lib64/python3.4/site-packages/webtest/app.py", line 595, in do_request
    self._check_status(status, res)
  File "/usr/lib64/python3.4/site-packages/webtest/app.py", line 624, in _check_status
    res)
nose.proxy.AppError: Bad response: 500 Internal Server Error (not 200 OK or 3xx redirect for http://127.0.0.1:54658/targets/NR2F1%C3%82-human/)
b'Internal Server Error\r\n\r\nTraceback (most recent call last):\n  File "/usr/lib64/python3.4/site-packages/waitress/channel.py", line 337, in service\n    task.service()\n  File "/usr/lib64/python3.4/site-packages/waitress/task.py", line 173, in service\n    self.execute()\n  File "/usr/lib64/python3.4/site-packages/waitress/task.py", line 392, in execute\n    app_iter = self.channel.server.application(env, start_response)\n  File "/usr/lib64/python3.4/site-packages/webtest/http.py", line 83, in wrapper\n    return self.test_app(environ, start_response)\n  File "/usr/lib64/python3.4/site-packages/webtest/debugapp.py", line 49, in __call__\n    body = body.encode(\'ascii\')\nUnicodeEncodeError: \'ascii\' codec can\'t encode characters in position 276-277: ordinal not in range(128)\n\r\n\r\n(generated by waitress)'
-------------------- >> begin captured logging << --------------------
requests.packages.urllib3.connectionpool: INFO: Starting new HTTP connection (1): 127.0.0.1
requests.packages.urllib3.connectionpool: DEBUG: "GET /targets/NR2F1%C3%82-human/ HTTP/1.1" 500 799
--------------------- >> end captured logging << ---------------------

======================================================================
ERROR: test_quoted_utf8_url (wsgiproxy.tests.TestUrllib3)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/mnt/gen2/TmpDir/portage/dev-python/wsgiproxy2-0.4.2/work/WSGIProxy2-0.4.2/wsgiproxy/tests.py", line 103, in test_quoted_utf8_url
    resp = self.app.get(path)
  File "/usr/lib64/python3.4/site-packages/webtest/app.py", line 286, in get
    expect_errors=expect_errors)
  File "/usr/lib64/python3.4/site-packages/webtest/app.py", line 595, in do_request
    self._check_status(status, res)
  File "/usr/lib64/python3.4/site-packages/webtest/app.py", line 624, in _check_status
    res)
nose.proxy.AppError: Bad response: 500 Internal Server Error (not 200 OK or 3xx redirect for http://127.0.0.1:50848/targets/NR2F1%C3%82-human/)
b'Internal Server Error\r\n\r\nTraceback (most recent call last):\n  File "/usr/lib64/python3.4/site-packages/waitress/channel.py", line 337, in service\n    task.service()\n  File "/usr/lib64/python3.4/site-packages/waitress/task.py", line 173, in service\n    self.execute()\n  File "/usr/lib64/python3.4/site-packages/waitress/task.py", line 392, in execute\n    app_iter = self.channel.server.application(env, start_response)\n  File "/usr/lib64/python3.4/site-packages/webtest/http.py", line 83, in wrapper\n    return self.test_app(environ, start_response)\n  File "/usr/lib64/python3.4/site-packages/webtest/debugapp.py", line 49, in __call__\n    body = body.encode(\'ascii\')\nUnicodeEncodeError: \'ascii\' codec can\'t encode characters in position 169-170: ordinal not in range(128)\n\r\n\r\n(generated by waitress)'
-------------------- >> begin captured logging << --------------------
urllib3.connectionpool: INFO: Starting new HTTP connection (1): 127.0.0.1
urllib3.connectionpool: DEBUG: "GET /targets/NR2F1%C3%82-human/ HTTP/1.1" 500 799
--------------------- >> end captured logging << ---------------------

Name                        Stmts   Miss  Cover   Missing
---------------------------------------------------------
wsgiproxy                       3      0   100%   
wsgiproxy.proxies             161      0   100%   
wsgiproxy.requests_client      28      2    93%   26, 32
wsgiproxy.urllib3_client       21      0   100%   
---------------------------------------------------------
TOTAL                         213      2    99%   
----------------------------------------------------------------------
Ran 31 tests in 3.388s

FAILED (errors=3)

They are all UnicodeEncode type Errors re utf under py3. They all source immediately to
the system installed /waitress/channel.py", line 337. It's looking like code inadequately converted ot ported to python3.

Apologies for any inconvenience if this has no place here.

unix socket support

I tried to use waitress in my Chaussette project with unix sockets, but I started to do a lot of hacks to make it work.

What about adding unix socket support directly in Waitress ?

That would allow it to be used behind Nginx or Circus etc.

Ensure sys.path is set correctly in runner

Hi,

I am experimenting with Waitress on a production system based on a bare Ubuntu install. The PYTHONPATH environment appears not to be set. waitress-serve my.wsgi.app fails with

Error: Bad module 'my.wsgi'

If I run PYTHONPATH='' waitress-serve path.to.wsgi.app, then Waitress starts correctly.

Gunicorn gets around this problem by forcing the current working directory onto the path, see: https://github.com/benoitc/gunicorn/blob/master/gunicorn/app/wsgiapp.py#L24

This can be solved by adding sys.path.insert(0, os.getcwd()) to the top of runner.py

I'm happy to provide a pull request for this, but I'm not sure whether (a) you agree this is a sensible thing to do, or (b) how to test it.

Many thanks

Request to url_prefix yields wrong PATH_INFO

If the origin request path is exactly the same as the url_prefix the
resulting PATH_INFO equals the SCRIPT_NAME whereas it should be the empty string.

Example:

$ URL_PREFIX=/foo # imagine, waitress using this
$ curl localhost/foo
SCRIPT_NAME=/foo
PATH_INFO=/foo

PEP-333, the WSGI-specification says this:

PATH_INFO
    The remainder of the request URL's "path", designating the virtual "location" of the request's target within the application. This may be an empty string, if the request URL targets the application root and does not have a trailing slash.

Testcase:

def test_get_environ_with_url_prefix_empty_path(self):
    inst = self._makeOne()
    inst.channel.server.adj.url_prefix = '/foo'
    request = DummyParser()
    request.path = '/foo'
    inst.request = request
    environ = inst.get_environment()
    self.assertEqual(environ['PATH_INFO'], '')
    self.assertEqual(environ['SCRIPT_NAME'], '/foo')

I think the testcase collides with test_get_environment_path_empty.
But I think this test case is invalid, as a request with an empty path would
not be valid HTTP.

Streaming responses buffer to harddisk until generator is exhausted or hard-disk is full

It seems that due to Waitress' architecture, using streaming responses for a larger amount of data will always buffer to a temporary file until the generator underlying the streaming response is exhausted or the partition/disk with the temporary directory runs out of physical space.

This makes Waitress unsuitable for cases where streaming responses are used with the intent of avoiding hitting the disk or filling the RAM every time large amounts of data are served. In my case I want to stream large amounts of data from a Raspberry Pi that is severely limited space-wise and is using SD-Flash storage that is rather sensitive to wear.

Here is a minimal example that illustrates the issue. It's a small WSGI application that will continuously stream 64KiB chunks of zeroes to the client.

def fill_harddisk(environ, start_response):
    start_response('200 OK', [('Content-Type', 'application/octet-stream')])
    with open('/dev/zero', 'r') as devzero:
        while True:
            # Read 64K of zeroes, yield
            yield devzero.read(2**16)

if __name__ == '__main__':
    import waitress
    waitress.serve(fill_harddisk)

Here is the behaviour when running under Waitress:

$ python fill_harddisk.py
serving on http://0.0.0.0:8080

-------- *snip* --------------
Now we open a client connection on another TTY:

$ curl localhost:8080 > /dev/null

And wait a while (depending on the size of your /tmp mount)
-------- *snap* --------------

ERROR:waitress:Exception when serving /
Traceback (most recent call last):
....
File "/home/jojo/.envs/spreads/local/lib/python2.7/site-packages/waitress/channel.py", line 319, in write_soon
    self.outbufs[-1].append(data)
File "/home/jojo/.envs/spreads/local/lib/python2.7/site-packages/waitress/buffers.py", line 247, in append
    buf.append(s)
File "/home/jojo/.envs/spreads/local/lib/python2.7/site-packages/waitress/buffers.py", line 55, in append
    file.write(s)
IOError: [Errno 28] No space left on device

Running the same application with the wsgiref implementation will chug along without any problems until you either Ctrl-C the server or the client, never using more than a few MiB of RAM and never writing to disk.

AssertionError: Can only use Waiter.switch method from the Hub greenlet

When I use the http://sdiehl.github.io/gevent-tutorial/#chat-server to test waitress, I get an exception:

AssertionError: Can only use Waiter.switch method from the Hub greenlet
File "C:\Users\honglei\AppData\Local\Enthought\Canopy\User\Lib\site-packages\gevent\hub.py", line 364, in run
loop.run()
File "C:\Users\honglei\AppData\Local\Enthought\Canopy\User\Lib\site-packages\gevent\queue.py", line 271, in _unlock
getter.switch(getter)
File "C:\Users\honglei\AppData\Local\Enthought\Canopy\User\Lib\site-packages\gevent\hub.py", line 534, in switch
assert getcurrent() is self.hub, "Can only use Waiter.switch method from the Hub greenlet"

# Micro gevent chatroom.
# ----------------------
# Make things as simple as possible, but not simpler.



from flask import Flask, render_template, request, json

from gevent import queue


app = Flask(__name__)
app.debug = True

class Room(object):

    def __init__(self):
        self.users = set()
        self.messages = []

    def backlog(self, size=25):
        return self.messages[-size:]

    def subscribe(self, user):
        self.users.add(user)

    def add(self, message):
        for user in self.users:
            print user
            user.queue.put_nowait(message)
        self.messages.append(message)

class User(object):

    def __init__(self):
        self.queue = queue.Queue()

rooms = {
    'python': Room(),
    'django': Room(),
}

users = {}

@app.route('/')
def choose_name():
    return render_template('choose.html')

@app.route('/<uid>')
def main(uid):
    return render_template('main.html',
        uid=uid,
        rooms=rooms.keys()
    )

@app.route('/<room>/<uid>')
def join(room, uid):
    user = users.get(uid, None)

    if not user:
        users[uid] = user = User()

    active_room = rooms[room]
    active_room.subscribe(user)
    print 'subscribe', active_room, user

    messages = active_room.backlog()

    return render_template('room.html',
        room=room, uid=uid, messages=messages)

@app.route("/put/<room>/<uid>", methods=["POST"])
def put(room, uid):
    user = users[uid]
    room = rooms[room]

    message = request.form['message']
    room.add(':'.join([uid, message]))

    return ''

@app.route("/poll/<uid>", methods=["POST"])
def poll(uid):
    try:
        msg = users[uid].queue.get(timeout=10)
    except queue.Empty:
        msg = []
    return json.dumps(msg)

#import wsgi_server
if __name__ == "__main__":
    #from gevent import monkey; monkey.patch_all()
    #from gevent.pywsgi import WSGIServer
    #http = WSGIServer(('', 5000), app)
    #http.serve_forever()

    #pulsar_version(app)
    #twisted_version(app)
    #wsgi_server.waitress_version(app)    
    from waitress import serve
    serve(app, port=5000)    

Console output:

serving on http://0.0.0.0:5000
subscribe <main.Room object at 0x0000000002DA2A90> <main.User object at 0x0000000002ED71D0>
subscribe <main.Room object at 0x0000000002DA2A90> <main.User object at 0x0000000002ED1C18>
subscribe <main.Room object at 0x0000000002DA2A90> <main.User object at 0x0000000002D577B8>
subscribe <main.Room object at 0x0000000002DA2A90> <main.User object at 0x0000000002CE8B38>
<main.User object at 0x0000000002ED1C18>
<main.User object at 0x0000000002D577B8>
<main.User object at 0x0000000002CE8B38>
<main.User object at 0x0000000002ED71D0>

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.

int overflow errors on large buffers

Org traceback can be found here:
https://bitbucket.org/marcinkuzminski/rhodecode/issue/838

2013-05-13 14:57:05.390 ERROR [waitress] Exception when serving /rhodecode/Machinima-Project
Traceback (most recent call last):
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/waitress/channel.py", line 329, in service
    task.service()
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/waitress/task.py", line 173, in service
    self.execute()
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/waitress/task.py", line 412, in execute
    self.write(chunk)
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/waitress/task.py", line 303, in write
    channel.write_soon(towrite)
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/waitress/channel.py", line 311, in write_soon
    self.outbufs[-1].append(data)
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/waitress/buffers.py", line 247, in append
    sz = len(buf)
OverflowError: long int too large to convert to int
Traceback (most recent call last):
  File "/usr/share/rhodecode/rhodecode-venv/bin/paster", line 8, in <module>
    load_entry_point('PasteScript==1.7.5', 'console_scripts', 'paster')()
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/paste/script/command.py", line 104, in run
    invoke(command, command_name, options, args[1:])
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/paste/script/command.py", line 143, in invoke
    exit_code = runner.run(args)
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/paste/script/command.py", line 238, in run
    result = self.command()
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/paste/script/serve.py", line 311, in command
    serve()
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/paste/script/serve.py", line 295, in serve
    server(app)
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/paste/deploy/loadwsgi.py", line 189, in server_wrapper
    **context.local_conf)
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/paste/deploy/util.py", line 56, in fix_call
    val = callable(*args, **kw)
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/waitress/__init__.py", line 21, in serve_paste
    serve(app, **kw)
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/waitress/__init__.py", line 18, in serve
    server.run()
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/waitress/server.py", line 129, in run
    self.asyncore.loop(map=self._map)
  File "/usr/lib/python2.6/asyncore.py", line 210, in loop
    poll_fun(timeout, map)
  File "/usr/lib/python2.6/asyncore.py", line 127, in poll
    is_r = obj.readable()
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/waitress/channel.py", line 157, in readable
    self.any_outbuf_has_data())
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/waitress/channel.py", line 84, in any_outbuf_has_data
    if bool(outbuf):
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/waitress/buffers.py", line 214, in __nonzero__
    return bool(len(self))
  File "/usr/share/rhodecode/rhodecode-venv/lib/python2.6/site-packages/waitress/buffers.py", line 209, in __len__
    return len(buf)
OverflowError: long int too large to convert to int
Removing PID file /usr/share/rhodecode/rhodecode.pid

So basically python expects an int when it calls len(), it seems that buffer length can exceed that , and len functions on buffers can return more than that.

Seems to be hard to fix issue, not sure if that should be fixed even ?

KeyboardInterrupt on Windows needs 30 seconds

If you press Ctrl-C under Windows to shut down a running waitress server, it will be only shut down after 30 seconds. This can be somewhat irritating and annoying. The problem can be solved by passing timeout=1 to the asyncore() call in the waitress.WSGIServer.run() method. The default timeout is 30 seconds and it seems a KeyboardInterrupt is only thrown on Windows after that timeout. Setting it to a lower value of 1s should not have any negative implications. The timeout could at least be made a tunable parameter.

Mimetype for svg font

I am trying to use waitress with Bootstrap.

The bootstrap glyphicons do not show up correctly on Mobile Safari (iPad and iPhone).
Bootstrap glyphicons are implemented as a special font, not an image.
Glyphicons are rendered correctly on browsers on other platforms.

Here is what I think is happening:

  • Mobile Safari uses svg font faces (not tiff or woff like other browers).
  • Mobile Safari also requires svg font faces to be marked with a mimetype of "image/svg+xml".
  • Incorrectly marked .svg files are ignored.
  • When it ignores the font, it uses an internal default which looks like musical instruments and sports equipment.

Is there a way to configure waitress to add the "image/svg+xml" mimetype to .svg files?

How to increase upload limit?

It looks like Waitress is limiting the size of file uploads allowed on the site. Any file upload bigger than the limit (which seems to be around a few kilobytes) fails with an HTTP 504 error.

I looked for the setting for changing this but couldn't find it. Could someone help? Also this should probably be in the docs.

default asyncore.loop uses select() that causes fd limit errors

Having a setup of 5 servers running in a loadbalanced ring we're getting such errors:

Starting server in PID 18618.
serving on http://127.0.0.1:5001
Traceback (most recent call last):
  File "/opt/rhodecode-env/bin/paster", line 10, in <module>
    load_entry_point('PasteScript==1.7.5', 'console_scripts', 'paster')()
  File "/opt/rhodecode-env/lib/python2.7/site-packages/PasteScript-1.7.5-py2.7.egg/paste/script/command.py", line 104, in run
    invoke(command, command_name, options, args[1:])
  File "/opt/rhodecode-env/lib/python2.7/site-packages/PasteScript-1.7.5-py2.7.egg/paste/script/command.py", line 143, in invoke
    exit_code = runner.run(args)
  File "/opt/rhodecode-env/lib/python2.7/site-packages/PasteScript-1.7.5-py2.7.egg/paste/script/command.py", line 238, in run
    result = self.command()
  File "/opt/rhodecode-env/lib/python2.7/site-packages/PasteScript-1.7.5-py2.7.egg/paste/script/serve.py", line 311, in command
    serve()
  File "/opt/rhodecode-env/lib/python2.7/site-packages/PasteScript-1.7.5-py2.7.egg/paste/script/serve.py", line 295, in serve
    server(app)
  File "/opt/rhodecode-env/lib/python2.7/site-packages/PasteDeploy-1.5.0-py2.7.egg/paste/deploy/loadwsgi.py", line 189, in server_wrapper
    **context.local_conf)
  File "/opt/rhodecode-env/lib/python2.7/site-packages/PasteDeploy-1.5.0-py2.7.egg/paste/deploy/util.py", line 56, in fix_call
    val = callable(*args, **kw)
  File "/opt/rhodecode-env/lib/python2.7/site-packages/waitress-0.8.1-py2.7.egg/waitress/__init__.py", line 21, in serve_paste
    serve(app, **kw)
  File "/opt/rhodecode-env/lib/python2.7/site-packages/waitress-0.8.1-py2.7.egg/waitress/__init__.py", line 18, in serve
    server.run()
  File "/opt/rhodecode-env/lib/python2.7/site-packages/waitress-0.8.1-py2.7.egg/waitress/server.py", line 129, in run
    self.asyncore.loop(map=self._map)
  File "/usr/local/lib/python2.7/asyncore.py", line 216, in loop
    poll_fun(timeout, map)
  File "/usr/local/lib/python2.7/asyncore.py", line 145, in poll
    r, w, e = select.select(r, w, e, timeout)
ValueError: filedescriptor out of range in select()

Error with cassandra

I get in error when use waitress with cassandra (https://github.com/datastax/python-driver), it is something about asyncore.

I do not know it's problem of cassandra-driver or waitress, please help me to detect it.

I posted my python script and the log to gist, here it is:

To reproduce errors, access to http://localhost:8080 after run script, the error will then randomly occur.

Thanks a lot

Nested Bottle app with Waitress

I am building a web application using nested Bottle apps and I'm having problems returning a static file from the nested app when running the site through the Waitress web server. It works fine when run with WSGIRefServer, which suggests a problem with Waitress.

Sample app that replicates the issue below (browse to /test/). If I run the app using WSGIRefServer (commented run command) then the javascript file downloads fine. If i use server="waitress" then /test/js returns a blank response (no errors).

from bottle import Bottle, run, static_file

baseapp = Bottle()
app = Bottle()
baseapp.mount("/test/", app)

@app.get("/")
def index():
    return """<!DOCTYPE html>
<html><body>
<p>Result: <span id="asdf">Failed :(</span></p>
<script src="js"></script>
</body></html>
"""

@app.get("/js")
def js():
    return static_file("test.js", "./")

run(app = baseapp, server="waitress", url="0.0.0.0", port=8080)
#run(app = baseapp, url="0.0.0.0", port=8080)

Contents of test.js:

document.getElementById('asdf').innerHTML = 'Worked! :)';

I'm running Python 3.4.2 with Bottle 0.12.7 and Waitress 0.8.9. (downloaded via pip).

unicode content_type causes "internal server error"

in pyramid:
Response(content_type=u'image/jpg')

leads to

Internal Server Error
The server encountered an unexpected internal server error
(generated by waitress)

with no traceback or debug-output whatsoever. Im didnt go into how the handoff to waitress is actually made, but im quite certain it shouldnt choke like that on the unicode-value.

waitress-server version in use: 0.8.2
pyramid-version: 1.4

if i can assist in any further way, let me know.

make: ./convert_images.sh: Command not found

$ make latex
mkdir -p _build/latex _build/doctrees
sphinx-build -b latex -d _build/doctrees . _build/latex
Running Sphinx v1.3.1
Already on 'master'
Already up-to-date.
loading pickled environment... not yet created
building [mo]: targets for 0 po files that are out of date
building [latex]: all documents
updating environment: 8 added, 0 changed, 0 removed
reading sources... [100%] runner
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
processing waitress.tex... index design differences api arguments filewrapper runner glossary
resolving references...
writing... /home/asarch/waitress/waitress/docs/index.rst:: WARNING: unusable reference target found: irc://irc.freenode.net/#p
yramid
done
copying TeX support files...
done
build succeeded, 1 warning.
cp static/.png build/latex
./convert_images.sh
make: ./convert_images.sh: Command not found
make: *
* [latex] Error 127

multi-line (folded) HTTP header wrongly parsed

According to RFC2616 2.2., the parsed value of a folded header is supposed to have continuations intact or replaced with a single SP though waitress strips them all (see this).

This behaviour keep developers from dealing with folded headers that are rendered with meaningful occurrences of continuations.

HTTP/1.1 header field values can be folded onto multiple lines if the
continuation line begins with a space or horizontal tab. All linear
white space, including folding, has the same semantics as SP. A
recipient MAY replace any linear white space with a single SP before
interpreting the field value or forwarding the message downstream.

  LWS            = [CRLF] 1*( SP | HT )

Graceful shutdown

Chris,

I'm trying to gracefully shutdown the server and it appears there is no way to do it. In server.py it looks like handle_accept() is so close but I hesitate to change it in my copy of the code. Any chance it could be supported in the formal code?

Thanks,
Chuck Wegrzyn

keep-alive option

Hey guys, is there any option to configure this HTTP feature directly?

Another int overflow on waitress Buffers

So it's another case of #22, now on waitress 0.8.7

Org exception was:

Traceback (most recent call last): 
  File "/data/rhodecodeProduktion/rhodecode-venv/lib/python2.6/site-packages/waitress/channel.py", line 332, in service 
    task.service() 
  File "/data/rhodecodeProduktion/rhodecode-venv/lib/python2.6/site-packages/waitress/task.py", line 173, in service 
    self.execute() 
  File "/data/rhodecodeProduktion/rhodecode-venv/lib/python2.6/site-packages/waitress/task.py", line 420, in execute 
    self.write(chunk) 
  File "/data/rhodecodeProduktion/rhodecode-venv/lib/python2.6/site-packages/waitress/task.py", line 303, in write 
    channel.write_soon(towrite) 
  File "/data/rhodecodeProduktion/rhodecode-venv/lib/python2.6/site-packages/waitress/channel.py", line 314, in write_soon 
    self.outbufs[-1].append(data) 
  File "/data/rhodecodeProduktion/rhodecode-venv/lib/python2.6/site-packages/waitress/buffers.py", line 244, in append 
    sz = len(buf) 
OverflowError: long int too large to convert to int 
2013-11-14 17:24:28.508 ERROR [waitress] Unexpected exception when flushing 
Traceback (most recent call last): 
  File "/data/rhodecodeProduktion/rhodecode-venv/lib/python2.6/site-packages/waitress/channel.py", line 137, in handle_write 
    flush() 
  File "/data/rhodecodeProduktion/rhodecode-venv/lib/python2.6/site-packages/waitress/channel.py", line 236, in _flush_some 
    outbuflen = len(outbuf) 
OverflowError: long int too large to convert to int

I did two changes just to test out:

-    outbuflen = len(outbuf)
+   outbuflen = outbuf.__len__()

and

- sz = len(buf)
+ sz = buf.__len__()

Then we end up with:

2013-11-15 15:05:47.369 ERROR [waitress] uncaptured python exception, 
closing channel <waitress.channel.HTTPChannel connected 127.0.0.1:33700 at 
0xc1a9a0c> (<type 'exceptions.OverflowError'>:long int too large to convert 
to int [/usr/lib/python2.6/asyncore.py|write|86] 
[/usr/lib/python2.6/asyncore.py|handle_write_event|450] 
[/data/rhodecodeProduktion/rhodecode-venv/lib/python2.6/site-packages/waitress/channel.py| 
handle_write|124] 
[/data/rhodecodeProduktion/rhodecode-venv/lib/python2.6/site-packages/waitress/channel.py| 
total_outbufs_len|92]) 
2013-11-15 15:05:47.369 ERROR [waitress] Unknown exception while trying to 
close outbuf 
Traceback (most recent call last): 
  File 
"/data/rhodecodeProduktion/rhodecode-venv/lib/python2.6/site-packages/waitress/channel.py", 
 line 273, in handle_close 
    outbuf._close() 
  File 
"/data/rhodecodeProduktion/rhodecode-venv/lib/python2.6/site-packages/waitress/buffers.py", 
 line 295, in _close 
    buf._close() 
  File 
"/data/rhodecodeProduktion/rhodecode-venv/lib/python2.6/site-packages/waitress/buffers.py", 
 line 110, in _close 
    self.file.close() 
IOError: close() called during concurrent operation on the same file 
object.

ReadOnlyFileBasedBuffer does not work with io.IOBase subclasses

ReadOnlyFileBasedBuffer checks if it can detect the file length by using seek and tell methods.

While it checks for the file to be able to provide them at https://github.com/Pylons/waitress/blob/master/waitress/buffers.py#L140 it doesn't actually check if those can be used.

In io.IOBase subclasses that are not seekable, those two methods exist but raise an UnsupportedOperation, in case of io.IOBase instance .seekable should probably be checked for True or the UnsupportedOperation should be trapped.

Currently waitress is just crashing if it receives an io.IOBase subclasses which is not seekable as the file to serve.

cp: cannot stat ‘_static/*.png’: No such file or directory

$ make latex
mkdir -p _build/latex _build/doctrees
sphinx-build -b latex -d _build/doctrees . _build/latex
Running Sphinx v1.3.1
Cloning into '_themes'...
remote: Counting objects: 447, done.
remote: Total 447 (delta 0), reused 0 (delta 0), pack-reused 447
Receiving objects: 100% (447/447), 435.11 KiB | 357.00 KiB/s, done.
Resolving deltas: 100% (202/202), done.
Checking connectivity... done
loading pickled environment... not yet created
building [mo]: targets for 0 po files that are out of date
building [latex]: all documents
updating environment: 8 added, 0 changed, 0 removed
reading sources... [100%] runner
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
processing waitress.tex... index design differences api arguments filewrapper runner glossary
resolving references...
writing... /home/asarch/waitress/waitress/docs/index.rst:: WARNING: unusable reference target found: irc://irc.freenode.net/#pyramid
done
copying TeX support files...
done
build succeeded, 1 warning.
cp static/.png _build/latex
cp: cannot stat ‘static/.png’: No such file or directory
make: *** [latex] Error 1

Header for Waitress

While the documents say Waitiress supports HTTP/1.0 and HTTP/1.1 I noticed the returned header always says HTTP/1.0. Is this an oversight?

docs/ and docstring license is non-commercial

According to https://github.com/Pylons/waitress/blob/master/CONTRIBUTORS.txt#L91 the license for the docs/ directory and the docstrings is Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License. This is a problem for distributions like openSUSE or Debian.
The problem was already discussed (see https://groups.google.com/forum/#!searchin/pylons-devel/commercial/pylons-devel/M__sXP0W-Ws/Yee63QK0aGcJ ) but without any conclusion.
So what do people think about changing the license for docs/ and docstrings so the distributions can ship it?

Automatic Reloader

I'd like to use Waitress both during development and in production (for simplicity, easier bugfixing, etc.). One little problem I have is that it does not support automatic module reloading when the code changes (like for example Werkzeug Reloader: http://werkzeug.pocoo.org/docs/0.10/serving/#reloader).

  1. Did I miss anything, is this feature supported? Is there already some discussion on this subject?
  2. If not then would it be a good idea to add such functionality to Waitress? Is providing development server in addition to production server within the scope of the project?
  3. If yes then would it be difficult / complex to add such functionality (if not then perhaps I could prepare a pull request)?

TypeError occured when using "waitress-serve" command and "--unix-socket-perms" option.

I want to change the permissions on the socket file using the waitress-serve command but an error occurred.

$ waitress-serve --unix-socket=app.sock --unix-socket-perms=660 hello:app
Traceback (most recent call last):
  File "/home/tokibito/.virtualenvs/waitress-test/bin/waitress-serve", line 9, in <module>
    load_entry_point('waitress==0.8.7', 'console_scripts', 'waitress-serve')()
  File "/home/tokibito/.virtualenvs/waitress-test/local/lib/python2.7/site-packages/waitress/runner.py", line 216, in run
    _serve(app, **kw)
  File "/home/tokibito/.virtualenvs/waitress-test/local/lib/python2.7/site-packages/waitress/__init__.py", line 11, in serve
    server = _server(app, **kw)
  File "/home/tokibito/.virtualenvs/waitress-test/local/lib/python2.7/site-packages/waitress/server.py", line 39, in create_server
    adj = Adjustments(**kw)
  File "/home/tokibito/.virtualenvs/waitress-test/local/lib/python2.7/site-packages/waitress/adjustments.py", line 177, in __init__
    setattr(self, k, self._param_map[k](v))
  File "/home/tokibito/.virtualenvs/waitress-test/local/lib/python2.7/site-packages/waitress/adjustments.py", line 37, in asoctal
    return int(s, 8)
TypeError: int() can't convert non-string with explicit base

Bad variable name

I think:
In channel.py file, line 194, must be:
self.sent_continue = True
instead of:
self.sent_expect_continue = True

Attr sent_expect_continue does not exist. It's sent_continue.
Regards.

Terminating waitress

Say that I have started waitress.serve on a separate thread. I now want to terminate Waitress. Any way to do it without killing all the threads?

Segmentation fault (sqlite, ctypes)

Hi i get a reproducible segmentation fault when i run my sqlite backup ctypes script with waitress, when i run it with werkzeug it works. Sadly my c knowledge is a bit too rusty to figure it out by my self.

I've added a simple flask app to demonstrate that error. http://pastebin.com/VuUgcr6z

Howto:

$ virtualenv env
$ env/bin/pip install flask-sqlalchemy
$ env/bin/pip install waitress
$ env/bin/python app.py

I get this error in python2 and python3.

Need a way to limit threads per remote

We have an OLAP application on Pyramid + Waitress; and we are using AJAX to fetch the results. Sometimes the computations are not that swift (especially if PostgreSQL makes a bad query plan); the problem is that 1 client doing the lengthy ops, or reloading the page could easily exhaust all the worker threads. There ought to be way to configure a policy whether a request is dispatched on yet another thread, or queued until the previous requests from that remote address are fulfilled.

Internal Server Error hides asserts

I use asserts within my code for debugging purposes. When an assert fails, Waitress just reports with Internal Server Error and gives no hint for where to look. Can that be implemented?

SyntaxError under python 3.5.0b2 in __init__.py line 36

after running pcreate to setup a template project, python setup.py develop downloads but reports a SyntaxError during waitress install (also when trying to run with pserve, commenting out line 36 allows it to run)

This is Python 3.5.0b2

Searching for waitress
Reading https://pypi.python.org/simple/waitress/
Best match: waitress 0.8.9
Downloading https://pypi.python.org/packages/source/w/waitress/waitress-0.8.9.tar.gz#md5=da3f2e62b3676be5dd630703a68e2a04
Processing waitress-0.8.9.tar.gz
Writing /tmp/easy_install-nufpse11/waitress-0.8.9/setup.cfg
Running waitress-0.8.9/setup.py -q bdist_egg --dist-dir /tmp/easy_install-nufpse11/waitress-0.8.9/egg-dist-tmp-_zpid2hv
File "build/bdist.linux-x86_64/egg/waitress/init.py", line 36
stats.sort_stats(*sort_order or ('cumulative', 'calls', 'time'))
^
SyntaxError: invalid syntax

creating /home/bkc/Python_Environments/D2DAdmin-py3.5/lib/python3.5/site-packages/waitress-0.8.9-py3.5.egg
Extracting waitress-0.8.9-py3.5.egg to /home/bkc/Python_Environments/D2DAdmin-py3.5/lib/python3.5/site-packages
File "/home/bkc/Python_Environments/D2DAdmin-py3.5/lib/python3.5/site-packages/waitress-0.8.9-py3.5.egg/waitress/init.py", line 36
stats.sort_stats(*sort_order or ('cumulative', 'calls', 'time'))
^
SyntaxError: invalid syntax

Adding waitress 0.8.9 to easy-install.pth file
Installing waitress-serve script to /home/bkc/Python_Environments/D2DAdmin-py3.5/bin

Installed /home/bkc/Python_Environments/D2DAdmin-py3.5/lib/python3.5/site-packages/waitress-0.8.9-py3.5.egg

HTTP/2 support

Just pulled from the spec readme:

At a high level, HTTP/2:

is binary, instead of textual
is fully multiplexed, instead of ordered and blocking
can therefore use one connection for parallelism
uses header compression to reduce overhead
allows servers to "push" responses proactively into client caches

Sounds awesome. Is it doable for waitress?

Waitress SocketError on Redirects

[ originally posted in https://github.com/Pylons/pyramid/issues/909 ]

I've been noticing this in my dev logs for a while, and decided to look into it...

Whenever I do:

raise HTTPFound('/new/path')

or

return HTTPFound('/new/path')

I get a Broken Pipe / Socket error

Sample error below. I think this could just have an exception caught or something ?

2013-03-12 18:06:52,518 ERROR [waitress][MainThread] Socket error
Traceback (most recent call last):
File "/Users/jvanasco/webserver/environments/myapp-2.7/lib/python2.7/site-packages/waitress-0.8.2-py2.7.egg/waitress/channel.py", line 134, in handle_write
flush()
File "/Users/jvanasco/webserver/environments/myapp-2.7/lib/python2.7/site-packages/waitress-0.8.2-py2.7.egg/waitress/channel.py", line 249, in _flush_some
num_sent = self.send(chunk)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/asyncore.py", line 362, in send
result = self.socket.send(data)
error: [Errno 32] Broken pipe

start_response() reraises exc_info even if headers have not been sent

While working on a wsgi error handler, I think I ran across a (small) bug in waitress' start_response function...

PEP3333 says start_response(status, headers, exc_info) should only re-raise the exception if the headers haven't been sent to the client. Whereas WSGITask.execute() re-raises the error if start_response() has been called at all, even if the headers haven't been sent.

The following quick patch seems to fix things... (my apologies, I'm new to github, and can't for the life of me figure out how to make an attachment).

diff --git a/waitress/task.py b/waitress/task.py
index a4c8f2e..ab3282f 100644
--- a/waitress/task.py
+++ b/waitress/task.py
@@ -346,7 +346,7 @@ class WSGITask(Task):
                                      "without providing exc_info.")
             if exc_info:
                 try:
-                    if self.complete:
+                    if self.wrote_header:
                         # higher levels will catch and handle raised exception:
                         #1. "service" method in task.py
                         #2. "service" method in channel.py

Best way to shutdown a server started within a thread?

Hi,

It seems that the way to shutdown waitress servers is by sending a SIGINT (KeyboardInterrupt) to the process. This works well if the waitress server is running in the main thread. I am starting my waitress server within a separate thread. Since Python does not pass down signals to other threads, i am not sure what is the best way to do that.

Any ideas?

Thanks!

No such file or directory: u'/home/asarch/waitress/waitress/docs/.static/logo_hi.gif'

Sphinx version: 1.3.1

Python version: 2.7.5 (CPython)

Docutils version: 0.12 release

Jinja2 version: 2.7.3

Last messages:

arguments

filewrapper

runner

glossary

resolving references...

writing...

/home/asarch/waitress/waitress/docs/index.rst:: WARNING: unusable reference target found: irc://irc.freenode.net/#pyramid

done

copying TeX support files...

Loaded extensions:

alabaster (0.7.3) from /usr/lib/python2.7/site-packages/alabaster/init.pyc

sphinx.ext.autodoc (1.3.1) from /usr/lib/python2.7/site-packages/sphinx/ext/autodoc.pyc

Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/sphinx/cmdline.py", line 245, in main
app.build(opts.force_all, filenames)
File "/usr/lib/python2.7/site-packages/sphinx/application.py", line 264, in build
self.builder.build_update()
File "/usr/lib/python2.7/site-packages/sphinx/builders/init.py", line 240, in build_update
self.build(['all'], to_build)
File "/usr/lib/python2.7/site-packages/sphinx/builders/init.py", line 319, in build
self.finish()
File "/usr/lib/python2.7/site-packages/sphinx/builders/latex.py", line 184, in finish
path.join(self.outdir, logobase))
File "/usr/lib/python2.7/site-packages/sphinx/util/osutil.py", line 140, in copyfile
shutil.copyfile(source, dest)
File "/usr/lib/python2.7/shutil.py", line 82, in copyfile
with open(src, 'rb') as fsrc:
IOError: [Errno 2] No such file or directory: u'/home/asarch/waitress/waitress/docs/.static/logo_hi.gif'

Uncaptured exception instead of 400 when receiving non-ascii bytes in request url

Hi.

I have waitress installed on my production server and it generates strange exceptions. Like this:

uncaptured python exception, closing channel <waitress.channel.HTTPChannel connected 127.0.0.1:54006 at 0xb034478c>
(<class 'UnicodeDecodeError'>:'ascii' codec can't decode byte 0xd0 in position 124: ordinal not in range(128)
[/usr/lib/python3.2/asyncore.py|read|83]
[/usr/lib/python3.2/asyncore.py|handle_read_event|449]
[/home/novo/py32/libpython3.2/site-packages/waitress/channel.py|handle_read|175]
[/home/novo/py32/lib/python3.2/site-packages/waitress/channel.py|received|192]
[/home/novo/py32/lib/python3.2/site-packages/waitress/parser.py|received|102]
[/home/novo/py32/lib/python3.2/site-packages/waitress/parser.py|parse_header|206]
[/home/novo/py32/lib/python3.2/site-packages/waitress/parser.py|split_uri|254]
[/usr/lib/python3.2/urllib/parse.py|urlsplit|314]
[/usr/lib/python3.2/urllib/parse.py|_coerce_args|101]
[/usr/lib/python3.2/urllib/parse.py|_decode_args|85]
[/usr/lib/python3.2/urllib/parse.py
<genexpr>|85])

I found that these exceptions generated when some stupid bot sends request with raw bytes \xd0 in http header in first line. Here is a line from nginx log (nginx proxy queries to waitress):

54.209.115.31 - myhost.ru - [03/Jul/2014:15:41:46 +0000] "GET /lands/lands/%D0%B1%D0%B0%D0%B9%D0%BA%D0%B0%D0%BB/%D0%BC%D0%B0%D0%BB%D0%BE%D0%B5-%D0%BC%D0%BE%D1%80%D0%B5/lands/\xD0\xB1\xD0\xB0\xD0\xB9\xD0\xBA\xD0\xB0\xD0\xBB/\xD0\xBC\xD0\xB0\xD0\xBB\xD0\xBE\xD0\xB5-\xD0\xBC\xD0\xBE\xD1\x80\xD0\xB5/\xD0\xB7\xD0\xB0\xD0\xBB\xD0\xB8\xD0\xB2-\xD0\xBA\xD1\x83\xD1\x80\xD0\xBA\xD1\x83\xD1\x82\xD1\x81\xD0\xBA\xD0\xB8\xD0\xB9/\xD0\xBA\xD1\x83\xD1\x80\xD0\xBA\xD1\x83\xD1\x82/id330/ HTTP/1.1" 502 172 "-" "" "-"

As you can see, here the client sent both urlescaped and raw bytes in GET. According to RFC, url must by escaped. But nginx doesn't care.

I also wrote simple POC to demonstrate the issue:

def send_xdo(host, port=80):
    s = socket.create_connection((host, port))
    req = b"GET /\xd0 HTTP/1.1\n\n"
    s.send(req)
    s.recv(4096)
    s.close()

send_xdo('localhost', 6543)

I think Waitress should be able to handle this exception. It will be better just send 400 Bad Request to the client. Take a look at the rfc - http://tools.ietf.org/html/rfc2616#section-5.1.2

The Request-URI is transmitted in the format specified in section
3.2.1. If the Request-URI is encoded using the "% HEX HEX" encoding
[42], the origin server MUST decode the Request-URI in order to
properly interpret the request. Servers SHOULD respond to invalid
Request-URIs with an appropriate status code.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.