Source

django-repose / repose / http.py

   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
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
"""
The classes in here are combinations of django's HttpResponse, but mixin
the base Exception class, to enable us to catch them.

Technically, perhaps we should only have the actual error classes inherit
from Exception, as they are the only ones that are truly errors, but having
HttpResponse as something we can raise, and drop right out of the stack then
and there is useful, if dirty.

Even request types that are probably not going to be used have been included,
just because.

Docstrings are from http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html,
unless otherwised noted.
"""

import logging

import django.http
from django.conf import settings
from django.db.models.query import QuerySet
from django.utils.translation import ugettext as _

from repose import serializers

logger = logging.getLogger('repose.http')

class BaseHttpResponse(django.http.HttpResponse, Exception):
    """
    A BaseHttpResponse object can be returned to django's handler, and will be used
    for the response data and meta-data.
    
    By also making it a subclass of Exception, we can raise one of them anywhere in our
    view code (or things called by the view code, but that is probably not a good idea)
    and that object will be returned, unprocessed.
    
    For instance, you may have a view that is wrapped in a decorator that checks for
    permission to do something (or have a helper function that does the same). This
    code can raise an exception, and you don't have to worry about returning back up
    the call chain: the exception is propagated, and the dispatcher can catch all
    Exceptions that are subclasses of this class, and return those.
    """
    def __init__(self, content='', content_type=None, **kwargs):
        """
        Override: we want to set the content_type, if we have content, to
        what we will serialize it to. Unless it is explicitly set.
        
        However, to do this, we need access to the request object, so we
        have to do it later: hence the _reset_content_type.
        """
        super(BaseHttpResponse, self).__init__(content=content, content_type=content_type, **kwargs)
        if not content_type and content:
            self._reset_content_type = True
        self.template_name = None
        self.request = None
        self._is_rendered = False
        self._rendered_content = None
    
    def render(self):
        if not self._is_rendered:
            self._rendered_content = self.content
            self._is_rendered = True
        return self
    
    def _get_content(self):
        if self._rendered_content:
            return self._rendered_content
        
        content_type = serializers.get_preferred_content_type(self.request)
        serializer = serializers.get_serializer(content_type)
        
        if serializer:
            data = serializer.serialize(self._container, request=self.request, response=self, template_name=self.template_name)
            self._container = data
            self._is_string = True
            self['Content-Length'] = len(data)
            self['Content-Type'] = content_type
            return data
        return super(BaseHttpResponse, self)._get_content()
    
    def _set_content(self, value):
        self._container = value
        self._is_string = isinstance(value, basestring)
    
    content = property(_get_content, _set_content)
    
    def __iter__(self):
        self._iterator = iter([1])
        return self
    
    def next(self):
        self._iterator.next()
        return self.content.encode('utf-8')

class LocationHeaderMixin(object):
    """
    Automatically set the 'Location' header on the response, based on the object
    that has been passed in.
    
    If more than one object was found in a container, then don't set it.
    """
    def __init__(self, *args, **kwargs):
        location = kwargs.pop('location', None)
        super(LocationHeaderMixin, self).__init__(*args, **kwargs)
        if not location:
            data = self._container
            if isinstance(data, (list, tuple, QuerySet)) and len(data) == 1:
                data = data[0]
            if hasattr(data, 'get_absolute_url'):
                location = data.get_absolute_url()
            elif hasattr(data, 'href'):
                location = data.href
            elif isinstance(data, dict):
                if 'href' in data:
                    location = data['href']
                else:
                    links = []
                    if 'links' in data:
                        links = data['links']
                    for link in links:
                        if link['rel'] == "self":
                            location = link["uri"]
                
#             else:
#                 location = data
        
        if location:
            self['Location'] = location

class NoContentMixin(object):
    """Mixin to prevent a content body from being sent."""
    def __init__(self, *args, **kwargs):
        err_msg = _(
            u'Body provided on a response type that should not contain one.'
        )
        super(NoContentMixin, self).__init__(*args, **kwargs)
        if hasattr(self, '_container') and self._container:
            logger.warning(err_msg, exc_info=True, extra={
                'request': self.request,
                'data': {
                },
                'stack': True,
            })
        self._container = []


######################
#
#   HTTP Responses
#
######################

class Continue(BaseHttpResponse):
    """
    The client SHOULD continue with its request. This interim response is used to 
    inform the client that the initial part of the request has been received and has 
    not yet been rejected by the server. The client SHOULD continue by sending the 
    remainder of the request or, if the request has already been completed, ignore 
    this response. The server MUST send a final response after the request has been 
    completed.
    """
    status_code = 100

class SwitchingProtocols(BaseHttpResponse):
    """
    The server understands and is willing to comply with the client's request, via 
    the Upgrade message header field (section 14.42), for a change in the application 
    protocol being used on this connection. The server will switch protocols to those 
    defined by the response's Upgrade header field immediately after the empty line 
    which terminates the 101 response.

    The protocol SHOULD be switched only when it is advantageous to do so. For example, 
    switching to a newer version of HTTP is advantageous over older versions, and 
    switching to a real-time, synchronous protocol might be advantageous when 
    delivering resources that use such features.
    """
    status_code = 101

class Processing(BaseHttpResponse):
    """
    As a WebDAV request may contain many sub-requests involving file operations, 
    it may take a long time to complete the request. This code indicates that the 
    server has received and is processing the request, but no response is available 
    yet.This prevents the client from timing out and assuming the request was lost.
    
    WebDAV: RFC 2518, via http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 102

class Checkpoint(BaseHttpResponse):
    """
    This code is used in the Resumable HTTP Requests Proposal to resume aborted PUT 
    or POST requests.
    
    http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 103
    
#####################################
#
#   Successful HTTP response codes
# 
#####################################

class HttpResponseSuccess(BaseHttpResponse):
    """
    This class of status codes indicates the action requested by the client was 
    received, understood, accepted and processed successfully. These status codes
    are 2xx codes.
    """
    pass

class OK(HttpResponseSuccess):
    """
    The request has succeeded. The information returned with the response is dependent 
    on the method used in the request, for example:

    * GET an entity corresponding to the requested resource is sent in the response;
    * HEAD the entity-header fields corresponding to the requested resource are sent 
      in the response without any message-body;
    * POST an entity describing or containing the result of the action;
    * TRACE an entity containing the request message as received by the end server.
    """
    status_code = 200

class Deleted(HttpResponseSuccess):
    """
    A convenience class that duplicates OK, but allows us to catch it differently in
    exception handling, if necessary.
    """
    status_code = 200

class Created(LocationHeaderMixin, HttpResponseSuccess):
    """
    The request has been fulfilled and resulted in a new resource being created. The 
    newly created resource can be referenced by the URI(s) returned in the entity of 
    the response, with the most specific URI for the resource given by a Location header 
    field. The response SHOULD include an entity containing a list of resource 
    characteristics and location(s) from which the user or user agent can choose the 
    one most appropriate. The entity format is specified by the media type given in 
    the Content-Type header field. The origin server MUST create the resource before 
    returning the 201 status code. If the action cannot be carried out immediately, 
    the server SHOULD respond with 202 (Accepted) response instead.
    
    A 201 response MAY contain an ETag response header field indicating the current 
    value of the entity tag for the requested variant just created.
    """
    status_code = 201
    
class Accepted(LocationHeaderMixin, HttpResponseSuccess):
    """
    The request has been accepted for processing, but the processing has not been 
    completed. The request might or might not eventually be acted upon, as it might 
    be disallowed when processing actually takes place. There is no facility for 
    re-sending a status code from an asynchronous operation such as this.

    The 202 response is intentionally non-committal. Its purpose is to allow a server 
    to accept a request for some other process (perhaps a batch-oriented process that 
    is only run once per day) without requiring that the user agent's connection to 
    the server persist until the process is completed. The entity returned with this 
    response SHOULD include an indication of the request's current status and either 
    a pointer to a status monitor or some estimate of when the user can expect the 
    request to be fulfilled.
    """
    status_code = 202
    
class NonAuthoritativeInformation(HttpResponseSuccess):
    """
    The returned metainformation in the entity-header is not the definitive set as 
    available from the origin server, but is gathered from a local or a third-party 
    copy. The set presented MAY be a subset or superset of the original version. For 
    example, including local annotation information about the resource might result 
    in a superset of the metainformation known by the origin server. Use of this 
    response code is not required and is only appropriate when the response would 
    otherwise be 200 (OK).
    """
    status_code = 203

class NoContent(NoContentMixin, HttpResponseSuccess):
    """
    The server has fulfilled the request but does not need to return an entity-body, 
    and might want to return updated metainformation. The response MAY include new or 
    updated metainformation in the form of entity-headers, which if present SHOULD be 
    associated with the requested variant.

    If the client is a user agent, it SHOULD NOT change its document view from that 
    which caused the request to be sent. This response is primarily intended to allow 
    input for actions to take place without causing a change to the user agent's active 
    document view, although any new or updated metainformation SHOULD be applied to the 
    document currently in the user agent's active view.

    The 204 response MUST NOT include a message-body, and thus is always terminated by 
    the first empty line after the header fields.
    """
    status_code = 204

class ResetContent(NoContentMixin, HttpResponseSuccess):
    """
    The server has fulfilled the request and the user agent SHOULD reset the document 
    view which caused the request to be sent. This response is primarily intended to 
    allow input for actions to take place via user input, followed by a clearing of 
    the form in which the input is given so that the user can easily initiate another 
    input action. The response MUST NOT include an entity.
    """
    status_code = 205

class PartialContent(HttpResponseSuccess):
    """
    The server has fulfilled the partial GET request for the resource. 
    The request MUST have included a Range header field indicating the desired range, 
    and MAY have included an If-Range header field to make the request conditional.

    The response MUST include the following header fields:

    * Either a Content-Range header field (section 14.16) indicating
      the range included with this response, or a multipart/byteranges
      Content-Type including Content-Range fields for each part. If a
      Content-Length header field is present in the response, its
      value MUST match the actual number of OCTETs transmitted in the
      message-body.
    * Date
    * ETag and/or Content-Location, if the header would have been sent
      in a 200 response to the same request
    * Expires, Cache-Control, and/or Vary, if the field-value might
      differ from that sent in any previous response for the same variant
    
    If the 206 response is the result of an If-Range request that used a strong cache 
    validator, the response SHOULD NOT include other entity-headers. If the response 
    is the result of an If-Range request that used a weak validator, the response MUST 
    NOT include other entity-headers; this prevents inconsistencies between cached 
    entity-bodies and updated headers. Otherwise, the response MUST include all of the 
    entity-headers that would have been returned with a 200 (OK) response to the same 
    request.

    A cache MUST NOT combine a 206 response with other previously cached content if 
    the ETag or Last-Modified headers do not match exactly.

    A cache that does not support the Range and Content-Range headers MUST NOT cache
    206 (Partial) responses.
    """
    status_code = 206

class MultiStatus(HttpResponseSuccess):
    """
    The message body that follows is an XML message and can contain a number of 
    separate response codes, depending on how many sub-requests were made.
    
    WebDAV: RFC 4918, via http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 207

class AlreadyReported(HttpResponseSuccess):
    """
    The members of a DAV binding have already been enumerated in a previous reply 
    to this request, and are not being included again.
    
    WebDAV: RFC 5842, via http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 208

class IMUsed(HttpResponseSuccess):
    """
    The server has fulfilled a GET request for the resource, and the response is 
    a representation of the result of one or more instance-manipulations applied 
    to the current instance.
    
    WebDAV: RFC 3229, via http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 226

########################
#
#   3xx Response codes
#
########################

class HttpResponseRedirect(BaseHttpResponse):
    """
    3xx series response codes.
    """
    pass

class MultipleChoices(HttpResponseRedirect):
    """
    The requested resource corresponds to any one of a set of representations, each 
    with its own specific location, and agent- driven negotiation information is being 
    provided so that the user (or user agent) can select a preferred representation and 
    redirect its request to that location.

    Unless it was a HEAD request, the response SHOULD include an entity containing a 
    list of resource characteristics and location(s) from which the user or user agent 
    can choose the one most appropriate. The entity format is specified by the media 
    type given in the Content- Type header field. Depending upon the format and the 
    capabilities of the user agent, selection of the most appropriate choice MAY be 
    performed automatically. However, this specification does not define any standard 
    for such automatic selection.

    If the server has a preferred choice of representation, it SHOULD include the 
    specific URI for that representation in the Location field; user agents MAY use 
    the Location field value for automatic redirection. This response is cacheable 
    unless indicated otherwise.
    """
    status_code = 300

class MovedPermanently(LocationHeaderMixin, HttpResponseRedirect):
    """
    The requested resource has been assigned a new permanent URI and any future 
    references to this resource SHOULD use one of the returned URIs. Clients with 
    link editing capabilities ought to automatically re-link references to the 
    Request-URI to one or more of the new references returned by the server, where 
    possible. This response is cacheable unless indicated otherwise.

    The new permanent URI SHOULD be given by the Location field in the response. Unless 
    the request method was HEAD, the entity of the response SHOULD contain a short 
    hypertext note with a hyperlink to the new URI(s).

    If the 301 status code is received in response to a request other than GET or HEAD, 
    the user agent MUST NOT automatically redirect the request unless it can be 
    confirmed by the user, since this might change the conditions under which the 
    request was issued.

    ..note:: When automatically redirecting a POST request after
      receiving a 301 status code, some existing HTTP/1.0 user agents
      will erroneously change it into a GET request.
    """
    status_code = 301

class Found(LocationHeaderMixin, HttpResponseRedirect):
    """
    The requested resource resides temporarily under a different URI. Since the 
    redirection might be altered on occasion, the client SHOULD continue to use 
    the Request-URI for future requests. This response is only cacheable if indicated 
    by a Cache-Control or Expires header field.

    The temporary URI SHOULD be given by the Location field in the response. Unless 
    the request method was HEAD, the entity of the response SHOULD contain a short 
    hypertext note with a hyperlink to the new URI(s).

    If the 302 status code is received in response to a request other than GET or HEAD, 
    the user agent MUST NOT automatically redirect the request unless it can be 
    confirmed by the user, since this might change the conditions under which the 
    request was issued.

    ..note:: RFC 1945 and RFC 2068 specify that the client is not allowed
      to change the method on the redirected request.  However, most
      existing user agent implementations treat 302 as if it were a 303
      response, performing a GET on the Location field-value regardless
      of the original request method. The status codes 303 and 307 have
      been added for servers that wish to make unambiguously clear which
      kind of reaction is expected of the client.
    """
    status_code = 302

class SeeOther(LocationHeaderMixin, HttpResponseRedirect):
    """
    The response to the request can be found under a different URI and SHOULD be 
    retrieved using a GET method on that resource. This method exists primarily to 
    allow the output of a POST-activated script to redirect the user agent to a 
    selected resource. The new URI is not a substitute reference for the originally 
    requested resource. The 303 response MUST NOT be cached, but the response to the 
    second (redirected) request might be cacheable.

    The different URI SHOULD be given by the Location field in the response. Unless 
    the request method was HEAD, the entity of the response SHOULD contain a short 
    hypertext note with a hyperlink to the new URI(s).

    ..note:: Many pre-HTTP/1.1 user agents do not understand the 303
      status. When interoperability with such clients is a concern, the
      302 status code may be used instead, since most user agents react
      to a 302 response as described here for 303.
    """
    status_code = 303

class NotModified(NoContentMixin, HttpResponseRedirect):
    """
    If the client has performed a conditional GET request and access is allowed, 
    but the document has not been modified, the server SHOULD respond with this 
    status code. The 304 response MUST NOT contain a message-body, and thus is 
    always terminated by the first empty line after the header fields.

    The response MUST include the following header fields:

    * Date, unless its omission is required (by clockless origin server)
      If a clockless origin server obeys these rules, and proxies and clients add 
      their own Date to any response received without one (as already specified by 
      [RFC 2068], section 14.19), caches will operate correctly.

    * ETag and/or Content-Location, if the header would have been sent in a 200 response
      to the same request
    * Expires, Cache-Control, and/or Vary, if the field-value might
      differ from that sent in any previous response for the same variant
    
    If the conditional GET used a strong cache validator, the response SHOULD NOT 
    include other entity-headers. Otherwise (i.e., the conditional GET used a weak 
    validator), the response MUST NOT include other entity-headers; this prevents 
    inconsistencies between cached entity-bodies and updated headers.
    
    If a 304 response indicates an entity not currently cached, then the cache MUST 
    disregard the response and repeat the request without the conditional.
    
    If a cache uses a received 304 response to update a cache entry, the cache MUST 
    update the entry to reflect any new field values given in the response.
    """
    status_code = 304
    # Must set date header.

class UseProxy(LocationHeaderMixin, HttpResponseRedirect):
    """
    The requested resource MUST be accessed through the proxy given by the Location 
    field. The Location field gives the URI of the proxy. The recipient is expected 
    to repeat this single request via the proxy. 305 responses MUST only be generated 
    by origin servers.

    ..note:: RFC 2068 was not clear that 305 was intended to redirect a
      single request, and to be generated by origin servers only.  Not
      observing these limitations has significant security consequences.
    """
    status_code = 305

class SwitchProxy(HttpResponseRedirect):
    """
    No longer used. Originally meant: 
        "Subsequent requests should use the specified proxy."
    
    http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 306

class TemporaryRedirect(HttpResponseRedirect):
    """
    The requested resource resides temporarily under a different URI. Since the 
    redirection MAY be altered on occasion, the client SHOULD continue to use the 
    Request-URI for future requests. This response is only cacheable if indicated 
    by a Cache-Control or Expires header field.

    The temporary URI SHOULD be given by the Location field in the response. Unless 
    the request method was HEAD, the entity of the response SHOULD contain a short 
    hypertext note with a hyperlink to the new URI(s) , since many pre-HTTP/1.1 user 
    agents do not understand the 307 status. Therefore, the note SHOULD contain the 
    information necessary for a user to repeat the original request on the new URI.

    If the 307 status code is received in response to a request other than GET or HEAD, 
    the user agent MUST NOT automatically redirect the request unless it can be 
    confirmed by the user, since this might change the conditions under which the 
    request was issued.
    """
    status_code = 307

class ResumeIncomplete(HttpResponseRedirect):
    """
    This code is used in the Resumable HTTP Requests Proposal to resume aborted PUT 
    or POST requests.
    
    http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 308

#######################################
#
#   4xx Response codes - client error
#
#######################################

class HttpResponseError(BaseHttpResponse):
    """
    The 4xx class of status code is intended for cases in which the client seems 
    to have erred. Except when responding to a HEAD request, the server should 
    include an entity containing an explanation of the error situation, and whether 
    it is a temporary or permanent condition. These status codes are applicable to 
    any request method. User agents should display any included entity to the user.
    """
    pass

class BadRequest(HttpResponseError):
    """
    The request could not be understood by the server due to malformed syntax. 
    The client SHOULD NOT repeat the request without modifications.
    """
    status_code = 400

class Unauthorized(HttpResponseError):
    """
    The request requires user authentication. The response MUST include a 
    WWW-Authenticate header field containing a challenge applicable to the requested 
    resource. The client MAY repeat the request with a suitable Authorization header 
    field. If the request already included Authorization credentials, then the 401 
    response indicates that authorization has been refused for those credentials. 
    If the 401 response contains the same challenge as the prior response, and the 
    user agent has already attempted authentication at least once, then the user 
    SHOULD be presented the entity that was given in the response, since that entity 
    might include relevant diagnostic information. HTTP access authentication is 
    explained in "HTTP Authentication: Basic and Digest Access Authentication" 
    
    http://www.w3.org/Protocols/rfc2616/rfc2616-sec17.html#bib43
    """
    status_code = 401
    
    def __init__(self, *args, **kwargs):
        super(Unauthorized, self).__init__(*args, **kwargs)
        # TODO: Look for the authentication type being used here.
        if settings.HTTP_AUTH_REALM:
            self['WWW-Authenticate'] = 'Basic realm=%s' % (
                settings.HTTP_AUTH_REALM
            )

class PaymentRequired(HttpResponseError):
    """
    This code is reserved for future use.
    
    Addendum - from http://en.wikipedia.org/wiki/List_of_HTTP_status_codes:
    
    The original intention was that this code might be used as part of some form 
    of digital cash or micropayment scheme, but that has not happened, and this code 
    is not usually used. As an example of its use, however, Apple's MobileMe service 
    generates a 402 error ("httpStatusCode:402" in the Mac OS X Console log) if the 
    MobileMe account is delinquent.
    """
    status_code = 402
    
class Forbidden(HttpResponseError):
    """
    The server understood the request, but is refusing to fulfill it. Authorization 
    will not help and the request SHOULD NOT be repeated. If the request method was 
    not HEAD and the server wishes to make public why the request has not been 
    fulfilled, it SHOULD describe the reason for the refusal in the entity. If the 
    server does not wish to make this information available to the client, the 
    status code 404 (Not Found) can be used instead.
    """
    status_code = 403

class NotFound(HttpResponseError):
    """
    The server has not found anything matching the Request-URI. No indication is 
    given of whether the condition is temporary or permanent. The 410 (Gone) status 
    code SHOULD be used if the server knows, through some internally configurable 
    mechanism, that an old resource is permanently unavailable and has no forwarding 
    address. This status code is commonly used when the server does not wish to 
    reveal exactly why the request has been refused, or when no other response 
    is applicable.
    """
    status_code = 404

class MethodNotAllowed(HttpResponseError):
    """
    The method specified in the Request-Line is not allowed for the resource 
    identified by the Request-URI. The response MUST include an Allow header 
    containing a list of valid methods for the requested resource.
    """
    status_code = 405
    # Allow header required

class NotAcceptable(HttpResponseError):
    """
    The resource identified by the request is only capable of generating response 
    entities which have content characteristics not acceptable according to the accept 
    headers sent in the request.

    Unless it was a HEAD request, the response SHOULD include an entity containing a 
    list of available entity characteristics and location(s) from which the user or 
    user agent can choose the one most appropriate. The entity format is specified by 
    the media type given in the Content-Type header field. Depending upon the format 
    and the capabilities of the user agent, selection of the most appropriate choice 
    MAY be performed automatically. However, this specification does not define any 
    standard for such automatic selection.

    ..note:: HTTP/1.1 servers are allowed to return responses which are
      not acceptable according to the accept headers sent in the
      request. In some cases, this may even be preferable to sending a
      406 response. User agents are encouraged to inspect the headers of
      an incoming response to determine if it is acceptable.
    
    If the response could be unacceptable, a user agent SHOULD temporarily stop 
    receipt of more data and query the user for a decision on further actions.
    """
    status_code = 406

class ProxyAuthenticationRequired(HttpResponseError):
    """
    This code is similar to 401 (Unauthorized), but indicates that the client must 
    first authenticate itself with the proxy. The proxy MUST return a Proxy-Authenticate 
    header field containing a challenge applicable to the proxy for the 
    requested resource. The client MAY repeat the request with a suitable 
    Proxy-Authorization header field (section 14.34). HTTP access authentication 
    is explained in "HTTP Authentication: Basic and Digest Access Authentication".
    """
    status_code = 407

class RequestTimeout(HttpResponseError):
    """
    The client did not produce a request within the time that the server was 
    prepared to wait. The client MAY repeat the request without modifications 
    at any later time.
    """
    status_code = 408

class Conflict(HttpResponseError):
    """
    The request could not be completed due to a conflict with the current state of 
    the resource. This code is only allowed in situations where it is expected that 
    the user might be able to resolve the conflict and resubmit the request. The 
    response body SHOULD include enough information for the user to recognize the 
    source of the conflict. Ideally, the response entity would include enough 
    information for the user or user agent to fix the problem; however, that 
    might not be possible and is not required.
    
    Conflicts are most likely to occur in response to a PUT request. For example, 
    if versioning were being used and the entity being PUT included changes to a 
    resource which conflict with those made by an earlier (third-party) request, 
    the server might use the 409 response to indicate that it can't complete the 
    request. In this case, the response entity would likely contain a list of the 
    differences between the two versions in a format defined by the response 
    Content-Type.
    """
    status_code = 409

class Gone(HttpResponseError):
    """
    The requested resource is no longer available at the server and no forwarding 
    address is known. This condition is expected to be considered permanent. Clients 
    with link editing capabilities SHOULD delete references to the Request-URI after 
    user approval. If the server does not know, or has no facility to determine, 
    whether or not the condition is permanent, the status code 404 (Not Found) SHOULD 
    be used instead. This response is cacheable unless indicated otherwise.

    The 410 response is primarily intended to assist the task of web maintenance by 
    notifying the recipient that the resource is intentionally unavailable and that 
    the server owners desire that remote links to that resource be removed. Such an 
    event is common for limited-time, promotional services and for resources belonging 
    to individuals no longer working at the server's site. It is not necessary to mark 
    all permanently unavailable resources as "gone" or to keep the mark for any length 
    of time -- that is left to the discretion of the server owner.
    """
    status_code = 410

class LengthRequired(HttpResponseError):
    """
    The server refuses to accept the request without a defined Content- Length. 
    The client MAY repeat the request if it adds a valid Content-Length header 
    field containing the length of the message-body in the request message.
    """
    status_code = 411

class PreconditionFailed(HttpResponseError):
    """
    The precondition given in one or more of the request-header fields evaluated 
    to false when it was tested on the server. This response code allows the client 
    to place preconditions on the current resource metainformation (header field data) 
    and thus prevent the requested method from being applied to a resource other than 
    the one intended.
    """
    status_code = 412

class RequestEntityTooLarge(HttpResponseError):
    """
    The server is refusing to process a request because the request entity is larger 
    than the server is willing or able to process. The server MAY close the connection 
    to prevent the client from continuing the request.

    If the condition is temporary, the server SHOULD include a Retry-After header 
    field to indicate that it is temporary and after what time the client MAY try again.
    """
    status_code = 413

class RequestURITooLong(HttpResponseError):
    """
    The server is refusing to service the request because the Request-URI is longer 
    than the server is willing to interpret. This rare condition is only likely to 
    occur when a client has improperly converted a POST request to a GET request with 
    long query information, when the client has descended into a URI "black hole" of 
    redirection (e.g., a redirected URI prefix that points to a suffix of itself), or 
    when the server is under attack by a client attempting to exploit security holes 
    present in some servers using fixed-length buffers for reading or manipulating 
    the Request-URI.
    """
    status_code = 414

class UnsupportedMediaType(HttpResponseError):
    """
    The server is refusing to service the request because the entity of the request 
    is in a format not supported by the requested resource for the requested method.
    """
    status_code = 415
    
class RequestedRangeNotSatisfiable(HttpResponseError):
    """
    A server SHOULD return a response with this status code if a request included a 
    Range request-header field (section 14.35), and none of the range-specifier 
    values in this field overlap the current extent of the selected resource, and 
    the request did not include an If-Range request-header field. (For byte-ranges, 
    this means that the first- byte-pos of all of the byte-range-spec values were 
    greater than the current length of the selected resource.)

    When this status code is returned for a byte-range request, the response SHOULD 
    include a Content-Range entity-header field specifying the current length of the 
    selected resource. This response MUST NOT use the multipart/byteranges content-type.
    """
    status_code = 416

class ExpectationFailed(HttpResponseError):
    """
    The expectation given in an Expect request-header field could not be met by 
    this server, or, if the server is a proxy, the server has unambiguous evidence 
    that the request could not be met by the next-hop server.
    """
    status_code = 417

class ImATeapot(HttpResponseError):
    """
    This code was defined in 1998 as one of the traditional IETF April Fools' jokes, 
    in RFC 2324, Hyper Text Coffee Pot Control Protocol, and is not expected to be 
    implemented by actual HTTP servers. However, known implementations do exist.
    
    http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 418
    
class UnprocessableEntity(HttpResponseError):
    """
    The request was well-formed but was unable to be followed due to semantic 
    errors.
    
    RFC 2324, via http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 422

class Locked(HttpResponseError):
    """
    The resource that is being accessed is Locked.
    
    WebDAV: RFC 4918, via http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 423

class FailedDependency(HttpResponseError):
    """
    Request failed due to the failure of the previous request. (eg, a PROPPATCH)
    
    WebDAV: RFC 4918, via http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 424

class UnorderedCollection(HttpResponseError):
    """
    Defined in drafts of "WebDAV Advanced Collections Protocol", but not present 
    in "Web Distributed Authoring and Versioning (WebDAV) Ordered Collections 
    Protocol".
    
    WebDAV: RFC 3648, via http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 425

class UpgradeRequired(HttpResponseError):
    """
    The client should switch to a different protocol such as TLS/1.0.
    
    http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 426

class PreconditionRequired(HttpResponseError):
    """
    The origin server requires the request to be conditional. Intended to prevent 
    "the 'lost update' problem, where a client GETs a resource's state, modifies 
    it, and PUTs it back to the server, when meanwhile a third party has modified 
    the state on the server, leading to a conflict."
    
    http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 428

class TooManyRequests(HttpResponseError):
    """
    The user has sent too many requests in a given amount of time. 
    Intended for use with rate limiting schemes.
    
    http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 429

class RequestHeaderFieldsTooLarge(HttpResponseError):
    """
    The server is unwilling to process the request because either an individual 
    header field, or all the header fields collectively, are too large.
    
    http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 431

class NoResponse(HttpResponseError):
    """
    An nginx HTTP server extension. The server returns no information to the 
    client and closes the connection (useful as a deterrent for malware).
    
    http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 444
    
class RetryWith(LocationHeaderMixin, HttpResponseError):
    """
    The 449 Retry With status code indicates that the request cannot be satisfied 
    because insufficient information was provided by the client.
    
    From: http://msdn.microsoft.com/en-us/library/dd891478(v=prot.10).aspx
    """
    status_code = 449

class ClientClosedRequest(HttpResponseError):
    """
    An Nginx HTTP server extension. This code is introduced to log the case when 
    the connection is closed by client while HTTP server is processing its request, 
    making server unable to send the HTTP header back.
    
    http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 499

#####################################
#
#   5xx Status Codes: Server Error
#
#####################################

class HttpResponseServerError(BaseHttpResponse):
    """
    The server failed to fulfill an apparently valid request.
    
    Response status codes beginning with the digit "5" indicate cases in 
    which the server is aware that it has encountered an error or is 
    otherwise incapable of performing the request. Except when responding 
    to a HEAD request, the server should include an entity containing an 
    explanation of the error situation, and indicate whether it is a 
    temporary or permanent condition. Likewise, user agents should display 
    any included entity to the user. These response codes are applicable to 
    any request method.
    
    http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    pass

class InternalServerError(HttpResponseServerError):
    """
    The server encountered an unexpected condition which prevented it from fulfilling 
    the request.
    """
    status_code = 500

class NotImplemented(HttpResponseServerError):
    """
    The server does not support the functionality required to fulfill the request. 
    This is the appropriate response when the server does not recognize the request 
    method and is not capable of supporting it for any resource.
    """
    status_code = 501

class BadGateway(HttpResponseServerError):
    """
    The server, while acting as a gateway or proxy, received an invalid response 
    from the upstream server it accessed in attempting to fulfill the request.
    """
    status_code = 502
        
class ServiceNotAvailable(HttpResponseServerError):
    """
    The server is currently unable to handle the request due to a temporary 
    overloading or maintenance of the server. The implication is that this is a 
    temporary condition which will be alleviated after some delay. If known, the 
    length of the delay MAY be indicated in a Retry-After header. If no Retry-After 
    is given, the client SHOULD handle the response as it would for a 500 response.

    ..note:: The existence of the 503 status code does not imply that a
      server must use it when becoming overloaded. Some servers may wish
      to simply refuse the connection.
    """
    status_code = 503
    
    def __init__(self, data=_(u"Server unavailable."), time=120):
        super(ServiceNotAvailable, self).__init__(data)
        self['Retry-After'] = time

class ServiceUnavailable(ServiceNotAvailable):
    """
    Convenience class for different spelling.
    """
    pass

class GatewayTimeout(HttpResponseServerError):
    """
    The server, while acting as a gateway or proxy, did not receive a timely response 
    from the upstream server specified by the URI (e.g. HTTP, FTP, LDAP) or some other 
    auxiliary server (e.g. DNS) it needed to access in attempting to complete the 
    request.

    ..note:: Note to implementors: some deployed proxies are known to
      return 400 or 500 when DNS lookups time out.
    """
    status_code = 504

class HttpVersionNotSupported(HttpResponseServerError):
    """
    The server does not support, or refuses to support, the HTTP protocol version 
    that was used in the request message. The server is indicating that it is unable 
    or unwilling to complete the request using the same major version as the client, 
    other than with this error message. The response SHOULD contain an entity 
    describing why that version is not supported and what other protocols are 
    supported by that server.
    """
    status_code = 505

class VariantAlsoNegotiates(HttpResponseServerError):
    """
    Transparent content negotiation for the request results in a circular reference.
    
    RFC 2295, via http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 506

class InsufficientStorage(HttpResponseServerError):
    """
    The server is unable to store the representation needed to complete the request.
    
    WebDAV: RFC 4918, via http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 507

class LoopDetected(HttpResponseServerError):
    """
    The server detected an infinite loop while processing the request 
    (sent in lieu of 208).
    
    WebDAV: RFC 5842, via http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 508

class BandwithLimitExceeded(HttpResponseServerError):
    """
    This status code, while used by many servers, is not specified in any RFCs.
    
    http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 509

class NotExtended(HttpResponseServerError):
    """
    Further extensions to the request are required for the server to fulfill it.
    
    http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 510
    

class NetworkAuthenticationRequired(HttpResponseServerError):
    """
    The client needs to authenticate to gain network access. Intended for 
    use by intercepting proxies used to control access to the network (e.g. 
    "captive portals" used to require agreement to Terms of Service before 
    granting full Internet access via a Wi-Fi hotspot)
    
    http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 511
    
class NetworkReadTimeout(HttpResponseServerError):
    """
    This status code is not specified in any RFCs, but is used by some 
    HTTP proxies to signal a network read timeout behind the proxy to a 
    client in front of the proxy.
    
    http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 598
    
class NetworkConnectTimeout(HttpResponseServerError):
    """
    This status code is not specified in any RFCs, but is used by some
    HTTP proxies to signal a network connect timeout behind the proxy 
    to a client in front of the proxy.
    
    http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
    """
    status_code = 599