119 |
119 |
"""
|
120 |
120 |
|
121 |
121 |
|
122 |
|
class HTTPException(Exception):
|
|
122 |
class HttpException(Exception):
|
123 |
123 |
code = None
|
124 |
124 |
message = None
|
125 |
125 |
|
... | ... | |
129 |
129 |
self.message = message
|
130 |
130 |
|
131 |
131 |
|
132 |
|
class HTTPBadRequest(HTTPException):
|
|
132 |
class HttpBadRequest(HttpException):
|
133 |
133 |
code = 400
|
134 |
134 |
|
135 |
135 |
|
136 |
|
class HTTPForbidden(HTTPException):
|
|
136 |
class HttpForbidden(HttpException):
|
137 |
137 |
code = 403
|
138 |
138 |
|
139 |
139 |
|
140 |
|
class HTTPNotFound(HTTPException):
|
|
140 |
class HttpNotFound(HttpException):
|
141 |
141 |
code = 404
|
142 |
142 |
|
143 |
143 |
|
144 |
|
class HTTPGone(HTTPException):
|
|
144 |
class HttpGone(HttpException):
|
145 |
145 |
code = 410
|
146 |
146 |
|
147 |
147 |
|
148 |
|
class HTTPLengthRequired(HTTPException):
|
|
148 |
class HttpLengthRequired(HttpException):
|
149 |
149 |
code = 411
|
150 |
150 |
|
151 |
151 |
|
152 |
|
class HTTPInternalError(HTTPException):
|
|
152 |
class HttpInternalError(HttpException):
|
153 |
153 |
code = 500
|
154 |
154 |
|
155 |
155 |
|
156 |
|
class HTTPNotImplemented(HTTPException):
|
|
156 |
class HttpNotImplemented(HttpException):
|
157 |
157 |
code = 501
|
158 |
158 |
|
159 |
159 |
|
160 |
|
class HTTPServiceUnavailable(HTTPException):
|
|
160 |
class HttpServiceUnavailable(HttpException):
|
161 |
161 |
code = 503
|
162 |
162 |
|
163 |
163 |
|
164 |
|
class HTTPVersionNotSupported(HTTPException):
|
|
164 |
class HttpVersionNotSupported(HttpException):
|
165 |
165 |
code = 505
|
166 |
166 |
|
167 |
167 |
|
168 |
|
class HTTPJsonConverter:
|
|
168 |
class HttpJsonConverter:
|
169 |
169 |
CONTENT_TYPE = "application/json"
|
170 |
170 |
|
171 |
171 |
def Encode(self, data):
|
... | ... | |
475 |
475 |
self._ReadRequest()
|
476 |
476 |
self._ReadPostData()
|
477 |
477 |
self._HandleRequest()
|
478 |
|
except HTTPException, err:
|
|
478 |
except HttpException, err:
|
479 |
479 |
self._SetErrorStatus(err)
|
480 |
480 |
finally:
|
481 |
481 |
# Try to send a response
|
... | ... | |
501 |
501 |
(WEEKDAYNAME[wd], day, MONTHNAME[month], year, hh, mm, ss))
|
502 |
502 |
|
503 |
503 |
def _SetErrorStatus(self, err):
|
504 |
|
"""Sets the response code and body from a HTTPException.
|
|
504 |
"""Sets the response code and body from a HttpException.
|
505 |
505 |
|
506 |
|
@type err: HTTPException
|
|
506 |
@type err: HttpException
|
507 |
507 |
@param err: Exception instance
|
508 |
508 |
|
509 |
509 |
"""
|
... | ... | |
547 |
547 |
result = self._server.HandleRequest(self)
|
548 |
548 |
|
549 |
549 |
# TODO: Content-type
|
550 |
|
encoder = HTTPJsonConverter()
|
|
550 |
encoder = HttpJsonConverter()
|
551 |
551 |
body = encoder.Encode(result)
|
552 |
552 |
|
553 |
553 |
self.response_content_type = encoder.CONTENT_TYPE
|
554 |
554 |
self.response_body = body
|
555 |
|
except (HTTPException, KeyboardInterrupt, SystemExit):
|
|
555 |
except (HttpException, KeyboardInterrupt, SystemExit):
|
556 |
556 |
raise
|
557 |
557 |
except Exception, err:
|
558 |
558 |
logging.exception("Caught exception")
|
559 |
|
raise HTTPInternalError(message=str(err))
|
|
559 |
raise HttpInternalError(message=str(err))
|
560 |
560 |
except:
|
561 |
561 |
logging.exception("Unknown exception")
|
562 |
|
raise HTTPInternalError(message="Unknown error")
|
|
562 |
raise HttpInternalError(message="Unknown error")
|
563 |
563 |
|
564 |
|
except HTTPException, err:
|
|
564 |
except HttpException, err:
|
565 |
565 |
self._SetErrorStatus(err)
|
566 |
566 |
|
567 |
567 |
def _SendResponse(self):
|
... | ... | |
616 |
616 |
requestline = requestline[:-1]
|
617 |
617 |
|
618 |
618 |
if not requestline:
|
619 |
|
raise HTTPBadRequest("Empty request line")
|
|
619 |
raise HttpBadRequest("Empty request line")
|
620 |
620 |
|
621 |
621 |
self.request_requestline = requestline
|
622 |
622 |
|
... | ... | |
627 |
627 |
if len(words) == 3:
|
628 |
628 |
[method, path, version] = words
|
629 |
629 |
if version[:5] != 'HTTP/':
|
630 |
|
raise HTTPBadRequest("Bad request version (%r)" % version)
|
|
630 |
raise HttpBadRequest("Bad request version (%r)" % version)
|
631 |
631 |
|
632 |
632 |
try:
|
633 |
633 |
base_version_number = version.split('/', 1)[1]
|
... | ... | |
640 |
640 |
# turn is lower than HTTP/12.3;
|
641 |
641 |
# - Leading zeros MUST be ignored by recipients.
|
642 |
642 |
if len(version_number) != 2:
|
643 |
|
raise HTTPBadRequest("Bad request version (%r)" % version)
|
|
643 |
raise HttpBadRequest("Bad request version (%r)" % version)
|
644 |
644 |
|
645 |
645 |
version_number = int(version_number[0]), int(version_number[1])
|
646 |
646 |
except (ValueError, IndexError):
|
647 |
|
raise HTTPBadRequest("Bad request version (%r)" % version)
|
|
647 |
raise HttpBadRequest("Bad request version (%r)" % version)
|
648 |
648 |
|
649 |
649 |
if version_number >= (2, 0):
|
650 |
|
raise HTTPVersionNotSupported("Invalid HTTP Version (%s)" %
|
|
650 |
raise HttpVersionNotSupported("Invalid HTTP Version (%s)" %
|
651 |
651 |
base_version_number)
|
652 |
652 |
|
653 |
653 |
elif len(words) == 2:
|
654 |
654 |
version = HTTP_0_9
|
655 |
655 |
[method, path] = words
|
656 |
656 |
if method != HTTP_GET:
|
657 |
|
raise HTTPBadRequest("Bad HTTP/0.9 request type (%r)" % method)
|
|
657 |
raise HttpBadRequest("Bad HTTP/0.9 request type (%r)" % method)
|
658 |
658 |
|
659 |
659 |
else:
|
660 |
|
raise HTTPBadRequest("Bad request syntax (%r)" % requestline)
|
|
660 |
raise HttpBadRequest("Bad request syntax (%r)" % requestline)
|
661 |
661 |
|
662 |
662 |
# Examine the headers and look for a Connection directive
|
663 |
663 |
headers = mimetools.Message(self.rfile, 0)
|
... | ... | |
694 |
694 |
|
695 |
695 |
# 411 Length Required is specified in RFC2616, section 10.4.12 (HTTP/1.1)
|
696 |
696 |
if content_length is None:
|
697 |
|
raise HTTPLengthRequired("Missing Content-Length header or"
|
|
697 |
raise HttpLengthRequired("Missing Content-Length header or"
|
698 |
698 |
" invalid format")
|
699 |
699 |
|
700 |
700 |
data = self.rfile.read(content_length)
|
701 |
701 |
|
702 |
702 |
# TODO: Content-type, error handling
|
703 |
703 |
if data:
|
704 |
|
self.request_post_data = HTTPJsonConverter().Decode(data)
|
|
704 |
self.request_post_data = HttpJsonConverter().Decode(data)
|
705 |
705 |
else:
|
706 |
706 |
self.request_post_data = None
|
707 |
707 |
|