{"action":"created","comment":{"url":"https://api.github.com/repos/azavea/raster-foundry/pulls/comments/42558433","id":42558433,"diff_hunk":"@@ -5,34 +5,93 @@\n \n from django.conf import settings\n \n+import imghdr\n import os\n import uuid\n \n from boto.s3.key import Key\n from boto.s3.connection import S3Connection\n+from boto.exception import NoAuthHandlerFound, S3ResponseError\n from osgeo import gdal\n \n+SUPPORTED_MIMES = [  # See https://docs.python.org/2/library/imghdr.html\n+    'tiff',\n+]\n \n-def ensure_band_count(key_string, byte_range=None):\n-    \"\"\"\n-    Gets the first `range` bytes from the s3 resource and uses it to\n-    determine the number of bands in the image.\n-    \"\"\"\n-    connection = S3Connection()\n-    bucket = connection.get_bucket(settings.AWS_BUCKET_NAME)\n-    s3_key = Key(bucket)\n-    s3_key.key = key_string\n-    random_filename = os.path.join(settings.TEMP_DIR, str(uuid.uuid4()))\n-    with open(random_filename, 'w') as tempfile:\n-        if byte_range is not None:\n-            header_range = {'Range': 'bytes=' + byte_range}\n-            s3_key.get_contents_to_file(tempfile, headers=header_range)\n-        else:\n-            s3_key.get_contents_to_file(tempfile)\n-\n-    # Throws AttributeError if it cannot be opened.\n-    validator = gdal.Open(random_filename)\n-    # Tiler needs 3+ bands.\n-    raster_ok = validator.RasterCount >= 3\n-    os.remove(random_filename)\n-    return raster_ok\n+ERROR_MESSAGE_UNSUPPORTED_MIME = 'The image format is not supported.' + \\\n+                                 ' Supported formats are: ' + \\\n+                                 ', '.join(map(str, SUPPORTED_MIMES))\n+ERROR_MESSAGE_GENERIC_UNKNOWN = 'The system encountered an error.' + \\\n+                                ' Please try again later.'\n+ERROR_MESSAGE_IMAGE_NOT_VALID = 'Image was not a valid GeoTiff file.'\n+ERROR_MESSAGE_IMAGE_TOO_FEW_BANDS = 'Image does not have enough band data.'\n+\n+\n+class ImageValidator(object):\n+    error = None\n+    random_filename = None\n+\n+    def __init__(self, key_string, byte_range=None):\n+        try:\n+            connection = S3Connection()\n+            bucket = connection.get_bucket(settings.AWS_BUCKET_NAME)\n+            s3_key = Key(bucket)\n+            s3_key.key = key_string\n+            self.random_filename = os.path.join(\n+                settings.TEMP_DIR, str(uuid.uuid4()))\n+\n+            with open(self.random_filename, 'w') as tempfile:\n+                if byte_range is not None:\n+                    header_range = {'Range': 'bytes=' + byte_range}\n+                    s3_key.get_contents_to_file(tempfile, headers=header_range)\n+                else:\n+                    s3_key.get_contents_to_file(tempfile)\n+        except (NoAuthHandlerFound, S3ResponseError):","path":"src/rf/apps/workers/image_validator.py","position":67,"original_position":68,"commit_id":"ab57732caae7b9787a1441efe3ac7e2315e9931b","original_commit_id":"64dda8c8d7c1924783afcafada2745300640450b","user":{"login":"lliss","id":903219,"avatar_url":"https://avatars.githubusercontent.com/u/903219?v=3","gravatar_id":"","url":"https://api.github.com/users/lliss","html_url":"https://github.com/lliss","followers_url":"https://api.github.com/users/lliss/followers","following_url":"https://api.github.com/users/lliss/following{/other_user}","gists_url":"https://api.github.com/users/lliss/gists{/gist_id}","starred_url":"https://api.github.com/users/lliss/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lliss/subscriptions","organizations_url":"https://api.github.com/users/lliss/orgs","repos_url":"https://api.github.com/users/lliss/repos","events_url":"https://api.github.com/users/lliss/events{/privacy}","received_events_url":"https://api.github.com/users/lliss/received_events","type":"User","site_admin":false},"body":"We have no monitoring though.","created_at":"2015-10-20T21:40:58Z","updated_at":"2015-10-20T21:40:58Z","html_url":"https://github.com/azavea/raster-foundry/pull/206#discussion_r42558433","pull_request_url":"https://api.github.com/repos/azavea/raster-foundry/pulls/206","_links":{"self":{"href":"https://api.github.com/repos/azavea/raster-foundry/pulls/comments/42558433"},"html":{"href":"https://github.com/azavea/raster-foundry/pull/206#discussion_r42558433"},"pull_request":{"href":"https://api.github.com/repos/azavea/raster-foundry/pulls/206"}}},"pull_request":{"url":"https://api.github.com/repos/azavea/raster-foundry/pulls/206","id":48230392,"html_url":"https://github.com/azavea/raster-foundry/pull/206","diff_url":"https://github.com/azavea/raster-foundry/pull/206.diff","patch_url":"https://github.com/azavea/raster-foundry/pull/206.patch","issue_url":"https://api.github.com/repos/azavea/raster-foundry/issues/206","number":206,"state":"open","locked":false,"title":"Feature/lol/only allow tifs","user":{"login":"lliss","id":903219,"avatar_url":"https://avatars.githubusercontent.com/u/903219?v=3","gravatar_id":"","url":"https://api.github.com/users/lliss","html_url":"https://github.com/lliss","followers_url":"https://api.github.com/users/lliss/followers","following_url":"https://api.github.com/users/lliss/following{/other_user}","gists_url":"https://api.github.com/users/lliss/gists{/gist_id}","starred_url":"https://api.github.com/users/lliss/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lliss/subscriptions","organizations_url":"https://api.github.com/users/lliss/orgs","repos_url":"https://api.github.com/users/lliss/repos","events_url":"https://api.github.com/users/lliss/events{/privacy}","received_events_url":"https://api.github.com/users/lliss/received_events","type":"User","site_admin":false},"body":"Connects #186\r\nConnects #187 \r\n\r\nThis provides mimetype checking for uploaded images and hardens the worker pipeline against failing because of bad data.\r\n\r\nMuch of the worker code has been refactored in an effort to make this more stable.\r\n\r\n### To test\r\n * Start worker\r\n * Go through normal site checks with varying images including some that will fail.\r\n * Go to SQS and feed it some junk messages.\r\n * Check that worker does not crash.\r\n * Upload a PNG file and ensure it is marked as invalid with appropriate error message.","created_at":"2015-10-20T17:13:52Z","updated_at":"2015-10-20T21:40:58Z","closed_at":null,"merged_at":null,"merge_commit_sha":"5de5bf74ba9e476fd54fc7428b96b230846fc5df","assignee":{"login":"kdeloach","id":43062,"avatar_url":"https://avatars.githubusercontent.com/u/43062?v=3","gravatar_id":"","url":"https://api.github.com/users/kdeloach","html_url":"https://github.com/kdeloach","followers_url":"https://api.github.com/users/kdeloach/followers","following_url":"https://api.github.com/users/kdeloach/following{/other_user}","gists_url":"https://api.github.com/users/kdeloach/gists{/gist_id}","starred_url":"https://api.github.com/users/kdeloach/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kdeloach/subscriptions","organizations_url":"https://api.github.com/users/kdeloach/orgs","repos_url":"https://api.github.com/users/kdeloach/repos","events_url":"https://api.github.com/users/kdeloach/events{/privacy}","received_events_url":"https://api.github.com/users/kdeloach/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/azavea/raster-foundry/pulls/206/commits","review_comments_url":"https://api.github.com/repos/azavea/raster-foundry/pulls/206/comments","review_comment_url":"https://api.github.com/repos/azavea/raster-foundry/pulls/comments{/number}","comments_url":"https://api.github.com/repos/azavea/raster-foundry/issues/206/comments","statuses_url":"https://api.github.com/repos/azavea/raster-foundry/statuses/ab57732caae7b9787a1441efe3ac7e2315e9931b","head":{"label":"lliss:feature/lol/only-allow-tifs","ref":"feature/lol/only-allow-tifs","sha":"ab57732caae7b9787a1441efe3ac7e2315e9931b","user":{"login":"lliss","id":903219,"avatar_url":"https://avatars.githubusercontent.com/u/903219?v=3","gravatar_id":"","url":"https://api.github.com/users/lliss","html_url":"https://github.com/lliss","followers_url":"https://api.github.com/users/lliss/followers","following_url":"https://api.github.com/users/lliss/following{/other_user}","gists_url":"https://api.github.com/users/lliss/gists{/gist_id}","starred_url":"https://api.github.com/users/lliss/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lliss/subscriptions","organizations_url":"https://api.github.com/users/lliss/orgs","repos_url":"https://api.github.com/users/lliss/repos","events_url":"https://api.github.com/users/lliss/events{/privacy}","received_events_url":"https://api.github.com/users/lliss/received_events","type":"User","site_admin":false},"repo":{"id":40502568,"name":"raster-foundry","full_name":"lliss/raster-foundry","owner":{"login":"lliss","id":903219,"avatar_url":"https://avatars.githubusercontent.com/u/903219?v=3","gravatar_id":"","url":"https://api.github.com/users/lliss","html_url":"https://github.com/lliss","followers_url":"https://api.github.com/users/lliss/followers","following_url":"https://api.github.com/users/lliss/following{/other_user}","gists_url":"https://api.github.com/users/lliss/gists{/gist_id}","starred_url":"https://api.github.com/users/lliss/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lliss/subscriptions","organizations_url":"https://api.github.com/users/lliss/orgs","repos_url":"https://api.github.com/users/lliss/repos","events_url":"https://api.github.com/users/lliss/events{/privacy}","received_events_url":"https://api.github.com/users/lliss/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/lliss/raster-foundry","description":"Raster Foundry.","fork":true,"url":"https://api.github.com/repos/lliss/raster-foundry","forks_url":"https://api.github.com/repos/lliss/raster-foundry/forks","keys_url":"https://api.github.com/repos/lliss/raster-foundry/keys{/key_id}","collaborators_url":"https://api.github.com/repos/lliss/raster-foundry/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/lliss/raster-foundry/teams","hooks_url":"https://api.github.com/repos/lliss/raster-foundry/hooks","issue_events_url":"https://api.github.com/repos/lliss/raster-foundry/issues/events{/number}","events_url":"https://api.github.com/repos/lliss/raster-foundry/events","assignees_url":"https://api.github.com/repos/lliss/raster-foundry/assignees{/user}","branches_url":"https://api.github.com/repos/lliss/raster-foundry/branches{/branch}","tags_url":"https://api.github.com/repos/lliss/raster-foundry/tags","blobs_url":"https://api.github.com/repos/lliss/raster-foundry/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/lliss/raster-foundry/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/lliss/raster-foundry/git/refs{/sha}","trees_url":"https://api.github.com/repos/lliss/raster-foundry/git/trees{/sha}","statuses_url":"https://api.github.com/repos/lliss/raster-foundry/statuses/{sha}","languages_url":"https://api.github.com/repos/lliss/raster-foundry/languages","stargazers_url":"https://api.github.com/repos/lliss/raster-foundry/stargazers","contributors_url":"https://api.github.com/repos/lliss/raster-foundry/contributors","subscribers_url":"https://api.github.com/repos/lliss/raster-foundry/subscribers","subscription_url":"https://api.github.com/repos/lliss/raster-foundry/subscription","commits_url":"https://api.github.com/repos/lliss/raster-foundry/commits{/sha}","git_commits_url":"https://api.github.com/repos/lliss/raster-foundry/git/commits{/sha}","comments_url":"https://api.github.com/repos/lliss/raster-foundry/comments{/number}","issue_comment_url":"https://api.github.com/repos/lliss/raster-foundry/issues/comments{/number}","contents_url":"https://api.github.com/repos/lliss/raster-foundry/contents/{+path}","compare_url":"https://api.github.com/repos/lliss/raster-foundry/compare/{base}...{head}","merges_url":"https://api.github.com/repos/lliss/raster-foundry/merges","archive_url":"https://api.github.com/repos/lliss/raster-foundry/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/lliss/raster-foundry/downloads","issues_url":"https://api.github.com/repos/lliss/raster-foundry/issues{/number}","pulls_url":"https://api.github.com/repos/lliss/raster-foundry/pulls{/number}","milestones_url":"https://api.github.com/repos/lliss/raster-foundry/milestones{/number}","notifications_url":"https://api.github.com/repos/lliss/raster-foundry/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/lliss/raster-foundry/labels{/name}","releases_url":"https://api.github.com/repos/lliss/raster-foundry/releases{/id}","created_at":"2015-08-10T19:46:24Z","updated_at":"2015-08-10T19:46:25Z","pushed_at":"2015-10-20T21:39:28Z","git_url":"git://github.com/lliss/raster-foundry.git","ssh_url":"git@github.com:lliss/raster-foundry.git","clone_url":"https://github.com/lliss/raster-foundry.git","svn_url":"https://github.com/lliss/raster-foundry","homepage":null,"size":12895,"stargazers_count":0,"watchers_count":0,"language":"HTML","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"azavea:develop","ref":"develop","sha":"7608e098357877f5e52ed13b4fb53f566b3ca56f","user":{"login":"azavea","id":595231,"avatar_url":"https://avatars.githubusercontent.com/u/595231?v=3","gravatar_id":"","url":"https://api.github.com/users/azavea","html_url":"https://github.com/azavea","followers_url":"https://api.github.com/users/azavea/followers","following_url":"https://api.github.com/users/azavea/following{/other_user}","gists_url":"https://api.github.com/users/azavea/gists{/gist_id}","starred_url":"https://api.github.com/users/azavea/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/azavea/subscriptions","organizations_url":"https://api.github.com/users/azavea/orgs","repos_url":"https://api.github.com/users/azavea/repos","events_url":"https://api.github.com/users/azavea/events{/privacy}","received_events_url":"https://api.github.com/users/azavea/received_events","type":"Organization","site_admin":false},"repo":{"id":36464140,"name":"raster-foundry","full_name":"azavea/raster-foundry","owner":{"login":"azavea","id":595231,"avatar_url":"https://avatars.githubusercontent.com/u/595231?v=3","gravatar_id":"","url":"https://api.github.com/users/azavea","html_url":"https://github.com/azavea","followers_url":"https://api.github.com/users/azavea/followers","following_url":"https://api.github.com/users/azavea/following{/other_user}","gists_url":"https://api.github.com/users/azavea/gists{/gist_id}","starred_url":"https://api.github.com/users/azavea/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/azavea/subscriptions","organizations_url":"https://api.github.com/users/azavea/orgs","repos_url":"https://api.github.com/users/azavea/repos","events_url":"https://api.github.com/users/azavea/events{/privacy}","received_events_url":"https://api.github.com/users/azavea/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/azavea/raster-foundry","description":"The Raster Foundry web application.","fork":false,"url":"https://api.github.com/repos/azavea/raster-foundry","forks_url":"https://api.github.com/repos/azavea/raster-foundry/forks","keys_url":"https://api.github.com/repos/azavea/raster-foundry/keys{/key_id}","collaborators_url":"https://api.github.com/repos/azavea/raster-foundry/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/azavea/raster-foundry/teams","hooks_url":"https://api.github.com/repos/azavea/raster-foundry/hooks","issue_events_url":"https://api.github.com/repos/azavea/raster-foundry/issues/events{/number}","events_url":"https://api.github.com/repos/azavea/raster-foundry/events","assignees_url":"https://api.github.com/repos/azavea/raster-foundry/assignees{/user}","branches_url":"https://api.github.com/repos/azavea/raster-foundry/branches{/branch}","tags_url":"https://api.github.com/repos/azavea/raster-foundry/tags","blobs_url":"https://api.github.com/repos/azavea/raster-foundry/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/azavea/raster-foundry/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/azavea/raster-foundry/git/refs{/sha}","trees_url":"https://api.github.com/repos/azavea/raster-foundry/git/trees{/sha}","statuses_url":"https://api.github.com/repos/azavea/raster-foundry/statuses/{sha}","languages_url":"https://api.github.com/repos/azavea/raster-foundry/languages","stargazers_url":"https://api.github.com/repos/azavea/raster-foundry/stargazers","contributors_url":"https://api.github.com/repos/azavea/raster-foundry/contributors","subscribers_url":"https://api.github.com/repos/azavea/raster-foundry/subscribers","subscription_url":"https://api.github.com/repos/azavea/raster-foundry/subscription","commits_url":"https://api.github.com/repos/azavea/raster-foundry/commits{/sha}","git_commits_url":"https://api.github.com/repos/azavea/raster-foundry/git/commits{/sha}","comments_url":"https://api.github.com/repos/azavea/raster-foundry/comments{/number}","issue_comment_url":"https://api.github.com/repos/azavea/raster-foundry/issues/comments{/number}","contents_url":"https://api.github.com/repos/azavea/raster-foundry/contents/{+path}","compare_url":"https://api.github.com/repos/azavea/raster-foundry/compare/{base}...{head}","merges_url":"https://api.github.com/repos/azavea/raster-foundry/merges","archive_url":"https://api.github.com/repos/azavea/raster-foundry/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/azavea/raster-foundry/downloads","issues_url":"https://api.github.com/repos/azavea/raster-foundry/issues{/number}","pulls_url":"https://api.github.com/repos/azavea/raster-foundry/pulls{/number}","milestones_url":"https://api.github.com/repos/azavea/raster-foundry/milestones{/number}","notifications_url":"https://api.github.com/repos/azavea/raster-foundry/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/azavea/raster-foundry/labels{/name}","releases_url":"https://api.github.com/repos/azavea/raster-foundry/releases{/id}","created_at":"2015-05-28T20:25:45Z","updated_at":"2015-10-20T20:51:43Z","pushed_at":"2015-10-20T21:39:29Z","git_url":"git://github.com/azavea/raster-foundry.git","ssh_url":"git@github.com:azavea/raster-foundry.git","clone_url":"https://github.com/azavea/raster-foundry.git","svn_url":"https://github.com/azavea/raster-foundry","homepage":"","size":13656,"stargazers_count":3,"watchers_count":3,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":7,"mirror_url":null,"open_issues_count":61,"forks":7,"open_issues":61,"watchers":3,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/azavea/raster-foundry/pulls/206"},"html":{"href":"https://github.com/azavea/raster-foundry/pull/206"},"issue":{"href":"https://api.github.com/repos/azavea/raster-foundry/issues/206"},"comments":{"href":"https://api.github.com/repos/azavea/raster-foundry/issues/206/comments"},"review_comments":{"href":"https://api.github.com/repos/azavea/raster-foundry/pulls/206/comments"},"review_comment":{"href":"https://api.github.com/repos/azavea/raster-foundry/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/azavea/raster-foundry/pulls/206/commits"},"statuses":{"href":"https://api.github.com/repos/azavea/raster-foundry/statuses/ab57732caae7b9787a1441efe3ac7e2315e9931b"}}}}