diff --git a/swh/web/api/views/directory.py b/swh/web/api/views/directory.py
--- a/swh/web/api/views/directory.py
+++ b/swh/web/api/views/directory.py
@@ -10,8 +10,8 @@
 from swh.web.api.views.utils import api_lookup
 
 
-@api_route(r'/directory/(?P<sha1_git>[0-9a-f]+)/', 'api-directory')
-@api_route(r'/directory/(?P<sha1_git>[0-9a-f]+)/(?P<path>.+)/',
+@api_route(r'/directory/(?P<sha1_git>[0-9a-fA-F]+)/', 'api-directory')
+@api_route(r'/directory/(?P<sha1_git>[0-9a-fA-F]+)/(?P<path>.+)/',
            'api-directory')
 @api_doc('/directory/')
 def api_directory(request, sha1_git, path=None):
diff --git a/swh/web/api/views/release.py b/swh/web/api/views/release.py
--- a/swh/web/api/views/release.py
+++ b/swh/web/api/views/release.py
@@ -10,7 +10,7 @@
 from swh.web.api.views.utils import api_lookup
 
 
-@api_route(r'/release/(?P<sha1_git>[0-9a-f]+)/', 'api-release')
+@api_route(r'/release/(?P<sha1_git>[0-9a-fA-F]+)/', 'api-release')
 @api_doc('/release/')
 def api_release(request, sha1_git):
     """
diff --git a/swh/web/api/views/revision.py b/swh/web/api/views/revision.py
--- a/swh/web/api/views/revision.py
+++ b/swh/web/api/views/revision.py
@@ -271,7 +271,7 @@
         enrich_fn=utils.enrich_revision)
 
 
-@api_route(r'/revision/(?P<sha1_git>[0-9a-f]+)/', 'api-revision')
+@api_route(r'/revision/(?P<sha1_git>[0-9a-fA-F]+)/', 'api-revision')
 @api_doc('/revision/')
 def api_revision(request, sha1_git):
     """
@@ -326,7 +326,7 @@
         enrich_fn=utils.enrich_revision)
 
 
-@api_route(r'/revision/(?P<sha1_git>[0-9a-f]+)/raw/',
+@api_route(r'/revision/(?P<sha1_git>[0-9a-fA-F]+)/raw/',
            'api-revision-raw-message')
 @api_doc('/revision/raw/', tags=['hidden'], handle_response=True)
 def api_revision_raw_message(request, sha1_git):
@@ -340,9 +340,9 @@
     return response
 
 
-@api_route(r'/revision/(?P<sha1_git>[0-9a-f]+)/directory/',
+@api_route(r'/revision/(?P<sha1_git>[0-9a-fA-F]+)/directory/',
            'api-revision-directory')
-@api_route(r'/revision/(?P<sha1_git>[0-9a-f]+)/directory/(?P<dir_path>.+)/',
+@api_route(r'/revision/(?P<sha1_git>[0-9a-fA-F]+)/directory/(?P<dir_path>.+)/',
            'api-revision-directory')
 @api_doc('/revision/directory/')
 def api_revision_directory(request, sha1_git,
@@ -386,9 +386,9 @@
                                   with_data=with_data)
 
 
-@api_route(r'/revision/(?P<sha1_git>[0-9a-f]+)/log/', 'api-revision-log')
-@api_route(r'/revision/(?P<sha1_git>[0-9a-f]+)'
-           r'/prev/(?P<prev_sha1s>[0-9a-f/]+)/log/',
+@api_route(r'/revision/(?P<sha1_git>[0-9a-fA-F]+)/log/', 'api-revision-log')
+@api_route(r'/revision/(?P<sha1_git>[0-9a-fA-F]+)'
+           r'/prev/(?P<prev_sha1s>[0-9a-fA-F/]+)/log/',
            'api-revision-log')
 @api_doc('/revision/log/')
 def api_revision_log(request, sha1_git, prev_sha1s=None):
diff --git a/swh/web/api/views/snapshot.py b/swh/web/api/views/snapshot.py
--- a/swh/web/api/views/snapshot.py
+++ b/swh/web/api/views/snapshot.py
@@ -12,7 +12,7 @@
 from swh.web.api.views.utils import api_lookup
 
 
-@api_route(r'/snapshot/(?P<snapshot_id>[0-9a-f]+)/', 'api-snapshot')
+@api_route(r'/snapshot/(?P<snapshot_id>[0-9a-fA-F]+)/', 'api-snapshot')
 @api_doc('/snapshot/')
 def api_snapshot(request, snapshot_id):
     """
diff --git a/swh/web/browse/views/directory.py b/swh/web/browse/views/directory.py
--- a/swh/web/browse/views/directory.py
+++ b/swh/web/browse/views/directory.py
@@ -21,8 +21,8 @@
 from swh.web.browse.browseurls import browse_route
 
 
-@browse_route(r'directory/(?P<sha1_git>[0-9a-f]+)/',
-              r'directory/(?P<sha1_git>[0-9a-f]+)/(?P<path>.+)/',
+@browse_route(r'directory/(?P<sha1_git>[0-9a-fA-F]+)/',
+              r'directory/(?P<sha1_git>[0-9a-fA-F]+)/(?P<path>.+)/',
               view_name='browse-directory')
 def directory_browse(request, sha1_git, path=None):
     """Django view for browsing the content of a directory identified
diff --git a/swh/web/browse/views/release.py b/swh/web/browse/views/release.py
--- a/swh/web/browse/views/release.py
+++ b/swh/web/browse/views/release.py
@@ -18,7 +18,7 @@
 )
 
 
-@browse_route(r'release/(?P<sha1_git>[0-9a-f]+)/',
+@browse_route(r'release/(?P<sha1_git>[0-9a-fA-F]+)/',
               view_name='browse-release')
 def release_browse(request, sha1_git):
     """
diff --git a/swh/web/browse/views/revision.py b/swh/web/browse/views/revision.py
--- a/swh/web/browse/views/revision.py
+++ b/swh/web/browse/views/revision.py
@@ -136,7 +136,7 @@
     return mark_safe('\n'.join(changes_msg))
 
 
-@browse_route(r'revision/(?P<sha1_git>[0-9a-f]+)/diff/',
+@browse_route(r'revision/(?P<sha1_git>[0-9a-fA-F]+)/diff/',
               view_name='diff-revision')
 def _revision_diff(request, sha1_git):
     """
@@ -174,7 +174,7 @@
 NB_LOG_ENTRIES = 100
 
 
-@browse_route(r'revision/(?P<sha1_git>[0-9a-f]+)/log/',
+@browse_route(r'revision/(?P<sha1_git>[0-9a-fA-F]+)/log/',
               view_name='browse-revision-log')
 def revision_log_browse(request, sha1_git):
     """
@@ -252,8 +252,8 @@
                    'swh_ids': None})
 
 
-@browse_route(r'revision/(?P<sha1_git>[0-9a-f]+)/',
-              r'revision/(?P<sha1_git>[0-9a-f]+)/(?P<extra_path>.+)/',
+@browse_route(r'revision/(?P<sha1_git>[0-9a-fA-F]+)/',
+              r'revision/(?P<sha1_git>[0-9a-fA-F]+)/(?P<extra_path>.+)/',
               view_name='browse-revision')
 def revision_browse(request, sha1_git, extra_path=None):
     """
diff --git a/swh/web/browse/views/snapshot.py b/swh/web/browse/views/snapshot.py
--- a/swh/web/browse/views/snapshot.py
+++ b/swh/web/browse/views/snapshot.py
@@ -16,7 +16,7 @@
 )
 
 
-@browse_route(r'snapshot/(?P<snapshot_id>[0-9a-f]+)/',
+@browse_route(r'snapshot/(?P<snapshot_id>[0-9a-fA-F]+)/',
               view_name='browse-snapshot')
 def snapshot_browse(request, snapshot_id):
     """Django view for browsing the content of a snapshot.
@@ -29,8 +29,8 @@
     return redirect(browse_snapshot_url)
 
 
-@browse_route(r'snapshot/(?P<snapshot_id>[0-9a-f]+)/directory/',
-              r'snapshot/(?P<snapshot_id>[0-9a-f]+)/directory/(?P<path>.+)/',
+@browse_route(r'snapshot/(?P<snapshot_id>[0-9a-fA-F]+)/directory/',
+              r'snapshot/(?P<snapshot_id>[0-9a-fA-F]+)/directory/(?P<path>.+)/', # noqa
               view_name='browse-snapshot-directory')
 def snapshot_directory_browse(request, snapshot_id, path=None):
     """Django view for browsing the content of a directory collected
@@ -47,7 +47,7 @@
                                      origin_url=origin_url)
 
 
-@browse_route(r'snapshot/(?P<snapshot_id>[0-9a-f]+)/content/(?P<path>.+)/',
+@browse_route(r'snapshot/(?P<snapshot_id>[0-9a-fA-F]+)/content/(?P<path>.+)/',
               view_name='browse-snapshot-content')
 def snapshot_content_browse(request, snapshot_id, path):
     """Django view that produces an HTML display of a content
@@ -58,7 +58,7 @@
     return browse_snapshot_content(request, snapshot_id=snapshot_id, path=path)
 
 
-@browse_route(r'snapshot/(?P<snapshot_id>[0-9a-f]+)/log/',
+@browse_route(r'snapshot/(?P<snapshot_id>[0-9a-fA-F]+)/log/',
               view_name='browse-snapshot-log')
 def snapshot_log_browse(request, snapshot_id):
     """Django view that produces an HTML display of revisions history (aka
@@ -69,7 +69,7 @@
     return browse_snapshot_log(request, snapshot_id=snapshot_id)
 
 
-@browse_route(r'snapshot/(?P<snapshot_id>[0-9a-f]+)/branches/',
+@browse_route(r'snapshot/(?P<snapshot_id>[0-9a-fA-F]+)/branches/',
               view_name='browse-snapshot-branches')
 def snapshot_branches_browse(request, snapshot_id):
     """Django view that produces an HTML display of the list of releases
@@ -80,7 +80,7 @@
     return browse_snapshot_branches(request, snapshot_id=snapshot_id)
 
 
-@browse_route(r'snapshot/(?P<snapshot_id>[0-9a-f]+)/releases/',
+@browse_route(r'snapshot/(?P<snapshot_id>[0-9a-fA-F]+)/releases/',
               view_name='browse-snapshot-releases')
 def snapshot_releases_browse(request, snapshot_id):
     """Django view that produces an HTML display of the list of releases
diff --git a/swh/web/tests/api/views/test_directory.py b/swh/web/tests/api/views/test_directory.py
--- a/swh/web/tests/api/views/test_directory.py
+++ b/swh/web/tests/api/views/test_directory.py
@@ -15,8 +15,7 @@
 
 class DirectoryApiTestCase(WebTestCase, APITestCase):
 
-    @given(directory())
-    def test_api_directory(self, directory):
+    def _api_directory_test(self, directory):
 
         url = reverse('api-directory', url_args={'sha1_git': directory})
         rv = self.client.get(url)
@@ -29,6 +28,14 @@
 
         self.assertEqual(rv.data, expected_data)
 
+    @given(directory())
+    def test_api_directory(self, directory):
+        self._api_directory_test(directory)
+
+    @given(directory())
+    def test_api_directory_with_uppercase_sha1(self, directory):
+        self._api_directory_test(directory.upper())
+
     @given(unknown_directory())
     def test_api_directory_not_found(self, unknown_directory):
 
diff --git a/swh/web/tests/api/views/test_release.py b/swh/web/tests/api/views/test_release.py
--- a/swh/web/tests/api/views/test_release.py
+++ b/swh/web/tests/api/views/test_release.py
@@ -17,8 +17,7 @@
 
 class ReleaseApiTestCase(WebTestCase, APITestCase):
 
-    @given(release())
-    def test_api_release(self, release):
+    def _api_release_test(self, release):
 
         url = reverse('api-release', url_args={'sha1_git': release})
 
@@ -38,6 +37,14 @@
         self.assertEqual(rv['Content-Type'], 'application/json')
         self.assertEqual(rv.data, expected_release)
 
+    @given(release())
+    def test_api_release(self, release):
+        self._api_release_test(release)
+
+    @given(release())
+    def test_api_release_with_uppercase_sha1(self, release):
+        self._api_release_test(release.upper())
+
     @given(sha1(), sha1(), sha1(), content(), directory(), release())
     def test_api_release_target_type_not_a_revision(self, new_rel1, new_rel2,
                                                     new_rel3, content,
diff --git a/swh/web/tests/api/views/test_revision.py b/swh/web/tests/api/views/test_revision.py
--- a/swh/web/tests/api/views/test_revision.py
+++ b/swh/web/tests/api/views/test_revision.py
@@ -23,9 +23,7 @@
 
 class RevisionApiTestCase(WebTestCase, APITestCase):
 
-    @given(revision())
-    def test_api_revision(self, revision):
-
+    def _api_revision_test(self, revision):
         url = reverse('api-revision', url_args={'sha1_git': revision})
         rv = self.client.get(url)
 
@@ -37,6 +35,14 @@
         self.assertEqual(rv['Content-Type'], 'application/json')
         self.assertEqual(rv.data, expected_revision)
 
+    @given(revision())
+    def test_api_revision(self, revision):
+        self._api_revision_test(revision)
+
+    @given(revision())
+    def test_api_revision_with_uppercase_sha1(self, revision):
+        self._api_revision_test(revision.upper())
+
     @given(unknown_revision())
     def test_api_revision_not_found(self, unknown_revision):
 
diff --git a/swh/web/tests/api/views/test_snapshot.py b/swh/web/tests/api/views/test_snapshot.py
--- a/swh/web/tests/api/views/test_snapshot.py
+++ b/swh/web/tests/api/views/test_snapshot.py
@@ -87,8 +87,7 @@
         self.assertEqual(rv['Content-Type'], 'application/json')
         self.assertEqual(rv.data, whole_snapshot)
 
-    @given(snapshot())
-    def test_api_snapshot_filtered(self, snapshot):
+    def _api_snapshot_filtered_test(self, snapshot):
 
         snapshot_branches = []
 
@@ -114,6 +113,14 @@
         self.assertEqual(rv['Content-Type'], 'application/json')
         self.assertEqual(rv.data, expected_data)
 
+    @given(snapshot())
+    def test_api_snapshot_filtered(self, snapshot):
+        self._api_snapshot_filtered_test(snapshot)
+
+    @given(snapshot())
+    def test_api_snapshot_filtered_with_uppercase_sha1(self, snapshot):
+        self._api_snapshot_filtered_test(snapshot.upper())
+
     @given(unknown_snapshot())
     def test_api_snapshot_errors(self, unknown_snapshot):
 
diff --git a/swh/web/tests/browse/views/test_directory.py b/swh/web/tests/browse/views/test_directory.py
--- a/swh/web/tests/browse/views/test_directory.py
+++ b/swh/web/tests/browse/views/test_directory.py
@@ -93,6 +93,13 @@
     def test_root_directory_view(self, directory):
         self.directory_view(directory, self.directory_ls(directory))
 
+    @given(directory())
+    def test_directory_uppercase_sha1(self, directory):
+        directory = directory.upper()
+        directory_entries = self.directory_ls(directory)
+        directory_entries[0]['dir_id'] = directory
+        self.directory_view(directory, directory_entries)
+
     @given(directory_with_subdirs())
     def test_sub_directory_view(self, directory):
         dir_content = self.directory_ls(directory)
diff --git a/swh/web/tests/browse/views/test_release.py b/swh/web/tests/browse/views/test_release.py
--- a/swh/web/tests/browse/views/test_release.py
+++ b/swh/web/tests/browse/views/test_release.py
@@ -18,18 +18,27 @@
 
 class SwhBrowseReleaseTest(WebTestCase):
 
-    @given(release())
-    def test_release_browse(self, release):
+    def _release_browse_test(self, release, release_data):
 
         url = reverse('browse-release',
                       url_args={'sha1_git': release})
 
-        release_data = self.release_get(release)
-
         resp = self.client.get(url)
 
         self._release_browse_checks(resp, release_data)
 
+    @given(release())
+    def test_release_browse(self, release):
+        release_data = self.release_get(release)
+        self._release_browse_test(release, release_data)
+
+    @given(release())
+    def test_release_browse_with_uppercase_sha1(self, release):
+        release = release.upper()
+        release_data = self.release_get(release)
+        release_data['id'] = release
+        self._release_browse_test(release, release_data)
+
     @given(origin_with_release())
     def test_release_browse_with_origin(self, origin):
         snapshot = self.snapshot_get_latest(origin['id'])
diff --git a/swh/web/tests/browse/views/test_revision.py b/swh/web/tests/browse/views/test_revision.py
--- a/swh/web/tests/browse/views/test_revision.py
+++ b/swh/web/tests/browse/views/test_revision.py
@@ -18,8 +18,7 @@
 
 class SwhBrowseRevisionTest(WebTestCase):
 
-    @given(revision())
-    def test_revision_browse(self, revision):
+    def _revision_browse_test(self, revision):
 
         url = reverse('browse-revision',
                       url_args={'sha1_git': revision})
@@ -70,6 +69,14 @@
         self.assertContains(resp, escape(message_lines[0]))
         self.assertContains(resp, escape('\n'.join(message_lines[1:])))
 
+    @given(revision())
+    def test_revision_browse(self, revision):
+        self._revision_browse_test(revision)
+
+    @given(revision())
+    def test_revision_browse_with_uppercase_sha1(self, revision):
+        self._revision_browse_test(revision.upper())
+
     @given(origin())
     def test_revision_origin_browse(self, origin):
 
diff --git a/swh/web/urls.py b/swh/web/urls.py
--- a/swh/web/urls.py
+++ b/swh/web/urls.py
@@ -49,7 +49,7 @@
     url(r'^browse/', include('swh.web.browse.urls')),
     url(r'^$', default_view, name='swh-web-homepage'),
     url(r'^jsreverse/$', urls_js, name='js_reverse'),
-    url(r'^(?P<swh_id>swh:[0-9]+:[a-z]+:[0-9a-f]+.*)/$',
+    url(r'^(?P<swh_id>swh:[0-9]+:[a-z]+:[0-9a-fA-F]+.*)/$',
         swh_id_browse, name='browse-swh-id'),
     url(r'^coverage/$', swh_coverage, name='swh-coverage'),
     url(r'^jslicenses/$', jslicenses, name='jslicenses'),