File Coverage

lib/LWP/CurlLog.pm
Criterion Covered Total %
statement 76 104 73.0
branch 13 26 50.0
condition 3 12 25.0
subroutine 10 11 90.9
pod 0 3 0.0
total 102 156 65.3


line stmt bran cond sub pod time code
1             package LWP::CurlLog;
2 1     1   90149 use strict;
  1         1  
  1         28  
3 1     1   4 use warnings;
  1         1  
  1         60  
4              
5             BEGIN {
6 1     1   3 eval {
7 1         1098 require LWP::UserAgent;
8             };
9 1         74947 eval {
10 1         887 require HTTP::Tiny;
11             };
12             }
13              
14             our $VERSION = "0.04";
15             our %opts = (
16             file => undef,
17             response => 1,
18             options => "-k",
19             timing => 0,
20             trace => 0,
21             );
22              
23             sub import {
24 1     1   16 my ($package, %args) = @_;
25 1         5 for my $key (keys %args) {
26 2         5 $opts{$key} = $args{$key};
27             }
28              
29 1 50       9 if (!$opts{file}) {
30 0         0 $opts{fh} = \*STDERR;
31             }
32             else {
33 1         2 my $expanded_file = $opts{file};
34 1 50       5 if ($expanded_file =~ m{^~/}) {
35 0   0     0 my $home = $ENV{HOME} || (getpwuid($<))[7];
36 0         0 $expanded_file =~ s{^~/}{$home/};
37             }
38 1 50       192 open $opts{fh}, ">>", $expanded_file or die "Can't open $opts{file}: $!";
39             }
40 1         8 select($opts{fh});
41 1         5 $| = 1;
42 1         48 select(STDOUT);
43             }
44              
45 1     1   74995 no strict "refs";
  1         2  
  1         69  
46 1     1   7 no warnings "redefine";
  1         2  
  1         1852  
47              
48             my $orig_lusr = \&LWP::UserAgent::send_request;
49             *{"LWP::UserAgent::send_request"} = sub {
50 1     1   279401 my ($self, $req) = @_;
51 1         3 my $headers = {};
52 1         6 for my $name ($req->headers()->header_field_names()) {
53 1         27 $headers->{$name} = $req->{headers}{$name};
54             }
55 1         9 my $content = $req->decoded_content();
56 1         327 my $res = request("LWP", $orig_lusr, \@_, $req->method(), $req->uri(), $headers, $content);
57 1         6 return $res;
58             };
59              
60             my $orig_htr = \&HTTP::Tiny::_request;
61             *{"HTTP::Tiny::_request"} = sub {
62 0     0   0 my ($self, $method, $url, $args) = @_;
63 0         0 my $res = request("HT", $orig_htr, \@_, $method, $url, $args->{headers}, $args->{content});
64 0         0 return $res;
65             };
66              
67             sub request {
68 1     1 0 26 my ($module, $orig_sub, $orig_args, $method, $url, $headers, $content) = @_;
69              
70 1         2 my $cmd = "curl ";
71 1 50       15 if ($url =~ /[=&;?]/) {
72 0         0 $cmd .= "\"$url\" ";
73             }
74             else {
75 1         13 $cmd .= "$url ";
76             }
77 1 50       13 if ($opts{options}) {
78 1         11 $cmd .= "$opts{options} ";
79             }
80              
81 1 50 33     15 if ($method && ($method ne "GET" || length $content)) {
      33        
82 0         0 $cmd .= "-X $method ";
83             }
84              
85 1         4 for my $name (keys %$headers) {
86 1 50       10 if ($name =~ /^(Content-Length|User-Agent)$/i) {
87 1         3 next;
88             }
89 0         0 my $value = $headers->{$name};
90 0         0 $value =~ s{([\\\$"])}{\\$1}g;
91 0         0 $cmd .= "-H \"$name: $value\" ";
92             }
93              
94 1 50 33     7 if (defined $content && length $content) {
95 0         0 $content =~ s{([\\\$"])}{\\$1}g;
96 0         0 $cmd .= "-d \"$content\" ";
97             }
98 1         11 $cmd =~ s/\s*$//;
99              
100 1         46 log_print("# " . localtime() . " $module request\n");
101 1         7 log_print_stack();
102 1         9 log_print("$cmd\n");
103 1         3 my $time1 = time();
104 1         8 my $res = $orig_sub->(@$orig_args);
105 1         163789 my $time2 = time();
106              
107 1 50       7 if ($opts{response}) {
108 0         0 log_print("\n# " . localtime() . " $module response\n");
109 0         0 my $str;
110 0 0       0 if (eval {$res->isa("HTTP::Response")}) {
  0         0  
111 0         0 $str = $res->as_string();
112             }
113             else {
114 0         0 $str = "$res->{protocol} $res->{status} $res->{reason}\n";
115 0         0 for my $name (keys %{$res->{headers}}) {
  0         0  
116 0         0 $str .= "$name: $res->{headers}{$name}\n";
117             }
118 0         0 $str .= "\n";
119 0         0 $str .= $res->{content};
120             }
121 0         0 $str =~ s/\s*$//g;
122 0         0 log_print("$str\n");
123             }
124 1 50       4 if ($opts{timing}) {
125 0         0 my $diff = $time2 - $time1;
126 0         0 log_print("# ${diff}s\n");
127             }
128              
129 1         4 log_print("\n");
130              
131 1         4 return $res;
132             }
133              
134             sub log_print {
135 4     4 0 10 my (@args) = @_;
136 4         10 my $mesg = join("", @args);
137 4         5 print {$opts{fh}} $mesg;
  4         244  
138             }
139              
140              
141             sub log_print_stack {
142 1     1 0 2 my @callers;
143 1         13 for (my $i = 0; my @caller = caller($i); $i++) {
144 6         51 push @callers, \@caller;
145             }
146              
147 1         2 my @filtered_callers;
148 1         3 CALLER: for my $caller (reverse @callers) {
149 2         7 my ($package, $file, $line, $long_name) = @$caller;
150 2         3 for my $test_package ("LWP::CurlLog", "HTTP::Tiny", "HTTP::AnyUA", "LWP::UserAgent") {
151 8 100       180 if ($package =~ /^${test_package}($|::)/) {
152 1         4 last CALLER;
153             }
154             }
155 1         4 push @filtered_callers, $caller;
156              
157             }
158 1 50       6 if (!$opts{trace}) {
159 1         4 @filtered_callers = ($filtered_callers[-1]);
160             }
161              
162 1         3 for my $caller (@filtered_callers) {
163 1         4 my ($package, $file, $line, $long_name) = @$caller;
164 1         2 my $name = $long_name;
165 1         7 $name =~ s/.*:://;
166 1         6 log_print("# $name $file $line\n");
167             }
168             }
169              
170             1;
171              
172             __END__