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""" 

2HTTP Exceptions 

3--------------- 

4 

5This module contains Pyramid HTTP exception classes. Each class relates to a 

6single HTTP status code. Each class is a subclass of the 

7:class:`~HTTPException`. Each exception class is also a :term:`response` 

8object. 

9 

10Each exception class has a status code according to :rfc:`2068` or :rfc:`7538`: 

11codes with 100-300 are not really errors; 400s are client errors, 

12and 500s are server errors. 

13 

14Exception 

15 HTTPException 

16 HTTPSuccessful 

17 * 200 - HTTPOk 

18 * 201 - HTTPCreated 

19 * 202 - HTTPAccepted 

20 * 203 - HTTPNonAuthoritativeInformation 

21 * 204 - HTTPNoContent 

22 * 205 - HTTPResetContent 

23 * 206 - HTTPPartialContent 

24 HTTPRedirection 

25 * 300 - HTTPMultipleChoices 

26 * 301 - HTTPMovedPermanently 

27 * 302 - HTTPFound 

28 * 303 - HTTPSeeOther 

29 * 304 - HTTPNotModified 

30 * 305 - HTTPUseProxy 

31 * 307 - HTTPTemporaryRedirect 

32 * 308 - HTTPPermanentRedirect 

33 HTTPError 

34 HTTPClientError 

35 * 400 - HTTPBadRequest 

36 * 401 - HTTPUnauthorized 

37 * 402 - HTTPPaymentRequired 

38 * 403 - HTTPForbidden 

39 * 404 - HTTPNotFound 

40 * 405 - HTTPMethodNotAllowed 

41 * 406 - HTTPNotAcceptable 

42 * 407 - HTTPProxyAuthenticationRequired 

43 * 408 - HTTPRequestTimeout 

44 * 409 - HTTPConflict 

45 * 410 - HTTPGone 

46 * 411 - HTTPLengthRequired 

47 * 412 - HTTPPreconditionFailed 

48 * 413 - HTTPRequestEntityTooLarge 

49 * 414 - HTTPRequestURITooLong 

50 * 415 - HTTPUnsupportedMediaType 

51 * 416 - HTTPRequestRangeNotSatisfiable 

52 * 417 - HTTPExpectationFailed 

53 * 422 - HTTPUnprocessableEntity 

54 * 423 - HTTPLocked 

55 * 424 - HTTPFailedDependency 

56 * 428 - HTTPPreconditionRequired 

57 * 429 - HTTPTooManyRequests 

58 * 431 - HTTPRequestHeaderFieldsTooLarge 

59 HTTPServerError 

60 * 500 - HTTPInternalServerError 

61 * 501 - HTTPNotImplemented 

62 * 502 - HTTPBadGateway 

63 * 503 - HTTPServiceUnavailable 

64 * 504 - HTTPGatewayTimeout 

65 * 505 - HTTPVersionNotSupported 

66 * 507 - HTTPInsufficientStorage 

67 

68HTTP exceptions are also :term:`response` objects, thus they accept most of 

69the same parameters that can be passed to a regular 

70:class:`~pyramid.response.Response`. Each HTTP exception also has the 

71following attributes: 

72 

73 ``code`` 

74 the HTTP status code for the exception 

75 

76 ``title`` 

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

78 

79 ``explanation`` 

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

81 not subject to environment or header substitutions; 

82 it is accessible in the template via ${explanation} 

83 

84 ``detail`` 

85 a plain-text message customization that is not subject 

86 to environment or header substitutions; accessible in 

87 the template via ${detail} 

88 

89 ``body_template`` 

90 a ``String.template``-format content fragment used for environment 

91 and header substitution; the default template includes both 

92 the explanation and further detail provided in the 

93 message. 

94 

95Each HTTP exception accepts the following parameters, any others will 

96be forwarded to its :class:`~pyramid.response.Response` superclass: 

97 

98 ``detail`` 

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

100 

101 ``headers`` 

102 a list of (k,v) header pairs, or a dict, to be added to the 

103 response; use the content_type='application/json' kwarg and other 

104 similar kwargs to to change properties of the response supported by the 

105 :class:`pyramid.response.Response` superclass 

106 

107 ``comment`` 

108 a plain-text additional information which is 

109 usually stripped/hidden for end-users 

110 

111 ``body_template`` 

112 a ``string.Template`` object containing a content fragment in HTML 

113 that frames the explanation and further detail 

114 

115 ``body`` 

116 a string that will override the ``body_template`` and be used as the 

117 body of the response. 

118 

119Substitution of response headers into template values is always performed. 

120Substitution of WSGI environment values is performed if a ``request`` is 

121passed to the exception's constructor. 

122 

123The subclasses of :class:`~_HTTPMove` 

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

125:class:`~HTTPFound`, :class:`~HTTPSeeOther`, :class:`~HTTPUseProxy`, 

126:class:`~HTTPTemporaryRedirect`, and :class: `~HTTPPermanentRedirect) are 

127redirections that require a ``Location`` field. Reflecting this, these 

128subclasses have one additional keyword argument: ``location``, 

129which indicates the location to which to redirect. 

130""" 

131import json 

132 

133from string import Template 

134 

135from zope.interface import implementer 

136 

137from webob import html_escape as _html_escape 

138from webob.acceptparse import create_accept_header 

139 

140from pyramid.compat import class_types, text_type, binary_type, text_ 

141 

142from pyramid.interfaces import IExceptionResponse 

143from pyramid.response import Response 

144 

145 

146def _no_escape(value): 

147 if value is None: 

148 return '' 

149 if not isinstance(value, text_type): 

150 if hasattr(value, '__unicode__'): 

151 value = value.__unicode__() 

152 if isinstance(value, binary_type): 

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

154 else: 

155 value = text_type(value) 

156 return value 

157 

158 

159@implementer(IExceptionResponse) 

160class HTTPException(Response, Exception): 

161 # You should set in subclasses: 

162 # code = 200 

163 # title = 'OK' 

164 # explanation = 'why this happens' 

165 # body_template_obj = Template('response template') 

166 # 

167 # This class itself uses the error code "520" with the error message/title 

168 # of "Unknown Error". This is not an RFC standard, however it is 

169 # implemented in practice. Sub-classes should be overriding the default 

170 # values and 520 should not be seen in the wild from Pyramid applications. 

171 # Due to changes in WebOb, a code of "None" is not valid, and WebOb due to 

172 # more strict error checking rejects it now. 

173 

174 # differences from webob.exc.WSGIHTTPException: 

175 # 

176 # - doesn't use "strip_tags" (${br} placeholder for <br/>, no other html 

177 # in default body template) 

178 # 

179 # - __call__ never generates a new Response, it always mutates self 

180 # 

181 # - explicitly sets self.message = detail to prevent whining by Python 

182 # 2.6.5+ access of Exception.message 

183 # 

184 # - its base class of HTTPException is no longer a Python 2.4 compatibility 

185 # shim; it's purely a base class that inherits from Exception. This 

186 # implies that this class' ``exception`` property always returns 

187 # ``self`` (it exists only for bw compat at this point). 

188 # 

189 # - documentation improvements (Pyramid-specific docstrings where 

190 # necessary) 

191 # 

192 code = 520 

193 title = 'Unknown Error' 

194 explanation = '' 

195 body_template_obj = Template( 

196 '''\ 

197${explanation}${br}${br} 

198${detail} 

199${html_comment} 

200''' 

201 ) 

202 

203 plain_template_obj = Template( 

204 '''\ 

205${status} 

206 

207${body}''' 

208 ) 

209 

210 html_template_obj = Template( 

211 '''\ 

212<html> 

213 <head> 

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

215 </head> 

216 <body> 

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

218 ${body} 

219 </body> 

220</html>''' 

221 ) 

222 

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

224 empty_body = False 

225 

226 def __init__( 

227 self, 

228 detail=None, 

229 headers=None, 

230 comment=None, 

231 body_template=None, 

232 json_formatter=None, 

233 **kw 

234 ): 

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

236 Response.__init__(self, status=status, **kw) 

237 Exception.__init__(self, detail) 

238 self.detail = self.message = detail 

239 if headers: 

240 self.headers.extend(headers) 

241 self.comment = comment 

242 if body_template is not None: 

243 self.body_template = body_template 

244 self.body_template_obj = Template(body_template) 

245 if json_formatter is not None: 

246 self._json_formatter = json_formatter 

247 

248 if self.empty_body: 

249 del self.content_type 

250 del self.content_length 

251 

252 def __str__(self): 

253 return str(self.detail) if self.detail else self.explanation 

254 

255 def _json_formatter(self, status, body, title, environ): 

256 return {'message': body, 'code': status, 'title': self.title} 

257 

258 def prepare(self, environ): 

259 if not self.has_body and not self.empty_body: 

260 html_comment = '' 

261 comment = self.comment or '' 

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

263 accept = create_accept_header(accept_value) 

264 # Attempt to match text/html or application/json, if those don't 

265 # match, we will fall through to defaulting to text/plain 

266 acceptable = accept.acceptable_offers( 

267 ['text/html', 'application/json'] 

268 ) 

269 acceptable = [offer[0] for offer in acceptable] + ['text/plain'] 

270 match = acceptable[0] 

271 

272 if match == 'text/html': 

273 self.content_type = 'text/html' 

274 escape = _html_escape 

275 page_template = self.html_template_obj 

276 br = '<br/>' 

277 if comment: 

278 html_comment = '<!-- %s -->' % escape(comment) 

279 elif match == 'application/json': 

280 self.content_type = 'application/json' 

281 self.charset = None 

282 escape = _no_escape 

283 br = '\n' 

284 if comment: 

285 html_comment = escape(comment) 

286 

287 class JsonPageTemplate(object): 

288 def __init__(self, excobj): 

289 self.excobj = excobj 

290 

291 def substitute(self, status, body): 

292 jsonbody = self.excobj._json_formatter( 

293 status=status, 

294 body=body, 

295 title=self.excobj.title, 

296 environ=environ, 

297 ) 

298 return json.dumps(jsonbody) 

299 

300 page_template = JsonPageTemplate(self) 

301 else: 

302 self.content_type = 'text/plain' 

303 escape = _no_escape 

304 page_template = self.plain_template_obj 

305 br = '\n' 

306 if comment: 

307 html_comment = escape(comment) 

308 args = { 

309 'br': br, 

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

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

312 'comment': escape(comment), 

313 'html_comment': html_comment, 

314 } 

315 body_tmpl = self.body_template_obj 

316 if HTTPException.body_template_obj is not body_tmpl: 

317 # Custom template; add headers to args 

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

319 if (not k.startswith('wsgi.')) and ('.' in k): 

320 # omit custom environ variables, stringifying them may 

321 # trigger code that should not be executed here; see 

322 # https://github.com/Pylons/pyramid/issues/239 

323 continue 

324 args[k] = escape(v) 

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

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

327 body = body_tmpl.substitute(args) 

328 page = page_template.substitute(status=self.status, body=body) 

329 if isinstance(page, text_type): 

330 page = page.encode(self.charset if self.charset else 'UTF-8') 

331 self.app_iter = [page] 

332 self.body = page 

333 

334 @property 

335 def wsgi_response(self): 

336 # bw compat only 

337 return self 

338 

339 exception = wsgi_response # bw compat only 

340 

341 def __call__(self, environ, start_response): 

342 # differences from webob.exc.WSGIHTTPException 

343 # 

344 # - does not try to deal with HEAD requests 

345 # 

346 # - does not manufacture a new response object when generating 

347 # the default response 

348 # 

349 self.prepare(environ) 

350 return Response.__call__(self, environ, start_response) 

351 

352 

353WSGIHTTPException = HTTPException # b/c post 1.5 

354 

355 

356class HTTPError(HTTPException): 

357 """ 

358 base class for exceptions with status codes in the 400s and 500s 

359 

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

361 and that any work in progress should not be committed. 

362 """ 

363 

364 

365class HTTPRedirection(HTTPException): 

366 """ 

367 base class for exceptions with status codes in the 300s (redirections) 

368 

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

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

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

372 condition. 

373 """ 

374 

375 

376class HTTPSuccessful(HTTPException): 

377 """ 

378 Base class for exceptions with status codes in the 200s (successful 

379 responses) 

380 """ 

381 

382 

383############################################################ 

384# 2xx success 

385############################################################ 

386 

387 

388class HTTPOk(HTTPSuccessful): 

389 """ 

390 subclass of :class:`~HTTPSuccessful` 

391 

392 Indicates that the request has succeeded. 

393 

394 code: 200, title: OK 

395 """ 

396 

397 code = 200 

398 title = 'OK' 

399 

400 

401class HTTPCreated(HTTPSuccessful): 

402 """ 

403 subclass of :class:`~HTTPSuccessful` 

404 

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

406 resource being created. 

407 

408 code: 201, title: Created 

409 """ 

410 

411 code = 201 

412 title = 'Created' 

413 

414 

415class HTTPAccepted(HTTPSuccessful): 

416 """ 

417 subclass of :class:`~HTTPSuccessful` 

418 

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

420 processing has not been completed. 

421 

422 code: 202, title: Accepted 

423 """ 

424 

425 code = 202 

426 title = 'Accepted' 

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

428 

429 

430class HTTPNonAuthoritativeInformation(HTTPSuccessful): 

431 """ 

432 subclass of :class:`~HTTPSuccessful` 

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 

441 code = 203 

442 title = 'Non-Authoritative Information' 

443 

444 

445class HTTPNoContent(HTTPSuccessful): 

446 """ 

447 subclass of :class:`~HTTPSuccessful` 

448 

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

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

451 metainformation. 

452 

453 code: 204, title: No Content 

454 """ 

455 

456 code = 204 

457 title = 'No Content' 

458 empty_body = True 

459 

460 

461class HTTPResetContent(HTTPSuccessful): 

462 """ 

463 subclass of :class:`~HTTPSuccessful` 

464 

465 This indicates that the server has fulfilled the request and 

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

467 request to be sent. 

468 

469 code: 205, title: Reset Content 

470 """ 

471 

472 code = 205 

473 title = 'Reset Content' 

474 empty_body = True 

475 

476 

477class HTTPPartialContent(HTTPSuccessful): 

478 """ 

479 subclass of :class:`~HTTPSuccessful` 

480 

481 This indicates that the server has fulfilled the partial GET 

482 request for the resource. 

483 

484 code: 206, title: Partial Content 

485 """ 

486 

487 code = 206 

488 title = 'Partial Content' 

489 

490 

491# FIXME: add 207 Multi-Status (but it's complicated) 

492 

493############################################################ 

494# 3xx redirection 

495############################################################ 

496 

497 

498class _HTTPMove(HTTPRedirection): 

499 """ 

500 redirections which require a Location field 

501 

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

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

504 make this easy. 

505 

506 You must provide a ``location`` keyword argument. 

507 """ 

508 

509 # differences from webob.exc._HTTPMove: 

510 # 

511 # - ${location} isn't wrapped in an <a> tag in body 

512 # 

513 # - location keyword arg defaults to '' 

514 # 

515 # - location isn't prepended with req.path_url when adding it as 

516 # a header 

517 # 

518 # - ``location`` is first keyword (and positional) argument 

519 # 

520 # - ``add_slash`` argument is no longer accepted: code that passes 

521 # add_slash argument to the constructor will receive an exception. 

522 explanation = 'The resource has been moved to' 

523 body_template_obj = Template( 

524 '''\ 

525${explanation} ${location}; you should be redirected automatically. 

526${detail} 

527${html_comment}''' 

528 ) 

529 

530 def __init__( 

531 self, 

532 location='', 

533 detail=None, 

534 headers=None, 

535 comment=None, 

536 body_template=None, 

537 **kw 

538 ): 

539 if location is None: 

540 raise ValueError("HTTP redirects need a location to redirect to.") 

541 super(_HTTPMove, self).__init__( 

542 detail=detail, 

543 headers=headers, 

544 comment=comment, 

545 body_template=body_template, 

546 location=location, 

547 **kw 

548 ) 

549 

550 

551class HTTPMultipleChoices(_HTTPMove): 

552 """ 

553 subclass of :class:`~_HTTPMove` 

554 

555 This indicates that the requested resource corresponds to any one 

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

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

558 the user can select a preferred representation and redirect its 

559 request to that location. 

560 

561 code: 300, title: Multiple Choices 

562 """ 

563 

564 code = 300 

565 title = 'Multiple Choices' 

566 

567 

568class HTTPMovedPermanently(_HTTPMove): 

569 """ 

570 subclass of :class:`~_HTTPMove` 

571 

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

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

574 one of the returned URIs. 

575 

576 code: 301, title: Moved Permanently 

577 """ 

578 

579 code = 301 

580 title = 'Moved Permanently' 

581 

582 

583class HTTPFound(_HTTPMove): 

584 """ 

585 subclass of :class:`~_HTTPMove` 

586 

587 This indicates that the requested resource resides temporarily under 

588 a different URI. 

589 

590 code: 302, title: Found 

591 """ 

592 

593 code = 302 

594 title = 'Found' 

595 explanation = 'The resource was found at' 

596 

597 

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

599# retrieved with GET): 

600class HTTPSeeOther(_HTTPMove): 

601 """ 

602 subclass of :class:`~_HTTPMove` 

603 

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

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

606 resource. 

607 

608 code: 303, title: See Other 

609 """ 

610 

611 code = 303 

612 title = 'See Other' 

613 

614 

615class HTTPNotModified(HTTPRedirection): 

616 """ 

617 subclass of :class:`~HTTPRedirection` 

618 

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

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

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

622 

623 code: 304, title: Not Modified 

624 """ 

625 

626 # FIXME: this should include a date or etag header 

627 code = 304 

628 title = 'Not Modified' 

629 empty_body = True 

630 

631 

632class HTTPUseProxy(_HTTPMove): 

633 """ 

634 subclass of :class:`~_HTTPMove` 

635 

636 This indicates that the requested resource MUST be accessed through 

637 the proxy given by the Location field. 

638 

639 code: 305, title: Use Proxy 

640 """ 

641 

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

643 code = 305 

644 title = 'Use Proxy' 

645 explanation = 'The resource must be accessed through a proxy located at' 

646 

647 

648class HTTPTemporaryRedirect(_HTTPMove): 

649 """ 

650 subclass of :class:`~_HTTPMove` 

651 

652 This indicates that the requested resource resides temporarily 

653 under a different URI. 

654 

655 code: 307, title: Temporary Redirect 

656 """ 

657 

658 code = 307 

659 title = 'Temporary Redirect' 

660 

661 

662class HTTPPermanentRedirect(_HTTPMove): 

663 """ 

664 subclass of :class:`~_HTTPMove` 

665 

666 This indicates that the requested resource resides permanently 

667 under a different URI and that the request method must not be 

668 changed. 

669 

670 code: 308, title: Permanent Redirect 

671 """ 

672 

673 code = 308 

674 title = 'Permanent Redirect' 

675 

676 

677############################################################ 

678# 4xx client error 

679############################################################ 

680 

681 

682class HTTPClientError(HTTPError): 

683 """ 

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

685 

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

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

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

689 this is a '400 Bad Request' 

690 """ 

691 

692 code = 400 

693 title = 'Bad Request' 

694 

695 

696class HTTPBadRequest(HTTPClientError): 

697 """ 

698 subclass of :class:`~HTTPClientError` 

699 

700 This indicates that the body or headers failed validity checks, 

701 preventing the server from being able to continue processing. 

702 

703 code: 400, title: Bad Request 

704 """ 

705 

706 explanation = ( 

707 'The server could not comply with the request since ' 

708 'it is either malformed or otherwise incorrect.' 

709 ) 

710 

711 

712class HTTPUnauthorized(HTTPClientError): 

713 """ 

714 subclass of :class:`~HTTPClientError` 

715 

716 This indicates that the request requires user authentication. 

717 

718 code: 401, title: Unauthorized 

719 """ 

720 

721 code = 401 

722 title = 'Unauthorized' 

723 explanation = ( 

724 'This server could not verify that you are authorized to ' 

725 'access the document you requested. Either you supplied the ' 

726 'wrong credentials (e.g., bad password), or your browser ' 

727 'does not understand how to supply the credentials required.' 

728 ) 

729 

730 

731class HTTPPaymentRequired(HTTPClientError): 

732 """ 

733 subclass of :class:`~HTTPClientError` 

734 

735 code: 402, title: Payment Required 

736 """ 

737 

738 code = 402 

739 title = 'Payment Required' 

740 explanation = 'Access was denied for financial reasons.' 

741 

742 

743class HTTPForbidden(HTTPClientError): 

744 """ 

745 subclass of :class:`~HTTPClientError` 

746 

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

748 refusing to fulfill it. 

749 

750 code: 403, title: Forbidden 

751 

752 Raise this exception within :term:`view` code to immediately return the 

753 :term:`forbidden view` to the invoking user. Usually this is a basic 

754 ``403`` page, but the forbidden view can be customized as necessary. See 

755 :ref:`changing_the_forbidden_view`. A ``Forbidden`` exception will be 

756 the ``context`` of a :term:`Forbidden View`. 

757 

758 This exception's constructor treats two arguments specially. The first 

759 argument, ``detail``, should be a string. The value of this string will 

760 be used as the ``message`` attribute of the exception object. The second 

761 special keyword argument, ``result`` is usually an instance of 

762 :class:`pyramid.security.Denied` or :class:`pyramid.security.ACLDenied` 

763 each of which indicates a reason for the forbidden error. However, 

764 ``result`` is also permitted to be just a plain boolean ``False`` object 

765 or ``None``. The ``result`` value will be used as the ``result`` 

766 attribute of the exception object. It defaults to ``None``. 

767 

768 The :term:`Forbidden View` can use the attributes of a Forbidden 

769 exception as necessary to provide extended information in an error 

770 report shown to a user. 

771 """ 

772 

773 # differences from webob.exc.HTTPForbidden: 

774 # 

775 # - accepts a ``result`` keyword argument 

776 # 

777 # - overrides constructor to set ``self.result`` 

778 # 

779 # differences from older ``pyramid.exceptions.Forbidden``: 

780 # 

781 # - ``result`` must be passed as a keyword argument. 

782 # 

783 code = 403 

784 title = 'Forbidden' 

785 explanation = 'Access was denied to this resource.' 

786 

787 def __init__( 

788 self, 

789 detail=None, 

790 headers=None, 

791 comment=None, 

792 body_template=None, 

793 result=None, 

794 **kw 

795 ): 

796 HTTPClientError.__init__( 

797 self, 

798 detail=detail, 

799 headers=headers, 

800 comment=comment, 

801 body_template=body_template, 

802 **kw 

803 ) 

804 self.result = result 

805 

806 

807class HTTPNotFound(HTTPClientError): 

808 """ 

809 subclass of :class:`~HTTPClientError` 

810 

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

812 Request-URI. 

813 

814 code: 404, title: Not Found 

815 

816 Raise this exception within :term:`view` code to immediately 

817 return the :term:`Not Found View` to the invoking user. Usually 

818 this is a basic ``404`` page, but the Not Found View can be 

819 customized as necessary. See :ref:`changing_the_notfound_view`. 

820 

821 This exception's constructor accepts a ``detail`` argument 

822 (the first argument), which should be a string. The value of this 

823 string will be available as the ``message`` attribute of this exception, 

824 for availability to the :term:`Not Found View`. 

825 """ 

826 

827 code = 404 

828 title = 'Not Found' 

829 explanation = 'The resource could not be found.' 

830 

831 

832class HTTPMethodNotAllowed(HTTPClientError): 

833 """ 

834 subclass of :class:`~HTTPClientError` 

835 

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

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

838 

839 code: 405, title: Method Not Allowed 

840 """ 

841 

842 # differences from webob.exc.HTTPMethodNotAllowed: 

843 # 

844 # - body_template_obj uses ${br} instead of <br /> 

845 code = 405 

846 title = 'Method Not Allowed' 

847 body_template_obj = Template( 

848 '''\ 

849The method ${REQUEST_METHOD} is not allowed for this resource. ${br}${br} 

850${detail}''' 

851 ) 

852 

853 

854class HTTPNotAcceptable(HTTPClientError): 

855 """ 

856 subclass of :class:`~HTTPClientError` 

857 

858 This indicates the resource identified by the request is only 

859 capable of generating response entities which have content 

860 characteristics not acceptable according to the accept headers 

861 sent in the request. 

862 

863 code: 406, title: Not Acceptable 

864 """ 

865 

866 # differences from webob.exc.HTTPNotAcceptable: 

867 # 

868 # - "template" attribute left off (useless, bug in webob?) 

869 code = 406 

870 title = 'Not Acceptable' 

871 

872 

873class HTTPProxyAuthenticationRequired(HTTPClientError): 

874 """ 

875 subclass of :class:`~HTTPClientError` 

876 

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

878 authenticate itself with the proxy. 

879 

880 code: 407, title: Proxy Authentication Required 

881 """ 

882 

883 code = 407 

884 title = 'Proxy Authentication Required' 

885 explanation = 'Authentication with a local proxy is needed.' 

886 

887 

888class HTTPRequestTimeout(HTTPClientError): 

889 """ 

890 subclass of :class:`~HTTPClientError` 

891 

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

893 the time that the server was prepared to wait. 

894 

895 code: 408, title: Request Timeout 

896 """ 

897 

898 code = 408 

899 title = 'Request Timeout' 

900 explanation = ( 

901 'The server has waited too long for the request to ' 

902 'be sent by the client.' 

903 ) 

904 

905 

906class HTTPConflict(HTTPClientError): 

907 """ 

908 subclass of :class:`~HTTPClientError` 

909 

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

911 conflict with the current state of the resource. 

912 

913 code: 409, title: Conflict 

914 """ 

915 

916 code = 409 

917 title = 'Conflict' 

918 explanation = ( 

919 'There was a conflict when trying to complete ' 'your request.' 

920 ) 

921 

922 

923class HTTPGone(HTTPClientError): 

924 """ 

925 subclass of :class:`~HTTPClientError` 

926 

927 This indicates that the requested resource is no longer available 

928 at the server and no forwarding address is known. 

929 

930 code: 410, title: Gone 

931 """ 

932 

933 code = 410 

934 title = 'Gone' 

935 explanation = ( 

936 'This resource is no longer available. No forwarding ' 

937 'address is given.' 

938 ) 

939 

940 

941class HTTPLengthRequired(HTTPClientError): 

942 """ 

943 subclass of :class:`~HTTPClientError` 

944 

945 This indicates that the server refuses to accept the request 

946 without a defined Content-Length. 

947 

948 code: 411, title: Length Required 

949 """ 

950 

951 code = 411 

952 title = 'Length Required' 

953 explanation = 'Content-Length header required.' 

954 

955 

956class HTTPPreconditionFailed(HTTPClientError): 

957 """ 

958 subclass of :class:`~HTTPClientError` 

959 

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

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

962 server. 

963 

964 code: 412, title: Precondition Failed 

965 """ 

966 

967 code = 412 

968 title = 'Precondition Failed' 

969 explanation = 'Request precondition failed.' 

970 

971 

972class HTTPRequestEntityTooLarge(HTTPClientError): 

973 """ 

974 subclass of :class:`~HTTPClientError` 

975 

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

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

978 able to process. 

979 

980 code: 413, title: Request Entity Too Large 

981 """ 

982 

983 code = 413 

984 title = 'Request Entity Too Large' 

985 explanation = 'The body of your request was too large for this server.' 

986 

987 

988class HTTPRequestURITooLong(HTTPClientError): 

989 """ 

990 subclass of :class:`~HTTPClientError` 

991 

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

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

994 interpret. 

995 

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

997 """ 

998 

999 code = 414 

1000 title = 'Request-URI Too Long' 

1001 explanation = 'The request URI was too long for this server.' 

1002 

1003 

1004class HTTPUnsupportedMediaType(HTTPClientError): 

1005 """ 

1006 subclass of :class:`~HTTPClientError` 

1007 

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

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

1010 the requested resource for the requested method. 

1011 

1012 code: 415, title: Unsupported Media Type 

1013 """ 

1014 

1015 # differences from webob.exc.HTTPUnsupportedMediaType: 

1016 # 

1017 # - "template_obj" attribute left off (useless, bug in webob?) 

1018 code = 415 

1019 title = 'Unsupported Media Type' 

1020 

1021 

1022class HTTPRequestRangeNotSatisfiable(HTTPClientError): 

1023 """ 

1024 subclass of :class:`~HTTPClientError` 

1025 

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

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

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

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

1030 If-Range request-header field. 

1031 

1032 code: 416, title: Request Range Not Satisfiable 

1033 """ 

1034 

1035 code = 416 

1036 title = 'Request Range Not Satisfiable' 

1037 explanation = 'The Range requested is not available.' 

1038 

1039 

1040class HTTPExpectationFailed(HTTPClientError): 

1041 """ 

1042 subclass of :class:`~HTTPClientError` 

1043 

1044 This indidcates that the expectation given in an Expect 

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

1046 

1047 code: 417, title: Expectation Failed 

1048 """ 

1049 

1050 code = 417 

1051 title = 'Expectation Failed' 

1052 explanation = 'Expectation failed.' 

1053 

1054 

1055class HTTPUnprocessableEntity(HTTPClientError): 

1056 """ 

1057 subclass of :class:`~HTTPClientError` 

1058 

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

1060 instructions. 

1061 

1062 May be used to notify the client that their JSON/XML is well formed, but 

1063 not correct for the current request. 

1064 

1065 See RFC4918 section 11 for more information. 

1066 

1067 code: 422, title: Unprocessable Entity 

1068 """ 

1069 

1070 # Note: from WebDAV 

1071 code = 422 

1072 title = 'Unprocessable Entity' 

1073 explanation = 'Unable to process the contained instructions' 

1074 

1075 

1076class HTTPLocked(HTTPClientError): 

1077 """ 

1078 subclass of :class:`~HTTPClientError` 

1079 

1080 This indicates that the resource is locked. 

1081 

1082 code: 423, title: Locked 

1083 """ 

1084 

1085 # Note: from WebDAV 

1086 code = 423 

1087 title = 'Locked' 

1088 explanation = 'The resource is locked' 

1089 

1090 

1091class HTTPFailedDependency(HTTPClientError): 

1092 """ 

1093 subclass of :class:`~HTTPClientError` 

1094 

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

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

1097 

1098 code: 424, title: Failed Dependency 

1099 """ 

1100 

1101 # Note: from WebDAV 

1102 code = 424 

1103 title = 'Failed Dependency' 

1104 explanation = ( 

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

1106 'action dependended on another action and that action failed' 

1107 ) 

1108 

1109 

1110class HTTPPreconditionRequired(HTTPClientError): 

1111 """ 

1112 subclass of :class:`~HTTPClientError` 

1113 

1114 This indicates that the origin server requires the 

1115 request to be conditional. 

1116 

1117 Its typical use is to avoid the "lost update" problem, where a client 

1118 GETs a resource's state, modifies it, and PUTs it back to the server, 

1119 when meanwhile a third party has modified the state on the server, 

1120 leading to a conflict. By requiring requests to be conditional, the 

1121 server can assure that clients are working with the correct copies. 

1122 

1123 RFC 6585.3 

1124 

1125 code: 428, title: Precondition Required 

1126 """ 

1127 

1128 code = 428 

1129 title = 'Precondition Required' 

1130 explanation = 'The origin server requires the request to be conditional.' 

1131 

1132 

1133class HTTPTooManyRequests(HTTPClientError): 

1134 """ 

1135 subclass of :class:`~HTTPClientError` 

1136 

1137 This indicates that the user has sent too many 

1138 requests in a given amount of time ("rate limiting"). 

1139 

1140 RFC 6585.4 

1141 

1142 code: 429, title: Too Many Requests 

1143 """ 

1144 

1145 code = 429 

1146 title = 'Too Many Requests' 

1147 explanation = ( 

1148 'The action could not be performed because there were too ' 

1149 'many requests by the client.' 

1150 ) 

1151 

1152 

1153class HTTPRequestHeaderFieldsTooLarge(HTTPClientError): 

1154 """ 

1155 subclass of :class:`~HTTPClientError` 

1156 

1157 This indicates that the server is unwilling to process 

1158 the request because its header fields are too large. The request MAY 

1159 be resubmitted after reducing the size of the request header fields. 

1160 

1161 RFC 6585.5 

1162 

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

1164 """ 

1165 

1166 code = 431 

1167 title = 'Request Header Fields Too Large' 

1168 explanation = 'The requests header fields were too large.' 

1169 

1170 

1171############################################################ 

1172# 5xx Server Error 

1173############################################################ 

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

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

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

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

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

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

1180# codes are applicable to any request method. 

1181 

1182 

1183class HTTPServerError(HTTPError): 

1184 """ 

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

1186 

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

1188 in-error. Unless specialized, this is a '500 Internal Server Error'. 

1189 """ 

1190 

1191 code = 500 

1192 title = 'Internal Server Error' 

1193 

1194 

1195class HTTPInternalServerError(HTTPServerError): 

1196 """ 

1197 subclass of :class:`~HTTPServerError` 

1198 

1199 This indicates that the server encountered an unexpected condition 

1200 which prevented it from fulfilling the request. 

1201 

1202 code: 500, title: Internal Server Error 

1203 """ 

1204 

1205 explanation = ( 

1206 'The server has either erred or is incapable of performing ' 

1207 'the requested operation.' 

1208 ) 

1209 

1210 

1211class HTTPNotImplemented(HTTPServerError): 

1212 """ 

1213 subclass of :class:`~HTTPServerError` 

1214 

1215 This indicates that the server does not support the functionality 

1216 required to fulfill the request. 

1217 

1218 code: 501, title: Not Implemented 

1219 """ 

1220 

1221 # differences from webob.exc.HTTPNotAcceptable: 

1222 # 

1223 # - "template" attr left off (useless, bug in webob?) 

1224 code = 501 

1225 title = 'Not Implemented' 

1226 

1227 

1228class HTTPBadGateway(HTTPServerError): 

1229 """ 

1230 subclass of :class:`~HTTPServerError` 

1231 

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

1233 received an invalid response from the upstream server it accessed 

1234 in attempting to fulfill the request. 

1235 

1236 code: 502, title: Bad Gateway 

1237 """ 

1238 

1239 code = 502 

1240 title = 'Bad Gateway' 

1241 explanation = 'Bad gateway.' 

1242 

1243 

1244class HTTPServiceUnavailable(HTTPServerError): 

1245 """ 

1246 subclass of :class:`~HTTPServerError` 

1247 

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

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

1250 

1251 code: 503, title: Service Unavailable 

1252 """ 

1253 

1254 code = 503 

1255 title = 'Service Unavailable' 

1256 explanation = ( 

1257 'The server is currently unavailable. ' 

1258 'Please try again at a later time.' 

1259 ) 

1260 

1261 

1262class HTTPGatewayTimeout(HTTPServerError): 

1263 """ 

1264 subclass of :class:`~HTTPServerError` 

1265 

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

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

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

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

1270 

1271 code: 504, title: Gateway Timeout 

1272 """ 

1273 

1274 code = 504 

1275 title = 'Gateway Timeout' 

1276 explanation = 'The gateway has timed out.' 

1277 

1278 

1279class HTTPVersionNotSupported(HTTPServerError): 

1280 """ 

1281 subclass of :class:`~HTTPServerError` 

1282 

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

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

1285 message. 

1286 

1287 code: 505, title: HTTP Version Not Supported 

1288 """ 

1289 

1290 code = 505 

1291 title = 'HTTP Version Not Supported' 

1292 explanation = 'The HTTP version is not supported.' 

1293 

1294 

1295class HTTPInsufficientStorage(HTTPServerError): 

1296 """ 

1297 subclass of :class:`~HTTPServerError` 

1298 

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

1300 the resource. 

1301 

1302 code: 507, title: Insufficient Storage 

1303 """ 

1304 

1305 code = 507 

1306 title = 'Insufficient Storage' 

1307 explanation = 'There was not enough space to save the resource' 

1308 

1309 

1310def exception_response(status_code, **kw): 

1311 """Creates an HTTP exception based on a status code. Example:: 

1312 

1313 raise exception_response(404) # raises an HTTPNotFound exception. 

1314 

1315 The values passed as ``kw`` are provided to the exception's constructor. 

1316 """ 

1317 exc = status_map[status_code](**kw) 

1318 return exc 

1319 

1320 

1321def default_exceptionresponse_view(context, request): 

1322 if not isinstance(context, Exception): 

1323 # backwards compat for an exception response view registered via 

1324 # config.set_notfound_view or config.set_forbidden_view 

1325 # instead of as a proper exception view 

1326 context = request.exception or context 

1327 return context # assumed to be an IResponse 

1328 

1329 

1330status_map = {} 

1331code = None 

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

1333 if ( 

1334 isinstance(value, class_types) 

1335 and issubclass(value, HTTPException) 

1336 and value not in {HTTPClientError, HTTPServerError} 

1337 and not name.startswith('_') 

1338 ): 

1339 code = getattr(value, 'code', None) 

1340 if code: 

1341 status_map[code] = value 

1342del name, value, code