1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
""" Composer for HTTP responses
This module contains a composer, which can compose responses to
HTTP requests from a client.
"""
import re
import time
from config import config
import encodings
from message import Response
from resource import Resource, FileExistError, FileAccessError
import weblogging as logging
class ResponseComposer:
"""Class that composes a HTTP response to a HTTP request"""
def __init__(self, timeout):
"""Initialize the ResponseComposer
Args:
timeout (int): connection timeout
"""
self.timeout = timeout
def compose_response(self, request):
"""Compose a response to a request
Args:
request (webhttp.Request): request from client
Returns:
webhttp.Response: response to request
"""
response = Response()
if re.search(r'\/\.\.?(\/|$)', request.uri):
return self.serve_error(403)
else:
return self.serve(request.uri, request=request)
def serve(self, uri, code=200, etag=None, request=None):
resp = Response()
try:
resource = Resource(uri)
req = request
if req != None and (
resource.etag_match(req.get_header('If-None-Match')) or \
req.get_header('If-Match') != None and \
not resource.etag_match(req.get_header('If-Match'))):
resp.code = 304
else:
resp.code = code
resp.body = None
encs = req.encodings() if req != None else [encodings.IDENTITY]
for enc in encs:
try:
resp.body = resource.get_content(enc)
resp.set_header('Content-Encoding', encodings.str(enc))
break
except UnknownEncodingError:
pass
if resp.body == None:
return self.serve_error(406)
resp.set_header('ETag', resource.generate_etag())
resp.set_header('Content-Type', resource.get_content_type())
resp.set_content_length()
except FileExistError:
if code < 400:
return self.serve_error(404)
else:
resp.code = code
resp.body = 'Error %d' % code
resp.set_content_length()
except FileAccessError:
return self.serve_error(403)
conn = 'keep-alive'
if req != None and req.get_header('Connection') == 'close':
conn = 'close'
resp.set_header('Connection', conn)
return resp
def serve_error(self, code):
return self.serve(config('error%d' % code, default=None), code=code)
def make_date_string(self):
"""Make string of date and time
Returns:
str: formatted string of date and time
"""
return time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())
|