File Coverage

blib/lib/Cache/KyotoTycoon/REST.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Cache::KyotoTycoon::REST;
2 3     3   549380 use strict;
  3         7  
  3         111  
3 3     3   15 use warnings;
  3         6  
  3         87  
4 3     3   58 use 5.00800;
  3         44  
  3         195  
5             our $VERSION = '0.03';
6 3     3   2741 use URI::Escape ();
  3         5134  
  3         79  
7              
8 3     3   10123 use WWW::Curl::Easy;
  0            
  0            
9              
10             sub new {
11             my $class = shift;
12             my %args = @_==1 ? %{$_[0]} : @_;
13              
14             my $agent = $args{agent} || "$class/$VERSION";
15             my $timeout = $args{timeout} || 5;
16             my $db = $args{db};
17              
18             my $curl = WWW::Curl::Easy->new();
19             $curl->setopt(CURLOPT_TIMEOUT, $timeout);
20             $curl->setopt(CURLOPT_USERAGENT, $agent);
21             $curl->setopt(CURLOPT_HEADER, 0);
22              
23             my $host = $args{host} || '127.0.0.1';
24             my $port = $args{port} || 1978;
25             my $base = "http://${host}:${port}/";
26             $base .= URI::Escape::uri_escape($db) . '/' if defined($db);
27             bless {
28             curl => $curl,
29             base => $base,
30             }, $class;
31             }
32              
33             sub base { $_[0]->{base} }
34              
35             sub get {
36             my ($self, $key) = @_;
37             my $curl = $self->{curl};
38             $curl->setopt( CURLOPT_URL, $self->{base} . URI::Escape::uri_escape($key) );
39             $curl->setopt( CURLOPT_CUSTOMREQUEST, "GET" );
40             $curl->setopt( CURLOPT_HTTPHEADER, [
41             "Connection: Keep-Alive",
42             "Keep-Alive: 300",
43             "Content-Length: 0",
44             "\r\n"
45             ]
46             );
47             $curl->setopt( CURLOPT_NOBODY, 0 );
48             $curl->setopt( CURLOPT_POSTFIELDS, '' );
49             my $response_content = '';
50             open(my $fh, ">", \$response_content) or die "cannot open buffer";
51             $curl->setopt(CURLOPT_WRITEDATA, $fh);
52             my $retcode = $curl->perform();
53             if ($retcode == 0) {
54             my $code = $curl->getinfo(CURLINFO_HTTP_CODE);
55             if ($code eq 200) {
56             return $response_content;
57             } elsif ($code eq 404) {
58             return; # not found
59             } else {
60             die "unknown status code: $code";
61             }
62             } else {
63             die $curl->strerror($retcode);
64             }
65             }
66              
67             sub head {
68             my ($self, $key) = @_;
69             my $curl = $self->{curl};
70             $curl->setopt( CURLOPT_URL, $self->{base} . URI::Escape::uri_escape($key) );
71             $curl->setopt( CURLOPT_HTTPHEADER,
72             [
73             "Content-Length: 0",
74             "Connection: Keep-Alive",
75             "Keep-Alive: 300",
76             "\r\n"
77             ]
78             );
79             $curl->setopt( CURLOPT_NOBODY, 1 );
80             $curl->setopt( CURLOPT_CUSTOMREQUEST, "HEAD" );
81             $curl->setopt( CURLOPT_POSTFIELDS, '' );
82             $curl->setopt( CURLOPT_HEADER, 0 );
83             $curl->setopt( CURLOPT_WRITEDATA, undef );
84             my $xt;
85             $curl->setopt( CURLOPT_HEADERFUNCTION,
86             sub {
87             $xt = $1 if $_[0] =~ m{^X-Kt-Xt\s*:\s*(.+)\015\012$};
88             return length( $_[0] );
89             }
90             );
91             my $retcode = $curl->perform;
92             if ($retcode == 0) {
93             my $code = $curl->getinfo(CURLINFO_HTTP_CODE);
94             if ($code eq 200) {
95             return $xt || '';
96             } elsif ($code eq 404) {
97             return; # not found
98             }
99             } else {
100             die $curl->strerror($retcode);
101             }
102             }
103              
104             sub put {
105             my ( $self, $key, $val, $expires_time ) = @_;
106             my @headers = (
107             "Content-Length: " . length($val),
108             "Connection: Keep-Alive",
109             "Keep-Alive: 300",
110             "\r\n"
111             );
112             if ($expires_time) {
113             my $expires =
114             $expires_time > 0 ? time() + $expires_time : -$expires_time;
115             unshift @headers, "X-Kt-Xt: $expires";
116             }
117             my $curl = $self->{curl};
118             $curl->setopt( CURLOPT_URL, $self->{base} . URI::Escape::uri_escape($key) );
119             $curl->setopt( CURLOPT_NOBODY, 0 );
120             $curl->setopt( CURLOPT_HTTPHEADER, \@headers );
121             $curl->setopt( CURLOPT_CUSTOMREQUEST, "PUT" );
122             $curl->setopt( CURLOPT_POSTFIELDS, $val );
123             $curl->setopt( CURLOPT_WRITEDATA, undef );
124             $curl->setopt( CURLOPT_HEADERFUNCTION, undef );
125              
126             my $retcode = $curl->perform();
127             if ( $retcode == 0 ) {
128             my $code = $curl->getinfo(CURLINFO_HTTP_CODE);
129             if ( $code eq 201 ) {
130             return 1;
131             }
132             else {
133             return undef;
134             }
135             }
136             else {
137             die $curl->strerror($retcode);
138             }
139             }
140              
141             sub delete {
142             my ($self, $key) = @_;
143             my $curl = $self->{curl};
144             $curl->setopt( CURLOPT_URL, $self->{base} . URI::Escape::uri_escape($key) );
145             $curl->setopt( CURLOPT_HTTPHEADER,
146             [
147             "Content-Length: 0",
148             "Connection: Keep-Alive",
149             "Keep-Alive: 300",
150             "\r\n"
151             ]
152             );
153             $curl->setopt( CURLOPT_CUSTOMREQUEST, "DELETE" );
154             $curl->setopt( CURLOPT_NOBODY, 1 );
155             $curl->setopt( CURLOPT_POSTFIELDS, '' );
156             $curl->setopt( CURLOPT_HEADER, 0 );
157             $curl->setopt( CURLOPT_WRITEDATA, undef );
158             $curl->setopt( CURLOPT_HEADERFUNCTION, undef );
159             my $retcode = $curl->perform();
160             if ($retcode == 0) {
161             my $code = $curl->getinfo(CURLINFO_HTTP_CODE);
162             if ($code eq 204) {
163             return 1;
164             } elsif ($code eq '404') {
165             return 0;
166             } else {
167             return undef;
168             }
169             } else {
170             die $curl->strerror($retcode);
171             }
172             }
173              
174             1;
175             __END__