File Coverage

blib/lib/App/MFILE/HTTP.pm
Criterion Covered Total %
statement 38 65 58.4
branch 0 8 0.0
condition n/a
subroutine 13 17 76.4
pod 2 2 100.0
total 53 92 57.6


line stmt bran cond sub pod time code
1             # *************************************************************************
2             # Copyright (c) 2014, SUSE LLC
3             #
4             # All rights reserved.
5             #
6             # Redistribution and use in source and binary forms, with or without
7             # modification, are permitted provided that the following conditions are met:
8             #
9             # 1. Redistributions of source code must retain the above copyright notice,
10             # this list of conditions and the following disclaimer.
11             #
12             # 2. Redistributions in binary form must reproduce the above copyright
13             # notice, this list of conditions and the following disclaimer in the
14             # documentation and/or other materials provided with the distribution.
15             #
16             # 3. Neither the name of SUSE LLC nor the names of its contributors may be
17             # used to endorse or promote products derived from this software without
18             # specific prior written permission.
19             #
20             # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21             # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22             # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23             # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24             # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25             # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26             # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27             # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28             # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29             # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30             # POSSIBILITY OF SUCH DAMAGE.
31             # *************************************************************************
32             #
33             # HTTP module
34             #
35             package App::MFILE::HTTP;
36              
37 1     1   3704 use 5.012;
  1         3  
38 1     1   4 use strict;
  1         1  
  1         18  
39 1     1   3 use warnings;
  1         2  
  1         28  
40              
41 1     1   652 use App::CELL qw( $CELL $log $site $meta );
  1         83763  
  1         173  
42 1     1   11 use Data::Dumper;
  1         3  
  1         67  
43 1     1   1066 use Encode qw( encode_utf8 );
  1         12863  
  1         115  
44 1     1   8 use Exporter qw( import );
  1         3  
  1         46  
45 1     1   831 use HTTP::Request::Common qw( GET PUT POST DELETE );
  1         18406  
  1         125  
46 1     1   938 use JSON;
  1         12893  
  1         7  
47 1     1   872 use LWP::UserAgent;
  1         18747  
  1         37  
48 1     1   7 use Params::Validate qw( :all );
  1         1  
  1         246  
49 1     1   5 use Try::Tiny;
  1         2  
  1         247  
50              
51             =head1 NAME
52              
53             App::MFILE::HTTP - general REST request forwarder for MFILE-based clients
54              
55              
56              
57              
58             =head1 SYNOPSIS
59              
60             use App::MFILE::HTTP qw( rest_req );
61              
62              
63              
64              
65             =head1 DESCRIPTION
66              
67             Module where C resides.
68              
69              
70              
71             =head1 EXPORTS
72              
73             =cut
74              
75             our @EXPORT_OK = qw( rest_req );
76              
77              
78              
79              
80             =head1 FUNCTIONS
81              
82              
83             =head2 init_ua
84              
85             Initialize a LWP::UserAgent singleton object.
86              
87             Takes two _mandatory_ parameters:
88              
89             - a LWP::UserAgent object
90             - a scalar (filename of cookie jar)
91              
92             =cut
93              
94             sub init_ua {
95             # process arguments
96 0     0 1   my ( $ua, $cj ) = validate_pos( @_,
97             { type => HASHREF, can => 'cookie_jar' },
98             { type => SCALAR },
99             );
100 0           $ua->cookie_jar( { file => $cj } );
101 0           return;
102             }
103              
104              
105             =head2 rest_req
106              
107             Algorithm: send request to REST server, get JSON response, decode it, return it.
108              
109             Takes a single _mandatory_ parameter: a LWP::UserAgent object
110              
111             Optionally takes PARAMHASH:
112              
113             server => [URI OF REST SERVER] default is 'http://0:5000'
114             method => [HTTP METHOD TO USE] default is 'GET'
115             nick => [NICK FOR BASIC AUTH] optional
116             password => [PASSWORD FOR BASIC AUTH] optional
117             path => [PATH OF REST RESOURCE] default is '/'
118             req_body => [HASHREF] optional
119              
120             Returns HASHREF containing:
121              
122             hr => HTTP::Response object (stripped of the body)
123             body => [BODY OF HTTP RESPONSE, IF ANY]
124              
125             =cut
126              
127             sub rest_req {
128              
129             # process arguments
130 0     0 1   my $ua = shift;
131 0 0         die "Bad user agent object" unless ref( $ua ) eq 'LWP::UserAgent';
132 0           my %ARGS = validate( @_, {
133             server => { type => SCALAR, default => 'http://localhost:5000' },
134             method => { type => SCALAR, default => 'GET', regex => qr/^(GET|POST|PUT|DELETE)$/ },
135             nick => { type => SCALAR, optional => 1 },
136             password => { type => SCALAR, default => '' },
137             path => { type => SCALAR, default => '/' },
138             req_body => { type => HASHREF, optional => 1 },
139             } );
140 0           $ARGS{'path'} =~ s/^\/*/\//;
141              
142 0           my $r;
143             {
144 1     1   8 no strict 'refs';
  1         2  
  1         328  
  0            
145 0           $r = &{ $ARGS{'method'} }( $ARGS{'server'} . encode_utf8( $ARGS{'path'} ),
  0            
146             Accept => 'application/json' );
147             }
148              
149 0 0         if ( $ARGS{'nick'} ) {
150 0           $r->authorization_basic( $ARGS{'nick'}, $ARGS{'password'} );
151             }
152              
153 0 0         if ( $ARGS{'method'} =~ m/^(POST|PUT)$/ ) {
154 0           $r->header( 'Content-Type' => 'application/json' );
155 0 0         if ( my $body = $ARGS{'req_body'} ) {
156 0           my $tmpvar = JSON->new->utf8(0)->encode( $body );
157 0           $r->content( encode_utf8( $tmpvar ) );
158             }
159             }
160              
161             # request is ready - send it and get response
162 0           my $response = $ua->request( $r );
163              
164             # process response
165 0           my $body_json = $response->decoded_content;
166 0           $log->debug( "rest_req: decoded JSON body " . Dumper $body_json );
167 0           $response->content('');
168 0           my $body;
169             try {
170 0     0     $body = JSON->new->decode( $body_json );
171             } catch {
172 0     0     $body = { 'code' => $body, 'text' => $body };
173 0           };
174              
175             return {
176 0           hr => $response,
177             body => $body
178             };
179             }
180