| line | stmt | bran | cond | sub | pod | time | code | 
| 1 | 18 |  |  | 18 |  | 138705 | use 5.010; | 
|  | 18 |  |  |  |  | 69 |  | 
| 2 | 18 |  |  | 18 |  | 90 | use strict; | 
|  | 18 |  |  |  |  | 43 |  | 
|  | 18 |  |  |  |  | 468 |  | 
| 3 | 18 |  |  | 18 |  | 80 | use warnings; | 
|  | 18 |  |  |  |  | 39 |  | 
|  | 18 |  |  |  |  | 442 |  | 
| 4 | 18 |  |  | 18 |  | 1934 | use utf8; | 
|  | 18 |  |  |  |  | 103 |  | 
|  | 18 |  |  |  |  | 122 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 |  |  |  |  |  |  | package Neo4j::Driver::Net::HTTP::LWP; | 
| 7 |  |  |  |  |  |  | # ABSTRACT: HTTP network adapter for libwww-perl | 
| 8 |  |  |  |  |  |  | $Neo4j::Driver::Net::HTTP::LWP::VERSION = '0.38'; | 
| 9 |  |  |  |  |  |  |  | 
| 10 | 18 |  |  | 18 |  | 1195 | use Carp qw(croak); | 
|  | 18 |  |  |  |  | 44 |  | 
|  | 18 |  |  |  |  | 1660 |  | 
| 11 |  |  |  |  |  |  | our @CARP_NOT = qw(Neo4j::Driver::Net::HTTP); | 
| 12 |  |  |  |  |  |  |  | 
| 13 | 18 |  |  | 18 |  | 586 | use JSON::MaybeXS 1.003003 qw(); | 
|  | 18 |  |  |  |  | 8516 |  | 
|  | 18 |  |  |  |  | 485 |  | 
| 14 | 18 |  |  | 18 |  | 13509 | use LWP::UserAgent 6.04 qw(); | 
|  | 18 |  |  |  |  | 763912 |  | 
|  | 18 |  |  |  |  | 649 |  | 
| 15 | 18 |  |  | 18 |  | 155 | use URI 1.31; | 
|  | 18 |  |  |  |  | 262 |  | 
|  | 18 |  |  |  |  | 18808 |  | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | my $CONTENT_TYPE = 'application/json'; | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | sub new { | 
| 21 | 19 |  |  | 19 | 1 | 25001 | my ($class, $driver) = @_; | 
| 22 |  |  |  |  |  |  |  | 
| 23 | 19 |  |  |  |  | 116 | my $self = bless { | 
| 24 |  |  |  |  |  |  | json_coder => JSON::MaybeXS->new(utf8 => 1, allow_nonref => 0), | 
| 25 |  |  |  |  |  |  | }, $class; | 
| 26 |  |  |  |  |  |  |  | 
| 27 | 19 |  |  |  |  | 424 | my $uri = $driver->config('uri'); | 
| 28 | 19 | 100 |  |  |  | 139 | if (my $auth = $driver->config('auth')) { | 
| 29 | 8 | 100 |  |  |  | 86 | croak "Only HTTP Basic Authentication is supported" if $auth->{scheme} ne 'basic'; | 
| 30 | 7 |  | 100 |  |  | 27 | my $userid = $auth->{principal}   // ''; | 
| 31 | 7 |  | 100 |  |  | 25 | my $passwd = $auth->{credentials} // ''; | 
| 32 |  |  |  |  |  |  | my $userinfo = join ':', map { | 
| 33 | 7 | 100 |  |  |  | 12 | utf8::encode $_ if utf8::is_utf8 $_;  # uri_escape doesn't handle wide characters | 
|  | 14 |  |  |  |  | 190 |  | 
| 34 | 14 |  |  |  |  | 39 | URI::Escape::uri_escape $_; | 
| 35 |  |  |  |  |  |  | } $userid, $passwd; | 
| 36 | 7 |  |  |  |  | 194 | $uri = $uri->clone; | 
| 37 | 7 |  |  |  |  | 111 | $uri->userinfo($userinfo); | 
| 38 |  |  |  |  |  |  | } | 
| 39 | 18 |  |  |  |  | 560 | $self->{uri_base} = $uri; | 
| 40 |  |  |  |  |  |  |  | 
| 41 | 18 |  |  |  |  | 37 | my $version = $Neo4j::Driver::Net::HTTP::LWP::VERSION; | 
| 42 | 18 | 100 |  |  |  | 124 | my $agent = $self->{agent} = LWP::UserAgent->new( | 
| 43 |  |  |  |  |  |  | # User-Agent: Neo4j-Driver/0.21 libwww-perl/6.52 | 
| 44 |  |  |  |  |  |  | agent => sprintf("Neo4j-Driver%s ", $version ? "/$version" : ""), | 
| 45 |  |  |  |  |  |  | timeout => $driver->config('timeout'), | 
| 46 |  |  |  |  |  |  | ); | 
| 47 | 18 |  |  |  |  | 17072 | $agent->default_headers->header( 'X-Stream' => 'true' ); | 
| 48 |  |  |  |  |  |  |  | 
| 49 | 18 | 100 |  |  |  | 1262 | if ($uri->scheme eq 'https') { | 
| 50 | 3 |  | 100 |  |  | 59 | my $unencrypted = defined $driver->config('encrypted') && ! $driver->config('encrypted'); | 
| 51 | 3 | 100 |  |  |  | 20 | croak "HTTPS does not support unencrypted communication; use HTTP" if $unencrypted; | 
| 52 | 2 |  |  |  |  | 8 | $agent->ssl_opts( verify_hostname => 1 ); | 
| 53 | 2 | 100 |  |  |  | 57 | if (defined( my $trust_ca = $driver->config('trust_ca') )) { | 
| 54 | 1 | 50 |  |  |  | 60 | croak "trust_ca file '$trust_ca' can't be used: $!" if ! open(my $fh, '<', $trust_ca); | 
| 55 | 0 |  |  |  |  | 0 | $agent->ssl_opts( SSL_ca_file => $trust_ca ); | 
| 56 |  |  |  |  |  |  | } | 
| 57 |  |  |  |  |  |  | } | 
| 58 |  |  |  |  |  |  | else { | 
| 59 | 15 | 100 |  |  |  | 316 | croak "HTTP does not support encrypted communication; use HTTPS" if $driver->config('encrypted'); | 
| 60 |  |  |  |  |  |  | } | 
| 61 |  |  |  |  |  |  |  | 
| 62 | 14 |  |  |  |  | 205 | return $self; | 
| 63 |  |  |  |  |  |  | } | 
| 64 |  |  |  |  |  |  |  | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | sub protocol { | 
| 67 |  |  |  |  |  |  | # uncoverable pod (see Deprecations.pod) | 
| 68 | 2 |  |  | 2 | 0 | 1536 | my ($self) = @_; | 
| 69 | 2 |  |  |  |  | 44 | warnings::warnif deprecated => __PACKAGE__ . "->protocol() is deprecated"; | 
| 70 | 2 |  | 100 |  |  | 717 | return $self->{response}->protocol // 'HTTP'; | 
| 71 |  |  |  |  |  |  | } | 
| 72 |  |  |  |  |  |  |  | 
| 73 |  |  |  |  |  |  |  | 
| 74 |  |  |  |  |  |  | sub agent { | 
| 75 |  |  |  |  |  |  | # uncoverable pod (see Deprecations.pod) | 
| 76 | 1 |  |  | 1 | 0 | 3461 | my ($self) = @_; | 
| 77 | 1 |  |  |  |  | 51 | warnings::warnif deprecated => __PACKAGE__ . "->agent() is deprecated; call ua() instead"; | 
| 78 | 1 |  |  |  |  | 765 | return $self->{agent}; | 
| 79 |  |  |  |  |  |  | } | 
| 80 |  |  |  |  |  |  |  | 
| 81 |  |  |  |  |  |  |  | 
| 82 | 3 |  |  | 3 | 1 | 2196 | sub ua { shift->{agent} } | 
| 83 |  |  |  |  |  |  |  | 
| 84 | 7 |  |  | 7 | 1 | 5409 | sub uri { shift->{uri_base} } | 
| 85 |  |  |  |  |  |  |  | 
| 86 | 2 |  |  | 2 | 1 | 2519 | sub json_coder { shift->{json_coder} } | 
| 87 |  |  |  |  |  |  |  | 
| 88 | 5 |  | 100 | 5 | 1 | 2169 | sub http_reason { shift->{response}->message // '' } | 
| 89 |  |  |  |  |  |  |  | 
| 90 | 2 |  | 100 | 2 | 1 | 1523 | sub date_header { scalar shift->{response}->header('Date') // '' } | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  |  | 
| 93 |  |  |  |  |  |  | sub http_header { | 
| 94 | 13 |  |  | 13 | 1 | 9061 | my $response = shift->{response}; | 
| 95 | 13 |  | 100 |  |  | 40 | my $header = { | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 96 |  |  |  |  |  |  | content_type => scalar $response->header('Content-Type') // '', | 
| 97 |  |  |  |  |  |  | location     => scalar $response->header('Location') // '', | 
| 98 |  |  |  |  |  |  | status       => $response->code // '', | 
| 99 |  |  |  |  |  |  | success      => $response->is_success, | 
| 100 |  |  |  |  |  |  | }; | 
| 101 | 13 | 100 | 100 |  |  | 1426 | if ( ! $header->{success} && $response->header('Client-Warning') // '' eq 'Internal response' ) { | 
|  |  |  | 100 |  |  |  |  | 
| 102 | 3 |  |  |  |  | 129 | $header->{content_type} = ''; | 
| 103 | 3 |  |  |  |  | 5 | $header->{status}       = ''; | 
| 104 |  |  |  |  |  |  | } | 
| 105 | 13 |  |  |  |  | 331 | return $header; | 
| 106 |  |  |  |  |  |  | } | 
| 107 |  |  |  |  |  |  |  | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  | sub fetch_event { | 
| 110 | 596 |  |  | 596 | 1 | 6356 | my ($self) = @_; | 
| 111 | 596 | 100 |  |  |  | 1286 | $self->{buffer} = [grep { length } split m/\n|\x{1e}/, $self->fetch_all] unless defined $self->{buffer}; | 
|  | 939 |  |  |  |  | 6118 |  | 
| 112 | 596 |  |  |  |  | 726 | return shift @{$self->{buffer}}; | 
|  | 596 |  |  |  |  | 1364 |  | 
| 113 |  |  |  |  |  |  | } | 
| 114 |  |  |  |  |  |  |  | 
| 115 |  |  |  |  |  |  |  | 
| 116 |  |  |  |  |  |  | sub fetch_all { | 
| 117 | 4 |  |  | 4 | 1 | 11174 | my ($self) = @_; | 
| 118 | 4 |  |  |  |  | 15 | return $self->{response}->content; | 
| 119 |  |  |  |  |  |  | } | 
| 120 |  |  |  |  |  |  |  | 
| 121 |  |  |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | sub request { | 
| 123 | 6 |  |  | 6 | 1 | 27613 | my ($self, $method, $url, $json, $accept, $mode) = @_; | 
| 124 |  |  |  |  |  |  |  | 
| 125 | 6 |  |  |  |  | 15 | $self->{buffer} = undef; | 
| 126 |  |  |  |  |  |  |  | 
| 127 | 6 |  |  |  |  | 24 | $url = URI->new_abs( $url, $self->{uri_base} ); | 
| 128 | 6 |  |  |  |  | 1693 | $method = lc $method; | 
| 129 | 6 | 100 |  |  |  | 17 | if ($json) { | 
| 130 |  |  |  |  |  |  | $self->{response} = $self->{agent}->$method( | 
| 131 |  |  |  |  |  |  | $url, | 
| 132 |  |  |  |  |  |  | 'Accept' => $accept, | 
| 133 | 3 | 100 |  |  |  | 35 | 'Content' => $self->{json_coder}->encode($json), | 
| 134 |  |  |  |  |  |  | 'Content-Type' => $CONTENT_TYPE, | 
| 135 |  |  |  |  |  |  | $mode ? ('Access-Mode' => $mode) : () | 
| 136 |  |  |  |  |  |  | ); | 
| 137 |  |  |  |  |  |  | } | 
| 138 |  |  |  |  |  |  | else { | 
| 139 | 3 |  |  |  |  | 18 | $self->{response} = $self->{agent}->$method( | 
| 140 |  |  |  |  |  |  | $url, | 
| 141 |  |  |  |  |  |  | 'Accept' => $accept, | 
| 142 |  |  |  |  |  |  | ); | 
| 143 |  |  |  |  |  |  | } | 
| 144 |  |  |  |  |  |  | } | 
| 145 |  |  |  |  |  |  |  | 
| 146 |  |  |  |  |  |  |  | 
| 147 |  |  |  |  |  |  | 1; | 
| 148 |  |  |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | __END__ |