# Copyright © 2015-2017 STRG.AT GmbH, Vienna, Austria
#
# This file is part of the The SCORE Framework.
#
# The SCORE Framework and all its parts are free software: you can redistribute
# them and/or modify them under the terms of the GNU Lesser General Public
# License version 3 as published by the Free Software Foundation which is in the
# file named COPYING.LESSER.txt.
#
# The SCORE Framework and all its parts are distributed without any WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. For more details see the GNU Lesser General Public
# License.
#
# If you have not received a copy of the GNU Lesser General Public License see
# http://www.gnu.org/licenses/.
#
# The License-Agreement realised between you as Licensee and STRG.AT GmbH as
# Licenser including the issue of its valid conclusion and its pre- and
# post-contractual effects is governed by the laws of Austria. Any disputes
# concerning this License-Agreement including the issue of its valid conclusion
# and its pre- and post-contractual effects are exclusively decided by the
# competent court, in whose district STRG.AT GmbH has its registered seat, at
# the discretion of STRG.AT GmbH also the competent court, in whose district the
# Licensee has his registered seat, an establishment or assets.
import threading
from http.client import HTTPConnection
from score.init import (
ConfiguredModule, parse_time_interval, parse_list, parse_host_port,
extract_conf)
defaults = {
'timeout': '5s',
'servers': [],
'header.domain': 'X-Purge-Domain',
'header.path': 'X-Purge-Path',
'header.type': 'X-Purge-Type',
}
[docs]def init(confdict):
"""
Initializes this module according to :ref:`our module initialization
guidelines <module_initialization>` with the following configuration keys:
:confkey:`servers` :confdefault:`[]`
A :func:`list <score.init.parse_list>` of Varnish hosts interpreted via
:func:`score.init.parse_host_port`.
:confkey:`timeout` :confdefault:`5s`
The :func:`timeout <score.init.parse_time_interval>` for sending
requests to a Varnish host passed to
:confkey:`header.domain` :confdefault:`X-Purge-Domain`
The header used for communicating the domain to purge.
:confkey:`header.path` :confdefault:`X-Purge-Path`
The header used for communicating the URL path to purge.
:confkey:`header.type` :confdefault:`X-Purge-Type`
The header that controls the :term:`purge type`.
"""
conf = dict(defaults.items())
conf.update(confdict)
servers = [parse_host_port(host) for host in parse_list(conf['servers'])]
timeout = parse_time_interval(conf['timeout'])
header_mapping = extract_conf(conf, 'header.')
return ConfiguredVarnishModule(servers, timeout, header_mapping)
class PurgeRequest(threading.Thread):
"""
A PurgeRequest handles a HTTP request with the method *PURGE* to a
Varnish_ server.
"""
def __init__(self, conf, server, domain, path, type):
super().__init__()
self.conf = conf
self.server = server
self.domain = domain
self.path = path
self.type = type
self.exception = None
self.response = None
def __repr__(self):
parts = ['server=%r']
args = [self.__class__.__name__, self.server]
if self.path is not None:
parts.append('path=%r')
args.append(self.path)
if self.domain is not None:
parts.append('domain=%r')
args.append(self.domain)
if self.type is not None:
parts.append('type=%r')
args.append(self.type)
tpl = '%s(' + ', '.join(parts) + ')'
return tpl % tuple(args)
def run(self):
try:
self.send()
except Exception as e:
self.conf.log.exception(e)
self.exception = e
def send(self):
"""
Sends the request to the provided :attr:`server`. Returns a
:class:`PurgeResponse` or raises a :class:`PurgeError`.
"""
self.conf.log.info(self)
headers = dict()
if self.domain:
headers[self.conf.header_mapping['domain']] = self.domain
if self.path:
headers[self.conf.header_mapping['path']] = self.path
if self.type:
headers[self.conf.header_mapping['type']] = self.type
connection = HTTPConnection(*self.server, timeout=self.conf.timeout)
try:
connection.request('GET', '/', headers=headers)
response = connection.getresponse()
finally:
connection.close()
self.response = response
self.conf.log.info(response)
if response.status is not 200:
raise PurgeError(response.reason)
[docs]class PurgeError(Exception):
"""
Thrown if a :term:`purge request` failed.
"""
def __init__(self, msg, causes=None):
"""
:param msg: The message.
:param causes: The list of causes.
"""
self.msg = msg
self.causes = causes