From d71bd57b645190cf3edb8772f8886272c30c2a6b Mon Sep 17 00:00:00 2001 From: Sander Steffann Date: Wed, 22 Nov 2017 15:47:03 +0100 Subject: [PATCH] SchemaJSRenderer renders invalid Javascript (#5607) * SchemaJSRenderer renders invalid Javascript Under Py3 the base64.b64encode() method returns a binary object, which gets rendered as `b'...'` in schema.js. This results in the output becoming: var coreJSON = window.atob('b'eyJf...''); which is invalid Javascript. Because base64 only uses ASCII characters it is safe to decode('ascii') it. Under Py2 this will result in a unicode object, which is fine. Under Py3 it results in a string, which is also fine. This solves the problem and results in a working schema.js output. * Add regression test for #5608 * Add regression test for #5608 * Apparently the linter on Travis wants the imports in a different order than on my box... --- rest_framework/renderers.py | 2 +- tests/test_renderers.py | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index bbefb4624..80a22dee5 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -852,7 +852,7 @@ class SchemaJSRenderer(BaseRenderer): def render(self, data, accepted_media_type=None, renderer_context=None): codec = coreapi.codecs.CoreJSONCodec() - schema = base64.b64encode(codec.encode(data)) + schema = base64.b64encode(codec.encode(data)).decode('ascii') template = loader.get_template(self.template) context = {'schema': mark_safe(schema)} diff --git a/tests/test_renderers.py b/tests/test_renderers.py index 54b3ce964..ba8400c06 100644 --- a/tests/test_renderers.py +++ b/tests/test_renderers.py @@ -18,7 +18,7 @@ import coreapi from rest_framework import permissions, serializers, status from rest_framework.renderers import ( AdminRenderer, BaseRenderer, BrowsableAPIRenderer, DocumentationRenderer, - HTMLFormRenderer, JSONRenderer, StaticHTMLRenderer + HTMLFormRenderer, JSONRenderer, SchemaJSRenderer, StaticHTMLRenderer ) from rest_framework.request import Request from rest_framework.response import Response @@ -736,3 +736,20 @@ class TestDocumentationRenderer(TestCase): html = renderer.render(document, accepted_media_type="text/html", renderer_context={"request": request}) assert '

Data Endpoint API

' in html + + +class TestSchemaJSRenderer(TestCase): + + def test_schemajs_output(self): + """ + Test output of the SchemaJS renderer as per #5608. Django 2.0 on Py3 prints binary data as b'xyz' in templates, + and the base64 encoding used by SchemaJSRenderer outputs base64 as binary. Test fix. + """ + factory = APIRequestFactory() + request = factory.get('/') + + renderer = SchemaJSRenderer() + + output = renderer.render('data', renderer_context={"request": request}) + assert "'ImRhdGEi'" in output + assert "'b'ImRhdGEi''" not in output