gs should retry on SSL read-operation-timed-out error.

Set "ssl.SSLError: ('The read operation timed out',)" as one
resumable error message.

BUG=chromium:642986
TEST=unit_test

Change-Id: I1b683d72ebe534ca60ae694aede15d91ad85c327
Reviewed-on: https://chromium-review.googlesource.com/399960
Commit-Ready: Dan Shi <dshi@google.com>
Tested-by: Ningning Xia <nxia@chromium.org>
Tested-by: Dan Shi <dshi@google.com>
Reviewed-by: Mike Frysinger <vapier@chromium.org>
(cherry picked from commit 14b255f36c4ca13f551ccca09ba3942df02e37cc)
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/2348398
Tested-by: Mike Frysinger <vapier@chromium.org>
diff --git a/lib/gs.py b/lib/gs.py
index 5b71c79..42f852e 100644
--- a/lib/gs.py
+++ b/lib/gs.py
@@ -547,6 +547,9 @@
           'ResumableUploadAbortException',
           'ResumableDownloadException',
           'ssl.SSLError: The read operation timed out',
+          # TODO: Error messages may change in different library versions,
+          # use regexes to match resumbale error messages.
+          'ssl.SSLError: (\'The read operation timed out\',)',
           'Unable to find the server',
           'doesn\'t match cloud-supplied digest',
           'ssl.SSLError: [Errno 8]',
diff --git a/lib/gs_unittest.py b/lib/gs_unittest.py
index 65ce93b..44204f3 100644
--- a/lib/gs_unittest.py
+++ b/lib/gs_unittest.py
@@ -936,6 +936,13 @@
     e = self._getException(['gsutil', 'cat', 'gs://totally/legit/uri'], error)
     self.assertEqual(self.ctx._RetryFilter(e), True)
 
+  def testRetrySSLTimeout(self):
+    """Verify retry behavior when read operation timed out."""
+    error = 'ssl.SSLError: (\'The read operation timed out\',)'
+    e = self._getException(['gsutil', 'cp', self.REMOTE_PATH, self.LOCAL_PATH],
+                           error)
+    self.assertEqual(self.ctx._RetryFilter(e), True)
+
 
 class GSContextTest(AbstractGSContextTest):
   """Tests for GSContext()"""