Skip to content

Commit

Permalink
Merge branch 'release-1.4.7' into develop
Browse files Browse the repository at this point in the history
* release-1.4.7:
  Bumping version to 1.4.7
  Update changelog with latest features
  Update models to the latest version
  Use status code/http msg for Code/Message
  Handle the case where we receive a generic html error response
  • Loading branch information
AWS committed Mar 24, 2016
2 parents 0d22abf + 5a344d4 commit 0f2a52f
Show file tree
Hide file tree
Showing 9 changed files with 779 additions and 2,279 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
CHANGELOG
=========

1.4.7 - (2016-03-24)
--------------------
* feature:``ElastiCache``: Update client to latest version
* feature:``RDS``: Update client to latest version
* feature:``StorageGateway``: Update client to latest version
* bugfix: Handle case where error response from proxy is received
(`issue 850 <https://github.com/boto/botocore/pull/850`__)

1.4.6 - (2016-03-22)
--------------------
* feature:``DeviceFarm``: Add support to pay a flat monthly fee for
Expand Down
2 changes: 1 addition & 1 deletion botocore/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import re
import logging

__version__ = '1.4.6'
__version__ = '1.4.7'


class NullHandler(logging.Handler):
Expand Down
2,732 changes: 521 additions & 2,211 deletions botocore/data/elasticache/2015-02-02/service-2.json

Large diffs are not rendered by default.

118 changes: 103 additions & 15 deletions botocore/data/rds/2014-10-31/service-2.json

Large diffs are not rendered by default.

137 changes: 89 additions & 48 deletions botocore/data/storagegateway/2013-06-30/service-2.json

Large diffs are not rendered by default.

32 changes: 31 additions & 1 deletion botocore/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,10 @@ def parse(self, response, shape):
LOG.debug('Response headers: %s', response['headers'])
LOG.debug('Response body:\n%s', response['body'])
if response['status_code'] >= 301:
parsed = self._do_error_parse(response, shape)
if self._is_generic_error_response(response):
parsed = self._do_generic_error_parse(response)
else:
parsed = self._do_error_parse(response, shape)
else:
parsed = self._do_parse(response, shape)
# Inject HTTPStatusCode key in the response metadata if the
Expand All @@ -213,6 +216,33 @@ def parse(self, response, shape):
response['status_code'])
return parsed

def _is_generic_error_response(self, response):
# There are times when a service will respond with a generic
# error response such as:
# '<html><body><b>Http/1.1 Service Unavailable</b></body></html>'
#
# This can also happen if you're going through a proxy.
# In this case the protocol specific _do_error_parse will either
# fail to parse the response (in the best case) or silently succeed
# and treat the HTML above as an XML response and return
# non sensical parsed data.
# To prevent this case from happening we first need to check
# whether or not this response looks like the generic response.
if response['status_code'] >= 500:
return response['body'].strip().startswith(b'<html>')

def _do_generic_error_parse(self, response):
# There's not really much we can do when we get a generic
# html response.
LOG.debug("Received a non protocol specific error response from the "
"service, unable to populate error code and message.")
return {
'Error': {'Code': str(response['status_code']),
'Message': six.moves.http_client.responses.get(
response['status_code'], '')},
'ResponseMetadata': {},
}

def _do_parse(self, response, shape):
raise NotImplementedError("%s._do_parse" % self.__class__.__name__)

Expand Down
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
# The short X.Y version.
version = '1.4'
# The full version, including alpha/beta/rc tags.
release = '1.4.6'
release = '1.4.7'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
4 changes: 2 additions & 2 deletions tests/functional/test_s3.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def test_multiple_transitions_returns_one(self):
' </NoncurrentVersionTransition>'
' </Rule>'
'</LifecycleConfiguration>'
)
).encode('utf-8')
http_response.headers = {}
self.http_session_send_mock.return_value = http_response
s3 = self.session.create_client('s3')
Expand Down Expand Up @@ -115,7 +115,7 @@ def test_500_error_with_non_xml_body(self):
'ETag: "a6d856bc171fc6aa1b236680856094e2"\r\n'
'Content-Length: 0\r\n'
'Server: AmazonS3\r\n'
)
).encode('utf-8')
http_500_response = mock.Mock()
http_500_response.status_code = 500
http_500_response.content = non_xml_content
Expand Down
23 changes: 23 additions & 0 deletions tests/unit/test_parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import datetime

from dateutil.tz import tzutc
from nose.tools import assert_equal

from botocore import parsers
from botocore import model
Expand Down Expand Up @@ -635,3 +636,25 @@ def test_can_parse_route53_with_missing_message(self):
# Even though there's no <Message /> we should
# still populate an empty string.
self.assertEqual(error['Message'], '')


def test_can_handle_generic_error_message():
# There are times when you can get a service to respond with a generic
# html error page. We should be able to handle this case.
for parser_cls in parsers.PROTOCOL_PARSERS.values():
yield _assert_parses_generic_error, parser_cls()


def _assert_parses_generic_error(parser):
# There are times when you can get a service to respond with a generic
# html error page. We should be able to handle this case.
body = (
'<html><body><b>Http/1.1 Service Unavailable</b></body></html>'
).encode('utf-8')
parsed = parser.parse({
'body': body, 'headers': {}, 'status_code': 503}, None)
assert_equal(
parsed,
{'Error': {'Code': '503', 'Message': 'Service Unavailable'},
'ResponseMetadata': {'HTTPStatusCode': 503}}
)

0 comments on commit 0f2a52f

Please sign in to comment.