Merge branch 'kaedroho-frontendcache-without-requests'

pull/1551/head
Matt Westcott 2015-08-26 16:38:48 +01:00
commit bc9c7f3f01
6 zmienionych plików z 51 dodań i 52 usunięć

Wyświetl plik

@ -30,6 +30,7 @@ Changelog
* Fix: H2 elements in rich text fields were accidentally given a click() binding when put insite a collapsible multi field panel
* Fix: The wagtailimages module is now compatible with remote storage backends that do not allow reopening closed files
* Fix: Search no longer crashes when auto-indexing a model that doesn't have an id field (Scot Hacker)
* Fix: The `wagtailfrontendcache` module's HTTP backend has been rewritten to reliably direct requests to the configured cache hostname
1.0 (16.07.2015)

Wyświetl plik

@ -66,6 +66,7 @@ Bug fixes
* H2 elements in rich text fields were accidentally given a click() binding when put insite a collapsible multi field panel
* The ``wagtailimages`` module is now compatible with remote storage backends that do not allow reopening closed files
* Search no longer crashes when auto-indexing a model that doesn't have an ``id`` field
* The ``wagtailfrontendcache`` module's HTTP backend has been rewritten to reliably direct requests to the configured cache hostname
Upgrade considerations

Wyświetl plik

@ -33,7 +33,6 @@ install_requires = [
"beautifulsoup4>=4.3.2",
"html5lib==0.999",
"Unidecode>=0.04.14",
'requests>=2.0.0',
"Willow==0.2.1",
]

Wyświetl plik

@ -28,7 +28,6 @@ deps =
html5lib==0.999
Unidecode>=0.04.14
six==1.7.3
requests==2.3.0
elasticsearch==1.1.0
mock==1.0.1
python-dateutil==2.2

Wyświetl plik

@ -1,9 +1,11 @@
import logging
import requests
import json
from django.utils.six.moves.urllib.parse import urlparse
from django.utils.six.moves.urllib.parse import urlparse, urlunparse, urlencode
from django.utils.six.moves.urllib.request import Request, urlopen
from django.utils.six.moves.urllib.error import URLError, HTTPError
from requests.adapters import HTTPAdapter
from wagtail.wagtailcore import __version__
logger = logging.getLogger('wagtail.frontendcache')
@ -15,44 +17,41 @@ class BaseBackend(object):
class HTTPBackend(BaseBackend):
class CustomHTTPAdapter(HTTPAdapter):
"""
Requests will always send requests to whatever server is in the netloc
part of the URL. This is a problem with purging the cache as this netloc
may point to a different server (such as an nginx instance running in
front of the cache).
This class allows us to send a purge request directly to the cache server
with the host header still set correctly. It does this by changing the "url"
parameter of get_connection to always point to the cache server. Requests
will then use this connection to purge the page.
"""
def __init__(self, cache_url):
self.cache_url = cache_url
super(HTTPBackend.CustomHTTPAdapter, self).__init__()
def get_connection(self, url, proxies=None):
return super(HTTPBackend.CustomHTTPAdapter, self).get_connection(self.cache_url, proxies)
def __init__(self, params):
self.cache_location = params.pop('LOCATION')
self.session = requests.Session()
self.session.mount('http://', self.CustomHTTPAdapter(self.cache_location))
location_url_parsed = urlparse(params.pop('LOCATION'))
self.cache_scheme = location_url_parsed.scheme
self.cache_netloc = location_url_parsed.netloc
def purge(self, url):
try:
response = self.session.request('PURGE', url)
except requests.ConnectionError:
logger.error("Couldn't purge '%s' from HTTP cache: Connection error", url)
return
url_parsed = urlparse(url)
host = url_parsed.hostname
# Check for error
if response.status_code != 200:
logger.error("Couldn't purge '%s' from HTTP cache: Didn't recieve a 200 response (instead, we got '%d %s')", url, response.status_code, response.reason)
return
# Append port to host if it is set in the original URL
if url_parsed.port:
host += (':' + str(url_parsed.port))
request = Request(
url=urlunparse([
self.cache_scheme,
self.cache_netloc,
url_parsed.path,
url_parsed.params,
url_parsed.query,
url_parsed.fragment
]),
headers={
'Host': host,
'User-Agent': 'Wagtail-frontendcache/' + __version__
},
method='PURGE'
)
try:
urlopen(request)
except HTTPError as e:
logger.error("Couldn't purge '%s' from HTTP cache. HTTPError: %d %s", url, e.code, e.reason)
except URLError as e:
logger.error("Couldn't purge '%s' from HTTP cache. URLError: %s", url, e.reason)
class CloudflareBackend(BaseBackend):
@ -62,23 +61,21 @@ class CloudflareBackend(BaseBackend):
def purge(self, url):
try:
response = requests.post('https://www.cloudflare.com/api_json.html', {
response = urlopen('https://www.cloudflare.com/api_json.html', data=urlencode({
'email': self.cloudflare_email,
'tkn': self.cloudflare_token,
'a': 'zone_file_purge',
'z': urlparse(url).netloc,
'url': url
})
except requests.ConnectionError:
logger.error("Couldn't purge '%s' from Cloudflare: Connection error", url)
}).encode('utf-8'))
except HTTPError as e:
logger.error("Couldn't purge '%s' from Cloudflare. HTTPError: %d %s", url, e.code, e.reason)
return
except URLError as e:
logger.error("Couldn't purge '%s' from Cloudflare. URLError: %s", url, e.reason)
return
# Check for error
if response.status_code != 200:
logger.error("Couldn't purge '%s' from Cloudflare: Didn't recieve a 200 response (instead, we got '%d %s')", url, response.status_code, response.reason)
return
response_json = response.json()
response_json = json.loads(response.read().decode('utf-8'))
if response_json['result'] == 'error':
logger.error("Couldn't purge '%s' from Cloudflare: Cloudflare error '%s'", url, response_json['msg'])
logger.error("Couldn't purge '%s' from Cloudflare. Cloudflare error '%s'", url, response_json['msg'])
return

Wyświetl plik

@ -25,7 +25,8 @@ class TestBackendConfiguration(TestCase):
self.assertEqual(set(backends.keys()), set(['varnish']))
self.assertIsInstance(backends['varnish'], HTTPBackend)
self.assertEqual(backends['varnish'].cache_location, 'http://localhost:8000')
self.assertEqual(backends['varnish'].cache_scheme, 'http')
self.assertEqual(backends['varnish'].cache_netloc, 'localhost:8000')
def test_cloudflare(self):
backends = get_backends(backend_settings={
@ -78,7 +79,8 @@ class TestBackendConfiguration(TestCase):
self.assertEqual(set(backends.keys()), set(['default']))
self.assertIsInstance(backends['default'], HTTPBackend)
self.assertEqual(backends['default'].cache_location, 'http://localhost:8000')
self.assertEqual(backends['default'].cache_scheme, 'http')
self.assertEqual(backends['default'].cache_netloc, 'localhost:8000')
PURGED_URLS = []