import collections
import errno
import os
+import shutil
import signal
import socket
import sys
+import tempfile
import traceback
import unittest
import eventlet
from eventlet import debug
from eventlet import event
-from eventlet.green import socket as greensocket
-from eventlet.green import ssl
-from eventlet.green import subprocess
from eventlet import greenio
from eventlet import greenthread
from eventlet import support
-from eventlet.support import bytes_to_str, capture_stderr, six
from eventlet import tpool
from eventlet import wsgi
-
+from eventlet.green import socket as greensocket
+from eventlet.green import ssl
+from eventlet.support import bytes_to_str, capture_stderr, six
import tests
CONTENT_LENGTH = 'content-length'
-"""
-HTTP/1.1 200 OK
-Date: foo
-Content-length: 11
-
-hello world
-"""
-
-
-def recvall(socket_):
+def recvall(sock):
result = b''
while True:
- chunk = socket_.recv()
- result += chunk
+ chunk = sock.recv(16 << 10)
if chunk == b'':
- break
-
- return result
+ return result
+ result += chunk
class ConnectionClosed(Exception):
"""Spawns a new wsgi server with the given arguments using
:meth:`spawn_thread`.
- Sets self.port to the port of the server
+ Sets `self.server_addr` to (host, port) tuple suitable for `socket.connect`.
"""
new_kwargs = dict(max_size=128,
log=self.logfile,
if 'sock' not in new_kwargs:
new_kwargs['sock'] = eventlet.listen(('localhost', 0))
- self.port = new_kwargs['sock'].getsockname()[1]
+ self.server_addr = new_kwargs['sock'].getsockname()
self.spawn_thread(wsgi.server, **new_kwargs)
def spawn_thread(self, target, **kwargs):
self.site = Site()
def test_001_server(self):
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
- fd.flush()
- result = fd.read()
- fd.close()
+ sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
+ result = recvall(sock)
# The server responds with the maximum version it supports
assert result.startswith(b'HTTP'), result
assert result.endswith(b'hello world'), result
def test_002_keepalive(self):
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
- fd = sock.makefile('wb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
read_http(sock)
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
read_http(sock)
- fd.close()
- sock.close()
-
- def test_003_passing_non_int_to_read(self):
- # This should go in greenio_test
- sock = eventlet.connect(
- ('localhost', self.port))
-
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
- cancel = eventlet.Timeout(1, RuntimeError)
- self.assertRaises(TypeError, fd.read, "This shouldn't work")
- cancel.cancel()
- fd.close()
def test_004_close_keepalive(self):
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
- fd = sock.makefile('wb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
- read_http(sock)
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
- read_http(sock)
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
+ result1 = read_http(sock)
+ assert result1.status == 'HTTP/1.1 200 OK'
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
+ result2 = read_http(sock)
+ assert result2.status == 'HTTP/1.1 200 OK'
+ assert result2.headers_lower['connection'] == 'close'
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
self.assertRaises(ConnectionClosed, read_http, sock)
- fd.close()
-
- @tests.skipped
- def test_005_run_apachebench(self):
- url = 'http://localhost:12346/'
- # ab is apachebench
- subprocess.call(
- [tests.find_command('ab'), '-c', '64', '-n', '1024', '-k', url],
- stdout=subprocess.PIPE)
def test_006_reject_long_urls(self):
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
path_parts = []
for ii in range(3000):
path_parts.append('path')
return [six.b('a is %s, body is %s' % (a, body))]
self.site.application = new_app
- sock = eventlet.connect(
- ('localhost', self.port))
- request = '\r\n'.join((
- 'POST / HTTP/1.0',
- 'Host: localhost',
- 'Content-Length: 3',
- '',
- 'a=a'))
- fd = sock.makefile('wb')
- fd.write(request.encode())
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ request = b'\r\n'.join((
+ b'POST / HTTP/1.0',
+ b'Host: localhost',
+ b'Content-Length: 3',
+ b'',
+ b'a=a'))
+ sock.sendall(request)
# send some junk after the actual request
- fd.write(b'01234567890123456789')
+ sock.sendall(b'01234567890123456789')
result = read_http(sock)
self.assertEqual(result.body, b'a is a, body is a=a')
- fd.close()
def test_008_correctresponse(self):
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
- fd = sock.makefile('wb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
result_200 = read_http(sock)
- fd.write(b'GET /notexist HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
+ sock.sendall(b'GET /notexist HTTP/1.1\r\nHost: localhost\r\n\r\n')
read_http(sock)
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
result_test = read_http(sock)
self.assertEqual(result_200.status, result_test.status)
- fd.close()
- sock.close()
def test_009_chunked_response(self):
self.site.application = chunked_app
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
- assert b'Transfer-Encoding: chunked' in fd.read()
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
+ assert b'Transfer-Encoding: chunked' in recvall(sock)
def test_010_no_chunked_http_1_0(self):
self.site.application = chunked_app
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
- assert b'Transfer-Encoding: chunked' not in fd.read()
+ sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n')
+ assert b'Transfer-Encoding: chunked' not in recvall(sock)
def test_011_multiple_chunks(self):
self.site.application = big_chunks
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fd = sock.makefile('rwb')
fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
# Require a CRLF to close the message body
self.assertEqual(response, b'\r\n')
+ def test_partial_writes_are_handled(self):
+ # https://github.com/eventlet/eventlet/issues/295
+ # Eventlet issue: "Python 3: wsgi doesn't handle correctly partial
+ # write of socket send() when using writelines()".
+ #
+ # The bug was caused by the default writelines() implementaiton
+ # (used by the wsgi module) which doesn't check if write()
+ # successfully completed sending *all* data therefore data could be
+ # lost and the client could be left hanging forever.
+ #
+ # Switching wsgi wfile to buffered mode fixes the issue.
+ #
+ # Related CPython issue: "Raw I/O writelines() broken",
+ # http://bugs.python.org/issue26292
+ #
+ # Custom accept() and send() in order to simulate a connection that
+ # only sends one byte at a time so that any code that doesn't handle
+ # partial writes correctly has to fail.
+ listen_socket = eventlet.listen(('localhost', 0))
+ original_accept = listen_socket.accept
+
+ def accept():
+ connection, address = original_accept()
+ original_send = connection.send
+
+ def send(b, *args):
+ b = b[:1]
+ return original_send(b, *args)
+
+ connection.send = send
+ return connection, address
+
+ listen_socket.accept = accept
+
+ def application(env, start_response):
+ # Sending content-length is important here so that the client knows
+ # exactly how many bytes does it need to wait for.
+ start_response('200 OK', [('Content-length', 3)])
+ yield 'asd'
+
+ self.spawn_server(sock=listen_socket)
+ self.site.application = application
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
+ # This would previously hang forever
+ result = read_http(sock)
+ assert result.body == b'asd'
+
@tests.skip_if_no_ssl
def test_012_ssl_server(self):
def wsgi_app(environ, start_response):
server_side=True)
self.spawn_server(sock=server_sock, site=wsgi_app)
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock = eventlet.wrap_ssl(sock)
sock.write(
b'POST /foo HTTP/1.1\r\nHost: localhost\r\n'
def test_014_chunked_post(self):
self.site.application = chunked_post
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fd = sock.makefile('rwb')
fd.write('PUT /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n'
'Transfer-Encoding: chunked\r\n\r\n'
response = fd.read()
assert response == b'oh hai', 'invalid response %s' % response
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fd = sock.makefile('rwb')
fd.write('PUT /b HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n'
'Transfer-Encoding: chunked\r\n\r\n'
response = fd.read()
assert response == b'oh hai', 'invalid response %s' % response
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fd = sock.makefile('rwb')
fd.write('PUT /c HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n'
'Transfer-Encoding: chunked\r\n\r\n'
def test_015_write(self):
self.site.application = use_write
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('wb')
- fd.write(b'GET /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
result1 = read_http(sock)
assert 'content-length' in result1.headers_lower
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('wb')
- fd.write(b'GET /b HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET /b HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
result2 = read_http(sock)
assert 'transfer-encoding' in result2.headers_lower
assert result2.headers_lower['transfer-encoding'] == 'chunked'
start_response('200 OK', [('Content-Length', '7')])
return [b'testing']
self.site.application = wsgi_app
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fd = sock.makefile('rwb')
fd.write(b'GET /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
fd.flush()
def test_018_http_10_keepalive(self):
# verify that if an http/1.0 client sends connection: keep-alive
# that we don't close the connection
- sock = eventlet.connect(
- ('localhost', self.port))
-
- fd = sock.makefile('wb')
- fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
result1 = read_http(sock)
assert 'connection' in result1.headers_lower
self.assertEqual('keep-alive', result1.headers_lower['connection'])
+
# repeat request to verify connection is actually still open
- fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
- fd.flush()
+ sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
result2 = read_http(sock)
assert 'connection' in result2.headers_lower
self.assertEqual('keep-alive', result2.headers_lower['connection'])
return [b'hello!']
self.site.application = use_fieldstorage
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
- fd = sock.makefile('rwb')
- fd.write('POST / HTTP/1.1\r\n'
- 'Host: localhost\r\n'
- 'Connection: close\r\n'
- 'Transfer-Encoding: chunked\r\n\r\n'
- '2\r\noh\r\n'
- '4\r\n hai\r\n0\r\n\r\n'.encode())
- fd.flush()
- assert b'hello!' in fd.read()
+ sock.sendall(b'POST / HTTP/1.1\r\n'
+ b'Host: localhost\r\n'
+ b'Connection: close\r\n'
+ b'Transfer-Encoding: chunked\r\n\r\n'
+ b'2\r\noh\r\n'
+ b'4\r\n hai\r\n0\r\n\r\n')
+ assert b'hello!' in recvall(sock)
def test_020_x_forwarded_for(self):
request_bytes = (
+ b'X-Forwarded-For: 1.2.3.4, 5.6.7.8\r\n\r\n'
)
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(request_bytes)
sock.recv(1024)
sock.close()
self.logfile = six.StringIO()
self.spawn_server(log_x_forwarded_for=False)
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(request_bytes)
sock.recv(1024)
sock.close()
server_sock_2 = server_sock.dup()
self.spawn_server(sock=server_sock_2)
# do a single req/response to verify it's up
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
- fd.flush()
- result = fd.read(1024)
- fd.close()
+ sock = eventlet.connect(server_sock.getsockname())
+ sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
+ result = sock.recv(1024)
assert result.startswith(b'HTTP'), result
assert result.endswith(b'hello world'), result
except socket.error as exc:
self.assertEqual(support.get_errno(exc), errno.EBADF)
self.spawn_server(sock=server_sock)
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
- fd.flush()
- result = fd.read(1024)
- fd.close()
+ sock = eventlet.connect(server_sock.getsockname())
+ sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
+ result = sock.recv(1024)
assert result.startswith(b'HTTP'), result
assert result.endswith(b'hello world'), result
start_response('200 OK', [('Content-type', 'text/plain')])
return []
self.site.application = clobberin_time
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write('GET / HTTP/1.1\r\n'
- 'Host: localhost\r\n'
- 'Connection: close\r\n'
- '\r\n\r\n'.encode())
- fd.flush()
- assert b'200 OK' in fd.read()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.1\r\n'
+ b'Host: localhost\r\n'
+ b'Connection: close\r\n'
+ b'\r\n\r\n')
+ assert b'200 OK' in recvall(sock)
def test_022_custom_pool(self):
# just test that it accepts the parameter for now
self.spawn_server(custom_pool=p)
# this stuff is copied from test_001_server, could be better factored
- sock = eventlet.connect(
- ('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
- fd.flush()
- result = fd.read()
- fd.close()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
+ result = recvall(sock)
assert result.startswith(b'HTTP'), result
assert result.endswith(b'hello world'), result
def test_023_bad_content_length(self):
- sock = eventlet.connect(
- ('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\nContent-length: argh\r\n\r\n')
- fd.flush()
- result = fd.read()
- fd.close()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nContent-length: argh\r\n\r\n')
+ result = recvall(sock)
assert result.startswith(b'HTTP'), result
assert b'400 Bad Request' in result, result
assert b'500' not in result, result
start_response('200 OK', [('Content-Length', str(len(text)))])
return [text]
self.site.application = wsgi_app
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fd = sock.makefile('rwb')
fd.write(b'PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 1025\r\n'
b'Expect: 100-continue\r\n\r\n')
start_response('200 OK', [('Content-Length', str(len(text)))])
return [text]
self.site.application = wsgi_app
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fd = sock.makefile('rwb')
fd.write(b'PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 1025\r\n'
b'Expect: 100-continue\r\n\r\n')
start_response('200 OK', [('Content-Length', str(len(text)))])
return [text]
self.site.application = wsgi_app
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fd = sock.makefile('rwb')
fd.write(b'PUT /a HTTP/1.1\r\n'
b'Host: localhost\r\nConnection: close\r\n'
return [text]
self.site.application = wsgi_app
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fd = sock.makefile('rwb')
fd.write(b'PUT /a HTTP/1.1\r\n'
b'Host: localhost\r\nConnection: close\r\n'
self.spawn_server(sock=listener)
eventlet.sleep(0) # need to enter server loop
try:
- eventlet.connect(('localhost', self.port))
+ eventlet.connect(self.server_addr)
self.fail("Didn't expect to connect")
except socket.error as exc:
self.assertEqual(support.get_errno(exc), errno.ECONNREFUSED)
def test_026_log_format(self):
self.spawn_server(log_format="HI %(request_line)s HI")
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(b'GET /yo! HTTP/1.1\r\nHost: localhost\r\n\r\n')
sock.recv(1024)
sock.close()
# and we're not speaking with a 1.1 client, that we
# close the connection
self.site.application = chunked_app
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
self.assertNotEqual(result.headers_lower.get('transfer-encoding'), 'chunked')
self.assertEqual(result.body, b"thisischunked")
+ def test_chunked_response_when_app_yields_empty_string(self):
+ def empty_string_chunked_app(env, start_response):
+ env['eventlet.minimum_write_chunk_size'] = 0 # no buffering
+ start_response('200 OK', [('Content-type', 'text/plain')])
+ return iter([b"stuff", b"", b"more stuff"])
+
+ self.site.application = empty_string_chunked_app
+ sock = eventlet.connect(self.server_addr)
+
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
+
+ result = read_http(sock)
+ self.assertEqual(result.headers_lower.get('transfer-encoding'), 'chunked')
+ self.assertEqual(result.body, b"5\r\nstuff\r\na\r\nmore stuff\r\n0\r\n\r\n")
+
def test_minimum_chunk_size_parameter_leaves_httpprotocol_class_member_intact(self):
start_size = wsgi.HttpProtocol.minimum_chunk_size
self.spawn_server(minimum_chunk_size=start_size * 2)
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
read_http(sock)
self.spawn_server(minimum_chunk_size=1)
self.site.application = chunked_fail_app
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
# verify that if an http/1.0 client sends connection: keep-alive
# and the server doesn't accept keep-alives, we close the connection
self.spawn_server(keepalive=False)
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
result = read_http(sock)
def test_027_keepalive_chunked(self):
self.site.application = chunked_post
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('wb')
+ sock = eventlet.connect(self.server_addr)
common_suffix = (
b'Host: localhost\r\nTransfer-Encoding: chunked\r\n\r\n' +
b'10\r\n0123456789abcdef\r\n0\r\n\r\n')
- fd.write(b'PUT /a HTTP/1.1\r\n' + common_suffix)
- fd.flush()
+ sock.sendall(b'PUT /a HTTP/1.1\r\n' + common_suffix)
read_http(sock)
- fd.write(b'PUT /b HTTP/1.1\r\n' + common_suffix)
- fd.flush()
+ sock.sendall(b'PUT /b HTTP/1.1\r\n' + common_suffix)
read_http(sock)
- fd.write(b'PUT /c HTTP/1.1\r\n' + common_suffix)
- fd.flush()
+ sock.sendall(b'PUT /c HTTP/1.1\r\n' + common_suffix)
read_http(sock)
- fd.write(b'PUT /a HTTP/1.1\r\n' + common_suffix)
- fd.flush()
+ sock.sendall(b'PUT /a HTTP/1.1\r\n' + common_suffix)
read_http(sock)
sock.close()
eventlet.listen(('localhost', 0)),
certfile=certificate_file, keyfile=private_key_file,
server_side=True)
- port = srv_sock.getsockname()[1]
+ addr = srv_sock.getsockname()
g = eventlet.spawn_n(server, srv_sock)
- client = eventlet.connect(('localhost', port))
+ client = eventlet.connect(addr)
if data: # send non-ssl request
client.sendall(data.encode())
else: # close sock prematurely
assert not errored[0], errored[0]
# make another request to ensure the server's still alive
try:
- client = ssl.wrap_socket(eventlet.connect(('localhost', port)))
+ client = ssl.wrap_socket(eventlet.connect(addr))
client.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
result = recvall(client)
assert result.startswith(b'HTTP'), result
start_response('200 OK', [('Content-Type', 'text/plain')])
yield b''
self.site.application = one_posthook_app
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fp = sock.makefile('rwb')
fp.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
fp.flush()
start_response('200 OK', [('Content-Type', 'text/plain')])
yield b''
self.site.application = two_posthook_app
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
fp = sock.makefile('rwb')
fp.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
fp.flush()
self.assertEqual(posthook2_count[0], 25)
def test_030_reject_long_header_lines(self):
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
request = 'GET / HTTP/1.0\r\nHost: localhost\r\nLong: %s\r\n\r\n' % \
('a' * 10000)
send_expect_close(sock, request.encode())
self.assertEqual(result.status, 'HTTP/1.0 400 Header Line Too Long')
def test_031_reject_large_headers(self):
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
headers = ('Name: %s\r\n' % ('a' * 7000,)) * 20
request = 'GET / HTTP/1.0\r\nHost: localhost\r\n%s\r\n\r\n' % headers
send_expect_close(sock, request.encode())
'Host: localhost\r\n'
'Content-Length: %i\r\n\r\n%s'
) % (len(upload_data), bytes_to_str(upload_data))
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write(request.encode())
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(request.encode())
result = read_http(sock)
self.assertEqual(result.body, upload_data)
- fd.close()
self.assertEqual(g[0], 1)
def test_zero_length_chunked_response(self):
yield b""
self.site.application = zero_chunked_app
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
- response = fd.read().split(b'\r\n')
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
+ response = recvall(sock).split(b'\r\n')
headers = []
while True:
h = response.pop(0)
def test_configurable_url_length_limit(self):
self.spawn_server(url_length_limit=20000)
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
path = 'x' * 15000
request = 'GET /%s HTTP/1.0\r\nHost: localhost\r\n\r\n' % path
fd = sock.makefile('rwb')
read_content.send(content)
start_response('200 OK', [('Content-Type', 'text/plain')])
return [content]
+
self.site.application = chunk_reader
expected_body = 'a bunch of stuff'
data = "\r\n".join(['PUT /somefile HTTP/1.0',
'def',
expected_body])
# start PUT-ing some chunked data but close prematurely
- sock = eventlet.connect(('127.0.0.1', self.port))
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(data.encode())
+ sock.close()
+ # the test passes if we successfully get here, and read all the data
+ # in spite of the early close
+ self.assertEqual(read_content.wait(), b'ok')
+ assert blew_up[0]
+
+ def test_aborted_chunked_post_between_chunks(self):
+ read_content = event.Event()
+ blew_up = [False]
+
+ def chunk_reader(env, start_response):
+ try:
+ content = env['wsgi.input'].read(1024)
+ except wsgi.ChunkReadError:
+ blew_up[0] = True
+ content = b'ok'
+ except Exception as err:
+ blew_up[0] = True
+ content = b'wrong exception: ' + str(err).encode()
+ read_content.send(content)
+ start_response('200 OK', [('Content-Type', 'text/plain')])
+ return [content]
+ self.site.application = chunk_reader
+ expected_body = 'A' * 0xdb
+ data = "\r\n".join(['PUT /somefile HTTP/1.0',
+ 'Transfer-Encoding: chunked',
+ '',
+ 'db',
+ expected_body])
+ # start PUT-ing some chunked data but close prematurely
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(data.encode())
+ sock.close()
+ # the test passes if we successfully get here, and read all the data
+ # in spite of the early close
+ self.assertEqual(read_content.wait(), b'ok')
+ assert blew_up[0]
+
+ def test_aborted_chunked_post_bad_chunks(self):
+ read_content = event.Event()
+ blew_up = [False]
+
+ def chunk_reader(env, start_response):
+ try:
+ content = env['wsgi.input'].read(1024)
+ except wsgi.ChunkReadError:
+ blew_up[0] = True
+ content = b'ok'
+ except Exception as err:
+ blew_up[0] = True
+ content = b'wrong exception: ' + str(err).encode()
+ read_content.send(content)
+ start_response('200 OK', [('Content-Type', 'text/plain')])
+ return [content]
+ self.site.application = chunk_reader
+ expected_body = 'look here is some data for you'
+ data = "\r\n".join(['PUT /somefile HTTP/1.0',
+ 'Transfer-Encoding: chunked',
+ '',
+ 'cats',
+ expected_body])
+ # start PUT-ing some garbage
+ sock = eventlet.connect(self.server_addr)
sock.sendall(data.encode())
sock.close()
# the test passes if we successfully get here, and read all the data
def wsgi_app(environ, start_response):
raise RuntimeError("intentional error")
self.site.application = wsgi_app
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
result = read_http(sock)
self.assertEqual(result.status, 'HTTP/1.1 500 Internal Server Error')
self.assertEqual(result.headers_lower['connection'], 'close')
yield b"oh hai, "
yield u"xxx"
self.site.application = wsgi_app
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
result = read_http(sock)
assert b'xxx' in result.body
yield b"oh hai, "
yield u"xxx \u0230"
self.site.application = wsgi_app
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
result = read_http(sock)
self.assertEqual(result.status, 'HTTP/1.1 500 Internal Server Error')
self.assertEqual(result.headers_lower['connection'], 'close')
yield six.b("decoded: %s" % environ['PATH_INFO'])
yield six.b("raw: %s" % environ['RAW_PATH_INFO'])
self.site.application = wsgi_app
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('rwb')
- fd.write(b'GET /a*b@%40%233 HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET /a*b@%40%233 HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
result = read_http(sock)
self.assertEqual(result.status, 'HTTP/1.1 200 OK')
assert b'decoded: /a*b@@#3' in result.body
raise RuntimeError("intentional crash")
self.site.application = crasher
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('wb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
result1 = read_http(sock)
self.assertEqual(result1.status, 'HTTP/1.1 500 Internal Server Error')
self.assertEqual(result1.body, b'')
# verify traceback when debugging enabled
self.spawn_server(debug=True)
self.site.application = crasher
- sock = eventlet.connect(('localhost', self.port))
- fd = sock.makefile('wb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
- fd.flush()
+ sock = eventlet.connect(self.server_addr)
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
result2 = read_http(sock)
self.assertEqual(result2.status, 'HTTP/1.1 500 Internal Server Error')
assert b'intentional crash' in result2.body, result2.body
yield b'a' * 9876
server_sock = eventlet.listen(('localhost', 0))
- self.port = server_sock.getsockname()[1]
+ self.server_addr = server_sock.getsockname()
server = wsgi.Server(server_sock, server_sock.getsockname(), long_response,
log=self.logfile)
def test_server_socket_timeout(self):
self.spawn_server(socket_timeout=0.1)
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.send(b'GET / HTTP/1.1\r\n')
eventlet.sleep(0.1)
try:
self.spawn_server(site=wsgi_app, capitalize_response_headers=False)
- sock = eventlet.connect(('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
result = read_http(sock)
sock.close()
self.assertEqual(result.headers_lower[random_case_header[0].lower()], random_case_header[1])
self.assertEqual(result.headers_original[random_case_header[0]], random_case_header[1])
+ def test_log_unix_address(self):
+ tempdir = tempfile.mkdtemp('eventlet_test_log_unix_address')
+ path = ''
+ try:
+ sock = eventlet.listen(tempdir + '/socket', socket.AF_UNIX)
+ path = sock.getsockname()
+
+ log = six.StringIO()
+ self.spawn_server(sock=sock, log=log)
+ eventlet.sleep(0) # need to enter server loop
+ assert 'http:' + path in log.getvalue()
+ finally:
+ shutil.rmtree(tempdir)
+
def read_headers(sock):
fd = sock.makefile('rb')
def test_iterable_app_keeps_socket_open_unless_connection_close_sent(self):
self.site.application = self.get_app()
- sock = eventlet.connect(
- ('localhost', self.port))
+ sock = eventlet.connect(self.server_addr)
- fd = sock.makefile('rwb')
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
-
- fd.flush()
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
response_line, headers = read_headers(sock)
self.assertEqual(response_line, 'HTTP/1.1 200 OK\r\n')
assert 'connection' not in headers
- fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
- fd.flush()
+
+ sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
result = read_http(sock)
self.assertEqual(result.status, 'HTTP/1.1 200 OK')
self.assertEqual(result.headers_lower.get('transfer-encoding'), 'chunked')
class TestChunkedInput(_TestBase):
- dirt = ""
validator = None
def application(self, env, start_response):
return response
def connect(self):
- return eventlet.connect(('localhost', self.port))
+ return eventlet.connect(self.server_addr)
def set_site(self):
self.site = Site()
self.site.application = self.application
- def chunk_encode(self, chunks, dirt=None):
- if dirt is None:
- dirt = self.dirt
-
+ def chunk_encode(self, chunks, dirt=""):
b = ""
for c in chunks:
b += "%x%s\r\n%s\r\n" % (len(c), dirt, c)
return b
- def body(self, dirt=None):
+ def body(self, dirt=""):
return self.chunk_encode(["this", " is ", "chunked", "\nline",
" 2", "\n", "line3", ""], dirt=dirt)