forked from asynchronoust/kbengine-httpserver
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathresponse.py
More file actions
115 lines (90 loc) · 3.15 KB
/
response.py
File metadata and controls
115 lines (90 loc) · 3.15 KB
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
98
99
100
101
102
103
104
105
106
107
108
# -*- coding: utf-8 -*-
"""
FileName: response
Author: Tao Hao
@contact: [email protected]
Created time: 2019/5/29
Description:
Changelog:
"""
from multidict import CIMultiDict
from httpserver.utils import remove_entity_headers, STATUS_CODES
class HTTPResponse(object):
def __init__(self, body=None,
status=200, headers=None,
content_type="text/plain", body_bytes=b""):
self.content_type = content_type
self.headers = headers
if body is not None:
self.body = self.encode_body(body)
else:
self.body = body_bytes
self.status = status
self.headers = CIMultiDict(headers or {})
def encode_body(self, data):
try:
return data.encode()
except AttributeError:
return str(data).encode()
def parse_headers(self):
headers = b""
for key, value in self.headers.items():
try:
headers += b"%b: %b\r\n" % (key.encode(), value.encode("utf-8"))
except AttributeError:
headers += b"%b: %b\r\n" % (
str(key).encode(), str(value).encode("utf-8")
)
return headers
def has_message_body(self):
"""
According to the following RFC message body and length SHOULD NOT
be included in responses status 1XX, 204 and 304.
https://tools.ietf.org/html/rfc2616#section-4.4
https://tools.ietf.org/html/rfc2616#section-4.3
"""
return self.status not in (204, 304) and not (100 <= self.status < 200)
def output(self, version="1.1", keep_alive=False, keep_alive_timeout=None):
"""
TODO 先暂时不支持 keep alive
:param version:
:return:
"""
timeout_header=b""
if keep_alive and keep_alive_timeout is not None:
timeout_header = b"Keep-Alive: %d\r\n" % keep_alive_timeout
body = b""
if self.has_message_body():
body = self.body
self.headers["Content-Length"] = self.headers.get(
"Content-Length", len(self.body)
)
self.headers["Content-Type"] = self.headers.get(
"Content-Type", self.content_type
)
if self.status in (304, 412):
self.headers = remove_entity_headers(self.headers)
headers = self.parse_headers()
if self.status == 200:
status_msg = b"OK"
else:
status_msg = STATUS_CODES.get(self.status, b"UNKNOWN RESPONSE")
"""
消息结构如下:
HTTP/1.1 200 OK # 状态行
Connection: close # headers
Content-Type: text/plain
# 空行
xxxxxbody part # body内容
"""
return (
b"HTTP/%b %d %b\r\n" b"Connection: %b\r\n" b"%b" b"%b\r\n" b"%b"
) % (
version.encode(),
self.status,
status_msg,
b"keep-alive" if keep_alive else b"close",
timeout_header,
headers,
body
)