Move Create_Formpost to Behaviors
* Moved method create_formpost from the client to behaviors. As it didn't directly interface with the API, it belongs in the behaviors. * Rearranged the imports of behaviors for alphabetical order. * Modified the docstring of create_formpost to be a little more descriptive. * Changed an if variable != '' to if variable Change-Id: Id7b63bfeb60b81dd7a080459595464546bfdcf35
This commit is contained in:
@@ -14,20 +14,24 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
import datetime
|
||||
import uuid
|
||||
import json
|
||||
import gzip
|
||||
from StringIO import StringIO
|
||||
import hmac
|
||||
import json
|
||||
import uuid
|
||||
|
||||
from copy import deepcopy
|
||||
from time import sleep
|
||||
from hashlib import md5, sha1
|
||||
from random import choice
|
||||
from hashlib import md5
|
||||
from StringIO import StringIO
|
||||
from time import sleep, time
|
||||
|
||||
from cafe.common.unicode import UNICODE_BLOCKS, BLOCK_NAMES
|
||||
from cafe.engine.behaviors import BaseBehavior, behavior
|
||||
from cloudcafe.objectstorage.objectstorage_api.config \
|
||||
import ObjectStorageAPIConfig
|
||||
from cloudcafe.common.tools.md5hash import get_md5_hash
|
||||
from cloudcafe.objectstorage.objectstorage_api.client \
|
||||
import ObjectStorageAPIClient
|
||||
from cafe.common.unicode import UNICODE_BLOCKS, BLOCK_NAMES
|
||||
from cloudcafe.objectstorage.objectstorage_api.config \
|
||||
import ObjectStorageAPIConfig
|
||||
|
||||
|
||||
class ObjectStorageAPIBehaviorException(Exception):
|
||||
@@ -780,3 +784,141 @@ class ObjectStorageAPI_Behaviors(BaseBehavior):
|
||||
|
||||
if not key_two_response.ok:
|
||||
raise Exception('Could not set TempURL key two.')
|
||||
|
||||
def create_formpost(self, container, files, object_prefix='',
|
||||
redirect='http://example.com/formpost',
|
||||
max_file_size=104857600, max_file_count=10,
|
||||
expires=None, key='', signature="",
|
||||
x_delete_at=None, x_delete_after=None):
|
||||
"""
|
||||
Creates a multipart/form-data body (RFC-2388) that can be used for
|
||||
POSTs to Swift.
|
||||
|
||||
@param container: Name of the container to post objects to.
|
||||
@type container: string
|
||||
@param files: Files to post in the form. The dictionaries representing
|
||||
a file should be formatted as follows:
|
||||
{
|
||||
'name': '<form name>',
|
||||
'filename': '<filename>',
|
||||
'content_type': '<content_type>',
|
||||
'data': '<filedata>'
|
||||
}
|
||||
Where only name is required, defaults to other values
|
||||
will be as follows:
|
||||
filename - the value stored in name.
|
||||
content_type - 'text/plain'
|
||||
data - the md5 hash of the value stored in name.
|
||||
@type files: list of dictionaries
|
||||
@param object_prefix: prefix to be used in the name of the objects
|
||||
created.
|
||||
@type object_prefix: string
|
||||
@param redirect: URL to be returned as the 'location' header in the
|
||||
HTTP response.
|
||||
@type redirect: string
|
||||
@param max_file_size: The maximum file size in bytes which can be
|
||||
uploaded with the form.
|
||||
@type max_file_size: int
|
||||
@param max_file_count: The maximum number of files allowed to be
|
||||
uploaded with the form.
|
||||
@type max_file_count: int
|
||||
@param expires: The unix time relating to when the form expires
|
||||
and will no longer allow uploads to the container.
|
||||
@type expires: int
|
||||
@param key: The account's X-Tempurl-Key used in creating the signatre
|
||||
which authorizes the form to be POSTed.
|
||||
@type key: string
|
||||
@param signature: The HMAC-SHA1 signature of the form.
|
||||
@type signature: string
|
||||
@param x_delete_at: The unix time relating to when the object will
|
||||
be deleted from the container.
|
||||
@type x_delete_at: int
|
||||
@param x_delete_after: The amount of time, in seconds, after which
|
||||
the object will be deleted from the container.
|
||||
@type x_delete_after: int
|
||||
|
||||
@return: Data to be POSTed in the following format:
|
||||
{
|
||||
'target_url': '<url to POST to>',
|
||||
'headers': '<headers to be added to the request>,
|
||||
'body': '<body to be posted to the target url>'
|
||||
}
|
||||
@rtype: dictionary
|
||||
"""
|
||||
base_url, account_hash = self.client.storage_url.split('/v1/')
|
||||
path = '/v1/{0}/{1}'.format(account_hash, container)
|
||||
if object_prefix:
|
||||
path = '{0}/{1}'.format(path, object_prefix)
|
||||
|
||||
if not expires:
|
||||
expires = int(time() + 600)
|
||||
|
||||
url = ''.join([base_url, path])
|
||||
hmac_body = '{0}\n{1}\n{2}\n{3}\n{4}'.format(
|
||||
path, redirect, max_file_size, max_file_count, expires)
|
||||
if not signature:
|
||||
signature = hmac.new(key, hmac_body, sha1).hexdigest()
|
||||
|
||||
form = []
|
||||
if redirect:
|
||||
form.append({
|
||||
'headers':
|
||||
{'Content-Disposition': 'form-data; name="redirect"'},
|
||||
'data': redirect})
|
||||
form.append({
|
||||
'headers': {'Content-Disposition':
|
||||
'form-data; name="max_file_size"'},
|
||||
'data': str(max_file_size)})
|
||||
form.append({
|
||||
'headers': {'Content-Disposition':
|
||||
'form-data; name="max_file_count"'},
|
||||
'data': str(max_file_count)})
|
||||
form.append({
|
||||
'headers': {'Content-Disposition': 'form-data; name="expires"'},
|
||||
'data': str(expires)})
|
||||
if x_delete_at:
|
||||
form.append({
|
||||
'headers': {'Content-Disposition':
|
||||
'form-data; name="x_delete_at"'},
|
||||
'data': str(x_delete_at)})
|
||||
if x_delete_after:
|
||||
form.append({
|
||||
'headers': {'Content-Disposition':
|
||||
'form-data; name="x_delete_after"'},
|
||||
'data': str(x_delete_after)})
|
||||
form.append({
|
||||
'headers': {'Content-Disposition': 'form-data; name="signature"'},
|
||||
'data': signature})
|
||||
|
||||
for data_file in files:
|
||||
form_name = data_file.get('name')
|
||||
form_filename = data_file.get('filename', form_name)
|
||||
form_content_type = data_file.get('content_type', 'text/plain')
|
||||
form_data = data_file.get('data', get_md5_hash(form_name))
|
||||
form.append({
|
||||
'headers': {'Content-Disposition':
|
||||
'form-data; name="{0}"; filename="{1}"'.format(
|
||||
form_name, form_filename),
|
||||
'Content-Type': form_content_type},
|
||||
'data': form_data})
|
||||
|
||||
data = []
|
||||
boundary = '----WebKitFormBoundary40Q4WaJHO84PBBIa'
|
||||
|
||||
for section in form:
|
||||
data.append('--{0}\r\n'.format(boundary))
|
||||
for key, value in section['headers'].iteritems():
|
||||
data.append('{0}: {1}\r\n'.format(key, value))
|
||||
data.append('\r\n')
|
||||
data.append(section['data'])
|
||||
data.append('\r\n')
|
||||
data.append('\r\n--{0}'.format(boundary))
|
||||
|
||||
post_headers = {
|
||||
'Cache-Control': 'max-age=0',
|
||||
'Accept': '*/*;q=0.8',
|
||||
'Content-Type': 'multipart/form-data; boundary={0}'.format(
|
||||
boundary)}
|
||||
|
||||
return {'target_url': url, 'headers': post_headers,
|
||||
'body': ''.join(data)}
|
||||
|
||||
@@ -587,143 +587,6 @@ class ObjectStorageAPIClient(HTTPClient):
|
||||
|
||||
return {'target_url': base_url, 'signature': sig, 'expires': expires}
|
||||
|
||||
def create_formpost(self, container, files, object_prefix='',
|
||||
redirect='http://example.com/formpost',
|
||||
max_file_size=104857600, max_file_count=10,
|
||||
expires=None, key='', signature="",
|
||||
x_delete_at=None, x_delete_after=None):
|
||||
"""
|
||||
Creates RFC-2388.
|
||||
|
||||
@param container: Name of the container to post objects to.
|
||||
@type container: string
|
||||
@param files: Files to post in the form. The dictionaries representing
|
||||
a file should be formatted as follows:
|
||||
{
|
||||
'name': '<form name>',
|
||||
'filename': '<filename>',
|
||||
'content_type': '<content_type>',
|
||||
'data': '<filedata>'
|
||||
}
|
||||
Where only name is required, defaults to other values
|
||||
will be as follows:
|
||||
filename - the value stored in name.
|
||||
content_type - 'text/plain'
|
||||
data - the md5 hash of the value stored in name.
|
||||
@type files: list of dictionaries
|
||||
@param object_prefix: prefix to be used in the name of the objects
|
||||
created.
|
||||
@type object_prefix: string
|
||||
@param redirect: URL to be returned as the 'location' header in the
|
||||
HTTP response.
|
||||
@type redirect: string
|
||||
@param max_file_size: The maximum file size in bytes which can be
|
||||
uploaded with the form.
|
||||
@type max_file_size: int
|
||||
@param max_file_count: The maximum number of files allowed to be
|
||||
uploaded with the form.
|
||||
@type max_file_count: int
|
||||
@param expires: The unix time relating to when the form expires
|
||||
and will no longer allow uploads to the container.
|
||||
@type expires: int
|
||||
@param key: The account's X-Tempurl-Key used in creating the signatre
|
||||
which authorizes the form to be POSTed.
|
||||
@type key: string
|
||||
@param signature: The HMAC-SHA1 signature of the form.
|
||||
@type signature: string
|
||||
@param x_delete_at: The unix time relating to when the object will
|
||||
be deleted from the container.
|
||||
@type x_delete_at: int
|
||||
@param x_delete_after: The amount of time, in seconds, after which
|
||||
the object will be deleted from the container.
|
||||
@type x_delete_after: int
|
||||
|
||||
@return: Data to be POSTed in the following format:
|
||||
{
|
||||
'target_url': '<url to POST to>',
|
||||
'headers': '<headers to be added to the request>,
|
||||
'body': '<body to be posted to the target url>'
|
||||
}
|
||||
@rtype: dictionary
|
||||
"""
|
||||
base_url, path = self.storage_url.split('/v1')
|
||||
path = '/v1{0}/{1}'.format(path, container)
|
||||
if object_prefix:
|
||||
path = '{0}/{1}'.format(path, object_prefix)
|
||||
|
||||
if not expires:
|
||||
expires = int(time() + 600)
|
||||
|
||||
url = ''.join([base_url, path])
|
||||
hmac_body = '{0}\n{1}\n{2}\n{3}\n{4}'.format(
|
||||
path, redirect, max_file_size, max_file_count, expires)
|
||||
if not signature:
|
||||
signature = hmac.new(key, hmac_body, sha1).hexdigest()
|
||||
|
||||
form = []
|
||||
if redirect != '':
|
||||
form.append({
|
||||
'headers':
|
||||
{'Content-Disposition': 'form-data; name="redirect"'},
|
||||
'data': redirect})
|
||||
form.append({
|
||||
'headers': {'Content-Disposition':
|
||||
'form-data; name="max_file_size"'},
|
||||
'data': str(max_file_size)})
|
||||
form.append({
|
||||
'headers': {'Content-Disposition':
|
||||
'form-data; name="max_file_count"'},
|
||||
'data': str(max_file_count)})
|
||||
form.append({
|
||||
'headers': {'Content-Disposition': 'form-data; name="expires"'},
|
||||
'data': str(expires)})
|
||||
if x_delete_at:
|
||||
form.append({
|
||||
'headers': {'Content-Disposition':
|
||||
'form-data; name="x_delete_at"'},
|
||||
'data': str(x_delete_at)})
|
||||
if x_delete_after:
|
||||
form.append({
|
||||
'headers': {'Content-Disposition':
|
||||
'form-data; name="x_delete_after"'},
|
||||
'data': str(x_delete_after)})
|
||||
form.append({
|
||||
'headers': {'Content-Disposition': 'form-data; name="signature"'},
|
||||
'data': signature})
|
||||
|
||||
for data_file in files:
|
||||
form_name = data_file.get('name')
|
||||
form_filename = data_file.get('filename', form_name)
|
||||
form_content_type = data_file.get('content_type', 'text/plain')
|
||||
form_data = data_file.get('data', get_md5_hash(form_name))
|
||||
form.append({
|
||||
'headers': {'Content-Disposition':
|
||||
'form-data; name="{0}"; filename="{1}"'.format(
|
||||
form_name, form_filename),
|
||||
'Content-Type': form_content_type},
|
||||
'data': form_data})
|
||||
|
||||
data = []
|
||||
boundary = '----WebKitFormBoundary40Q4WaJHO84PBBIa'
|
||||
|
||||
for section in form:
|
||||
data.append('--{0}\r\n'.format(boundary))
|
||||
for key, value in section['headers'].iteritems():
|
||||
data.append('{0}: {1}\r\n'.format(key, value))
|
||||
data.append('\r\n')
|
||||
data.append(section['data'])
|
||||
data.append('\r\n')
|
||||
data.append('\r\n--{0}'.format(boundary))
|
||||
|
||||
post_headers = {
|
||||
'Cache-Control': 'max-age=0',
|
||||
'Accept': '*/*;q=0.8',
|
||||
'Content-Type': 'multipart/form-data; boundary={0}'.format(
|
||||
boundary)}
|
||||
|
||||
return {'target_url': url, 'headers': post_headers,
|
||||
'body': ''.join(data)}
|
||||
|
||||
def create_archive(self, object_names, compression_type,
|
||||
archive_name=BULK_ARCHIVE_NAME):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user