Revert "remove Content-Type restriction for manifests (bug 778214)"
This reverts commit 35ce8e5844
.
This commit is contained in:
Родитель
c9f2f1b10c
Коммит
17bc34e36f
|
@ -800,6 +800,8 @@ class TestCreateApp(BaseOAuth):
|
|||
|
||||
response_mock = Mock()
|
||||
response_mock.read.return_value = '{"name": "Some App"}'
|
||||
response_mock.headers = {'Content-Type':
|
||||
'application/x-web-app-manifest+json'}
|
||||
|
||||
self.urlopen_mock = patcher.start()
|
||||
self.urlopen_mock.return_value = response_mock
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import base64
|
||||
from datetime import date
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
|
@ -13,6 +14,7 @@ import uuid
|
|||
from django.conf import settings
|
||||
from django.core.files.storage import default_storage as storage
|
||||
from django.core.management import call_command
|
||||
from django.utils.http import urlencode
|
||||
|
||||
from celeryutils import task
|
||||
from django_statsd.clients import statsd
|
||||
|
@ -152,8 +154,8 @@ def run_validator(file_path, for_appversions=None, test_all_tiers=False,
|
|||
return validate(path,
|
||||
for_appversions=for_appversions,
|
||||
format='json',
|
||||
# When False, this flag says to stop testing after
|
||||
# one tier fails.
|
||||
# When False, this flag says to stop testing after one
|
||||
# tier fails.
|
||||
determined=test_all_tiers,
|
||||
approved_applications=apps,
|
||||
spidermonkey=settings.SPIDERMONKEY,
|
||||
|
@ -252,9 +254,11 @@ def get_preview_sizes(ids, **kw):
|
|||
for preview in previews:
|
||||
try:
|
||||
log.info('Getting size for preview: %s' % preview.pk)
|
||||
thumb = Image.open(storage.open(preview.thumbnail_path)).size
|
||||
img = Image.open(storage.open(preview.image_path)).size
|
||||
preview.update(sizes={'thumbnail': thumb, 'image': img})
|
||||
sizes = {
|
||||
'thumbnail': Image.open(storage.open(preview.thumbnail_path)).size,
|
||||
'image': Image.open(storage.open(preview.image_path)).size,
|
||||
}
|
||||
preview.update(sizes=sizes)
|
||||
except Exception, err:
|
||||
log.error('Failed to find size of preview: %s, error: %s'
|
||||
% (addon.pk, err))
|
||||
|
@ -329,6 +333,16 @@ def _fetch_content(url):
|
|||
raise Exception(str(e.reason))
|
||||
|
||||
|
||||
def check_content_type(response, content_type,
|
||||
no_ct_message, wrong_ct_message):
|
||||
if not response.headers.get('Content-Type', '').startswith(content_type):
|
||||
if 'Content-Type' in response.headers:
|
||||
raise Exception(wrong_ct_message %
|
||||
(content_type, response.headers['Content-Type']))
|
||||
else:
|
||||
raise Exception(no_ct_message % content_type)
|
||||
|
||||
|
||||
def get_content_and_check_size(response, max_size, error_message):
|
||||
# Read one extra byte. Reject if it's too big so we don't have issues
|
||||
# downloading huge files.
|
||||
|
@ -392,6 +406,13 @@ def fetch_manifest(url, upload_pk=None, **kw):
|
|||
try:
|
||||
response = _fetch_content(url)
|
||||
|
||||
no_ct_message = _('Your manifest must be served with the HTTP '
|
||||
'header "Content-Type: %s".')
|
||||
wrong_ct_message = _('Your manifest must be served with the HTTP '
|
||||
'header "Content-Type: %s". We saw "%s".')
|
||||
check_content_type(response, 'application/x-web-app-manifest+json',
|
||||
no_ct_message, wrong_ct_message)
|
||||
|
||||
size_error_message = _('Your manifest must be less than %s bytes.')
|
||||
content = get_content_and_check_size(response,
|
||||
settings.MAX_WEBAPP_UPLOAD_SIZE,
|
||||
|
|
|
@ -284,9 +284,15 @@ def fetch_icon(webapp, **kw):
|
|||
def _fetch_manifest(url):
|
||||
try:
|
||||
response = _fetch_content(url)
|
||||
ct = response.headers.get('Content-Type', '')
|
||||
if not ct.startswith('application/x-web-app-manifest+json'):
|
||||
raise Exception('Content type is ' + ct)
|
||||
except Exception, e:
|
||||
log.error('Failed to fetch manifest from %r: %s' % (url, e))
|
||||
raise Exception('No manifest was found at that URL.')
|
||||
raise Exception('No manifest was found at that URL. Check the '
|
||||
'address and make sure the manifest is served '
|
||||
'with the HTTP header "Content-Type: '
|
||||
'application/x-web-app-manifest+json".')
|
||||
|
||||
size_error_message = _('Your manifest must be less than %s bytes.')
|
||||
content = get_content_and_check_size(response,
|
||||
|
|
|
@ -151,6 +151,7 @@ class TestFetchManifest(amo.tests.TestCase):
|
|||
|
||||
def setUp(self):
|
||||
self.upload = FileUpload.objects.create()
|
||||
self.content_type = 'application/x-web-app-manifest+json'
|
||||
|
||||
patcher = mock.patch('mkt.developers.tasks.urllib2.urlopen')
|
||||
self.urlopen_mock = patcher.start()
|
||||
|
@ -166,6 +167,7 @@ class TestFetchManifest(amo.tests.TestCase):
|
|||
def patch_urlopen(self):
|
||||
response_mock = mock.Mock()
|
||||
response_mock.read.return_value = '<default>'
|
||||
response_mock.headers = {'Content-Type': self.content_type}
|
||||
yield response_mock
|
||||
self.urlopen_mock.return_value = response_mock
|
||||
|
||||
|
@ -173,6 +175,7 @@ class TestFetchManifest(amo.tests.TestCase):
|
|||
def test_success_add_file(self, validator_mock):
|
||||
with self.patch_urlopen() as ur:
|
||||
ur.read.return_value = 'woo'
|
||||
ur.headers = {'Content-Type': self.content_type}
|
||||
|
||||
tasks.fetch_manifest('http://xx.com/manifest.json', self.upload.pk)
|
||||
upload = FileUpload.objects.get(pk=self.upload.pk)
|
||||
|
@ -183,7 +186,8 @@ class TestFetchManifest(amo.tests.TestCase):
|
|||
@mock.patch('mkt.developers.tasks.validator')
|
||||
def test_success_call_validator(self, validator_mock):
|
||||
with self.patch_urlopen() as ur:
|
||||
ur.read.return_value = 'woo'
|
||||
ct = self.content_type + '; charset=utf-8'
|
||||
ur.headers = {'Content-Type': ct}
|
||||
|
||||
tasks.fetch_manifest('http://xx.com/manifest.json', self.upload.pk)
|
||||
assert validator_mock.called
|
||||
|
@ -200,33 +204,48 @@ class TestFetchManifest(amo.tests.TestCase):
|
|||
reason = socket.gaierror(8, 'nodename nor servname provided')
|
||||
self.urlopen_mock.side_effect = urllib2.URLError(reason)
|
||||
tasks.fetch_manifest('url', self.upload.pk)
|
||||
self.check_validation('No manifest was found at that URL.')
|
||||
self.check_validation(
|
||||
'No manifest was found at that URL. Check the address and make'
|
||||
' sure the manifest is served with the HTTP header '
|
||||
'"Content-Type: application/x-web-app-manifest+json".')
|
||||
|
||||
def test_url_timeout(self):
|
||||
reason = socket.timeout('too slow')
|
||||
self.urlopen_mock.side_effect = urllib2.URLError(reason)
|
||||
tasks.fetch_manifest('url', self.upload.pk)
|
||||
self.check_validation('No manifest was found at that URL.')
|
||||
self.check_validation(
|
||||
'No manifest was found at that URL. Check the address and make'
|
||||
' sure the manifest is served with the HTTP header '
|
||||
'"Content-Type: application/x-web-app-manifest+json".')
|
||||
|
||||
def test_other_url_error(self):
|
||||
reason = Exception('Some other failure.')
|
||||
self.urlopen_mock.side_effect = urllib2.URLError(reason)
|
||||
tasks.fetch_manifest('url', self.upload.pk)
|
||||
self.check_validation('No manifest was found at that URL.')
|
||||
self.check_validation(
|
||||
'No manifest was found at that URL. Check the address and make'
|
||||
' sure the manifest is served with the HTTP header '
|
||||
'"Content-Type: application/x-web-app-manifest+json".')
|
||||
|
||||
def test_no_content_type_bad_json(self):
|
||||
def test_no_content_type(self):
|
||||
with self.patch_urlopen() as ur:
|
||||
ur.headers = {}
|
||||
|
||||
tasks.fetch_manifest('url', self.upload.pk)
|
||||
self.check_validation('JSON Parse Error')
|
||||
self.check_validation(
|
||||
'No manifest was found at that URL. Check the address and make'
|
||||
' sure the manifest is served with the HTTP header '
|
||||
'"Content-Type: application/x-web-app-manifest+json".')
|
||||
|
||||
def test_bad_content_type_bad_json(self):
|
||||
def test_bad_content_type(self):
|
||||
with self.patch_urlopen() as ur:
|
||||
ur.headers = {'Content-Type': 'x'}
|
||||
|
||||
tasks.fetch_manifest('url', self.upload.pk)
|
||||
self.check_validation('JSON Parse Error')
|
||||
self.check_validation(
|
||||
'No manifest was found at that URL. Check the address and make'
|
||||
' sure the manifest is served with the HTTP header '
|
||||
'"Content-Type: application/x-web-app-manifest+json".')
|
||||
|
||||
def test_response_too_large(self):
|
||||
with self.patch_urlopen() as ur:
|
||||
|
@ -240,7 +259,10 @@ class TestFetchManifest(amo.tests.TestCase):
|
|||
self.urlopen_mock.side_effect = urllib2.HTTPError(
|
||||
'url', 404, 'Not Found', [], None)
|
||||
tasks.fetch_manifest('url', self.upload.pk)
|
||||
self.check_validation('No manifest was found at that URL.')
|
||||
self.check_validation(
|
||||
'No manifest was found at that URL. Check the address and make'
|
||||
' sure the manifest is served with the HTTP header '
|
||||
'"Content-Type: application/x-web-app-manifest+json".')
|
||||
|
||||
def test_strip_utf8_bom(self):
|
||||
with self.patch_urlopen() as ur:
|
||||
|
|
|
@ -1433,6 +1433,7 @@ class TestUploadDetail(BaseUploadTest):
|
|||
urlopen_mock):
|
||||
rs = mock.Mock()
|
||||
rs.read.return_value = self.file_content('mozball.owa')
|
||||
rs.headers = {'Content-Type': 'application/x-web-app-manifest+json'}
|
||||
urlopen_mock.return_value = rs
|
||||
validator_mock.return_value = json.dumps(self.validation_ok())
|
||||
self.upload_file('mozball.owa')
|
||||
|
|
|
@ -47,6 +47,8 @@ response_mock.read.return_value = '''
|
|||
"installs_allowed_from": [ "https://marketplace.mozilla.org" ]
|
||||
}
|
||||
'''
|
||||
response_mock.headers = {'Content-Type':
|
||||
'application/x-web-app-manifest+json'}
|
||||
|
||||
|
||||
def get_section_url(addon, section, edit=False):
|
||||
|
|
|
@ -23,22 +23,22 @@ class Test404(amo.tests.TestCase):
|
|||
return r
|
||||
|
||||
def test_404(self):
|
||||
self._test_404('/xxx')
|
||||
r = self._test_404('/xxx')
|
||||
|
||||
def test_404_devhub(self):
|
||||
# TODO: Remove log-in bit when we remove `request.can_view_consumer`.
|
||||
assert self.client.login(username='steamcube@mozilla.com',
|
||||
password='password')
|
||||
self._test_404('/developers/xxx')
|
||||
r = self._test_404('/developers/xxx')
|
||||
|
||||
def test_404_consumer_legacy(self):
|
||||
self._test_404('/xxx')
|
||||
r = self._test_404('/xxx')
|
||||
|
||||
def test_404_consumer(self):
|
||||
# TODO: Remove log-in bit when we remove `request.can_view_consumer`.
|
||||
assert self.client.login(username='steamcube@mozilla.com',
|
||||
password='password')
|
||||
self._test_404('/xxx')
|
||||
r = self._test_404('/xxx')
|
||||
|
||||
|
||||
class TestManifest(amo.tests.TestCase):
|
||||
|
@ -46,6 +46,7 @@ class TestManifest(amo.tests.TestCase):
|
|||
def test_manifest(self):
|
||||
response = self.client.get(reverse('manifest.webapp'))
|
||||
eq_(response.status_code, 200)
|
||||
eq_(response['Content-Type'], 'application/x-web-app-manifest+json')
|
||||
content = json.loads(response.content)
|
||||
eq_(content['name'], 'Firefox Marketplace')
|
||||
eq_(content['default_locale'], 'en-US')
|
||||
|
|
|
@ -65,7 +65,8 @@ def manifest(request):
|
|||
'locales': {},
|
||||
'default_locale': 'en-US'
|
||||
}
|
||||
return HttpResponse(json.dumps(data))
|
||||
return HttpResponse(json.dumps(data),
|
||||
mimetype='application/x-web-app-manifest+json')
|
||||
|
||||
|
||||
def robots(request):
|
||||
|
|
|
@ -82,6 +82,8 @@ class TestUpdateManifest(amo.tests.TestCase):
|
|||
|
||||
self.response_mock = mock.Mock()
|
||||
self.response_mock.read.return_value = self._data()
|
||||
self.response_mock.headers = {
|
||||
'Content-Type': 'application/x-web-app-manifest+json'}
|
||||
self.urlopen_mock.return_value = self.response_mock
|
||||
|
||||
@mock.patch('mkt.webapps.tasks._get_content_hash')
|
||||
|
@ -166,6 +168,8 @@ class TestUpdateManifest(amo.tests.TestCase):
|
|||
n['name'] = 'Mozilla Ball Ultimate Edition'
|
||||
response_mock = mock.Mock()
|
||||
response_mock.read.return_value = json.dumps(n)
|
||||
response_mock.headers = {
|
||||
'Content-Type': 'application/x-web-app-manifest+json'}
|
||||
self.urlopen_mock.return_value = response_mock
|
||||
|
||||
eq_(RereviewQueue.objects.count(), 0)
|
||||
|
@ -185,6 +189,8 @@ class TestUpdateManifest(amo.tests.TestCase):
|
|||
n['locale'] = 'en-US'
|
||||
response_mock = mock.Mock()
|
||||
response_mock.read.return_value = json.dumps(n)
|
||||
response_mock.headers = {
|
||||
'Content-Type': 'application/x-web-app-manifest+json'}
|
||||
self.urlopen_mock.return_value = response_mock
|
||||
|
||||
eq_(RereviewQueue.objects.count(), 0)
|
||||
|
|
|
@ -31,7 +31,7 @@ def fileapp(environ, start_response):
|
|||
body = "".join(out)
|
||||
else:
|
||||
f = open(full_path, 'r')
|
||||
if full_path.endswith(('.webapp', '.json')):
|
||||
if full_path.endswith('.webapp') or full_path.endswith('.json'):
|
||||
content_type = 'application/x-web-app-manifest+json'
|
||||
body = f.read() # optimized for small files :)
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче