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           'InvalidRange',
28           'NotFoundError',
29           'ServerError',
30           'TimeoutError',
31           'TransientError',
32          ]
33
34import httplib
35
36
37class Error(Exception):
38  """Base error for all gcs operations.
39
40  Error can happen on GAE side or GCS server side.
41  For details on a particular GCS HTTP response code, see
42  https://developers.google.com/storage/docs/reference-status#standardcodes
43  """
44
45
46class TransientError(Error):
47  """TransientError could be retried."""
48
49
50class TimeoutError(TransientError):
51  """HTTP 408 timeout."""
52
53
54class FatalError(Error):
55  """FatalError shouldn't be retried."""
56
57
58class FileClosedError(FatalError):
59  """File is already closed.
60
61  This can happen when the upload has finished but 'write' is called on
62  a stale upload handle.
63  """
64
65
66class NotFoundError(FatalError):
67  """HTTP 404 resource not found."""
68
69
70class ForbiddenError(FatalError):
71  """HTTP 403 Forbidden.
72
73  While GCS replies with a 403 error for many reasons, the most common one
74  is due to bucket permission not correctly setup for your app to access.
75  """
76
77
78class AuthorizationError(FatalError):
79  """HTTP 401 authentication required.
80
81  Unauthorized request has been received by GCS.
82
83  This error is mostly handled by GCS client. GCS client will request
84  a new access token and retry the request.
85  """
86
87
88class InvalidRange(FatalError):
89  """HTTP 416 RequestRangeNotSatifiable."""
90
91
92class ServerError(TransientError):
93  """HTTP >= 500 server side error."""
94
95
96def check_status(status, expected, path, headers=None,
97                 resp_headers=None, body=None, extras=None):
98  """Check HTTP response status is expected.
99
100  Args:
101    status: HTTP response status. int.
102    expected: a list of expected statuses. A list of ints.
103    path: filename or a path prefix.
104    headers: HTTP request headers.
105    resp_headers: HTTP response headers.
106    body: HTTP response body.
107    extras: extra info to be logged verbatim if error occurs.
108
109  Raises:
110    AuthorizationError: if authorization failed.
111    NotFoundError: if an object that's expected to exist doesn't.
112    TimeoutError: if HTTP request timed out.
113    ServerError: if server experienced some errors.
114    FatalError: if any other unexpected errors occurred.
115  """
116  if status in expected:
117    return
118
119  msg = ('Expect status %r from Google Storage. But got status %d.\n'
120         'Path: %r.\n'
121         'Request headers: %r.\n'
122         'Response headers: %r.\n'
123         'Body: %r.\n'
124         'Extra info: %r.\n' %
125         (expected, status, path, headers, resp_headers, body, extras))
126
127  if status == httplib.UNAUTHORIZED:
128    raise AuthorizationError(msg)
129  elif status == httplib.FORBIDDEN:
130    raise ForbiddenError(msg)
131  elif status == httplib.NOT_FOUND:
132    raise NotFoundError(msg)
133  elif status == httplib.REQUEST_TIMEOUT:
134    raise TimeoutError(msg)
135  elif status == httplib.REQUESTED_RANGE_NOT_SATISFIABLE:
136    raise InvalidRange(msg)
137  elif (status == httplib.OK and 308 in expected and
138        httplib.OK not in expected):
139    raise FileClosedError(msg)
140  elif status >= 500:
141    raise ServerError(msg)
142  else:
143    raise FatalError(msg)
144