<commit_before>#!/usr/bin/python

# Author: <NAME> (<EMAIL>)
# Copyright (c) 2012, Zebrafish Labs Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 	Redistributions of source code must retain the above copyright notice,
# 	this list of conditions and the following disclaimer.
#
# 	Redistributions in binary form must reproduce the above copyright notice,
# 	this list of conditions and the following disclaimer in the documentation
# 	and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

from datetime import datetime
import httplib2
import json
import re
import urllib

from version import __version__

FASTLY_SCHEME = "https"
FASTLY_HOST = "api.fastly.com"

FASTLY_SESSION_REGEX = re.compile("(fastly\.session=[^;]+);")


class FastlyRoles(object):
	USER = "user"
	BILLING = "billing"
	ENGINEER = "engineer"
	SUPERUSER = "superuser"


class FastlyCacheSettingsAction(object):
	CACHE = "cache"
	PASS = "pass"
	RESTART = "restart"


class FastlyConditionType(object):
	RESPONSE = "response"
	CACHE = "cache"
	REQUEST = "request"
	FETCH = "fetch"


class FastlyHeaderAction(object):
	SET = "set"
	APPEND = "append"
	DELETE = "delete"
	REGEX = "regex"
	REGEX_ALL = "regex_repeat"


class FastlyHeaderType(object):
	RESPONSE = "response"
	FETCH = "fetch"
	CACHE = "cache"
	REQUEST = "request"


class FastlyRequestSettingAction(object):
	LOOKUP = "lookup"
	PASS = "pass"


class FastlyForwardedForAction(object):
	CLEAR = "clear"
	LEAVE = "leave"
	APPEND = "append"
	APPEND_ALL = "append_all"
	OVERWRITE = "overwrite"


class FastlyStatsType(object):
	ALL = "all"
	DAILY = "daily"
	HOURLY = "hourly"
	MINUTELY = "minutely"


class FastlyDirectorType(object):
	RANDOM = 1
	ROUNDROBIN = 2
	HASH = 3
	CLIENT = 4


class FastlyConnection(object):
	def __init__(self, api_key):
		self._session = None
		self._api_key = api_key
		self._fully_authed = False

	@property
	def fully_authed(self):
		return self._fully_authed

	def login(self, user, password):
		body = self._formdata({
			"user": user,
			"password": password,
		}, ["user", "password"])
		content = self._fetch("/login", method="POST", body=body)
		self._fully_authed = True
		return FastlySession(self, content)

	def list_backends(self, service_id, version_number):
		"""List all backends for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/backend" % (service_id, version_number))
		return map(lambda x: FastlyBackend(self, x), content)

	def create_backend(
		self,
		service_id,
		version_number,
		name,
		address,
		use_ssl=False,
		port=80,
		connect_timeout=1000,
		first_byte_timeout=15000,
		between_bytes_timeout=10000,
		error_threshold=0,
		max_conn=20,
		weight=100,
		auto_loadbalance=False,
		shield=None,
		request_condition=None,
		healthcheck=None,
		comment=None):
		"""Create a backend for a particular service and version."""
		body = self._formdata({
			"name": name,
			"address": address,
			"use_ssl": use_ssl,
			"port": port,
			"connect_timeout": connect_timeout,
			"first_byte_timeout": first_byte_timeout,
			"between_bytes_timeout": between_bytes_timeout,
			"error_threshold": error_threshold,
			"max_conn": max_conn,
			"weight": weight,
			"auto_loadbalance": auto_loadbalance,
			"shield": shield,
			"request_condition": request_condition,
			"healthcheck": healthcheck,
			"comment": comment,
		}, FastlyBackend.FIELDS)
		content = self._fetch("/service/%s/version/%d/backend" % (service_id, version_number), method="POST", body=body)
		return FastlyBackend(self, content)

	def get_backend(self, service_id, version_number, name):
		"""Get the backend for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/backend/%s" % (service_id, version_number, urllib.quote(name)))
		return FastlyBackend(self, content)

	def update_backend(self, service_id, version_number, name_key, **kwargs):
		"""Update the backend for a particular service and version."""
		body = self._formdata(kwargs, FastlyBackend.FIELDS)
		content = self._fetch("/service/%s/version/%d/backend/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body)
		return FastlyBackend(self, content)

	def delete_backend(self, service_id, version_number, name):
		"""Delete the backend for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/backend/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE")
		return self._status(content)

	def check_backends(self, service_id, version_number):
		"""Performs a health check against each backend in version. If the backend has a specific type of healthcheck, that one is performed, otherwise a HEAD request to / is performed. The first item is the details on the Backend itself. The second item is details of the specific HTTP request performed as a health check. The third item is the response details."""
		content = self._fetch("/service/%s/version/%d/backend/check_all" % (service_id, version_number))
		# TODO: Use a strong-typed class for output?
		return content

	def list_cache_settings(self, service_id, version_number):
		"""Get a list of all cache settings for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/cache_settings" % (service_id, version_number))
		return map(lambda x: FastlyCacheSettings(self, x), content)

	def create_cache_settings(
		self,
		service_id,
		version_number,
		name,
		action,
		ttl=None,
		stale_ttl=None,
		cache_condition=None):
		"""Create a new cache settings object."""
		body = self._formdata({
			"name": name,
			"action": action,
			"ttl": ttl,
			"stale_ttl": stale_ttl,
			"cache_condition": cache_condition,
		}, FastlyCacheSettings.FIELDS)
		content = self._fetch("/service/%s/version/%d/cache_settings" % (service_id, version_number), method="POST", body=body)
		return FastlyCacheSettings(self, content)

	def get_cache_settings(self, service_id, version_number, name):
		"""Get a specific cache settings object."""
		content = self._fetch("/service/%s/version/%d/cache_settings/%s" % (service_id, version_number, urllib.quote(name)))
		return FastlyCacheSettings(self, content)

	def update_cache_settings(self, service_id, version_number, name_key, **kwargs):
		"""Update a specific cache settings object."""
		body = self._formdata(kwargs, FastlyCacheSettings.FIELDS)
		content = self._fetch("/service/%s/version/%d/cache_settings/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body)
		return FastlyCacheSettings(self, content)

	def delete_cache_settings(self, service_id, version_number, name):
		"""Delete a specific cache settings object."""
		content = self._fetch("/service/%s/version/%d/cache_settings/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE")
		return self._status(content)

	def list_conditions(self, service_id, version_number):
		"""Gets all conditions for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/condition" % (service_id, version_number))
		return map(lambda x: FastlyCondition(self, x), content)

	def create_condition(
		self,
		service_id,
		version_number,
		name,
		_type,
		statement,
		priority="10",
		comment=None):
		"""Creates a new condition."""
		body = self._formdata({
			"name": name,
			"type": _type,
			"statement": statement,
			"priority": priority,
			"comment": comment,
		}, FastlyCondition.FIELDS)
		content = self._fetch("/service/%s/version/%d/condition" % (service_id, version_number), method="POST", body=body)
		return FastlyCondition(self, content)

	def get_condition(self, service_id, version_number, name):
		"""Gets a specified condition."""
		content = self._fetch("/service/%s/version/%d/condition/%s" % (service_id, version_number, urllib.quote(name)))
		return FastlyCondition(self, content)

	def update_condition(self, service_id, version_number, name_key, **kwargs):
		"""Updates the specified condition."""
		body = self._formdata(kwargs, FastlyCondition.FIELDS)
		content = self._fetch("/service/%s/version/%d/condition/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body)
		return FastlyCondition(self, content)

	def delete_condition(self, service_id, version_number, name):
		"""Deletes the specified condition."""
		content = self._fetch("/service/%s/version/%d/condition/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE")
		return self._status(content)

	def content_edge_check(self, url):
		"""Retrieve headers and MD5 hash of the content for a particular url from each Fastly edge server."""
		prefixes = ["http://", "https://"]
		for prefix in prefixes:
			if url.startswith(prefix):
				url = url[len(prefix):]
				break
		content = self._fetch("/content/edge_check/%s" % url)
		return content

	def get_current_customer(self):
		"""Get the logged in customer."""
		content = self._fetch("/current_customer")
		return FastlyCustomer(self, content)

	def get_customer(self, customer_id):
		"""Get a specific customer."""
		content = self._fetch("/customer/%s" % customer_id)
		return FastlyCustomer(self, content)

	def get_customer_details(self, customer_id):
		"""Get a specific customer, owner, and billing contact."""
		content = self._fetch("/customer/details/%s" % customer_id)
		return content

	def list_customer_users(self, customer_id):
		"""List all users from a specified customer id."""
		content = self._fetch("/customer/users/%s" % customer_id)
		return map(lambda x: FastlyUser(self, x), content)

	def update_customer(self, customer_id, **kwargs):
		"""Update a customer."""
		body = self._formdata(kwargs, FastlyCustomer.FIELDS)
		content = self._fetch("/customer/%s" % customer_id, method="PUT", body=body)
		return FastlyCustomer(self, content)

	def delete_customer(self, customer_id):
		"""Delete a customer."""
		content = self._fetch("/customer/%s" % customer_id, method="DELETE")
		return self._status(content)

	def list_directors(self, service_id, version_number):
		"""List the directors for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/director" % (service_id, version_number))
		return map(lambda x: FastlyDirector(self, x), content)

	def create_director(
		self,
		service_id,
		version_number,
		name,
		quorum=75,
		_type=FastlyDirectorType.RANDOM,
		retries=5,
		shield=None):
		"""Create a director for a particular service and version."""
		body = self._formdata({
			"name": name,
			"quorum": quorum,
			"type": _type,
			"retries": retries,
			"shield": shield,

		}, FastlyDirector.FIELDS)
		content = self._fetch("/service/%s/version/%d/director" % (service_id, version_number), method="POST", body=body)
		return FastlyDirector(self, content)

	def get_director(self, service_id, version_number, name):
		"""Get the director for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/director/%s" % (service_id, version_number, urllib.quote(name)))
		return FastlyDirector(self, content)

	def update_director(self, service_id, version_number, name_key, **kwargs):
		"""Update the director for a particular service and version."""
		body = self._formdata(kwargs, FastlyDirector.FIELDS)
		content = self._fetch("/service/%s/version/%d/director/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body)
		return FastlyDirector(self, content)

	def delete_director(self, service_id, version_number, name):
		"""Delete the director for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/director/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE")
		return self._status(content)

	def get_director_backend(self, service_id, version_number, director_name, backend_name):
		"""Returns the relationship between a Backend and a Director. If the Backend has been associated with the Director, it returns a simple record indicating this. Otherwise, returns a 404."""
		content = self._fetch("/service/%s/version/%d/director/%s/backend/%s" % (service_id, version_number, director_name, urllib.quote(backend_name)), method="GET")
		return FastlyDirectorBackend(self, content)

	def create_director_backend(self, service_id, version_number, director_name, backend_name):
		"""Establishes a relationship between a Backend and a Director. The Backend is then considered a member of the Director and can be used to balance traffic onto."""
		content = self._fetch("/service/%s/version/%d/director/%s/backend/%s" % (service_id, version_number, director_name, urllib.quote(backend_name)), method="POST")
		return FastlyDirectorBackend(self, content)
	
	def delete_director_backend(self, service_id, version_number, director_name, backend_name):
		"""Deletes the relationship between a Backend and a Director. The Backend is no longer considered a member of the Director and thus will not have traffic balanced onto it from this Director."""
		content = self._fetch("/service/%s/version/%d/director/%s/backend/%s" % (service_id, version_number, director_name, urllib.quote(backend_name)), method="DELETE")
		return self._status(content)

	def list_domains(self, service_id, version_number):
		"""List the domains for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/domain" % (service_id, version_number))
		return map(lambda x: FastlyDomain(self, x), content)

	def create_domain(
		self,
		service_id,
		version_number,
		name,
		comment=None):
		"""Create a domain for a particular service and version."""
		body = self._formdata({
			"name": name,
			"comment": comment,

		}, FastlyDomain.FIELDS)
		content = self._fetch("/service/%s/version/%d/domain" % (service_id, version_number), method="POST", body=body)
		return FastlyDomain(self, content)

	def get_domain(self, service_id, version_number, name):
		"""Get the domain for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/domain/%s" % (service_id, version_number, urllib.quote(name)))
		return FastlyDomain(self, content)

	def update_domain(self, service_id, version_number, name_key, **kwargs):
		"""Update the domain for a particular service and version."""
		body = self._formdata(kwargs, FastlyDomain.FIELDS)
		content = self._fetch("/service/%s/version/%d/domain/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body)
		return FastlyDomain(self, content)

	def delete_domain(self, service_id, version_number, name):
		"""Delete the domain for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/domain/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE")
		return self._status(content)

	def check_domain(self, service_id, version_number, name):
		"""Checks the status of a domain's DNS record. Returns an array of 3 items. The first is the details for the domain. The second is the current CNAME of the domain. The third is a boolean indicating whether or not it has been properly setup to use Fastly."""
		content = self._fetch("/service/%s/version/%d/domain/%s/check" % (service_id, version_number, urllib.quote(name)))
		return FastlyDomainCheck(self, content)

	def check_domains(self, service_id, version_number):
		"""Checks the status of all domain DNS records for a Service Version. Returns an array items in the same format as the single domain /check."""
		content = self._fetch("/service/%s/version/%d/domain/check_all" % (service_id, version_number))
		return map(lambda x: FastlyDomainCheck(self, x), content)

	def get_event_log(self, object_id):
		"""Get the specified event log."""
		content = self._fetch("/event_log/%s" % object_id, method="GET")
		return FastlyEventLog(self, content)

	def list_gzip(self, service_id, version_number):
		"""List all gzip configurations for a particular service and version"""
		content = self._fetch("/service/%s/version/%d/gzip" % (service_id, version_number))
		return map(lambda x: FastlyGzip(self, x), content)

	def create_gzip(self, service_id, version_number, name, cache_condition=None, content_types=None, extensions=None):
		body = self._formdata({
			"name": name,
			"cache_condition": cache_condition,
			"content_types": content_types,
			"extensions": extensions
		}, FastlyGzip.FIELDS)
		"""Creates a new Gzip object."""
		content = self._fetch("/service/%s/version/%d/gzip" % (service_id, version_number), method="POST", body=body)
		return FastlyGzip(self, content)

	def get_gzip(self, service_id, version_number, name):
		"""Retrieves a Header object by name."""
		content = self._fetch("/service/%s/version/%d/gzip/%s" % (service_id, version_number, urllib.quote(name)))
		return FastlyGzip(self, content)

	def update_gzip(self, service_id, version_number, name_key, **kwargs):
		"""Modifies an existing Gzip object by name."""
		body = self._formdata(kwargs, FastlyGzip.FIELDS)
		content = self._fetch("/service/%s/version/%d/gzip/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body)
		return FastlyGzip(self, content)

	def delete_gzip(self, service_id, version_number, name):
		"""Deletes a Gzip object by name."""
		content = self._fetch("/service/%s/version/%d/gzip/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE")
		return self._status(content)

	def list_headers(self, service_id, version_number):
		"""Retrieves all Header objects for a particular Version of a Service."""
		content = self._fetch("/service/%s/version/%d/header" % (service_id, version_number))
		return map(lambda x: FastlyHeader(self, x), content)

	def create_header(self, service_id, version_number, name, destination, source, _type=FastlyHeaderType.RESPONSE, action=FastlyHeaderAction.SET, regex=None, substitution=None, ignore_if_set=None, priority=10, response_condition=None, cache_condition=None, request_condition=None):
		body = self._formdata({
			"name": name,
			"dst": destination,
			"src": source,
			"type": _type,
			"action": action,
			"regex": regex,<commit_msg>Use the same keyword name in create_header and update_header<commit_after>#!/usr/bin/python

# Author: <NAME> (<EMAIL>)
# Copyright (c) 2012, Zebrafish Labs Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 	Redistributions of source code must retain the above copyright notice,
# 	this list of conditions and the following disclaimer.
#
# 	Redistributions in binary form must reproduce the above copyright notice,
# 	this list of conditions and the following disclaimer in the documentation
# 	and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

from datetime import datetime
import httplib2
import json
import re
import urllib

from version import __version__

FASTLY_SCHEME = "https"
FASTLY_HOST = "api.fastly.com"

FASTLY_SESSION_REGEX = re.compile("(fastly\.session=[^;]+);")


class FastlyRoles(object):
	USER = "user"
	BILLING = "billing"
	ENGINEER = "engineer"
	SUPERUSER = "superuser"


class FastlyCacheSettingsAction(object):
	CACHE = "cache"
	PASS = "pass"
	RESTART = "restart"


class FastlyConditionType(object):
	RESPONSE = "response"
	CACHE = "cache"
	REQUEST = "request"
	FETCH = "fetch"


class FastlyHeaderAction(object):
	SET = "set"
	APPEND = "append"
	DELETE = "delete"
	REGEX = "regex"
	REGEX_ALL = "regex_repeat"


class FastlyHeaderType(object):
	RESPONSE = "response"
	FETCH = "fetch"
	CACHE = "cache"
	REQUEST = "request"


class FastlyRequestSettingAction(object):
	LOOKUP = "lookup"
	PASS = "pass"


class FastlyForwardedForAction(object):
	CLEAR = "clear"
	LEAVE = "leave"
	APPEND = "append"
	APPEND_ALL = "append_all"
	OVERWRITE = "overwrite"


class FastlyStatsType(object):
	ALL = "all"
	DAILY = "daily"
	HOURLY = "hourly"
	MINUTELY = "minutely"


class FastlyDirectorType(object):
	RANDOM = 1
	ROUNDROBIN = 2
	HASH = 3
	CLIENT = 4


class FastlyConnection(object):
	def __init__(self, api_key):
		self._session = None
		self._api_key = api_key
		self._fully_authed = False

	@property
	def fully_authed(self):
		return self._fully_authed

	def login(self, user, password):
		body = self._formdata({
			"user": user,
			"password": password,
		}, ["user", "password"])
		content = self._fetch("/login", method="POST", body=body)
		self._fully_authed = True
		return FastlySession(self, content)

	def list_backends(self, service_id, version_number):
		"""List all backends for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/backend" % (service_id, version_number))
		return map(lambda x: FastlyBackend(self, x), content)

	def create_backend(
		self,
		service_id,
		version_number,
		name,
		address,
		use_ssl=False,
		port=80,
		connect_timeout=1000,
		first_byte_timeout=15000,
		between_bytes_timeout=10000,
		error_threshold=0,
		max_conn=20,
		weight=100,
		auto_loadbalance=False,
		shield=None,
		request_condition=None,
		healthcheck=None,
		comment=None):
		"""Create a backend for a particular service and version."""
		body = self._formdata({
			"name": name,
			"address": address,
			"use_ssl": use_ssl,
			"port": port,
			"connect_timeout": connect_timeout,
			"first_byte_timeout": first_byte_timeout,
			"between_bytes_timeout": between_bytes_timeout,
			"error_threshold": error_threshold,
			"max_conn": max_conn,
			"weight": weight,
			"auto_loadbalance": auto_loadbalance,
			"shield": shield,
			"request_condition": request_condition,
			"healthcheck": healthcheck,
			"comment": comment,
		}, FastlyBackend.FIELDS)
		content = self._fetch("/service/%s/version/%d/backend" % (service_id, version_number), method="POST", body=body)
		return FastlyBackend(self, content)

	def get_backend(self, service_id, version_number, name):
		"""Get the backend for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/backend/%s" % (service_id, version_number, urllib.quote(name)))
		return FastlyBackend(self, content)

	def update_backend(self, service_id, version_number, name_key, **kwargs):
		"""Update the backend for a particular service and version."""
		body = self._formdata(kwargs, FastlyBackend.FIELDS)
		content = self._fetch("/service/%s/version/%d/backend/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body)
		return FastlyBackend(self, content)

	def delete_backend(self, service_id, version_number, name):
		"""Delete the backend for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/backend/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE")
		return self._status(content)

	def check_backends(self, service_id, version_number):
		"""Performs a health check against each backend in version. If the backend has a specific type of healthcheck, that one is performed, otherwise a HEAD request to / is performed. The first item is the details on the Backend itself. The second item is details of the specific HTTP request performed as a health check. The third item is the response details."""
		content = self._fetch("/service/%s/version/%d/backend/check_all" % (service_id, version_number))
		# TODO: Use a strong-typed class for output?
		return content

	def list_cache_settings(self, service_id, version_number):
		"""Get a list of all cache settings for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/cache_settings" % (service_id, version_number))
		return map(lambda x: FastlyCacheSettings(self, x), content)

	def create_cache_settings(
		self,
		service_id,
		version_number,
		name,
		action,
		ttl=None,
		stale_ttl=None,
		cache_condition=None):
		"""Create a new cache settings object."""
		body = self._formdata({
			"name": name,
			"action": action,
			"ttl": ttl,
			"stale_ttl": stale_ttl,
			"cache_condition": cache_condition,
		}, FastlyCacheSettings.FIELDS)
		content = self._fetch("/service/%s/version/%d/cache_settings" % (service_id, version_number), method="POST", body=body)
		return FastlyCacheSettings(self, content)

	def get_cache_settings(self, service_id, version_number, name):
		"""Get a specific cache settings object."""
		content = self._fetch("/service/%s/version/%d/cache_settings/%s" % (service_id, version_number, urllib.quote(name)))
		return FastlyCacheSettings(self, content)

	def update_cache_settings(self, service_id, version_number, name_key, **kwargs):
		"""Update a specific cache settings object."""
		body = self._formdata(kwargs, FastlyCacheSettings.FIELDS)
		content = self._fetch("/service/%s/version/%d/cache_settings/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body)
		return FastlyCacheSettings(self, content)

	def delete_cache_settings(self, service_id, version_number, name):
		"""Delete a specific cache settings object."""
		content = self._fetch("/service/%s/version/%d/cache_settings/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE")
		return self._status(content)

	def list_conditions(self, service_id, version_number):
		"""Gets all conditions for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/condition" % (service_id, version_number))
		return map(lambda x: FastlyCondition(self, x), content)

	def create_condition(
		self,
		service_id,
		version_number,
		name,
		_type,
		statement,
		priority="10",
		comment=None):
		"""Creates a new condition."""
		body = self._formdata({
			"name": name,
			"type": _type,
			"statement": statement,
			"priority": priority,
			"comment": comment,
		}, FastlyCondition.FIELDS)
		content = self._fetch("/service/%s/version/%d/condition" % (service_id, version_number), method="POST", body=body)
		return FastlyCondition(self, content)

	def get_condition(self, service_id, version_number, name):
		"""Gets a specified condition."""
		content = self._fetch("/service/%s/version/%d/condition/%s" % (service_id, version_number, urllib.quote(name)))
		return FastlyCondition(self, content)

	def update_condition(self, service_id, version_number, name_key, **kwargs):
		"""Updates the specified condition."""
		body = self._formdata(kwargs, FastlyCondition.FIELDS)
		content = self._fetch("/service/%s/version/%d/condition/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body)
		return FastlyCondition(self, content)

	def delete_condition(self, service_id, version_number, name):
		"""Deletes the specified condition."""
		content = self._fetch("/service/%s/version/%d/condition/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE")
		return self._status(content)

	def content_edge_check(self, url):
		"""Retrieve headers and MD5 hash of the content for a particular url from each Fastly edge server."""
		prefixes = ["http://", "https://"]
		for prefix in prefixes:
			if url.startswith(prefix):
				url = url[len(prefix):]
				break
		content = self._fetch("/content/edge_check/%s" % url)
		return content

	def get_current_customer(self):
		"""Get the logged in customer."""
		content = self._fetch("/current_customer")
		return FastlyCustomer(self, content)

	def get_customer(self, customer_id):
		"""Get a specific customer."""
		content = self._fetch("/customer/%s" % customer_id)
		return FastlyCustomer(self, content)

	def get_customer_details(self, customer_id):
		"""Get a specific customer, owner, and billing contact."""
		content = self._fetch("/customer/details/%s" % customer_id)
		return content

	def list_customer_users(self, customer_id):
		"""List all users from a specified customer id."""
		content = self._fetch("/customer/users/%s" % customer_id)
		return map(lambda x: FastlyUser(self, x), content)

	def update_customer(self, customer_id, **kwargs):
		"""Update a customer."""
		body = self._formdata(kwargs, FastlyCustomer.FIELDS)
		content = self._fetch("/customer/%s" % customer_id, method="PUT", body=body)
		return FastlyCustomer(self, content)

	def delete_customer(self, customer_id):
		"""Delete a customer."""
		content = self._fetch("/customer/%s" % customer_id, method="DELETE")
		return self._status(content)

	def list_directors(self, service_id, version_number):
		"""List the directors for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/director" % (service_id, version_number))
		return map(lambda x: FastlyDirector(self, x), content)

	def create_director(
		self,
		service_id,
		version_number,
		name,
		quorum=75,
		_type=FastlyDirectorType.RANDOM,
		retries=5,
		shield=None):
		"""Create a director for a particular service and version."""
		body = self._formdata({
			"name": name,
			"quorum": quorum,
			"type": _type,
			"retries": retries,
			"shield": shield,

		}, FastlyDirector.FIELDS)
		content = self._fetch("/service/%s/version/%d/director" % (service_id, version_number), method="POST", body=body)
		return FastlyDirector(self, content)

	def get_director(self, service_id, version_number, name):
		"""Get the director for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/director/%s" % (service_id, version_number, urllib.quote(name)))
		return FastlyDirector(self, content)

	def update_director(self, service_id, version_number, name_key, **kwargs):
		"""Update the director for a particular service and version."""
		body = self._formdata(kwargs, FastlyDirector.FIELDS)
		content = self._fetch("/service/%s/version/%d/director/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body)
		return FastlyDirector(self, content)

	def delete_director(self, service_id, version_number, name):
		"""Delete the director for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/director/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE")
		return self._status(content)

	def get_director_backend(self, service_id, version_number, director_name, backend_name):
		"""Returns the relationship between a Backend and a Director. If the Backend has been associated with the Director, it returns a simple record indicating this. Otherwise, returns a 404."""
		content = self._fetch("/service/%s/version/%d/director/%s/backend/%s" % (service_id, version_number, director_name, urllib.quote(backend_name)), method="GET")
		return FastlyDirectorBackend(self, content)

	def create_director_backend(self, service_id, version_number, director_name, backend_name):
		"""Establishes a relationship between a Backend and a Director. The Backend is then considered a member of the Director and can be used to balance traffic onto."""
		content = self._fetch("/service/%s/version/%d/director/%s/backend/%s" % (service_id, version_number, director_name, urllib.quote(backend_name)), method="POST")
		return FastlyDirectorBackend(self, content)
	
	def delete_director_backend(self, service_id, version_number, director_name, backend_name):
		"""Deletes the relationship between a Backend and a Director. The Backend is no longer considered a member of the Director and thus will not have traffic balanced onto it from this Director."""
		content = self._fetch("/service/%s/version/%d/director/%s/backend/%s" % (service_id, version_number, director_name, urllib.quote(backend_name)), method="DELETE")
		return self._status(content)

	def list_domains(self, service_id, version_number):
		"""List the domains for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/domain" % (service_id, version_number))
		return map(lambda x: FastlyDomain(self, x), content)

	def create_domain(
		self,
		service_id,
		version_number,
		name,
		comment=None):
		"""Create a domain for a particular service and version."""
		body = self._formdata({
			"name": name,
			"comment": comment,

		}, FastlyDomain.FIELDS)
		content = self._fetch("/service/%s/version/%d/domain" % (service_id, version_number), method="POST", body=body)
		return FastlyDomain(self, content)

	def get_domain(self, service_id, version_number, name):
		"""Get the domain for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/domain/%s" % (service_id, version_number, urllib.quote(name)))
		return FastlyDomain(self, content)

	def update_domain(self, service_id, version_number, name_key, **kwargs):
		"""Update the domain for a particular service and version."""
		body = self._formdata(kwargs, FastlyDomain.FIELDS)
		content = self._fetch("/service/%s/version/%d/domain/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body)
		return FastlyDomain(self, content)

	def delete_domain(self, service_id, version_number, name):
		"""Delete the domain for a particular service and version."""
		content = self._fetch("/service/%s/version/%d/domain/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE")
		return self._status(content)

	def check_domain(self, service_id, version_number, name):
		"""Checks the status of a domain's DNS record. Returns an array of 3 items. The first is the details for the domain. The second is the current CNAME of the domain. The third is a boolean indicating whether or not it has been properly setup to use Fastly."""
		content = self._fetch("/service/%s/version/%d/domain/%s/check" % (service_id, version_number, urllib.quote(name)))
		return FastlyDomainCheck(self, content)

	def check_domains(self, service_id, version_number):
		"""Checks the status of all domain DNS records for a Service Version. Returns an array items in the same format as the single domain /check."""
		content = self._fetch("/service/%s/version/%d/domain/check_all" % (service_id, version_number))
		return map(lambda x: FastlyDomainCheck(self, x), content)

	def get_event_log(self, object_id):
		"""Get the specified event log."""
		content = self._fetch("/event_log/%s" % object_id, method="GET")
		return FastlyEventLog(self, content)

	def list_gzip(self, service_id, version_number):
		"""List all gzip configurations for a particular service and version"""
		content = self._fetch("/service/%s/version/%d/gzip" % (service_id, version_number))
		return map(lambda x: FastlyGzip(self, x), content)

	def create_gzip(self, service_id, version_number, name, cache_condition=None, content_types=None, extensions=None):
		body = self._formdata({
			"name": name,
			"cache_condition": cache_condition,
			"content_types": content_types,
			"extensions": extensions
		}, FastlyGzip.FIELDS)
		"""Creates a new Gzip object."""
		content = self._fetch("/service/%s/version/%d/gzip" % (service_id, version_number), method="POST", body=body)
		return FastlyGzip(self, content)

	def get_gzip(self, service_id, version_number, name):
		"""Retrieves a Header object by name."""
		content = self._fetch("/service/%s/version/%d/gzip/%s" % (service_id, version_number, urllib.quote(name)))
		return FastlyGzip(self, content)

	def update_gzip(self, service_id, version_number, name_key, **kwargs):
		"""Modifies an existing Gzip object by name."""
		body = self._formdata(kwargs, FastlyGzip.FIELDS)
		content = self._fetch("/service/%s/version/%d/gzip/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body)
		return FastlyGzip(self, content)

	def delete_gzip(self, service_id, version_number, name):
		"""Deletes a Gzip object by name."""
		content = self._fetch("/service/%s/version/%d/gzip/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE")
		return self._status(content)

	def list_headers(self, service_id, version_number):
		"""Retrieves all Header objects for a particular Version of a Service."""
		content = self._fetch("/service/%s/version/%d/header" % (service_id, version_number))
		return map(lambda x: FastlyHeader(self, x), content)

	def create_header(self, service_id, version_number, name, dst, src, _type=FastlyHeaderType.RESPONSE, action=FastlyHeaderAction.SET, regex=None, substitution=None, ignore_if_set=None, priority=10, response_condition=None, cache_condition=None, request_condition=None):
		body = self._formdata({
			"name": name,
			"dst": dst,
			"src": src,
			"type": _type,
			"action": action,
			"regex": regex,
{'fraction_non_alphanumeric': 0.12769674669772613, 'fraction_numerical': 0.0022765174577123646, 'mean_word_length': 5.299483074870769, 'pattern_counts': {'":': 88, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1024055', 'n_tokens_mistral': 12511, 'n_tokens_neox': 11536, 'n_words': 3303}