6 use Scalar
::Util qw
/weaken/;
8 use BS
::HTTPD
::HTTPServer
;
9 use BS
::HTTPD
::Request
;
11 our @ISA = qw
/BS::HTTPD::HTTPServer/;
15 BS::HTTPD - A simple lightweight event based web (application) server
23 our $VERSION = '0.01';
29 my $httpd = BS::HTTPD->new (port => 9090);
33 my ($httpd, $req) = @_;
35 $req->o ("<html><body><h1>Hello World!</h1>");
36 $req->o ("<a href=\"/test\">another test page</a>");
37 $req->o ("</body></html>");
41 my ($httpd, $req) = @_;
43 $req->o ("<html><body><h1>Test page</h1>");
44 $req->o ("<a href=\"/\">Back to the main page</a>");
45 $req->o ("</body></html>");
52 This module provides a simple HTTPD for serving simple web application
53 interfaces. It's completly event based and independend from any event loop
54 by using the L<AnyEvent> module.
56 It's HTTP implementation is a bit hacky, so before using this module make sure
57 it works for you and the expected deployment. Feel free to improve the HTTP support
60 I mainly wrote this module to provide a HTTP interface in L<BS>. However,
61 it doesn't depend on L<BS> and it can be used to extend any application
62 with a (simple) web interface.
64 The documentation is currently only the source code, but next versions of
65 this module will be better documented hopefully. See also the C<samples/> directory
66 in the L<BS::HTTPD> distribution for basic starting points.
68 L<BS::HTTPD> even comes with some basic AJAX framework/helper.
74 =item * support for GET and POST requests
76 =item * processing of C<x-www-form-urlencoded> and C<multipart/form-data> encoded form parameters
78 =item * ajax helper and javascript output functions in L<BS::HTTPD::Appgets>
80 =item * support for chunked encoding output to the HTTP client
86 The L<BS::HTTPD> class inherits directly from L<BS::HTTPD::HTTPServer>
87 which inherits the event callback interface from L<BS::Event>.
89 Event callbacks can be registered via the L<BS::Event> API (see the documentation
90 of L<BS::Event> for details).
92 For a list of available events see below in the I<EVENTS> section.
100 my $class = ref($this) || $this;
101 my $self = $class->SUPER::new
(@_);
103 $self->start_cleanup;
107 my ($self, $con) = @_;
109 $self->{conns
}->{$con} = $con->reg_cb (
111 my ($con, $meth, $url, $hdr, $cont) = @_;
112 #d# warn "REQUEST: $meth, $url, [$cont] " . join (',', %$hdr) . "\n";
114 $url = URI
->new ($url);
116 if ($meth eq 'GET') {
117 $cont = $con->parse_urlencoded ($url->query);
120 if ($meth eq 'GET' or $meth eq 'POST') {
123 $self->handle_app_req ($url, $hdr, $cont, sub {
124 $con->response (@_) if $con;
127 $con->response (200, "ok");
133 my ($self, $con) = @_;
134 $con->unreg_cb (delete $self->{conns
}->{$con});
138 $self->{max_data
} //= 10;
139 $self->{cleanup_interval
} //= 60;
140 $self->{state} //= {};
148 AnyEvent
->timer (after
=> $self->{cleanup_interval
}, cb
=> sub {
150 $self->start_cleanup;
157 my $cnt = scalar @
{$self->{form_ages
} || []};
159 if ($cnt > $self->{max_data
}) {
160 my $diff = $cnt - $self->{max_data
};
163 my $d = pop @
{$self->{form_ages
} || []};
164 last unless defined $d;
165 delete $self->{form_cbs
}->{$d->[1]};
171 my ($self, $dest, @args) = @_;
173 $self->{form_cbs
}->{"$self->{form_id}"} = [$dest, \
@args];
174 push @
{$self->{form_ages
}}, [time, $self->{form_id
}];
179 my ($self, $url, $hdr, $cont, $respcb) = @_;
184 BS
::HTTPD
::Request
->new (
188 parm
=> (ref $cont ?
$cont : {}),
189 input
=> (ref $cont ?
undef : $cont),
193 if ($req->is_form_submit) {
194 my $id = $req->form_id;
195 my $cb = $self->{form_cbs
}->{"$id"};
197 if (ref $cb->[0] eq 'CODE') {
202 my (@segs) = $url->path_segments;
203 my $ev = join "_", @segs;
205 my @res = $self->event ('request' => $req);
206 push @res, $self->event ($ev => $req);
213 Every request goes to a specific URL. After a (GET or POST) request is
214 received the URL is split at the '/' characters and joined again with '_' characters.
215 After that the event with the name of the converted URL is invoked, this means that
216 if you get a request to the url '/test/bla' the even C<_test_bla> is emitted,
217 you can register a callback for that URL like this:
221 my ($httpd, $url, $headers, $respcb) = @_;
225 [200, 'ok', { 'Content-Type' => 'text/html' }, '<h1>Test</h1>' }]
229 The first argument to such a callback is always the L<BS::HTTPD> object itself.
230 The second argument (C<$url>) is the L<URI::URL> object of the request URL, the
231 third argument (C<$headers>) are the HTTP headers as hashreference of array
234 The C<$respcb> argument is a callback that you can call with the values that
235 you would normally return from the callback. It will then generate a response
236 and send it back as response to the request. Take care that you return the
237 string C<'delay'> from the event if you want to handle it later.
238 See also the C<delayed_example> in the C<samples/> directory.
240 Also every request also emits the C<request> event, with the same arguments and semantics,
241 you can use this to implement your own request multiplexing.
243 The return value of these event callbacks are searched for array or hash references.
244 The first callback that returned some response (a non-empty list) determines what
245 the server will respond to the HTTP useragent.
247 If the return value was an array reference it's elements have the following semantics:
249 Alternatively you can fill the response via the C<o> method which will append
250 any strings it gets as argument to the response. The content type of a
251 response constructed by C<o> will be C<text/html>.
255 Any response from the HTTP server will have C<Cache-Control> set to C<max-age=0> and
256 also the C<Expires> header set to the C<Date> header. Meaning: Caching is disabled.
258 If you need caching or would like to have it you can send me a mail or even
263 Robin Redeker, C<< <elmex at ta-sa.org> >>
267 Please report any bugs or feature requests to C<bug-bs-httpd at rt.cpan.org>, or through
268 the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=BS-HTTPD>. I will be notified, and then you'll
269 automatically be notified of progress on your bug as I make changes.
273 You can find documentation for this module with the perldoc command.
278 You can also look for information at:
282 =item * RT: CPAN's request tracker
284 L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=BS-HTTPD>
286 =item * AnnoCPAN: Annotated CPAN documentation
288 L<http://annocpan.org/dist/BS-HTTPD>
292 L<http://cpanratings.perl.org/d/BS-HTTPD>
296 L<http://search.cpan.org/dist/BS-HTTPD>
301 =head1 ACKNOWLEDGEMENTS
304 =head1 COPYRIGHT & LICENSE
306 Copyright 2008 Robin Redeker, all rights reserved.
308 This program is free software; you can redistribute it and/or modify it
309 under the same terms as Perl itself.
314 1; # End of BS::HTTPD