Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Compress response's content according to client's accepted encoding
Currently Glance ignores the Accept-Encoding header and returns responses as they are regardless the client accepts gzip or other type of compression. This patch adds this capability to glance (by using a middleware) supporting just gzip for now. Important note: - The patch uses a lazy compression for Content-Type application/octet-stream but in order to do that, the content-length has to be unset which means that when an image is downloaded the content-length will be unknown to the client. Fixes bug: 1150380 Change-Id: Ieb65837d4e3fe310f97d9666882ecc572b14956a
- Loading branch information
Showing
5 changed files
with
127 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# vim: tabstop=4 shiftwidth=4 softtabstop=4 | ||
|
||
# Copyright 2013 Red Hat, Inc. | ||
# All Rights Reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); you may | ||
# not use this file except in compliance with the License. You may obtain | ||
# a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
# License for the specific language governing permissions and limitations | ||
# under the License. | ||
|
||
""" | ||
Use gzip compression if the client accepts it. | ||
""" | ||
|
||
import re | ||
|
||
from glance.common import wsgi | ||
import glance.openstack.common.log as logging | ||
|
||
LOG = logging.getLogger(__name__) | ||
|
||
|
||
class GzipMiddleware(wsgi.Middleware): | ||
|
||
re_zip = re.compile(r'\bgzip\b') | ||
|
||
def __init__(self, app): | ||
LOG.info(_("Initialized gzip middleware")) | ||
super(GzipMiddleware, self).__init__(app) | ||
|
||
def process_response(self, response): | ||
request = response.request | ||
accept_encoding = request.headers.get('Accept-Encoding', '') | ||
|
||
if self.re_zip.search(accept_encoding): | ||
# NOTE(flaper87): Webob removes the content-md5 when | ||
# app_iter is called. We'll keep it and reset it later | ||
checksum = response.headers.get("Content-MD5") | ||
|
||
# NOTE(flaper87): We'll use lazy for images so | ||
# that they can be compressed without reading | ||
# the whole content in memory. Notice that using | ||
# lazy will set response's content-length to 0. | ||
content_type = response.headers["Content-Type"] | ||
lazy = content_type == "application/octet-stream" | ||
|
||
# NOTE(flaper87): Webob takes care of the compression | ||
# process, it will replace the body either with a | ||
# compressed body or a generator - used for lazy com | ||
# pression - depending on the lazy value. | ||
# | ||
# Webob itself will set the Content-Encoding header. | ||
response.encode_content(lazy=lazy) | ||
|
||
if checksum: | ||
response.headers['Content-MD5'] = checksum | ||
|
||
return response |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# vim: tabstop=4 shiftwidth=4 softtabstop=4 | ||
|
||
# Copyright 2013 Red Hat, Inc | ||
# All Rights Reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); you may | ||
# not use this file except in compliance with the License. You may obtain | ||
# a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
# License for the specific language governing permissions and limitations | ||
# under the License. | ||
|
||
"""Tests gzip middleware.""" | ||
|
||
import httplib2 | ||
|
||
from glance.tests import functional | ||
from glance.tests import utils | ||
|
||
|
||
class GzipMiddlewareTest(functional.FunctionalTest): | ||
|
||
@utils.skip_if_disabled | ||
def test_gzip_requests(self): | ||
self.cleanup() | ||
self.start_servers(**self.__dict__.copy()) | ||
|
||
def request(path, headers=None): | ||
# We don't care what version we're using here so, | ||
# sticking with latest | ||
url = 'http://127.0.0.1:%s/v2/%s' % (self.api_port, path) | ||
http = httplib2.Http() | ||
return http.request(url, 'GET', headers=headers) | ||
|
||
# Accept-Encoding: Identity | ||
headers = {'Accept-Encoding': 'identity'} | ||
response, content = request('images', headers=headers) | ||
self.assertEqual(response.get("-content-encoding"), None) | ||
|
||
# Accept-Encoding: gzip | ||
headers = {'Accept-Encoding': 'gzip'} | ||
response, content = request('images', headers=headers) | ||
self.assertEqual(response.get("-content-encoding"), 'gzip') | ||
|
||
self.stop_servers() |