Search code examples
perlsoapwsdlhttp-request

Perl: Getting complete request from SOAP::WSDL object


I'm working with SOAP::WSDL and another company's custom WSDL file. Every time they make a change for me and I recreate my modules, something breaks. Finding the problem is rather tedious because I don't find a proper way to access the actual request that is sent to the SOAP server.

The only way to get to the request so far has been to use tcpdump in conjunction with wireshark to extract the request and result. That works, but since I don't have root privileges on the dev machine I have to get an admin over every time I want to do that. I feel there must be another way to get to the HTTP::Request object inside the SOAP::WSDL thing. But if the server returns a fault, I don't even have a response object, but rather a SOAP::WSDL::SOAP::Typelib::Fault11 object that has no visible relation to the request.

I've also tried using the debugger but I'm having trouble finding the actual request part. I've not yet understood how to tell the debuger to skip to a specific part deep inside a complex number of packages.


Solution

  • I found a way to at least print out the generated XML code.

    First, I looked at SOAP::WSDL::Client as raina77ow suggested. That wasn't what I needed, though. But then I came across SOAP::WSDL::Factory::Serializer. There, it says:

    Serializer objects may also be passed directly to SOAP::WSDL::Client by using the set_serializer method.

    A little fidgeting and I came up with a wrapper class for SOAP::WSDL::Serializer::XSD which is the default serializer used by SOAP::WSDL. A look at the code helped, too.

    Here's the module I wrote. It uses SOAP::WSDL::Serializer::XSD as a base class and overloads the new and serialize methods. While it only passes arguments to new, it grabs the returned XML from serialize and prints it, which suffices for debugging. I'm not sure if there's a way to put it somewhere I can easily get it from.

    package MySerializer;
    use strict;
    use warnings;
    use base qw(SOAP::WSDL::Serializer::XSD);
    
    sub new {
      my $self = shift;
      my $class = ref($self) || $self;
      return $self if ref $self;
    
      # Create the base object and return it
      my $base_object = $class->SUPER::new(@_);
      return bless ($base_object, $class);
    }
    
    sub serialize {
      my ($self, $args_of_ref) = @_;
    
      # This is basically a wrapper function that calls the real Serializer's
      # serialize-method and grabs and prints the returned XML before it
      # giving it back to the caller
    
      my $xml = ref($self)->SUPER::serialize($args_of_ref);
      print "\n\n$xml\n\n"; # here we go
      return $xml;
    }
    
    1;
    

    And here's how I call it:

    my $serializer = MySerializer->new();
    $self->{'_interface'} = Lib::Interfaces::MyInterface->new();
    $self->{'_interface'}->set_serializer($serializer); # comment out to deactivate
    

    It's easy to deactivate. Only put a comment in the set_serializer line.

    Of course printing a block of XML to the command line is not very pretty, but it gets the job done. I only need it once in a while why coding/testing, so this is fine I guess.