Commit 30d093db authored by Sofia Papagiannaki's avatar Sofia Papagiannaki
Browse files

snf_django: Change error status code if request method is not valid

Return 405 (NotAllowed) instead of 400 (BadRequest)
Add Allow header in the response containing the list of valid methods
parent ff55e946
......@@ -268,7 +268,7 @@ def projects(request):
return get_projects(request)
elif method == "POST":
return create_project(request)
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request, allowed_methods=['GET', 'POST'])
@api.api_method(http_method="GET", token_required=True, user_required=False)
......@@ -316,7 +316,7 @@ def project(request, project_id):
return get_project(request, project_id)
if method == "POST":
return modify_project(request, project_id)
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request, allowed_methods=['GET', 'POST'])
@api.api_method(http_method="GET", token_required=True, user_required=False)
......@@ -485,7 +485,7 @@ def applications(request):
method = request.method
if method == "GET":
return get_applications(request)
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request, allowed_methods=['GET'])
def make_application_query(input_data):
......@@ -569,7 +569,7 @@ def memberships(request):
return get_memberships(request)
elif method == "POST":
return post_memberships(request)
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request, allowed_methods=['GET', 'POST'])
def make_membership_query(input_data):
......
......@@ -96,7 +96,7 @@ def commissions(request):
return get_pending_commissions(request)
elif method == 'POST':
return issue_commission(request)
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request, allowed_methods=['GET', 'POST'])
@api.api_method(http_method='GET', token_required=True, user_required=False)
......
......@@ -401,7 +401,8 @@ class QuotaAPITest(TestCase):
# Bad Request
r = client.head(u('commissions'))
self.assertEqual(r.status_code, 400)
self.assertEqual(r.status_code, 405)
self.assertTrue('Allow' in r)
class TokensApiTest(TestCase):
......@@ -451,7 +452,9 @@ class TokensApiTest(TestCase):
# Check not allowed method
r = client.get(url, post_data={})
self.assertEqual(r.status_code, 400)
self.assertEqual(r.status_code, 405)
self.assertTrue('Allow' in r)
self.assertEqual(r['Allow'], 'POST')
# check public mode
r = client.post(url, CONTENT_LENGTH=0)
......
......@@ -487,17 +487,21 @@ class ProjectAPITest(TestCase):
# Bad requests
r = client.head(reverse("api_projects"), **h_admin)
self.assertEqual(r.status_code, 400)
self.assertEqual(r.status_code, 405)
self.assertTrue('Allow' in r)
r = client.head(reverse("api_project",
kwargs={"project_id": 1}), **h_admin)
self.assertEqual(r.status_code, 400)
self.assertEqual(r.status_code, 405)
self.assertTrue('Allow' in r)
r = client.head(reverse("api_applications"), **h_admin)
self.assertEqual(r.status_code, 400)
self.assertEqual(r.status_code, 405)
self.assertTrue('Allow' in r)
r = client.head(reverse("api_memberships"), **h_admin)
self.assertEqual(r.status_code, 400)
self.assertEqual(r.status_code, 405)
self.assertTrue('Allow' in r)
status = self.project_action(1, "nonex", h_owner)
self.assertEqual(status, 400)
......
......@@ -52,14 +52,14 @@ def demux(request):
if request.method == 'GET':
return list_extensions(request)
else:
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request, allowed_methods=['GET'])
def demux_extension(request, extension_alias):
if request.method == 'GET':
return get_extension(request, extension_alias)
else:
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request, allowed_methods=['GET'])
@api.api_method(http_method='GET', user_required=True, logger=log)
......
......@@ -71,7 +71,8 @@ def demux(request):
elif request.method == 'POST':
return allocate_floating_ip(request)
else:
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request,
allowed_methods=['GET', 'POST'])
def floating_ip_demux(request, floating_ip_id):
......@@ -82,7 +83,8 @@ def floating_ip_demux(request, floating_ip_id):
elif request.method == 'PUT':
return update_floating_ip(request, floating_ip_id)
else:
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request,
allowed_methods=['GET', 'DELETE'])
def ip_to_dict(floating_ip):
......
......@@ -65,7 +65,8 @@ def demux(request):
elif request.method == 'POST':
return create_image(request)
else:
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request,
allowed_methods=['GET', 'POST'])
def image_demux(request, image_id):
......@@ -74,7 +75,8 @@ def image_demux(request, image_id):
elif request.method == 'DELETE':
return delete_image(request, image_id)
else:
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request,
allowed_methods=['GET', 'DELETE'])
def metadata_demux(request, image_id):
......@@ -83,7 +85,8 @@ def metadata_demux(request, image_id):
elif request.method == 'POST':
return update_metadata(request, image_id)
else:
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request,
allowed_methods=['GET', 'POST'])
def metadata_item_demux(request, image_id, key):
......@@ -94,7 +97,10 @@ def metadata_item_demux(request, image_id, key):
elif request.method == 'DELETE':
return delete_metadata_item(request, image_id, key)
else:
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request,
allowed_methods=['GET',
'PUT',
'DELETE'])
def image_to_dict(image, detail=True):
......
......@@ -62,7 +62,8 @@ def demux(request):
elif request.method == 'POST':
return create_network(request)
else:
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request,
allowed_methods=['GET', 'POST'])
def network_demux(request, network_id):
......@@ -74,7 +75,10 @@ def network_demux(request, network_id):
elif request.method == 'PUT':
return update_network(request, network_id)
else:
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request,
allowed_methods=['GET',
'PUT',
'DELETE'])
@api.api_method(http_method='GET', user_required=True, logger=log)
......
......@@ -70,7 +70,8 @@ def demux(request):
elif request.method == 'POST':
return create_server(request)
else:
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request,
allowed_methods=['GET', 'POST'])
def server_demux(request, server_id):
......@@ -81,7 +82,10 @@ def server_demux(request, server_id):
elif request.method == 'DELETE':
return delete_server(request, server_id)
else:
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request,
allowed_methods=['GET',
'PUT',
'DELETE'])
def metadata_demux(request, server_id):
......@@ -90,7 +94,8 @@ def metadata_demux(request, server_id):
elif request.method == 'POST':
return update_metadata(request, server_id)
else:
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request,
allowed_methods=['GET', 'POST'])
def metadata_item_demux(request, server_id, key):
......@@ -101,7 +106,10 @@ def metadata_item_demux(request, server_id, key):
elif request.method == 'DELETE':
return delete_metadata_item(request, server_id, key)
else:
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request,
allowed_methods=['GET',
'PUT',
'DELETE'])
def nic_to_attachments(nic):
......
......@@ -91,7 +91,8 @@ def api_method(http_method=None, token_required=True, user_required=True,
# Check HTTP method
if http_method and request.method != http_method:
raise faults.BadRequest("Method not allowed")
raise faults.NotAllowed("Method not allowed",
allowed_methods=[http_method])
# Get authentication token
request.x_auth_token = None
......@@ -246,6 +247,8 @@ def render_fault(request, fault):
data = json.dumps(d)
response = HttpResponse(data, status=fault.code)
if response.status_code == 405 and hasattr(fault, 'allowed_methods'):
response['Allow'] = ','.join(fault.allowed_methods)
update_response_headers(request, response)
return response
......@@ -256,8 +259,9 @@ def api_endpoint_not_found(request):
@api_method(token_required=False, user_required=False)
def api_method_not_allowed(request):
raise faults.BadRequest('Method not allowed')
def api_method_not_allowed(request, allowed_methods):
raise faults.NotAllowed("Method not allowed",
allowed_methods=allowed_methods)
def allow_jsonp(key='callback'):
......
......@@ -71,6 +71,18 @@ class ResizeNotAllowed(Forbidden):
pass
class NotAllowed(Fault):
code = 405
def __init__(self, message='', details='', name='', code=500,
allowed_methods=None):
"""
:param allowed_methods: (list) the valid methods
"""
super(NotAllowed, self).__init__(message, details, name, code)
self.allowed_methods = allowed_methods or []
class ItemNotFound(Fault):
code = 404
......
......@@ -268,12 +268,13 @@ class BaseAPITest(TestCase):
self.assertFault(response, 409, "conflict")
def assertMethodNotAllowed(self, response):
self.assertFault(response, 400, 'badRequest')
self.assertFault(response, 405, 'notAllowed')
self.assertTrue('Allow' in response)
try:
error = json.loads(response.content)
except ValueError:
self.assertTrue(False)
self.assertEqual(error['badRequest']['message'], 'Method not allowed')
self.assertEqual(error['notAllowed']['message'], 'Method not allowed')
# Imitate unittest assertions new in Python 2.7
......
......@@ -98,7 +98,7 @@ def top_demux(request):
return authenticate(request)
return account_list(request)
else:
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request, allowed_methods=['GET'])
@csrf_exempt
......@@ -117,7 +117,10 @@ def account_demux(request, v_account):
elif request.method == 'GET':
return container_list(request, v_account)
else:
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request,
allowed_methods=['HEAD',
'POST',
'GET'])
@csrf_exempt
......@@ -140,7 +143,12 @@ def container_demux(request, v_account, v_container):
elif request.method == 'GET':
return object_list(request, v_account, v_container)
else:
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request,
allowed_methods=['HEAD',
'PUT',
'POST',
'DELETE',
'GET'])
@csrf_exempt
......@@ -172,7 +180,13 @@ def object_demux(request, v_account, v_container, v_object):
elif request.method == 'DELETE':
return object_delete(request, v_account, v_container, v_object)
else:
return api.api_method_not_allowed(request)
return api.api_method_not_allowed(request, allowed_methods=['HEAD',
'GET',
'PUT',
'COPY',
'MOVE',
'POST',
'DELETE'])
@api_method('GET', token_required=False, user_required=False, logger=logger)
......
......@@ -42,13 +42,22 @@ class TopLevel(PithosAPITest):
def test_not_allowed_method(self):
url = join_urls(self.pithos_path, '/')
r = self.head(url)
self.assertEqual(r.status_code, 400)
self.assertEqual(r.status_code, 405)
self.assertTrue('Allow' in r)
self.assertEqual(r['Allow'], 'GET')
r = self.put(url, data='')
self.assertEqual(r.status_code, 400)
self.assertEqual(r.status_code, 405)
self.assertTrue('Allow' in r)
self.assertEqual(r['Allow'], 'GET')
r = self.post(url, data='')
self.assertEqual(r.status_code, 400)
self.assertEqual(r.status_code, 405)
self.assertTrue('Allow' in r)
self.assertEqual(r['Allow'], 'GET')
r = self.delete(url)
self.assertEqual(r.status_code, 400)
self.assertEqual(r.status_code, 405)
self.assertTrue('Allow' in r)
self.assertEqual(r['Allow'], 'GET')
def test_authenticate(self):
url = join_urls(self.pithos_path, '/')
......
......@@ -92,22 +92,34 @@ class NotAllowedView(PithosAPITest):
get_random_name())
r = self.head(self.view_url)
self.assertEqual(r.status_code, 400)
self.assertEqual(r.status_code, 405)
self.assertTrue('Allow' in r)
self.assertEqual(r['Allow'], 'GET')
r = self.delete(self.view_url)
self.assertEqual(r.status_code, 400)
self.assertEqual(r.status_code, 405)
self.assertTrue('Allow' in r)
self.assertEqual(r['Allow'], 'GET')
r = self.post(self.view_url)
self.assertEqual(r.status_code, 400)
self.assertEqual(r.status_code, 405)
self.assertTrue('Allow' in r)
self.assertEqual(r['Allow'], 'GET')
r = self.put(self.view_url)
self.assertEqual(r.status_code, 400)
self.assertEqual(r.status_code, 405)
self.assertTrue('Allow' in r)
self.assertEqual(r['Allow'], 'GET')
r = self.copy(self.view_url)
self.assertEqual(r.status_code, 400)
self.assertEqual(r.status_code, 405)
self.assertTrue('Allow' in r)
self.assertEqual(r['Allow'], 'GET')
r = self.move(self.view_url)
self.assertEqual(r.status_code, 400)
self.assertEqual(r.status_code, 405)
self.assertTrue('Allow' in r)
self.assertEqual(r['Allow'], 'GET')
class ObjectGetView(PithosAPITest):
......
......@@ -66,7 +66,7 @@ pithos_api_patterns = api_patterns(
pithos_view_patterns = patterns(
'pithos.api.views',
(r'^view/(?P<v_account>.+?)/(?P<v_container>.+?)/(?P<v_object>.+?)$',
'object_read'))
'object_demux'))
pithos_patterns = patterns(
'',
......
......@@ -31,6 +31,10 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
from django.views.decorators.csrf import csrf_exempt
from snf_django.lib import api
from pithos.api.functions import _object_read
from pithos.api.util import api_method, view_method
......@@ -38,6 +42,14 @@ import logging
logger = logging.getLogger(__name__)
@csrf_exempt
def object_demux(request, v_account, v_container, v_object):
if request.method == 'GET':
return object_read(request, v_account, v_container, v_object)
else:
return api.api_method_not_allowed(request, allowed_methods=['GET'])
@view_method()
@api_method('GET', format_allowed=True, user_required=True, logger=logger)
def object_read(request, v_account, v_container, v_object):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment