Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

100-continue and PUT request - they hang on env['wsgi.input'].read() call #4

Open
jn0 opened this issue Dec 6, 2016 · 6 comments
Open

Comments

@jn0
Copy link

jn0 commented Dec 6, 2016

wsgiserver 1.3 in Python 2.7.12 under Ubuntu 16.04

Create the script

#!/usr/bin/python

import sys
import wsgiserver
import pprint
import signal

sample_text = [
	'Hello world\n',
	'\n',
]

def The_Application(env, proc):
	status, response_headers, result = \
		'200 OK', [('Content-Type', 'text/plain; charset=utf-8'),], []

	# cardinal workaround: don't allow a thread to hang the node forever
	signal.alarm(15)

	pprint.pprint(env)
	pprint.pprint(server)

	data = env['wsgi.input'].read() # XXX this will block forever XXX
	pprint.pprint(data)
	

	# poor attempt to work it around
#	if env.get('HTTP_EXPECT', '-') == '100-continue':
#		proc('100 Continue', [])

	for x in sample_text:
		result.append(x)

	proc(status, response_headers)
	return result and result or ['ERROR']

wsgi_pathes = {
	'/': The_Application,
}

dispatcher = wsgiserver.WSGIPathInfoDispatcher(wsgi_pathes)

server = wsgiserver.WSGIServer(dispatcher, host = '0.0.0.0', port = 8080)

try:
	server.start()
except e:
	server.interrupt = e
	server.stop()
	sys.stderr.write('Killed\n')

# EOF #

run it and call with curl.
You'll see that

curl -vv -F a=b http://127.0.0.1:8080/some/path/to

performs just fine with POST method, but

curl -vv -F a=b -T some.small.file http://127.0.0.1:8080/some/path/to

will cause the app (and the whole box!) to hang until alarm just after sending HTTP/1.1 100 Continue response.

If one comment out the .read() call, then normal operation resumes:

> PUT /some/path/to HTTP/1.1
> Host: 172.17.16.105:8080
> User-Agent: curl/7.47.0
> Accept: */*
> Transfer-Encoding: chunked
> Expect: 100-continue
> 
< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< Content-Type: text/plain; charset=utf-8
< Transfer-Encoding: chunked
< Date: Tue, 06 Dec 2016 14:37:52 GMT
< Server: jno-intra
< 
Hello world

Here we are.


I.e. it's the .read() method of ChunkedRFile class from wsgiserver.py module.

If the size parameter is not set, then it could set once the self.buffer to something and loop forever eating all the RAM available (in data += self.buffer).

I think, the line # 457

                data += self.buffer

should read somehow as

                data += self.buffer; self.buffer = None

Yes, it works for me with this "patch".

@jn0
Copy link
Author

jn0 commented Dec 6, 2016

BTW, line # 483 in .readline() method has also such an "unguarded" data update which may persist forever if self.buffer has no LF...

@jn0
Copy link
Author

jn0 commented Dec 6, 2016

Plus, it may be a good idea to

  1. make a worker thread to call self.setDaemon(True) in .__init__() to get killed along with the main thread
  2. make'em "stoppable" for graceful shutdown.
  3. provide a mean to use with-as syntax (i.e. add .__enter__() and .__exit__() methods)

I'd like to call it as

with WSGIServer(...) as server:
    server.start()
    ###

@fgallaire
Copy link
Owner

@jn0
As WSGIserver is a standalone fork of the CherryPy WSGI server, could it be possible for you to test it too ?

@fgallaire
Copy link
Owner

seems related to cherrypy/cherrypy#1486

@jn0
Copy link
Author

jn0 commented Dec 7, 2016

Yes, it looks the same.
And needs almost the same patch.

@webknjaz
Copy link

webknjaz commented Jun 20, 2017

@jn0 This is fixed in cherrypy/cheroot upstream. Please use cheroot of version v5.6.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants