Fix the loss of JSON types when using multipart/form-data
To pass a binary blob in a POST request, browser sets the header 'Content-Type: multipart/form-data', which in turn causes all form fields' values to be passed as strings. Circumvent this by storing original field values as a JSON string on client-side and decoding it on server-side. As a result the setting HORIZON_IMAGES_UPLOAD_MODE = 'legacy' will start working together with Glance V2. Closes-Bug: #1613703 Change-Id: I53a8fbba15e4c3c6c17d6ef1ffe701634efda149
This commit is contained in:
parent
a0f18e3444
commit
f85d2fdbb7
@ -57,6 +57,9 @@ limitations under the License.
|
||||
for (var key in config.data) {
|
||||
if (config.data.hasOwnProperty(key) && uploadService.isFile(config.data[key])) {
|
||||
backend = uploadService.upload;
|
||||
// NOTE(tsufiev): keeping the original JSON to not lose value types
|
||||
// after sending them all as strings via multipart/form-data
|
||||
config.data.$$originalJSON = JSON.stringify(config.data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +128,10 @@
|
||||
it('upload() is used when there is a File() blob inside data', function () {
|
||||
api.post('/good', {first: file, second: 'the data'});
|
||||
expect(Upload.upload).toHaveBeenCalled();
|
||||
expect(called.config.data).toEqual({first: file, second: 'the data'});
|
||||
|
||||
var expected = {first: file, second: 'the data'};
|
||||
expected.$$originalJSON = JSON.stringify(expected);
|
||||
expect(called.config.data).toEqual(expected);
|
||||
});
|
||||
|
||||
it('upload() is NOT used when a File() blob is passed as data', function () {
|
||||
|
@ -170,14 +170,15 @@ class Images(generic.View):
|
||||
|
||||
# note: not an AJAX request - the body will be raw file content mixed with
|
||||
# metadata
|
||||
@rest_utils.post2data
|
||||
@csrf_exempt
|
||||
def post(self, request):
|
||||
form = UploadObjectForm(request.POST, request.FILES)
|
||||
form = UploadObjectForm(request.DATA, request.FILES)
|
||||
if not form.is_valid():
|
||||
raise rest_utils.AjaxError(500, 'Invalid request')
|
||||
|
||||
data = form.clean()
|
||||
meta = create_image_metadata(request.POST)
|
||||
meta = create_image_metadata(request.DATA)
|
||||
meta['data'] = data['data']
|
||||
|
||||
image = api.glance.image_create(request, **meta)
|
||||
|
@ -163,3 +163,20 @@ def parse_filters_kwargs(request, client_keywords=None):
|
||||
else:
|
||||
filters[param] = request.GET[param]
|
||||
return filters, kwargs
|
||||
|
||||
|
||||
def post2data(func):
|
||||
"""The sole purpose of this decorator is to restore original form values
|
||||
along with their types stored on client-side under key $$originalJSON.
|
||||
This in turn prevents the loss of field types when they are passed with
|
||||
header 'Content-Type: multipart/form-data', which is needed to pass a
|
||||
binary blob as a part of POST request.
|
||||
"""
|
||||
def wrapper(self, request):
|
||||
request.DATA = request.POST
|
||||
if '$$originalJSON' in request.POST:
|
||||
request.DATA = json.loads(request.POST['$$originalJSON'])
|
||||
|
||||
return func(self, request)
|
||||
|
||||
return wrapper
|
||||
|
Loading…
Reference in New Issue
Block a user