line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Elasticsearch::Role::Cxn::HTTP; |
2
|
|
|
|
|
|
|
$Elasticsearch::Role::Cxn::HTTP::VERSION = '1.05'; |
3
|
42
|
|
|
42
|
|
42834
|
use Moo::Role; |
|
42
|
|
|
|
|
140
|
|
|
42
|
|
|
|
|
516
|
|
4
|
|
|
|
|
|
|
|
5
|
42
|
|
|
42
|
|
18583
|
use URI(); |
|
42
|
|
|
|
|
94
|
|
|
42
|
|
|
|
|
1057
|
|
6
|
42
|
|
|
42
|
|
285
|
use Elasticsearch::Util qw(parse_params throw); |
|
42
|
|
|
|
|
296
|
|
|
42
|
|
|
|
|
448
|
|
7
|
42
|
|
|
42
|
|
21872
|
use namespace::clean; |
|
42
|
|
|
|
|
91
|
|
|
42
|
|
|
|
|
373
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
has 'scheme' => ( is => 'ro' ); |
10
|
|
|
|
|
|
|
has 'is_https' => ( is => 'ro' ); |
11
|
|
|
|
|
|
|
has 'userinfo' => ( is => 'ro' ); |
12
|
|
|
|
|
|
|
has 'max_content_length' => ( is => 'ro' ); |
13
|
|
|
|
|
|
|
has 'default_headers' => ( is => 'ro' ); |
14
|
|
|
|
|
|
|
has 'handle' => ( is => 'lazy' ); |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
#=================================== |
17
|
78
|
|
|
78
|
0
|
289
|
sub protocol {'http'} |
18
|
71
|
|
|
71
|
0
|
339
|
sub default_host {'http://localhost:9200'} |
19
|
555
|
|
|
555
|
0
|
4506
|
sub stringify { shift->uri . '' } |
20
|
|
|
|
|
|
|
#=================================== |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
#=================================== |
23
|
|
|
|
|
|
|
sub BUILDARGS { |
24
|
|
|
|
|
|
|
#=================================== |
25
|
147
|
|
|
147
|
0
|
152994
|
my ( $class, $params ) = parse_params(@_); |
26
|
|
|
|
|
|
|
|
27
|
147
|
|
50
|
|
|
766
|
my $node = $params->{node} |
28
|
|
|
|
|
|
|
|| { host => 'localhost', port => '9200' }; |
29
|
|
|
|
|
|
|
|
30
|
147
|
100
|
|
|
|
595
|
unless ( ref $node eq 'HASH' ) { |
31
|
144
|
100
|
|
|
|
665
|
unless ( $node =~ m{^http(s)?://} ) { |
32
|
119
|
100
|
|
|
|
534
|
$node = ( $params->{use_https} ? 'https://' : 'http://' ) . $node; |
33
|
|
|
|
|
|
|
} |
34
|
144
|
100
|
100
|
|
|
691
|
if ( $params->{port} && $node !~ m{//[^/]+:\d+} ) { |
35
|
1
|
|
|
|
|
12
|
$node =~ s{(//[^/]+)}{$1:$params->{port}}; |
36
|
|
|
|
|
|
|
} |
37
|
144
|
|
|
|
|
948
|
my $uri = URI->new($node); |
38
|
144
|
|
|
|
|
528415
|
$node = { |
39
|
|
|
|
|
|
|
scheme => $uri->scheme, |
40
|
|
|
|
|
|
|
host => $uri->host, |
41
|
|
|
|
|
|
|
port => $uri->port, |
42
|
|
|
|
|
|
|
path => $uri->path, |
43
|
|
|
|
|
|
|
userinfo => $uri->userinfo |
44
|
|
|
|
|
|
|
}; |
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
|
47
|
147
|
|
100
|
|
|
25311
|
my $host = $node->{host} || 'localhost'; |
48
|
147
|
|
100
|
|
|
6806
|
my $userinfo = $node->{userinfo} || $params->{userinfo} || ''; |
49
|
147
|
|
66
|
|
|
685
|
my $scheme |
50
|
|
|
|
|
|
|
= $node->{scheme} || ( $params->{use_https} ? 'https' : 'http' ); |
51
|
147
|
|
66
|
|
|
1128
|
my $port |
52
|
|
|
|
|
|
|
= $node->{port} |
53
|
|
|
|
|
|
|
|| $params->{port} |
54
|
|
|
|
|
|
|
|| ( $scheme eq 'http' ? 80 : 443 ); |
55
|
147
|
|
100
|
|
|
1447
|
my $path = $node->{path} || $params->{path_prefix} || ''; |
56
|
147
|
|
|
|
|
830
|
$path =~ s{^/?}{/}g; |
57
|
147
|
|
|
|
|
602
|
$path =~ s{/+$}{}; |
58
|
|
|
|
|
|
|
|
59
|
147
|
50
|
|
|
|
308
|
my %default_headers = %{ $params->{default_headers} || {} }; |
|
147
|
|
|
|
|
1128
|
|
60
|
|
|
|
|
|
|
|
61
|
147
|
100
|
|
|
|
599
|
if ($userinfo) { |
62
|
3
|
|
|
|
|
1174
|
require MIME::Base64; |
63
|
3
|
|
|
|
|
889
|
my $auth = MIME::Base64::encode_base64($userinfo); |
64
|
3
|
|
|
|
|
9
|
chomp $auth; |
65
|
3
|
|
|
|
|
15
|
$default_headers{Authorization} = "Basic $auth"; |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
|
68
|
147
|
100
|
|
|
|
609
|
if ( $params->{deflate} ) { |
69
|
1
|
|
|
|
|
4
|
$default_headers{'Accept-Encoding'} = "deflate"; |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
|
72
|
147
|
|
|
|
|
460
|
$params->{scheme} = $scheme; |
73
|
147
|
|
|
|
|
416
|
$params->{is_http} = $scheme eq 'https'; |
74
|
147
|
|
|
|
|
381
|
$params->{host} = $host; |
75
|
147
|
|
|
|
|
404
|
$params->{port} = $port; |
76
|
147
|
|
|
|
|
347
|
$params->{path} = $path; |
77
|
147
|
|
|
|
|
19425
|
$params->{userinfo} = $userinfo; |
78
|
147
|
|
|
|
|
1157
|
$params->{uri} = URI->new("$scheme://$host:$port$path"); |
79
|
147
|
|
|
|
|
10436
|
$params->{default_headers} = \%default_headers; |
80
|
|
|
|
|
|
|
|
81
|
147
|
|
|
|
|
4875
|
return $params; |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
#=================================== |
86
|
|
|
|
|
|
|
sub build_uri { |
87
|
|
|
|
|
|
|
#=================================== |
88
|
0
|
|
|
0
|
1
|
|
my ( $self, $params ) = @_; |
89
|
0
|
|
|
|
|
|
my $uri = $self->uri->clone; |
90
|
0
|
|
|
|
|
|
$uri->path( $uri->path . $params->{path} ); |
91
|
0
|
|
|
|
|
|
$uri->query_form( $params->{qs} ); |
92
|
0
|
|
|
|
|
|
return $uri; |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
#=================================== |
96
|
|
|
|
|
|
|
before 'perform_request' => sub { |
97
|
|
|
|
|
|
|
#=================================== |
98
|
|
|
|
|
|
|
my ( $self, $params ) = @_; |
99
|
|
|
|
|
|
|
return unless defined $params->{data}; |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
my $max = $self->max_content_length |
102
|
|
|
|
|
|
|
or return; |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
return if length( $params->{data} ) < $max; |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
$self->logger->throw_error( 'ContentLength', |
107
|
|
|
|
|
|
|
"Body is longer than max_content_length ($max)", |
108
|
|
|
|
|
|
|
); |
109
|
|
|
|
|
|
|
}; |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
#=================================== |
112
|
|
|
|
|
|
|
around 'process_response' => sub { |
113
|
|
|
|
|
|
|
#=================================== |
114
|
|
|
|
|
|
|
my ( $orig, $self, $params, $code, $msg, $body, $headers ) = @_; |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
if ( my $encoding = $headers->{'content-encoding'} ) { |
117
|
|
|
|
|
|
|
$body = $self->inflate($body) |
118
|
|
|
|
|
|
|
if $encoding eq 'deflate'; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
my ($mime_type) = split /\s*;\s*/, ( $headers->{'content-type'} || '' ); |
122
|
|
|
|
|
|
|
$orig->( $self, $params, $code, $msg, $body, $mime_type ); |
123
|
|
|
|
|
|
|
}; |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
#=================================== |
126
|
|
|
|
|
|
|
sub inflate { |
127
|
|
|
|
|
|
|
#=================================== |
128
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
129
|
0
|
|
|
|
|
|
my $content = shift; |
130
|
|
|
|
|
|
|
|
131
|
0
|
|
|
|
|
|
my $output; |
132
|
0
|
|
|
|
|
|
require IO::Uncompress::Inflate; |
133
|
42
|
|
|
42
|
|
77663
|
no warnings 'once'; |
|
42
|
|
|
|
|
109
|
|
|
42
|
|
|
|
|
5301
|
|
134
|
|
|
|
|
|
|
|
135
|
0
|
0
|
|
|
|
|
IO::Uncompress::Inflate::inflate( \$content, \$output, Transparent => 0 ) |
136
|
|
|
|
|
|
|
or throw( 'Request', |
137
|
|
|
|
|
|
|
"Couldn't inflate response: $IO::Uncompress::Inflate::InflateError" ); |
138
|
|
|
|
|
|
|
|
139
|
0
|
|
|
|
|
|
return $output; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
1; |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
# ABSTRACT: Provides common functionality to HTTP Cxn implementations |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
__END__ |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=pod |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=encoding UTF-8 |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=head1 NAME |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
Elasticsearch::Role::Cxn::HTTP - Provides common functionality to HTTP Cxn implementations |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=head1 VERSION |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
version 1.05 |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=head1 DESCRIPTION |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
L<Elasticsearch::Role::Cxn::HTTP> provides common functionality to the Cxn |
163
|
|
|
|
|
|
|
implementations which use the HTTP protocol. Cxn instances are created by a |
164
|
|
|
|
|
|
|
L<Elasticsearch::Role::CxnPool> implementation, using the |
165
|
|
|
|
|
|
|
L<Elasticsearch::Cxn::Factory> class. |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=head1 CONFIGURATION |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
The configuration options are as follows: |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
=head2 C<node> |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
A single C<node> is passed to C<new()> by the L<Elasticsearch::Cxn::Factory> |
174
|
|
|
|
|
|
|
class. It can either be a URI or a hash containing each part. For instance: |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
node => 'localhost'; # equiv of 'http://localhost:80' |
177
|
|
|
|
|
|
|
node => 'localhost:9200'; # equiv of 'http://localhost:9200' |
178
|
|
|
|
|
|
|
node => 'http://localhost:9200'; |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
node => 'https://localhost'; # equiv of 'https://localhost:443' |
181
|
|
|
|
|
|
|
node => 'localhost/path'; # equiv of 'http://localhost:80/path' |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
node => 'http://user:pass@localhost'; # equiv of 'http://localhost:80' |
185
|
|
|
|
|
|
|
# with userinfo => 'user:pass' |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
Alternatively, a C<node> can be specified as a hash: |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
{ |
190
|
|
|
|
|
|
|
scheme => 'http', |
191
|
|
|
|
|
|
|
host => 'search.domain.com', |
192
|
|
|
|
|
|
|
port => '9200', |
193
|
|
|
|
|
|
|
path => '/path', |
194
|
|
|
|
|
|
|
userinfo => 'user:pass' |
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
Similarly, default values can be specified with C<port>, C<path_prefix>, |
198
|
|
|
|
|
|
|
C<userinfo> and C<use_https>: |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
$e = Elasticsearch->new( |
201
|
|
|
|
|
|
|
port => 9201, |
202
|
|
|
|
|
|
|
path_prefix => '/path', |
203
|
|
|
|
|
|
|
userinfo => 'user:pass', |
204
|
|
|
|
|
|
|
use_https => 1, |
205
|
|
|
|
|
|
|
nodes => [ 'search1', 'search2' ] |
206
|
|
|
|
|
|
|
) |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=head2 C<max_content_length> |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
By default, Elasticsearch nodes accept a maximum post body of 100MB or |
211
|
|
|
|
|
|
|
C<104_857_600> bytes. This client enforces that limit. The limit can |
212
|
|
|
|
|
|
|
be customised with the C<max_content_length> parameter (specified in bytes). |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
If you're using the L<Elasticsearch::CxnPool::Sniff> module, then the |
215
|
|
|
|
|
|
|
C<max_content_length> will be automatically retrieved from the live cluster, |
216
|
|
|
|
|
|
|
unless you specify a custom C<max_content_length>: |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
# max_content_length retrieved from cluster |
219
|
|
|
|
|
|
|
$e = Elasticsearch->new( |
220
|
|
|
|
|
|
|
cxn_pool => 'Sniff' |
221
|
|
|
|
|
|
|
); |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
# max_content_length fixed at 10,000 bytes |
224
|
|
|
|
|
|
|
$e = Elasticsearch->new( |
225
|
|
|
|
|
|
|
cxn_pool => 'Sniff', |
226
|
|
|
|
|
|
|
max_content_length => 10_000 |
227
|
|
|
|
|
|
|
); |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=head2 C<deflate> |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
This client can request compressed responses from Elasticsearch by |
232
|
|
|
|
|
|
|
enabling the C<http.compression> config setting in |
233
|
|
|
|
|
|
|
L<Elasticsearch|http://www.elasticsearch.org/guide/reference/modules/http/> |
234
|
|
|
|
|
|
|
and setting C<deflate> to C<true>: |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
$e = Elasticsearch->new( |
237
|
|
|
|
|
|
|
deflate => 1 |
238
|
|
|
|
|
|
|
); |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
=head1 METHODS |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
None of the methods listed below are useful to the user. They are |
243
|
|
|
|
|
|
|
documented for those who are writing alternative implementations only. |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=head2 C<scheme()> |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
$scheme = $cxn->scheme; |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
Returns the scheme of the connection, ie C<http> or C<https>. |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
=head2 C<is_https()> |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
$bool = $cxn->is_https; |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
Returns C<true> or C<false> depending on whether the C</scheme()> is C<https> |
256
|
|
|
|
|
|
|
or not. |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=head2 C<userinfo()> |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
$userinfo = $cxn->userinfo |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
Returns the username and password of the cxn, if any, eg C<"user:pass">. |
263
|
|
|
|
|
|
|
If C<userinfo> is provided, then a Basic Authorization header is added |
264
|
|
|
|
|
|
|
to each request. |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
=head2 C<default_headers()> |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
$headers = $cxn->default_headers |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
The default headers that are passed with each request. This includes |
271
|
|
|
|
|
|
|
the C<Accept-Encoding> header if C</deflate> is true, and the C<Authorization> |
272
|
|
|
|
|
|
|
header if C</userinfo> has a value. |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
=head2 C<max_content_length()> |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
$int = $cxn->max_content_length; |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
Returns the maximum length in bytes that the HTTP body can have. |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
=head2 C<build_uri()> |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
$uri = $cxn->build_uri({ path => '/_search', qs => { size => 10 }}); |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
Returns the HTTP URI to use for a particular request, combining the passed |
285
|
|
|
|
|
|
|
in C<path> parameter with any defined C<path_prefix>, and adding the |
286
|
|
|
|
|
|
|
query-string parameters. |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=head1 AUTHOR |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
Clinton Gormley <drtech@cpan.org> |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
This software is Copyright (c) 2014 by Elasticsearch BV. |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
This is free software, licensed under: |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
The Apache License, Version 2.0, January 2004 |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
=cut |