Files
storlets/tests/functional/python/test_multiinput_storlet.py
Takashi Kajinami 8401b6c581 Allow limiting maximum extra resources
Using many extra resources may cause high load at proxy server, because
the process needs to get all of the requested objects concurrently.
This change introduces a new option to limit maximum number of extra
resources per request to avoid DoS attack by too many extra resources.
If a request contains extra resources over the limit, then the request
is rejected at an early stage. The default value is -1 which means
unlimited. In case this option is set to 0 then users are not allowed
to use extra resources at all.

This also refactors handling of extra-resources header. One side
benefit of the refactoring is that now users can use additional inputs
when executing storlet over PUT requests.

Change-Id: I0ea7d78614f2b1ef5bf4961d2d5fe773264ef448
2024-02-14 01:03:52 +09:00

175 lines
6.0 KiB
Python

# Copyright (c) 2010-2016 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
from swiftclient import client as c
from tests.functional.python import StorletPythonFunctionalTest
import unittest
from hashlib import md5
class TestMultiInputStorlet(StorletPythonFunctionalTest):
def setUp(self):
self.additional_headers = {}
super(TestMultiInputStorlet, self).setUp(
storlet_dir='multi_input',
storlet_name='multi_input.py',
storlet_main='multi_input.MultiInputStorlet',
storlet_file=None,
headers={})
def test_get_extra_sources(self):
obj = 'small'
obj2 = 'small2'
c.put_object(self.url, self.token,
self.container, obj,
b'0123456789abcd')
c.put_object(self.url, self.token,
self.container, obj2,
b'efghijklmnopqr')
headers = {
'X-Run-Storlet': self.storlet_name,
'X-Storlet-Extra-Resources':
os.path.join('/' + self.container, obj2)
}
headers.update(self.additional_headers)
resp_headers, resp_content = c.get_object(
self.url, self.token, self.container, obj,
headers=headers)
self.assertEqual(b'0123456789abcdefghijklmnopqr',
resp_content)
def test_put_extra_sources(self):
obj = 'small'
obj2 = 'small2'
c.put_object(self.url, self.token,
self.container, obj2,
b'efghijklmnopqr')
headers = {
'X-Run-Storlet': self.storlet_name,
'X-Storlet-Extra-Resources':
os.path.join('/' + self.container, obj2)
}
headers.update(self.additional_headers)
c.put_object(
self.url, self.token, self.container, obj,
b'0123456789abcd', headers=headers)
resp_headers, resp_content = c.get_object(
self.url, self.token, self.container, obj)
self.assertEqual(b'0123456789abcdefghijklmnopqr',
resp_content)
def test_put_x_copy_from_extra_sources(self):
obj = 'small'
obj2 = 'small2'
copied_obj = 'copied'
c.put_object(self.url, self.token,
self.container, obj,
b'0123456789abcd',
headers={'X-Object-Meta-Key1': 'value1'})
c.put_object(self.url, self.token,
self.container, obj2,
b'efghijklmnopqr',
headers={'X-Object-Meta-Key2': 'value2'})
headers = {
'X-Run-Storlet': self.storlet_name,
'X-Copy-From':
os.path.join('/' + self.container, obj),
'X-Storlet-Extra-Resources':
os.path.join('/' + self.container, obj2),
}
headers.update(self.additional_headers)
expected_string = b'0123456789abcdefghijklmnopqr'
etag = c.put_object(
self.url, self.token, self.container, copied_obj,
headers=headers)
hasher = md5()
hasher.update(expected_string)
self.assertEqual(hasher.hexdigest(), etag)
resp_headers, resp_content = c.get_object(
self.url, self.token, self.container, copied_obj)
self.assertEqual(expected_string, resp_content)
self.assertEqual('value1', resp_headers['x-object-meta-key1'])
self.assertEqual('value2', resp_headers['x-object-meta-key2'])
class TestMultiInputStorletOnProxy(TestMultiInputStorlet):
def setUp(self):
super(TestMultiInputStorletOnProxy, self).setUp()
self.additional_headers = {'X-Storlet-Run-On-Proxy': ''}
class TestMultiInputMIMEStorlet(StorletPythonFunctionalTest):
def setUp(self):
self.additional_headers = {}
super(TestMultiInputMIMEStorlet, self).setUp(
storlet_dir='multi_input',
storlet_name='multi_input_mime.py',
storlet_main='multi_input_mime.MultiInputMIMEStorlet',
storlet_file=None,
headers={})
def test_get_multipart_mime_response(self):
obj = 'small'
obj2 = 'small2'
body = b'0123456789abcd'
body2 = b'efghijklmnopqr'
c.put_object(self.url, self.token,
self.container, obj, body)
c.put_object(self.url, self.token,
self.container, obj2, body2)
headers = {
'X-Run-Storlet': self.storlet_name,
'X-Storlet-Extra-Resources':
os.path.join('/' + self.container, obj2)
}
headers.update(self.additional_headers)
resp_headers, resp_content = c.get_object(
self.url, self.token, self.container, obj,
headers=headers)
multipart_prefix = 'multipart/mixed; boundary='
# N.B. swiftclient makes the header key as lower case
self.assertIn('content-type', resp_headers)
self.assertEqual(multipart_prefix,
resp_headers['content-type'][:len(multipart_prefix)])
boundary = resp_headers['content-type'][len(multipart_prefix):]
boundary = boundary.encode('ascii')
self.assertEqual(
b'%s\n--%s\n%s\n--%s--' % (body, boundary, body2, boundary),
resp_content)
class TestMultiInputMIMEStorletOnProxy(TestMultiInputMIMEStorlet):
def setUp(self):
super(TestMultiInputMIMEStorletOnProxy, self).setUp()
self.additional_headers = {'X-Storlet-Run-On-Proxy': ''}
if __name__ == '__main__':
unittest.main()