Beispiel #1
0
 def test_matcher_functional_newstyle(self):
     self.matches('/{x}', '', None)
     self.matches('/{x}', '/', None)
     self.matches('/abc/{def}', '/abc/', None)
     self.matches('/{x}', '/a', {'x':'a'})
     self.matches('zzz/{x}', '/zzz/abc', {'x':'abc'})
     self.matches('zzz/{x}*traverse', '/zzz/abc', {'x':'abc', 'traverse':()})
     self.matches('zzz/{x}*traverse', '/zzz/abc/def/g',
                  {'x':'abc', 'traverse':('def', 'g')})
     self.matches('*traverse', '/zzz/abc', {'traverse':('zzz', 'abc')})
     self.matches('*traverse', '/zzz/ abc', {'traverse':('zzz', ' abc')})
     #'/La%20Pe%C3%B1a'
     self.matches('{x}', native_(b'/La Pe\xc3\xb1a'),
                  {'x':text_(b'La Pe\xf1a')})
     # '/La%20Pe%C3%B1a/x'
     self.matches('*traverse', native_(b'/La Pe\xc3\xb1a/x'),
                  {'traverse':(text_(b'La Pe\xf1a'), 'x')})
     self.matches('/foo/{id}.html', '/foo/bar.html', {'id':'bar'})
     self.matches('/{num:[0-9]+}/*traverse', '/555/abc/def',
                  {'num':'555', 'traverse':('abc', 'def')})
     self.matches('/{num:[0-9]*}/*traverse', '/555/abc/def',
                  {'num':'555', 'traverse':('abc', 'def')})
     self.matches('zzz/{_}', '/zzz/abc', {'_':'abc'})
     self.matches('zzz/{_abc}', '/zzz/abc', {'_abc':'abc'})
     self.matches('zzz/{abc_def}', '/zzz/abc', {'abc_def':'abc'})
def oauth_response(result):
    headers, body, status = result
    return Response(
        body=body,
        status=status,
        headers={
            native_(name, encoding="latin-1"): native_(value, encoding="latin-1") for name, value in headers.items()
        },
    )
Beispiel #3
0
def oauth_response(result):
    headers, body, status = result
    headerlist = headers.items() if hasattr(headers, 'items') else headers

    return Response(body=body, status=status, charset='utf-8', headerlist=[
        (native_(name, encoding='latin-1'), native_(value, encoding='latin-1'))
        for name, value
        in headerlist
    ])
Beispiel #4
0
def oauth_response(result):
    headers, body, status = result

    if isinstance(headers, dict):
        header_iter = headers.items()
    else:
        header_iter = headers

    return Response(body=body, status=status, headerlist=[
        (native_(name, encoding='latin-1'), native_(value, encoding='latin-1'))
        for name, value
        in header_iter
    ])
Beispiel #5
0
 def test_post_collection_warning_exception(self):
     # First POST - get back a 307.
     res1 = self.app.post(self.path, params='foo name',
                          status=307)
     body_text = native_(res1.body.rstrip(), encoding='utf-8')
     self.assert_true(body_text.endswith(
                                 UserMessagePostCollectionView.message))
     self.assert_true(res1.body.startswith(b'307 Temporary Redirect'))
     # Second POST to redirection location - get back a 201.
     resubmit_location1 = res1.headers['Location']
     res2 = self.app.post(resubmit_location1,
                          params='foo name',
                          status=201)
     self.assert_true(not res2 is None)
     # Third POST to same redirection location with different warning
     # message triggers a 307 again.
     old_msg = UserMessagePostCollectionView.message
     UserMessagePostCollectionView.message = old_msg[::-1]
     try:
         res3 = self.app.post(resubmit_location1,
                              params='foo name',
                              status=307)
         self.assert_true(res3.body.startswith(b'307 Temporary Redirect'))
         # Fourth POST to new redirection location - get back a 409 (since
         # the second POST from above went through).
         resubmit_location2 = res3.headers['Location']
         res4 = self.app.post(resubmit_location2,
                              params='foo name',
                              status=409)
         self.assert_true(not res4 is None)
     finally:
         UserMessagePostCollectionView.message = old_msg
Beispiel #6
0
 def test_resource_url_anchor_is_encoded_utf8_if_unicode(self):
     request = self._makeOne()
     self._registerResourceURL(request.registry)
     context = DummyContext()
     uc = text_(b"La Pe\xc3\xb1a", "utf-8")
     result = request.resource_url(context, anchor=uc)
     self.assertEqual(result, native_(text_(b"http://example.com:5432/context/#La Pe\xc3\xb1a", "utf-8"), "utf-8"))
Beispiel #7
0
 def template_renderer(self, content, vars, filename=None):
     content = native_(content, fsenc)
     try:
         return bytes_(
             substitute_double_braces(content, TypeMapper(vars)), fsenc)
     except Exception as e:
         _add_except(e, ' in file %s' % filename)
         raise
def generate_secret(length=40):
    """
    Returns a random ascii hash of the specified length (default is 40).

    .. note:: Due to the way the secret is generated, ``length`` should always
              be an even number.
    """
    return native_(binascii.hexlify(os.urandom(int(length / 2))))
Beispiel #9
0
 def pre(self, command, output_dir, vars):
     vars["random_string"] = native_(binascii.hexlify(os.urandom(20)))
     package_logger = vars["package"]
     if package_logger == "root":
         # Rename the app logger in the rare case a project is named 'root'
         package_logger = "app"
     vars["package_logger"] = package_logger
     return Template.pre(self, command, output_dir, vars)
Beispiel #10
0
 def test_get_collection_with_refs_options(self):
     # The links options are not processed by the renderers, so we need
     # a native everest view with a defined response MIME type.
     self.config.add_resource_view(IMyEntity,
                                   default_response_content_type=CsvMime,
                                   request_method=RequestMethods.GET)
     create_collection()
     res1 = self.app.get(self.path, params=dict(refs='parent:OFF'),
                        status=200)
     self.assert_is_not_none(res1)
     self.assert_equal(native_(res1.body).find(',"parent",'), -1)
     self.assert_equal(native_(res1.body).find(',"parent.id",'), -1)
     res2 = self.app.get(self.path, params=dict(refs='parent:INLINE'),
                        status=200)
     self.assert_is_not_none(res2)
     self.assert_equal(native_(res2.body).find(',"parent",'), -1)
     self.assert_not_equal(native_(res2.body).find(',"parent.id",'), -1)
Beispiel #11
0
 def pre(self, command, output_dir, vars):
     vars['random_string'] = native_(binascii.hexlify(os.urandom(20)))
     package_logger = vars['package']
     if package_logger == 'root':
         # Rename the app logger in the rare case a project is named 'root'
         package_logger = 'app'
     vars['package_logger'] = package_logger
     return Template.pre(self, command, output_dir, vars)
Beispiel #12
0
    def test_route_url_with_anchor_binary(self):
        from pyramid.interfaces import IRoutesMapper

        request = self._makeOne()
        mapper = DummyRoutesMapper(route=DummyRoute("/1/2/3"))
        request.registry.registerUtility(mapper, IRoutesMapper)
        result = request.route_url("flub", _anchor=b"La Pe\xc3\xb1a")

        self.assertEqual(result, native_(text_(b"http://example.com:5432/1/2/3#La Pe\xc3\xb1a", "utf-8"), "utf-8"))
 def test_non_utf8_path_segment_settings_unicode_path_segments_fails(self):
     from pyramid.exceptions import URLDecodeError
     foo = DummyContext()
     root = DummyContext(foo)
     policy = self._makeOne(root)
     segment = native_(text_(b'LaPe\xc3\xb1a', 'utf-8'), 'utf-16')
     environ = self._getEnviron(PATH_INFO='/%s' % segment)
     request = DummyRequest(environ)
     self.assertRaises(URLDecodeError, policy, request)
Beispiel #14
0
def normalize(title):
    """
    make an URL resource name ready for use in a URL. Essentially it
    takes a string representing an id or title and makes it character
    safe for use in a URL. In ``lumin`` this is likely to be the
    :term:`_id` or the :term:`__name__` by which we find the resource.
    """
    url_safer = unicodedata.normalize('NFKD', title).encode('ascii', 'ignore')
    url_safe = re.sub('[^\w\s-]', '', native_(url_safer, encoding="utf8")).strip().lower()
    return re.sub('[-\s]+', '-', url_safe)
Beispiel #15
0
 def test_subpath_path_info_and_script_name_have_utf8(self):
     encoded = native_(text_(b"La Pe\xc3\xb1a"))
     decoded = text_(bytes_(encoded), "utf-8")
     request = DummyRequest({"PATH_INFO": "/" + encoded, "SCRIPT_NAME": "/" + encoded})
     request.subpath = (decoded,)
     response = self._callFUT(request, "app")
     self.assertTrue(request.copied)
     self.assertEqual(response, "app")
     self.assertEqual(request.environ["SCRIPT_NAME"], "/" + encoded)
     self.assertEqual(request.environ["PATH_INFO"], "/" + encoded)
Beispiel #16
0
def serialize(data, secret):
    import hmac
    import base64
    from hashlib import sha1
    from pyramid.compat import bytes_
    from pyramid.compat import native_
    from pyramid.compat import pickle
    pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
    sig = hmac.new(bytes_(secret, 'utf-8'), pickled, sha1).hexdigest()
    return sig + native_(base64.b64encode(pickled))
Beispiel #17
0
 def test_post_collection_no_id(self):
     req_body = b'"text","number"\n"abc",2\n'
     res = self.app.post("%s" % self.path,
                         params=req_body,
                         content_type=CsvMime.mime_type_string,
                         status=201)
     self.assert_is_not_none(res)
     self.assert_true(res.headers['Location'].endswith(self.path))
     self.assert_not_equal(native_(res.body).split(os.linesep)[1][:2],
                           '""')
Beispiel #18
0
 def test_handler_w_unicode_unauthenticated_userid(self):
     from pyramid.compat import native_
     from pyramid_tm.compat import PY3
     USERID = b'phred/\xd1\x80\xd0\xb5\xd1\x81'.decode('utf-8')
     self.config.testing_securitypolicy(userid=USERID)
     self._callFUT()
     if PY3:  # pragma: no cover Py3k
         self.assertEqual(self.txn.username, ' phred/рес')
     else:
         self.assertEqual(self.txn.username,
                          ' ' + native_(USERID, 'utf-8'))
Beispiel #19
0
 def test_subpath_path_info_and_script_name_have_utf8(self):
     encoded = native_(text_(b'La Pe\xc3\xb1a'))
     decoded = text_(bytes_(encoded), 'utf-8')
     request = DummyRequest({'PATH_INFO':'/' + encoded,
                             'SCRIPT_NAME':'/' + encoded})
     request.subpath = (decoded, )
     response = self._callFUT(request, 'app')
     self.assertTrue(request.copied)
     self.assertEqual(response, 'app')
     self.assertEqual(request.environ['SCRIPT_NAME'], '/' + encoded)
     self.assertEqual(request.environ['PATH_INFO'], '/' + encoded)
Beispiel #20
0
def call_app_with_subpath_as_path_info(request, app):
    # Copy the request.  Use the source request's subpath (if it exists) as
    # the new request's PATH_INFO.  Set the request copy's SCRIPT_NAME to the
    # prefix before the subpath.  Call the application with the new request
    # and return a response.
    #
    # Postconditions:
    # - SCRIPT_NAME and PATH_INFO are empty or start with /
    # - At least one of SCRIPT_NAME or PATH_INFO are set.
    # - SCRIPT_NAME is not '/' (it should be '', and PATH_INFO should
    #   be '/').

    environ = request.environ
    script_name = environ.get('SCRIPT_NAME', '')
    path_info = environ.get('PATH_INFO', '/')
    subpath = list(getattr(request, 'subpath', ()))

    new_script_name = ''

    # compute new_path_info
    new_path_info = '/' + '/'.join(
        [native_(x.encode('utf-8'), 'latin-1') for x in subpath])

    if new_path_info != '/':  # don't want a sole double-slash
        if path_info != '/':  # if orig path_info is '/', we're already done
            if path_info.endswith('/'):
                # readd trailing slash stripped by subpath (traversal)
                # conversion
                new_path_info += '/'

    # compute new_script_name
    workback = (script_name + path_info).split('/')

    tmp = []
    while workback:
        if tmp == subpath:
            break
        el = workback.pop()
        if el:
            tmp.insert(0, text_(bytes_(el, 'latin-1'), 'utf-8'))

    # strip all trailing slashes from workback to avoid appending undue slashes
    # to end of script_name
    while workback and (workback[-1] == ''):
        workback = workback[:-1]

    new_script_name = '/'.join(workback)

    new_request = request.copy()
    new_request.environ['SCRIPT_NAME'] = new_script_name
    new_request.environ['PATH_INFO'] = new_path_info

    return new_request.get_response(app)
Beispiel #21
0
 def pre(self, command, output_dir, vars):
     if vars['package'] == 'site':
         raise ValueError('Sorry, you may not name your package "site". '
                          'The package name "site" has a special meaning in '
                          'Python.  Please name it anything except "site".')
     vars['random_string'] = native_(binascii.hexlify(os.urandom(20)))
     package_logger = vars['package']
     if package_logger == 'root':
         # Rename the app logger in the rare case a project is named 'root'
         package_logger = 'app'
     vars['package_logger'] = package_logger
     return Template.pre(self, command, output_dir, vars)
Beispiel #22
0
def call_app_with_subpath_as_path_info(request, app):
    # Copy the request.  Use the source request's subpath (if it exists) as
    # the new request's PATH_INFO.  Set the request copy's SCRIPT_NAME to the
    # prefix before the subpath.  Call the application with the new request
    # and return a response.
    #
    # Postconditions:
    # - SCRIPT_NAME and PATH_INFO are empty or start with /
    # - At least one of SCRIPT_NAME or PATH_INFO are set.
    # - SCRIPT_NAME is not '/' (it should be '', and PATH_INFO should
    #   be '/').

    environ = request.environ
    script_name = environ.get('SCRIPT_NAME', '')
    path_info = environ.get('PATH_INFO', '/')
    subpath = list(getattr(request, 'subpath', ()))

    new_script_name = ''

    # compute new_path_info
    new_path_info = '/' + '/'.join([native_(x.encode('utf-8'), 'latin-1')
                                    for x in subpath])

    if new_path_info != '/': # don't want a sole double-slash
        if path_info != '/': # if orig path_info is '/', we're already done
            if path_info.endswith('/'):
                # readd trailing slash stripped by subpath (traversal)
                # conversion
                new_path_info += '/'

    # compute new_script_name
    workback = (script_name + path_info).split('/')

    tmp = []
    while workback:
        if tmp == subpath:
            break
        el = workback.pop()
        if el:
            tmp.insert(0, text_(bytes_(el, 'latin-1'), 'utf-8'))

    # strip all trailing slashes from workback to avoid appending undue slashes
    # to end of script_name
    while workback and (workback[-1] == ''):
        workback = workback[:-1]

    new_script_name = '/'.join(workback)

    new_request = request.copy()
    new_request.environ['SCRIPT_NAME'] = new_script_name
    new_request.environ['PATH_INFO'] = new_path_info

    return new_request.get_response(app)
Beispiel #23
0
    def test_route_url_with_anchor_binary(self):
        from pyramid.interfaces import IRoutesMapper
        request = self._makeOne()
        mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
        request.registry.registerUtility(mapper, IRoutesMapper)
        result = request.route_url('flub', _anchor=b"La Pe\xc3\xb1a")

        self.assertEqual(
            result,
            native_(
                text_(b'http://example.com:5432/1/2/3#La Pe\xc3\xb1a',
                      'utf-8'), 'utf-8'))
Beispiel #24
0
def create_version_hash(uri_dict, request):
    '''
    Turn a response into a version hash.

    :param dict uri_dict:
    :param pyramid.request.Request request:
    :rtype: str
    '''
    json = render(renderer_name='json', value=uri_dict, request=request)
    hash = native_(
        base64.b64encode(hashlib.md5(bytes_(json, encoding='UTF-8')).digest()), encoding='UTF-8')
    return hash.strip('=')
Beispiel #25
0
 def test_post_collection_no_id(self,
                                view_app_creator): # pylint:disable=W0621
     # This only works in the memory backend because of the referential
     # constraint of the parent attribute.
     req_body = b'"text","number"\n"abc",2\n'
     res = view_app_creator.post("%s" % self.path,
                                 params=req_body,
                                 content_type=CsvMime.mime_type_string,
                                 status=201)
     assert not res is None
     assert res.headers['Location'].endswith(self.path)
     assert native_(res.body).split(os.linesep)[1][:2] != '""'
Beispiel #26
0
def serialize(data, secret):
    from pyramid.compat import (
        pickle,
        bytes_,
        native_
        )
    from hashlib import sha1
    import hmac
    import base64
    pickled = pickle.dumps('123', pickle.HIGHEST_PROTOCOL)
    sig = hmac.new(bytes_(secret), pickled, sha1).hexdigest()
    return sig + native_(base64.b64encode(pickled))
Beispiel #27
0
 def __record_message(self, logging_level, message):
     do_record = True
     if logging_level >= logging.ERROR:
         do_record = not self._disable_err_warn_rec
         if do_record:
             self._error_count += 1
         self.abort_execution = True
     if do_record:
         msg = "%s - %s" % (self.__name, native_(message))
         evt = (logging_level, msg)
          # pylint:disable=W0212
         self._root_recorder._message_stack.append(evt)
         self._root_recorder._logger.log(*evt)
Beispiel #28
0
def get_callable_name(name):
    """
    Verifies that the ``name`` is ascii and will raise a ``ConfigurationError``
    if it is not.
    """
    try:
        return native_(name, 'ascii')
    except (UnicodeEncodeError, UnicodeDecodeError):
        msg = (
            '`name="%s"` is invalid. `name` must be ascii because it is '
            'used on __name__ of the method'
        )
        raise ConfigurationError(msg % name)
Beispiel #29
0
 def generator(dict):
     newdict = {}
     for k, v in dict.items():
         if v.__class__ is text_type:
             v = native_(v, "utf-8")
         if k == star and is_nonstr_iter(v):
             v = "/".join([quote_path_segment(x) for x in v])
         elif k != star:
             if v.__class__ not in string_types:
                 v = str(v)
             v = url_quote(v, safe="")
         newdict[k] = v
     return gen % newdict
Beispiel #30
0
 def pre(self, command, output_dir, vars):
     if vars['package'] == 'site':
         raise ValueError(
             'Sorry, you may not name your package "site". '
             'The package name "site" has a special meaning in '
             'Python.  Please name it anything except "site".')
     vars['random_string'] = native_(binascii.hexlify(os.urandom(20)))
     package_logger = vars['package']
     if package_logger == 'root':
         # Rename the app logger in the rare case a project is named 'root'
         package_logger = 'app'
     vars['package_logger'] = package_logger
     return Template.pre(self, command, output_dir, vars)
Beispiel #31
0
        def _save_session(self, response):
            if not self._cookie_on_exception:
                exception = getattr(self.request, 'exception', None)
                if exception is not None:  # dont set a cookie during exceptions
                    return False

            sess_val = native_(
                serializer.dumps((self.accessed, self.created, dict(self))))

            self._plug.dumps(self, self.request, sess_val)
            self._cookie.set_cookies(response, self._session_id)

            return True
Beispiel #32
0
 def generator(dict):
     newdict = {}
     for k, v in dict.items():
         if v.__class__ is text_type:
             v = native_(v, 'utf-8')
         if k == star and is_nonstr_iter(v):
             v = '/'.join([quote_path_segment(x) for x in v])
         elif k != star:
             if v.__class__ not in string_types:
                 v = str(v)
             v = url_quote(v, safe='')
         newdict[k] = v
     return gen % newdict
Beispiel #33
0
 def test_matcher_functional_oldstyle(self):
     self.matches('/:x', '', None)
     self.matches('/:x', '/', None)
     self.matches('/abc/:def', '/abc/', None)
     self.matches('/:x', '/a', {'x':'a'})
     self.matches('zzz/:x', '/zzz/abc', {'x':'abc'})
     self.matches('zzz/:x*traverse', '/zzz/abc', {'x':'abc', 'traverse':()})
     self.matches('zzz/:x*traverse', '/zzz/abc/def/g',
                  {'x':'abc', 'traverse':('def', 'g')})
     self.matches('*traverse', '/zzz/abc', {'traverse':('zzz', 'abc')})
     self.matches('*traverse', '/zzz/ abc', {'traverse':('zzz', ' abc')})
     #'/La%20Pe%C3%B1a'
     self.matches(':x', native_(b'/La Pe\xc3\xb1a'),
                  {'x':text_(b'La Pe\xf1a')})
     # '/La%20Pe%C3%B1a/x'
     self.matches('*traverse', native_(b'/La Pe\xc3\xb1a/x'),
                  {'traverse':(text_(b'La Pe\xf1a'), 'x')})
     self.matches('/foo/:id.html', '/foo/bar.html', {'id':'bar'})
     self.matches('/foo/:id_html', '/foo/bar_html', {'id_html':'bar_html'})
     self.matches('zzz/:_', '/zzz/abc', {'_':'abc'})
     self.matches('zzz/:_abc', '/zzz/abc', {'_abc':'abc'})
     self.matches('zzz/:abc_def', '/zzz/abc', {'abc_def':'abc'})
Beispiel #34
0
 def test_get_collection_with_refs_options(self,
                                 view_app_creator): # pylint:disable=W0621
     # The refs options are not processed by the renderers, so we need
     # a native everest view with a defined response MIME type.
     view_app_creator.config.add_resource_view(
                                 IMyEntity,
                                 default_response_content_type=CsvMime,
                                 request_method=RequestMethods.GET)
     res1 = view_app_creator.get(self.path, params=dict(refs='parent:OFF'),
                                 status=200)
     assert not res1 is None
     assert native_(res1.body).find(',"parent",') == -1
     assert native_(res1.body).find(',"parent.id",') == -1
     res2 = view_app_creator.get(self.path,
                                 params=dict(refs='parent:INLINE'),
                                 status=200)
     assert not res2 is None
     assert native_(res2.body).find(',"parent",') == -1
     assert native_(res2.body).find(',"parent.id",') != -1
     # Bogus refs parameters.
     view_app_creator.get(self.path, params=dict(refs='parent:XXX'),
                          status=500)
Beispiel #35
0
 def test_resource_url_anchor_is_encoded_utf8_if_unicode(self):
     request = self._makeOne()
     self._registerContextURL(request.registry)
     context = DummyContext()
     uc = text_(b'La Pe\xc3\xb1a', 'utf-8') 
     result = request.resource_url(context, anchor=uc)
     self.assertEqual(
         result,
         native_(
             text_(b'http://example.com/context/#La Pe\xc3\xb1a',
                   'utf-8'),
             'utf-8')
         )
Beispiel #36
0
def get_callable_name(name):
    """
    Verifies that the ``name`` is ascii and will raise a ``ConfigurationError``
    if it is not.
    """
    try:
        return native_(name, 'ascii')
    except (UnicodeEncodeError, UnicodeDecodeError):
        msg = (
            '`name="%s"` is invalid. `name` must be ascii because it is '
            'used on __name__ of the method'
        )
        raise ConfigurationError(msg % name)
Beispiel #37
0
 def __record_message(self, logging_level, message):
     do_record = True
     if logging_level >= logging.ERROR:
         do_record = not self._disable_err_warn_rec
         if do_record:
             self._error_count += 1
         self.abort_execution = True
     if do_record:
         msg = "%s - %s" % (self.__name, native_(message))
         evt = (logging_level, msg)
         # pylint:disable=W0212
         self._root_recorder._message_stack.append(evt)
         self._root_recorder._logger.log(*evt)
Beispiel #38
0
 def test_resource_url_anchor_is_encoded_utf8_if_unicode(self):
     request = self._makeOne()
     self._registerResourceURL(request.registry)
     context = DummyContext()
     uc = text_(b'La Pe\xc3\xb1a', 'utf-8') 
     result = request.resource_url(context, anchor=uc)
     self.assertEqual(
         result,
         native_(
             text_(b'http://example.com:5432/context/#La Pe\xc3\xb1a',
                   'utf-8'),
             'utf-8')
         )
Beispiel #39
0
 def test_subpath_path_info_and_script_name_have_utf8(self):
     encoded = native_(text_(b'La Pe\xc3\xb1a'))
     decoded = text_(bytes_(encoded), 'utf-8')
     request = DummyRequest({
         'PATH_INFO': '/' + encoded,
         'SCRIPT_NAME': '/' + encoded
     })
     request.subpath = (decoded, )
     response = self._callFUT(request, 'app')
     self.assertTrue(request.copied)
     self.assertEqual(response, 'app')
     self.assertEqual(request.environ['SCRIPT_NAME'], '/' + encoded)
     self.assertEqual(request.environ['PATH_INFO'], '/' + encoded)
Beispiel #40
0
 def test_get_collection_with_refs_options(self, view_app_creator):  # pylint:disable=W0621
     # The refs options are not processed by the renderers, so we need
     # a native everest view with a defined response MIME type.
     view_app_creator.config.add_resource_view(
         IMyEntity,
         default_response_content_type=CsvMime,
         request_method=RequestMethods.GET)
     res1 = view_app_creator.get(self.path,
                                 params=dict(refs='parent:OFF'),
                                 status=200)
     assert not res1 is None
     assert native_(res1.body).find(',"parent",') == -1
     assert native_(res1.body).find(',"parent.id",') == -1
     res2 = view_app_creator.get(self.path,
                                 params=dict(refs='parent:INLINE'),
                                 status=200)
     assert not res2 is None
     assert native_(res2.body).find(',"parent",') == -1
     assert native_(res2.body).find(',"parent.id",') != -1
     # Bogus refs parameters.
     view_app_creator.get(self.path,
                          params=dict(refs='parent:XXX'),
                          status=500)
Beispiel #41
0
 def pre(self, command, output_dir, vars):
     """ Overrides :meth:`pyramid.scaffolds.template.Template.pre`, adding
     several variables to the default variables list (including
     ``random_string``, and ``package_logger``).  It also prevents common
     misnamings (such as naming a package "site" or naming a package
     logger "root".
     """
     vars['random_string'] = native_(binascii.hexlify(os.urandom(20)))
     package_logger = vars['package']
     if package_logger == 'root':
         # Rename the app logger in the rare case a project is named 'root'
         package_logger = 'app'
     vars['package_logger'] = package_logger
     return Template.pre(self, command, output_dir, vars)
Beispiel #42
0
def signed_serialize(data, secret):
    """ Serialize any pickleable structure (``data``) and sign it
    using the ``secret`` (must be a string).  Return the
    serialization, which includes the signature as its first 40 bytes.
    The ``signed_deserialize`` method will deserialize such a value.

    This function is useful for creating signed cookies.  For example:

    .. code-block:: python

       cookieval = signed_serialize({'a':1}, 'secret')
       response.set_cookie('signed_cookie', cookieval)
    """
    pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
    sig = hmac.new(bytes_(secret), pickled, sha1).hexdigest()
    return sig + native_(base64.b64encode(pickled))
Beispiel #43
0
 def quote_path_segment(segment, safe=''):
     """ %s """ % quote_path_segment_doc
     # The bit of this code that deals with ``_segment_cache`` is an
     # optimization: we cache all the computation of URL path segments
     # in this module-scope dictionary with the original string (or
     # unicode value) as the key, so we can look it up later without
     # needing to reencode or re-url-quote it
     try:
         return _segment_cache[(segment, safe)]
     except KeyError:
         if segment.__class__ not in (text_type, binary_type):
             segment = str(segment)
         result = url_quote(native_(segment, 'utf-8'), safe)
         # we don't need a lock to mutate _segment_cache, as the below
         # will generate exactly one Python bytecode (STORE_SUBSCR)
         _segment_cache[(segment, safe)] = result
         return result
Beispiel #44
0
 def render_template(self, content, vars, filename=None):
     """ Return a bytestring representing a templated file based on the
     input (content) and the variable names defined (vars).  ``filename``
     is used for exception reporting."""
     # this method must not be named "template_renderer" fbo of extension
     # scaffolds that need to work under pyramid 1.2 and 1.3, and which
     # need to do "template_renderer =
     # staticmethod(paste_script_template_renderer)"
     content = native_(content, fsenc)
     try:
         return bytes_(
             substitute_escaped_double_braces(
                 substitute_double_braces(content, TypeMapper(vars))),
             fsenc)
     except Exception as e:
         _add_except(e, ' in file %s' % filename)
         raise
Beispiel #45
0
 def pre(self, command, output_dir, vars):
     """ Overrides :meth:`pyramid.scaffolds.template.Template.pre`, adding
     several variables to the default variables list (including
     ``random_string``, and ``package_logger``).  It also prevents common
     misnamings (such as naming a package "site" or naming a package
     logger "root".
     """
     if vars['package'] == 'site':
         raise ValueError('Sorry, you may not name your package "site". '
                          'The package name "site" has a special meaning in '
                          'Python.  Please name it anything except "site".')
     vars['random_string'] = native_(binascii.hexlify(os.urandom(20)))
     package_logger = vars['package']
     if package_logger == 'root':
         # Rename the app logger in the rare case a project is named 'root'
         package_logger = 'app'
     vars['package_logger'] = package_logger
     return Template.pre(self, command, output_dir, vars)
Beispiel #46
0
def signed_serialize(data, secret):
    """ Serialize any pickleable structure (``data``) and sign it
    using the ``secret`` (must be a string).  Return the
    serialization, which includes the signature as its first 40 bytes.
    The ``signed_deserialize`` method will deserialize such a value.
    This function is useful for creating signed cookies.  For example:
    .. code-block:: python
       cookieval = signed_serialize({'a':1}, 'secret')
       response.set_cookie('signed_cookie', cookieval)
    """
    pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
    try:
        # bw-compat with pyramid <= 1.5b1 where latin1 is the default
        secret = bytes_(secret)
    except UnicodeEncodeError:
        secret = bytes_(secret, "utf-8")
    sig = hmac.new(secret, pickled, hashlib.sha1).hexdigest()
    return sig + native_(base64.b64encode(pickled))
Beispiel #47
0
def embed(request, *elements, **kw):
    """ as_user=True for current user
    """
    # Should really be more careful about what gets included instead.
    # Cache cut response time from ~800ms to ~420ms.
    as_user = kw.get('as_user')
    path = join(*elements)
    path = unquote_bytes_to_wsgi(native_(path))
    if as_user is not None:
        result, embedded, linked = _embed(request, path, as_user)
    else:
        cached = embed_cache.get(path, None)
        if cached is None:
            cached = _embed(request, path)
            embed_cache[path] = cached
        result, embedded, linked = cached
        result = deepcopy(result)
    request._embedded_uuids.update(embedded)
    request._linked_uuids.update(linked)
    return result
Beispiel #48
0
 def _set_cookie(self, response):
     if not self._cookie_on_exception:
         exception = getattr(self.request, 'exception', None)
         if exception is not None:  # dont set a cookie during exceptions
             return False
     cookieval = native_(
         serializer.dumps((self.accessed, self.created, dict(self))))
     if len(cookieval) > 4064:
         raise ValueError(
             'Cookie value is too long to store (%s bytes)' %
             len(cookieval))
     response.set_cookie(
         self._cookie_name,
         value=cookieval,
         max_age=self._cookie_max_age,
         path=self._cookie_path,
         domain=self._cookie_domain,
         secure=self._cookie_secure,
         httponly=self._cookie_httponly,
     )
     return True
    def test_me(self):  # /api/me.json
        # Test unauthenticated/unauthorized access
        headers = {'Accept': 'application/json'}
        res = self.testapp.get('/api/me.json', headers=headers, status=200)
        self.assertEqual(res.json, {'data': None})

        # Test unauthenticated access -- invalid scheme
        headers = {'Accept': 'application/json', 'Authorization': 'Test Test'}
        res = self.testapp.get('/api/me.json', headers=headers, status=200)
        self.assertEqual(res.json, {'data': None})

        # Test unauthenticated access -- missing token
        headers = {'Accept': 'application/json', 'Authorization': 'Token'}
        res = self.testapp.get('/api/me.json', headers=headers, status=200)
        self.assertEqual(res.json, {'data': None})

        # Test unauthenticated access -- mangled traditional token
        headers = {'Accept': 'application/json', 'Authorization': 'Token +='}
        res = self.testapp.get('/api/me.json', headers=headers, status=200)
        self.assertEqual(res.json, {'data': None})

        token = b64encode('%s%s' %
                          (self.user_user.email, self.user_user.api_token))
        headers = {
            'Accept': 'application/json',
            'Authorization': 'Token %s' % native_(token)
        }
        res = self.testapp.get('/api/me.json', headers=headers, status=200)
        self.assertEqual(res.json, {'data': None})

        # Test authenticated/authorized access
        token = self.user_user.authorization_token
        headers = {
            'Accept': 'application/json',
            'Authorization': 'Token %s' % token
        }
        res = self.testapp.get('/api/me.json', headers=headers, status=200)
        self.assertIn('data', res.json)
        self.assertIn('email', res.json['data'])
        self.assertEqual(res.json['data']['email'], '*****@*****.**')
Beispiel #50
0
def parse_ticket(secret, ticket, ip, hashalg='md5'):
    """
    Parse the ticket, returning (timestamp, userid, tokens, user_data).

    If the ticket cannot be parsed, a ``BadTicket`` exception will be raised
    with an explanation.
    """
    ticket = native_(ticket).strip('"')
    digest_size = hashlib.new(hashalg).digest_size * 2
    digest = ticket[:digest_size]
    try:
        timestamp = int(ticket[digest_size:digest_size + 8], 16)
    except ValueError as e:
        raise BadTicket('Timestamp is not a hex integer: %s' % e)
    try:
        userid, data = ticket[digest_size + 8:].split('!', 1)
    except ValueError:
        raise BadTicket('userid is not followed by !')
    userid = url_unquote(userid)
    if '!' in data:
        tokens, user_data = data.split('!', 1)
    else: # pragma: no cover (never generated)
        # @@: Is this the right order?
        tokens = ''
        user_data = data

    expected = calculate_digest(ip, timestamp, secret,
                                userid, tokens, user_data, hashalg)

    # Avoid timing attacks (see
    # http://seb.dbzteam.org/crypto/python-oauth-timing-hmac.pdf)
    if strings_differ(expected, digest):
        raise BadTicket('Digest signature is not correct',
                        expected=(expected, digest))

    tokens = tokens.split(',')

    return (timestamp, userid, tokens, user_data)
Beispiel #51
0
 def matcher(path):
     # This function really wants to consume Unicode patterns natively,
     # but if someone passes us a bytestring, we allow it by converting it
     # to Unicode using the ASCII decoding.  We decode it using ASCII
     # because we don't want to accept bytestrings with high-order
     # characters in them here as we have no idea what the encoding
     # represents.
     if path.__class__ is not text_type:
         path = text_(path, 'ascii')
     m = match(path)
     if m is None:
         return None
     d = {}
     for k, v in m.groupdict().items():
         # k and v will be Unicode 2.6.4 and lower doesnt accept unicode
         # kwargs as **kw, so we explicitly cast the keys to native
         # strings in case someone wants to pass the result as **kw
         nk = native_(k, 'ascii')
         if k == remainder:
             d[nk] = split_path_info(v)
         else:
             d[nk] = v
     return d
Beispiel #52
0
 def loads(self, bstruct):
     return native_(bstruct)
 def test_it_native(self):
     la = native_(b'La/Pe\xc3\xb1a', 'utf-8')
     result = self._callFUT(la)
     self.assertEqual(result, 'La%2FPe%C3%B1a')
Beispiel #54
0
    def resource_url(self, resource, *elements, **kw):
        """

        Generate a string representing the absolute URL of the
        :term:`resource` object based on the ``wsgi.url_scheme``,
        ``HTTP_HOST`` or ``SERVER_NAME`` in the request, plus any
        ``SCRIPT_NAME``.  The overall result of this method is always a
        UTF-8 encoded string (never Unicode).

        Examples::

            request.resource_url(resource) =>

                                       http://example.com/

            request.resource_url(resource, 'a.html') =>

                                       http://example.com/a.html

            request.resource_url(resource, 'a.html', query={'q':'1'}) =>

                                       http://example.com/a.html?q=1

            request.resource_url(resource, 'a.html', anchor='abc') =>

                                       http://example.com/a.html#abc

        Any positional arguments passed in as ``elements`` must be strings
        Unicode objects, or integer objects.  These will be joined by slashes
        and appended to the generated resource URL.  Each of the elements
        passed in is URL-quoted before being appended; if any element is
        Unicode, it will converted to a UTF-8 bytestring before being
        URL-quoted. If any element is an integer, it will be converted to its
        string representation before being URL-quoted.

        .. warning:: if no ``elements`` arguments are specified, the resource
                     URL will end with a trailing slash.  If any
                     ``elements`` are used, the generated URL will *not*
                     end in trailing a slash.

        If a keyword argument ``query`` is present, it will be used to
        compose a query string that will be tacked on to the end of the URL.
        The value of ``query`` must be a sequence of two-tuples *or* a data
        structure with an ``.items()`` method that returns a sequence of
        two-tuples (presumably a dictionary).  This data structure will be
        turned into a query string per the documentation of
        ``pyramid.url.urlencode`` function.  After the query data is turned
        into a query string, a leading ``?`` is prepended, and the resulting
        string is appended to the generated URL.

        .. note::

           Python data structures that are passed as ``query`` which are
           sequences or dictionaries are turned into a string under the same
           rules as when run through :func:`urllib.urlencode` with the ``doseq``
           argument equal to ``True``.  This means that sequences can be passed
           as values, and a k=v pair will be placed into the query string for
           each value.

        If a keyword argument ``anchor`` is present, its string
        representation will be used as a named anchor in the generated URL
        (e.g. if ``anchor`` is passed as ``foo`` and the resource URL is
        ``http://example.com/resource/url``, the resulting generated URL will
        be ``http://example.com/resource/url#foo``).

        .. note::

           If ``anchor`` is passed as a string, it should be UTF-8 encoded. If
           ``anchor`` is passed as a Unicode object, it will be converted to
           UTF-8 before being appended to the URL.  The anchor value is not
           quoted in any way before being appended to the generated URL.

        If both ``anchor`` and ``query`` are specified, the anchor element
        will always follow the query element,
        e.g. ``http://example.com?foo=1#bar``.

        If the ``resource`` passed in has a ``__resource_url__`` method, it
        will be used to generate the URL (scheme, host, port, path) that for
        the base resource which is operated upon by this function.  See also
        :ref:`overriding_resource_url_generation`.

        .. note::

           If the :term:`resource` used is the result of a :term:`traversal`, it
           must be :term:`location`-aware.  The resource can also be the context
           of a :term:`URL dispatch`; contexts found this way do not need to be
           location-aware.

        .. note::

           If a 'virtual root path' is present in the request environment (the
           value of the WSGI environ key ``HTTP_X_VHM_ROOT``), and the resource
           was obtained via :term:`traversal`, the URL path will not include the
           virtual root prefix (it will be stripped off the left hand side of
           the generated URL).

        .. note::

           For backwards compatibility purposes, this method is also
           aliased as the ``model_url`` method of request.
        """
        try:
            reg = self.registry
        except AttributeError:
            reg = get_current_registry()  # b/c

        context_url = reg.queryMultiAdapter((resource, self), IContextURL)
        if context_url is None:
            context_url = TraversalContextURL(resource, self)
        resource_url = context_url()

        qs = ''
        anchor = ''

        if 'query' in kw:
            qs = '?' + urlencode(kw['query'], doseq=True)

        if 'anchor' in kw:
            anchor = kw['anchor']
            if isinstance(anchor, text_type):
                anchor = native_(anchor, 'utf-8')
            anchor = '#' + anchor

        if elements:
            suffix = _join_elements(elements)
        else:
            suffix = ''

        return resource_url + suffix + qs + anchor
Beispiel #55
0
 def test_highorder(self):
     la = b'La Pe\xc3\xb1a'
     latin1 = native_(la)
     result = self._callFUT(latin1)
     self.assertEqual(result, (text_(la, 'utf-8'), ))
Beispiel #56
0
 def test_highorder_undecodeable(self):
     from pyramid.exceptions import URLDecodeError
     la = text_(b'La Pe\xc3\xb1a', 'utf-8')
     notlatin1 = native_(la)
     self.assertRaises(URLDecodeError, self._callFUT, notlatin1)
Beispiel #57
0
def _compile_route(route):
    # This function really wants to consume Unicode patterns natively, but if
    # someone passes us a bytestring, we allow it by converting it to Unicode
    # using the ASCII decoding.  We decode it using ASCII because we don't
    # want to accept bytestrings with high-order characters in them here as
    # we have no idea what the encoding represents.
    if route.__class__ is not text_type:
        try:
            route = text_(route, 'ascii')
        except UnicodeDecodeError:
            raise ValueError(
                'The pattern value passed to add_route must be '
                'either a Unicode string or a plain string without '
                'any non-ASCII characters (you provided %r).' % route)

    if old_route_re.search(route) and not route_re.search(route):
        route = old_route_re.sub(update_pattern, route)

    if not route.startswith('/'):
        route = '/' + route

    remainder = None
    if star_at_end.search(route):
        route, remainder = route.rsplit('*', 1)

    pat = route_re.split(route)

    # every element in "pat" will be Unicode (regardless of whether the
    # route_re regex pattern is itself Unicode or str)
    pat.reverse()
    rpat = []
    gen = []
    prefix = pat.pop()  # invar: always at least one element (route='/'+route)

    # We want to generate URL-encoded URLs, so we url-quote the prefix, being
    # careful not to quote any embedded slashes.  We have to replace '%' with
    # '%%' afterwards, as the strings that go into "gen" are used as string
    # replacement targets.
    gen.append(quote_path_segment(prefix, safe='/').replace('%',
                                                            '%%'))  # native
    rpat.append(re.escape(prefix))  # unicode

    while pat:
        name = pat.pop()  # unicode
        name = name[1:-1]
        if ':' in name:
            # reg may contain colons as well,
            # so we must strictly split name into two parts
            name, reg = name.split(':', 1)
        else:
            reg = '[^/]+'
        gen.append('%%(%s)s' % native_(name))  # native
        name = '(?P<%s>%s)' % (name, reg)  # unicode
        rpat.append(name)
        s = pat.pop()  # unicode
        if s:
            rpat.append(re.escape(s))  # unicode
            # We want to generate URL-encoded URLs, so we url-quote this
            # literal in the pattern, being careful not to quote the embedded
            # slashes.  We have to replace '%' with '%%' afterwards, as the
            # strings that go into "gen" are used as string replacement
            # targets.  What is appended to gen is a native string.
            gen.append(quote_path_segment(s, safe='/').replace('%', '%%'))

    if remainder:
        rpat.append('(?P<%s>.*?)' % remainder)  # unicode
        gen.append('%%(%s)s' % native_(remainder))  # native

    pattern = ''.join(rpat) + '$'  # unicode

    match = re.compile(pattern).match

    def matcher(path):
        # This function really wants to consume Unicode patterns natively,
        # but if someone passes us a bytestring, we allow it by converting it
        # to Unicode using the ASCII decoding.  We decode it using ASCII
        # because we don't want to accept bytestrings with high-order
        # characters in them here as we have no idea what the encoding
        # represents.
        if path.__class__ is not text_type:
            path = text_(path, 'ascii')
        m = match(path)
        if m is None:
            return None
        d = {}
        for k, v in m.groupdict().items():
            # k and v will be Unicode 2.6.4 and lower doesnt accept unicode
            # kwargs as **kw, so we explicitly cast the keys to native
            # strings in case someone wants to pass the result as **kw
            nk = native_(k, 'ascii')
            if k == remainder:
                d[nk] = split_path_info(v)
            else:
                d[nk] = v
        return d

    gen = ''.join(gen)

    def generator(dict):
        newdict = {}
        for k, v in dict.items():
            if PY3:  # pragma: no cover
                if v.__class__ is binary_type:
                    # url_quote below needs a native string, not bytes on Py3
                    v = v.decode('utf-8')
            else:
                if v.__class__ is text_type:
                    # url_quote below needs bytes, not unicode on Py2
                    v = v.encode('utf-8')

            if k == remainder:
                # a stararg argument
                if is_nonstr_iter(v):
                    v = '/'.join([quote_path_segment(x, safe='/')
                                  for x in v])  # native
                else:
                    if v.__class__ not in string_types:
                        v = str(v)
                    v = quote_path_segment(v, safe='/')
            else:
                if v.__class__ not in string_types:
                    v = str(v)
                # v may be bytes (py2) or native string (py3)
                v = quote_path_segment(v, safe='/')

            # at this point, the value will be a native string
            newdict[k] = v

        result = gen % newdict  # native string result
        return result

    return matcher, generator
Beispiel #58
0
    def route_url(self, route_name, *elements, **kw):
        """Generates a fully qualified URL for a named :app:`Pyramid`
        :term:`route configuration`.

        Use the route's ``name`` as the first positional argument.
        Additional positional arguments (``*elements``) are appended to the
        URL as path segments after it is generated.

        Use keyword arguments to supply values which match any dynamic
        path elements in the route definition.  Raises a :exc:`KeyError`
        exception if the URL cannot be generated for any reason (not
        enough arguments, for example).

        For example, if you've defined a route named "foobar" with the path
        ``{foo}/{bar}/*traverse``::

            request.route_url('foobar',
                               foo='1')             => <KeyError exception>
            request.route_url('foobar',
                               foo='1',
                               bar='2')             => <KeyError exception>
            request.route_url('foobar',
                               foo='1',
                               bar='2',
                               traverse=('a','b'))  => http://e.com/1/2/a/b
            request.route_url('foobar',
                               foo='1',
                               bar='2',
                               traverse='/a/b')     => http://e.com/1/2/a/b

        Values replacing ``:segment`` arguments can be passed as strings
        or Unicode objects.  They will be encoded to UTF-8 and URL-quoted
        before being placed into the generated URL.

        Values replacing ``*remainder`` arguments can be passed as strings
        *or* tuples of Unicode/string values.  If a tuple is passed as a
        ``*remainder`` replacement value, its values are URL-quoted and
        encoded to UTF-8.  The resulting strings are joined with slashes
        and rendered into the URL.  If a string is passed as a
        ``*remainder`` replacement value, it is tacked on to the URL
        after being URL-quoted-except-for-embedded-slashes.

        If a keyword argument ``_query`` is present, it will be used to
        compose a query string that will be tacked on to the end of the
        URL.  The value of ``_query`` must be a sequence of two-tuples
        *or* a data structure with an ``.items()`` method that returns a
        sequence of two-tuples (presumably a dictionary).  This data
        structure will be turned into a query string per the documentation
        of :func:`pyramid.encode.urlencode` function.  After the query
        data is turned into a query string, a leading ``?`` is prepended,
        and the resulting string is appended to the generated URL.

        .. note::

           Python data structures that are passed as ``_query`` which are
           sequences or dictionaries are turned into a string under the same
           rules as when run through :func:`urllib.urlencode` with the ``doseq``
           argument equal to ``True``.  This means that sequences can be passed
           as values, and a k=v pair will be placed into the query string for
           each value.

        If a keyword argument ``_anchor`` is present, its string
        representation will be used as a named anchor in the generated URL
        (e.g. if ``_anchor`` is passed as ``foo`` and the route URL is
        ``http://example.com/route/url``, the resulting generated URL will
        be ``http://example.com/route/url#foo``).

        .. note::

           If ``_anchor`` is passed as a string, it should be UTF-8 encoded. If
           ``_anchor`` is passed as a Unicode object, it will be converted to
           UTF-8 before being appended to the URL.  The anchor value is not
           quoted in any way before being appended to the generated URL.

        If both ``_anchor`` and ``_query`` are specified, the anchor
        element will always follow the query element,
        e.g. ``http://example.com?foo=1#bar``.

        If any of the keyword arguments ``_scheme``, ``_host``, or ``_port``
        is passed and is non-``None``, the provided value will replace the
        named portion in the generated URL.  For example, if you pass
        ``_host='foo.com'``, and the URL that would have been generated
        without the host replacement is ``http://example.com/a``, the result
        will be ``https://foo.com/a``.
        
        Note that if ``_scheme`` is passed as ``https``, and ``_port`` is not
        passed, the ``_port`` value is assumed to have been passed as
        ``443``.  Likewise, if ``_scheme`` is passed as ``http`` and
        ``_port`` is not passed, the ``_port`` value is assumed to have been
        passed as ``80``. To avoid this behavior, always explicitly pass
        ``_port`` whenever you pass ``_scheme``.

        If a keyword ``_app_url`` is present, it will be used as the
        protocol/hostname/port/leading path prefix of the generated URL.
        For example, using an ``_app_url`` of
        ``http://example.com:8080/foo`` would cause the URL
        ``http://example.com:8080/foo/fleeb/flub`` to be returned from
        this function if the expansion of the route pattern associated
        with the ``route_name`` expanded to ``/fleeb/flub``.  If
        ``_app_url`` is not specified, the result of
        ``request.application_url`` will be used as the prefix (the
        default).

        If both ``_app_url`` and any of ``_scheme``, ``_host``, or ``_port``
        are passed, ``_app_url`` takes precedence and any values passed for
        ``_scheme``, ``_host``, and ``_port`` will be ignored.

        This function raises a :exc:`KeyError` if the URL cannot be
        generated due to missing replacement names.  Extra replacement
        names are ignored.

        If the route object which matches the ``route_name`` argument has
        a :term:`pregenerator`, the ``*elements`` and ``**kw``
        arguments passed to this function might be augmented or changed.
        """
        try:
            reg = self.registry
        except AttributeError:
            reg = get_current_registry() # b/c
        mapper = reg.getUtility(IRoutesMapper)
        route = mapper.get_route(route_name)

        if route is None:
            raise KeyError('No such route named %s' % route_name)

        if route.pregenerator is not None:
            elements, kw = route.pregenerator(self, elements, kw)

        anchor = ''
        qs = ''
        app_url = None
        host = None
        scheme = None
        port = None

        if '_query' in kw:
            query = kw.pop('_query')
            if query:
                qs = '?' + urlencode(query, doseq=True)

        if '_anchor' in kw:
            anchor = kw.pop('_anchor')
            anchor = native_(anchor, 'utf-8')
            anchor = '#' + anchor

        if '_app_url' in kw:
            app_url = kw.pop('_app_url')

        if '_host' in kw:
            host = kw.pop('_host')

        if '_scheme' in kw:
            scheme = kw.pop('_scheme')

        if '_port' in kw:
            port = kw.pop('_port')

        if app_url is None:
            if (scheme is not None or host is not None or port is not None):
                app_url = self._partial_application_url(scheme, host, port)
            else:
                app_url = self.application_url

        path = route.generate(kw) # raises KeyError if generate fails

        if elements:
            suffix = _join_elements(elements)
            if not path.endswith('/'):
                suffix = '/' + suffix
        else:
            suffix = ''

        return app_url + path + suffix + qs + anchor
Beispiel #59
0
    def resource_url(self, resource, *elements, **kw):
        """

        Generate a string representing the absolute URL of the
        :term:`resource` object based on the ``wsgi.url_scheme``,
        ``HTTP_HOST`` or ``SERVER_NAME`` in the request, plus any
        ``SCRIPT_NAME``.  The overall result of this method is always a
        UTF-8 encoded string.

        Examples::

            request.resource_url(resource) =>

                                       http://example.com/

            request.resource_url(resource, 'a.html') =>

                                       http://example.com/a.html

            request.resource_url(resource, 'a.html', query={'q':'1'}) =>

                                       http://example.com/a.html?q=1

            request.resource_url(resource, 'a.html', anchor='abc') =>

                                       http://example.com/a.html#abc

            request.resource_url(resource, app_url='') =>

                                       /

        Any positional arguments passed in as ``elements`` must be strings
        Unicode objects, or integer objects.  These will be joined by slashes
        and appended to the generated resource URL.  Each of the elements
        passed in is URL-quoted before being appended; if any element is
        Unicode, it will converted to a UTF-8 bytestring before being
        URL-quoted. If any element is an integer, it will be converted to its
        string representation before being URL-quoted.

        .. warning:: if no ``elements`` arguments are specified, the resource
                     URL will end with a trailing slash.  If any
                     ``elements`` are used, the generated URL will *not*
                     end in trailing a slash.

        If a keyword argument ``query`` is present, it will be used to
        compose a query string that will be tacked on to the end of the URL.
        The value of ``query`` must be a sequence of two-tuples *or* a data
        structure with an ``.items()`` method that returns a sequence of
        two-tuples (presumably a dictionary).  This data structure will be
        turned into a query string per the documentation of
        ``pyramid.url.urlencode`` function.  After the query data is turned
        into a query string, a leading ``?`` is prepended, and the resulting
        string is appended to the generated URL.

        .. note::

           Python data structures that are passed as ``query`` which are
           sequences or dictionaries are turned into a string under the same
           rules as when run through :func:`urllib.urlencode` with the ``doseq``
           argument equal to ``True``.  This means that sequences can be passed
           as values, and a k=v pair will be placed into the query string for
           each value.

        If a keyword argument ``anchor`` is present, its string
        representation will be used as a named anchor in the generated URL
        (e.g. if ``anchor`` is passed as ``foo`` and the resource URL is
        ``http://example.com/resource/url``, the resulting generated URL will
        be ``http://example.com/resource/url#foo``).

        .. note::

           If ``anchor`` is passed as a string, it should be UTF-8 encoded. If
           ``anchor`` is passed as a Unicode object, it will be converted to
           UTF-8 before being appended to the URL.  The anchor value is not
           quoted in any way before being appended to the generated URL.

        If both ``anchor`` and ``query`` are specified, the anchor element
        will always follow the query element,
        e.g. ``http://example.com?foo=1#bar``.

        If any of the keyword arguments ``scheme``, ``host``, or ``port`` is
        passed and is non-``None``, the provided value will replace the named
        portion in the generated URL.  For example, if you pass
        ``host='foo.com'``, and the URL that would have been generated
        without the host replacement is ``http://example.com/a``, the result
        will be ``https://foo.com/a``.
        
        If ``scheme`` is passed as ``https``, and an explicit ``port`` is not
        passed, the ``port`` value is assumed to have been passed as ``443``.
        Likewise, if ``scheme`` is passed as ``http`` and ``port`` is not
        passed, the ``port`` value is assumed to have been passed as
        ``80``. To avoid this behavior, always explicitly pass ``port``
        whenever you pass ``scheme``.

        If a keyword argument ``app_url`` is passed and is not ``None``, it
        should be a string that will be used as the port/hostname/initial
        path portion of the generated URL instead of the default request
        application URL.  For example, if ``app_url='http://foo'``, then the
        resulting url of a resource that has a path of ``/baz/bar`` will be
        ``http://foo/baz/bar``.  If you want to generate completely relative
        URLs with no leading scheme, host, port, or initial path, you can
        pass ``app_url=''`.  Passing ``app_url=''` when the resource path is
        ``/baz/bar`` will return ``/baz/bar``.

        .. note::

           ``app_url`` is new as of Pyramid 1.3.

        If ``app_url`` is passed and any of ``scheme``, ``port``, or ``host``
        are also passed, ``app_url`` will take precedence and the values
        passed for ``scheme``, ``host``, and/or ``port`` will be ignored.

        If the ``resource`` passed in has a ``__resource_url__`` method, it
        will be used to generate the URL (scheme, host, port, path) that for
        the base resource which is operated upon by this function.  See also
        :ref:`overriding_resource_url_generation`.

        .. note::

           If the :term:`resource` used is the result of a :term:`traversal`, it
           must be :term:`location`-aware.  The resource can also be the context
           of a :term:`URL dispatch`; contexts found this way do not need to be
           location-aware.

        .. note::

           If a 'virtual root path' is present in the request environment (the
           value of the WSGI environ key ``HTTP_X_VHM_ROOT``), and the resource
           was obtained via :term:`traversal`, the URL path will not include the
           virtual root prefix (it will be stripped off the left hand side of
           the generated URL).

        .. note::

           For backwards compatibility purposes, this method is also
           aliased as the ``model_url`` method of request.
        """
        try:
            reg = self.registry
        except AttributeError:
            reg = get_current_registry() # b/c

        url_adapter = reg.queryMultiAdapter((resource, self), IResourceURL)
        if url_adapter is None:
            url_adapter = ResourceURL(resource, self)

        virtual_path = getattr(url_adapter, 'virtual_path', None)

        if virtual_path is None:
            # old-style IContextURL adapter (Pyramid 1.2 and previous)
            warnings.warn(
                'Pyramid is using an IContextURL adapter to generate a '
                'resource URL; any "app_url", "host", "port", or "scheme" '
                'arguments passed to resource_url are being ignored.  To '
                'avoid this behavior, as of Pyramid 1.3, register an '
                'IResourceURL adapter instead of an IContextURL '
                'adapter for the resource type(s).  IContextURL adapters '
                'will be ignored in a later major release of Pyramid.',
                DeprecationWarning,
                2)

            resource_url = url_adapter()

        else:
            # newer-style IResourceURL adapter (Pyramid 1.3 and after)
            app_url = None
            scheme = None
            host = None
            port = None

            if 'app_url' in kw:
                app_url = kw['app_url']

            if 'scheme' in kw:
                scheme = kw['scheme']

            if 'host' in kw:
                host = kw['host']

            if 'port' in kw:
                port = kw['port']

            if app_url is None:
                if scheme or host or port:
                    app_url = self._partial_application_url(scheme, host, port)
                else:
                    app_url = self.application_url

            resource_url = None
            local_url = getattr(resource, '__resource_url__', None)

            if local_url is not None:
                # the resource handles its own url generation
                d = dict(
                    virtual_path = virtual_path,
                    physical_path = url_adapter.physical_path,
                    app_url = app_url,
                    )
                # allow __resource_url__ to punt by returning None
                resource_url = local_url(self, d)

            if resource_url is None:
                # the resource did not handle its own url generation or the
                # __resource_url__ function returned None
                resource_url = app_url + virtual_path

        qs = ''
        anchor = ''

        if 'query' in kw:
            query = kw['query']
            if query:
                qs = '?' + urlencode(query, doseq=True)

        if 'anchor' in kw:
            anchor = kw['anchor']
            if isinstance(anchor, text_type):
                anchor = native_(anchor, 'utf-8')
            anchor = '#' + anchor

        if elements:
            suffix = _join_elements(elements)
        else:
            suffix = ''

        return resource_url + suffix + qs + anchor
Beispiel #60
0
 def test_url_decode_error(self):
     from pyramid.exceptions import URLDecodeError
     matcher, generator = self._callFUT('/:foo')
     self.assertRaises(URLDecodeError, matcher,
                       native_(b'/\xff\xfe\x8b\x00'))