diff options
author | Karl Berry <karl@freefriends.org> | 2016-04-05 22:27:26 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2016-04-05 22:27:26 +0000 |
commit | b56b320b5e2515160073fa1b469514002688fe11 (patch) | |
tree | 965a7100c5e45fca8ec803d22b8b6ce14fca4633 /Master/tlpkg/tlperl/lib/HTTP/Daemon.pm | |
parent | d26c206452d2e285c3bbf949f34011e4a55fd8f9 (diff) |
tlperl 5.22.1 from siep
git-svn-id: svn://tug.org/texlive/trunk@40252 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/tlpkg/tlperl/lib/HTTP/Daemon.pm')
-rw-r--r-- | Master/tlpkg/tlperl/lib/HTTP/Daemon.pm | 906 |
1 files changed, 0 insertions, 906 deletions
diff --git a/Master/tlpkg/tlperl/lib/HTTP/Daemon.pm b/Master/tlpkg/tlperl/lib/HTTP/Daemon.pm deleted file mode 100644 index 27a7bf4e173..00000000000 --- a/Master/tlpkg/tlperl/lib/HTTP/Daemon.pm +++ /dev/null @@ -1,906 +0,0 @@ -package HTTP::Daemon; - -use strict; -use vars qw($VERSION @ISA $PROTO $DEBUG); - -$VERSION = "6.01"; - -use IO::Socket qw(AF_INET INADDR_ANY INADDR_LOOPBACK inet_ntoa); -@ISA=qw(IO::Socket::INET); - -$PROTO = "HTTP/1.1"; - - -sub new -{ - my($class, %args) = @_; - $args{Listen} ||= 5; - $args{Proto} ||= 'tcp'; - return $class->SUPER::new(%args); -} - - -sub accept -{ - my $self = shift; - my $pkg = shift || "HTTP::Daemon::ClientConn"; - my ($sock, $peer) = $self->SUPER::accept($pkg); - if ($sock) { - ${*$sock}{'httpd_daemon'} = $self; - return wantarray ? ($sock, $peer) : $sock; - } - else { - return; - } -} - - -sub url -{ - my $self = shift; - my $url = $self->_default_scheme . "://"; - my $addr = $self->sockaddr; - if (!$addr || $addr eq INADDR_ANY) { - require Sys::Hostname; - $url .= lc Sys::Hostname::hostname(); - } - elsif ($addr eq INADDR_LOOPBACK) { - $url .= inet_ntoa($addr); - } - else { - $url .= gethostbyaddr($addr, AF_INET) || inet_ntoa($addr); - } - my $port = $self->sockport; - $url .= ":$port" if $port != $self->_default_port; - $url .= "/"; - $url; -} - - -sub _default_port { - 80; -} - - -sub _default_scheme { - "http"; -} - - -sub product_tokens -{ - "libwww-perl-daemon/$HTTP::Daemon::VERSION"; -} - - - -package HTTP::Daemon::ClientConn; - -use vars qw(@ISA $DEBUG); -use IO::Socket (); -@ISA=qw(IO::Socket::INET); -*DEBUG = \$HTTP::Daemon::DEBUG; - -use HTTP::Request (); -use HTTP::Response (); -use HTTP::Status; -use HTTP::Date qw(time2str); -use LWP::MediaTypes qw(guess_media_type); -use Carp (); - -my $CRLF = "\015\012"; # "\r\n" is not portable -my $HTTP_1_0 = _http_version("HTTP/1.0"); -my $HTTP_1_1 = _http_version("HTTP/1.1"); - - -sub get_request -{ - my($self, $only_headers) = @_; - if (${*$self}{'httpd_nomore'}) { - $self->reason("No more requests from this connection"); - return; - } - - $self->reason(""); - my $buf = ${*$self}{'httpd_rbuf'}; - $buf = "" unless defined $buf; - - my $timeout = $ {*$self}{'io_socket_timeout'}; - my $fdset = ""; - vec($fdset, $self->fileno, 1) = 1; - local($_); - - READ_HEADER: - while (1) { - # loop until we have the whole header in $buf - $buf =~ s/^(?:\015?\012)+//; # ignore leading blank lines - if ($buf =~ /\012/) { # potential, has at least one line - if ($buf =~ /^\w+[^\012]+HTTP\/\d+\.\d+\015?\012/) { - if ($buf =~ /\015?\012\015?\012/) { - last READ_HEADER; # we have it - } - elsif (length($buf) > 16*1024) { - $self->send_error(413); # REQUEST_ENTITY_TOO_LARGE - $self->reason("Very long header"); - return; - } - } - else { - last READ_HEADER; # HTTP/0.9 client - } - } - elsif (length($buf) > 16*1024) { - $self->send_error(414); # REQUEST_URI_TOO_LARGE - $self->reason("Very long first line"); - return; - } - print STDERR "Need more data for complete header\n" if $DEBUG; - return unless $self->_need_more($buf, $timeout, $fdset); - } - if ($buf !~ s/^(\S+)[ \t]+(\S+)(?:[ \t]+(HTTP\/\d+\.\d+))?[^\012]*\012//) { - ${*$self}{'httpd_client_proto'} = _http_version("HTTP/1.0"); - $self->send_error(400); # BAD_REQUEST - $self->reason("Bad request line: $buf"); - return; - } - my $method = $1; - my $uri = $2; - my $proto = $3 || "HTTP/0.9"; - $uri = "http://$uri" if $method eq "CONNECT"; - $uri = $HTTP::URI_CLASS->new($uri, $self->daemon->url); - my $r = HTTP::Request->new($method, $uri); - $r->protocol($proto); - ${*$self}{'httpd_client_proto'} = $proto = _http_version($proto); - ${*$self}{'httpd_head'} = ($method eq "HEAD"); - - if ($proto >= $HTTP_1_0) { - # we expect to find some headers - my($key, $val); - HEADER: - while ($buf =~ s/^([^\012]*)\012//) { - $_ = $1; - s/\015$//; - if (/^([^:\s]+)\s*:\s*(.*)/) { - $r->push_header($key, $val) if $key; - ($key, $val) = ($1, $2); - } - elsif (/^\s+(.*)/) { - $val .= " $1"; - } - else { - last HEADER; - } - } - $r->push_header($key, $val) if $key; - } - - my $conn = $r->header('Connection'); - if ($proto >= $HTTP_1_1) { - ${*$self}{'httpd_nomore'}++ if $conn && lc($conn) =~ /\bclose\b/; - } - else { - ${*$self}{'httpd_nomore'}++ unless $conn && - lc($conn) =~ /\bkeep-alive\b/; - } - - if ($only_headers) { - ${*$self}{'httpd_rbuf'} = $buf; - return $r; - } - - # Find out how much content to read - my $te = $r->header('Transfer-Encoding'); - my $ct = $r->header('Content-Type'); - my $len = $r->header('Content-Length'); - - # Act on the Expect header, if it's there - for my $e ( $r->header('Expect') ) { - if( lc($e) eq '100-continue' ) { - $self->send_status_line(100); - $self->send_crlf; - } - else { - $self->send_error(417); - $self->reason("Unsupported Expect header value"); - return; - } - } - - if ($te && lc($te) eq 'chunked') { - # Handle chunked transfer encoding - my $body = ""; - CHUNK: - while (1) { - print STDERR "Chunked\n" if $DEBUG; - if ($buf =~ s/^([^\012]*)\012//) { - my $chunk_head = $1; - unless ($chunk_head =~ /^([0-9A-Fa-f]+)/) { - $self->send_error(400); - $self->reason("Bad chunk header $chunk_head"); - return; - } - my $size = hex($1); - last CHUNK if $size == 0; - - my $missing = $size - length($buf) + 2; # 2=CRLF at chunk end - # must read until we have a complete chunk - while ($missing > 0) { - print STDERR "Need $missing more bytes\n" if $DEBUG; - my $n = $self->_need_more($buf, $timeout, $fdset); - return unless $n; - $missing -= $n; - } - $body .= substr($buf, 0, $size); - substr($buf, 0, $size+2) = ''; - - } - else { - # need more data in order to have a complete chunk header - return unless $self->_need_more($buf, $timeout, $fdset); - } - } - $r->content($body); - - # pretend it was a normal entity body - $r->remove_header('Transfer-Encoding'); - $r->header('Content-Length', length($body)); - - my($key, $val); - FOOTER: - while (1) { - if ($buf !~ /\012/) { - # need at least one line to look at - return unless $self->_need_more($buf, $timeout, $fdset); - } - else { - $buf =~ s/^([^\012]*)\012//; - $_ = $1; - s/\015$//; - if (/^([\w\-]+)\s*:\s*(.*)/) { - $r->push_header($key, $val) if $key; - ($key, $val) = ($1, $2); - } - elsif (/^\s+(.*)/) { - $val .= " $1"; - } - elsif (!length) { - last FOOTER; - } - else { - $self->reason("Bad footer syntax"); - return; - } - } - } - $r->push_header($key, $val) if $key; - - } - elsif ($te) { - $self->send_error(501); # Unknown transfer encoding - $self->reason("Unknown transfer encoding '$te'"); - return; - - } - elsif ($len) { - # Plain body specified by "Content-Length" - my $missing = $len - length($buf); - while ($missing > 0) { - print "Need $missing more bytes of content\n" if $DEBUG; - my $n = $self->_need_more($buf, $timeout, $fdset); - return unless $n; - $missing -= $n; - } - if (length($buf) > $len) { - $r->content(substr($buf,0,$len)); - substr($buf, 0, $len) = ''; - } - else { - $r->content($buf); - $buf=''; - } - } - elsif ($ct && $ct =~ m/^multipart\/\w+\s*;.*boundary\s*=\s*("?)(\w+)\1/i) { - # Handle multipart content type - my $boundary = "$CRLF--$2--"; - my $index; - while (1) { - $index = index($buf, $boundary); - last if $index >= 0; - # end marker not yet found - return unless $self->_need_more($buf, $timeout, $fdset); - } - $index += length($boundary); - $r->content(substr($buf, 0, $index)); - substr($buf, 0, $index) = ''; - - } - ${*$self}{'httpd_rbuf'} = $buf; - - $r; -} - - -sub _need_more -{ - my $self = shift; - #my($buf,$timeout,$fdset) = @_; - if ($_[1]) { - my($timeout, $fdset) = @_[1,2]; - print STDERR "select(,,,$timeout)\n" if $DEBUG; - my $n = select($fdset,undef,undef,$timeout); - unless ($n) { - $self->reason(defined($n) ? "Timeout" : "select: $!"); - return; - } - } - print STDERR "sysread()\n" if $DEBUG; - my $n = sysread($self, $_[0], 2048, length($_[0])); - $self->reason(defined($n) ? "Client closed" : "sysread: $!") unless $n; - $n; -} - - -sub read_buffer -{ - my $self = shift; - my $old = ${*$self}{'httpd_rbuf'}; - if (@_) { - ${*$self}{'httpd_rbuf'} = shift; - } - $old; -} - - -sub reason -{ - my $self = shift; - my $old = ${*$self}{'httpd_reason'}; - if (@_) { - ${*$self}{'httpd_reason'} = shift; - } - $old; -} - - -sub proto_ge -{ - my $self = shift; - ${*$self}{'httpd_client_proto'} >= _http_version(shift); -} - - -sub _http_version -{ - local($_) = shift; - return 0 unless m,^(?:HTTP/)?(\d+)\.(\d+)$,i; - $1 * 1000 + $2; -} - - -sub antique_client -{ - my $self = shift; - ${*$self}{'httpd_client_proto'} < $HTTP_1_0; -} - - -sub force_last_request -{ - my $self = shift; - ${*$self}{'httpd_nomore'}++; -} - -sub head_request -{ - my $self = shift; - ${*$self}{'httpd_head'}; -} - - -sub send_status_line -{ - my($self, $status, $message, $proto) = @_; - return if $self->antique_client; - $status ||= RC_OK; - $message ||= status_message($status) || ""; - $proto ||= $HTTP::Daemon::PROTO || "HTTP/1.1"; - print $self "$proto $status $message$CRLF"; -} - - -sub send_crlf -{ - my $self = shift; - print $self $CRLF; -} - - -sub send_basic_header -{ - my $self = shift; - return if $self->antique_client; - $self->send_status_line(@_); - print $self "Date: ", time2str(time), $CRLF; - my $product = $self->daemon->product_tokens; - print $self "Server: $product$CRLF" if $product; -} - - -sub send_header -{ - my $self = shift; - while (@_) { - my($k, $v) = splice(@_, 0, 2); - $v = "" unless defined($v); - print $self "$k: $v$CRLF"; - } -} - - -sub send_response -{ - my $self = shift; - my $res = shift; - if (!ref $res) { - $res ||= RC_OK; - $res = HTTP::Response->new($res, @_); - } - my $content = $res->content; - my $chunked; - unless ($self->antique_client) { - my $code = $res->code; - $self->send_basic_header($code, $res->message, $res->protocol); - if ($code =~ /^(1\d\d|[23]04)$/) { - # make sure content is empty - $res->remove_header("Content-Length"); - $content = ""; - } - elsif ($res->request && $res->request->method eq "HEAD") { - # probably OK - } - elsif (ref($content) eq "CODE") { - if ($self->proto_ge("HTTP/1.1")) { - $res->push_header("Transfer-Encoding" => "chunked"); - $chunked++; - } - else { - $self->force_last_request; - } - } - elsif (length($content)) { - $res->header("Content-Length" => length($content)); - } - else { - $self->force_last_request; - $res->header('connection','close'); - } - print $self $res->headers_as_string($CRLF); - print $self $CRLF; # separates headers and content - } - if ($self->head_request) { - # no content - } - elsif (ref($content) eq "CODE") { - while (1) { - my $chunk = &$content(); - last unless defined($chunk) && length($chunk); - if ($chunked) { - printf $self "%x%s%s%s", length($chunk), $CRLF, $chunk, $CRLF; - } - else { - print $self $chunk; - } - } - print $self "0$CRLF$CRLF" if $chunked; # no trailers either - } - elsif (length $content) { - print $self $content; - } -} - - -sub send_redirect -{ - my($self, $loc, $status, $content) = @_; - $status ||= RC_MOVED_PERMANENTLY; - Carp::croak("Status '$status' is not redirect") unless is_redirect($status); - $self->send_basic_header($status); - my $base = $self->daemon->url; - $loc = $HTTP::URI_CLASS->new($loc, $base) unless ref($loc); - $loc = $loc->abs($base); - print $self "Location: $loc$CRLF"; - if ($content) { - my $ct = $content =~ /^\s*</ ? "text/html" : "text/plain"; - print $self "Content-Type: $ct$CRLF"; - } - print $self $CRLF; - print $self $content if $content && !$self->head_request; - $self->force_last_request; # no use keeping the connection open -} - - -sub send_error -{ - my($self, $status, $error) = @_; - $status ||= RC_BAD_REQUEST; - Carp::croak("Status '$status' is not an error") unless is_error($status); - my $mess = status_message($status); - $error ||= ""; - $mess = <<EOT; -<title>$status $mess</title> -<h1>$status $mess</h1> -$error -EOT - unless ($self->antique_client) { - $self->send_basic_header($status); - print $self "Content-Type: text/html$CRLF"; - print $self "Content-Length: " . length($mess) . $CRLF; - print $self $CRLF; - } - print $self $mess unless $self->head_request; - $status; -} - - -sub send_file_response -{ - my($self, $file) = @_; - if (-d $file) { - $self->send_dir($file); - } - elsif (-f _) { - # plain file - local(*F); - sysopen(F, $file, 0) or - return $self->send_error(RC_FORBIDDEN); - binmode(F); - my($ct,$ce) = guess_media_type($file); - my($size,$mtime) = (stat _)[7,9]; - unless ($self->antique_client) { - $self->send_basic_header; - print $self "Content-Type: $ct$CRLF"; - print $self "Content-Encoding: $ce$CRLF" if $ce; - print $self "Content-Length: $size$CRLF" if $size; - print $self "Last-Modified: ", time2str($mtime), "$CRLF" if $mtime; - print $self $CRLF; - } - $self->send_file(\*F) unless $self->head_request; - return RC_OK; - } - else { - $self->send_error(RC_NOT_FOUND); - } -} - - -sub send_dir -{ - my($self, $dir) = @_; - $self->send_error(RC_NOT_FOUND) unless -d $dir; - $self->send_error(RC_NOT_IMPLEMENTED); -} - - -sub send_file -{ - my($self, $file) = @_; - my $opened = 0; - local(*FILE); - if (!ref($file)) { - open(FILE, $file) || return undef; - binmode(FILE); - $file = \*FILE; - $opened++; - } - my $cnt = 0; - my $buf = ""; - my $n; - while ($n = sysread($file, $buf, 8*1024)) { - last if !$n; - $cnt += $n; - print $self $buf; - } - close($file) if $opened; - $cnt; -} - - -sub daemon -{ - my $self = shift; - ${*$self}{'httpd_daemon'}; -} - - -1; - -__END__ - -=head1 NAME - -HTTP::Daemon - a simple http server class - -=head1 SYNOPSIS - - use HTTP::Daemon; - use HTTP::Status; - - my $d = HTTP::Daemon->new || die; - print "Please contact me at: <URL:", $d->url, ">\n"; - while (my $c = $d->accept) { - while (my $r = $c->get_request) { - if ($r->method eq 'GET' and $r->uri->path eq "/xyzzy") { - # remember, this is *not* recommended practice :-) - $c->send_file_response("/etc/passwd"); - } - else { - $c->send_error(RC_FORBIDDEN) - } - } - $c->close; - undef($c); - } - -=head1 DESCRIPTION - -Instances of the C<HTTP::Daemon> class are HTTP/1.1 servers that -listen on a socket for incoming requests. The C<HTTP::Daemon> is a -subclass of C<IO::Socket::INET>, so you can perform socket operations -directly on it too. - -The accept() method will return when a connection from a client is -available. The returned value will be an C<HTTP::Daemon::ClientConn> -object which is another C<IO::Socket::INET> subclass. Calling the -get_request() method on this object will read data from the client and -return an C<HTTP::Request> object. The ClientConn object also provide -methods to send back various responses. - -This HTTP daemon does not fork(2) for you. Your application, i.e. the -user of the C<HTTP::Daemon> is responsible for forking if that is -desirable. Also note that the user is responsible for generating -responses that conform to the HTTP/1.1 protocol. - -The following methods of C<HTTP::Daemon> are new (or enhanced) relative -to the C<IO::Socket::INET> base class: - -=over 4 - -=item $d = HTTP::Daemon->new - -=item $d = HTTP::Daemon->new( %opts ) - -The constructor method takes the same arguments as the -C<IO::Socket::INET> constructor, but unlike its base class it can also -be called without any arguments. The daemon will then set up a listen -queue of 5 connections and allocate some random port number. - -A server that wants to bind to some specific address on the standard -HTTP port will be constructed like this: - - $d = HTTP::Daemon->new( - LocalAddr => 'www.thisplace.com', - LocalPort => 80, - ); - -See L<IO::Socket::INET> for a description of other arguments that can -be used configure the daemon during construction. - -=item $c = $d->accept - -=item $c = $d->accept( $pkg ) - -=item ($c, $peer_addr) = $d->accept - -This method works the same the one provided by the base class, but it -returns an C<HTTP::Daemon::ClientConn> reference by default. If a -package name is provided as argument, then the returned object will be -blessed into the given class. It is probably a good idea to make that -class a subclass of C<HTTP::Daemon::ClientConn>. - -The accept method will return C<undef> if timeouts have been enabled -and no connection is made within the given time. The timeout() method -is described in L<IO::Socket>. - -In list context both the client object and the peer address will be -returned; see the description of the accept method L<IO::Socket> for -details. - -=item $d->url - -Returns a URL string that can be used to access the server root. - -=item $d->product_tokens - -Returns the name that this server will use to identify itself. This -is the string that is sent with the C<Server> response header. The -main reason to have this method is that subclasses can override it if -they want to use another product name. - -The default is the string "libwww-perl-daemon/#.##" where "#.##" is -replaced with the version number of this module. - -=back - -The C<HTTP::Daemon::ClientConn> is a C<IO::Socket::INET> -subclass. Instances of this class are returned by the accept() method -of C<HTTP::Daemon>. The following methods are provided: - -=over 4 - -=item $c->get_request - -=item $c->get_request( $headers_only ) - -This method reads data from the client and turns it into an -C<HTTP::Request> object which is returned. It returns C<undef> -if reading fails. If it fails, then the C<HTTP::Daemon::ClientConn> -object ($c) should be discarded, and you should not try call this -method again on it. The $c->reason method might give you some -information about why $c->get_request failed. - -The get_request() method will normally not return until the whole -request has been received from the client. This might not be what you -want if the request is an upload of a large file (and with chunked -transfer encoding HTTP can even support infinite request messages - -uploading live audio for instance). If you pass a TRUE value as the -$headers_only argument, then get_request() will return immediately -after parsing the request headers and you are responsible for reading -the rest of the request content. If you are going to call -$c->get_request again on the same connection you better read the -correct number of bytes. - -=item $c->read_buffer - -=item $c->read_buffer( $new_value ) - -Bytes read by $c->get_request, but not used are placed in the I<read -buffer>. The next time $c->get_request is called it will consume the -bytes in this buffer before reading more data from the network -connection itself. The read buffer is invalid after $c->get_request -has failed. - -If you handle the reading of the request content yourself you need to -empty this buffer before you read more and you need to place -unconsumed bytes here. You also need this buffer if you implement -services like I<101 Switching Protocols>. - -This method always returns the old buffer content and can optionally -replace the buffer content if you pass it an argument. - -=item $c->reason - -When $c->get_request returns C<undef> you can obtain a short string -describing why it happened by calling $c->reason. - -=item $c->proto_ge( $proto ) - -Return TRUE if the client announced a protocol with version number -greater or equal to the given argument. The $proto argument can be a -string like "HTTP/1.1" or just "1.1". - -=item $c->antique_client - -Return TRUE if the client speaks the HTTP/0.9 protocol. No status -code and no headers should be returned to such a client. This should -be the same as !$c->proto_ge("HTTP/1.0"). - -=item $c->head_request - -Return TRUE if the last request was a C<HEAD> request. No content -body must be generated for these requests. - -=item $c->force_last_request - -Make sure that $c->get_request will not try to read more requests off -this connection. If you generate a response that is not self -delimiting, then you should signal this fact by calling this method. - -This attribute is turned on automatically if the client announces -protocol HTTP/1.0 or worse and does not include a "Connection: -Keep-Alive" header. It is also turned on automatically when HTTP/1.1 -or better clients send the "Connection: close" request header. - -=item $c->send_status_line - -=item $c->send_status_line( $code ) - -=item $c->send_status_line( $code, $mess ) - -=item $c->send_status_line( $code, $mess, $proto ) - -Send the status line back to the client. If $code is omitted 200 is -assumed. If $mess is omitted, then a message corresponding to $code -is inserted. If $proto is missing the content of the -$HTTP::Daemon::PROTO variable is used. - -=item $c->send_crlf - -Send the CRLF sequence to the client. - -=item $c->send_basic_header - -=item $c->send_basic_header( $code ) - -=item $c->send_basic_header( $code, $mess ) - -=item $c->send_basic_header( $code, $mess, $proto ) - -Send the status line and the "Date:" and "Server:" headers back to -the client. This header is assumed to be continued and does not end -with an empty CRLF line. - -See the description of send_status_line() for the description of the -accepted arguments. - -=item $c->send_header( $field, $value ) - -=item $c->send_header( $field1, $value1, $field2, $value2, ... ) - -Send one or more header lines. - -=item $c->send_response( $res ) - -Write a C<HTTP::Response> object to the -client as a response. We try hard to make sure that the response is -self delimiting so that the connection can stay persistent for further -request/response exchanges. - -The content attribute of the C<HTTP::Response> object can be a normal -string or a subroutine reference. If it is a subroutine, then -whatever this callback routine returns is written back to the -client as the response content. The routine will be called until it -return an undefined or empty value. If the client is HTTP/1.1 aware -then we will use chunked transfer encoding for the response. - -=item $c->send_redirect( $loc ) - -=item $c->send_redirect( $loc, $code ) - -=item $c->send_redirect( $loc, $code, $entity_body ) - -Send a redirect response back to the client. The location ($loc) can -be an absolute or relative URL. The $code must be one the redirect -status codes, and defaults to "301 Moved Permanently" - -=item $c->send_error - -=item $c->send_error( $code ) - -=item $c->send_error( $code, $error_message ) - -Send an error response back to the client. If the $code is missing a -"Bad Request" error is reported. The $error_message is a string that -is incorporated in the body of the HTML entity body. - -=item $c->send_file_response( $filename ) - -Send back a response with the specified $filename as content. If the -file is a directory we try to generate an HTML index of it. - -=item $c->send_file( $filename ) - -=item $c->send_file( $fd ) - -Copy the file to the client. The file can be a string (which -will be interpreted as a filename) or a reference to an C<IO::Handle> -or glob. - -=item $c->daemon - -Return a reference to the corresponding C<HTTP::Daemon> object. - -=back - -=head1 SEE ALSO - -RFC 2616 - -L<IO::Socket::INET>, L<IO::Socket> - -=head1 COPYRIGHT - -Copyright 1996-2003, Gisle Aas - -This library is free software; you can redistribute it and/or -modify it under the same terms as Perl itself. - |