import os.path
import unittest
import socket
import sys
import time
from webhttp.config import config
import webhttp.message
import webhttp.parser
portnr = 8001
class TestGetRequests(unittest.TestCase):
"""Test cases for GET requests"""
def setUp(self):
"""Prepare for testing"""
self.client_skt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client_skt.connect(("localhost", portnr))
self.parser = webhttp.parser.ResponseParser()
self.default_headers = [
('Host', 'localhost:%d' % portnr),
('Connection', 'close')
]
self.default_headers_pers = [
('Host', 'localhost:%d' % portnr),
('Connection', 'keep-alive')
]
config().read(os.path.expanduser('~/.webpy.ini'))
def tearDown(self):
"""Clean up after testing"""
try:
self.client_skt.shutdown(socket.SHUT_RDWR)
self.client_skt.close()
except:
pass
def refresh_socket(self):
try:
self.client_skt.shutdown(socket.SHUT_RDWR)
self.client_skt.close()
except:
pass
self.client_skt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client_skt.connect(("localhost", portnr))
def request(self, method, uri, headers, persistent=False):
request = webhttp.message.Request()
request.method = method
request.uri = uri
for name, value in headers:
request.set_header(name, value)
sent = self.client_skt.send(str(request))
if sent == 0:
return None
message = self.client_skt.recv(1024)
if not persistent:
self.refresh_socket()
if message == '':
return None
else:
response = self.parser.parse_response(message)
return response
def test_existing_file(self):
"""GET for a single resource that exists"""
response = self.request(
'GET', '/test/index.html', self.default_headers)
self.assertEqual(response.code, 200)
self.assertTrue(response.body)
def test_nonexistant_file(self):
"""GET for a single resource that does not exist"""
response = self.request(
'GET', '/test/nonexistant.html', self.default_headers)
self.assertEqual(response.code, 404)
self.assertTrue(response.body)
def test_caching(self):
"""GET for an existing single resource followed by a GET for that same
resource with caching utilized on the client/tester side
"""
response = self.request('GET', '/test', self.default_headers)
response = self.request('GET', '/test', self.default_headers + \
[('If-None-Match', 'invalid-etag')])
self.assertEqual(response.code, 200, 'If-None-Match returns 200')
response = self.request('GET', '/test', self.default_headers + \
[('If-None-Match', response.get_header('ETag'))])
self.assertEqual(response.code, 304, 'If-None-Match returns 304')
response = self.request('GET', '/test', self.default_headers + \
[('If-Match', response.get_header('ETag'))])
self.assertEqual(response.code, 200, 'If-Match returns 200')
response = self.request('GET', '/test', self.default_headers + \
[('If-Match', 'invalid-etag')])
self.assertEqual(response.code, 304, 'If-Match returns 304')
def test_extisting_index_file(self):
"""GET for a directory with an existing index.html file"""
self.assertEqual(self.request('GET', '/test', self.default_headers),
self.request('GET', '/test/index.html', self.default_headers))
def test_nonexistant_index_file(self):
"""GET for a directory with a non-existant index.html file"""
response = self.request('GET', '/test/no-index', self.default_headers)
self.assertEqual(response.code, 403)
self.assertTrue(response.body)
def test_error_page(self):
r1 = self.request('GET', '/test/nonexistant', self.default_headers)
r2 = self.request('GET', config('error404'), self.default_headers)
self.assertEqual(r1.body, r2.body)
def test_persistent_close(self):
"""Multiple GETs over the same (persistent) connection with the last
GET prompting closing the connection, the connection should be closed.
"""
try:
self.request('GET', '/test', self.default_headers_pers, True)
self.request('GET', '/test', self.default_headers_pers, True)
self.request('GET', '/test', self.default_headers_pers, True)
except socket.error:
self.fail('Persistent connection closed prematurely')
self.request('GET', '/test', self.default_headers, True)
self.assertIsNone(self.request('GET', '/test',
self.default_headers_pers, True))
self.refresh_socket()
def test_persistent_timeout(self):
"""Multiple GETs over the same (persistent) connection, followed by a
wait during which the connection times out, the connection should be
closed.
"""
self.request('GET', '/test', self.default_headers_pers, True)
time.sleep(20)
self.assertIsNone(self.request('GET', '/test',
self.default_headers_pers, True))
self.refresh_socket()
def test_encoding(self):
"""GET which requests an existing resource using gzip encodign, which
is accepted by the server.
"""
r1 = self.request('GET', '/test', self.default_headers + \
[('Accept-Encoding', 'gzip;q=1, identity;q=0')])
self.assertEqual(r1.get_header('Content-Encoding'), 'gzip')
r1.decompress()
r2 = self.request('GET', '/test', self.default_headers + \
[('Accept-Encoding', '')])
self.assertEqual(r1.body, r2.body)
def test_doubledot(self):
response = self.request('GET', '/../test', self.default_headers)
self.assertEquals(response.code, 403)
if __name__ == "__main__":
# Parse command line arguments
import argparse
parser = argparse.ArgumentParser(description="HTTP Tests")
parser.add_argument("-p", "--port", type=int, default=8001)
# Arguments for the unittest framework
parser.add_argument('unittest_args', nargs='*')
args = parser.parse_args()
portnr = args.port
# Only pass the unittest arguments to unittest
sys.argv[1:] = args.unittest_args
# Start test suite
unittest.main()