Pulled changes from lp:~gholt/swift/repozewhat
This commit is contained in:
commit
b5ae6a2924
@ -15,6 +15,7 @@
|
||||
# limitations under the License.
|
||||
|
||||
from ConfigParser import ConfigParser
|
||||
from os.path import basename
|
||||
from sys import argv, exit
|
||||
|
||||
from swift.common.bufferedhttp import http_connect_raw as http_connect
|
||||
@ -22,11 +23,27 @@ from swift.common.bufferedhttp import http_connect_raw as http_connect
|
||||
|
||||
if __name__ == '__main__':
|
||||
f = '/etc/swift/auth-server.conf'
|
||||
if len(argv) == 5:
|
||||
f = argv[4]
|
||||
elif len(argv) != 4:
|
||||
exit('Syntax: %s <new_account> <new_user> <new_password> [conf_file]' %
|
||||
argv[0])
|
||||
good = False
|
||||
noaccess = False
|
||||
if len(argv) == 6 and argv[4] == 'noaccess':
|
||||
good = True
|
||||
noaccess = True
|
||||
f = argv[5]
|
||||
elif len(argv) == 5:
|
||||
good = True
|
||||
if argv[4] == 'noaccess':
|
||||
noaccess = True
|
||||
else:
|
||||
f = argv[4]
|
||||
elif len(argv) == 4:
|
||||
good = True
|
||||
if not good:
|
||||
exit('''
|
||||
Syntax: %s <new_account> <new_user> <new_password> [noaccess] [conf_file]
|
||||
The noaccess keyword will create a user with no access to the account; another
|
||||
user for the account will have to add the user to the ACLs for a container to
|
||||
grant some access.
|
||||
'''.strip() % basename(argv[0]))
|
||||
new_account = argv[1]
|
||||
new_user = argv[2]
|
||||
new_password = argv[3]
|
||||
@ -38,8 +55,10 @@ if __name__ == '__main__':
|
||||
port = int(conf.get('bind_port', 11000))
|
||||
ssl = conf.get('cert_file') is not None
|
||||
path = '/account/%s/%s' % (new_account, new_user)
|
||||
conn = http_connect(host, port, 'PUT', path, {'x-auth-key':new_password},
|
||||
ssl=ssl)
|
||||
headers = {'X-Auth-Key': new_password}
|
||||
if noaccess:
|
||||
headers['X-User-No-Access'] = 'true'
|
||||
conn = http_connect(host, port, 'PUT', path, headers, ssl=ssl)
|
||||
resp = conn.getresponse()
|
||||
if resp.status == 204:
|
||||
print resp.getheader('x-storage-url')
|
||||
|
@ -530,17 +530,11 @@ good idea what to do on other environments.
|
||||
#. Get an `X-Storage-Url` and `X-Auth-Token`: ``curl -v -H 'X-Storage-User: test:tester' -H 'X-Storage-Pass: testing' http://127.0.0.1:11000/v1.0``
|
||||
#. Check that you can GET account: ``curl -v -H 'X-Auth-Token: <token-from-x-auth-token-above>' <url-from-x-storage-url-above>``
|
||||
#. Check that `st` works: `st -A http://127.0.0.1:11000/v1.0 -U test:tester -K testing stat`
|
||||
#. `swift-auth-create-account test2 tester2 testing2`
|
||||
#. `swift-auth-create-account test tester3 testing3 noaccess`
|
||||
#. Create `/etc/swift/func_test.conf`::
|
||||
|
||||
auth_host = 127.0.0.1
|
||||
auth_port = 11000
|
||||
auth_ssl = no
|
||||
|
||||
account = test
|
||||
username = tester
|
||||
password = testing
|
||||
|
||||
collate = C
|
||||
cp ~/swift/trunk/test/functional/sample.conf /etc/swift/func_test.conf
|
||||
|
||||
#. `cd ~/swift/trunk; ./.functests`
|
||||
#. `cd ~/swift/trunk; ./.probetests` (Note for future reference: probe tests
|
||||
|
@ -7,3 +7,8 @@ source-dir = doc/source
|
||||
tag_build =
|
||||
tag_date = 0
|
||||
tag_svn_revision = 0
|
||||
|
||||
[nosetests]
|
||||
with-coverage=1
|
||||
cover-package=swift
|
||||
verbosity=2
|
||||
|
@ -22,6 +22,7 @@ from time import gmtime, strftime, time
|
||||
from urllib import unquote, quote
|
||||
from uuid import uuid4
|
||||
|
||||
import sqlite3
|
||||
from webob import Request, Response
|
||||
from webob.exc import HTTPBadRequest, HTTPNoContent, HTTPUnauthorized, \
|
||||
HTTPServiceUnavailable, HTTPNotFound
|
||||
@ -58,10 +59,10 @@ class AuthController(object):
|
||||
* The user makes a ReST call to the Swift cluster using the url given with
|
||||
the token as the X-Auth-Token header.
|
||||
* The Swift cluster makes an ReST call to the auth server to validate the
|
||||
token for the given account hash, caching the result for future requests
|
||||
up to the expiration the auth server returns.
|
||||
* The auth server validates the token / account hash given and returns the
|
||||
expiration for the token.
|
||||
token, caching the result for future requests up to the expiration the
|
||||
auth server returns.
|
||||
* The auth server validates the token given and returns the expiration for
|
||||
the token.
|
||||
* The Swift cluster completes the user's request.
|
||||
|
||||
Another use case is creating a new account:
|
||||
@ -103,17 +104,33 @@ class AuthController(object):
|
||||
Ring(os.path.join(self.swift_dir, 'account.ring.gz'))
|
||||
self.db_file = os.path.join(self.swift_dir, 'auth.db')
|
||||
self.conn = get_db_connection(self.db_file, okay_to_create=True)
|
||||
try:
|
||||
self.conn.execute('SELECT noaccess FROM account LIMIT 1')
|
||||
except sqlite3.OperationalError, err:
|
||||
if str(err) == 'no such column: noaccess':
|
||||
self.conn.execute(
|
||||
'ALTER TABLE account ADD COLUMN noaccess TEXT')
|
||||
self.conn.execute('''CREATE TABLE IF NOT EXISTS account (
|
||||
account TEXT, url TEXT, cfaccount TEXT,
|
||||
user TEXT, password TEXT)''')
|
||||
user TEXT, password TEXT, noaccess TEXT)''')
|
||||
self.conn.execute('''CREATE INDEX IF NOT EXISTS ix_account_account
|
||||
ON account (account)''')
|
||||
try:
|
||||
self.conn.execute('SELECT user FROM token LIMIT 1')
|
||||
except sqlite3.OperationalError, err:
|
||||
if str(err) == 'no such column: user':
|
||||
self.conn.execute('DROP INDEX IF EXISTS ix_token_created')
|
||||
self.conn.execute('DROP INDEX IF EXISTS ix_token_cfaccount')
|
||||
self.conn.execute('DROP TABLE IF EXISTS token')
|
||||
self.conn.execute('''CREATE TABLE IF NOT EXISTS token (
|
||||
cfaccount TEXT, token TEXT, created FLOAT)''')
|
||||
self.conn.execute('''CREATE INDEX IF NOT EXISTS ix_token_cfaccount
|
||||
ON token (cfaccount)''')
|
||||
token TEXT, created FLOAT,
|
||||
account TEXT, user TEXT, cfaccount TEXT)''')
|
||||
self.conn.execute('''CREATE INDEX IF NOT EXISTS ix_token_token
|
||||
ON token (token)''')
|
||||
self.conn.execute('''CREATE INDEX IF NOT EXISTS ix_token_created
|
||||
ON token (created)''')
|
||||
self.conn.execute('''CREATE INDEX IF NOT EXISTS ix_token_account
|
||||
ON token (account)''')
|
||||
self.conn.commit()
|
||||
|
||||
def add_storage_account(self, account_name=''):
|
||||
@ -202,38 +219,36 @@ class AuthController(object):
|
||||
(time() - self.token_life,))
|
||||
conn.commit()
|
||||
|
||||
def validate_token(self, token, account_hash):
|
||||
def validate_token(self, token):
|
||||
"""
|
||||
Tests if the given token is a valid token
|
||||
|
||||
:param token: The token to validate
|
||||
:param account_hash: The account hash the token is being used with
|
||||
:returns: TTL if valid, False otherwise
|
||||
:returns: (TTL, account, user, cfaccount) if valid, False otherwise
|
||||
"""
|
||||
begin = time()
|
||||
self.purge_old_tokens()
|
||||
rv = False
|
||||
with self.get_conn() as conn:
|
||||
row = conn.execute('''
|
||||
SELECT created FROM token
|
||||
WHERE cfaccount = ? AND token = ?''',
|
||||
(account_hash, token)).fetchone()
|
||||
SELECT created, account, user, cfaccount FROM token
|
||||
WHERE token = ?''',
|
||||
(token,)).fetchone()
|
||||
if row is not None:
|
||||
created = row[0]
|
||||
if time() - created >= self.token_life:
|
||||
conn.execute('''
|
||||
DELETE FROM token
|
||||
WHERE cfaccount = ? AND token = ?''',
|
||||
(account_hash, token))
|
||||
DELETE FROM token WHERE token = ?''', (token,))
|
||||
conn.commit()
|
||||
else:
|
||||
rv = self.token_life - (time() - created)
|
||||
self.logger.info('validate_token(%s, %s, _, _) = %s [%.02f]' %
|
||||
(repr(token), repr(account_hash), repr(rv),
|
||||
time() - begin))
|
||||
rv = (self.token_life - (time() - created), row[1], row[2],
|
||||
row[3])
|
||||
self.logger.info('validate_token(%s, _, _) = %s [%.02f]' %
|
||||
(repr(token), repr(rv), time() - begin))
|
||||
return rv
|
||||
|
||||
def create_account(self, new_account, new_user, new_password):
|
||||
def create_account(self, new_account, new_user, new_password,
|
||||
noaccess=False):
|
||||
"""
|
||||
Handles the create_account call for developers, used to request
|
||||
an account be created both on a Swift cluster and in the auth server
|
||||
@ -251,28 +266,51 @@ class AuthController(object):
|
||||
:param new_account: The name for the new account
|
||||
:param new_user: The name for the new user
|
||||
:param new_password: The password for the new account
|
||||
:param noaccess: If true, the user will be granted no access to the
|
||||
account by default; another user will have to add the
|
||||
user to the ACLs for containers to grant access.
|
||||
|
||||
:returns: False if the create fails, storage url if successful
|
||||
:returns: False if the create fails, 'already exists' if the user
|
||||
already exists, or storage url if successful
|
||||
"""
|
||||
begin = time()
|
||||
if not all((new_account, new_user, new_password)):
|
||||
return False
|
||||
account_hash = self.add_storage_account()
|
||||
if not account_hash:
|
||||
self.logger.info(
|
||||
'FAILED create_account(%s, %s, _,) [%.02f]' %
|
||||
(repr(new_account), repr(new_user), time() - begin))
|
||||
return False
|
||||
url = self.default_cluster_url.rstrip('/') + '/' + account_hash
|
||||
with self.get_conn() as conn:
|
||||
row = conn.execute(
|
||||
'SELECT url FROM account WHERE account = ? AND user = ?',
|
||||
(new_account, new_user)).fetchone()
|
||||
if row:
|
||||
self.logger.info(
|
||||
'ALREADY EXISTS create_account(%s, %s, _, %s) [%.02f]' %
|
||||
(repr(new_account), repr(new_user), repr(noaccess),
|
||||
time() - begin))
|
||||
return 'already exists'
|
||||
row = conn.execute(
|
||||
'SELECT url, cfaccount FROM account WHERE account = ?',
|
||||
(new_account,)).fetchone()
|
||||
if row:
|
||||
url = row[0]
|
||||
account_hash = row[1]
|
||||
else:
|
||||
account_hash = self.add_storage_account()
|
||||
if not account_hash:
|
||||
self.logger.info(
|
||||
'FAILED create_account(%s, %s, _, %s) [%.02f]' %
|
||||
(repr(new_account), repr(new_user), repr(noaccess),
|
||||
time() - begin))
|
||||
return False
|
||||
url = self.default_cluster_url.rstrip('/') + '/' + account_hash
|
||||
conn.execute('''INSERT INTO account
|
||||
(account, url, cfaccount, user, password)
|
||||
VALUES (?, ?, ?, ?, ?)''',
|
||||
(new_account, url, account_hash, new_user, new_password))
|
||||
(account, url, cfaccount, user, password, noaccess)
|
||||
VALUES (?, ?, ?, ?, ?, ?)''',
|
||||
(new_account, url, account_hash, new_user, new_password,
|
||||
noaccess and 't' or ''))
|
||||
conn.commit()
|
||||
self.logger.info(
|
||||
'SUCCESS create_account(%s, %s, _) = %s [%.02f]' %
|
||||
(repr(new_account), repr(new_user), repr(url), time() - begin))
|
||||
'SUCCESS create_account(%s, %s, _, %s) = %s [%.02f]' %
|
||||
(repr(new_account), repr(new_user), repr(noaccess), repr(url),
|
||||
time() - begin))
|
||||
return url
|
||||
|
||||
def recreate_accounts(self):
|
||||
@ -285,8 +323,8 @@ class AuthController(object):
|
||||
"""
|
||||
begin = time()
|
||||
with self.get_conn() as conn:
|
||||
account_hashes = [r[0] for r in
|
||||
conn.execute('SELECT cfaccount FROM account').fetchall()]
|
||||
account_hashes = [r[0] for r in conn.execute(
|
||||
'SELECT distinct(cfaccount) FROM account').fetchall()]
|
||||
failures = []
|
||||
for i, account_hash in enumerate(account_hashes):
|
||||
if not self.add_storage_account(account_hash):
|
||||
@ -301,7 +339,7 @@ class AuthController(object):
|
||||
Hanles ReST request from Swift to validate tokens
|
||||
|
||||
Valid URL paths:
|
||||
* GET /token/<account-hash>/<token>
|
||||
* GET /token/<token>
|
||||
|
||||
If the HTTP equest returns with a 204, then the token is valid,
|
||||
and the TTL of the token will be available in the X-Auth-Ttl header.
|
||||
@ -309,13 +347,14 @@ class AuthController(object):
|
||||
:param request: webob.Request object
|
||||
"""
|
||||
try:
|
||||
_, account_hash, token = split_path(request.path, minsegs=3)
|
||||
_, token = split_path(request.path, minsegs=2)
|
||||
except ValueError:
|
||||
return HTTPBadRequest()
|
||||
ttl = self.validate_token(token, account_hash)
|
||||
if not ttl:
|
||||
validation = self.validate_token(token)
|
||||
if not validation:
|
||||
return HTTPNotFound()
|
||||
return HTTPNoContent(headers={'x-auth-ttl': ttl})
|
||||
return HTTPNoContent(headers={'X-Auth-TTL': validation[0],
|
||||
'X-Auth-User': ':'.join(validation[1:])})
|
||||
|
||||
def handle_account_create(self, request):
|
||||
"""
|
||||
@ -339,7 +378,10 @@ class AuthController(object):
|
||||
if 'X-Auth-Key' not in request.headers:
|
||||
return HTTPBadRequest('X-Auth-Key is required')
|
||||
password = request.headers['x-auth-key']
|
||||
storage_url = self.create_account(account_name, user_name, password)
|
||||
storage_url = self.create_account(account_name, user_name, password,
|
||||
request.headers.get('x-user-no-access'))
|
||||
if storage_url == 'already exists':
|
||||
return HTTPBadRequest(storage_url)
|
||||
if not storage_url:
|
||||
return HTTPServiceUnavailable()
|
||||
return HTTPNoContent(headers={'x-storage-url': storage_url})
|
||||
@ -414,23 +456,25 @@ class AuthController(object):
|
||||
self.purge_old_tokens()
|
||||
with self.get_conn() as conn:
|
||||
row = conn.execute('''
|
||||
SELECT cfaccount, url FROM account
|
||||
SELECT cfaccount, url, noaccess FROM account
|
||||
WHERE account = ? AND user = ? AND password = ?''',
|
||||
(account, user, password)).fetchone()
|
||||
if row is None:
|
||||
return HTTPUnauthorized()
|
||||
cfaccount = row[0]
|
||||
cfaccount = row[2] and '.none' or row[0]
|
||||
url = row[1]
|
||||
row = conn.execute('SELECT token FROM token WHERE cfaccount = ?',
|
||||
(cfaccount,)).fetchone()
|
||||
row = conn.execute('''
|
||||
SELECT token FROM token WHERE account = ? AND user = ?''',
|
||||
(account, user)).fetchone()
|
||||
if row:
|
||||
token = row[0]
|
||||
else:
|
||||
token = 'tk' + str(uuid4())
|
||||
conn.execute('''
|
||||
INSERT INTO token (cfaccount, token, created)
|
||||
VALUES (?, ?, ?)''',
|
||||
(cfaccount, token, time()))
|
||||
INSERT INTO token
|
||||
(token, created, account, user, cfaccount)
|
||||
VALUES (?, ?, ?, ?, ?)''',
|
||||
(token, time(), account, user, cfaccount))
|
||||
conn.commit()
|
||||
return HTTPNoContent(headers={'x-auth-token': token,
|
||||
'x-storage-token': token,
|
||||
|
@ -13,30 +13,135 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import time
|
||||
from time import time
|
||||
|
||||
from webob.request import Request
|
||||
from webob.exc import HTTPUnauthorized, HTTPPreconditionFailed
|
||||
from eventlet.timeout import Timeout
|
||||
from repoze.what.adapters import BaseSourceAdapter
|
||||
from repoze.what.middleware import setup_auth
|
||||
from repoze.what.predicates import in_any_group, NotAuthorizedError
|
||||
from webob.exc import HTTPForbidden, HTTPUnauthorized
|
||||
|
||||
from swift.common.utils import split_path
|
||||
from swift.common.bufferedhttp import http_connect_raw as http_connect
|
||||
from swift.common.utils import get_logger, cache_from_env
|
||||
from swift.common.memcached import MemcacheRing
|
||||
from swift.common.utils import cache_from_env, split_path
|
||||
|
||||
|
||||
class DevAuthMiddleware(object):
|
||||
"""
|
||||
Auth Middleware that uses the dev auth server
|
||||
"""
|
||||
class DevAuthorization(object):
|
||||
|
||||
def __init__(self, app, conf, memcache_client=None, logger=None):
|
||||
def __init__(self, app, conf):
|
||||
self.app = app
|
||||
self.memcache_client = memcache_client
|
||||
if logger is None:
|
||||
self.logger = get_logger(conf)
|
||||
self.conf = conf
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
environ['swift.authorize'] = self.authorize
|
||||
environ['swift.clean_acl'] = self.clean_acl
|
||||
return self.app(environ, start_response)
|
||||
|
||||
def authorize(self, req):
|
||||
version, account, container, obj = split_path(req.path, 1, 4, True)
|
||||
if not account:
|
||||
return self.denied_response(req)
|
||||
groups = [account]
|
||||
acl = self.parse_acl(getattr(req, 'acl', None))
|
||||
if acl:
|
||||
referrers, accounts, users = acl
|
||||
if referrers:
|
||||
parts = req.referer.split('//', 1)
|
||||
allow = False
|
||||
if len(parts) == 2:
|
||||
rhost = parts[1].split('/', 1)[0].split(':', 1)[0].lower()
|
||||
else:
|
||||
rhost = 'unknown'
|
||||
for mhost in referrers:
|
||||
if mhost[0] == '-':
|
||||
mhost = mhost[1:]
|
||||
if mhost == rhost or \
|
||||
(mhost[0] == '.' and rhost.endswith(mhost)):
|
||||
allow = False
|
||||
elif mhost == 'any' or mhost == rhost or \
|
||||
(mhost[0] == '.' and rhost.endswith(mhost)):
|
||||
allow = True
|
||||
if allow:
|
||||
return None
|
||||
groups.extend(accounts)
|
||||
groups.extend(users)
|
||||
try:
|
||||
in_any_group(*groups).check_authorization(req.environ)
|
||||
except NotAuthorizedError:
|
||||
return self.denied_response(req)
|
||||
return None
|
||||
|
||||
def denied_response(self, req):
|
||||
if req.remote_user:
|
||||
return HTTPForbidden(request=req)
|
||||
else:
|
||||
self.logger = logger
|
||||
return HTTPUnauthorized(request=req)
|
||||
|
||||
def clean_acl(self, header_name, value):
|
||||
values = []
|
||||
for raw_value in value.lower().split(','):
|
||||
raw_value = raw_value.strip()
|
||||
if raw_value:
|
||||
if ':' in raw_value:
|
||||
first, second = \
|
||||
(v.strip() for v in raw_value.split(':', 1))
|
||||
if not first:
|
||||
raise ValueError('No value before colon in %s' %
|
||||
repr(raw_value))
|
||||
if first == '.ref' and 'write' in header_name:
|
||||
raise ValueError('Referrers not allowed in write '
|
||||
'ACLs: %s' % repr(raw_value))
|
||||
if second:
|
||||
if first == '.ref' and second[0] == '-':
|
||||
second = second[1:].strip()
|
||||
if not second:
|
||||
raise ValueError('No value after referrer '
|
||||
'deny designation in %s' % repr(raw_value))
|
||||
second = '-' + second
|
||||
values.append('%s:%s' % (first, second))
|
||||
elif first == '.ref':
|
||||
raise ValueError('No value after referrer designation '
|
||||
'in %s' % repr(raw_value))
|
||||
else:
|
||||
values.append(first)
|
||||
else:
|
||||
values.append(raw_value)
|
||||
return ','.join(values)
|
||||
|
||||
def parse_acl(self, acl_string):
|
||||
if not acl_string:
|
||||
return None
|
||||
referrers = []
|
||||
accounts = []
|
||||
users = []
|
||||
for value in acl_string.split(','):
|
||||
if value.startswith('.ref:'):
|
||||
referrers.append(value[len('.ref:'):])
|
||||
elif ':' in value:
|
||||
users.append(value)
|
||||
else:
|
||||
accounts.append(value)
|
||||
return (referrers, accounts, users)
|
||||
|
||||
|
||||
class DevIdentifier(object):
|
||||
|
||||
def __init__(self, conf):
|
||||
self.conf = conf
|
||||
|
||||
def identify(self, env):
|
||||
return {'token':
|
||||
env.get('HTTP_X_AUTH_TOKEN', env.get('HTTP_X_STORAGE_TOKEN'))}
|
||||
|
||||
def remember(self, env, identity):
|
||||
return []
|
||||
|
||||
def forget(self, env, identity):
|
||||
return []
|
||||
|
||||
|
||||
class DevAuthenticator(object):
|
||||
|
||||
def __init__(self, conf):
|
||||
self.conf = conf
|
||||
self.auth_host = conf.get('ip', '127.0.0.1')
|
||||
self.auth_port = int(conf.get('port', 11000))
|
||||
@ -44,69 +149,135 @@ class DevAuthMiddleware(object):
|
||||
conf.get('ssl', 'false').lower() in ('true', 'on', '1', 'yes')
|
||||
self.timeout = int(conf.get('node_timeout', 10))
|
||||
|
||||
def __call__(self, env, start_response):
|
||||
if self.memcache_client is None:
|
||||
self.memcache_client = cache_from_env(env)
|
||||
req = Request(env)
|
||||
if 'x-storage-token' in req.headers and \
|
||||
'x-auth-token' not in req.headers:
|
||||
req.headers['x-auth-token'] = req.headers['x-storage-token']
|
||||
try:
|
||||
version, account, container, obj = split_path(req.path, 1, 4, True)
|
||||
except ValueError, e:
|
||||
version = account = container = obj = None
|
||||
if account is None:
|
||||
return HTTPPreconditionFailed(request=req, body='Bad URL')(
|
||||
env, start_response)
|
||||
if not req.headers.get('x-auth-token'):
|
||||
return HTTPPreconditionFailed(request=req,
|
||||
body='Missing Auth Token')(env, start_response)
|
||||
if not self.auth(account, req.headers['x-auth-token']):
|
||||
return HTTPUnauthorized(request=req)(env, start_response)
|
||||
|
||||
# If we get here, then things should be good.
|
||||
return self.app(env, start_response)
|
||||
|
||||
def auth(self, account, token):
|
||||
"""
|
||||
Dev authorization implmentation
|
||||
|
||||
:param account: account name
|
||||
:param token: auth token
|
||||
|
||||
:returns: True if authorization is successful, False otherwise
|
||||
"""
|
||||
key = 'auth/%s/%s' % (account, token)
|
||||
now = time.time()
|
||||
cached_auth_data = self.memcache_client.get(key)
|
||||
def authenticate(self, env, identity):
|
||||
token = identity.get('token')
|
||||
if not token:
|
||||
return None
|
||||
memcache_client = cache_from_env(env)
|
||||
key = 'devauth/%s' % token
|
||||
cached_auth_data = memcache_client.get(key)
|
||||
if cached_auth_data:
|
||||
start, expiration = cached_auth_data
|
||||
if now - start <= expiration:
|
||||
return True
|
||||
try:
|
||||
with Timeout(self.timeout):
|
||||
conn = http_connect(self.auth_host, self.auth_port, 'GET',
|
||||
'/token/%s/%s' % (account, token), ssl=self.ssl)
|
||||
resp = conn.getresponse()
|
||||
resp.read()
|
||||
conn.close()
|
||||
if resp.status == 204:
|
||||
validated = float(resp.getheader('x-auth-ttl'))
|
||||
else:
|
||||
validated = False
|
||||
except:
|
||||
self.logger.exception('ERROR with auth')
|
||||
return False
|
||||
if not validated:
|
||||
return False
|
||||
else:
|
||||
val = (now, validated)
|
||||
self.memcache_client.set(key, val, timeout=validated)
|
||||
return True
|
||||
start, expiration, user = cached_auth_data
|
||||
if time() - start <= expiration:
|
||||
return user
|
||||
with Timeout(self.timeout):
|
||||
conn = http_connect(self.auth_host, self.auth_port, 'GET',
|
||||
'/token/%s' % token, ssl=self.ssl)
|
||||
resp = conn.getresponse()
|
||||
resp.read()
|
||||
conn.close()
|
||||
if resp.status == 204:
|
||||
expiration = float(resp.getheader('x-auth-ttl'))
|
||||
user = resp.getheader('x-auth-user')
|
||||
memcache_client.set(key, (time(), expiration, user),
|
||||
timeout=expiration)
|
||||
return user
|
||||
return None
|
||||
|
||||
|
||||
class DevChallenger(object):
|
||||
|
||||
def __init__(self, conf):
|
||||
self.conf = conf
|
||||
|
||||
def challenge(self, env, status, app_headers, forget_headers):
|
||||
def no_challenge(env, start_response):
|
||||
start_response(str(status), [])
|
||||
return []
|
||||
return no_challenge
|
||||
|
||||
|
||||
class DevGroupSourceAdapter(BaseSourceAdapter):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(DevGroupSourceAdapter, self).__init__(*args, **kwargs)
|
||||
self.sections = {}
|
||||
|
||||
def _get_all_sections(self):
|
||||
return self.sections
|
||||
|
||||
def _get_section_items(self, section):
|
||||
return self.sections[section]
|
||||
|
||||
def _find_sections(self, credentials):
|
||||
creds = credentials['repoze.what.userid'].split(':')
|
||||
if len(creds) != 3:
|
||||
return set()
|
||||
rv = set([creds[0], ':'.join(creds[:2]), creds[2]])
|
||||
return rv
|
||||
|
||||
def _include_items(self, section, items):
|
||||
self.sections[section] |= items
|
||||
|
||||
def _exclude_items(self, section, items):
|
||||
for item in items:
|
||||
self.sections[section].remove(item)
|
||||
|
||||
def _item_is_included(self, section, item):
|
||||
return item in self.sections[section]
|
||||
|
||||
def _create_section(self, section):
|
||||
self.sections[section] = set()
|
||||
|
||||
def _edit_section(self, section, new_section):
|
||||
self.sections[new_section] = self.sections[section]
|
||||
del self.sections[section]
|
||||
|
||||
def _delete_section(self, section):
|
||||
del self.sections[section]
|
||||
|
||||
def _section_exists(self, section):
|
||||
return self.sections.has_key(section)
|
||||
|
||||
|
||||
class DevPermissionSourceAdapter(BaseSourceAdapter):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(DevPermissionSourceAdapter, self).__init__(*args, **kwargs)
|
||||
self.sections = {}
|
||||
|
||||
def _get_all_sections(self):
|
||||
return self.sections
|
||||
|
||||
def _get_section_items(self, section):
|
||||
return self.sections[section]
|
||||
|
||||
def _find_sections(self, group_name):
|
||||
return set([n for (n, p) in self.sections.items()
|
||||
if group_name in p])
|
||||
|
||||
def _include_items(self, section, items):
|
||||
self.sections[section] |= items
|
||||
|
||||
def _exclude_items(self, section, items):
|
||||
for item in items:
|
||||
self.sections[section].remove(item)
|
||||
|
||||
def _item_is_included(self, section, item):
|
||||
return item in self.sections[section]
|
||||
|
||||
def _create_section(self, section):
|
||||
self.sections[section] = set()
|
||||
|
||||
def _edit_section(self, section, new_section):
|
||||
self.sections[new_section] = self.sections[section]
|
||||
del self.sections[section]
|
||||
|
||||
def _delete_section(self, section):
|
||||
del self.sections[section]
|
||||
|
||||
def _section_exists(self, section):
|
||||
return self.sections.has_key(section)
|
||||
|
||||
|
||||
def filter_factory(global_conf, **local_conf):
|
||||
conf = global_conf.copy()
|
||||
conf.update(local_conf)
|
||||
def auth_filter(app):
|
||||
return DevAuthMiddleware(app, conf)
|
||||
return setup_auth(DevAuthorization(app, conf),
|
||||
group_adapters={'all_groups': DevGroupSourceAdapter()},
|
||||
permission_adapters={'all_perms': DevPermissionSourceAdapter()},
|
||||
identifiers=[('devauth', DevIdentifier(conf))],
|
||||
authenticators=[('devauth', DevAuthenticator(conf))],
|
||||
challengers=[('devauth', DevChallenger(conf))])
|
||||
return auth_filter
|
||||
|
@ -44,6 +44,9 @@ DATADIR = 'containers'
|
||||
class ContainerController(object):
|
||||
"""WSGI Controller for the container server."""
|
||||
|
||||
# Ensure these are all lowercase
|
||||
save_headers = ['x-container-read', 'x-container-write']
|
||||
|
||||
def __init__(self, conf):
|
||||
self.logger = get_logger(conf)
|
||||
self.root = conf.get('devices', '/srv/node/')
|
||||
@ -192,7 +195,8 @@ class ContainerController(object):
|
||||
metadata = {}
|
||||
metadata.update((key, (value, timestamp))
|
||||
for key, value in req.headers.iteritems()
|
||||
if key.lower().startswith('x-container-meta-'))
|
||||
if key.lower() in self.save_headers or
|
||||
key.lower().startswith('x-container-meta-'))
|
||||
if metadata:
|
||||
broker.update_metadata(metadata)
|
||||
resp = self.account_update(req, account, container, broker)
|
||||
@ -373,7 +377,8 @@ class ContainerController(object):
|
||||
metadata = {}
|
||||
metadata.update((key, (value, timestamp))
|
||||
for key, value in req.headers.iteritems()
|
||||
if key.lower().startswith('x-container-meta-'))
|
||||
if key.lower() in self.save_headers or
|
||||
key.lower().startswith('x-container-meta-'))
|
||||
if metadata:
|
||||
broker.update_metadata(metadata)
|
||||
return HTTPNoContent(request=req)
|
||||
|
@ -17,6 +17,7 @@ from __future__ import with_statement
|
||||
import mimetypes
|
||||
import os
|
||||
import time
|
||||
import traceback
|
||||
from ConfigParser import ConfigParser
|
||||
from urllib import unquote, quote
|
||||
import uuid
|
||||
@ -73,6 +74,22 @@ def public(func):
|
||||
return wrapped
|
||||
|
||||
|
||||
def delay_denial(func):
|
||||
"""
|
||||
Decorator to declare which methods should have any swift.authorize call
|
||||
delayed. This is so the method can load the Request object up with
|
||||
additional information that may be needed by the authorization system.
|
||||
|
||||
:param func: function to delay authorization on
|
||||
"""
|
||||
func.delay_denial = True
|
||||
|
||||
@functools.wraps(func)
|
||||
def wrapped(*a, **kw):
|
||||
return func(*a, **kw)
|
||||
return wrapped
|
||||
|
||||
|
||||
class Controller(object):
|
||||
"""Base WSGI controller class for the proxy"""
|
||||
|
||||
@ -206,19 +223,28 @@ class Controller(object):
|
||||
|
||||
:param account: account name for the container
|
||||
:param container: container name to look up
|
||||
:returns: tuple of (container partition, container nodes) or
|
||||
(None, None) if the container does not exist
|
||||
:returns: tuple of (container partition, container nodes, container
|
||||
read acl, container write acl) or (None, None, None, None) if
|
||||
the container does not exist
|
||||
"""
|
||||
partition, nodes = self.app.container_ring.get_nodes(
|
||||
account, container)
|
||||
path = '/%s/%s' % (account, container)
|
||||
cache_key = 'container%s' % path
|
||||
# Older memcache values (should be treated as if they aren't there):
|
||||
# 0 = no responses, 200 = found, 404 = not found, -1 = mixed responses
|
||||
if self.app.memcache.get(cache_key) == 200:
|
||||
return partition, nodes
|
||||
# Newer memcache values:
|
||||
# [older status value from above, read acl, write acl]
|
||||
cache_value = self.app.memcache.get(cache_key)
|
||||
if hasattr(cache_value, '__iter__'):
|
||||
status, read_acl, write_acl = cache_value
|
||||
if status == 200:
|
||||
return partition, nodes, read_acl, write_acl
|
||||
if not self.account_info(account)[1]:
|
||||
return (None, None)
|
||||
return (None, None, None, None)
|
||||
result_code = 0
|
||||
read_acl = None
|
||||
write_acl = None
|
||||
attempts_left = self.app.container_ring.replica_count
|
||||
headers = {'x-cf-trans-id': self.trans_id}
|
||||
for node in self.iter_nodes(partition, nodes, self.app.container_ring):
|
||||
@ -233,6 +259,8 @@ class Controller(object):
|
||||
body = resp.read()
|
||||
if 200 <= resp.status <= 299:
|
||||
result_code = 200
|
||||
read_acl = resp.getheader('x-container-read')
|
||||
write_acl = resp.getheader('x-container-write')
|
||||
break
|
||||
elif resp.status == 404:
|
||||
result_code = 404 if not result_code else -1
|
||||
@ -251,10 +279,11 @@ class Controller(object):
|
||||
cache_timeout = self.app.recheck_container_existence
|
||||
else:
|
||||
cache_timeout = self.app.recheck_container_existence * 0.1
|
||||
self.app.memcache.set(cache_key, result_code, timeout=cache_timeout)
|
||||
self.app.memcache.set(cache_key, (result_code, read_acl, write_acl),
|
||||
timeout=cache_timeout)
|
||||
if result_code == 200:
|
||||
return partition, nodes
|
||||
return (None, None)
|
||||
return partition, nodes, read_acl, write_acl
|
||||
return (None, None, None, None)
|
||||
|
||||
def iter_nodes(self, partition, nodes, ring):
|
||||
"""
|
||||
@ -474,6 +503,12 @@ class ObjectController(Controller):
|
||||
|
||||
def GETorHEAD(self, req):
|
||||
"""Handle HTTP GET or HEAD requests."""
|
||||
if 'swift.authorize' in req.environ:
|
||||
req.acl = \
|
||||
self.container_info(self.account_name, self.container_name)[2]
|
||||
aresp = req.environ['swift.authorize'](req)
|
||||
if aresp:
|
||||
return aresp
|
||||
partition, nodes = self.app.object_ring.get_nodes(
|
||||
self.account_name, self.container_name, self.object_name)
|
||||
return self.GETorHEAD_base(req, 'Object', partition,
|
||||
@ -481,13 +516,30 @@ class ObjectController(Controller):
|
||||
req.path_info, self.app.object_ring.replica_count)
|
||||
|
||||
@public
|
||||
@delay_denial
|
||||
def GET(self, req):
|
||||
"""Handler for HTTP GET requests."""
|
||||
return self.GETorHEAD(req)
|
||||
|
||||
@public
|
||||
@delay_denial
|
||||
def HEAD(self, req):
|
||||
"""Handler for HTTP HEAD requests."""
|
||||
return self.GETorHEAD(req)
|
||||
|
||||
@public
|
||||
@delay_denial
|
||||
def POST(self, req):
|
||||
"""HTTP POST request handler."""
|
||||
error_response = check_metadata(req, 'object')
|
||||
if error_response:
|
||||
return error_response
|
||||
container_partition, containers = \
|
||||
container_partition, containers, _, req.acl = \
|
||||
self.container_info(self.account_name, self.container_name)
|
||||
if 'swift.authorize' in req.environ:
|
||||
aresp = req.environ['swift.authorize'](req)
|
||||
if aresp:
|
||||
return aresp
|
||||
if not containers:
|
||||
return HTTPNotFound(request=req)
|
||||
containers = self.get_update_nodes(container_partition, containers,
|
||||
@ -521,10 +573,15 @@ class ObjectController(Controller):
|
||||
bodies, 'Object POST')
|
||||
|
||||
@public
|
||||
@delay_denial
|
||||
def PUT(self, req):
|
||||
"""HTTP PUT request handler."""
|
||||
container_partition, containers = \
|
||||
container_partition, containers, _, req.acl = \
|
||||
self.container_info(self.account_name, self.container_name)
|
||||
if 'swift.authorize' in req.environ:
|
||||
aresp = req.environ['swift.authorize'](req)
|
||||
if aresp:
|
||||
return aresp
|
||||
if not containers:
|
||||
return HTTPNotFound(request=req)
|
||||
containers = self.get_update_nodes(container_partition, containers,
|
||||
@ -701,10 +758,15 @@ class ObjectController(Controller):
|
||||
return resp
|
||||
|
||||
@public
|
||||
@delay_denial
|
||||
def DELETE(self, req):
|
||||
"""HTTP DELETE request handler."""
|
||||
container_partition, containers = \
|
||||
container_partition, containers, _, req.acl = \
|
||||
self.container_info(self.account_name, self.container_name)
|
||||
if 'swift.authorize' in req.environ:
|
||||
aresp = req.environ['swift.authorize'](req)
|
||||
if aresp:
|
||||
return aresp
|
||||
if not containers:
|
||||
return HTTPNotFound(request=req)
|
||||
containers = self.get_update_nodes(container_partition, containers,
|
||||
@ -771,11 +833,25 @@ class ObjectController(Controller):
|
||||
class ContainerController(Controller):
|
||||
"""WSGI controller for container requests"""
|
||||
|
||||
# Ensure these are all lowercase
|
||||
pass_through_headers = ['x-container-read', 'x-container-write']
|
||||
|
||||
def __init__(self, app, account_name, container_name, **kwargs):
|
||||
Controller.__init__(self, app)
|
||||
self.account_name = unquote(account_name)
|
||||
self.container_name = unquote(container_name)
|
||||
|
||||
def clean_acls(self, req):
|
||||
if 'swift.clean_acl' in req.environ:
|
||||
for header in ('x-container-read', 'x-container-write'):
|
||||
if header in req.headers:
|
||||
try:
|
||||
req.headers[header] = \
|
||||
req.environ['swift.clean_acl'](header,
|
||||
req.headers[header])
|
||||
except ValueError, err:
|
||||
return HTTPBadRequest(request=req, body=str(err))
|
||||
|
||||
def GETorHEAD(self, req):
|
||||
"""Handler for HTTP GET/HEAD requests."""
|
||||
if not self.account_info(self.account_name)[1]:
|
||||
@ -784,8 +860,25 @@ class ContainerController(Controller):
|
||||
self.account_name, self.container_name)
|
||||
resp = self.GETorHEAD_base(req, 'Container', part, nodes,
|
||||
req.path_info, self.app.container_ring.replica_count)
|
||||
if 'swift.authorize' in req.environ:
|
||||
req.acl = resp.headers.get('x-container-read')
|
||||
aresp = req.environ['swift.authorize'](req)
|
||||
if aresp:
|
||||
return aresp
|
||||
return resp
|
||||
|
||||
@public
|
||||
@delay_denial
|
||||
def GET(self, req):
|
||||
"""Handler for HTTP GET requests."""
|
||||
return self.GETorHEAD(req)
|
||||
|
||||
@public
|
||||
@delay_denial
|
||||
def HEAD(self, req):
|
||||
"""Handler for HTTP HEAD requests."""
|
||||
return self.GETorHEAD(req)
|
||||
|
||||
@public
|
||||
def PUT(self, req):
|
||||
"""HTTP PUT request handler."""
|
||||
@ -806,8 +899,10 @@ class ContainerController(Controller):
|
||||
self.account_name, self.container_name)
|
||||
headers = {'X-Timestamp': normalize_timestamp(time.time()),
|
||||
'x-cf-trans-id': self.trans_id}
|
||||
self.clean_acls(req)
|
||||
headers.update(value for value in req.headers.iteritems()
|
||||
if value[0].lower().startswith('x-container-meta-'))
|
||||
if value[0].lower() in self.pass_through_headers or
|
||||
value[0].lower().startswith('x-container-meta-'))
|
||||
statuses = []
|
||||
reasons = []
|
||||
bodies = []
|
||||
@ -863,8 +958,10 @@ class ContainerController(Controller):
|
||||
self.account_name, self.container_name)
|
||||
headers = {'X-Timestamp': normalize_timestamp(time.time()),
|
||||
'x-cf-trans-id': self.trans_id}
|
||||
self.clean_acls(req)
|
||||
headers.update(value for value in req.headers.iteritems()
|
||||
if value[0].lower().startswith('x-container-meta-'))
|
||||
if value[0].lower() in self.pass_through_headers or
|
||||
value[0].lower().startswith('x-container-meta-'))
|
||||
statuses = []
|
||||
reasons = []
|
||||
bodies = []
|
||||
@ -1118,7 +1215,8 @@ class BaseApplication(object):
|
||||
self.posthooklogger(env, req)
|
||||
return response
|
||||
except:
|
||||
print "EXCEPTION IN __call__: %s" % env
|
||||
print "EXCEPTION IN __call__: %s: %s" % \
|
||||
(traceback.format_exc(), env)
|
||||
start_response('500 Server Error',
|
||||
[('Content-Type', 'text/plain')])
|
||||
return ['Internal server error.\n']
|
||||
@ -1160,12 +1258,28 @@ class BaseApplication(object):
|
||||
controller.trans_id = req.headers.get('x-cf-trans-id', '-')
|
||||
try:
|
||||
handler = getattr(controller, req.method)
|
||||
if getattr(handler, 'publicly_accessible'):
|
||||
if path_parts['version']:
|
||||
req.path_info_pop()
|
||||
return handler(req)
|
||||
if not getattr(handler, 'publicly_accessible'):
|
||||
handler = None
|
||||
except AttributeError:
|
||||
handler = None
|
||||
if not handler:
|
||||
return HTTPMethodNotAllowed(request=req)
|
||||
if path_parts['version']:
|
||||
req.path_info_pop()
|
||||
if 'swift.authorize' in req.environ:
|
||||
# We call authorize before the handler, always. If authorized,
|
||||
# we remove the swift.authorize hook so isn't ever called
|
||||
# again. If not authorized, we return the denial unless the
|
||||
# controller's method indicates it'd like to gather more
|
||||
# information and try again later.
|
||||
resp = req.environ['swift.authorize'](req)
|
||||
if resp:
|
||||
if not getattr(handler, 'delay_denial', None) and \
|
||||
'swift.authorize' in req.environ:
|
||||
return resp
|
||||
else:
|
||||
del req.environ['swift.authorize']
|
||||
return handler(req)
|
||||
except Exception:
|
||||
self.logger.exception('ERROR Unhandled exception in request')
|
||||
return HTTPServerError(request=req)
|
||||
@ -1187,7 +1301,9 @@ class Application(BaseApplication):
|
||||
return req.response
|
||||
|
||||
def posthooklogger(self, env, req):
|
||||
response = req.response
|
||||
response = getattr(req, 'response', None)
|
||||
if not response:
|
||||
return
|
||||
trans_time = '%.4f' % (time.time() - req.start_time)
|
||||
the_request = quote(unquote(req.path))
|
||||
if req.query_string:
|
||||
@ -1215,7 +1331,8 @@ class Application(BaseApplication):
|
||||
status_int,
|
||||
req.referer or '-',
|
||||
req.user_agent or '-',
|
||||
req.headers.get('x-auth-token', '-'),
|
||||
'%s:%s' % (req.remote_user or '',
|
||||
req.headers.get('x-auth-token', '-')),
|
||||
getattr(req, 'bytes_transferred', 0) or '-',
|
||||
getattr(response, 'bytes_transferred', 0) or '-',
|
||||
req.headers.get('etag', '-'),
|
||||
|
@ -1,10 +1,20 @@
|
||||
# Sample functional test configuration file
|
||||
# sample config
|
||||
auth_host = 127.0.0.1
|
||||
auth_port = 80
|
||||
auth_port = 11000
|
||||
auth_ssl = no
|
||||
|
||||
account = test_account
|
||||
username = test_user
|
||||
password = test_password
|
||||
# Primary functional test account
|
||||
account = test
|
||||
username = tester
|
||||
password = testing
|
||||
|
||||
# User on a second account
|
||||
account2 = test2
|
||||
username2 = tester2
|
||||
password2 = testing2
|
||||
|
||||
# User on same account as first, but with noaccess
|
||||
username3 = tester3
|
||||
password3 = testing3
|
||||
|
||||
collate = C
|
||||
|
@ -106,9 +106,12 @@ class Base(unittest.TestCase):
|
||||
self.assert_(response_body == body,
|
||||
'Body returned: %s' % (response_body))
|
||||
|
||||
def assert_status(self, status):
|
||||
self.assert_(self.env.conn.response.status == status,
|
||||
'Status returned: %d' % (self.env.conn.response.status))
|
||||
def assert_status(self, status_or_statuses):
|
||||
self.assert_(self.env.conn.response.status == status_or_statuses or
|
||||
(hasattr(status_or_statuses, '__iter__') and
|
||||
self.env.conn.response.status in status_or_statuses),
|
||||
'Status returned: %d Expected: %s' %
|
||||
(self.env.conn.response.status, status_or_statuses))
|
||||
|
||||
class Base2(object):
|
||||
def setUp(self):
|
||||
@ -148,11 +151,11 @@ class TestAccount(Base):
|
||||
def testNoAuthToken(self):
|
||||
self.assertRaises(ResponseError, self.env.account.info,
|
||||
cfg={'no_auth_token':True})
|
||||
self.assert_status(412)
|
||||
self.assert_status([401, 412])
|
||||
|
||||
self.assertRaises(ResponseError, self.env.account.containers,
|
||||
cfg={'no_auth_token':True})
|
||||
self.assert_status(412)
|
||||
self.assert_status([401, 412])
|
||||
|
||||
def testInvalidUTF8Path(self):
|
||||
invalid_utf8 = Utils.create_utf8_name()[::-1]
|
||||
@ -1123,7 +1126,8 @@ class TestFile(Base):
|
||||
self.assert_status(400)
|
||||
|
||||
# bad request types
|
||||
for req in ('LICK', 'GETorHEAD_base', 'container_info', 'best_response'):
|
||||
#for req in ('LICK', 'GETorHEAD_base', 'container_info', 'best_response'):
|
||||
for req in ('LICK', 'GETorHEAD_base'):
|
||||
self.env.account.conn.make_request(req)
|
||||
self.assert_status(405)
|
||||
|
||||
|
@ -10,11 +10,11 @@ from swift.common.client import get_auth, http_connection
|
||||
|
||||
|
||||
swift_test_auth = os.environ.get('SWIFT_TEST_AUTH')
|
||||
swift_test_user = os.environ.get('SWIFT_TEST_USER')
|
||||
swift_test_key = os.environ.get('SWIFT_TEST_KEY')
|
||||
swift_test_user = [os.environ.get('SWIFT_TEST_USER'), None, None]
|
||||
swift_test_key = [os.environ.get('SWIFT_TEST_KEY'), None, None]
|
||||
|
||||
# If no environment set, fall back to old school conf file
|
||||
if not all([swift_test_auth, swift_test_user, swift_test_key]):
|
||||
if not all([swift_test_auth, swift_test_user[0], swift_test_key[0]]):
|
||||
conf = ConfigParser()
|
||||
class Sectionizer(object):
|
||||
def __init__(self, fp):
|
||||
@ -32,16 +32,36 @@ if not all([swift_test_auth, swift_test_user, swift_test_key]):
|
||||
if conf.get('auth_ssl', 'no').lower() in ('yes', 'true', 'on', '1'):
|
||||
swift_test_auth = 'https'
|
||||
swift_test_auth += '://%(auth_host)s:%(auth_port)s/v1.0' % conf
|
||||
swift_test_user = '%(account)s:%(username)s' % conf
|
||||
swift_test_key = conf['password']
|
||||
swift_test_user[0] = '%(account)s:%(username)s' % conf
|
||||
swift_test_key[0] = conf['password']
|
||||
try:
|
||||
swift_test_user[1] = '%(account2)s:%(username2)s' % conf
|
||||
swift_test_key[1] = conf['password2']
|
||||
except KeyError, err:
|
||||
pass # old conf, no second account tests can be run
|
||||
try:
|
||||
swift_test_user[2] = '%(account)s:%(username3)s' % conf
|
||||
swift_test_key[2] = conf['password3']
|
||||
except KeyError, err:
|
||||
pass # old conf, no third account tests can be run
|
||||
except IOError, err:
|
||||
if err.errno != errno.ENOENT:
|
||||
raise
|
||||
|
||||
skip = not all([swift_test_auth, swift_test_user, swift_test_key])
|
||||
skip = not all([swift_test_auth, swift_test_user[0], swift_test_key[0]])
|
||||
if skip:
|
||||
print >>sys.stderr, 'SKIPPING FUNCTIONAL TESTS DUE TO NO CONFIG'
|
||||
|
||||
skip2 = not all([not skip, swift_test_user[1], swift_test_key[1]])
|
||||
if not skip and skip2:
|
||||
print >>sys.stderr, \
|
||||
'SKIPPING SECOND ACCOUNT FUNCTIONAL TESTS DUE TO NO CONFIG FOR THEM'
|
||||
|
||||
skip3 = not all([not skip, swift_test_user[2], swift_test_key[2]])
|
||||
if not skip and skip3:
|
||||
print >>sys.stderr, \
|
||||
'SKIPPING THIRD ACCOUNT FUNCTIONAL TESTS DUE TO NO CONFIG FOR THEM'
|
||||
|
||||
|
||||
class AuthError(Exception):
|
||||
pass
|
||||
@ -51,29 +71,44 @@ class InternalServerError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
url = token = parsed = conn = None
|
||||
url = [None, None, None]
|
||||
token = [None, None, None]
|
||||
parsed = [None, None, None]
|
||||
conn = [None, None, None]
|
||||
|
||||
def retry(func, *args, **kwargs):
|
||||
"""
|
||||
You can use the kwargs to override the 'retries' (default: 5) and
|
||||
'use_account' (default: 1).
|
||||
"""
|
||||
global url, token, parsed, conn
|
||||
retries = kwargs.get('retries', 5)
|
||||
use_account = 1
|
||||
if 'use_account' in kwargs:
|
||||
use_account = kwargs['use_account']
|
||||
del kwargs['use_account']
|
||||
use_account -= 1
|
||||
attempts = 0
|
||||
backoff = 1
|
||||
while attempts <= retries:
|
||||
attempts += 1
|
||||
try:
|
||||
if not url or not token:
|
||||
url, token = \
|
||||
get_auth(swift_test_auth, swift_test_user, swift_test_key)
|
||||
parsed = conn = None
|
||||
if not parsed or not conn:
|
||||
parsed, conn = http_connection(url)
|
||||
return func(url, token, parsed, conn, *args, **kwargs)
|
||||
if not url[use_account] or not token[use_account]:
|
||||
url[use_account], token[use_account] = \
|
||||
get_auth(swift_test_auth, swift_test_user[use_account],
|
||||
swift_test_key[use_account])
|
||||
parsed[use_account] = conn[use_account] = None
|
||||
if not parsed[use_account] or not conn[use_account]:
|
||||
parsed[use_account], conn[use_account] = \
|
||||
http_connection(url[use_account])
|
||||
return func(url[use_account], token[use_account],
|
||||
parsed[use_account], conn[use_account], *args, **kwargs)
|
||||
except (socket.error, HTTPException):
|
||||
if attempts > retries:
|
||||
raise
|
||||
parsed = conn = None
|
||||
parsed[use_account] = conn[use_account] = None
|
||||
except AuthError, err:
|
||||
url = token = None
|
||||
url[use_account] = token[use_account] = None
|
||||
continue
|
||||
except InternalServerError, err:
|
||||
pass
|
||||
|
@ -1,6 +1,7 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import unittest
|
||||
from nose import SkipTest
|
||||
|
||||
from swift.common.constraints import MAX_META_COUNT, MAX_META_NAME_LENGTH, \
|
||||
MAX_META_OVERALL_SIZE, MAX_META_VALUE_LENGTH
|
||||
@ -12,7 +13,7 @@ class TestAccount(unittest.TestCase):
|
||||
|
||||
def test_metadata(self):
|
||||
if skip:
|
||||
return
|
||||
raise SkipTest
|
||||
def post(url, token, parsed, conn, value):
|
||||
conn.request('POST', parsed.path, '',
|
||||
{'X-Auth-Token': token, 'X-Account-Meta-Test': value})
|
||||
@ -48,7 +49,7 @@ class TestAccount(unittest.TestCase):
|
||||
|
||||
def test_multi_metadata(self):
|
||||
if skip:
|
||||
return
|
||||
raise SkipTest
|
||||
def post(url, token, parsed, conn, name, value):
|
||||
conn.request('POST', parsed.path, '',
|
||||
{'X-Auth-Token': token, name: value})
|
||||
@ -74,7 +75,7 @@ class TestAccount(unittest.TestCase):
|
||||
|
||||
def test_bad_metadata(self):
|
||||
if skip:
|
||||
return
|
||||
raise SkipTest
|
||||
def post(url, token, parsed, conn, extra_headers):
|
||||
headers = {'X-Auth-Token': token}
|
||||
headers.update(extra_headers)
|
||||
|
@ -1,19 +1,22 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import json
|
||||
import unittest
|
||||
from nose import SkipTest
|
||||
from uuid import uuid4
|
||||
|
||||
from swift.common.constraints import MAX_META_COUNT, MAX_META_NAME_LENGTH, \
|
||||
MAX_META_OVERALL_SIZE, MAX_META_VALUE_LENGTH
|
||||
|
||||
from swift_testing import check_response, retry, skip
|
||||
from swift_testing import check_response, retry, skip, skip2, skip3, \
|
||||
swift_test_user
|
||||
|
||||
|
||||
class TestContainer(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
if skip:
|
||||
return
|
||||
raise SkipTest
|
||||
self.name = uuid4().hex
|
||||
def put(url, token, parsed, conn):
|
||||
conn.request('PUT', parsed.path + '/' + self.name, '',
|
||||
@ -25,7 +28,27 @@ class TestContainer(unittest.TestCase):
|
||||
|
||||
def tearDown(self):
|
||||
if skip:
|
||||
return
|
||||
raise SkipTest
|
||||
def get(url, token, parsed, conn):
|
||||
conn.request('GET', parsed.path + '/' + self.name + '?format=json',
|
||||
'', {'X-Auth-Token': token})
|
||||
return check_response(conn)
|
||||
def delete(url, token, parsed, conn, obj):
|
||||
conn.request('DELETE',
|
||||
'/'.join([parsed.path, self.name, obj['name']]), '',
|
||||
{'X-Auth-Token': token})
|
||||
return check_response(conn)
|
||||
while True:
|
||||
resp = retry(get)
|
||||
body = resp.read()
|
||||
self.assert_(resp.status // 100 == 2, resp.status)
|
||||
objs = json.loads(body)
|
||||
if not objs:
|
||||
break
|
||||
for obj in objs:
|
||||
resp = retry(delete, obj)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 204)
|
||||
def delete(url, token, parsed, conn):
|
||||
conn.request('DELETE', parsed.path + '/' + self.name, '',
|
||||
{'X-Auth-Token': token})
|
||||
@ -36,7 +59,7 @@ class TestContainer(unittest.TestCase):
|
||||
|
||||
def test_multi_metadata(self):
|
||||
if skip:
|
||||
return
|
||||
raise SkipTest
|
||||
def post(url, token, parsed, conn, name, value):
|
||||
conn.request('POST', parsed.path + '/' + self.name, '',
|
||||
{'X-Auth-Token': token, name: value})
|
||||
@ -63,7 +86,7 @@ class TestContainer(unittest.TestCase):
|
||||
|
||||
def test_PUT_metadata(self):
|
||||
if skip:
|
||||
return
|
||||
raise SkipTest
|
||||
def put(url, token, parsed, conn, name, value):
|
||||
conn.request('PUT', parsed.path + '/' + name, '',
|
||||
{'X-Auth-Token': token, 'X-Container-Meta-Test': value})
|
||||
@ -110,7 +133,7 @@ class TestContainer(unittest.TestCase):
|
||||
|
||||
def test_POST_metadata(self):
|
||||
if skip:
|
||||
return
|
||||
raise SkipTest
|
||||
def post(url, token, parsed, conn, value):
|
||||
conn.request('POST', parsed.path + '/' + self.name, '',
|
||||
{'X-Auth-Token': token, 'X-Container-Meta-Test': value})
|
||||
@ -145,7 +168,7 @@ class TestContainer(unittest.TestCase):
|
||||
|
||||
def test_PUT_bad_metadata(self):
|
||||
if skip:
|
||||
return
|
||||
raise SkipTest
|
||||
def put(url, token, parsed, conn, name, extra_headers):
|
||||
headers = {'X-Auth-Token': token}
|
||||
headers.update(extra_headers)
|
||||
@ -240,7 +263,7 @@ class TestContainer(unittest.TestCase):
|
||||
|
||||
def test_POST_bad_metadata(self):
|
||||
if skip:
|
||||
return
|
||||
raise SkipTest
|
||||
def post(url, token, parsed, conn, extra_headers):
|
||||
headers = {'X-Auth-Token': token}
|
||||
headers.update(extra_headers)
|
||||
@ -297,6 +320,206 @@ class TestContainer(unittest.TestCase):
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 400)
|
||||
|
||||
def test_public_container(self):
|
||||
if skip:
|
||||
raise SkipTest
|
||||
def get(url, token, parsed, conn):
|
||||
conn.request('GET', parsed.path + '/' + self.name)
|
||||
return check_response(conn)
|
||||
try:
|
||||
resp = retry(get)
|
||||
raise Exception('Should not have been able to GET')
|
||||
except Exception, err:
|
||||
self.assert_(str(err).startswith('No result after '), err)
|
||||
def post(url, token, parsed, conn):
|
||||
conn.request('POST', parsed.path + '/' + self.name, '',
|
||||
{'X-Auth-Token': token,
|
||||
'X-Container-Read': '.ref:any'})
|
||||
return check_response(conn)
|
||||
resp = retry(post)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 204)
|
||||
resp = retry(get)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 204)
|
||||
def post(url, token, parsed, conn):
|
||||
conn.request('POST', parsed.path + '/' + self.name, '',
|
||||
{'X-Auth-Token': token, 'X-Container-Read': ''})
|
||||
return check_response(conn)
|
||||
resp = retry(post)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 204)
|
||||
try:
|
||||
resp = retry(get)
|
||||
raise Exception('Should not have been able to GET')
|
||||
except Exception, err:
|
||||
self.assert_(str(err).startswith('No result after '), err)
|
||||
|
||||
def test_cross_account_container(self):
|
||||
if skip or skip2:
|
||||
raise SkipTest
|
||||
# Obtain the first account's string
|
||||
first_account = ['unknown']
|
||||
def get1(url, token, parsed, conn):
|
||||
first_account[0] = parsed.path
|
||||
conn.request('HEAD', parsed.path + '/' + self.name, '',
|
||||
{'X-Auth-Token': token})
|
||||
return check_response(conn)
|
||||
resp = retry(get1)
|
||||
resp.read()
|
||||
# Ensure we can't access the container with the second account
|
||||
def get2(url, token, parsed, conn):
|
||||
conn.request('GET', first_account[0] + '/' + self.name, '',
|
||||
{'X-Auth-Token': token})
|
||||
return check_response(conn)
|
||||
resp = retry(get2, use_account=2)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 403)
|
||||
# Make the container accessible by the second account
|
||||
def post(url, token, parsed, conn):
|
||||
conn.request('POST', parsed.path + '/' + self.name, '',
|
||||
{'X-Auth-Token': token,
|
||||
'X-Container-Read': 'test2',
|
||||
'X-Container-Write': 'test2'})
|
||||
return check_response(conn)
|
||||
resp = retry(post)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 204)
|
||||
# Ensure we can now use the container with the second account
|
||||
resp = retry(get2, use_account=2)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 204)
|
||||
# Make the container private again
|
||||
def post(url, token, parsed, conn):
|
||||
conn.request('POST', parsed.path + '/' + self.name, '',
|
||||
{'X-Auth-Token': token, 'X-Container-Read': '',
|
||||
'X-Container-Write': ''})
|
||||
return check_response(conn)
|
||||
resp = retry(post)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 204)
|
||||
# Ensure we can't access the container with the second account again
|
||||
resp = retry(get2, use_account=2)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 403)
|
||||
|
||||
def test_cross_account_public_container(self):
|
||||
if skip or skip2:
|
||||
raise SkipTest
|
||||
# Obtain the first account's string
|
||||
first_account = ['unknown']
|
||||
def get1(url, token, parsed, conn):
|
||||
first_account[0] = parsed.path
|
||||
conn.request('HEAD', parsed.path + '/' + self.name, '',
|
||||
{'X-Auth-Token': token})
|
||||
return check_response(conn)
|
||||
resp = retry(get1)
|
||||
resp.read()
|
||||
# Ensure we can't access the container with the second account
|
||||
def get2(url, token, parsed, conn):
|
||||
conn.request('GET', first_account[0] + '/' + self.name, '',
|
||||
{'X-Auth-Token': token})
|
||||
return check_response(conn)
|
||||
resp = retry(get2, use_account=2)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 403)
|
||||
# Make the container completely public
|
||||
def post(url, token, parsed, conn):
|
||||
conn.request('POST', parsed.path + '/' + self.name, '',
|
||||
{'X-Auth-Token': token,
|
||||
'X-Container-Read': '.ref:any'})
|
||||
return check_response(conn)
|
||||
resp = retry(post)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 204)
|
||||
# Ensure we can now read the container with the second account
|
||||
resp = retry(get2, use_account=2)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 204)
|
||||
# But we shouldn't be able to write with the second account
|
||||
def put2(url, token, parsed, conn):
|
||||
conn.request('PUT', first_account[0] + '/' + self.name + '/object',
|
||||
'test object', {'X-Auth-Token': token})
|
||||
return check_response(conn)
|
||||
resp = retry(put2, use_account=2)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 403)
|
||||
# Now make the container also writeable by the second account
|
||||
def post(url, token, parsed, conn):
|
||||
conn.request('POST', parsed.path + '/' + self.name, '',
|
||||
{'X-Auth-Token': token,
|
||||
'X-Container-Write': 'test2'})
|
||||
return check_response(conn)
|
||||
resp = retry(post)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 204)
|
||||
# Ensure we can still read the container with the second account
|
||||
resp = retry(get2, use_account=2)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 204)
|
||||
# And that we can now write with the second account
|
||||
resp = retry(put2, use_account=2)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 201)
|
||||
|
||||
def test_noaccess_user(self):
|
||||
if skip or skip3:
|
||||
raise SkipTest
|
||||
# Obtain the first account's string
|
||||
first_account = ['unknown']
|
||||
def get1(url, token, parsed, conn):
|
||||
first_account[0] = parsed.path
|
||||
conn.request('HEAD', parsed.path + '/' + self.name, '',
|
||||
{'X-Auth-Token': token})
|
||||
return check_response(conn)
|
||||
resp = retry(get1)
|
||||
resp.read()
|
||||
# Ensure we can't access the container with the third account
|
||||
def get3(url, token, parsed, conn):
|
||||
conn.request('GET', first_account[0] + '/' + self.name, '',
|
||||
{'X-Auth-Token': token})
|
||||
return check_response(conn)
|
||||
resp = retry(get3, use_account=3)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 403)
|
||||
# Make the container accessible by the third account
|
||||
def post(url, token, parsed, conn):
|
||||
conn.request('POST', parsed.path + '/' + self.name, '',
|
||||
{'X-Auth-Token': token, 'X-Container-Read': swift_test_user[2]})
|
||||
return check_response(conn)
|
||||
resp = retry(post)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 204)
|
||||
# Ensure we can now read the container with the third account
|
||||
resp = retry(get3, use_account=3)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 204)
|
||||
# But we shouldn't be able to write with the third account
|
||||
def put3(url, token, parsed, conn):
|
||||
conn.request('PUT', first_account[0] + '/' + self.name + '/object',
|
||||
'test object', {'X-Auth-Token': token})
|
||||
return check_response(conn)
|
||||
resp = retry(put3, use_account=3)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 403)
|
||||
# Now make the container also writeable by the third account
|
||||
def post(url, token, parsed, conn):
|
||||
conn.request('POST', parsed.path + '/' + self.name, '',
|
||||
{'X-Auth-Token': token,
|
||||
'X-Container-Write': swift_test_user[2]})
|
||||
return check_response(conn)
|
||||
resp = retry(post)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 204)
|
||||
# Ensure we can still read the container with the third account
|
||||
resp = retry(get3, use_account=3)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 204)
|
||||
# And that we can now write with the third account
|
||||
resp = retry(put3, use_account=3)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 201)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
91
test/functionalnosetests/test_object.py
Normal file
91
test/functionalnosetests/test_object.py
Normal file
@ -0,0 +1,91 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import unittest
|
||||
from nose import SkipTest
|
||||
from uuid import uuid4
|
||||
|
||||
from swift.common.constraints import MAX_META_COUNT, MAX_META_NAME_LENGTH, \
|
||||
MAX_META_OVERALL_SIZE, MAX_META_VALUE_LENGTH
|
||||
|
||||
from swift_testing import check_response, retry, skip
|
||||
|
||||
|
||||
class TestObject(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
if skip:
|
||||
raise SkipTest
|
||||
self.container = uuid4().hex
|
||||
def put(url, token, parsed, conn):
|
||||
conn.request('PUT', parsed.path + '/' + self.container, '',
|
||||
{'X-Auth-Token': token})
|
||||
return check_response(conn)
|
||||
resp = retry(put)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 201)
|
||||
self.obj = uuid4().hex
|
||||
def put(url, token, parsed, conn):
|
||||
conn.request('PUT', '%s/%s/%s' % (parsed.path, self.container,
|
||||
self.obj), 'test', {'X-Auth-Token': token})
|
||||
return check_response(conn)
|
||||
resp = retry(put)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 201)
|
||||
|
||||
def tearDown(self):
|
||||
if skip:
|
||||
raise SkipTest
|
||||
def delete(url, token, parsed, conn):
|
||||
conn.request('DELETE', '%s/%s/%s' % (parsed.path, self.container,
|
||||
self.obj), '', {'X-Auth-Token': token})
|
||||
return check_response(conn)
|
||||
resp = retry(delete)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 204)
|
||||
def delete(url, token, parsed, conn):
|
||||
conn.request('DELETE', parsed.path + '/' + self.container, '',
|
||||
{'X-Auth-Token': token})
|
||||
return check_response(conn)
|
||||
resp = retry(delete)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 204)
|
||||
|
||||
def test_public_object(self):
|
||||
if skip:
|
||||
raise SkipTest
|
||||
def get(url, token, parsed, conn):
|
||||
conn.request('GET',
|
||||
'%s/%s/%s' % (parsed.path, self.container, self.obj))
|
||||
return check_response(conn)
|
||||
try:
|
||||
resp = retry(get)
|
||||
raise Exception('Should not have been able to GET')
|
||||
except Exception, err:
|
||||
self.assert_(str(err).startswith('No result after '))
|
||||
def post(url, token, parsed, conn):
|
||||
conn.request('POST', parsed.path + '/' + self.container, '',
|
||||
{'X-Auth-Token': token,
|
||||
'X-Container-Read': '.ref:any'})
|
||||
return check_response(conn)
|
||||
resp = retry(post)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 204)
|
||||
resp = retry(get)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 200)
|
||||
def post(url, token, parsed, conn):
|
||||
conn.request('POST', parsed.path + '/' + self.container, '',
|
||||
{'X-Auth-Token': token, 'X-Container-Read': ''})
|
||||
return check_response(conn)
|
||||
resp = retry(post)
|
||||
resp.read()
|
||||
self.assertEquals(resp.status, 204)
|
||||
try:
|
||||
resp = retry(get)
|
||||
raise Exception('Should not have been able to GET')
|
||||
except Exception, err:
|
||||
self.assert_(str(err).startswith('No result after '))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -113,20 +113,7 @@ class TestAuthServer(unittest.TestCase):
|
||||
headers={'X-Storage-User': 'tester',
|
||||
'X-Storage-Pass': 'testing'}))
|
||||
token = res.headers['x-storage-token']
|
||||
self.assertEquals(self.controller.validate_token(token + 'bad',
|
||||
cfaccount), False)
|
||||
|
||||
def test_validate_token_non_existant_cfaccount(self):
|
||||
auth_server.http_connect = fake_http_connect(201, 201, 201)
|
||||
cfaccount = self.controller.create_account(
|
||||
'test', 'tester', 'testing').split('/')[-1]
|
||||
res = self.controller.handle_auth(Request.blank('/v1/test/auth',
|
||||
environ={'REQUEST_METHOD': 'GET'},
|
||||
headers={'X-Storage-User': 'tester',
|
||||
'X-Storage-Pass': 'testing'}))
|
||||
token = res.headers['x-storage-token']
|
||||
self.assertEquals(self.controller.validate_token(token,
|
||||
cfaccount + 'bad'), False)
|
||||
self.assertEquals(self.controller.validate_token(token + 'bad'), False)
|
||||
|
||||
def test_validate_token_good(self):
|
||||
auth_server.http_connect = fake_http_connect(201, 201, 201)
|
||||
@ -137,7 +124,7 @@ class TestAuthServer(unittest.TestCase):
|
||||
headers={'X-Storage-User': 'tester',
|
||||
'X-Storage-Pass': 'testing'}))
|
||||
token = res.headers['x-storage-token']
|
||||
ttl = self.controller.validate_token(token, cfaccount)
|
||||
ttl = self.controller.validate_token(token)
|
||||
self.assert_(ttl > 0, repr(ttl))
|
||||
|
||||
def test_validate_token_expired(self):
|
||||
@ -152,12 +139,10 @@ class TestAuthServer(unittest.TestCase):
|
||||
headers={'X-Storage-User': 'tester',
|
||||
'X-Storage-Pass': 'testing'}))
|
||||
token = res.headers['x-storage-token']
|
||||
ttl = self.controller.validate_token(
|
||||
token, cfaccount)
|
||||
ttl = self.controller.validate_token(token)
|
||||
self.assert_(ttl > 0, repr(ttl))
|
||||
auth_server.time = lambda: 1 + self.controller.token_life
|
||||
self.assertEquals(self.controller.validate_token(
|
||||
token, cfaccount), False)
|
||||
self.assertEquals(self.controller.validate_token(token), False)
|
||||
finally:
|
||||
auth_server.time = orig_time
|
||||
|
||||
@ -244,7 +229,7 @@ class TestAuthServer(unittest.TestCase):
|
||||
rv = self.controller.recreate_accounts()
|
||||
self.assertEquals(rv.split()[0], '4', repr(rv))
|
||||
failed = rv.split('[', 1)[-1][:-1].split(', ')
|
||||
self.assertEquals(failed, [repr(a) for a in cfaccounts])
|
||||
self.assertEquals(set(failed), set(repr(a) for a in cfaccounts))
|
||||
|
||||
def test_recreate_accounts_several_fail_some(self):
|
||||
auth_server.http_connect = fake_http_connect(201, 201, 201)
|
||||
@ -266,11 +251,8 @@ class TestAuthServer(unittest.TestCase):
|
||||
rv = self.controller.recreate_accounts()
|
||||
self.assertEquals(rv.split()[0], '4', repr(rv))
|
||||
failed = rv.split('[', 1)[-1][:-1].split(', ')
|
||||
expected = []
|
||||
for i, value in enumerate(cfaccounts):
|
||||
if not i % 2:
|
||||
expected.append(repr(value))
|
||||
self.assertEquals(failed, expected)
|
||||
self.assertEquals(
|
||||
len(set(repr(a) for a in cfaccounts) - set(failed)), 2)
|
||||
|
||||
def test_auth_bad_path(self):
|
||||
self.assertRaises(ValueError, self.controller.handle_auth,
|
||||
@ -349,7 +331,7 @@ class TestAuthServer(unittest.TestCase):
|
||||
headers={'X-Storage-User': 'tester',
|
||||
'X-Storage-Pass': 'testing'}))
|
||||
token = res.headers['x-storage-token']
|
||||
ttl = self.controller.validate_token(token, cfaccount)
|
||||
ttl = self.controller.validate_token(token)
|
||||
self.assert_(ttl > 0, repr(ttl))
|
||||
|
||||
def test_auth_SOSO_good_Mosso_headers(self):
|
||||
@ -361,7 +343,7 @@ class TestAuthServer(unittest.TestCase):
|
||||
headers={'X-Auth-User': 'test:tester',
|
||||
'X-Auth-Key': 'testing'}))
|
||||
token = res.headers['x-storage-token']
|
||||
ttl = self.controller.validate_token(token, cfaccount)
|
||||
ttl = self.controller.validate_token(token)
|
||||
self.assert_(ttl > 0, repr(ttl))
|
||||
|
||||
def test_auth_SOSO_bad_Mosso_headers(self):
|
||||
@ -469,7 +451,7 @@ class TestAuthServer(unittest.TestCase):
|
||||
headers={'X-Auth-User': 'test:tester',
|
||||
'X-Auth-Key': 'testing'}))
|
||||
token = res.headers['x-storage-token']
|
||||
ttl = self.controller.validate_token(token, cfaccount)
|
||||
ttl = self.controller.validate_token(token)
|
||||
self.assert_(ttl > 0, repr(ttl))
|
||||
|
||||
def test_auth_Mosso_good_SOSO_header_names(self):
|
||||
@ -481,7 +463,7 @@ class TestAuthServer(unittest.TestCase):
|
||||
headers={'X-Storage-User': 'test:tester',
|
||||
'X-Storage-Pass': 'testing'}))
|
||||
token = res.headers['x-storage-token']
|
||||
ttl = self.controller.validate_token(token, cfaccount)
|
||||
ttl = self.controller.validate_token(token)
|
||||
self.assert_(ttl > 0, repr(ttl))
|
||||
|
||||
def test_basic_logging(self):
|
||||
@ -493,8 +475,8 @@ class TestAuthServer(unittest.TestCase):
|
||||
auth_server.http_connect = fake_http_connect(201, 201, 201)
|
||||
url = self.controller.create_account('test', 'tester', 'testing')
|
||||
self.assertEquals(log.getvalue().rsplit(' ', 1)[0],
|
||||
"auth SUCCESS create_account('test', 'tester', _) = %s" %
|
||||
repr(url))
|
||||
"auth SUCCESS create_account('test', 'tester', _, False) = %s"
|
||||
% repr(url))
|
||||
log.truncate(0)
|
||||
def start_response(*args):
|
||||
pass
|
||||
|
@ -100,77 +100,58 @@ def start_response(*args):
|
||||
pass
|
||||
|
||||
class TestAuth(unittest.TestCase):
|
||||
# TODO: With the auth refactor, these tests have to be refactored as well.
|
||||
# I brought some over from another refactor I've been trying, but these
|
||||
# also need work.
|
||||
|
||||
def setUp(self):
|
||||
self.test_auth = auth.DevAuthMiddleware(
|
||||
FakeApp(), {}, FakeMemcache(), Logger())
|
||||
def test_clean_acl(self):
|
||||
devauth = auth.DevAuthorization(None, None)
|
||||
value = devauth.clean_acl('header', '.ref:any')
|
||||
self.assertEquals(value, '.ref:any')
|
||||
value = devauth.clean_acl('header', '.ref:specific.host')
|
||||
self.assertEquals(value, '.ref:specific.host')
|
||||
value = devauth.clean_acl('header', '.ref:.ending.with')
|
||||
self.assertEquals(value, '.ref:.ending.with')
|
||||
value = devauth.clean_acl('header', '.ref:one,.ref:two')
|
||||
self.assertEquals(value, '.ref:one,.ref:two')
|
||||
value = devauth.clean_acl('header', '.ref:any,.ref:-specific.host')
|
||||
self.assertEquals(value, '.ref:any,.ref:-specific.host')
|
||||
value = devauth.clean_acl('header', '.ref:any,.ref:-.ending.with')
|
||||
self.assertEquals(value, '.ref:any,.ref:-.ending.with')
|
||||
value = devauth.clean_acl('header', '.ref:one,.ref:-two')
|
||||
self.assertEquals(value, '.ref:one,.ref:-two')
|
||||
value = devauth.clean_acl('header',
|
||||
' .ref : one , ,, .ref:two , .ref : - three ')
|
||||
self.assertEquals(value, '.ref:one,.ref:two,.ref:-three')
|
||||
self.assertRaises(ValueError, devauth.clean_acl, 'header', '.ref:')
|
||||
self.assertRaises(ValueError, devauth.clean_acl, 'header', ' .ref : ')
|
||||
self.assertRaises(ValueError, devauth.clean_acl, 'header',
|
||||
'user , .ref : ')
|
||||
self.assertRaises(ValueError, devauth.clean_acl, 'header', '.ref:-')
|
||||
self.assertRaises(ValueError, devauth.clean_acl, 'header',
|
||||
' .ref : - ')
|
||||
self.assertRaises(ValueError, devauth.clean_acl, 'header',
|
||||
'user , .ref : - ')
|
||||
|
||||
def test_auth_fail(self):
|
||||
old_http_connect = auth.http_connect
|
||||
try:
|
||||
auth.http_connect = mock_http_connect(404)
|
||||
self.assertFalse(self.test_auth.auth('a','t'))
|
||||
finally:
|
||||
auth.http_connect = old_http_connect
|
||||
|
||||
def test_auth_success(self):
|
||||
old_http_connect = auth.http_connect
|
||||
try:
|
||||
auth.http_connect = mock_http_connect(204, {'x-auth-ttl':'1234'})
|
||||
self.assertTrue(self.test_auth.auth('a','t'))
|
||||
finally:
|
||||
auth.http_connect = old_http_connect
|
||||
|
||||
def test_auth_memcache(self):
|
||||
old_http_connect = auth.http_connect
|
||||
try:
|
||||
auth.http_connect = mock_http_connect(204, {'x-auth-ttl':'1234'})
|
||||
self.assertTrue(self.test_auth.auth('a','t'))
|
||||
auth.http_connect = mock_http_connect(404)
|
||||
# Should still be in memcache
|
||||
self.assertTrue(self.test_auth.auth('a','t'))
|
||||
finally:
|
||||
auth.http_connect = old_http_connect
|
||||
|
||||
def test_middleware_success(self):
|
||||
old_http_connect = auth.http_connect
|
||||
try:
|
||||
auth.http_connect = mock_http_connect(204, {'x-auth-ttl':'1234'})
|
||||
req = Request.blank('/v/a/c/o', headers={'x-auth-token':'t'})
|
||||
resp = self.test_auth(req.environ, start_response)
|
||||
self.assertEquals(resp, 'OK')
|
||||
finally:
|
||||
auth.http_connect = old_http_connect
|
||||
|
||||
def test_middleware_no_header(self):
|
||||
old_http_connect = auth.http_connect
|
||||
try:
|
||||
auth.http_connect = mock_http_connect(204, {'x-auth-ttl':'1234'})
|
||||
req = Request.blank('/v/a/c/o')
|
||||
resp = self.test_auth(req.environ, start_response)
|
||||
self.assertEquals(resp, ['Missing Auth Token'])
|
||||
finally:
|
||||
auth.http_connect = old_http_connect
|
||||
|
||||
def test_middleware_storage_token(self):
|
||||
old_http_connect = auth.http_connect
|
||||
try:
|
||||
auth.http_connect = mock_http_connect(204, {'x-auth-ttl':'1234'})
|
||||
req = Request.blank('/v/a/c/o', headers={'x-storage-token':'t'})
|
||||
resp = self.test_auth(req.environ, start_response)
|
||||
self.assertEquals(resp, 'OK')
|
||||
finally:
|
||||
auth.http_connect = old_http_connect
|
||||
|
||||
def test_middleware_only_version(self):
|
||||
old_http_connect = auth.http_connect
|
||||
try:
|
||||
auth.http_connect = mock_http_connect(204, {'x-auth-ttl':'1234'})
|
||||
req = Request.blank('/v', headers={'x-auth-token':'t'})
|
||||
resp = self.test_auth(req.environ, start_response)
|
||||
self.assertEquals(resp, ['Bad URL'])
|
||||
finally:
|
||||
auth.http_connect = old_http_connect
|
||||
def test_parse_acl(self):
|
||||
devauth = auth.DevAuthorization(None, None)
|
||||
self.assertEquals(devauth.parse_acl(None), None)
|
||||
self.assertEquals(devauth.parse_acl(''), None)
|
||||
self.assertEquals(devauth.parse_acl('.ref:ref1'),
|
||||
(['ref1'], [], []))
|
||||
self.assertEquals(devauth.parse_acl('.ref:-ref1'),
|
||||
(['-ref1'], [], []))
|
||||
self.assertEquals(devauth.parse_acl('account:user'),
|
||||
([], [], ['account:user']))
|
||||
self.assertEquals(devauth.parse_acl('account'),
|
||||
([], ['account'], []))
|
||||
self.assertEquals(
|
||||
devauth.parse_acl('acc1,acc2:usr2,.ref:ref3,.ref:-ref4'),
|
||||
(['ref3', '-ref4'], ['acc1'], ['acc2:usr2']))
|
||||
self.assertEquals(devauth.parse_acl(
|
||||
'acc1,acc2:usr2,.ref:ref3,acc3,acc4:usr4,.ref:ref5,.ref:-ref6'),
|
||||
(['ref3', 'ref5', '-ref6'], ['acc1', 'acc3'],
|
||||
['acc2:usr2', 'acc4:usr4']))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -55,6 +55,51 @@ class TestContainerController(unittest.TestCase):
|
||||
""" Tear down for testing swift.object_server.ObjectController """
|
||||
rmtree(self.testdir, ignore_errors=1)
|
||||
|
||||
def test_acl_container(self):
|
||||
# Ensure no acl by default
|
||||
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'X-Timestamp': '0'})
|
||||
self.controller.PUT(req)
|
||||
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'HEAD'})
|
||||
response = self.controller.HEAD(req)
|
||||
self.assert_(response.status.startswith('204'))
|
||||
self.assert_('x-container-read' not in response.headers)
|
||||
self.assert_('x-container-write' not in response.headers)
|
||||
# Ensure POSTing acls works
|
||||
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'},
|
||||
headers={'X-Timestamp': '1', 'X-Container-Read': '.ref:any',
|
||||
'X-Container-Write': 'account:user'})
|
||||
self.controller.POST(req)
|
||||
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'HEAD'})
|
||||
response = self.controller.HEAD(req)
|
||||
self.assert_(response.status.startswith('204'))
|
||||
self.assertEquals(response.headers.get('x-container-read'),
|
||||
'.ref:any')
|
||||
self.assertEquals(response.headers.get('x-container-write'),
|
||||
'account:user')
|
||||
# Ensure we can clear acls on POST
|
||||
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'},
|
||||
headers={'X-Timestamp': '3', 'X-Container-Read': '',
|
||||
'X-Container-Write': ''})
|
||||
self.controller.POST(req)
|
||||
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'HEAD'})
|
||||
response = self.controller.HEAD(req)
|
||||
self.assert_(response.status.startswith('204'))
|
||||
self.assert_('x-container-read' not in response.headers)
|
||||
self.assert_('x-container-write' not in response.headers)
|
||||
# Ensure PUTing acls works
|
||||
req = Request.blank('/sda1/p/a/c2', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'X-Timestamp': '4', 'X-Container-Read': '.ref:any',
|
||||
'X-Container-Write': 'account:user'})
|
||||
self.controller.PUT(req)
|
||||
req = Request.blank('/sda1/p/a/c2', environ={'REQUEST_METHOD': 'HEAD'})
|
||||
response = self.controller.HEAD(req)
|
||||
self.assert_(response.status.startswith('204'))
|
||||
self.assertEquals(response.headers.get('x-container-read'),
|
||||
'.ref:any')
|
||||
self.assertEquals(response.headers.get('x-container-write'),
|
||||
'account:user')
|
||||
|
||||
def test_HEAD(self):
|
||||
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT',
|
||||
'HTTP_X_TIMESTAMP': '0'})
|
||||
|
@ -19,6 +19,7 @@ import cPickle as pickle
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
from nose import SkipTest
|
||||
from shutil import rmtree
|
||||
from StringIO import StringIO
|
||||
from time import gmtime, sleep, strftime, time
|
||||
@ -64,7 +65,7 @@ class TestObjectController(unittest.TestCase):
|
||||
def test_POST_update_meta(self):
|
||||
""" Test swift.object_server.ObjectController.POST """
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
timestamp = normalize_timestamp(time())
|
||||
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'X-Timestamp': timestamp,
|
||||
@ -92,7 +93,7 @@ class TestObjectController(unittest.TestCase):
|
||||
|
||||
def test_POST_not_exist(self):
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
timestamp = normalize_timestamp(time())
|
||||
req = Request.blank('/sda1/p/a/c/fail', environ={'REQUEST_METHOD': 'POST'},
|
||||
headers={'X-Timestamp': timestamp,
|
||||
@ -114,7 +115,7 @@ class TestObjectController(unittest.TestCase):
|
||||
|
||||
def test_POST_container_connection(self):
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
def mock_http_connect(response, with_exc=False):
|
||||
class FakeConn(object):
|
||||
def __init__(self, status, with_exc):
|
||||
@ -210,7 +211,7 @@ class TestObjectController(unittest.TestCase):
|
||||
|
||||
def test_PUT_common(self):
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
timestamp = normalize_timestamp(time())
|
||||
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'X-Timestamp': timestamp,
|
||||
@ -234,7 +235,7 @@ class TestObjectController(unittest.TestCase):
|
||||
|
||||
def test_PUT_overwrite(self):
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'X-Timestamp': normalize_timestamp(time()),
|
||||
'Content-Length': '6',
|
||||
@ -267,7 +268,7 @@ class TestObjectController(unittest.TestCase):
|
||||
|
||||
def test_PUT_no_etag(self):
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'X-Timestamp': normalize_timestamp(time()),
|
||||
'Content-Type': 'text/plain'})
|
||||
@ -286,7 +287,7 @@ class TestObjectController(unittest.TestCase):
|
||||
|
||||
def test_PUT_user_metadata(self):
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
timestamp = normalize_timestamp(time())
|
||||
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'X-Timestamp': timestamp,
|
||||
@ -314,7 +315,7 @@ class TestObjectController(unittest.TestCase):
|
||||
|
||||
def test_PUT_container_connection(self):
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
def mock_http_connect(response, with_exc=False):
|
||||
class FakeConn(object):
|
||||
def __init__(self, status, with_exc):
|
||||
@ -376,7 +377,7 @@ class TestObjectController(unittest.TestCase):
|
||||
def test_HEAD(self):
|
||||
""" Test swift.object_server.ObjectController.HEAD """
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
req = Request.blank('/sda1/p/a/c')
|
||||
resp = self.object_controller.HEAD(req)
|
||||
self.assertEquals(resp.status_int, 400)
|
||||
@ -443,7 +444,7 @@ class TestObjectController(unittest.TestCase):
|
||||
def test_GET(self):
|
||||
""" Test swift.object_server.ObjectController.GET """
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
req = Request.blank('/sda1/p/a/c')
|
||||
resp = self.object_controller.GET(req)
|
||||
self.assertEquals(resp.status_int, 400)
|
||||
@ -532,7 +533,7 @@ class TestObjectController(unittest.TestCase):
|
||||
|
||||
def test_GET_if_match(self):
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={
|
||||
'X-Timestamp': normalize_timestamp(time()),
|
||||
@ -586,7 +587,7 @@ class TestObjectController(unittest.TestCase):
|
||||
|
||||
def test_GET_if_none_match(self):
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={
|
||||
'X-Timestamp': normalize_timestamp(time()),
|
||||
@ -637,7 +638,7 @@ class TestObjectController(unittest.TestCase):
|
||||
|
||||
def test_GET_if_modified_since(self):
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
timestamp = normalize_timestamp(time())
|
||||
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={
|
||||
@ -674,7 +675,7 @@ class TestObjectController(unittest.TestCase):
|
||||
|
||||
def test_GET_if_unmodified_since(self):
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
timestamp = normalize_timestamp(time())
|
||||
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={
|
||||
@ -713,7 +714,7 @@ class TestObjectController(unittest.TestCase):
|
||||
def test_DELETE(self):
|
||||
""" Test swift.object_server.ObjectController.DELETE """
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'DELETE'})
|
||||
resp = self.object_controller.DELETE(req)
|
||||
self.assertEquals(resp.status_int, 400)
|
||||
@ -840,7 +841,7 @@ class TestObjectController(unittest.TestCase):
|
||||
|
||||
def test_chunked_put(self):
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
listener = listen(('localhost', 0))
|
||||
port = listener.getsockname()[1]
|
||||
killer = spawn(wsgi.server, listener, self.object_controller,
|
||||
@ -866,7 +867,7 @@ class TestObjectController(unittest.TestCase):
|
||||
|
||||
def test_max_object_name_length(self):
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
timestamp = normalize_timestamp(time())
|
||||
req = Request.blank('/sda1/p/a/c/' + ('1' * 1024),
|
||||
environ={'REQUEST_METHOD': 'PUT'},
|
||||
@ -887,7 +888,7 @@ class TestObjectController(unittest.TestCase):
|
||||
|
||||
def test_disk_file_app_iter_corners(self):
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
df = object_server.DiskFile(self.testdir, 'sda1', '0', 'a', 'c', 'o')
|
||||
mkdirs(df.datadir)
|
||||
f = open(os.path.join(df.datadir,
|
||||
@ -920,7 +921,7 @@ class TestObjectController(unittest.TestCase):
|
||||
|
||||
def test_max_upload_time(self):
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
class SlowBody():
|
||||
def __init__(self):
|
||||
self.sent = 0
|
||||
@ -962,7 +963,7 @@ class TestObjectController(unittest.TestCase):
|
||||
|
||||
def test_bad_sinces(self):
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'X-Timestamp': normalize_timestamp(time()),
|
||||
'Content-Length': '4', 'Content-Type': 'text/plain'},
|
||||
@ -988,7 +989,7 @@ class TestObjectController(unittest.TestCase):
|
||||
|
||||
def test_content_encoding(self):
|
||||
if not self.path_to_test_xfs:
|
||||
return
|
||||
raise SkipTest
|
||||
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'X-Timestamp': normalize_timestamp(time()),
|
||||
'Content-Length': '4', 'Content-Type': 'text/plain',
|
||||
|
@ -19,6 +19,7 @@ import logging
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
from nose import SkipTest
|
||||
from ConfigParser import ConfigParser
|
||||
from contextlib import contextmanager
|
||||
from cStringIO import StringIO
|
||||
@ -203,7 +204,7 @@ class TestProxyServer(unittest.TestCase):
|
||||
app = MyApp(None, FakeMemcache(), account_ring=FakeRing(),
|
||||
container_ring=FakeRing(), object_ring=FakeRing())
|
||||
req = Request.blank('/account', environ={'REQUEST_METHOD': 'HEAD'})
|
||||
req.account = 'account'
|
||||
app.update_request(req)
|
||||
resp = app.handle_request(req)
|
||||
self.assertEquals(resp.status_int, 500)
|
||||
|
||||
@ -224,14 +225,14 @@ class TestObjectController(unittest.TestCase):
|
||||
self.app.memcache.store = {}
|
||||
req = Request.blank('/a/c/o', headers={'Content-Length': '0',
|
||||
'Content-Type': 'text/plain'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = method(req)
|
||||
self.assertEquals(res.status_int, expected)
|
||||
proxy_server.http_connect = fake_http_connect(*statuses, **kwargs)
|
||||
self.app.memcache.store = {}
|
||||
req = Request.blank('/a/c/o', headers={'Content-Length': '0',
|
||||
'Content-Type': 'text/plain'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = method(req)
|
||||
self.assertEquals(res.status_int, expected)
|
||||
|
||||
@ -244,7 +245,7 @@ class TestObjectController(unittest.TestCase):
|
||||
give_content_type=lambda content_type:
|
||||
self.assertEquals(content_type, expected.next()))
|
||||
req = Request.blank('/a/c/%s' % filename, {})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.PUT(req)
|
||||
test_content_type('test.jpg',
|
||||
iter(['', '', '', 'image/jpeg', 'image/jpeg', 'image/jpeg']))
|
||||
@ -261,7 +262,7 @@ class TestObjectController(unittest.TestCase):
|
||||
proxy_server.http_connect = fake_http_connect(*statuses)
|
||||
req = Request.blank('/a/c/o.jpg', {})
|
||||
req.content_length = 0
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
self.app.memcache.store = {}
|
||||
res = controller.PUT(req)
|
||||
expected = str(expected)
|
||||
@ -296,7 +297,7 @@ class TestObjectController(unittest.TestCase):
|
||||
self.app.memcache.store = {}
|
||||
req = Request.blank('/a/c/o.jpg', {})
|
||||
req.content_length = 0
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.PUT(req)
|
||||
expected = str(expected)
|
||||
self.assertEquals(res.status[:len(expected)], expected)
|
||||
@ -330,7 +331,7 @@ class TestObjectController(unittest.TestCase):
|
||||
self.app.memcache.store = {}
|
||||
proxy_server.http_connect = mock_http_connect(*statuses)
|
||||
req = Request.blank('/a/c/o.jpg', {})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
req.body_file = StringIO('some data')
|
||||
res = controller.PUT(req)
|
||||
expected = str(expected)
|
||||
@ -347,7 +348,7 @@ class TestObjectController(unittest.TestCase):
|
||||
req = Request.blank('/a/c/o', {}, headers={
|
||||
'Content-Length': str(MAX_FILE_SIZE + 1),
|
||||
'Content-Type': 'foo/bar'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.PUT(req)
|
||||
self.assertEquals(res.status_int, 413)
|
||||
|
||||
@ -379,7 +380,7 @@ class TestObjectController(unittest.TestCase):
|
||||
proxy_server.http_connect = mock_http_connect(*statuses)
|
||||
req = Request.blank('/a/c/o.jpg', {})
|
||||
req.content_length = 0
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.PUT(req)
|
||||
expected = str(expected)
|
||||
self.assertEquals(res.status[:len(str(expected))],
|
||||
@ -397,7 +398,7 @@ class TestObjectController(unittest.TestCase):
|
||||
self.app.memcache.store = {}
|
||||
req = Request.blank('/a/c/o', {}, headers={
|
||||
'Content-Type': 'foo/bar'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.POST(req)
|
||||
expected = str(expected)
|
||||
self.assertEquals(res.status[:len(expected)], expected)
|
||||
@ -417,7 +418,7 @@ class TestObjectController(unittest.TestCase):
|
||||
proxy_server.http_connect = fake_http_connect(*statuses)
|
||||
self.app.memcache.store = {}
|
||||
req = Request.blank('/a/c/o', {})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.DELETE(req)
|
||||
self.assertEquals(res.status[:len(str(expected))],
|
||||
str(expected))
|
||||
@ -436,7 +437,7 @@ class TestObjectController(unittest.TestCase):
|
||||
proxy_server.http_connect = fake_http_connect(*statuses)
|
||||
self.app.memcache.store = {}
|
||||
req = Request.blank('/a/c/o', {})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.HEAD(req)
|
||||
self.assertEquals(res.status[:len(str(expected))],
|
||||
str(expected))
|
||||
@ -460,14 +461,14 @@ class TestObjectController(unittest.TestCase):
|
||||
req = Request.blank('/a/c/o', {}, headers={
|
||||
'Content-Type': 'foo/bar',
|
||||
'X-Object-Meta-Foo': 'x'*256})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.POST(req)
|
||||
self.assertEquals(res.status_int, 202)
|
||||
proxy_server.http_connect = fake_http_connect(202, 202, 202)
|
||||
req = Request.blank('/a/c/o', {}, headers={
|
||||
'Content-Type': 'foo/bar',
|
||||
'X-Object-Meta-Foo': 'x'*257})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.POST(req)
|
||||
self.assertEquals(res.status_int, 400)
|
||||
|
||||
@ -481,14 +482,14 @@ class TestObjectController(unittest.TestCase):
|
||||
req = Request.blank('/a/c/o', {}, headers={
|
||||
'Content-Type': 'foo/bar',
|
||||
('X-Object-Meta-'+'x'*128): 'x'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.POST(req)
|
||||
self.assertEquals(res.status_int, 202)
|
||||
proxy_server.http_connect = fake_http_connect(202, 202, 202)
|
||||
req = Request.blank('/a/c/o', {}, headers={
|
||||
'Content-Type': 'foo/bar',
|
||||
('X-Object-Meta-'+'x'*129): 'x'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.POST(req)
|
||||
self.assertEquals(res.status_int, 400)
|
||||
|
||||
@ -500,7 +501,7 @@ class TestObjectController(unittest.TestCase):
|
||||
headers.update({'Content-Type': 'foo/bar'})
|
||||
proxy_server.http_connect = fake_http_connect(202, 202, 202)
|
||||
req = Request.blank('/a/c/o', {}, headers=headers)
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.POST(req)
|
||||
self.assertEquals(res.status_int, 400)
|
||||
|
||||
@ -512,7 +513,7 @@ class TestObjectController(unittest.TestCase):
|
||||
headers.update({'Content-Type': 'foo/bar'})
|
||||
proxy_server.http_connect = fake_http_connect(202, 202, 202)
|
||||
req = Request.blank('/a/c/o', {}, headers=headers)
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.POST(req)
|
||||
self.assertEquals(res.status_int, 400)
|
||||
|
||||
@ -542,7 +543,7 @@ class TestObjectController(unittest.TestCase):
|
||||
req = Request.blank('/a/c/o',
|
||||
environ={'REQUEST_METHOD': 'PUT', 'wsgi.input': SlowBody()},
|
||||
headers={'Content-Length': '4', 'Content-Type': 'text/plain'})
|
||||
req.account = 'account'
|
||||
self.app.update_request(req)
|
||||
controller = proxy_server.ObjectController(self.app, 'account',
|
||||
'container', 'object')
|
||||
proxy_server.http_connect = \
|
||||
@ -554,7 +555,7 @@ class TestObjectController(unittest.TestCase):
|
||||
req = Request.blank('/a/c/o',
|
||||
environ={'REQUEST_METHOD': 'PUT', 'wsgi.input': SlowBody()},
|
||||
headers={'Content-Length': '4', 'Content-Type': 'text/plain'})
|
||||
req.account = 'account'
|
||||
self.app.update_request(req)
|
||||
proxy_server.http_connect = \
|
||||
fake_http_connect(201, 201, 201)
|
||||
# obj obj obj
|
||||
@ -583,7 +584,7 @@ class TestObjectController(unittest.TestCase):
|
||||
req = Request.blank('/a/c/o',
|
||||
environ={'REQUEST_METHOD': 'PUT', 'wsgi.input': SlowBody()},
|
||||
headers={'Content-Length': '4', 'Content-Type': 'text/plain'})
|
||||
req.account = 'account'
|
||||
self.app.update_request(req)
|
||||
controller = proxy_server.ObjectController(self.app, 'account',
|
||||
'container', 'object')
|
||||
proxy_server.http_connect = \
|
||||
@ -607,7 +608,7 @@ class TestObjectController(unittest.TestCase):
|
||||
dev['ip'] = '127.0.0.1'
|
||||
dev['port'] = 1
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'GET'})
|
||||
req.account = 'account'
|
||||
self.app.update_request(req)
|
||||
controller = proxy_server.ObjectController(self.app, 'account',
|
||||
'container', 'object')
|
||||
proxy_server.http_connect = \
|
||||
@ -649,7 +650,7 @@ class TestObjectController(unittest.TestCase):
|
||||
environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'Content-Length': '4', 'Content-Type': 'text/plain'},
|
||||
body=' ')
|
||||
req.account = 'account'
|
||||
self.app.update_request(req)
|
||||
controller = proxy_server.ObjectController(self.app, 'account',
|
||||
'container', 'object')
|
||||
proxy_server.http_connect = \
|
||||
@ -663,7 +664,7 @@ class TestObjectController(unittest.TestCase):
|
||||
environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'Content-Length': '4', 'Content-Type': 'text/plain'},
|
||||
body=' ')
|
||||
req.account = 'account'
|
||||
self.app.update_request(req)
|
||||
resp = controller.PUT(req)
|
||||
self.assertEquals(resp.status_int, 503)
|
||||
|
||||
@ -708,7 +709,7 @@ class TestObjectController(unittest.TestCase):
|
||||
def test_proxy_passes_content_type(self):
|
||||
with save_globals():
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'GET'})
|
||||
req.account = 'account'
|
||||
self.app.update_request(req)
|
||||
controller = proxy_server.ObjectController(self.app, 'account',
|
||||
'container', 'object')
|
||||
proxy_server.http_connect = fake_http_connect(200, 200, 200)
|
||||
@ -728,7 +729,7 @@ class TestObjectController(unittest.TestCase):
|
||||
def test_proxy_passes_content_length_on_head(self):
|
||||
with save_globals():
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'HEAD'})
|
||||
req.account = 'account'
|
||||
self.app.update_request(req)
|
||||
controller = proxy_server.ObjectController(self.app, 'account',
|
||||
'container', 'object')
|
||||
proxy_server.http_connect = fake_http_connect(200, 200, 200)
|
||||
@ -777,7 +778,7 @@ class TestObjectController(unittest.TestCase):
|
||||
proxy_server.http_connect = \
|
||||
fake_http_connect(200, 200, 200, 200, 200, 200)
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'DELETE'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = getattr(controller, 'DELETE')(req)
|
||||
self.assertEquals(resp.status_int, 200)
|
||||
|
||||
@ -853,7 +854,7 @@ class TestObjectController(unittest.TestCase):
|
||||
proxy_server.http_connect = \
|
||||
fake_http_connect(404, 404, 404, 200, 200, 200)
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.PUT(req)
|
||||
self.assertEquals(resp.status_int, 404)
|
||||
|
||||
@ -861,7 +862,7 @@ class TestObjectController(unittest.TestCase):
|
||||
fake_http_connect(404, 404, 404, 200, 200, 200)
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'POST'},
|
||||
headers={'Content-Type': 'text/plain'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.POST(req)
|
||||
self.assertEquals(resp.status_int, 404)
|
||||
|
||||
@ -874,7 +875,7 @@ class TestObjectController(unittest.TestCase):
|
||||
# acct cont obj obj obj
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'Content-Length': '0'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.PUT(req)
|
||||
self.assertEquals(resp.status_int, 201)
|
||||
|
||||
@ -883,7 +884,7 @@ class TestObjectController(unittest.TestCase):
|
||||
headers={'Content-Length': '0',
|
||||
'X-Object-Meta-' + ('a' *
|
||||
MAX_META_NAME_LENGTH) : 'v'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.PUT(req)
|
||||
self.assertEquals(resp.status_int, 201)
|
||||
proxy_server.http_connect = fake_http_connect(201, 201, 201)
|
||||
@ -891,7 +892,7 @@ class TestObjectController(unittest.TestCase):
|
||||
headers={'Content-Length': '0',
|
||||
'X-Object-Meta-' + ('a' *
|
||||
(MAX_META_NAME_LENGTH + 1)) : 'v'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.PUT(req)
|
||||
self.assertEquals(resp.status_int, 400)
|
||||
|
||||
@ -900,7 +901,7 @@ class TestObjectController(unittest.TestCase):
|
||||
headers={'Content-Length': '0',
|
||||
'X-Object-Meta-Too-Long': 'a' *
|
||||
MAX_META_VALUE_LENGTH})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.PUT(req)
|
||||
self.assertEquals(resp.status_int, 201)
|
||||
proxy_server.http_connect = fake_http_connect(201, 201, 201)
|
||||
@ -908,7 +909,7 @@ class TestObjectController(unittest.TestCase):
|
||||
headers={'Content-Length': '0',
|
||||
'X-Object-Meta-Too-Long': 'a' *
|
||||
(MAX_META_VALUE_LENGTH + 1)})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.PUT(req)
|
||||
self.assertEquals(resp.status_int, 400)
|
||||
|
||||
@ -918,7 +919,7 @@ class TestObjectController(unittest.TestCase):
|
||||
headers['X-Object-Meta-%d' % x] = 'v'
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers=headers)
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.PUT(req)
|
||||
self.assertEquals(resp.status_int, 201)
|
||||
proxy_server.http_connect = fake_http_connect(201, 201, 201)
|
||||
@ -927,7 +928,7 @@ class TestObjectController(unittest.TestCase):
|
||||
headers['X-Object-Meta-%d' % x] = 'v'
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers=headers)
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.PUT(req)
|
||||
self.assertEquals(resp.status_int, 400)
|
||||
|
||||
@ -946,7 +947,7 @@ class TestObjectController(unittest.TestCase):
|
||||
'a' * (MAX_META_OVERALL_SIZE - size - 1)
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers=headers)
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.PUT(req)
|
||||
self.assertEquals(resp.status_int, 201)
|
||||
proxy_server.http_connect = fake_http_connect(201, 201, 201)
|
||||
@ -954,7 +955,7 @@ class TestObjectController(unittest.TestCase):
|
||||
'a' * (MAX_META_OVERALL_SIZE - size)
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers=headers)
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.PUT(req)
|
||||
self.assertEquals(resp.status_int, 400)
|
||||
|
||||
@ -964,7 +965,7 @@ class TestObjectController(unittest.TestCase):
|
||||
'container', 'object')
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'Content-Length': '0'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
proxy_server.http_connect = \
|
||||
fake_http_connect(200, 200, 201, 201, 201)
|
||||
# acct cont obj obj obj
|
||||
@ -974,7 +975,7 @@ class TestObjectController(unittest.TestCase):
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'Content-Length': '0',
|
||||
'X-Copy-From': 'c/o'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
proxy_server.http_connect = \
|
||||
fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201)
|
||||
# acct cont acct cont objc obj obj obj
|
||||
@ -986,7 +987,7 @@ class TestObjectController(unittest.TestCase):
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'Content-Length': '0',
|
||||
'X-Copy-From': '/c/o'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
proxy_server.http_connect = \
|
||||
fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201)
|
||||
# acct cont acct cont objc obj obj obj
|
||||
@ -998,7 +999,7 @@ class TestObjectController(unittest.TestCase):
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'Content-Length': '0',
|
||||
'X-Copy-From': '/c/o'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
proxy_server.http_connect = \
|
||||
fake_http_connect(200, 200, 503, 503, 503)
|
||||
# acct cont objc objc objc
|
||||
@ -1009,7 +1010,7 @@ class TestObjectController(unittest.TestCase):
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'Content-Length': '0',
|
||||
'X-Copy-From': '/c/o'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
proxy_server.http_connect = \
|
||||
fake_http_connect(200, 200, 404, 404, 404)
|
||||
# acct cont objc objc objc
|
||||
@ -1020,7 +1021,7 @@ class TestObjectController(unittest.TestCase):
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'Content-Length': '0',
|
||||
'X-Copy-From': '/c/o'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
proxy_server.http_connect = \
|
||||
fake_http_connect(200, 200, 404, 404, 200, 201, 201, 201)
|
||||
# acct cont objc objc objc obj obj obj
|
||||
@ -1032,7 +1033,7 @@ class TestObjectController(unittest.TestCase):
|
||||
headers={'Content-Length': '0',
|
||||
'X-Copy-From': '/c/o',
|
||||
'X-Object-Meta-Ours': 'okay'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
proxy_server.http_connect = \
|
||||
fake_http_connect(200, 200, 200, 201, 201, 201)
|
||||
# acct cont objc obj obj obj
|
||||
@ -1052,7 +1053,7 @@ class TestObjectController(unittest.TestCase):
|
||||
'pointing to a valid directory.\n' \
|
||||
'Please set PATH_TO_TEST_XFS to a directory on an XFS file ' \
|
||||
'system for testing.'
|
||||
return
|
||||
raise SkipTest
|
||||
testdir = \
|
||||
os.path.join(path_to_test_xfs, 'tmp_test_proxy_server_chunked')
|
||||
mkdirs(testdir)
|
||||
@ -1434,7 +1435,7 @@ class TestObjectController(unittest.TestCase):
|
||||
'container', 'object')
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'Content-Length': '0'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
proxy_server.http_connect = fake_http_connect(200, 201, 201, 201,
|
||||
etags=[None,
|
||||
'68b329da9893e34099c7d8ad5cb9c940',
|
||||
@ -1452,7 +1453,7 @@ class TestObjectController(unittest.TestCase):
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'Content-Length': '10'},
|
||||
body='1234567890')
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.PUT(req)
|
||||
self.assert_(hasattr(req, 'bytes_transferred'))
|
||||
self.assertEquals(req.bytes_transferred, 10)
|
||||
@ -1464,7 +1465,7 @@ class TestObjectController(unittest.TestCase):
|
||||
controller = proxy_server.ObjectController(self.app, 'account',
|
||||
'container', 'object')
|
||||
req = Request.blank('/a/c/o')
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.GET(req)
|
||||
res.body
|
||||
self.assert_(hasattr(res, 'bytes_transferred'))
|
||||
@ -1479,7 +1480,7 @@ class TestObjectController(unittest.TestCase):
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'Content-Length': '10'},
|
||||
body='12345')
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.PUT(req)
|
||||
self.assertEquals(req.bytes_transferred, 5)
|
||||
self.assert_(hasattr(req, 'client_disconnect'))
|
||||
@ -1492,7 +1493,7 @@ class TestObjectController(unittest.TestCase):
|
||||
controller = proxy_server.ObjectController(self.app, 'account',
|
||||
'container', 'object')
|
||||
req = Request.blank('/a/c/o')
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
orig_object_chunk_size = self.app.object_chunk_size
|
||||
try:
|
||||
self.app.object_chunk_size = 5
|
||||
@ -1528,14 +1529,14 @@ class TestContainerController(unittest.TestCase):
|
||||
self.app.memcache.store = {}
|
||||
req = Request.blank('/a/c', headers={'Content-Length': '0',
|
||||
'Content-Type': 'text/plain'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = method(req)
|
||||
self.assertEquals(res.status_int, expected)
|
||||
proxy_server.http_connect = fake_http_connect(*statuses, **kwargs)
|
||||
self.app.memcache.store = {}
|
||||
req = Request.blank('/a/c/', headers={'Content-Length': '0',
|
||||
'Content-Type': 'text/plain'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = method(req)
|
||||
self.assertEquals(res.status_int, expected)
|
||||
|
||||
@ -1547,7 +1548,7 @@ class TestContainerController(unittest.TestCase):
|
||||
proxy_server.http_connect = fake_http_connect(*statuses, **kwargs)
|
||||
self.app.memcache.store = {}
|
||||
req = Request.blank('/a/c', {})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.HEAD(req)
|
||||
self.assertEquals(res.status[:len(str(expected))],
|
||||
str(expected))
|
||||
@ -1570,7 +1571,7 @@ class TestContainerController(unittest.TestCase):
|
||||
self.app.memcache.store = {}
|
||||
req = Request.blank('/a/c', {})
|
||||
req.content_length = 0
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.PUT(req)
|
||||
expected = str(expected)
|
||||
self.assertEquals(res.status[:len(expected)], expected)
|
||||
@ -1613,7 +1614,7 @@ class TestContainerController(unittest.TestCase):
|
||||
fake_http_connect(200, 200, 200, 200)
|
||||
self.app.memcache.store = {}
|
||||
req = Request.blank('/a/c', environ={'REQUEST_METHOD': meth})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = getattr(controller, meth)(req)
|
||||
self.assertEquals(resp.status_int, 200)
|
||||
|
||||
@ -1657,7 +1658,7 @@ class TestContainerController(unittest.TestCase):
|
||||
self.app.memcache = MockMemcache(allow_lock=True)
|
||||
proxy_server.http_connect = fake_http_connect(200, 200, 200, 201, 201, 201, missing_container=True)
|
||||
req = Request.blank('/a/c', environ={'REQUEST_METHOD': 'PUT'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.PUT(req)
|
||||
self.assertEquals(res.status_int, 201)
|
||||
|
||||
@ -1703,7 +1704,7 @@ class TestContainerController(unittest.TestCase):
|
||||
controller = proxy_server.ContainerController(self.app, 'account',
|
||||
'container')
|
||||
req = Request.blank('/a/c?format=json')
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.GET(req)
|
||||
res.body
|
||||
self.assert_(hasattr(res, 'bytes_transferred'))
|
||||
@ -1715,7 +1716,7 @@ class TestContainerController(unittest.TestCase):
|
||||
controller = proxy_server.ContainerController(self.app, 'account',
|
||||
'container')
|
||||
req = Request.blank('/a/c?format=json')
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
orig_object_chunk_size = self.app.object_chunk_size
|
||||
try:
|
||||
self.app.object_chunk_size = 1
|
||||
@ -1760,8 +1761,7 @@ class TestContainerController(unittest.TestCase):
|
||||
201, give_connect=test_connect)
|
||||
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method},
|
||||
headers={test_header: test_value})
|
||||
req.account = 'a'
|
||||
req.container = 'c'
|
||||
self.app.update_request(req)
|
||||
res = getattr(controller, method)(req)
|
||||
self.assertEquals(test_errors, [])
|
||||
|
||||
@ -1776,7 +1776,7 @@ class TestContainerController(unittest.TestCase):
|
||||
controller = proxy_server.ContainerController(self.app, 'a', 'c')
|
||||
proxy_server.http_connect = fake_http_connect(200, 201, 201, 201)
|
||||
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = getattr(controller, method)(req)
|
||||
self.assertEquals(resp.status_int, 201)
|
||||
|
||||
@ -1784,16 +1784,14 @@ class TestContainerController(unittest.TestCase):
|
||||
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method},
|
||||
headers={'X-Container-Meta-' +
|
||||
('a' * MAX_META_NAME_LENGTH): 'v'})
|
||||
req.account = 'a'
|
||||
req.container = 'c'
|
||||
self.app.update_request(req)
|
||||
resp = getattr(controller, method)(req)
|
||||
self.assertEquals(resp.status_int, 201)
|
||||
proxy_server.http_connect = fake_http_connect(201, 201, 201)
|
||||
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method},
|
||||
headers={'X-Container-Meta-' +
|
||||
('a' * (MAX_META_NAME_LENGTH + 1)): 'v'})
|
||||
req.account = 'a'
|
||||
req.container = 'c'
|
||||
self.app.update_request(req)
|
||||
resp = getattr(controller, method)(req)
|
||||
self.assertEquals(resp.status_int, 400)
|
||||
|
||||
@ -1801,16 +1799,14 @@ class TestContainerController(unittest.TestCase):
|
||||
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method},
|
||||
headers={'X-Container-Meta-Too-Long':
|
||||
'a' * MAX_META_VALUE_LENGTH})
|
||||
req.account = 'a'
|
||||
req.container = 'c'
|
||||
self.app.update_request(req)
|
||||
resp = getattr(controller, method)(req)
|
||||
self.assertEquals(resp.status_int, 201)
|
||||
proxy_server.http_connect = fake_http_connect(201, 201, 201)
|
||||
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method},
|
||||
headers={'X-Container-Meta-Too-Long':
|
||||
'a' * (MAX_META_VALUE_LENGTH + 1)})
|
||||
req.account = 'a'
|
||||
req.container = 'c'
|
||||
self.app.update_request(req)
|
||||
resp = getattr(controller, method)(req)
|
||||
self.assertEquals(resp.status_int, 400)
|
||||
|
||||
@ -1820,8 +1816,7 @@ class TestContainerController(unittest.TestCase):
|
||||
headers['X-Container-Meta-%d' % x] = 'v'
|
||||
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method},
|
||||
headers=headers)
|
||||
req.account = 'a'
|
||||
req.container = 'c'
|
||||
self.app.update_request(req)
|
||||
resp = getattr(controller, method)(req)
|
||||
self.assertEquals(resp.status_int, 201)
|
||||
proxy_server.http_connect = fake_http_connect(201, 201, 201)
|
||||
@ -1830,8 +1825,7 @@ class TestContainerController(unittest.TestCase):
|
||||
headers['X-Container-Meta-%d' % x] = 'v'
|
||||
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method},
|
||||
headers=headers)
|
||||
req.account = 'a'
|
||||
req.container = 'c'
|
||||
self.app.update_request(req)
|
||||
resp = getattr(controller, method)(req)
|
||||
self.assertEquals(resp.status_int, 400)
|
||||
|
||||
@ -1849,8 +1843,7 @@ class TestContainerController(unittest.TestCase):
|
||||
'a' * (MAX_META_OVERALL_SIZE - size - 1)
|
||||
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method},
|
||||
headers=headers)
|
||||
req.account = 'a'
|
||||
req.container = 'c'
|
||||
self.app.update_request(req)
|
||||
resp = getattr(controller, method)(req)
|
||||
self.assertEquals(resp.status_int, 201)
|
||||
proxy_server.http_connect = fake_http_connect(201, 201, 201)
|
||||
@ -1858,8 +1851,7 @@ class TestContainerController(unittest.TestCase):
|
||||
'a' * (MAX_META_OVERALL_SIZE - size)
|
||||
req = Request.blank('/a/c', environ={'REQUEST_METHOD': method},
|
||||
headers=headers)
|
||||
req.account = 'a'
|
||||
req.container = 'c'
|
||||
self.app.update_request(req)
|
||||
resp = getattr(controller, method)(req)
|
||||
self.assertEquals(resp.status_int, 400)
|
||||
|
||||
@ -1875,12 +1867,12 @@ class TestAccountController(unittest.TestCase):
|
||||
with save_globals():
|
||||
proxy_server.http_connect = fake_http_connect(*statuses)
|
||||
req = Request.blank('/a', {})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = method(req)
|
||||
self.assertEquals(res.status_int, expected)
|
||||
proxy_server.http_connect = fake_http_connect(*statuses)
|
||||
req = Request.blank('/a/', {})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = method(req)
|
||||
self.assertEquals(res.status_int, expected)
|
||||
|
||||
@ -1930,7 +1922,7 @@ class TestAccountController(unittest.TestCase):
|
||||
dev['port'] = 1 ## can't connect on this port
|
||||
controller = proxy_server.AccountController(self.app, 'account')
|
||||
req = Request.blank('/account', environ={'REQUEST_METHOD': 'HEAD'})
|
||||
req.account = 'account'
|
||||
self.app.update_request(req)
|
||||
resp = controller.HEAD(req)
|
||||
self.assertEquals(resp.status_int, 503)
|
||||
|
||||
@ -1941,7 +1933,7 @@ class TestAccountController(unittest.TestCase):
|
||||
dev['port'] = -1 ## invalid port number
|
||||
controller = proxy_server.AccountController(self.app, 'account')
|
||||
req = Request.blank('/account', environ={'REQUEST_METHOD': 'HEAD'})
|
||||
req.account = 'account'
|
||||
self.app.update_request(req)
|
||||
resp = controller.HEAD(req)
|
||||
self.assertEquals(resp.status_int, 503)
|
||||
|
||||
@ -1950,7 +1942,7 @@ class TestAccountController(unittest.TestCase):
|
||||
proxy_server.http_connect = fake_http_connect(200, 200, body='{}')
|
||||
controller = proxy_server.AccountController(self.app, 'account')
|
||||
req = Request.blank('/a?format=json')
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.GET(req)
|
||||
res.body
|
||||
self.assert_(hasattr(res, 'bytes_transferred'))
|
||||
@ -1961,7 +1953,7 @@ class TestAccountController(unittest.TestCase):
|
||||
proxy_server.http_connect = fake_http_connect(200, 200, body='{}')
|
||||
controller = proxy_server.AccountController(self.app, 'account')
|
||||
req = Request.blank('/a?format=json')
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
orig_object_chunk_size = self.app.object_chunk_size
|
||||
try:
|
||||
self.app.object_chunk_size = 1
|
||||
@ -1999,7 +1991,7 @@ class TestAccountController(unittest.TestCase):
|
||||
give_connect=test_connect)
|
||||
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'},
|
||||
headers={test_header: test_value})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
res = controller.POST(req)
|
||||
self.assertEquals(test_errors, [])
|
||||
|
||||
@ -2008,7 +2000,7 @@ class TestAccountController(unittest.TestCase):
|
||||
controller = proxy_server.AccountController(self.app, 'a')
|
||||
proxy_server.http_connect = fake_http_connect(204, 204, 204)
|
||||
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.POST(req)
|
||||
self.assertEquals(resp.status_int, 204)
|
||||
|
||||
@ -2016,14 +2008,14 @@ class TestAccountController(unittest.TestCase):
|
||||
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'},
|
||||
headers={'X-Account-Meta-' +
|
||||
('a' * MAX_META_NAME_LENGTH): 'v'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.POST(req)
|
||||
self.assertEquals(resp.status_int, 204)
|
||||
proxy_server.http_connect = fake_http_connect(204, 204, 204)
|
||||
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'},
|
||||
headers={'X-Account-Meta-' +
|
||||
('a' * (MAX_META_NAME_LENGTH + 1)): 'v'})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.POST(req)
|
||||
self.assertEquals(resp.status_int, 400)
|
||||
|
||||
@ -2031,14 +2023,14 @@ class TestAccountController(unittest.TestCase):
|
||||
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'},
|
||||
headers={'X-Account-Meta-Too-Long':
|
||||
'a' * MAX_META_VALUE_LENGTH})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.POST(req)
|
||||
self.assertEquals(resp.status_int, 204)
|
||||
proxy_server.http_connect = fake_http_connect(204, 204, 204)
|
||||
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'},
|
||||
headers={'X-Account-Meta-Too-Long':
|
||||
'a' * (MAX_META_VALUE_LENGTH + 1)})
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.POST(req)
|
||||
self.assertEquals(resp.status_int, 400)
|
||||
|
||||
@ -2048,7 +2040,7 @@ class TestAccountController(unittest.TestCase):
|
||||
headers['X-Account-Meta-%d' % x] = 'v'
|
||||
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'},
|
||||
headers=headers)
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.POST(req)
|
||||
self.assertEquals(resp.status_int, 204)
|
||||
proxy_server.http_connect = fake_http_connect(204, 204, 204)
|
||||
@ -2057,7 +2049,7 @@ class TestAccountController(unittest.TestCase):
|
||||
headers['X-Account-Meta-%d' % x] = 'v'
|
||||
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'},
|
||||
headers=headers)
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.POST(req)
|
||||
self.assertEquals(resp.status_int, 400)
|
||||
|
||||
@ -2075,7 +2067,7 @@ class TestAccountController(unittest.TestCase):
|
||||
'a' * (MAX_META_OVERALL_SIZE - size - 1)
|
||||
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'},
|
||||
headers=headers)
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.POST(req)
|
||||
self.assertEquals(resp.status_int, 204)
|
||||
proxy_server.http_connect = fake_http_connect(204, 204, 204)
|
||||
@ -2083,7 +2075,7 @@ class TestAccountController(unittest.TestCase):
|
||||
'a' * (MAX_META_OVERALL_SIZE - size)
|
||||
req = Request.blank('/a', environ={'REQUEST_METHOD': 'POST'},
|
||||
headers=headers)
|
||||
req.account = 'a'
|
||||
self.app.update_request(req)
|
||||
resp = controller.POST(req)
|
||||
self.assertEquals(resp.status_int, 400)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user