Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1""" 

2This module processes Python exceptions that relate to HTTP exceptions 

3by defining a set of exceptions, all subclasses of HTTPException. 

4Each exception, in addition to being a Python exception that can be 

5raised and caught, is also a WSGI application and ``webob.Response`` 

6object. 

7 

8This module defines exceptions according to RFC 2068 [1]_ : codes with 

9100-300 are not really errors; 400's are client errors, and 500's are 

10server errors. According to the WSGI specification [2]_ , the application 

11can call ``start_response`` more then once only under two conditions: 

12(a) the response has not yet been sent, or (b) if the second and 

13subsequent invocations of ``start_response`` have a valid ``exc_info`` 

14argument obtained from ``sys.exc_info()``. The WSGI specification then 

15requires the server or gateway to handle the case where content has been 

16sent and then an exception was encountered. 

17 

18Exception 

19 HTTPException 

20 HTTPOk 

21 * 200 - :class:`HTTPOk` 

22 * 201 - :class:`HTTPCreated` 

23 * 202 - :class:`HTTPAccepted` 

24 * 203 - :class:`HTTPNonAuthoritativeInformation` 

25 * 204 - :class:`HTTPNoContent` 

26 * 205 - :class:`HTTPResetContent` 

27 * 206 - :class:`HTTPPartialContent` 

28 HTTPRedirection 

29 * 300 - :class:`HTTPMultipleChoices` 

30 * 301 - :class:`HTTPMovedPermanently` 

31 * 302 - :class:`HTTPFound` 

32 * 303 - :class:`HTTPSeeOther` 

33 * 304 - :class:`HTTPNotModified` 

34 * 305 - :class:`HTTPUseProxy` 

35 * 307 - :class:`HTTPTemporaryRedirect` 

36 * 308 - :class:`HTTPPermanentRedirect` 

37 HTTPError 

38 HTTPClientError 

39 * 400 - :class:`HTTPBadRequest` 

40 * 401 - :class:`HTTPUnauthorized` 

41 * 402 - :class:`HTTPPaymentRequired` 

42 * 403 - :class:`HTTPForbidden` 

43 * 404 - :class:`HTTPNotFound` 

44 * 405 - :class:`HTTPMethodNotAllowed` 

45 * 406 - :class:`HTTPNotAcceptable` 

46 * 407 - :class:`HTTPProxyAuthenticationRequired` 

47 * 408 - :class:`HTTPRequestTimeout` 

48 * 409 - :class:`HTTPConflict` 

49 * 410 - :class:`HTTPGone` 

50 * 411 - :class:`HTTPLengthRequired` 

51 * 412 - :class:`HTTPPreconditionFailed` 

52 * 413 - :class:`HTTPRequestEntityTooLarge` 

53 * 414 - :class:`HTTPRequestURITooLong` 

54 * 415 - :class:`HTTPUnsupportedMediaType` 

55 * 416 - :class:`HTTPRequestRangeNotSatisfiable` 

56 * 417 - :class:`HTTPExpectationFailed` 

57 * 422 - :class:`HTTPUnprocessableEntity` 

58 * 423 - :class:`HTTPLocked` 

59 * 424 - :class:`HTTPFailedDependency` 

60 * 428 - :class:`HTTPPreconditionRequired` 

61 * 429 - :class:`HTTPTooManyRequests` 

62 * 431 - :class:`HTTPRequestHeaderFieldsTooLarge` 

63 * 451 - :class:`HTTPUnavailableForLegalReasons` 

64 HTTPServerError 

65 * 500 - :class:`HTTPInternalServerError` 

66 * 501 - :class:`HTTPNotImplemented` 

67 * 502 - :class:`HTTPBadGateway` 

68 * 503 - :class:`HTTPServiceUnavailable` 

69 * 504 - :class:`HTTPGatewayTimeout` 

70 * 505 - :class:`HTTPVersionNotSupported` 

71 * 511 - :class:`HTTPNetworkAuthenticationRequired` 

72 

73Usage notes 

74----------- 

75 

76The HTTPException class is complicated by 4 factors: 

77 

78 1. The content given to the exception may either be plain-text or 

79 as html-text. 

80 

81 2. The template may want to have string-substitutions taken from 

82 the current ``environ`` or values from incoming headers. This 

83 is especially troublesome due to case sensitivity. 

84 

85 3. The final output may either be text/plain or text/html 

86 mime-type as requested by the client application. 

87 

88 4. Each exception has a default explanation, but those who 

89 raise exceptions may want to provide additional detail. 

90 

91Subclass attributes and call parameters are designed to provide an easier path 

92through the complications. 

93 

94Attributes: 

95 

96 ``code`` 

97 the HTTP status code for the exception 

98 

99 ``title`` 

100 remainder of the status line (stuff after the code) 

101 

102 ``explanation`` 

103 a plain-text explanation of the error message that is 

104 not subject to environment or header substitutions; 

105 it is accessible in the template via %(explanation)s 

106 

107 ``detail`` 

108 a plain-text message customization that is not subject 

109 to environment or header substitutions; accessible in 

110 the template via %(detail)s 

111 

112 ``body_template`` 

113 a content fragment (in HTML) used for environment and 

114 header substitution; the default template includes both 

115 the explanation and further detail provided in the 

116 message 

117 

118Parameters: 

119 

120 ``detail`` 

121 a plain-text override of the default ``detail`` 

122 

123 ``headers`` 

124 a list of (k,v) header pairs 

125 

126 ``comment`` 

127 a plain-text additional information which is 

128 usually stripped/hidden for end-users 

129 

130 ``body_template`` 

131 a string.Template object containing a content fragment in HTML 

132 that frames the explanation and further detail 

133 

134To override the template (which is HTML content) or the plain-text 

135explanation, one must subclass the given exception; or customize it 

136after it has been created. This particular breakdown of a message 

137into explanation, detail and template allows both the creation of 

138plain-text and html messages for various clients as well as 

139error-free substitution of environment variables and headers. 

140 

141 

142The subclasses of :class:`~_HTTPMove` 

143(:class:`~HTTPMultipleChoices`, :class:`~HTTPMovedPermanently`, 

144:class:`~HTTPFound`, :class:`~HTTPSeeOther`, :class:`~HTTPUseProxy` and 

145:class:`~HTTPTemporaryRedirect`) are redirections that require a ``Location`` 

146field. Reflecting this, these subclasses have two additional keyword arguments: 

147``location`` and ``add_slash``. 

148 

149Parameters: 

150 

151 ``location`` 

152 to set the location immediately 

153 

154 ``add_slash`` 

155 set to True to redirect to the same URL as the request, except with a 

156 ``/`` appended 

157 

158Relative URLs in the location will be resolved to absolute. 

159 

160References: 

161 

162.. [1] https://www.python.org/dev/peps/pep-0333/#error-handling 

163.. [2] https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5 

164 

165 

166""" 

167 

168import json 

169from string import Template 

170import re 

171import sys 

172 

173from webob.acceptparse import create_accept_header 

174from webob.compat import ( 

175 class_types, 

176 text_, 

177 text_type, 

178 urlparse, 

179 ) 

180from webob.request import Request 

181from webob.response import Response 

182from webob.util import html_escape 

183 

184tag_re = re.compile(r'<.*?>', re.S) 

185br_re = re.compile(r'<br.*?>', re.I | re.S) 

186comment_re = re.compile(r'<!--|-->') 

187 

188class _lazified(object): 

189 def __init__(self, func, value): 

190 self.func = func 

191 self.value = value 

192 

193 def __str__(self): 

194 return self.func(self.value) 

195 

196def lazify(func): 

197 def wrapper(value): 

198 return _lazified(func, value) 

199 return wrapper 

200 

201def no_escape(value): 

202 if value is None: 

203 return '' 

204 if not isinstance(value, text_type): 

205 if hasattr(value, '__unicode__'): 

206 value = value.__unicode__() 

207 if isinstance(value, bytes): 

208 value = text_(value, 'utf-8') 

209 else: 

210 value = text_type(value) 

211 return value 

212 

213def strip_tags(value): 

214 value = value.replace('\n', ' ') 

215 value = value.replace('\r', '') 

216 value = br_re.sub('\n', value) 

217 value = comment_re.sub('', value) 

218 value = tag_re.sub('', value) 

219 return value 

220 

221class HTTPException(Exception): 

222 def __init__(self, message, wsgi_response): 

223 Exception.__init__(self, message) 

224 self.wsgi_response = wsgi_response 

225 

226 def __call__(self, environ, start_response): 

227 return self.wsgi_response(environ, start_response) 

228 

229class WSGIHTTPException(Response, HTTPException): 

230 

231 ## You should set in subclasses: 

232 # code = 200 

233 # title = 'OK' 

234 # explanation = 'why this happens' 

235 # body_template_obj = Template('response template') 

236 code = 500 

237 title = 'Internal Server Error' 

238 explanation = '' 

239 body_template_obj = Template('''\ 

240${explanation}<br /><br /> 

241${detail} 

242${html_comment} 

243''') 

244 

245 plain_template_obj = Template('''\ 

246${status} 

247 

248${body}''') 

249 

250 html_template_obj = Template('''\ 

251<html> 

252 <head> 

253 <title>${status}</title> 

254 </head> 

255 <body> 

256 <h1>${status}</h1> 

257 ${body} 

258 </body> 

259</html>''') 

260 

261 ## Set this to True for responses that should have no request body 

262 empty_body = False 

263 

264 def __init__(self, detail=None, headers=None, comment=None, 

265 body_template=None, json_formatter=None, **kw): 

266 Response.__init__(self, 

267 status='%s %s' % (self.code, self.title), 

268 **kw) 

269 Exception.__init__(self, detail) 

270 if headers: 

271 self.headers.extend(headers) 

272 self.detail = detail 

273 self.comment = comment 

274 if body_template is not None: 

275 self.body_template = body_template 

276 self.body_template_obj = Template(body_template) 

277 if self.empty_body: 

278 del self.content_type 

279 del self.content_length 

280 if json_formatter is not None: 

281 self.json_formatter = json_formatter 

282 

283 def __str__(self): 

284 return self.detail or self.explanation 

285 

286 def _make_body(self, environ, escape): 

287 escape = lazify(escape) 

288 args = { 

289 'explanation': escape(self.explanation), 

290 'detail': escape(self.detail or ''), 

291 'comment': escape(self.comment or ''), 

292 } 

293 if self.comment: 

294 args['html_comment'] = '<!-- %s -->' % escape(self.comment) 

295 else: 

296 args['html_comment'] = '' 

297 if WSGIHTTPException.body_template_obj is not self.body_template_obj: 

298 # Custom template; add headers to args 

299 for k, v in environ.items(): 

300 args[k] = escape(v) 

301 for k, v in self.headers.items(): 

302 args[k.lower()] = escape(v) 

303 t_obj = self.body_template_obj 

304 return t_obj.safe_substitute(args) 

305 

306 def plain_body(self, environ): 

307 body = self._make_body(environ, no_escape) 

308 body = strip_tags(body) 

309 return self.plain_template_obj.substitute(status=self.status, 

310 title=self.title, 

311 body=body) 

312 

313 def html_body(self, environ): 

314 body = self._make_body(environ, html_escape) 

315 return self.html_template_obj.substitute(status=self.status, 

316 body=body) 

317 

318 def json_formatter(self, body, status, title, environ): 

319 return {'message': body, 

320 'code': status, 

321 'title': title} 

322 

323 def json_body(self, environ): 

324 body = self._make_body(environ, no_escape) 

325 jsonbody = self.json_formatter(body=body, status=self.status, 

326 title=self.title, environ=environ) 

327 return json.dumps(jsonbody) 

328 

329 def generate_response(self, environ, start_response): 

330 if self.content_length is not None: 

331 del self.content_length 

332 headerlist = list(self.headerlist) 

333 accept_value = environ.get('HTTP_ACCEPT', '') 

334 accept_header = create_accept_header(header_value=accept_value) 

335 acceptable_offers = accept_header.acceptable_offers( 

336 offers=['text/html', 'application/json'], 

337 ) 

338 match = acceptable_offers[0][0] if acceptable_offers else None 

339 

340 if match == 'text/html': 

341 content_type = 'text/html' 

342 body = self.html_body(environ) 

343 elif match == 'application/json': 

344 content_type = 'application/json' 

345 body = self.json_body(environ) 

346 else: 

347 content_type = 'text/plain' 

348 body = self.plain_body(environ) 

349 resp = Response(body, 

350 status=self.status, 

351 headerlist=headerlist, 

352 content_type=content_type, 

353 ) 

354 resp.content_type = content_type 

355 return resp(environ, start_response) 

356 

357 def __call__(self, environ, start_response): 

358 is_head = environ['REQUEST_METHOD'] == 'HEAD' 

359 if self.has_body or self.empty_body or is_head: 

360 app_iter = Response.__call__(self, environ, start_response) 

361 else: 

362 app_iter = self.generate_response(environ, start_response) 

363 if is_head: 

364 app_iter = [] 

365 return app_iter 

366 

367 @property 

368 def wsgi_response(self): 

369 return self 

370 

371 

372 

373class HTTPError(WSGIHTTPException): 

374 """ 

375 base class for status codes in the 400's and 500's 

376 

377 This is an exception which indicates that an error has occurred, 

378 and that any work in progress should not be committed. These are 

379 typically results in the 400's and 500's. 

380 """ 

381 

382class HTTPRedirection(WSGIHTTPException): 

383 """ 

384 base class for 300's status code (redirections) 

385 

386 This is an abstract base class for 3xx redirection. It indicates 

387 that further action needs to be taken by the user agent in order 

388 to fulfill the request. It does not necessarly signal an error 

389 condition. 

390 """ 

391 

392class HTTPOk(WSGIHTTPException): 

393 """ 

394 Base class for the 200's status code (successful responses) 

395 

396 code: 200, title: OK 

397 """ 

398 code = 200 

399 title = 'OK' 

400 

401############################################################ 

402## 2xx success 

403############################################################ 

404 

405class HTTPCreated(HTTPOk): 

406 """ 

407 subclass of :class:`~HTTPOk` 

408 

409 This indicates that request has been fulfilled and resulted in a new 

410 resource being created. 

411 

412 code: 201, title: Created 

413 """ 

414 code = 201 

415 title = 'Created' 

416 

417class HTTPAccepted(HTTPOk): 

418 """ 

419 subclass of :class:`~HTTPOk` 

420 

421 This indicates that the request has been accepted for processing, but the 

422 processing has not been completed. 

423 

424 code: 202, title: Accepted 

425 """ 

426 code = 202 

427 title = 'Accepted' 

428 explanation = 'The request is accepted for processing.' 

429 

430class HTTPNonAuthoritativeInformation(HTTPOk): 

431 """ 

432 subclass of :class:`~HTTPOk` 

433 

434 This indicates that the returned metainformation in the entity-header is 

435 not the definitive set as available from the origin server, but is 

436 gathered from a local or a third-party copy. 

437 

438 code: 203, title: Non-Authoritative Information 

439 """ 

440 code = 203 

441 title = 'Non-Authoritative Information' 

442 

443class HTTPNoContent(HTTPOk): 

444 """ 

445 subclass of :class:`~HTTPOk` 

446 

447 This indicates that the server has fulfilled the request but does 

448 not need to return an entity-body, and might want to return updated 

449 metainformation. 

450 

451 code: 204, title: No Content 

452 """ 

453 code = 204 

454 title = 'No Content' 

455 empty_body = True 

456 

457class HTTPResetContent(HTTPOk): 

458 """ 

459 subclass of :class:`~HTTPOk` 

460 

461 This indicates that the the server has fulfilled the request and 

462 the user agent SHOULD reset the document view which caused the 

463 request to be sent. 

464 

465 code: 205, title: Reset Content 

466 """ 

467 code = 205 

468 title = 'Reset Content' 

469 empty_body = True 

470 

471class HTTPPartialContent(HTTPOk): 

472 """ 

473 subclass of :class:`~HTTPOk` 

474 

475 This indicates that the server has fulfilled the partial GET 

476 request for the resource. 

477 

478 code: 206, title: Partial Content 

479 """ 

480 code = 206 

481 title = 'Partial Content' 

482 

483############################################################ 

484## 3xx redirection 

485############################################################ 

486 

487class _HTTPMove(HTTPRedirection): 

488 """ 

489 redirections which require a Location field 

490 

491 Since a 'Location' header is a required attribute of 301, 302, 303, 

492 305, 307 and 308 (but not 304), this base class provides the mechanics to 

493 make this easy. 

494 

495 You can provide a location keyword argument to set the location 

496 immediately. You may also give ``add_slash=True`` if you want to 

497 redirect to the same URL as the request, except with a ``/`` added 

498 to the end. 

499 

500 Relative URLs in the location will be resolved to absolute. 

501 """ 

502 explanation = 'The resource has been moved to' 

503 body_template_obj = Template('''\ 

504${explanation} <a href="${location}">${location}</a>; 

505you should be redirected automatically. 

506${detail} 

507${html_comment}''') 

508 

509 def __init__(self, detail=None, headers=None, comment=None, 

510 body_template=None, location=None, add_slash=False): 

511 super(_HTTPMove, self).__init__( 

512 detail=detail, headers=headers, comment=comment, 

513 body_template=body_template) 

514 if location is not None: 

515 if '\n' in location or '\r' in location: 

516 raise ValueError('Control characters are not allowed in location') 

517 

518 self.location = location 

519 if add_slash: 

520 raise TypeError( 

521 "You can only provide one of the arguments location " 

522 "and add_slash") 

523 self.add_slash = add_slash 

524 

525 def __call__(self, environ, start_response): 

526 req = Request(environ) 

527 if self.add_slash: 

528 url = req.path_url 

529 url += '/' 

530 if req.environ.get('QUERY_STRING'): 

531 url += '?' + req.environ['QUERY_STRING'] 

532 self.location = url 

533 self.location = urlparse.urljoin(req.path_url, self.location) 

534 return super(_HTTPMove, self).__call__( 

535 environ, start_response) 

536 

537class HTTPMultipleChoices(_HTTPMove): 

538 """ 

539 subclass of :class:`~_HTTPMove` 

540 

541 This indicates that the requested resource corresponds to any one 

542 of a set of representations, each with its own specific location, 

543 and agent-driven negotiation information is being provided so that 

544 the user can select a preferred representation and redirect its 

545 request to that location. 

546 

547 code: 300, title: Multiple Choices 

548 """ 

549 code = 300 

550 title = 'Multiple Choices' 

551 

552class HTTPMovedPermanently(_HTTPMove): 

553 """ 

554 subclass of :class:`~_HTTPMove` 

555 

556 This indicates that the requested resource has been assigned a new 

557 permanent URI and any future references to this resource SHOULD use 

558 one of the returned URIs. 

559 

560 code: 301, title: Moved Permanently 

561 """ 

562 code = 301 

563 title = 'Moved Permanently' 

564 

565class HTTPFound(_HTTPMove): 

566 """ 

567 subclass of :class:`~_HTTPMove` 

568 

569 This indicates that the requested resource resides temporarily under 

570 a different URI. 

571 

572 code: 302, title: Found 

573 """ 

574 code = 302 

575 title = 'Found' 

576 explanation = 'The resource was found at' 

577 

578# This one is safe after a POST (the redirected location will be 

579# retrieved with GET): 

580class HTTPSeeOther(_HTTPMove): 

581 """ 

582 subclass of :class:`~_HTTPMove` 

583 

584 This indicates that the response to the request can be found under 

585 a different URI and SHOULD be retrieved using a GET method on that 

586 resource. 

587 

588 code: 303, title: See Other 

589 """ 

590 code = 303 

591 title = 'See Other' 

592 

593class HTTPNotModified(HTTPRedirection): 

594 """ 

595 subclass of :class:`~HTTPRedirection` 

596 

597 This indicates that if the client has performed a conditional GET 

598 request and access is allowed, but the document has not been 

599 modified, the server SHOULD respond with this status code. 

600 

601 code: 304, title: Not Modified 

602 """ 

603 # TODO: this should include a date or etag header 

604 code = 304 

605 title = 'Not Modified' 

606 empty_body = True 

607 

608class HTTPUseProxy(_HTTPMove): 

609 """ 

610 subclass of :class:`~_HTTPMove` 

611 

612 This indicates that the requested resource MUST be accessed through 

613 the proxy given by the Location field. 

614 

615 code: 305, title: Use Proxy 

616 """ 

617 # Not a move, but looks a little like one 

618 code = 305 

619 title = 'Use Proxy' 

620 explanation = ( 

621 'The resource must be accessed through a proxy located at') 

622 

623class HTTPTemporaryRedirect(_HTTPMove): 

624 """ 

625 subclass of :class:`~_HTTPMove` 

626 

627 This indicates that the requested resource resides temporarily 

628 under a different URI. 

629 

630 code: 307, title: Temporary Redirect 

631 """ 

632 code = 307 

633 title = 'Temporary Redirect' 

634 

635class HTTPPermanentRedirect(_HTTPMove): 

636 """ 

637 subclass of :class:`~_HTTPMove` 

638 

639 This indicates that the requested resource resides permanently 

640 under a different URI. 

641 

642 code: 308, title: Permanent Redirect 

643 """ 

644 code = 308 

645 title = 'Permanent Redirect' 

646 

647 

648############################################################ 

649## 4xx client error 

650############################################################ 

651 

652class HTTPClientError(HTTPError): 

653 """ 

654 base class for the 400's, where the client is in error 

655 

656 This is an error condition in which the client is presumed to be 

657 in-error. This is an expected problem, and thus is not considered 

658 a bug. A server-side traceback is not warranted. Unless specialized, 

659 this is a '400 Bad Request' 

660 

661 code: 400, title: Bad Request 

662 """ 

663 code = 400 

664 title = 'Bad Request' 

665 explanation = ('The server could not comply with the request since\r\n' 

666 'it is either malformed or otherwise incorrect.\r\n') 

667 

668class HTTPBadRequest(HTTPClientError): 

669 pass 

670 

671class HTTPUnauthorized(HTTPClientError): 

672 """ 

673 subclass of :class:`~HTTPClientError` 

674 

675 This indicates that the request requires user authentication. 

676 

677 code: 401, title: Unauthorized 

678 """ 

679 code = 401 

680 title = 'Unauthorized' 

681 explanation = ( 

682 'This server could not verify that you are authorized to\r\n' 

683 'access the document you requested. Either you supplied the\r\n' 

684 'wrong credentials (e.g., bad password), or your browser\r\n' 

685 'does not understand how to supply the credentials required.\r\n') 

686 

687class HTTPPaymentRequired(HTTPClientError): 

688 """ 

689 subclass of :class:`~HTTPClientError` 

690 

691 code: 402, title: Payment Required 

692 """ 

693 code = 402 

694 title = 'Payment Required' 

695 explanation = ('Access was denied for financial reasons.') 

696 

697class HTTPForbidden(HTTPClientError): 

698 """ 

699 subclass of :class:`~HTTPClientError` 

700 

701 This indicates that the server understood the request, but is 

702 refusing to fulfill it. 

703 

704 code: 403, title: Forbidden 

705 """ 

706 code = 403 

707 title = 'Forbidden' 

708 explanation = ('Access was denied to this resource.') 

709 

710class HTTPNotFound(HTTPClientError): 

711 """ 

712 subclass of :class:`~HTTPClientError` 

713 

714 This indicates that the server did not find anything matching the 

715 Request-URI. 

716 

717 code: 404, title: Not Found 

718 """ 

719 code = 404 

720 title = 'Not Found' 

721 explanation = ('The resource could not be found.') 

722 

723class HTTPMethodNotAllowed(HTTPClientError): 

724 """ 

725 subclass of :class:`~HTTPClientError` 

726 

727 This indicates that the method specified in the Request-Line is 

728 not allowed for the resource identified by the Request-URI. 

729 

730 code: 405, title: Method Not Allowed 

731 """ 

732 code = 405 

733 title = 'Method Not Allowed' 

734 # override template since we need an environment variable 

735 body_template_obj = Template('''\ 

736The method ${REQUEST_METHOD} is not allowed for this resource. <br /><br /> 

737${detail}''') 

738 

739class HTTPNotAcceptable(HTTPClientError): 

740 """ 

741 subclass of :class:`~HTTPClientError` 

742 

743 This indicates the resource identified by the request is only 

744 capable of generating response entities which have content 

745 characteristics not acceptable according to the accept headers 

746 sent in the request. 

747 

748 code: 406, title: Not Acceptable 

749 """ 

750 code = 406 

751 title = 'Not Acceptable' 

752 # override template since we need an environment variable 

753 body_template_obj = Template('''\ 

754The resource could not be generated that was acceptable to your browser 

755(content of type ${HTTP_ACCEPT}. <br /><br /> 

756${detail}''') 

757 

758class HTTPProxyAuthenticationRequired(HTTPClientError): 

759 """ 

760 subclass of :class:`~HTTPClientError` 

761 

762 This is similar to 401, but indicates that the client must first 

763 authenticate itself with the proxy. 

764 

765 code: 407, title: Proxy Authentication Required 

766 """ 

767 code = 407 

768 title = 'Proxy Authentication Required' 

769 explanation = ('Authentication with a local proxy is needed.') 

770 

771class HTTPRequestTimeout(HTTPClientError): 

772 """ 

773 subclass of :class:`~HTTPClientError` 

774 

775 This indicates that the client did not produce a request within 

776 the time that the server was prepared to wait. 

777 

778 code: 408, title: Request Timeout 

779 """ 

780 code = 408 

781 title = 'Request Timeout' 

782 explanation = ('The server has waited too long for the request to ' 

783 'be sent by the client.') 

784 

785class HTTPConflict(HTTPClientError): 

786 """ 

787 subclass of :class:`~HTTPClientError` 

788 

789 This indicates that the request could not be completed due to a 

790 conflict with the current state of the resource. 

791 

792 code: 409, title: Conflict 

793 """ 

794 code = 409 

795 title = 'Conflict' 

796 explanation = ('There was a conflict when trying to complete ' 

797 'your request.') 

798 

799class HTTPGone(HTTPClientError): 

800 """ 

801 subclass of :class:`~HTTPClientError` 

802 

803 This indicates that the requested resource is no longer available 

804 at the server and no forwarding address is known. 

805 

806 code: 410, title: Gone 

807 """ 

808 code = 410 

809 title = 'Gone' 

810 explanation = ('This resource is no longer available. No forwarding ' 

811 'address is given.') 

812 

813class HTTPLengthRequired(HTTPClientError): 

814 """ 

815 subclass of :class:`~HTTPClientError` 

816 

817 This indicates that the the server refuses to accept the request 

818 without a defined Content-Length. 

819 

820 code: 411, title: Length Required 

821 """ 

822 code = 411 

823 title = 'Length Required' 

824 explanation = ('Content-Length header required.') 

825 

826class HTTPPreconditionFailed(HTTPClientError): 

827 """ 

828 subclass of :class:`~HTTPClientError` 

829 

830 This indicates that the precondition given in one or more of the 

831 request-header fields evaluated to false when it was tested on the 

832 server. 

833 

834 code: 412, title: Precondition Failed 

835 """ 

836 code = 412 

837 title = 'Precondition Failed' 

838 explanation = ('Request precondition failed.') 

839 

840class HTTPRequestEntityTooLarge(HTTPClientError): 

841 """ 

842 subclass of :class:`~HTTPClientError` 

843 

844 This indicates that the server is refusing to process a request 

845 because the request entity is larger than the server is willing or 

846 able to process. 

847 

848 code: 413, title: Request Entity Too Large 

849 """ 

850 code = 413 

851 title = 'Request Entity Too Large' 

852 explanation = ('The body of your request was too large for this server.') 

853 

854class HTTPRequestURITooLong(HTTPClientError): 

855 """ 

856 subclass of :class:`~HTTPClientError` 

857 

858 This indicates that the server is refusing to service the request 

859 because the Request-URI is longer than the server is willing to 

860 interpret. 

861 

862 code: 414, title: Request-URI Too Long 

863 """ 

864 code = 414 

865 title = 'Request-URI Too Long' 

866 explanation = ('The request URI was too long for this server.') 

867 

868class HTTPUnsupportedMediaType(HTTPClientError): 

869 """ 

870 subclass of :class:`~HTTPClientError` 

871 

872 This indicates that the server is refusing to service the request 

873 because the entity of the request is in a format not supported by 

874 the requested resource for the requested method. 

875 

876 code: 415, title: Unsupported Media Type 

877 """ 

878 code = 415 

879 title = 'Unsupported Media Type' 

880 # override template since we need an environment variable 

881 body_template_obj = Template('''\ 

882The request media type ${CONTENT_TYPE} is not supported by this server. 

883<br /><br /> 

884${detail}''') 

885 

886class HTTPRequestRangeNotSatisfiable(HTTPClientError): 

887 """ 

888 subclass of :class:`~HTTPClientError` 

889 

890 The server SHOULD return a response with this status code if a 

891 request included a Range request-header field, and none of the 

892 range-specifier values in this field overlap the current extent 

893 of the selected resource, and the request did not include an 

894 If-Range request-header field. 

895 

896 code: 416, title: Request Range Not Satisfiable 

897 """ 

898 code = 416 

899 title = 'Request Range Not Satisfiable' 

900 explanation = ('The Range requested is not available.') 

901 

902class HTTPExpectationFailed(HTTPClientError): 

903 """ 

904 subclass of :class:`~HTTPClientError` 

905 

906 This indidcates that the expectation given in an Expect 

907 request-header field could not be met by this server. 

908 

909 code: 417, title: Expectation Failed 

910 """ 

911 code = 417 

912 title = 'Expectation Failed' 

913 explanation = ('Expectation failed.') 

914 

915class HTTPUnprocessableEntity(HTTPClientError): 

916 """ 

917 subclass of :class:`~HTTPClientError` 

918 

919 This indicates that the server is unable to process the contained 

920 instructions. 

921 

922 code: 422, title: Unprocessable Entity 

923 """ 

924 ## Note: from WebDAV 

925 code = 422 

926 title = 'Unprocessable Entity' 

927 explanation = 'Unable to process the contained instructions' 

928 

929class HTTPLocked(HTTPClientError): 

930 """ 

931 subclass of :class:`~HTTPClientError` 

932 

933 This indicates that the resource is locked. 

934 

935 code: 423, title: Locked 

936 """ 

937 ## Note: from WebDAV 

938 code = 423 

939 title = 'Locked' 

940 explanation = ('The resource is locked') 

941 

942class HTTPFailedDependency(HTTPClientError): 

943 """ 

944 subclass of :class:`~HTTPClientError` 

945 

946 This indicates that the method could not be performed because the 

947 requested action depended on another action and that action failed. 

948 

949 code: 424, title: Failed Dependency 

950 """ 

951 ## Note: from WebDAV 

952 code = 424 

953 title = 'Failed Dependency' 

954 explanation = ( 

955 'The method could not be performed because the requested ' 

956 'action dependended on another action and that action failed') 

957 

958class HTTPPreconditionRequired(HTTPClientError): 

959 """ 

960 subclass of :class:`~HTTPClientError` 

961 

962 This indicates that the origin server requires the request to be 

963 conditional. From RFC 6585, "Additional HTTP Status Codes". 

964 

965 code: 428, title: Precondition Required 

966 """ 

967 code = 428 

968 title = 'Precondition Required' 

969 explanation = ('This request is required to be conditional') 

970 

971class HTTPTooManyRequests(HTTPClientError): 

972 """ 

973 subclass of :class:`~HTTPClientError` 

974 

975 This indicates that the client has sent too many requests in a 

976 given amount of time. Useful for rate limiting. 

977 

978 From RFC 6585, "Additional HTTP Status Codes". 

979 

980 code: 429, title: Too Many Requests 

981 """ 

982 code = 429 

983 title = 'Too Many Requests' 

984 explanation = ( 

985 'The client has sent too many requests in a given amount of time') 

986 

987class HTTPRequestHeaderFieldsTooLarge(HTTPClientError): 

988 """ 

989 subclass of :class:`~HTTPClientError` 

990 

991 This indicates that the server is unwilling to process the request 

992 because its header fields are too large. The request may be resubmitted 

993 after reducing the size of the request header fields. 

994 

995 From RFC 6585, "Additional HTTP Status Codes". 

996 

997 code: 431, title: Request Header Fields Too Large 

998 """ 

999 code = 431 

1000 title = 'Request Header Fields Too Large' 

1001 explanation = ( 

1002 'The request header fields were too large') 

1003 

1004class HTTPUnavailableForLegalReasons(HTTPClientError): 

1005 """ 

1006 subclass of :class:`~HTTPClientError` 

1007 

1008 This indicates that the server is unable to process the request 

1009 because of legal reasons, e.g. censorship or government-mandated 

1010 blocked access. 

1011 

1012 From the draft "A New HTTP Status Code for Legally-restricted Resources" 

1013 by Tim Bray: 

1014 

1015 https://tools.ietf.org/html/draft-tbray-http-legally-restricted-status-00 

1016 

1017 code: 451, title: Unavailable For Legal Reasons 

1018 """ 

1019 code = 451 

1020 title = 'Unavailable For Legal Reasons' 

1021 explanation = ('The resource is not available due to legal reasons.') 

1022 

1023############################################################ 

1024## 5xx Server Error 

1025############################################################ 

1026# Response status codes beginning with the digit "5" indicate cases in 

1027# which the server is aware that it has erred or is incapable of 

1028# performing the request. Except when responding to a HEAD request, the 

1029# server SHOULD include an entity containing an explanation of the error 

1030# situation, and whether it is a temporary or permanent condition. User 

1031# agents SHOULD display any included entity to the user. These response 

1032# codes are applicable to any request method. 

1033 

1034class HTTPServerError(HTTPError): 

1035 """ 

1036 base class for the 500's, where the server is in-error 

1037 

1038 This is an error condition in which the server is presumed to be 

1039 in-error. This is usually unexpected, and thus requires a traceback; 

1040 ideally, opening a support ticket for the customer. Unless specialized, 

1041 this is a '500 Internal Server Error' 

1042 """ 

1043 code = 500 

1044 title = 'Internal Server Error' 

1045 explanation = ( 

1046 'The server has either erred or is incapable of performing\r\n' 

1047 'the requested operation.\r\n') 

1048 

1049class HTTPInternalServerError(HTTPServerError): 

1050 pass 

1051 

1052class HTTPNotImplemented(HTTPServerError): 

1053 """ 

1054 subclass of :class:`~HTTPServerError` 

1055 

1056 This indicates that the server does not support the functionality 

1057 required to fulfill the request. 

1058 

1059 code: 501, title: Not Implemented 

1060 """ 

1061 code = 501 

1062 title = 'Not Implemented' 

1063 body_template_obj = Template(''' 

1064The request method ${REQUEST_METHOD} is not implemented for this server. <br /><br /> 

1065${detail}''') 

1066 

1067class HTTPBadGateway(HTTPServerError): 

1068 """ 

1069 subclass of :class:`~HTTPServerError` 

1070 

1071 This indicates that the server, while acting as a gateway or proxy, 

1072 received an invalid response from the upstream server it accessed 

1073 in attempting to fulfill the request. 

1074 

1075 code: 502, title: Bad Gateway 

1076 """ 

1077 code = 502 

1078 title = 'Bad Gateway' 

1079 explanation = ('Bad gateway.') 

1080 

1081class HTTPServiceUnavailable(HTTPServerError): 

1082 """ 

1083 subclass of :class:`~HTTPServerError` 

1084 

1085 This indicates that the server is currently unable to handle the 

1086 request due to a temporary overloading or maintenance of the server. 

1087 

1088 code: 503, title: Service Unavailable 

1089 """ 

1090 code = 503 

1091 title = 'Service Unavailable' 

1092 explanation = ('The server is currently unavailable. ' 

1093 'Please try again at a later time.') 

1094 

1095class HTTPGatewayTimeout(HTTPServerError): 

1096 """ 

1097 subclass of :class:`~HTTPServerError` 

1098 

1099 This indicates that the server, while acting as a gateway or proxy, 

1100 did not receive a timely response from the upstream server specified 

1101 by the URI (e.g. HTTP, FTP, LDAP) or some other auxiliary server 

1102 (e.g. DNS) it needed to access in attempting to complete the request. 

1103 

1104 code: 504, title: Gateway Timeout 

1105 """ 

1106 code = 504 

1107 title = 'Gateway Timeout' 

1108 explanation = ('The gateway has timed out.') 

1109 

1110class HTTPVersionNotSupported(HTTPServerError): 

1111 """ 

1112 subclass of :class:`~HTTPServerError` 

1113 

1114 This indicates that the server does not support, or refuses to 

1115 support, the HTTP protocol version that was used in the request 

1116 message. 

1117 

1118 code: 505, title: HTTP Version Not Supported 

1119 """ 

1120 code = 505 

1121 title = 'HTTP Version Not Supported' 

1122 explanation = ('The HTTP version is not supported.') 

1123 

1124class HTTPInsufficientStorage(HTTPServerError): 

1125 """ 

1126 subclass of :class:`~HTTPServerError` 

1127 

1128 This indicates that the server does not have enough space to save 

1129 the resource. 

1130 

1131 code: 507, title: Insufficient Storage 

1132 """ 

1133 code = 507 

1134 title = 'Insufficient Storage' 

1135 explanation = ('There was not enough space to save the resource') 

1136 

1137class HTTPNetworkAuthenticationRequired(HTTPServerError): 

1138 """ 

1139 subclass of :class:`~HTTPServerError` 

1140 

1141 This indicates that the client needs to authenticate to gain 

1142 network access. From RFC 6585, "Additional HTTP Status Codes". 

1143 

1144 code: 511, title: Network Authentication Required 

1145 """ 

1146 code = 511 

1147 title = 'Network Authentication Required' 

1148 explanation = ('Network authentication is required') 

1149 

1150class HTTPExceptionMiddleware(object): 

1151 """ 

1152 Middleware that catches exceptions in the sub-application. This 

1153 does not catch exceptions in the app_iter; only during the initial 

1154 calling of the application. 

1155 

1156 This should be put *very close* to applications that might raise 

1157 these exceptions. This should not be applied globally; letting 

1158 *expected* exceptions raise through the WSGI stack is dangerous. 

1159 """ 

1160 

1161 def __init__(self, application): 

1162 self.application = application 

1163 def __call__(self, environ, start_response): 

1164 try: 

1165 return self.application(environ, start_response) 

1166 except HTTPException: 

1167 parent_exc_info = sys.exc_info() 

1168 def repl_start_response(status, headers, exc_info=None): 

1169 if exc_info is None: 

1170 exc_info = parent_exc_info 

1171 return start_response(status, headers, exc_info) 

1172 return parent_exc_info[1](environ, repl_start_response) 

1173 

1174try: 

1175 from paste import httpexceptions 

1176except ImportError: # pragma: no cover 

1177 # Without Paste we don't need to do this fixup 

1178 pass 

1179else: # pragma: no cover 

1180 for name in dir(httpexceptions): 

1181 obj = globals().get(name) 

1182 if (obj and isinstance(obj, type) and issubclass(obj, HTTPException) 

1183 and obj is not HTTPException 

1184 and obj is not WSGIHTTPException): 

1185 obj.__bases__ = obj.__bases__ + (getattr(httpexceptions, name),) 

1186 del name, obj, httpexceptions 

1187 

1188__all__ = ['HTTPExceptionMiddleware', 'status_map'] 

1189status_map={} 

1190for name, value in list(globals().items()): 

1191 if (isinstance(value, (type, class_types)) and 

1192 issubclass(value, HTTPException) 

1193 and not name.startswith('_')): 

1194 __all__.append(name) 

1195 if all(( 

1196 getattr(value, 'code', None), 

1197 value not in (HTTPRedirection, HTTPClientError, HTTPServerError), 

1198 issubclass( 

1199 value, 

1200 (HTTPOk, HTTPRedirection, HTTPClientError, HTTPServerError) 

1201 ) 

1202 )): 

1203 status_map[value.code]=value 

1204 if hasattr(value, 'explanation'): 

1205 value.explanation = ' '.join(value.explanation.strip().split()) 

1206del name, value