option to skip SSL validation for http export, RT#29298
[freeside.git] / FS / FS / part_export / http.pm
1 package FS::part_export::http;
2
3 use base qw( FS::part_export );
4 use vars qw( %options %info );
5 use Tie::IxHash;
6
7 tie %options, 'Tie::IxHash',
8   'method' => { label   =>'Method',
9                 type    =>'select',
10                 #options =>[qw(POST GET)],
11                 options =>[qw(POST)],
12                 default =>'POST' },
13   'url'    => { label   => 'URL', default => 'http://', },
14   'ssl_no_verify' => { label => 'Skip SSL certificate validation',
15                        type  => 'checkbox',
16                      },
17   'insert_data' => {
18     label   => 'Insert data',
19     type    => 'textarea',
20     default => join("\n",
21       'DomainName $svc_x->domain',
22       'Email ( grep { $_ !~ /^(POST|FAX)$/ } $svc_x->cust_svc->cust_pkg->cust_main->invoicing_list)[0]',
23       'test 1',
24       'reseller $svc_x->cust_svc->cust_pkg->part_pkg->pkg =~ /reseller/i',
25     ),
26   },
27   'delete_data' => {
28     label   => 'Delete data',
29     type    => 'textarea',
30     default => join("\n",
31     ),
32   },
33   'replace_data' => {
34     label   => 'Replace data',
35     type    => 'textarea',
36     default => join("\n",
37     ),
38   },
39   'suspend_data' => {
40     label   => 'Suspend data',
41     type    => 'textarea',
42     default => join("\n",
43     ),
44   },
45   'unsuspend_data' => {
46     label   => 'Unsuspend data',
47     type    => 'textarea',
48     default => join("\n",
49     ),
50   },
51   'success_regexp' => {
52     label  => 'Success Regexp',
53     default => '',
54   },
55 ;
56
57 %info = (
58   'svc'     => 'svc_domain',
59   'desc'    => 'Send an HTTP or HTTPS GET or POST request',
60   'options' => \%options,
61   'notes'   => <<'END'
62 Send an HTTP or HTTPS GET or POST to the specified URL.  For HTTPS support,
63 <a href="http://search.cpan.org/dist/Crypt-SSLeay">Crypt::SSLeay</a>
64 or <a href="http://search.cpan.org/dist/IO-Socket-SSL">IO::Socket::SSL</a>
65 is required.
66 END
67 );
68
69 sub rebless { shift; }
70
71 sub _export_insert {
72   my $self = shift;
73   $self->_export_command('insert', @_);
74 }
75
76 sub _export_delete {
77   my $self = shift;
78   $self->_export_command('delete', @_);
79 }
80
81 sub _export_suspend {
82   my $self = shift;
83   $self->_export_command('suspend', @_);
84 }
85
86 sub _export_unsuspend {
87   my $self = shift;
88   $self->_export_command('unsuspend', @_);
89 }
90
91 sub _export_command {
92   my( $self, $action, $svc_x ) = ( shift, shift, shift );
93
94   return unless $self->option("${action}_data");
95
96   my $cust_main = $svc_x->table eq 'cust_main'
97                     ? $svc_x
98                     : $svc_x->cust_svc->cust_pkg->cust_main;
99
100   $self->http_queue( $svc_x->svcnum,
101     ( $self->option('ssl_no_verify') ? 'ssl_no_verify' : '' ),
102     $self->option('method'),
103     $self->option('url'),
104     $self->option('success_regexp'),
105     map {
106       /^\s*(\S+)\s+(.*)$/ or /()()/;
107       my( $field, $value_expression ) = ( $1, $2 );
108       my $value = eval $value_expression;
109       die $@ if $@;
110       ( $field, $value );
111     } split(/\n/, $self->option("${action}_data") )
112   );
113
114 }
115
116 sub _export_replace {
117   my( $self, $new, $old ) = ( shift, shift, shift );
118
119   return unless $self->option('replace_data');
120
121   my $new_cust_main = $new->table eq 'cust_main'
122                         ? $new
123                         : $new->cust_svc->cust_pkg->cust_main;
124   my $cust_main = $new_cust_main; #so folks can use $new_cust_main or $cust_main
125
126   $self->http_queue( $new->svcnum,
127     ( $self->option('ssl_no_verify') ? 'ssl_no_verify' : '' ),
128     $self->option('method'),
129     $self->option('url'),
130     $self->option('success_regexp'),
131     map {
132       /^\s*(\S+)\s+(.*)$/ or /()()/;
133       my( $field, $value_expression ) = ( $1, $2 );
134       my $value = eval $value_expression;
135       die $@ if $@;
136       ( $field, $value );
137     } split(/\n/, $self->option('replace_data') )
138   );
139
140 }
141
142 sub http_queue {
143   my($self, $svcnum) = (shift, shift);
144   my $queue = new FS::queue { 'job' => "FS::part_export::http::http" };
145   $queue->svcnum($svcnum) if $svcnum;
146   $queue->insert( @_ );
147 }
148
149 sub http {
150   my $ssl_no_verify = ( $_[0] eq 'ssl_no_verify' || $_[0] eq '' ) ? shift : '';
151   my($method, $url, $success_regexp, @data) = @_;
152
153   $method = lc($method);
154
155   eval "use LWP::UserAgent;";
156   die "using LWP::UserAgent: $@" if $@;
157   eval "use HTTP::Request::Common;";
158   die "using HTTP::Request::Common: $@" if $@;
159
160   my @lwp_opts = ();
161   push @lwp_opts, 'ssl_opts'=>{ 'verify_hostname'=>0 } if $ssl_no_verify;
162   my $ua = LWP::UserAgent->new(@lwp_opts);
163
164   #my $response = $ua->$method(
165   #  $url, \%data,
166   #  'Content-Type'=>'application/x-www-form-urlencoded'
167   #);
168   my $req = HTTP::Request::Common::POST( $url, \@data );
169   my $response = $ua->request($req);
170
171   die $response->error_as_HTML if $response->is_error;
172
173   if(length($success_regexp) > 1) {
174     my $response_content = $response->content;
175     die $response_content unless $response_content =~ /$success_regexp/;
176   }
177
178 }
179
180 1;
181