{"action":"created","comment":{"url":"https://api.github.com/repos/edx/edx-platform/pulls/comments/48442232","id":48442232,"diff_hunk":"@@ -127,11 +134,100 @@ def get_location_from_path(path):\n                 return AssetKey.from_string(path[1:])\n \n     @staticmethod\n+    def get_canonicalized_asset_path(course_key, path):\n+        \"\"\"\n+        Returns a fully-qualified path to a piece of static content.\n+\n+        If a static asset CDN is configured, this path will include it.\n+        Otherwise, the path will simply be relative.\n+\n+        Args:\n+            course_key: key to the course which owns this asset\n+            path: the path to said content\n+\n+        Returns:\n+            string: fully-qualified path to asset\n+        \"\"\"\n+\n+        # Break down the input path.\n+        _, base_url, relative_path, params, query_string, fragment = urlparse(path)\n+\n+        # Convert our path to an asset key.\n+        asset_key = StaticContent.get_asset_key_from_path(course_key, relative_path)\n+\n+        # Check to see if we can actually provide a CDN-ified version\n+        # of this asset back to the caller.\n+        is_locked = False\n+        try:\n+            content = AssetManager.find(asset_key, as_stream=False)\n+            is_locked = getattr(content, \"locked\", False)\n+        except (ItemNotFoundError, NotFoundError):\n+            # TODO: What's the right fallback here?  Assume it's locked?\n+            # Can we ever reasonably except this state since we're actually\n+            # calling the same store that will be asked to serve the asset?\n+            pass\n+\n+        # Update any query parameter values that have asset paths in them.\n+        query_params = parse_qsl(query_string)\n+        updated_query_params = []\n+        for query_name, query_value in query_params:\n+            if query_value.startswith(\"/static/\"):\n+                offset = len('/static/')\n+                new_query_value = unicode(StaticContent.get_asset_key_from_path(course_key, query_value[offset:]))\n+                if not new_query_value.startswith('/'):\n+                    new_query_value = '/' + new_query_value\n+                updated_query_params.append((query_name, new_query_value))\n+            else:\n+                updated_query_params.append((query_name, query_value))","path":"common/lib/xmodule/xmodule/contentstore/content.py","position":72,"original_position":72,"commit_id":"2bad2d7d6e4f67e8526410e67b7864e6d5d28ffc","original_commit_id":"2bad2d7d6e4f67e8526410e67b7864e6d5d28ffc","user":{"login":"tobz","id":222615,"avatar_url":"https://avatars.githubusercontent.com/u/222615?v=3","gravatar_id":"","url":"https://api.github.com/users/tobz","html_url":"https://github.com/tobz","followers_url":"https://api.github.com/users/tobz/followers","following_url":"https://api.github.com/users/tobz/following{/other_user}","gists_url":"https://api.github.com/users/tobz/gists{/gist_id}","starred_url":"https://api.github.com/users/tobz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tobz/subscriptions","organizations_url":"https://api.github.com/users/tobz/orgs","repos_url":"https://api.github.com/users/tobz/repos","events_url":"https://api.github.com/users/tobz/events{/privacy}","received_events_url":"https://api.github.com/users/tobz/received_events","type":"User","site_admin":false},"body":"I'll definitely add comments, but to at least answer your question: the example in the unit tests is something like a Flash file, where query parameters are used to indicate where some sort of data/config file is located.","created_at":"2015-12-25T17:21:04Z","updated_at":"2015-12-25T17:21:04Z","html_url":"https://github.com/edx/edx-platform/pull/11025#discussion_r48442232","pull_request_url":"https://api.github.com/repos/edx/edx-platform/pulls/11025","_links":{"self":{"href":"https://api.github.com/repos/edx/edx-platform/pulls/comments/48442232"},"html":{"href":"https://github.com/edx/edx-platform/pull/11025#discussion_r48442232"},"pull_request":{"href":"https://api.github.com/repos/edx/edx-platform/pulls/11025"}}},"pull_request":{"url":"https://api.github.com/repos/edx/edx-platform/pulls/11025","id":54027630,"html_url":"https://github.com/edx/edx-platform/pull/11025","diff_url":"https://github.com/edx/edx-platform/pull/11025.diff","patch_url":"https://github.com/edx/edx-platform/pull/11025.patch","issue_url":"https://api.github.com/repos/edx/edx-platform/issues/11025","number":11025,"state":"open","locked":false,"title":"[WIP] [PERF-224] Serve course assets from a CDN","user":{"login":"tobz","id":222615,"avatar_url":"https://avatars.githubusercontent.com/u/222615?v=3","gravatar_id":"","url":"https://api.github.com/users/tobz","html_url":"https://github.com/tobz","followers_url":"https://api.github.com/users/tobz/followers","following_url":"https://api.github.com/users/tobz/following{/other_user}","gists_url":"https://api.github.com/users/tobz/gists{/gist_id}","starred_url":"https://api.github.com/users/tobz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tobz/subscriptions","organizations_url":"https://api.github.com/users/tobz/orgs","repos_url":"https://api.github.com/users/tobz/repos","events_url":"https://api.github.com/users/tobz/events{/privacy}","received_events_url":"https://api.github.com/users/tobz/received_events","type":"User","site_admin":false},"body":"This is a quick & not-terribly-dirty approach to turning the static URLs generated for course assets into full URLs pointing at some sort of CDN.\r\n\r\nWe have a feature flag -- ENABLE_STATIC_ASSET_CDN -- and a setting -- STATIC_ASSET_CDN_BASE_URL -- which are used to turn asset URLs from relative to absolute.  This only triggered for unlocked content.  Also, it's only used in the codepath that deals with ^/static/ assets.\r\n\r\nDeep questions:\r\n- is this the right configuration method? do we feel comfortable having to redeploy to change this value?\r\n- are there other codepaths for generating asset URLs that this doesn't catch?\r\n- should we clean up/simplify asset URL generation as a whole while we're in here?\r\n\r\ncc @ormsbee ","created_at":"2015-12-17T20:30:53Z","updated_at":"2015-12-25T17:21:04Z","closed_at":null,"merged_at":null,"merge_commit_sha":"2ec31ca5b53d1142cbd577e88d4fd123bb963786","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/edx/edx-platform/pulls/11025/commits","review_comments_url":"https://api.github.com/repos/edx/edx-platform/pulls/11025/comments","review_comment_url":"https://api.github.com/repos/edx/edx-platform/pulls/comments{/number}","comments_url":"https://api.github.com/repos/edx/edx-platform/issues/11025/comments","statuses_url":"https://api.github.com/repos/edx/edx-platform/statuses/2bad2d7d6e4f67e8526410e67b7864e6d5d28ffc","head":{"label":"edx:PERF-224","ref":"PERF-224","sha":"2bad2d7d6e4f67e8526410e67b7864e6d5d28ffc","user":{"login":"edx","id":3179841,"avatar_url":"https://avatars.githubusercontent.com/u/3179841?v=3","gravatar_id":"","url":"https://api.github.com/users/edx","html_url":"https://github.com/edx","followers_url":"https://api.github.com/users/edx/followers","following_url":"https://api.github.com/users/edx/following{/other_user}","gists_url":"https://api.github.com/users/edx/gists{/gist_id}","starred_url":"https://api.github.com/users/edx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edx/subscriptions","organizations_url":"https://api.github.com/users/edx/orgs","repos_url":"https://api.github.com/users/edx/repos","events_url":"https://api.github.com/users/edx/events{/privacy}","received_events_url":"https://api.github.com/users/edx/received_events","type":"Organization","site_admin":false},"repo":{"id":10391073,"name":"edx-platform","full_name":"edx/edx-platform","owner":{"login":"edx","id":3179841,"avatar_url":"https://avatars.githubusercontent.com/u/3179841?v=3","gravatar_id":"","url":"https://api.github.com/users/edx","html_url":"https://github.com/edx","followers_url":"https://api.github.com/users/edx/followers","following_url":"https://api.github.com/users/edx/following{/other_user}","gists_url":"https://api.github.com/users/edx/gists{/gist_id}","starred_url":"https://api.github.com/users/edx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edx/subscriptions","organizations_url":"https://api.github.com/users/edx/orgs","repos_url":"https://api.github.com/users/edx/repos","events_url":"https://api.github.com/users/edx/events{/privacy}","received_events_url":"https://api.github.com/users/edx/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/edx/edx-platform","description":"The Open edX platform, the software that powers edX!","fork":false,"url":"https://api.github.com/repos/edx/edx-platform","forks_url":"https://api.github.com/repos/edx/edx-platform/forks","keys_url":"https://api.github.com/repos/edx/edx-platform/keys{/key_id}","collaborators_url":"https://api.github.com/repos/edx/edx-platform/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/edx/edx-platform/teams","hooks_url":"https://api.github.com/repos/edx/edx-platform/hooks","issue_events_url":"https://api.github.com/repos/edx/edx-platform/issues/events{/number}","events_url":"https://api.github.com/repos/edx/edx-platform/events","assignees_url":"https://api.github.com/repos/edx/edx-platform/assignees{/user}","branches_url":"https://api.github.com/repos/edx/edx-platform/branches{/branch}","tags_url":"https://api.github.com/repos/edx/edx-platform/tags","blobs_url":"https://api.github.com/repos/edx/edx-platform/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/edx/edx-platform/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/edx/edx-platform/git/refs{/sha}","trees_url":"https://api.github.com/repos/edx/edx-platform/git/trees{/sha}","statuses_url":"https://api.github.com/repos/edx/edx-platform/statuses/{sha}","languages_url":"https://api.github.com/repos/edx/edx-platform/languages","stargazers_url":"https://api.github.com/repos/edx/edx-platform/stargazers","contributors_url":"https://api.github.com/repos/edx/edx-platform/contributors","subscribers_url":"https://api.github.com/repos/edx/edx-platform/subscribers","subscription_url":"https://api.github.com/repos/edx/edx-platform/subscription","commits_url":"https://api.github.com/repos/edx/edx-platform/commits{/sha}","git_commits_url":"https://api.github.com/repos/edx/edx-platform/git/commits{/sha}","comments_url":"https://api.github.com/repos/edx/edx-platform/comments{/number}","issue_comment_url":"https://api.github.com/repos/edx/edx-platform/issues/comments{/number}","contents_url":"https://api.github.com/repos/edx/edx-platform/contents/{+path}","compare_url":"https://api.github.com/repos/edx/edx-platform/compare/{base}...{head}","merges_url":"https://api.github.com/repos/edx/edx-platform/merges","archive_url":"https://api.github.com/repos/edx/edx-platform/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/edx/edx-platform/downloads","issues_url":"https://api.github.com/repos/edx/edx-platform/issues{/number}","pulls_url":"https://api.github.com/repos/edx/edx-platform/pulls{/number}","milestones_url":"https://api.github.com/repos/edx/edx-platform/milestones{/number}","notifications_url":"https://api.github.com/repos/edx/edx-platform/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/edx/edx-platform/labels{/name}","releases_url":"https://api.github.com/repos/edx/edx-platform/releases{/id}","created_at":"2013-05-30T20:20:38Z","updated_at":"2015-12-25T09:34:47Z","pushed_at":"2015-12-25T15:43:13Z","git_url":"git://github.com/edx/edx-platform.git","ssh_url":"git@github.com:edx/edx-platform.git","clone_url":"https://github.com/edx/edx-platform.git","svn_url":"https://github.com/edx/edx-platform","homepage":"http://open.edx.org/","size":633293,"stargazers_count":2320,"watchers_count":2320,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":1408,"mirror_url":null,"open_issues_count":127,"forks":1408,"open_issues":127,"watchers":2320,"default_branch":"master"}},"base":{"label":"edx:master","ref":"master","sha":"5a4ccabeafd72b1b10d57dab8bda81494f7c68c0","user":{"login":"edx","id":3179841,"avatar_url":"https://avatars.githubusercontent.com/u/3179841?v=3","gravatar_id":"","url":"https://api.github.com/users/edx","html_url":"https://github.com/edx","followers_url":"https://api.github.com/users/edx/followers","following_url":"https://api.github.com/users/edx/following{/other_user}","gists_url":"https://api.github.com/users/edx/gists{/gist_id}","starred_url":"https://api.github.com/users/edx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edx/subscriptions","organizations_url":"https://api.github.com/users/edx/orgs","repos_url":"https://api.github.com/users/edx/repos","events_url":"https://api.github.com/users/edx/events{/privacy}","received_events_url":"https://api.github.com/users/edx/received_events","type":"Organization","site_admin":false},"repo":{"id":10391073,"name":"edx-platform","full_name":"edx/edx-platform","owner":{"login":"edx","id":3179841,"avatar_url":"https://avatars.githubusercontent.com/u/3179841?v=3","gravatar_id":"","url":"https://api.github.com/users/edx","html_url":"https://github.com/edx","followers_url":"https://api.github.com/users/edx/followers","following_url":"https://api.github.com/users/edx/following{/other_user}","gists_url":"https://api.github.com/users/edx/gists{/gist_id}","starred_url":"https://api.github.com/users/edx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edx/subscriptions","organizations_url":"https://api.github.com/users/edx/orgs","repos_url":"https://api.github.com/users/edx/repos","events_url":"https://api.github.com/users/edx/events{/privacy}","received_events_url":"https://api.github.com/users/edx/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/edx/edx-platform","description":"The Open edX platform, the software that powers edX!","fork":false,"url":"https://api.github.com/repos/edx/edx-platform","forks_url":"https://api.github.com/repos/edx/edx-platform/forks","keys_url":"https://api.github.com/repos/edx/edx-platform/keys{/key_id}","collaborators_url":"https://api.github.com/repos/edx/edx-platform/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/edx/edx-platform/teams","hooks_url":"https://api.github.com/repos/edx/edx-platform/hooks","issue_events_url":"https://api.github.com/repos/edx/edx-platform/issues/events{/number}","events_url":"https://api.github.com/repos/edx/edx-platform/events","assignees_url":"https://api.github.com/repos/edx/edx-platform/assignees{/user}","branches_url":"https://api.github.com/repos/edx/edx-platform/branches{/branch}","tags_url":"https://api.github.com/repos/edx/edx-platform/tags","blobs_url":"https://api.github.com/repos/edx/edx-platform/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/edx/edx-platform/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/edx/edx-platform/git/refs{/sha}","trees_url":"https://api.github.com/repos/edx/edx-platform/git/trees{/sha}","statuses_url":"https://api.github.com/repos/edx/edx-platform/statuses/{sha}","languages_url":"https://api.github.com/repos/edx/edx-platform/languages","stargazers_url":"https://api.github.com/repos/edx/edx-platform/stargazers","contributors_url":"https://api.github.com/repos/edx/edx-platform/contributors","subscribers_url":"https://api.github.com/repos/edx/edx-platform/subscribers","subscription_url":"https://api.github.com/repos/edx/edx-platform/subscription","commits_url":"https://api.github.com/repos/edx/edx-platform/commits{/sha}","git_commits_url":"https://api.github.com/repos/edx/edx-platform/git/commits{/sha}","comments_url":"https://api.github.com/repos/edx/edx-platform/comments{/number}","issue_comment_url":"https://api.github.com/repos/edx/edx-platform/issues/comments{/number}","contents_url":"https://api.github.com/repos/edx/edx-platform/contents/{+path}","compare_url":"https://api.github.com/repos/edx/edx-platform/compare/{base}...{head}","merges_url":"https://api.github.com/repos/edx/edx-platform/merges","archive_url":"https://api.github.com/repos/edx/edx-platform/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/edx/edx-platform/downloads","issues_url":"https://api.github.com/repos/edx/edx-platform/issues{/number}","pulls_url":"https://api.github.com/repos/edx/edx-platform/pulls{/number}","milestones_url":"https://api.github.com/repos/edx/edx-platform/milestones{/number}","notifications_url":"https://api.github.com/repos/edx/edx-platform/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/edx/edx-platform/labels{/name}","releases_url":"https://api.github.com/repos/edx/edx-platform/releases{/id}","created_at":"2013-05-30T20:20:38Z","updated_at":"2015-12-25T09:34:47Z","pushed_at":"2015-12-25T15:43:13Z","git_url":"git://github.com/edx/edx-platform.git","ssh_url":"git@github.com:edx/edx-platform.git","clone_url":"https://github.com/edx/edx-platform.git","svn_url":"https://github.com/edx/edx-platform","homepage":"http://open.edx.org/","size":633293,"stargazers_count":2320,"watchers_count":2320,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":1408,"mirror_url":null,"open_issues_count":127,"forks":1408,"open_issues":127,"watchers":2320,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/edx/edx-platform/pulls/11025"},"html":{"href":"https://github.com/edx/edx-platform/pull/11025"},"issue":{"href":"https://api.github.com/repos/edx/edx-platform/issues/11025"},"comments":{"href":"https://api.github.com/repos/edx/edx-platform/issues/11025/comments"},"review_comments":{"href":"https://api.github.com/repos/edx/edx-platform/pulls/11025/comments"},"review_comment":{"href":"https://api.github.com/repos/edx/edx-platform/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/edx/edx-platform/pulls/11025/commits"},"statuses":{"href":"https://api.github.com/repos/edx/edx-platform/statuses/2bad2d7d6e4f67e8526410e67b7864e6d5d28ffc"}}}}