ray.rick.mini has asked for the wisdom of the Perl Monks concerning the following question:

Disclaimer: same issue has been treated without solution in node_id 806606. I'm trying to integrate a client webservice, that allows ticket opening requests via SOAP. Everything works great, except when I try to attach file in the SOAP::Lite message, using SOAP::Packager and MIME::Entity. I deepened the issue, and I confirm that the problem is caused by the remote server expecting sequences of CRLF and not '\n' for line ending. Here is a snippet of the code I'm using:

.. my $ent = build MIME::Entity Type => "application/octet-stream", Encoding => "binary", Path => "/usr/share/httpd/icons/small/uu.gif", Filename => "uu.gif", Disposition => "attachment", my $method = SOAP::Data->name('OpCreate') ->attr({'Request_Urgency' => $options{'urgency' +}}); my $header = SOAP::Header ->name('AuthenticationInfo' => \SOAP::Header->value(@logininfo) ); print Dumper \$ent; #exit; my $result = SOAP::Lite ->packager(SOAP::Packager::MIME->new) ->parts([$ent]) ->proxy($create_proxy, ssl_opts => [ SSL_verify_mode => 1, S +SL_ca_file => '/root/Firefox_CERT/CUSTOMERROOTCA2'] ) ->call($header, $method => @data) ; ..

I'm looking forward to change things in my code, to generate/change on the fly needed ending characters. I manually test things with curl using raw data coming from SOAP::Lite trace output as raw file input and I confirm that is sufficient to use "unix2dos" on the ASCII part of the resulting file to see things working as expected. Hacky solutions are welcome, Thanks for any hints

Replies are listed 'Best First'.
Re: Again on SOAP::Lite, MIME::Entity and SOAP::Packager
by Corion (Patriarch) on Dec 28, 2016 at 12:25 UTC

    I think the reply in SOAP::Lite or MIME::Entity generate invalid HTTP line endings pointing out that MIME::Entity uses hardcoded \n in various places and has old bugs pertaining to newlines, the simplest approach would be to clone MIME::Entity and replace all \n by \r\n (hardcoded) in its source code.

    The less intrusive and far more hacky solution is to post-process the output of MIME::Entity yourself:

    open my $output_fh, '>', \my $mime_body or die "In-memory handles are not supported by your version of Per +l."; $mime->print( $output_fh ); close $output_fh; $mime_body =~ s!\n!\r\n!g; # use $mime_body as the string wherever you would use it with SOAP::Pa +ckager # I don't know if the following is valid, using a raw string as a MIME + part: $soap->parts( [$mime_body] );

    Maybe you need to mock up a MIME::Entity::NewlineFixed instead which implements just enough of the MIME::Entity interface to make SOAP::Packager happy, but I don't know which parts SOAP::Packager uses.

      Unluckily, your suggestion doesn't seems to work. I managed to substitute chars, but parts() method starts complaining for the raw string, as you already guessed in your comments. That's why I tried to modify as following:

      .. print Dumper \$ent; my $aref=[]; my $oldr=$ent->{mail_inet_head}->{mail_hdr_list}; foreach (@$oldr){ my $n=$_; $n=~s/\n/\r\n/g; push(@$aref,$n); } $ent->{mail_inet_head}->{mail_hdr_list}=$aref; # exit; my $result = SOAP::Lite ->packager(SOAP::Packager::MIME->new) ->parts([$ent]) ->proxy($create_proxy, ssl_opts => [ SSL_verify_mode => 1, S +SL_ca_file => '/root/Firefox_CERT/CUSTOMERROOTCA2'] ) ->call($header, $method => @data) ;

      This actually override \n in header section, but the request is still not accepted by remote server throwing a 500 error. I'm still confused because MIME::Entity is only building a little block of the final HTTP request (the encoded binary file with his headers), I guess SOAP::Packager is adding lot of things like multipart etc. I'll try to deepen with curl changing only 1 row at a time to see which section of the request is causing the behaviour. In the meanwhile, suggestions are welcome

        Looking at the source code of SOAP::Packager::MIME, the meat of it seems to be the sub ->package, which adds some headers to the MIME entity and after that calls $top->stringify_body;. So maybe the main trick is to use your own MIME::Entity subclass which has a better ->stringify_body:

        package MIME::Entity::Ray; use strict; use parent 'MIME::Entity'; sub stringify_body { my( $self ) = @_; my $body = $self->SUPER::stringify_body(); $body =~ s!\n!\r\n!g; return $body };

        And then instead of creating your own MIME::Entity objects create MIME::Entity::Ray objects instead.

        If that still fails, maybe something else is creating MIME::Entity objects. Then either edit the source code or monkey patch MIME::Entity:

        use MIME::Entity; my $old_stringify_body = \&MIME::Entity::stringify_body; *MIME::Entity::stringify_body = sub { my( $self ) = @_; my $body = $self->SUPER::stringify_body(); $body =~ s!\n!\r\n!g; return $body };

        Update: After looking some more at SOAP::Packager, it even tries to do the Right Thing by setting:

        local $MIME::Entity::BOUNDARY_DELIMITER = "\r\n";

        except that MIME::Entity does not use that variable.

        The real solution would be to make MIME::Entity use that variable.