def test_index_page(self): os.mkdir(os.path.join(self.test_dir, "index-test")) create_file(bytes_("index"), self.test_dir, "index-test", "index.html") app = static.DirectoryApp(self.test_dir) resp = get_response(app, "/index-test") self.assertEqual(resp.status_code, 301) self.assertTrue(resp.location.endswith("/index-test/")) resp = get_response(app, "/index-test?test") self.assertTrue(resp.location.endswith("/index-test/?test")) resp = get_response(app, "/index-test/") self.assertEqual(resp.status_code, 200) self.assertEqual(resp.body, bytes_("index")) self.assertEqual(resp.content_type, "text/html") resp = get_response(app, "/index-test/index.html") self.assertEqual(resp.status_code, 200) self.assertEqual(resp.body, bytes_("index")) redir_app = static.DirectoryApp(self.test_dir, hide_index_with_redirect=True) resp = get_response(redir_app, "/index-test/index.html") self.assertEqual(resp.status_code, 301) self.assertTrue(resp.location.endswith("/index-test/")) resp = get_response(redir_app, "/index-test/index.html?test") self.assertTrue(resp.location.endswith("/index-test/?test")) page_app = static.DirectoryApp(self.test_dir, index_page="something-else.html") self.assertEqual( get_response(page_app, "/index-test/").status_code, 404)
def test_seek_bigger_than_limit(self): fp = BytesIO(bytes_("0123456789")) i = static.FileIter(fp).app_iter_range(limit=1, seek=2) # XXX: this should not return anything actually, since we are starting # to read after the place we wanted to stop. self.assertEqual(bytes_("23456789"), next(i)) self.assertRaises(StopIteration, next, i)
def test_multiple_reads(self): fp = BytesIO(bytes_("012")) i = static.FileIter(fp).app_iter_range(block_size=1) self.assertEqual(bytes_("0"), next(i)) self.assertEqual(bytes_("1"), next(i)) self.assertEqual(bytes_("2"), next(i)) self.assertRaises(StopIteration, next, i)
def serialize(secret, salt, data): import base64 from hashlib import sha1 import hmac import json from webob.util import bytes_ salted_secret = bytes_(salt or "", "utf-8") + bytes_(secret, "utf-8") cstruct = bytes_(json.dumps(data)) sig = hmac.new(salted_secret, cstruct, sha1).digest() return base64.urlsafe_b64encode(sig + cstruct).rstrip(b"=")
def serialize_max_age(v): if isinstance(v, timedelta): v = str(v.seconds + v.days * 24 * 60 * 60) elif isinstance(v, int): v = str(v) return bytes_(v)
def test_middleware(self): resp_str = "These are the vars: %s" @wsgify.middleware def set_urlvar(req, app, **vars): req.urlvars.update(vars) return app(req) from webob.dec import _MiddlewareFactory self.assertTrue(set_urlvar.__class__ is _MiddlewareFactory) r = repr(set_urlvar) self.assertTrue("set_urlvar" in r) @wsgify def show_vars(req): return resp_str % (sorted(req.urlvars.items())) show_vars2 = set_urlvar(show_vars, a=1, b=2) resp = self._testit(show_vars2, "/path") self.assertEqual(resp.body, bytes_(resp_str % "[('a', 1), ('b', 2)]")) self.assertEqual(resp.content_type, "text/html") self.assertEqual(resp.charset, "UTF-8") self.assertEqual(resp.content_length, 40)
def create_file(content, *paths): """Convenient function to create a new file with some content""" path = os.path.join(*paths) with open(path, "wb") as fp: fp.write(bytes_(content)) return path
def _send_interrupted_req(server, path="/"): sock = socket.socket() sock.connect(("localhost", server.server_port)) f = sock.makefile("wb") f.write(bytes_(_interrupted_req % path)) f.flush() f.close() sock.close()
def serialize_samesite(v): v = bytes_(v) if SAMESITE_VALIDATION: if v.lower() not in (b"strict", b"lax", b"none"): raise ValueError("SameSite must be 'strict', 'lax', or 'none'") return v
def test_serve_file(self): app = static.DirectoryApp(self.test_dir) create_file("abcde", self.test_dir, "bar") self.assertEqual(404, get_response(app).status_code) self.assertEqual(404, get_response(app, "/foo").status_code) resp = get_response(app, "/bar") self.assertEqual(200, resp.status_code) self.assertEqual(bytes_("abcde"), resp.body)
def test_wsgify_call_args_override(self): resp_str = "args: %s, kwargs: %s" def show_vars(req, *args, **kwargs): return bytes_(resp_str % (sorted(args), sorted(kwargs.items()))) app = wsgify(show_vars, args=("foo", "bar"), kwargs={"a": 1, "b": 2}) resp = app(Request.blank("/"), "qux", c=3) self.assertEqual(resp, bytes_(resp_str % ("['qux']", "[('c', 3)]")))
def __init__(self, secret, salt, hashalg="sha512", serializer=None): self.salt = salt self.secret = secret self.hashalg = hashalg try: # bwcompat with webob <= 1.3.1, leave latin-1 as the default self.salted_secret = bytes_(salt or "") + bytes_(secret) except UnicodeEncodeError: self.salted_secret = bytes_(salt or "", "utf-8") + bytes_( secret, "utf-8") self.digestmod = lambda string=b"": hashlib.new(self.hashalg, string) self.digest_size = self.digestmod().digest_size if serializer is None: serializer = JSONSerializer() self.serializer = serializer
def _mutate_header(self, name, value): header = self._environ.get("HTTP_COOKIE") had_header = header is not None header = header or "" header = header.encode("latin-1") bytes_name = bytes_(name, "ascii") if value is None: replacement = None else: bytes_val = _value_quote(bytes_(value, "utf-8")) replacement = bytes_name + b"=" + bytes_val matches = _rx_cookie.finditer(header) found = False for match in matches: start, end = match.span() match_name = match.group(1) if match_name == bytes_name: found = True if replacement is None: # remove value header = header[:start].rstrip(b" ;") + header[end:] else: # replace value header = header[:start] + replacement + header[end:] break else: if replacement is not None: if header: header += b"; " + replacement else: header = replacement if header: self._environ["HTTP_COOKIE"] = text_(header, "latin-1") elif had_header: self._environ["HTTP_COOKIE"] = "" return found
def test_wsgify_post(self): post_dict = dict(speaker="Robin", words="Holy test coverage, Batman!") @wsgify def test_app(req): return Response("%s: %s" % (req.POST["speaker"], req.POST["words"])) resp = test_app.post("/url/path", post_dict) self.assertEqual( resp.body, bytes_("%s: %s" % (post_dict["speaker"], post_dict["words"])) )
def test_wsgify(self): resp_str = "hey, this is a test: %s" @wsgify def test_app(req): return bytes_(resp_str % req.url) resp = self._testit(test_app, "/a url") self.assertEqual(resp.body, bytes_(resp_str % "http://localhost/a%20url")) self.assertEqual(resp.content_length, 45) self.assertEqual(resp.content_type, "text/html") self.assertEqual(resp.charset, "UTF-8")
def test_wsgify_call_args(self): resp_str = "args: %s, kwargs: %s" def show_vars(req, *args, **kwargs): return bytes_(resp_str % (sorted(args), sorted(kwargs.items()))) app = wsgify(show_vars, args=("foo", "bar"), kwargs={"a": 1, "b": 2}) resp = app(Request.blank("/")) self.assertEqual( resp, bytes_(resp_str % ("['bar', 'foo']", "[('a', 1), ('b', 2)]")) )
def loads(self, bstruct): """ Given a ``bstruct`` (a bytestring), verify the signature and then deserialize and return the deserialized value. A ``ValueError`` will be raised if the signature fails to validate. """ try: cstruct = base64.urlsafe_b64decode(bytes_(bstruct)) except (binascii.Error, TypeError) as e: raise ValueError("Badly formed base64 data: %s" % e) return self.serializer.loads(cstruct)
def _valid_cookie_name(self, name): if not isinstance(name, str): raise TypeError(name, "cookie name must be a string") try: bytes_cookie_name = bytes_(name, "ascii") except UnicodeEncodeError: raise TypeError("cookie name must be encodable to ascii") if not _valid_cookie_name(bytes_cookie_name): raise TypeError("cookie name must be valid according to RFC 6265") return name
def loads(self, bstruct): """ Given a ``bstruct`` (a bytestring), verify the signature and then deserialize and return the deserialized value. A ``ValueError`` will be raised if the signature fails to validate. """ try: b64padding = b"=" * (-len(bstruct) % 4) fstruct = base64.urlsafe_b64decode(bytes_(bstruct) + b64padding) except (binascii.Error, TypeError) as e: raise ValueError("Badly formed base64 data: %s" % e) cstruct = fstruct[self.digest_size:] expected_sig = fstruct[:self.digest_size] sig = hmac.new(self.salted_secret, bytes_(cstruct), self.digestmod).digest() if not hmac.compare_digest(sig, expected_sig): raise ValueError("Invalid signature") return self.serializer.loads(cstruct)
def __call__(self, req, *args, **kw): """Call this as a WSGI application or with a request""" func = self.func if func is None: if args or kw: raise TypeError( "Unbound %s can only be called with the function it " "will wrap" % self.__class__.__name__) func = req return self.clone(func) if isinstance(req, dict): if len(args) != 1 or kw: raise TypeError( "Calling %r as a WSGI app with the wrong signature" % self.func) environ = req start_response = args[0] req = self.RequestClass(environ) req.response = req.ResponseClass() try: args, kw = self._prepare_args(None, None) resp = self.call_func(req, *args, **kw) except HTTPException as exc: resp = exc if resp is None: # FIXME: I'm not sure what this should be? resp = req.response if isinstance(resp, str): resp = bytes_(resp, req.charset) if isinstance(resp, bytes): body = resp resp = req.response resp.write(body) if resp is not req.response: resp = req.response.merge_cookies(resp) return resp(environ, start_response) else: args, kw = self._prepare_args(args, kw) return self.call_func(req, *args, **kw)
def test_use_wsgi_filewrapper(self): class TestWrapper: __slots__ = ("file", "block_size") def __init__(self, file, block_size): self.file = file self.block_size = block_size environ = environ_from_url("/") environ["wsgi.file_wrapper"] = TestWrapper app = static.FileApp(self.tempfile) app_iter = Request(environ).get_response(app).app_iter self.assertTrue(isinstance(app_iter, TestWrapper)) self.assertEqual(bytes_("import this\n"), app_iter.file.read()) self.assertEqual(static.BLOCK_SIZE, app_iter.block_size)
def test_middleware_call_kwargs_override(self): resp_str = "kwargs: %s" @wsgify.middleware def set_args(req, app, **kwargs): req.urlvars = kwargs return req.get_response(app) @wsgify def show_vars(req): return resp_str % sorted(req.urlvars.items()) app = set_args(show_vars, a=1, b=2) resp = app(Request.blank("/"), c=3) self.assertEqual(resp.body, bytes_(resp_str % "[('c', 3)]"))
def serialize_cookie_date(v): if v is None: return None elif isinstance(v, bytes): return v elif isinstance(v, str): return v.encode("ascii") elif isinstance(v, int): v = timedelta(seconds=v) if isinstance(v, timedelta): v = datetime.utcnow() + v if isinstance(v, (datetime, date)): v = v.timetuple() r = time.strftime("%%s, %d-%%s-%Y %H:%M:%S GMT", v) return bytes_(r % (weekdays[v[6]], months[v[1]]), "ascii")
def test_middleware_as_decorator(self): resp_str = "These are the vars: %s" @wsgify.middleware def set_urlvar(req, app, **vars): req.urlvars.update(vars) return app(req) @set_urlvar(a=1, b=2) @wsgify def show_vars(req): return resp_str % (sorted(req.urlvars.items())) resp = self._testit(show_vars, "/path") self.assertEqual(resp.body, bytes_(resp_str % "[('a', 1), ('b', 2)]")) self.assertEqual(resp.content_type, "text/html") self.assertEqual(resp.charset, "UTF-8") self.assertEqual(resp.content_length, 40)
def get_value(self): """Looks for a cookie by name in the currently bound request, and returns its value. If the cookie profile is not bound to a request, this method will raise a :exc:`ValueError`. Looks for the cookie in the cookies jar, and if it can find it it will attempt to deserialize it. Returns ``None`` if there is no cookie or if the value in the cookie cannot be successfully deserialized. """ if not self.request: raise ValueError("No request bound to cookie profile") cookie = self.request.cookies.get(self.cookie_name) if cookie is not None: try: return self.serializer.loads(bytes_(cookie)) except ValueError: return None
def test_fileapp(self): app = static.FileApp(self.tempfile) resp1 = get_response(app) assert resp1.content_type in ("text/x-python", "text/plain") self.assertEqual(resp1.charset, "UTF-8") self.assertEqual(resp1.last_modified.timetuple(), gmtime(getmtime(self.tempfile))) self.assertEqual(resp1.body, b"import this\n") resp2 = get_response(app) assert resp2.content_type in ("text/x-python", "text/plain") self.assertEqual(resp2.last_modified.timetuple(), gmtime(getmtime(self.tempfile))) self.assertEqual(resp2.body, b"import this\n") resp3 = get_response(app, range=(7, 11)) self.assertEqual(resp3.status_code, 206) self.assertEqual(tuple(resp3.content_range)[:2], (7, 11)) self.assertEqual(resp3.last_modified.timetuple(), gmtime(getmtime(self.tempfile))) self.assertEqual(resp3.body, bytes_("this"))
def test_from_file2(): res = Response(app_iter=iter([b"test ", b"body"]), content_type="text/plain") inp = io.BytesIO(bytes_(str(res))) equal_resp(res, inp)
def test_from_file(): res = Response("test") inp = io.BytesIO(bytes_(str(res))) equal_resp(res, inp)
def _callFUT(self, *arg, **kw): from webob.util import bytes_ return bytes_(*arg, **kw)
def dumps(self, appstruct): return bytes_(json.dumps(appstruct), encoding="utf-8")