File Coverage

blib/lib/HTTP/Request/Params.pm
Criterion Covered Total %
statement 73 77 94.8
branch 13 18 72.2
condition 1 3 33.3
subroutine 12 12 100.0
pod 1 1 100.0
total 100 111 90.0


line stmt bran cond sub pod time code
1             package HTTP::Request::Params;
2              
3             # $Id: Params.pm,v 1.2 2015/08/11 10:01:12 kiz Exp $
4 1     1   503459 use strict;
  1         2  
  1         31  
5              
6             =pod
7              
8             =head1 NAME
9              
10             HTTP::Request::Params - Retrieve GET/POST Parameters from HTTP Requests
11              
12             =head1 SYNOPSIS
13              
14             use HTTP::Request::Params;
15            
16             my $http_request = read_request();
17             my $parse_params = HTTP::Request::Params->new({
18             req => $http_request,
19             });
20             my $params = $parse_params->params;
21              
22             =cut
23              
24 1     1   4 use vars qw[$VERSION];
  1         1  
  1         92  
25             $VERSION = sprintf '%d.%02d', split m/\./, (qw$Revision: 1.2 $)[1];
26              
27 1     1   7 use CGI;
  1         8  
  1         9  
28 1     1   61 use Email::MIME;
  1         1  
  1         27  
29 1     1   4 use Email::MIME::Modifier;
  1         1  
  1         34  
30 1     1   6 use Email::MIME::ContentType qw[parse_content_type];
  1         2  
  1         121  
31 1     1   6 use HTTP::Request;
  1         1  
  1         21  
32 1     1   3 use HTTP::Message;
  1         1  
  1         26  
33 1     1   3 use parent qw[Class::Accessor::Fast];
  1         1  
  1         7  
34              
35             =pod
36              
37             =head1 DESCRIPTION
38              
39             This software does all the dirty work of parsing HTTP Requests to find
40             incoming query parameters.
41              
42             =head2 new
43              
44             my $parser = HTTP::Request::Params->new({
45             req => $http_request,
46             });
47              
48             C - This required argument is either an C object or a
49             string containing an entier HTTP Request.
50              
51             Incoming query parameters come from two places. The first place is the
52             C portion of the URL. Second is the content portion of an HTTP
53             request as is the case when parsing a POST request, for example.
54              
55             =head2 params
56              
57             my $params = $parser->params;
58              
59             Returns a hash reference containing all the parameters. The keys in this hash
60             are the names of the parameters. Values are the values associated with those
61             parameters in the incoming query. For parameters with multiple values, the value
62             in this hash will be a list reference. This is the same behaviour as the C
63             module's C function.
64              
65             =head2 req
66              
67             my $req_object = $parser->req;
68              
69             Returns the C object.
70              
71             =head2 mime
72              
73             my $mime_object = $parser->mime;
74              
75             Returns the C object.
76              
77             Now, you may be wondering why we're dealing with an C object.
78             The answer is simple. It's an amazing parser for MIME compliant messages,
79             and RFC 822 compliant messages. When parsing incoming POST data, especially
80             file uploads, C is the perfect fit. It's fast and light.
81              
82             =cut
83              
84             sub new {
85 3     3 1 43481 my ($class) = shift;
86 3         25 my $self = $class->SUPER::new(@_);
87              
88 3 100       36 if ( not ref( $self->req ) ) {
89 1         9 $self->req( HTTP::Request->parse( $self->req ) );
90             }
91              
92 3         180 my $message = ( split /\n/, $self->req->as_string, 2 )[1];
93 3         374 $self->mime( Email::MIME->new( $self->req->as_string ) );
94              
95 3         2030 $self->_find_params;
96              
97 3         8 return $self;
98             } ## end sub new
99              
100             __PACKAGE__->mk_accessors(qw[req mime params]);
101              
102             sub _find_params {
103 3     3   7 my $self = shift;
104 3         8 my $query_params = CGI->new( $self->req->url->query )->Vars;
105 3         1004 my $post_params = {};
106              
107 3 100       10 if ( $self->mime->parts > 1 ) {
108 1         15 foreach my $part ( $self->mime->parts ) {
109 3 50       14 next if $part == $self->mime;
110 3         20 $part->disposition_set('text/plain'); # for easy parsing
111              
112 3         190 my $disp = $part->header('Content-Disposition');
113 3         63 my $ct = parse_content_type($disp);
114 3         170 my $name = $ct->{attributes}->{name};
115 3         10 my $content = $part->body;
116              
117 3         118 $content =~ s/\r\n$//;
118 3         8 $self->_add_to_field( $post_params, $name, $content );
119             } ## end foreach my $part ( $self->mime...)
120             } else {
121 2         23 my $body = $self->mime->body;
122 2         80 chomp $body;
123 2         6 $post_params = CGI->new($body)->Vars;
124             }
125              
126 3         330 my $params = {};
127              
128             # I dislike the use of $_
129 3         3 for my $k ( keys %{$post_params} ) {
  3         12  
130 5         17 $self->_add_to_field( $params, $k, $post_params->{$k} );
131             }
132 3         14 for my $k ( keys %{$query_params} ) {
  3         15  
133 4         39 $self->_add_to_field( $params, $k, $query_params->{$k} );
134             }
135 3         12 $self->params($params);
136              
137 3 50       13 return keys %{$params} ? 0 : 1;
  3         25  
138             } ## end sub _find_params
139              
140             sub _add_to_field {
141 12     12   31 my ( $self, $hash, $name, @content ) = @_;
142 12         213 my $field = $hash->{$name};
143 12 50 33     47 if ( @content && ref( $content[0] ) ) {
144 0         0 @content = @{ $content[0] };
  0         0  
145             }
146 12         48 @content = map split(/\0/), @content;
147              
148 12 100       26 if ( defined $field ) {
149 2 50       6 if ( ref($field) ) {
150 0         0 push @{$field}, @content;
  0         0  
151             } else {
152 2         5 $field = [ $field, @content ];
153             }
154             } else {
155 10 100       15 if ( @content > 1 ) {
156 1         3 $field = \@content;
157             } else {
158 9         10 $field = $content[0];
159             }
160             } ## end else [ if ( defined $field ) ]
161 12         18 $hash->{$name} = $field;
162              
163 12 50       36 return $field ? 1 : 0;
164             } ## end sub _add_to_field
165              
166             1;
167              
168             __END__