1 # Vend::SOAP - Handle SOAP connections for Interchange
3 # $Id: SOAP.pm,v 2.18 2007-08-09 13:40:54 pajamian Exp $
5 # Copyright (C) 2002-2007 Interchange Development Group
6 # Copyright (C) 2000-2002 Red Hat, Inc.
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public
19 # License along with this program; if not, write to the Free
20 # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
28 use Vend::Interpolate;
32 use Vend::SOAP::Transport;
33 require SOAP::Transport::IO;
34 require SOAP::Transport::HTTP;
37 use vars qw($VERSION @ISA $AUTOLOAD);
38 $VERSION = substr(q$Revision: 2.18 $, 10);
39 @ISA = qw/SOAP::Server/;
42 my @Allowed_tags = qw/
96 $Allowed_tags{$_} = 1;
102 return "hello from the Vend::SOAP server, pid $$, world!\nreceived args:\n"
113 my ($method, $uri, $proxy, $opt) = @_;
116 if (ref($opt->{param}) eq 'ARRAY') {
117 @args = @{$opt->{param}};
119 elsif (ref($opt->{param}) eq 'HASH') {
120 @args = %{$opt->{param}};
123 @args = $opt->{param};
130 if($opt->{trace_transport}) {
131 if (exists $Vend::Cfg->{Sub}->{$opt->{trace_transport}}) {
132 SOAP::Trace->import('transport' => $Vend::Cfg->{Sub}->{$opt->{trace_transport}});
134 ::logError (qq{no such subroutine "$opt->{trace_transport}" for SOAP transport tracing});
139 #::logDebug("to method call, uri=$uri proxy=$proxy call=$method args=" . ::uneval(\@args));
147 elsif(ref $opt->{object}) {
148 $result = $opt->{object}
151 -> call( $method => @args )
158 -> call( $method => @args )
163 ::logError("error on SOAP call: %s", $@);
165 #::logDebug("after method call, uri=$uri proxy=$proxy call=$method result=$result");
167 $::Scratch->{$opt->{result}} = $result if $opt->{result};
168 return '' if $opt->{init};
172 sub tag_soap_entity {
177 my @values = map {tag_soap_entity($_)} @{$opt->{value}};
178 $opt->{value} = \@values;
180 eval {$obj = new SOAP::Data (%$opt);};
182 logError ("soap_entity failed: $@");
188 my %intrinsic = (local => sub {$CGI::remote_addr eq '127.0.0.1'},
189 never => sub {return 0},
190 always => sub {return 1});
193 my (@args, $status, $subref, $spath);
195 # check first global control configuration which takes
196 # precedence, then catalog control configuration
197 for $subref ($Global::SOAP_Control,
198 $Vend::Cfg->{SOAP_Control}) {
202 $spath = join('/', @args);
204 next unless exists $subref->{$spath};
206 if (ref($subref->{$spath}) eq 'CODE') {
207 $status = $subref->{$spath}->($spath);
208 } elsif ($subref->{$spath}) {
209 $status = soap_control_intrinsic($subref->{$spath}, $spath);
212 # check found, done with loop
219 die errmsg("Unauthorized access to '%s' method\n", join('/', @_))
225 sub soap_control_intrinsic {
226 my ($checklist, $action) = @_;
227 my @checks = split /\s*;\s*/, $checklist;
231 my ($check, @args) = split /:/, $_;
232 my $sub = $intrinsic{$check} or return 0;
234 unless( $sub->($action, @args) ) {
242 # This is used to check the session name. If there is some reason
243 # the session is retired, the returned ID will be different from the
244 # passed ID and the client can cope.
246 # This variant returns the full SessionName so that multiple hosts
247 # can use the same ID.
250 my $class = ref($self) || $self;
254 #::logDebug("looking to assign session $sid, sessionID=$Vend::SessionID cookiehost=$CGI::cookiehost");
255 $Vend::SessionID = $sid;
256 $Vend::SessionID =~ s/:(.*)//
257 and $CGI::cookiehost = $1;
261 close_soap_session();
263 #::logDebug("actual session name $Vend::SessionName");
264 return $Vend::SessionName;
267 # This is used to check the session name. If there is some reason
268 # the session is retired, the returned ID will be different from the
269 # passed ID and the client can cope.
271 # This variant returns only the SessionID for better security in single-host
275 my $class = ref($self) || $self;
279 #::logDebug("looking to assign session id $sid");
280 $Vend::SessionID = $sid;
284 close_soap_session();
286 #::logDebug("actual session name $Vend::SessionID");
287 return $Vend::SessionID;
296 my $ref = $::Values ||= {};
297 #::logDebug("ref from session is " . ::uneval($ref));
298 if($putref = shift) {
299 %{$ref} = %{$putref};
301 close_soap_session();
302 #::logDebug("ref from session is now " . ::uneval($ref));
310 my $ref = $Vend::Session;
311 if($putref = shift) {
313 Vend::Session::init_session();
314 $ref = $Vend::Session;
316 %{$ref} = %{$putref};
318 close_soap_session();
325 soap_gate('Scratch');
328 my $ref = $Vend::Session->{scratch};
329 if($putref = shift) {
330 $ref = $Vend::Session->{scratch} = {}
332 %{$ref} = %{$putref};
334 close_soap_session();
342 soap_gate('Database', $name);
344 my $ref = $Vend::Cfg->{Database};
345 return $ref->{$name} if $name;
349 sub open_soap_session {
350 #::logDebug("opening session $Vend::SessionID");
351 ::get_session($Vend::SessionID);
352 #::logDebug("actual session $Vend::SessionID");
353 return $Vend::SessionID;
356 sub close_soap_session {
357 #::logDebug("closing session $Vend::SessionID");
360 undef $Vend::Session;
361 undef $Vend::SessionOpen;
365 my $routine = $AUTOLOAD;
366 #::logDebug("SOAP autoload called, routine=$routine, args=" . ::uneval(\@_));
370 if($Tmp::Autoloaded++ > 100) {
371 die "must be in endless loop, autoloaded $Tmp::Autoloaded times";
374 chdir $Vend::Cfg->{VendRoot}
375 or die "Couldn't change to $Vend::Cfg->{VendRoot}: $!\n";
379 #::logDebug("SOAP init_session done, session_id=$Vend::SessionID");
381 #::logDebug("session " . ::full_dump() );
383 $routine =~ s/.*:://;
385 if ($Vend::Cfg->{SOAP_Action}{$routine}) {
386 soap_gate ('Action', $routine);
387 $sub = $Vend::Cfg->{SOAP_Action}{$routine};
388 Vend::Interpolate::init_calc();
390 new Vend::Parse; # enable catalog usertags within SOAP actions
391 } elsif (! $Allowed_tags{$routine}) {
392 die ::errmsg("Not allowed routine: %s", $routine);
394 soap_gate ('Tag', $routine);
400 $result = $sub->(@_);
403 #::logDebug("do_tag $routine, args=" . ::uneval(\@_));
406 #::logDebug("resolving args");
407 @_ = Vend::Parse::resolve_args($routine, @_);
409 #::logDebug("do_tag $routine");
410 $result = Vend::Parse::do_tag($routine, @_);
416 ::logError("SOAP call for $routine failed: %s", $@);
418 $error = SOAP::Server->make_fault($SOAP::Constants::FAULT_SERVER,
419 'Application error');
421 #::logDebug("session " . ::full_dump() );
423 close_soap_session();
426 die $error if $error;
428 #::logDebug("session " . ::full_dump() );