How-to...
This provides a place to start when trying to figure out how to do common web server tasks, such as getting query string values from a request or configuring for HTTPS. Stuff that has its own obvious guide page is usually not repeated here, so check the Guide TOC too.
- Logging
- Caching Pages
- Customizing Objects
- Debugging
- Directory Indexing
- HTTP/SSL/TLS
- Query Strings
- Uploading
- Virtual Hosting
- Proxying
- Forking/Threading
Logging
Logging is accomplished through the Sloop::Logger class. This produces timestamped output; it is generally used via Sloop::Base::err_log()
, ::debug_log()
, or Sloop::Client::logReq()
, which add a tag from the object's id
in either square brackets (request), exclamation points (error), or curly braces (debugging). For clients id
is by default fdN
where N is the actual file descriptor (these will repeat, but there can only be one object with a particular descriptor at any given time). The err_log()
and debug_log()
methods also add the calling function, which may or may not be meaningful to you.
By default, one logger object is instantiated in the Sloop::Server constructor and then passed to Sloop::Client objects when they are created. If you want to differentiate between these, you may indicate a different logger object via the client_constructor
attribute of the server object.
The default logger object logs errors and debugging messages to standard error and requests to standard output. Both streams are set to autoflush, i.e., non-buffered. You can override the streams used via the Sloop::Logger logs
attribute. You can also subclass Sloop::Logger to override, e.g., the out()
and/or timestamp()
methods — but as mentioned, part of the format comes from methods in Sloop::Base and Sloop::Client.
There is also Sloop::Logger::SimpleColor and Sloop::Logger::TriColor if you want to differentiate things with ANSI color. For example, if out of curiosity you want to track how long a given connection lasts after the first request, you could do something like this in a handler:
my $client = shift; my %colors = ('red', 'yellow', 'green', 'cyan', 'magenta'); $client->{id} =~ /fd(\d+)/; my $n = $1 % ($#colors + 1); $client->{logger} = Sloop::Logger::SimpleColor->new($colors[$n]);
Caching Pages
If you have pages that are generated dynamically from a source that only changes from time to time (as opposed to pages that are always unique in some way), you can probably make use of Sloop::Static::Cache. There is an example of this using markdown and Template Toolkit, markdownCache.pl.
Since the "source" for such pages isn't examined beyond the timestamp, you could conceivably use this to cache complex queries by using zero size files, named according to some schema, created when the first time a given query occurs.
Customizing Objects
Although it's an impossible sin in many other OO languages, perl allows you to attach whatever you want to an object, regardless of what that object is or where it came from. In a Sloop context, it may occasionally be useful with Sloop::Clients, etc., to tack on some arbitrary bit of data, rather than going the more conventional route of subclassing and providing an appropriate client_constructor
to Sloop::Server.
To prevent collisions and confusion, it is a guarantee that no Sloop class ever uses an attribute starting with an underscore. Hence, anything you attach using such a key won't clobber or get clobbered.
Debugging
If something isn't happening the way you think it should, you can get a closer look at what is going on by setting the 'debug' parameter to Sloop::Server using one or more of the constants explained in Sloop::Constants.
Directory Indexing
See the index()
function in Sloop::Static. There's also a demonstration of Sloop::Static::directory()
, which uses index()
by default, in simpleStatic.pl.
HTTPS/SSL/TLS
HTTPS support is provided by the GnuTLS library, which implements TLS 1.2 (the latest) as well as earlier protocol versions (1.1, 1.0, SSL 3.0). Configuring use with Sloop is done by providing appropriate details in the 'secure' argument to the Sloop::Server constructor.
Query Strings
See the qargs
attribute and query()
method of Sloop::Client::Request.
Uploading
- The guide has a section on multipart uploads.
- For basic POST handling, see the
readPost()
andsimplePost()
methods of Sloop::Client.
Virtual Hosting
Sloop only supports name based virtual hosting.
- See
virtualHosts
in Sloop::Server SYNOPSIS. - There's also a simple example in the source tarball.
Proxying
Currently Sloop doesn't support true HTTP CONNECT tunnelling, but you could approximate it using Sloop::Other. The issue is that Sloop always parses incoming messages as HTTP requests, so if you just want a web proxy, a (relatively inefficient) one is possible. There is a potential way around this if you dig into how Sloop::WebSocket works; a proper implementation will probably be in a near future version of Sloop.
Forking/Threading
Don't fork after initializing a Sloop::Server. It may seem okay at first, but eventually you will have a problem. Fork/exec is okay.
Sloop is thread safe in the sense that appropriate measures are taken in the XS code, including use of re-entrant functions. However, while using a sloop server in a multi-threaded application should be fine, actually accessing the object from multiple threads is largely untested. Since during run()
it is continuously active and there are no internal locks, doing so is probably a very bad idea. If instead you want to access shared data from a sloop handler, beware when locking that you don't block for an indeterminate period of time.
If your concern is with generating very time consuming dynamic pages, it is probably better done by offloading the work to another instance via a Sloop::Other object and appropriate callbacks; the guide has a discussion of this.