Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

393 lines
9.8 KiB

  1. #
  2. # $Id: Response.pm,v 1.34 2000/06/13 20:05:59 gisle Exp $
  3. package HTTP::Response;
  4. =head1 NAME
  5. HTTP::Response - Class encapsulating HTTP Responses
  6. =head1 SYNOPSIS
  7. require HTTP::Response;
  8. =head1 DESCRIPTION
  9. The C<HTTP::Response> class encapsulates HTTP style responses. A
  10. response consists of a response line, some headers, and (potentially
  11. empty) content. Note that the LWP library also uses HTTP style
  12. responses for non-HTTP protocol schemes.
  13. Instances of this class are usually created and returned by the
  14. C<request()> method of an C<LWP::UserAgent> object:
  15. #...
  16. $response = $ua->request($request)
  17. if ($response->is_success) {
  18. print $response->content;
  19. } else {
  20. print $response->error_as_HTML;
  21. }
  22. C<HTTP::Response> is a subclass of C<HTTP::Message> and therefore
  23. inherits its methods. The inherited methods most often used are header(),
  24. push_header(), remove_header(), headers_as_string(), and content().
  25. The header convenience methods are also available. See
  26. L<HTTP::Message> for details.
  27. The following additional methods are available:
  28. =over 4
  29. =cut
  30. require HTTP::Message;
  31. @ISA = qw(HTTP::Message);
  32. $VERSION = sprintf("%d.%02d", q$Revision: 1.34 $ =~ /(\d+)\.(\d+)/);
  33. use HTTP::Status ();
  34. use strict;
  35. =item $r = HTTP::Response->new($rc, [$msg, [$header, [$content]]])
  36. Constructs a new C<HTTP::Response> object describing a response with
  37. response code C<$rc> and optional message C<$msg>. The message is a
  38. short human readable single line string that explains the response
  39. code.
  40. =cut
  41. sub new
  42. {
  43. my($class, $rc, $msg, $header, $content) = @_;
  44. my $self = $class->SUPER::new($header, $content);
  45. $self->code($rc);
  46. $self->message($msg);
  47. $self;
  48. }
  49. sub clone
  50. {
  51. my $self = shift;
  52. my $clone = bless $self->SUPER::clone, ref($self);
  53. $clone->code($self->code);
  54. $clone->message($self->message);
  55. $clone->request($self->request->clone) if $self->request;
  56. # we don't clone previous
  57. $clone;
  58. }
  59. =item $r->code([$code])
  60. =item $r->message([$message])
  61. =item $r->request([$request])
  62. =item $r->previous([$previousResponse])
  63. These methods provide public access to the object attributes. The
  64. first two contain respectively the response code and the message
  65. of the response.
  66. The request attribute is a reference the request that caused this
  67. response. It does not have to be the same request as passed to the
  68. $ua->request() method, because there might have been redirects and
  69. authorization retries in between.
  70. The previous attribute is used to link together chains of responses.
  71. You get chains of responses if the first response is redirect or
  72. unauthorized.
  73. =cut
  74. sub code { shift->_elem('_rc', @_); }
  75. sub message { shift->_elem('_msg', @_); }
  76. sub previous { shift->_elem('_previous',@_); }
  77. sub request { shift->_elem('_request', @_); }
  78. =item $r->status_line
  79. Returns the string "E<lt>code> E<lt>message>". If the message attribute
  80. is not set then the official name of E<lt>code> (see L<HTTP::Status>)
  81. is substituted.
  82. =cut
  83. sub status_line
  84. {
  85. my $self = shift;
  86. my $code = $self->{'_rc'} || "000";
  87. my $mess = $self->{'_msg'} || HTTP::Status::status_message($code) || "?";
  88. return "$code $mess";
  89. }
  90. =item $r->base
  91. Returns the base URI for this response. The return value will be a
  92. reference to a URI object.
  93. The base URI is obtained from one the following sources (in priority
  94. order):
  95. =over 4
  96. =item 1.
  97. Embedded in the document content, for instance <BASE HREF="...">
  98. in HTML documents.
  99. =item 2.
  100. A "Content-Base:" or a "Content-Location:" header in the response.
  101. For backwards compatability with older HTTP implementations we will
  102. also look for the "Base:" header.
  103. =item 3.
  104. The URI used to request this response. This might not be the original
  105. URI that was passed to $ua->request() method, because we might have
  106. received some redirect responses first.
  107. =back
  108. When the LWP protocol modules produce the HTTP::Response object, then
  109. any base URI embedded in the document (step 1) will already have
  110. initialized the "Content-Base:" header. This means that this method
  111. only performs the last 2 steps (the content is not always available
  112. either).
  113. =cut
  114. sub base
  115. {
  116. my $self = shift;
  117. my $base = $self->header('Content-Base') || # used to be HTTP/1.1
  118. $self->header('Content-Location') || # HTTP/1.1
  119. $self->header('Base'); # HTTP/1.0
  120. return $HTTP::URI_CLASS->new_abs($base, $self->request->uri);
  121. }
  122. =item $r->as_string
  123. Returns a textual representation of the response. Mainly
  124. useful for debugging purposes. It takes no arguments.
  125. =cut
  126. sub as_string
  127. {
  128. require HTTP::Status;
  129. my $self = shift;
  130. my @result;
  131. #push(@result, "---- $self ----");
  132. my $code = $self->code;
  133. my $status_message = HTTP::Status::status_message($code) || "Unknown code";
  134. my $message = $self->message || "";
  135. my $status_line = "$code";
  136. my $proto = $self->protocol;
  137. $status_line = "$proto $status_line" if $proto;
  138. $status_line .= " ($status_message)" if $status_message ne $message;
  139. $status_line .= " $message";
  140. push(@result, $status_line);
  141. push(@result, $self->headers_as_string);
  142. my $content = $self->content;
  143. if (defined $content) {
  144. push(@result, $content);
  145. }
  146. #push(@result, ("-" x 40));
  147. join("\n", @result, "");
  148. }
  149. =item $r->is_info
  150. =item $r->is_success
  151. =item $r->is_redirect
  152. =item $r->is_error
  153. These methods indicate if the response was informational, sucessful, a
  154. redirection, or an error.
  155. =cut
  156. sub is_info { HTTP::Status::is_info (shift->{'_rc'}); }
  157. sub is_success { HTTP::Status::is_success (shift->{'_rc'}); }
  158. sub is_redirect { HTTP::Status::is_redirect (shift->{'_rc'}); }
  159. sub is_error { HTTP::Status::is_error (shift->{'_rc'}); }
  160. =item $r->error_as_HTML()
  161. Returns a string containing a complete HTML document indicating what
  162. error occurred. This method should only be called when $r->is_error
  163. is TRUE.
  164. =cut
  165. sub error_as_HTML
  166. {
  167. my $self = shift;
  168. my $title = 'An Error Occurred';
  169. my $body = $self->status_line;
  170. return <<EOM;
  171. <HTML>
  172. <HEAD><TITLE>$title</TITLE></HEAD>
  173. <BODY>
  174. <H1>$title</h1>
  175. $body
  176. </BODY>
  177. </HTML>
  178. EOM
  179. }
  180. =item $r->current_age
  181. Calculates the "current age" of the response as
  182. specified by E<lt>draft-ietf-http-v11-spec-07> section 13.2.3. The
  183. age of a response is the time since it was sent by the origin server.
  184. The returned value is a number representing the age in seconds.
  185. =cut
  186. sub current_age
  187. {
  188. my $self = shift;
  189. # Implementation of <draft-ietf-http-v11-spec-07> section 13.2.3
  190. # (age calculations)
  191. my $response_time = $self->client_date;
  192. my $date = $self->date;
  193. my $age = 0;
  194. if ($response_time && $date) {
  195. $age = $response_time - $date; # apparent_age
  196. $age = 0 if $age < 0;
  197. }
  198. my $age_v = $self->header('Age');
  199. if ($age_v && $age_v > $age) {
  200. $age = $age_v; # corrected_received_age
  201. }
  202. my $request = $self->request;
  203. if ($request) {
  204. my $request_time = $request->date;
  205. if ($request_time) {
  206. # Add response_delay to age to get 'corrected_initial_age'
  207. $age += $response_time - $request_time;
  208. }
  209. }
  210. if ($response_time) {
  211. $age += time - $response_time;
  212. }
  213. return $age;
  214. }
  215. =item $r->freshness_lifetime
  216. Calculates the "freshness lifetime" of the response
  217. as specified by E<lt>draft-ietf-http-v11-spec-07> section 13.2.4. The
  218. "freshness lifetime" is the length of time between the generation of a
  219. response and its expiration time. The returned value is a number
  220. representing the freshness lifetime in seconds.
  221. If the response does not contain an "Expires" or a "Cache-Control"
  222. header, then this function will apply some simple heuristic based on
  223. 'Last-Modified' to determine a suitable lifetime.
  224. =cut
  225. sub freshness_lifetime
  226. {
  227. my $self = shift;
  228. # First look for the Cache-Control: max-age=n header
  229. my @cc = $self->header('Cache-Control');
  230. if (@cc) {
  231. my $cc;
  232. for $cc (@cc) {
  233. my $cc_dir;
  234. for $cc_dir (split(/\s*,\s*/, $cc)) {
  235. if ($cc_dir =~ /max-age\s*=\s*(\d+)/i) {
  236. return $1;
  237. }
  238. }
  239. }
  240. }
  241. # Next possibility is to look at the "Expires" header
  242. my $date = $self->date || $self->client_date || time;
  243. my $expires = $self->expires;
  244. unless ($expires) {
  245. # Must apply heuristic expiration
  246. my $last_modified = $self->last_modified;
  247. if ($last_modified) {
  248. my $h_exp = ($date - $last_modified) * 0.10; # 10% since last-mod
  249. if ($h_exp < 60) {
  250. return 60; # minimum
  251. } elsif ($h_exp > 24 * 3600) {
  252. # Should give a warning if more than 24 hours according to
  253. # <draft-ietf-http-v11-spec-07> section 13.2.4, but I don't
  254. # know how to do it from this function interface, so I just
  255. # make this the maximum value.
  256. return 24 * 3600;
  257. }
  258. return $h_exp;
  259. } else {
  260. return 3600; # 1 hour is fallback when all else fails
  261. }
  262. }
  263. return $expires - $date;
  264. }
  265. =item $r->is_fresh
  266. Returns TRUE if the response is fresh, based on the values of
  267. freshness_lifetime() and current_age(). If the response is no longer
  268. fresh, then it has to be refetched or revalidated by the origin
  269. server.
  270. =cut
  271. sub is_fresh
  272. {
  273. my $self = shift;
  274. $self->freshness_lifetime > $self->current_age;
  275. }
  276. =item $r->fresh_until
  277. Returns the time when this entiy is no longer fresh.
  278. =cut
  279. sub fresh_until
  280. {
  281. my $self = shift;
  282. return $self->freshness_lifetime - $self->current_age + time;
  283. }
  284. 1;
  285. =back
  286. =head1 COPYRIGHT
  287. Copyright 1995-1997 Gisle Aas.
  288. This library is free software; you can redistribute it and/or
  289. modify it under the same terms as Perl itself.
  290. =cut