web/request.py
changeset 8314 cfd6ab461849
parent 8312 6c2119509fac
child 8316 d5b1b75805dd
equal deleted inserted replaced
8313:386b6313de28 8314:cfd6ab461849
    23 import random
    23 import random
    24 import base64
    24 import base64
    25 from hashlib import sha1 # pylint: disable=E0611
    25 from hashlib import sha1 # pylint: disable=E0611
    26 from Cookie import SimpleCookie
    26 from Cookie import SimpleCookie
    27 from calendar import timegm
    27 from calendar import timegm
    28 from datetime import date
    28 from datetime import date, datetime
    29 from urlparse import urlsplit
    29 from urlparse import urlsplit
    30 from itertools import count
    30 from itertools import count
    31 from warnings import warn
    31 from warnings import warn
    32 
    32 
    33 from rql.utils import rqlvar_maker
    33 from rql.utils import rqlvar_maker
    84     """abstract HTTP request, should be extended according to the HTTP backend
    84     """abstract HTTP request, should be extended according to the HTTP backend
    85     Immutable attributes that describe the received query and generic configuration
    85     Immutable attributes that describe the received query and generic configuration
    86     """
    86     """
    87     ajax_request = False # to be set to True by ajax controllers
    87     ajax_request = False # to be set to True by ajax controllers
    88 
    88 
    89     def __init__(self, vreg, https=False, form=None):
    89     def __init__(self, vreg, https=False, form=None, headers={}):
    90         """
    90         """
    91         :vreg: Vregistry,
    91         :vreg: Vregistry,
    92         :https: boolean, s this a https request
    92         :https: boolean, s this a https request
    93         :form: Forms value
    93         :form: Forms value
    94         """
    94         """
   105         else:
   105         else:
   106             self.uiprops = vreg.config.uiprops
   106             self.uiprops = vreg.config.uiprops
   107             self.datadir_url = vreg.config.datadir_url
   107             self.datadir_url = vreg.config.datadir_url
   108         #: raw html headers that can be added from any view
   108         #: raw html headers that can be added from any view
   109         self.html_headers = HTMLHead(self)
   109         self.html_headers = HTMLHead(self)
       
   110         #: received headers
       
   111         self._headers_in = Headers()
       
   112         for k, v in headers.iteritems():
       
   113             self._headers_in.addRawHeader(k, v)
   110         #: form parameters
   114         #: form parameters
   111         self.setup_params(form)
   115         self.setup_params(form)
   112         #: dictionary that may be used to store request data that has to be
   116         #: dictionary that may be used to store request data that has to be
   113         #: shared among various components used to publish the request (views,
   117         #: shared among various components used to publish the request (views,
   114         #: controller, application...)
   118         #: controller, application...)
   303         """
   307         """
   304         if form is None:
   308         if form is None:
   305             form = self.form
   309             form = self.form
   306         return list_form_param(form, param, pop)
   310         return list_form_param(form, param, pop)
   307 
   311 
   308 
       
   309     def reset_headers(self):
   312     def reset_headers(self):
   310         """used by AutomaticWebTest to clear html headers between tests on
   313         """used by AutomaticWebTest to clear html headers between tests on
   311         the same resultset
   314         the same resultset
   312         """
   315         """
   313         self.html_headers = HTMLHead(self)
   316         self.html_headers = HTMLHead(self)
   776         :param includeparams:
   779         :param includeparams:
   777            boolean indicating if GET form parameters should be kept in the path
   780            boolean indicating if GET form parameters should be kept in the path
   778         """
   781         """
   779         raise NotImplementedError()
   782         raise NotImplementedError()
   780 
   783 
   781     def get_header(self, header, default=None):
   784     # http headers ############################################################
   782         """return the value associated with the given input HTTP header,
   785 
   783         raise KeyError if the header is not set
   786     ### incoming headers
   784         """
   787 
   785         raise NotImplementedError()
   788     def get_header(self, header, default=None, raw=True):
   786 
   789         """return the value associated with the given input header, raise
       
   790         KeyError if the header is not set
       
   791         """
       
   792         if raw:
       
   793             return self._headers_in.getRawHeaders(header, [default])[0]
       
   794         return self._headers_in.getHeader(header, default)
       
   795 
       
   796     def header_accept_language(self):
       
   797         """returns an ordered list of preferred languages"""
       
   798         acceptedlangs = self.get_header('Accept-Language', raw=False) or {}
       
   799         for lang, _ in sorted(acceptedlangs.iteritems(), key=lambda x: x[1],
       
   800                               reverse=True):
       
   801             lang = lang.split('-')[0]
       
   802             yield lang
       
   803 
       
   804     def header_if_modified_since(self):
       
   805         """If the HTTP header If-modified-since is set, return the equivalent
       
   806         date time value (GMT), else return None
       
   807         """
       
   808         mtime = self.get_header('If-modified-since', raw=False)
       
   809         if mtime:
       
   810             # :/ twisted is returned a localized time stamp
       
   811             return datetime.fromtimestamp(mtime) + GMTOFFSET
       
   812         return None
       
   813 
       
   814     ### outcoming headers
   787     def set_header(self, header, value, raw=True):
   815     def set_header(self, header, value, raw=True):
   788         """set an output HTTP header"""
   816         """set an output HTTP header"""
   789         if raw:
   817         if raw:
   790             # adding encoded header is important, else page content
   818             # adding encoded header is important, else page content
   791             # will be reconverted back to unicode and apart unefficiency, this
   819             # will be reconverted back to unicode and apart unefficiency, this
   829             value_parser = value_sort_key = None
   857             value_parser = value_sort_key = None
   830         accepteds = self.get_header(header, '')
   858         accepteds = self.get_header(header, '')
   831         values = _parse_accept_header(accepteds, value_parser, value_sort_key)
   859         values = _parse_accept_header(accepteds, value_parser, value_sort_key)
   832         return (raw_value for (raw_value, parsed_value, score) in values)
   860         return (raw_value for (raw_value, parsed_value, score) in values)
   833 
   861 
   834     def header_if_modified_since(self):
       
   835         """If the HTTP header If-modified-since is set, return the equivalent
       
   836         mx date time value (GMT), else return None
       
   837         """
       
   838         raise NotImplementedError()
       
   839 
       
   840     def demote_to_html(self):
   862     def demote_to_html(self):
   841         """helper method to dynamically set request content type to text/html
   863         """helper method to dynamically set request content type to text/html
   842 
   864 
   843         The global doctype and xmldec must also be changed otherwise the browser
   865         The global doctype and xmldec must also be changed otherwise the browser
   844         will display '<[' at the beginning of the page
   866         will display '<[' at the beginning of the page
   848                 raise Exception("Can't demote to html from an ajax context. You "
   870                 raise Exception("Can't demote to html from an ajax context. You "
   849                                 "should change force-html-content-type to yes "
   871                                 "should change force-html-content-type to yes "
   850                                 "in the instance configuration file.")
   872                                 "in the instance configuration file.")
   851             self.set_content_type('text/html')
   873             self.set_content_type('text/html')
   852             self.main_stream.set_doctype(TRANSITIONAL_DOCTYPE_NOEXT)
   874             self.main_stream.set_doctype(TRANSITIONAL_DOCTYPE_NOEXT)
       
   875 
       
   876     # xml doctype #############################################################
   853 
   877 
   854     def set_doctype(self, doctype, reset_xmldecl=True):
   878     def set_doctype(self, doctype, reset_xmldecl=True):
   855         """helper method to dynamically change page doctype
   879         """helper method to dynamically change page doctype
   856 
   880 
   857         :param doctype: the new doctype, e.g. '<!DOCTYPE html>'
   881         :param doctype: the new doctype, e.g. '<!DOCTYPE html>'