Perlbal
view release on metacpan or search on metacpan
lib/Perlbal/Service.pm view on Meta::CPAN
######################################################################
# Service class
######################################################################
#
# Copyright 2004, Danga Interactive, Inc.
# Copyright 2005-2007, Six Apart, Ltd.
#
package Perlbal::Service;
use strict;
use warnings;
no warnings qw(deprecated);
use Perlbal::BackendHTTP;
use Perlbal::Cache;
use Perlbal::Util;
use fields (
'name', # scalar: name of this service
'role', # scalar: role type 'web_server', 'reverse_proxy', etc...
'enabled', # scalar: bool, whether we're enabled or not (enabled = listening)
'pool', # Perlbal::Pool that we're using to allocate nodes if we're in proxy mode
'listener', # Perlbal::TCPListener object, when enabled
'reproxy_cache', # Perlbal::Cache object, when enabled
# end-user tunables
'listen', # scalar IP:port of where we're listening for new connections
'docroot', # document root for webserver role
'dirindexing', # bool: directory indexing? (for webserver role) not async.
'index_files', # arrayref of filenames to try for index files
'enable_concatenate_get', # bool: if user can request concatenated files
'enable_put', # bool: whether PUT is supported
'enable_md5', # bool: whether Content-MD5 is supported on PUT
'max_put_size', # int: max size in bytes of a put file
'max_chunked_request_size', # int: max size in bytes of a chunked request (to be written to disk first)
'min_put_directory', # int: number of directories required to exist at beginning of URIs in put
'enable_delete', # bool: whether DELETE is supported
'high_priority_cookie', # cookie name to check if client can 'cut in line' and get backends faster
'high_priority_cookie_contents', # aforementioned cookie value must contain this substring
'backend_persist_cache', # scalar: max number of persistent backends to hold onto while no clients
'persist_client', # bool: persistent connections for clients
'persist_backend', # bool: persistent connections for backends
'verify_backend', # bool: get attention of backend before giving it clients (using OPTIONS)
'verify_backend_path', # path to check with the OPTIONS request (default *)
'max_backend_uses', # max requests to send per kept-alive backend (default 0 = unlimited)
'connect_ahead', # scalar: number of spare backends to connect to in advance all the time
'buffer_size', # int: specifies how much data a ClientProxy object should buffer from a backend
'buffer_size_reproxy_url', # int: same as above but for backends that are reproxying for us
'queue_relief_size', # int; number of outstanding standard priority
# connections to activate pressure relief at
'queue_relief_chance', # int:0-100; % chance to take a standard priority
# request when we're in pressure relief mode
'trusted_upstream_proxies', # Net::Netmask object containing netmasks for trusted upstreams
'always_trusted', # bool; if true, always trust upstreams
'blind_proxy', # bool: if true, do not modify X-Forwarded-For, X-Host, or X-Forwarded-Host headers
'enable_reproxy', # bool; if true, advertise that server will reproxy files and/or URLs
'reproxy_cache_maxsize', # int; maximum number of reproxy results to be cached. (0 is disabled and default)
'client_sndbuf_size', # int: bytes for SO_SNDBUF
'server_process' , # scalar: path to server process (executable)
'persist_client_idle_timeout', # int: keep-alive timeout in seconds for clients (default is 30)
'idle_timeout', # int: idle timeout outside of keep-alive time (default is 30)
# Internal state:
'waiting_clients', # arrayref of clients waiting for backendhttp conns
'waiting_clients_highpri', # arrayref of high-priority clients waiting for backendhttp conns
'waiting_clients_lowpri', # arrayref of low-priority clients waiting for backendhttp conns
'waiting_client_count', # number of clients waiting for backends
'waiting_client_map' , # map of clientproxy fd -> 1 (if they're waiting for a conn)
'pending_connects', # hashref of "ip:port" -> $time (only one pending connect to backend at a time)
'pending_connect_count', # number of outstanding backend connects
'bored_backends', # arrayref of backends we've already connected to, but haven't got clients
'hooks', # hashref: hookname => [ [ plugin, ref ], [ plugin, ref ], ... ]
'plugins', # hashref: name => 1
'plugin_order', # arrayref: name, name, name...
'plugin_setters', # hashref: { plugin_name => { key_name => coderef } }
'extra_config', # hashref: extra config options; name => values
'spawn_lock', # bool: if true, we're currently in spawn_backends
'extra_headers', # { insert => [ [ header, value ], ... ], remove => [ header, header, ... ],
# set => [ [ header, value ], ... ] }; used in header management interface
'generation', # int; generation count so we can slough off backends from old pools
'backend_no_spawn', # { "ip:port" => 1 }; if on, spawn_backends will ignore this ip:port combo
'buffer_backend_connect', # 0 for of, else, number of bytes to buffer before we ask for a backend
'selector', # CODE ref, or undef, for role 'selector' services
'default_service', # Perlbal::Service; name of a service a selector should default to
'buffer_uploads', # bool; enable/disable the buffered uploads to disk system
'buffer_uploads_path', # string; path to store buffered upload files
'buffer_upload_threshold_time', # int; buffer uploads estimated to take longer than this
'buffer_upload_threshold_size', # int; buffer uploads greater than this size (in bytes)
'buffer_upload_threshold_rate', # int; buffer uploads uploading at less than this rate (in bytes/sec)
'upload_status_listeners', # string: comma separated list of ip:port of UDP upload status receivers
'upload_status_listeners_sockaddr', # arrayref of sockaddrs (packed ip/port)
'enable_ssl', # bool: whether this service speaks SSL to the client
'ssl_key_file', # file: path to key pem file
'ssl_cert_file', # file: path to key pem file
'ssl_cipher_list', # OpenSSL cipher list string
'ssl_ca_path', # directory: path to certificates
'ssl_verify_mode', # int: verification mode, see IO::Socket::SSL documentation
'enable_error_retries', # bool: whether we should retry requests after errors
'error_retry_schedule', # string of comma-separated seconds (full or partial) to delay between retries
'latency', # int: milliseconds of latency to add to request
'server_tokens', # bool: whether to provide a "Server" header
# stats:
'_stat_requests', # total requests to this service
'_stat_cache_hits', # total requests to this service that were served via the reproxy-url cache
);
# hash; 'role' => coderef to instantiate a client for this role
our %PluginRoles;
# used by set_defaults
our $defaults = {};
lib/Perlbal/Service.pm view on Meta::CPAN
$self->{reproxy_cache} = undef;
}
return $mc->ok;
},
},
'upload_status_listeners' => {
des => "Comma separated list of hosts in form 'a.b.c.d:port' which will receive UDP upload status packets no faster than once a second per HTTP request (PUT/POST) from clients that have requested an upload status bar, which they request by ap...
default => "",
check_role => "reverse_proxy",
check_type => sub {
my ($self, $val, $errref) = @_;
my @packed;
foreach my $ipa (grep { $_ } split(/\s*,\s*/, $val)) {
unless ($ipa =~ /^(\d+\.\d+\.\d+\.\d+):(\d+)$/) {
$$errref = "Invalid UDP endpoint: \"$ipa\". Must be of form a.b.c.d:port";
return 0;
}
push @packed, scalar Socket::sockaddr_in($2, Socket::inet_aton($1));
}
$self->{upload_status_listeners_sockaddr} = \@packed;
return 1;
},
},
'min_put_directory' => {
des => "If PUT requests are enabled, require this many levels of directories to already exist. If not, fail.",
default => 0, # no limit
check_role => "web_server",
check_type => "int",
},
'dirindexing' => {
des => "Show directory indexes when an HTTP request is for a directory. Warning: this is not an async operation, so will slow down Perlbal on heavily loaded sites.",
default => 0,
check_role => "web_server",
check_type => "bool",
},
'enable_concatenate_get' => {
des => "Enable Perlbal's multiple-files-in-one-request mode, where a client have use a comma-separated list of files to return, always in text/plain. Useful for web apps which have dozens/hundreds of tiny css/js files, and don't trust browse...
default => 0,
check_role => "web_server",
check_type => "bool",
},
'connect_ahead' => {
des => "How many extra backend connections we keep alive in addition to the current ones, in anticipation of new client connections.",
default => 0,
check_type => "int",
check_role => "reverse_proxy",
setter => sub {
my ($self, $val, $set, $mc) = @_;
my $rv = $set->();
$self->spawn_backends if $self->{enabled};
return $rv;
},
},
'always_trusted' => {
des => "Whether to trust all incoming requests' X-Forwarded-For and related headers. Set to true only if you know that all incoming requests from your own proxy servers that clean/set those headers.",
default => 0,
check_type => "bool",
check_role => "*",
},
'blind_proxy' => {
des => "Flag to disable any modification of X-Forwarded-For, X-Host, and X-Forwarded-Host headers.",
default => 0,
check_type => "bool",
check_role => "reverse_proxy",
},
'high_priority_cookie' => {
des => "The cookie name to inspect to determine if the client goes onto the high-priority queue.",
check_role => "reverse_proxy",
},
'high_priority_cookie_contents' => {
des => "A string that the high_priority_cookie must contain to go onto the high-priority queue.",
check_role => "reverse_proxy",
},
'trusted_upstream_proxies' => {
des => "A comma separated list of Net::Netmask filters (e.g. 10.0.0.0/24, see Net::Netmask) that determines whether upstream clients are trusted or not, where trusted means their X-Forwarded-For/etc headers are not munged.",
check_role => "*",
check_type => sub {
my ($self, $val, $errref) = @_;
unless (my $loaded = eval { require Net::Netmask; 1; }) {
$$errref = "Net::Netmask not installed";
return 0;
}
my @val = split /\s*,\s*/, $val;
my @trusted_upstreams = ();
for my $ip (@val) {
my $net = Net::Netmask->new2($ip);
unless ($net) {
$$errref = "Error defining trusted upstream proxies: " . Net::Netmask::errstr();
return 0;
}
push @trusted_upstreams, $net;
}
unless (@trusted_upstreams) {
$$errref = "Error defining trusted upstream proxies: None found";
return 0;
}
$self->{trusted_upstream_proxies} = \@trusted_upstreams;
},
setter => sub {
my ($self, $val, $set, $mc) = @_;
# Do nothing here, we don't want the default setter because we've
# already set the value in the type_check step.
return $mc->ok;
},
},
'index_files' => {
check_role => "web_server",
default => "index.html",
des => "Comma-separated list of filenames to load when a user visits a directory URL, listed in order of preference.",
setter => sub {
my ($self, $val, $set, $mc) = @_;
$self->{index_files} = [ split(/[\s,]+/, $val) ];
return $mc->ok;
},
dumper => sub {
my ($self, $val) = @_;
return unless defined $val;
return join(', ', @$val);
},
},
'default_service' => {
des => "Name of previously-created service to default requests that aren't matched by a selector plugin to.",
check_role => "selector",
check_type => sub {
my ($self, $val, $errref) = @_;
my $svc = Perlbal->service($val);
unless ($svc) {
$$errref = "Service '$svc' not found";
return 0;
( run in 1.000 second using v1.01-cache-2.11-cpan-39bf76dae61 )