def test_iri_safe_conversion(): strict_eq(urls.iri_to_uri(u"magnet:?foo=bar"), "magnet:?foo=bar") strict_eq(urls.iri_to_uri(u"itms-service://?foo=bar"), "itms-service:?foo=bar") strict_eq( urls.iri_to_uri(u"itms-service://?foo=bar", safe_conversion=True), "itms-service://?foo=bar", )
def test_iri_support(): strict_eq(urls.uri_to_iri("http://xn--n3h.net/"), u"http://\u2603.net/") strict_eq( urls.uri_to_iri(b"http://%C3%BCser:p%C3%[email protected]/p%C3%A5th"), u"http://\xfcser:p\xe4ssword@\u2603.net/p\xe5th", ) strict_eq(urls.iri_to_uri(u"http://☃.net/"), "http://xn--n3h.net/") strict_eq( urls.iri_to_uri(u"http://üser:pässword@☃.net/påth"), "http://%C3%BCser:p%C3%[email protected]/p%C3%A5th", ) strict_eq( urls.uri_to_iri("http://test.com/%3Fmeh?foo=%26%2F"), u"http://test.com/%3Fmeh?foo=%26%2F", ) # this should work as well, might break on 2.4 because of a broken # idna codec strict_eq(urls.uri_to_iri(b"/foo"), u"/foo") strict_eq(urls.iri_to_uri(u"/foo"), "/foo") strict_eq( urls.iri_to_uri(u"http://föö.com:8080/bam/baz"), "http://xn--f-1gaa.com:8080/bam/baz", )
def __init__(self, path='/', base_url=None, query_string=None, method='GET', input_stream=None, content_type=None, content_length=None, errors_stream=None, multithread=False, multiprocess=False, run_once=False, headers=None, data=None, environ_base=None, environ_overrides=None, charset='utf-8'): path_s = make_literal_wrapper(path) if query_string is None and path_s('?') in path: path, query_string = path.split(path_s('?'), 1) self.charset = charset self.path = iri_to_uri(path) if base_url is not None: base_url = url_fix(iri_to_uri(base_url, charset), charset) self.base_url = base_url if isinstance(query_string, (bytes, text_type)): self.query_string = query_string else: if query_string is None: query_string = MultiDict() elif not isinstance(query_string, MultiDict): query_string = MultiDict(query_string) self.args = query_string self.method = method if headers is None: headers = Headers() elif not isinstance(headers, Headers): headers = Headers(headers) self.headers = headers if content_type is not None: self.content_type = content_type if errors_stream is None: errors_stream = sys.stderr self.errors_stream = errors_stream self.multithread = multithread self.multiprocess = multiprocess self.run_once = run_once self.environ_base = environ_base self.environ_overrides = environ_overrides self.input_stream = input_stream self.content_length = content_length self.closed = False if data: if input_stream is not None: raise TypeError('can\'t provide input stream and data') if hasattr(data, 'read'): data = data.read() if isinstance(data, text_type): data = data.encode(self.charset) if isinstance(data, bytes): self.input_stream = BytesIO(data) if self.content_length is None: self.content_length = len(data) else: for key, value in _iter_data(data): if isinstance(value, (tuple, dict)) or \ hasattr(value, 'read'): self._add_file_from_data(key, value) else: self.form.setlistdefault(key).append(value)
def test_iri_safe_conversion(self): self.assert_strict_equal(urls.iri_to_uri(u'magnet:?foo=bar'), 'magnet:?foo=bar') self.assert_strict_equal(urls.iri_to_uri(u'itms-service://?foo=bar'), 'itms-service:?foo=bar') self.assert_strict_equal(urls.iri_to_uri(u'itms-service://?foo=bar', safe_conversion=True), 'itms-service://?foo=bar')
def test_iri_safe_conversion(): strict_eq(urls.iri_to_uri(u'magnet:?foo=bar'), 'magnet:?foo=bar') strict_eq(urls.iri_to_uri(u'itms-service://?foo=bar'), 'itms-service:?foo=bar') strict_eq(urls.iri_to_uri(u'itms-service://?foo=bar', safe_conversion=True), 'itms-service://?foo=bar')
def redirect(location, code=302): """Return a response object (a WSGI application) that, if called, redirects the client to the target location. Supported codes are 301, 302, 303, 305, and 307. 300 is not supported because it's not a real redirect and 304 because it's the answer for a request with a request with defined If-Modified-Since headers. .. versionadded:: 0.6 The location can now be unicode strings that are encoded using the :func:`iri_to_uri` function. :param location: the location the response should redirect to. :param code: the redirect status code. """ assert code in (301, 302, 303, 305, 307), 'invalid code' from werkzeug.wrappers import BaseResponse display_location = location if isinstance(location, unicode): from werkzeug.urls import iri_to_uri location = iri_to_uri(location) response = BaseResponse( '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n' '<title>Redirecting...</title>\n' '<h1>Redirecting...</h1>\n' '<p>You should be redirected automatically to target URL: ' '<a href="%s">%s</a>. If not click the link.' % (location, display_location), code, mimetype='text/html') response.headers['Location'] = location return response
def redirect(location, code=302): """Return a response object (a WSGI application) that, if called, redirects the client to the target location. Supported codes are 301, 302, 303, 305, and 307. 300 is not supported because it's not a real redirect and 304 because it's the answer for a request with a request with defined If-Modified-Since headers. .. versionadded:: 0.6 The location can now be a unicode string that is encoded using the :func:`iri_to_uri` function. :param location: the location the response should redirect to. :param code: the redirect status code. defaults to 302. """ from werkzeug.wrappers import Response display_location = escape(location) if isinstance(location, text_type): # Safe conversion is necessary here as we might redirect # to a broken URI scheme (for instance itms-services). from werkzeug.urls import iri_to_uri location = iri_to_uri(location, safe_conversion=True) response = Response( '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n' '<title>Redirecting...</title>\n' '<h1>Redirecting...</h1>\n' '<p>You should be redirected automatically to target URL: ' '<a href="%s">%s</a>. If not click the link.' % (escape(location), display_location), code, mimetype='text/html') response.headers['Location'] = location return response
def redirect(location, code=302): """Return a response object (a WSGI application) that, if called, redirects the client to the target location. Supported codes are 301, 302, 303, 305, and 307. 300 is not supported because it's not a real redirect and 304 because it's the answer for a request with a request with defined If-Modified-Since headers. .. versionadded:: 0.6 The location can now be a unicode string that is encoded using the :func:`iri_to_uri` function. :param location: the location the response should redirect to. :param code: the redirect status code. defaults to 302. """ display_location = escape(location) if isinstance(location, str): location = iri_to_uri(location) response = Response( '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n' '<title>Redirecting...</title>\n' '<h1>Redirecting...</h1>\n' '<p>You should be redirected automatically to target URL: ' '<a href="%s">%s</a>. If not click the link.' % (escape(location), display_location), code, mimetype="text/html") response.headers["Location"] = location return response
def process_bind_param(self, value, dialect): if not value: return value if isinstance(value, str): value = value.decode('utf-8') # TODO: Ensure NFC order. value = iri_to_uri(value) return value
def test_iri_support(self): self.assert_raises(UnicodeError, urls.uri_to_iri, u'http://föö.com/') self.assert_raises(UnicodeError, urls.iri_to_uri, 'http://föö.com/') assert urls.uri_to_iri('http://xn--n3h.net/') == u'http://\u2603.net/' assert urls.uri_to_iri('http://%C3%BCser:p%C3%[email protected]/p%C3%A5th') == \ u'http://\xfcser:p\xe4ssword@\u2603.net/p\xe5th' assert urls.iri_to_uri(u'http://☃.net/') == 'http://xn--n3h.net/' assert urls.iri_to_uri(u'http://üser:pässword@☃.net/påth') == \ 'http://%C3%BCser:p%C3%[email protected]/p%C3%A5th' assert urls.uri_to_iri('http://test.com/%3Fmeh?foo=%26%2F') == \ u'http://test.com/%3Fmeh?foo=%26%2F' # this should work as well, might break on 2.4 because of a broken # idna codec assert urls.uri_to_iri('/foo') == u'/foo' assert urls.iri_to_uri(u'/foo') == '/foo'
def redirect(location, code = 302): from werkzeug.wrappers import BaseResponse display_location = location if isinstance(location, unicode): from werkzeug.urls import iri_to_uri location = iri_to_uri(location) response = BaseResponse('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n<title>Redirecting...</title>\n<h1>Redirecting...</h1>\n<p>You should be redirected automatically to target URL: <a href="%s">%s</a>. If not click the link.' % (location, display_location), code, mimetype='text/html') response.headers['Location'] = location return response
def __init__(self, location, code=302): self.display_location = location if isinstance(location, unicode): from werkzeug.urls import iri_to_uri location = iri_to_uri(location) self.location = location self.code = code self.response = self._get_response()
def _redirect_to_nginx(location): """This creates an internal redirection to a specified location. This feature is only supported by nginx. See http://wiki.nginx.org/X-accel for more information about it. """ response = Response(status=200) location = iri_to_uri(location, safe_conversion=True) response.headers['X-Accel-Redirect'] = location return response
def test_iri_support(self): self.assert_raises(UnicodeError, urls.uri_to_iri, u"http://föö.com/") self.assert_raises(UnicodeError, urls.iri_to_uri, "http://föö.com/") assert urls.uri_to_iri("http://xn--n3h.net/") == u"http://\u2603.net/" assert ( urls.uri_to_iri("http://%C3%BCser:p%C3%[email protected]/p%C3%A5th") == u"http://\xfcser:p\xe4ssword@\u2603.net/p\xe5th" ) assert urls.iri_to_uri(u"http://☃.net/") == "http://xn--n3h.net/" assert ( urls.iri_to_uri(u"http://üser:pässword@☃.net/påth") == "http://%C3%BCser:p%C3%[email protected]/p%C3%A5th" ) assert urls.uri_to_iri("http://test.com/%3Fmeh?foo=%26%2F") == u"http://test.com/%3Fmeh?foo=%26%2F" # this should work as well, might break on 2.4 because of a broken # idna codec assert urls.uri_to_iri("/foo") == u"/foo" assert urls.iri_to_uri(u"/foo") == "/foo"
def test_uri_iri_normalization(): uri = "http://xn--f-rgao.com/%E2%98%90/fred?utf8=%E2%9C%93" iri = u"http://föñ.com/\N{BALLOT BOX}/fred?utf8=\u2713" tests = [ u"http://föñ.com/\N{BALLOT BOX}/fred?utf8=\u2713", u"http://xn--f-rgao.com/\u2610/fred?utf8=\N{CHECK MARK}", b"http://xn--f-rgao.com/%E2%98%90/fred?utf8=%E2%9C%93", u"http://xn--f-rgao.com/%E2%98%90/fred?utf8=%E2%9C%93", u"http://föñ.com/\u2610/fred?utf8=%E2%9C%93", b"http://xn--f-rgao.com/\xe2\x98\x90/fred?utf8=\xe2\x9c\x93", ] for test in tests: assert urls.uri_to_iri(test) == iri assert urls.iri_to_uri(test) == uri assert urls.uri_to_iri(urls.iri_to_uri(test)) == iri assert urls.iri_to_uri(urls.uri_to_iri(test)) == uri assert urls.uri_to_iri(urls.uri_to_iri(test)) == iri assert urls.iri_to_uri(urls.iri_to_uri(test)) == uri
def test_uri_iri_normalization(self): uri = 'http://xn--f-rgao.com/%E2%98%90/fred?utf8=%E2%9C%93' iri = u'http://föñ.com/\N{BALLOT BOX}/fred?utf8=\u2713' tests = [ u'http://föñ.com/\N{BALLOT BOX}/fred?utf8=\u2713', u'http://xn--f-rgao.com/\u2610/fred?utf8=\N{CHECK MARK}', b'http://xn--f-rgao.com/%E2%98%90/fred?utf8=%E2%9C%93', u'http://xn--f-rgao.com/%E2%98%90/fred?utf8=%E2%9C%93', u'http://föñ.com/\u2610/fred?utf8=%E2%9C%93', b'http://xn--f-rgao.com/\xe2\x98\x90/fred?utf8=\xe2\x9c\x93', ] for test in tests: self.assert_equal(urls.uri_to_iri(test), iri) self.assert_equal(urls.iri_to_uri(test), uri) self.assert_equal(urls.uri_to_iri(urls.iri_to_uri(test)), iri) self.assert_equal(urls.iri_to_uri(urls.uri_to_iri(test)), uri) self.assert_equal(urls.uri_to_iri(urls.uri_to_iri(test)), iri) self.assert_equal(urls.iri_to_uri(urls.iri_to_uri(test)), uri)
def test_iri_support(self): self.assert_strict_equal(urls.uri_to_iri('http://xn--n3h.net/'), u'http://\u2603.net/') self.assert_strict_equal( urls.uri_to_iri(b'http://%C3%BCser:p%C3%[email protected]/p%C3%A5th'), u'http://\xfcser:p\xe4ssword@\u2603.net/p\xe5th') self.assert_strict_equal(urls.iri_to_uri(u'http://☃.net/'), 'http://xn--n3h.net/') self.assert_strict_equal( urls.iri_to_uri(u'http://üser:pässword@☃.net/påth'), 'http://%C3%BCser:p%C3%[email protected]/p%C3%A5th') self.assert_strict_equal(urls.uri_to_iri('http://test.com/%3Fmeh?foo=%26%2F'), u'http://test.com/%3Fmeh?foo=%26%2F') # this should work as well, might break on 2.4 because of a broken # idna codec self.assert_strict_equal(urls.uri_to_iri(b'/foo'), u'/foo') self.assert_strict_equal(urls.iri_to_uri(u'/foo'), '/foo') self.assert_strict_equal(urls.iri_to_uri(u'http://föö.com:8080/bam/baz'), 'http://xn--f-1gaa.com:8080/bam/baz')
def _error_common(template, template_modal, code, e): # g.is_ajax здесь не всегда присутствует, так что так is_ajax = request.headers.get('X-AJAX') == '1' or request.args.get('isajax') == '1' if is_ajax: html = render_template(template_modal, error=e, error_code=code) response = jsonify({'page_content': {'modal': html}}) response.status_code = code # for github-fetch polyfill: response.headers['X-Request-URL'] = iri_to_uri(request.url) return response html = render_template(template, error=e, error_code=code) return html, code
def get_wsgi_headers(self, environ): headers = Headers(self.headers) location = headers.get('location') if location is not None: if isinstance(location, unicode): location = iri_to_uri(location) headers['Location'] = urlparse.urljoin(get_current_url(environ, root_only=True), location) content_location = headers.get('content-location') if content_location is not None and isinstance(content_location, unicode): headers['Content-Location'] = iri_to_uri(content_location) if 100 <= self.status_code < 200 or self.status_code == 204: headers['Content-Length'] = '0' elif self.status_code == 304: remove_entity_headers(headers) if self.is_sequence and 'content-length' not in self.headers: try: content_length = sum((len(str(x)) for x in self.response)) except UnicodeError: pass else: headers['Content-Length'] = str(content_length) return headers
def redirect(location, status=302): """ which is seldom used in api server """ from werkzeug.wrappers import Response from werkzeug.urls import iri_to_uri location = iri_to_uri(location, safe_conversion=True) return Response( "<!DOCTYPE html>\ <html>\ <h1>Redirecting...</h1>\ <a href='{0}'>touch this to make manually redirection</a>\ </html>" .format(location), status=status, headers={'Location': location})
def handle_get(path): """ Handle the GET """ path = '/api' + iri_to_uri(request.url).partition('/api')[-1] if path == '/api': abort(400) logging.debug('Received %s', path) dump = session.get(path) logging.debug('From Fake APIC: %s', dump.json()) response = json.dumps(dump.json(), indent=4, separators=(',', ':')) failure_hdlr.enforce_delay() if failure_hdlr.enforce_connection_failure(): abort(400) return response
def get_page(path=''): path = Page.strip_path(path) page = page_service.get_page_by_path(path) if not page: # Try if this might be a redirect. redirection = Redirect.query.filter(Redirect.fro == path).first() if redirection: # get GET parameters so they can be applied to the redirected # URL if request.args: redir_url = redirection.to + '?' for key in request.args: redir_url += key + '=' + \ request.args[key] + '&' # this is necssary to prevent incorrect escaping return redirect(iri_to_uri(redir_url)) return redirect(redirection.to) return abort(404) if not page_service.can_user_read_page(page, current_user): return abort(403) revision = page.get_latest_revision() if not revision: return abort(500) # Check if the current user has already entered data in this custom # form if getattr(revision, 'custom_form', False): if current_user.is_authenticated and current_user.has_paid: all_form_results = CustomFormResult.query \ .filter(CustomFormResult.form_id == revision.custom_form.id) form_result = all_form_results \ .filter(CustomFormResult.owner_id == current_user.id).first() if form_result: revision.custom_form_data = form_result.data.replace('"', "'") can_write = role_service.user_has_role(current_user, Roles.PAGE_WRITE) return render_template('%s/view_single.htm' % (page.type), page=page, revision=revision, title=revision.title, context=revision.__class__.context, can_write=can_write)
def ajax_template_response(response): if response.headers.get('Vary'): response.headers['Vary'] = 'X-AJAX, ' + response.headers['Vary'] else: response.headers['Vary'] = 'X-AJAX' if not getattr(g, 'is_ajax', False): return response if not response.direct_passthrough and response.data and response.data.startswith(b'{') and response.content_type == 'text/html; charset=utf-8': response.content_type = 'application/json' # for github-fetch polyfill: response.headers['X-Request-URL'] = iri_to_uri(request.url) elif response.status_code == 302: # Люблю разрабов js во всех смыслах response.data = flask_json.dumps({'page_content': {'redirect': response.headers.get('Location')}}) response.content_type = 'application/json' response.status_code = 200 return response
def short_url(id): context['short_url'] = id get_long_url() if context['long_url']: if context['json'] == True: return jsonify(long_url=context['long_url'], short_url= \ request.url_root + context['short_url']) if context['direct_redirect']: return redirect(iri_to_uri(context['long_url'])) else: return render_template('show.html', long_url=context['long_url'], \ short_url=request.url_root+context['short_url']) else: if context['json'] == True: return jsonify(error='404') abort(404)
def test_my_api(): protcol = 'http://' domain = u'ほげ.com' query = u'?q=ふが' url = protcol + domain # idna_url = protcol + domain.encode('idna') idna_url = iri_to_uri(url) responses.add(responses.GET, idna_url, json={"error": "not found"}, status=404) resp = requests.get(url) print resp.json() assert resp.json() == {"error": "not found"} assert len(responses.calls) == 1 #assert responses.calls[0].request.url == url_quote(u'http://hoge?q=ぐーぐる') assert responses.calls[0].response.text == '{"error": "not found"}'
def get_page(path=''): path = Page.strip_path(path) page = Page.get_by_path(path) if not page: # Try if this might be a redirect. print("not page") redirection = Redirect.query.filter(Redirect.fro == path).first() if redirection: # get GET parameters so they can be applied to the redirected # URL if request.args: redir_url = redirection.to + '?' for key in request.args: redir_url += key + '=' + \ request.args[key] + '&' print(redir_url) # this is necssary to prevent incorrect escaping return redirect(iri_to_uri(redir_url)) return redirect(redirection.to) return abort(404) if not PageAPI.can_read(page): return abort(403) revision = page.get_latest_revision() if not revision: return abort(500) return render_template('%s/view_single.htm' % (page.type), page=page, revision=revision, title=revision.title, context=revision.__class__.context)
def dump_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=False, httponly=False, charset='utf-8', sync_expires=True): """Creates a new Set-Cookie header without the ``Set-Cookie`` prefix The parameters are the same as in the cookie Morsel object in the Python standard library but it accepts unicode data, too. On Python 3 the return value of this function will be a unicode string, on Python 2 it will be a native string. In both cases the return value is usually restricted to ascii as the vast majority of values are properly escaped, but that is no guarantee. If a unicode string is returned it's tunneled through latin1 as required by PEP 3333. The return value is not ASCII safe if the key contains unicode characters. This is technically against the specification but happens in the wild. It's strongly recommended to not use non-ASCII values for the keys. :param max_age: should be a number of seconds, or `None` (default) if the cookie should last only as long as the client's browser session. Additionally `timedelta` objects are accepted, too. :param expires: should be a `datetime` object or unix timestamp. :param path: limits the cookie to a given path, per default it will span the whole domain. :param domain: Use this if you want to set a cross-domain cookie. For example, ``domain=".example.com"`` will set a cookie that is readable by the domain ``www.example.com``, ``foo.example.com`` etc. Otherwise, a cookie will only be readable by the domain that set it. :param secure: The cookie will only be available via HTTPS :param httponly: disallow JavaScript to access the cookie. This is an extension to the cookie standard and probably not supported by all browsers. :param charset: the encoding for unicode values. :param sync_expires: automatically set expires if max_age is defined but expires not. """ key = to_bytes(key, charset) value = to_bytes(value, charset) if path is not None: path = iri_to_uri(path, charset) domain = _make_cookie_domain(domain) if isinstance(max_age, timedelta): max_age = (max_age.days * 60 * 60 * 24) + max_age.seconds if expires is not None: if not isinstance(expires, string_types): expires = cookie_date(expires) elif max_age is not None and sync_expires: expires = to_bytes(cookie_date(time() + max_age)) buf = [key + b'=' + _cookie_quote(value)] # XXX: In theory all of these parameters that are not marked with `None` # should be quoted. Because stdlib did not quote it before I did not # want to introduce quoting there now. for k, v, q in ((b'Domain', domain, True), (b'Expires', expires, False,), (b'Max-Age', max_age, False), (b'Secure', secure, None), (b'HttpOnly', httponly, None), (b'Path', path, False)): if q is None: if v: buf.append(k) continue if v is None: continue tmp = bytearray(k) if not isinstance(v, (bytes, bytearray)): v = to_bytes(text_type(v), charset) if q: v = _cookie_quote(v) tmp += b'=' + v buf.append(bytes(tmp)) # The return value will be an incorrectly encoded latin1 header on # Python 3 for consistency with the headers object and a bytestring # on Python 2 because that's how the API makes more sense. rv = b'; '.join(buf) if not PY2: rv = rv.decode('latin1') return rv
def test_quoting_of_local_urls(): """Make sure that urls without domain quote correctly.""" rv = iri_to_uri(u'/foo\x8f') assert rv == '/foo%C2%8F' assert type(rv) is str
def dump_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=False, httponly=False, charset='utf-8', sync_expires=True, max_size=4093, samesite=None): """Creates a new Set-Cookie header without the ``Set-Cookie`` prefix The parameters are the same as in the cookie Morsel object in the Python standard library but it accepts unicode data, too. On Python 3 the return value of this function will be a unicode string, on Python 2 it will be a native string. In both cases the return value is usually restricted to ascii as the vast majority of values are properly escaped, but that is no guarantee. If a unicode string is returned it's tunneled through latin1 as required by PEP 3333. The return value is not ASCII safe if the key contains unicode characters. This is technically against the specification but happens in the wild. It's strongly recommended to not use non-ASCII values for the keys. :param max_age: should be a number of seconds, or `None` (default) if the cookie should last only as long as the client's browser session. Additionally `timedelta` objects are accepted, too. :param expires: should be a `datetime` object or unix timestamp. :param path: limits the cookie to a given path, per default it will span the whole domain. :param domain: Use this if you want to set a cross-domain cookie. For example, ``domain=".example.com"`` will set a cookie that is readable by the domain ``www.example.com``, ``foo.example.com`` etc. Otherwise, a cookie will only be readable by the domain that set it. :param secure: The cookie will only be available via HTTPS :param httponly: disallow JavaScript to access the cookie. This is an extension to the cookie standard and probably not supported by all browsers. :param charset: the encoding for unicode values. :param sync_expires: automatically set expires if max_age is defined but expires not. :param max_size: Warn if the final header value exceeds this size. The default, 4093, should be safely `supported by most browsers <cookie_>`_. Set to 0 to disable this check. :param samesite: Limits the scope of the cookie such that it will only be attached to requests if those requests are "same-site". .. _`cookie`: http://browsercookielimits.squawky.net/ """ key = to_bytes(key, charset) value = to_bytes(value, charset) if path is not None: path = iri_to_uri(path, charset) domain = _make_cookie_domain(domain) if isinstance(max_age, timedelta): max_age = (max_age.days * 60 * 60 * 24) + max_age.seconds if expires is not None: if not isinstance(expires, string_types): expires = cookie_date(expires) elif max_age is not None and sync_expires: expires = to_bytes(cookie_date(time() + max_age)) samesite = samesite.title() if samesite else None if samesite not in ('Strict', 'Lax', None): raise ValueError("invalid SameSite value; must be 'Strict', 'Lax' or None") buf = [key + b'=' + _cookie_quote(value)] # XXX: In theory all of these parameters that are not marked with `None` # should be quoted. Because stdlib did not quote it before I did not # want to introduce quoting there now. for k, v, q in ((b'Domain', domain, True), (b'Expires', expires, False,), (b'Max-Age', max_age, False), (b'Secure', secure, None), (b'HttpOnly', httponly, None), (b'Path', path, False), (b'SameSite', samesite, False)): if q is None: if v: buf.append(k) continue if v is None: continue tmp = bytearray(k) if not isinstance(v, (bytes, bytearray)): v = to_bytes(text_type(v), charset) if q: v = _cookie_quote(v) tmp += b'=' + v buf.append(bytes(tmp)) # The return value will be an incorrectly encoded latin1 header on # Python 3 for consistency with the headers object and a bytestring # on Python 2 because that's how the API makes more sense. rv = b'; '.join(buf) if not PY2: rv = rv.decode('latin1') # Warn if the final value of the cookie is less than the limit. If the # cookie is too large, then it may be silently ignored, which can be quite # hard to debug. cookie_size = len(rv) if max_size and cookie_size > max_size: value_size = len(value) warnings.warn( 'The "{key}" cookie is too large: the value was {value_size} bytes' ' but the header required {extra_size} extra bytes. The final size' ' was {cookie_size} bytes but the limit is {max_size} bytes.' ' Browsers may silently ignore cookies larger than this.'.format( key=key, value_size=value_size, extra_size=cookie_size - value_size, cookie_size=cookie_size, max_size=max_size ), stacklevel=2 ) return rv
def safe_url(self): """ Encoded URL as string rather than unicode. """ return iri_to_uri(self.submitted_url)
def dump_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=False, httponly=False, charset='utf-8', sync_expires=True, max_size=4093, samesite=None): """Creates a new Set-Cookie header without the ``Set-Cookie`` prefix The parameters are the same as in the cookie Morsel object in the Python standard library but it accepts unicode data, too. On Python 3 the return value of this function will be a unicode string, on Python 2 it will be a native string. In both cases the return value is usually restricted to ascii as the vast majority of values are properly escaped, but that is no guarantee. If a unicode string is returned it's tunneled through latin1 as required by PEP 3333. The return value is not ASCII safe if the key contains unicode characters. This is technically against the specification but happens in the wild. It's strongly recommended to not use non-ASCII values for the keys. :param max_age: should be a number of seconds, or `None` (default) if the cookie should last only as long as the client's browser session. Additionally `timedelta` objects are accepted, too. :param expires: should be a `datetime` object or unix timestamp. :param path: limits the cookie to a given path, per default it will span the whole domain. :param domain: Use this if you want to set a cross-domain cookie. For example, ``domain=".example.com"`` will set a cookie that is readable by the domain ``www.example.com``, ``foo.example.com`` etc. Otherwise, a cookie will only be readable by the domain that set it. :param secure: The cookie will only be available via HTTPS :param httponly: disallow JavaScript to access the cookie. This is an extension to the cookie standard and probably not supported by all browsers. :param charset: the encoding for unicode values. :param sync_expires: automatically set expires if max_age is defined but expires not. :param max_size: Warn if the final header value exceeds this size. The default, 4093, should be safely `supported by most browsers <cookie_>`_. Set to 0 to disable this check. :param samesite: Limits the scope of the cookie such that it will only be attached to requests if those requests are "same-site". .. _`cookie`: http://browsercookielimits.squawky.net/ """ key = to_bytes(key, charset) value = to_bytes(value, charset) if path is not None: path = iri_to_uri(path, charset) domain = _make_cookie_domain(domain) if isinstance(max_age, timedelta): max_age = (max_age.days * 60 * 60 * 24) + max_age.seconds if expires is not None: if not isinstance(expires, string_types): expires = cookie_date(expires) elif max_age is not None and sync_expires: expires = to_bytes(cookie_date(time() + max_age)) samesite = samesite.title() if samesite else None if samesite not in ('Strict', 'Lax', None): raise ValueError( "invalid SameSite value; must be 'Strict', 'Lax' or None") buf = [key + b'=' + _cookie_quote(value)] # XXX: In theory all of these parameters that are not marked with `None` # should be quoted. Because stdlib did not quote it before I did not # want to introduce quoting there now. for k, v, q in ((b'Domain', domain, True), ( b'Expires', expires, False, ), (b'Max-Age', max_age, False), (b'Secure', secure, None), (b'HttpOnly', httponly, None), (b'Path', path, False), (b'SameSite', samesite, False)): if q is None: if v: buf.append(k) continue if v is None: continue tmp = bytearray(k) if not isinstance(v, (bytes, bytearray)): v = to_bytes(text_type(v), charset) if q: v = _cookie_quote(v) tmp += b'=' + v buf.append(bytes(tmp)) # The return value will be an incorrectly encoded latin1 header on # Python 3 for consistency with the headers object and a bytestring # on Python 2 because that's how the API makes more sense. rv = b'; '.join(buf) if not PY2: rv = rv.decode('latin1') # Warn if the final value of the cookie is less than the limit. If the # cookie is too large, then it may be silently ignored, which can be quite # hard to debug. cookie_size = len(rv) if max_size and cookie_size > max_size: value_size = len(value) warnings.warn( 'The "{key}" cookie is too large: the value was {value_size} bytes' ' but the header required {extra_size} extra bytes. The final size' ' was {cookie_size} bytes but the limit is {max_size} bytes.' ' Browsers may silently ignore cookies larger than this.'.format( key=key, value_size=value_size, extra_size=cookie_size - value_size, cookie_size=cookie_size, max_size=max_size), stacklevel=2) return rv
def __init__(self, path='/', base_url=None, query_string=None, method='GET', input_stream=None, content_type=None, content_length=None, errors_stream=None, multithread=False, multiprocess=False, run_once=False, headers=None, data=None, environ_base=None, environ_overrides=None, charset='utf-8', mimetype=None): path_s = make_literal_wrapper(path) if query_string is None and path_s('?') in path: path, query_string = path.split(path_s('?'), 1) self.charset = charset self.path = iri_to_uri(path) if base_url is not None: base_url = url_fix(iri_to_uri(base_url, charset), charset) self.base_url = base_url if isinstance(query_string, (bytes, text_type)): self.query_string = query_string else: if query_string is None: query_string = MultiDict() elif not isinstance(query_string, MultiDict): query_string = MultiDict(query_string) self.args = query_string self.method = method if headers is None: headers = Headers() elif not isinstance(headers, Headers): headers = Headers(headers) self.headers = headers if content_type is not None: self.content_type = content_type if errors_stream is None: errors_stream = sys.stderr self.errors_stream = errors_stream self.multithread = multithread self.multiprocess = multiprocess self.run_once = run_once self.environ_base = environ_base self.environ_overrides = environ_overrides self.input_stream = input_stream self.content_length = content_length self.closed = False if data: if input_stream is not None: raise TypeError('can\'t provide input stream and data') if hasattr(data, 'read'): data = data.read() if isinstance(data, text_type): data = data.encode(self.charset) if isinstance(data, bytes): self.input_stream = BytesIO(data) if self.content_length is None: self.content_length = len(data) else: for key, value in _iter_data(data): if isinstance(value, (tuple, dict)) or \ hasattr(value, 'read'): self._add_file_from_data(key, value) else: self.form.setlistdefault(key).append(value) if mimetype is not None: self.mimetype = mimetype
def redirectCustom(location, *render_args, code=302, response_cb=None, force_redirect=False): """ ======= Summary ======= Combines functionality of :func:`werkzeug.utils.redirect` with :func:`flask.templating.render_template` to allow for virtual redirection to an endpoint with any HTTP status code.\n ========= Use Cases ========= 1. render template at a custom url (doesn't have to be an endpoint) def index(): return redirectCustom('http://localhost:5000/notfound', render_template('not_found.html'), code=404) def index(): html = '<h1>Are you lost {{ username }}?</h1>' return redirectCustom(url_for('notfound'), render_template_string(html), username='******', code=404) 2. customizing the response before sending to the client def index(): def addAuthHeaders(response): response.headers['Access-Control-Allow-Origin' = '*' response.headers['Access-Control-Allow-Headers'] = 'origin, x-requested-with, content-type' response.headers['Access-Control-Allow-Methods'] = 'PUT, GET, POST, DELETE, OPTIONS' return redirectCustom(url_for('login'), render_template('login_custom.html'), code=403, response_cb=addAuthHeaders) 3. redirecting with a custom HTTP status code (normally restricted to 300's) def index(): return redirectCustom(url_for('http://localhost:5000/error'), showError()) 4. forcing redirection when client normally would ignore location header def index(): return redirectCustom(url_for(showError), showError(), code=500, force_redirect=True) :note: the endpoint logic is only executed when a the view function is passed in render_args :param location: the location the response should virtually redirect to :param render_args: the return value from a view / template rendering function :param code: the return HTTP status code, defaults to 302 like a normal redirect :param response_cb: callback function taking :class:`werkzeug.wrappers.Response` object as arg and returning edited response :param force_redirect: whether to force redirection on client, only needed when client ignores location header :return: client viewable :class:`werkzeug.wrappers.Response` object """ display_location = escape(location) if isinstance(location, str): # Safe conversion as stated in :func:`werkzeug.utils.redirect` location = iri_to_uri(location, safe_conversion=True) # create a response object, from rendered data (accepts None) response = make_response(*render_args) # if no render_args given fill response with default redirect html if len(render_args) <= 0: response.response = '<!DOCTYPE HTML">\n' \ '<html><head><meta charset="utf-8"><meta http-equiv="refresh" content="0; URL={location}">' \ '<title>Redirecting</title></head>\n' \ '<body><script type="text/javascript">window.location.href={location};</script></body></html>' if force_redirect else \ '<body><h1>Redirecting...</h1>\n' \ '<p>You should be redirected automatically to target URL: ' \ '<a href="{location}">{display_location}</a>. If not click the link.</p></body></html>' \ .format(location=escape(location), display_location=display_location) response.mimetype = 'text/html' # customize response if needed if response_cb is not None: response = response_cb(response) # override return code if set from render args # if len(render_args) == 3: response.status = code # change response location response.headers['Location'] = location return response
def __init__(self, path='/', base_url=None, query_string=None, method='GET', input_stream=None, content_type=None, content_length=None, errors_stream=None, multithread=False, multiprocess=False, run_once=False, headers=None, data=None, environ_base=None, environ_overrides=None, charset='utf-8'): if query_string is None and '?' in path: path, query_string = path.split('?', 1) self.charset = charset if isinstance(path, unicode): path = iri_to_uri(path, charset) self.path = path if base_url is not None: if isinstance(base_url, unicode): base_url = iri_to_uri(base_url, charset) else: base_url = url_fix(base_url, charset) self.base_url = base_url if isinstance(query_string, basestring): self.query_string = query_string else: if query_string is None: query_string = MultiDict() elif not isinstance(query_string, MultiDict): query_string = MultiDict(query_string) self.args = query_string self.method = method if headers is None: headers = Headers() elif not isinstance(headers, Headers): headers = Headers(headers) self.headers = headers self.content_type = content_type if errors_stream is None: errors_stream = sys.stderr self.errors_stream = errors_stream self.multithread = multithread self.multiprocess = multiprocess self.run_once = run_once self.environ_base = environ_base self.environ_overrides = environ_overrides self.input_stream = input_stream self.content_length = content_length self.closed = False if data: if input_stream is not None: raise TypeError("can't provide input stream and data") if isinstance(data, basestring): self.input_stream = StringIO(data) if self.content_length is None: self.content_length = len(data) else: for key, value in _iter_data(data): if isinstance(value, (tuple, dict)) or hasattr(value, 'read'): self._add_file_from_data(key, value) else: self.form.setlistdefault(key).append(value)