diff --git a/cms/djangoapps/contentstore/views/checklist.py b/cms/djangoapps/contentstore/views/checklist.py
index 5a7658542ad50f58a063c9e5a7ed15232da6ed67..fa0a7b7b62f673f68e8ff663c9c4d921545e84de 100644
--- a/cms/djangoapps/contentstore/views/checklist.py
+++ b/cms/djangoapps/contentstore/views/checklist.py
@@ -3,6 +3,7 @@ import json
 from util.json_request import JsonResponse
 from django.http import HttpResponseBadRequest
 from django.contrib.auth.decorators import login_required
+from django.views.decorators.http import require_http_methods
 from django_future.csrf import ensure_csrf_cookie
 from mitxmako.shortcuts import render_to_response
 
@@ -10,7 +11,6 @@ from xmodule.modulestore import Location
 from xmodule.modulestore.inheritance import own_metadata
 
 from ..utils import get_modulestore, get_url_reverse
-from .requests import get_request_method
 from .access import get_location_and_verify_access
 
 __all__ = ['get_checklists', 'update_checklist']
@@ -47,6 +47,7 @@ def get_checklists(request, org, course, name):
                               })
 
 
+@require_http_methods(("GET", "POST", "PUT"))
 @ensure_csrf_cookie
 @login_required
 def update_checklist(request, org, course, name, checklist_index=None):
@@ -63,8 +64,7 @@ def update_checklist(request, org, course, name, checklist_index=None):
     modulestore = get_modulestore(location)
     course_module = modulestore.get_item(location)
 
-    real_method = get_request_method(request)
-    if real_method == 'POST' or real_method == 'PUT':
+    if request.method in ("POST", "PUT"):
         if checklist_index is not None and 0 <= int(checklist_index) < len(course_module.checklists):
             index = int(checklist_index)
             course_module.checklists[index] = json.loads(request.body)
@@ -83,8 +83,6 @@ def update_checklist(request, org, course, name, checklist_index=None):
         if modified:
             modulestore.update_metadata(location, own_metadata(course_module))
         return JsonResponse(checklists)
-    else:
-        return HttpResponseBadRequest("Unsupported request.", content_type="text/plain")
 
 
 def expand_checklist_action_urls(course_module):
diff --git a/cms/djangoapps/contentstore/views/component.py b/cms/djangoapps/contentstore/views/component.py
index c4fb9277040217ab7f1a6e136d609ecc89d10184..fcf024d682762db99070992ab7269dd5f32ce4ac 100644
--- a/cms/djangoapps/contentstore/views/component.py
+++ b/cms/djangoapps/contentstore/views/component.py
@@ -4,6 +4,7 @@ from collections import defaultdict
 
 from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden
 from django.contrib.auth.decorators import login_required
+from django.views.decorators.http import require_http_methods
 from django.core.exceptions import PermissionDenied
 from django_future.csrf import ensure_csrf_cookie
 from django.conf import settings
@@ -23,7 +24,7 @@ from contentstore.utils import get_modulestore, get_lms_link_for_item, \
 
 from models.settings.course_grading import CourseGradingModel
 
-from .requests import get_request_method, _xmodule_recurse
+from .requests import _xmodule_recurse
 from .access import has_access
 
 __all__ = ['OPEN_ENDED_COMPONENT_TYPES',
@@ -288,6 +289,7 @@ def unpublish_unit(request):
 
 
 @expect_json
+@require_http_methods(("GET", "POST", "PUT"))
 @login_required
 @ensure_csrf_cookie
 def module_info(request, module_location):
@@ -297,8 +299,6 @@ def module_info(request, module_location):
     if not has_access(request.user, location):
         raise PermissionDenied()
 
-    real_method = get_request_method(request)
-
     rewrite_static_links = request.GET.get('rewrite_url_links', 'True') in ['True', 'true']
     logging.debug('rewrite_static_links = {0} {1}'.format(request.GET.get('rewrite_url_links', 'False'), rewrite_static_links))
 
@@ -306,9 +306,7 @@ def module_info(request, module_location):
     if not has_access(request.user, location):
         raise PermissionDenied()
 
-    if real_method == 'GET':
+    if request.method == 'GET':
         return JsonResponse(get_module_info(get_modulestore(location), location, rewrite_static_links=rewrite_static_links))
-    elif real_method == 'POST' or real_method == 'PUT':
+    elif request.method in ("POST", "PUT"):
         return JsonResponse(set_module_info(get_modulestore(location), location, request.POST))
-    else:
-        return HttpResponseBadRequest()
diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py
index a7917d86697c325bbb3c57c4619e802f738b778b..0405112ea1263c0e37ebc8a18a76cc5b2011d41e 100644
--- a/cms/djangoapps/contentstore/views/course.py
+++ b/cms/djangoapps/contentstore/views/course.py
@@ -36,7 +36,6 @@ from auth.authz import create_all_course_groups, is_user_in_creator_group
 from util.json_request import expect_json
 
 from .access import has_access, get_location_and_verify_access
-from .requests import get_request_method
 from .tabs import initialize_course_tabs
 from .component import (
     OPEN_ENDED_COMPONENT_TYPES, NOTE_COMPONENT_TYPES,
@@ -199,11 +198,9 @@ def course_info_updates(request, org, course, provided_id=None):
     if not has_access(request.user, location):
         raise PermissionDenied()
 
-    real_method = get_request_method(request)
-
     if request.method == 'GET':
         return JsonResponse(get_course_updates(location))
-    elif real_method == 'DELETE':
+    elif request.method == 'DELETE':
         try:
             return JsonResponse(delete_course_update(location, request.POST, provided_id))
         except:
@@ -308,6 +305,7 @@ def course_settings_updates(request, org, course, name, section):
 
 
 @expect_json
+@require_http_methods(("GET", "POST", "PUT", "DELETE"))
 @login_required
 @ensure_csrf_cookie
 def course_grader_updates(request, org, course, name, grader_index=None):
@@ -320,20 +318,19 @@ def course_grader_updates(request, org, course, name, grader_index=None):
 
     location = get_location_and_verify_access(request, org, course, name)
 
-    real_method = get_request_method(request)
-
-    if real_method == 'GET':
+    if request.method == 'GET':
         # Cannot just do a get w/o knowing the course name :-(
         return JsonResponse(CourseGradingModel.fetch_grader(Location(location), grader_index))
-    elif real_method == "DELETE":
+    elif request.method == "DELETE":
         # ??? Should this return anything? Perhaps success fail?
         CourseGradingModel.delete_grader(Location(location), grader_index)
         return JsonResponse()
-    elif request.method == 'POST':  # post or put, doesn't matter.
+    else:  # post or put, doesn't matter.
         return JsonResponse(CourseGradingModel.update_grader_from_json(Location(location), request.POST))
 
 
 # # NB: expect_json failed on ["key", "key2"] and json payload
+@require_http_methods(("GET", "POST", "PUT", "DELETE"))
 @login_required
 @ensure_csrf_cookie
 def course_advanced_updates(request, org, course, name):
@@ -345,13 +342,11 @@ def course_advanced_updates(request, org, course, name):
     """
     location = get_location_and_verify_access(request, org, course, name)
 
-    real_method = get_request_method(request)
-
-    if real_method == 'GET':
+    if request.method == 'GET':
         return JsonResponse(CourseMetadata.fetch(location))
-    elif real_method == 'DELETE':
+    elif request.method == 'DELETE':
         return JsonResponse(CourseMetadata.delete_key(location, json.loads(request.body)))
-    elif real_method == 'POST' or real_method == 'PUT':
+    else:
         # NOTE: request.POST is messed up because expect_json
         # cloned_request.POST.copy() is creating a defective entry w/ the whole payload as the key
         request_body = json.loads(request.body)
diff --git a/cms/djangoapps/contentstore/views/requests.py b/cms/djangoapps/contentstore/views/requests.py
index c493441c77379781873791941272d8dd1c39a15a..1385eaddba6b2daedeaae790f4bb3e4ae922f0ee 100644
--- a/cms/djangoapps/contentstore/views/requests.py
+++ b/cms/djangoapps/contentstore/views/requests.py
@@ -24,20 +24,6 @@ def event(request):
     return HttpResponse(status=204)
 
 
-def get_request_method(request):
-    """
-    Using HTTP_X_HTTP_METHOD_OVERRIDE, in the request metadata, determine
-    what type of request came from the client, and return it.
-    """
-    # NB: we're setting Backbone.emulateHTTP to true on the client so everything comes as a post!!!
-    if request.method == 'POST' and 'HTTP_X_HTTP_METHOD_OVERRIDE' in request.META:
-        real_method = request.META['HTTP_X_HTTP_METHOD_OVERRIDE']
-    else:
-        real_method = request.method
-
-    return real_method
-
-
 def create_json_response(errmsg=None):
     if errmsg is not None:
         resp = HttpResponse(json.dumps({'Status': 'Failed', 'ErrMsg': errmsg}))
diff --git a/cms/envs/common.py b/cms/envs/common.py
index 0d8412bee2c321fd56a2936afd33ba235318c382..1207b8fe059925569388edbef719d4f73ff043a4 100644
--- a/cms/envs/common.py
+++ b/cms/envs/common.py
@@ -143,6 +143,7 @@ MIDDLEWARE_CLASSES = (
     'django.middleware.common.CommonMiddleware',
     'django.contrib.sessions.middleware.SessionMiddleware',
     'django.middleware.csrf.CsrfViewMiddleware',
+    'method_override.middleware.MethodOverrideMiddleware',
 
     # Instead of AuthenticationMiddleware, we use a cache-backed version
     'cache_toolbox.middleware.CacheBackedAuthenticationMiddleware',
@@ -325,6 +326,7 @@ INSTALLED_APPS = (
     'django.contrib.messages',
     'djcelery',
     'south',
+    'method_override',
 
     # Monitor the status of services
     'service_status',
diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt
index 1117b67d029a3736535b6f6eed11bead798713dd..910b6f3defc3a8c16025cce74749cbf932adc755 100644
--- a/requirements/edx/base.txt
+++ b/requirements/edx/base.txt
@@ -19,6 +19,7 @@ django-sekizai==0.6.1
 django-ses==0.4.1
 django-storages==1.1.5
 django-threaded-multihost==1.4-1
+django-method-override==0.1.0
 django==1.4.5
 feedparser==5.1.3
 fs==0.4.0