1# Copyright 2012 Google Inc. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#    http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing,
10# software distributed under the License is distributed on an
11# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
12# either express or implied. See the License for the specific
13# language governing permissions and limitations under the License.
14
15"""Google Cloud Storage specific Files API calls."""
16
17
18
19
20
21__all__ = ['AuthorizationError',
22           'check_status',
23           'Error',
24           'FatalError',
25           'FileClosedError',
26           'ForbiddenError',
27           'NotFoundError',
28           'ServerError',
29           'TimeoutError',
30           'TransientError',
31          ]
32
33import httplib
34
35
36class Error(Exception):
37  """Base error for all gcs operations.
38
39  Error can happen on GAE side or GCS server side.
40  For details on a particular GCS HTTP response code, see
41  https://developers.google.com/storage/docs/reference-status#standardcodes
42  """
43
44
45class TransientError(Error):
46  """TransientError could be retried."""
47
48
49class TimeoutError(TransientError):
50  """HTTP 408 timeout."""
51
52
53class FatalError(Error):
54  """FatalError shouldn't be retried."""
55
56
57class FileClosedError(FatalError):
58  """File is already closed.
59
60  This can happen when the upload has finished but 'write' is called on
61  a stale upload handle.
62  """
63
64
65class NotFoundError(FatalError):
66  """HTTP 404 resource not found."""
67
68
69class ForbiddenError(FatalError):
70  """HTTP 403 Forbidden.
71
72  While GCS replies with a 403 error for many reasons, the most common one
73  is due to bucket permission not correctly setup for your app to access.
74  """
75
76
77class AuthorizationError(FatalError):
78  """HTTP 401 authentication required.
79
80  Unauthorized request has been received by GCS.
81
82  This error is mostly handled by GCS client. GCS client will request
83  a new access token and retry the request.
84  """
85
86
87class InvalidRange(FatalError):
88  """HTTP 416 RequestRangeNotSatifiable."""
89
90
91class ServerError(TransientError):
92  """HTTP >= 500 server side error."""
93
94
95def check_status(status, expected, path, headers=None,
96                 resp_headers=None, extras=None):
97  """Check HTTP response status is expected.
98
99  Args:
100    status: HTTP response status. int.
101    expected: a list of expected statuses. A list of ints.
102    path: filename or a path prefix.
103    headers: HTTP request headers.
104    resp_headers: HTTP response headers.
105    extras: extra info to be logged verbatim if error occurs.
106
107  Raises:
108    AuthorizationError: if authorization failed.
109    NotFoundError: if an object that's expected to exist doesn't.
110    TimeoutError: if HTTP request timed out.
111    ServerError: if server experienced some errors.
112    FatalError: if any other unexpected errors occurred.
113  """
114  if status in expected:
115    return
116
117  msg = ('Expect status %r from Google Storage. But got status %d.\n'
118         'Path: %r.\n'
119         'Request headers: %r.\n'
120         'Response headers: %r.\n'
121         'Extra info: %r.\n' %
122         (expected, status, path, headers, resp_headers, extras))
123
124  if status == httplib.UNAUTHORIZED:
125    raise AuthorizationError(msg)
126  elif status == httplib.FORBIDDEN:
127    raise ForbiddenError(msg)
128  elif status == httplib.NOT_FOUND:
129    raise NotFoundError(msg)
130  elif status == httplib.REQUEST_TIMEOUT:
131    raise TimeoutError(msg)
132  elif status == httplib.REQUESTED_RANGE_NOT_SATISFIABLE:
133    raise InvalidRange(msg)
134  elif (status == httplib.OK and 308 in expected and
135        httplib.OK not in expected):
136    raise FileClosedError(msg)
137  elif status >= 500:
138    raise ServerError(msg)
139  else:
140    raise FatalError(msg)
141