# ==================================================================== # Gossamer Threads Module Library - http://gossamer-threads.com/ # # GT::WWW::http::Response # Author: Jason Rhinelander # CVS Info : # $Id: Response.pm,v 1.8 2004/08/04 19:23:07 jagerman Exp $ # # Copyright (c) 2004 Gossamer Threads Inc. All Rights Reserved. # ==================================================================== # # Description: # Response object for GT::WWW HTTP/HTTPS requests. # package GT::WWW::http::Response; use strict; use vars qw/$AUTOLOAD/; use overload '""' => \&content, bool => \&boolean, cmp => \&strcmp; use Carp; sub new { my $class = shift; $class = ref $class if ref $class; my $self = {}; bless $self, $class; } AUTOLOAD { my ($self, @args) = @_; my ($attr) = $AUTOLOAD =~ /([^:]+)$/; if (@args) { $self->{$attr} = shift @args; } $self->{$attr}; } sub content { $_[0]->{content} } sub boolean { 1 } # So you can you do things like: $www->get() or die sub status { my $self = shift; if (@_) { my ($num, $str) = @_; $self->{status} = GT::WWW::http::Response::Status->new($num, $str); } $self->{status}; } sub header { my $self = shift; if (@_) { $self->{header}->header(@_); } else { $self->{header}; } } sub strcmp { $_[2] ? $_[1] cmp $_[0]->{content} : $_[0]->{content} cmp $_[1] } package GT::WWW::http::Response::Status; use overload '""' => \&string, bool => \&boolean, '0+' => \&numeric, '+' => \&addition, '<=>' => \&numcmp, 'cmp' => \&strcmp; sub new { my ($class, $numeric, $string) = @_; my $self = [$numeric, $string]; bless $self, $class; } sub numeric { $_[0]->[0] } sub string { "$_[0]->[0] $_[0]->[1]" } sub boolean { substr($_[0]->[0], 0, 1) eq '2' } sub addition { int($_[0]) + int($_[1]) } sub numcmp { $_[2] ? $_[1] <=> $_[0]->[0] : $_[0]->[0] <=> $_[1] } sub strcmp { $_[2] ? $_[1] cmp $_[0]->[1] : $_[0]->[1] cmp $_[1] } 1; __END__ =head1 NAME GT::WWW::http::Response and GT::WWW::http::Response::Status - Overloaded response objects for HTTP request data. =head1 SYNOPSIS # ($www is continued from GT::WWW::http SYNOPSIS) my $response = $www->get(); # or post(), or head() # -- or, after having called get(), post() or head(): -- my $response = $www->response(); my $status = $response->status(); my $content = "$response"; my $response_code = int($status); # i.e. 200, 404, 500 my $response_str = "$status"; # i.e. 'OK', 'Not Found', 'Internal Server Error' if ($status) { # True for 2xx requests, false otherwise (e.g. 404, 500, etc.) ... } =head1 DESCRIPTION GT::WWW::http::Response objects are returned by the L|GT::WWW/get>, L|GT::WWW/post>, and L|GT::WWW/head> methods of GT::WWW HTTP requests (and derivatives - i.e. HTTPS), or by calling L|GT::WWW::http/response> after having made such a request. The objects are overloaded in order to provide a simple interface to the response, while still having all the information available. A response object always returns true in boolean context, allowing you to do things like C<$www-Eget($url) or die;> - even when a page is empty, or contains just '0'. =head1 CONTENT In addition to the methods described below, the way to simply access the data returned by the server is to simply use it like a string - for example, printing it, concatenating it with another string, or quoting it. You should, however, take note that when using the L|GT::WWW/chunk> option for an HTTP request, the content will not be available. =head1 METHODS For simple requests, often the content alone is enough. The following methods are used to determine any other information available about the response. =head2 content Returns the content of the HTTP response. Note that this returns the exact same value as using the object in double quotes. =head2 status Returns the response status object for the request. This object provides three pieces of information, and has no public methods. Instead, the data is retrieved based on the context of the object. my $status = $response->status; (N.B. Though the examples below use a C<$status> variable, there is no reason they couldn't be written to use C<$response-Estatus> instead.) =over 4 =item numeric status The numeric status of an HTTP request (e.g. 200, 404, 500) is available simply by using the status object as a number. my $numeric_status = int $status; =item string status The string status of an HTTP request (e.g. "OK", "Not Found", "Internal Server Error") is available by using the status object as a string (e.g. printing it, or concatenating it with another string). # Assign the status string to a variable: my $status_string = "$status"; # Print out the status string: print $status; # To get a string such as "500 Internal Server Error": my $string = int($status) . " " . $status; =item boolean status In order to quickly determine whether or not a request was successful, you can use the status object in a boolean context. Success is determined by the numeric status of the response. Any 2xx status (usually 200 OK, but there are others) counts as a successful response, while any other status counts as a failure. if ($status) { print "Request successful!" } else { print "Request failed!" } =back =head2 header This method, called without arguments, returns the L object for the response. my $header = $response->header; If this method is called with arguments, those arguments are passed to the L|GT::WWW::http::Header/header> method of the header object. This allows this useful shortcut: my $some_header_value = $response->header("Some-Header"); instead of the alternative (which also works): my $some_header_value = $response->header->header("Some-Header"); Information on header object usage is contained in L. Note that although a header object allows for header manipulation, changing the headers of a response object should be considered bad practise, and is strongly discouraged. =head1 CAVEATS Although the response object _works_ like a string, keep in mind that it is still an object, and thus a reference. If you intend to pass the data to another subroutine expecting a string, it is recommended that you force the content into string form, either by quoting the variable (C<"$var">) or by calling the content() method (C<$var-Econtent>). Not doing so can lead to unexpected results, particularly in cases where another subroutine may differentiate between a string and a reference, and not just use the value as a string. Also, in terms of speed, obtaining the content (not the object) into another variable (either via C<"$var"> or C<$var-Econtent>) can make quite a substantial difference when several string comparison operations are performed. The reason is simply that every time the object is used is a string, the content method is called, which can amount to a significant slowdown. Although string operations that change the string (i.e. s///) appear to work, they in fact clobber the reference and turn your variable into an ordinary string. This should not be done - if the string needs to be modified, take a copy of it first, and modify the copy. =head1 SEE ALSO L L L RFC 2616: L =head1 MAINTAINER Jason Rhinelander =head1 COPYRIGHT Copyright (c) 2004 Gossamer Threads Inc. All Rights Reserved. http://www.gossamer-threads.com/ =head1 VERSION Revision: $Id: Response.pm,v 1.8 2004/08/04 19:23:07 jagerman Exp $ =cut