SOAP-MIME

 view release on metacpan or  search on metacpan

lib/SOAP/MIME.pm  view on Meta::CPAN

  # TO DO: in composing the response, I need to parse MIME::Entities that are returned...
  # breese - 3/17/2003
  sub SOAP::Server::handle {

    SOAP::Trace::trace('()');
    my $self = shift;

    # we want to restore it when we are done
    local $SOAP::Constants::DEFAULT_XML_SCHEMA = $SOAP::Constants::DEFAULT_XML_SCHEMA;

    # SOAP version WILL NOT be restored when we are done.
    # is it problem?

    my $result = eval {
      local $SIG{__DIE__};
      $self->serializer->soapversion(1.1);
      my $request = eval { $self->deserializer->deserialize($_[0]) };
      die SOAP::Fault
	->faultcode($SOAP::Constants::FAULT_VERSION_MISMATCH)
	  ->faultstring($@)
	    if $@ && $@ =~ /^$SOAP::Constants::WRONG_VERSION/;
      die "Application failed during request deserialization: $@" if $@;
      my $som = ref $request;
      die "Can't find root element in the message" unless $request->match($som->envelope);
      $self->serializer->soapversion(SOAP::Lite->soapversion);
      $self->serializer->xmlschema($SOAP::Constants::DEFAULT_XML_SCHEMA
				   = $self->deserializer->xmlschema)
	if $self->deserializer->xmlschema;

      die SOAP::Fault
	->faultcode($SOAP::Constants::FAULT_MUST_UNDERSTAND)
	  ->faultstring("Unrecognized header has mustUnderstand attribute set to 'true'")
	    if !$SOAP::Constants::DO_NOT_CHECK_MUSTUNDERSTAND &&
	      grep { $_->mustUnderstand && 
		       (!$_->actor || $_->actor eq $SOAP::Constants::NEXT_ACTOR)
		     } $request->dataof($som->headers);

      die "Can't find method element in the message" unless $request->match($som->method);

      my($class, $method_uri, $method_name) = $self->find_target($request);

      my @results = eval {
	local $^W;
	my @parameters = $request->paramsin;

	# SOAP::Trace::dispatch($fullname);
	SOAP::Trace::parameters(@parameters);

	push @parameters, $request 
	  if UNIVERSAL::isa($class => 'SOAP::Server::Parameters');

	SOAP::Server::Object->references(defined $parameters[0] &&
					 ref $parameters[0] &&
					 UNIVERSAL::isa($parameters[0] => $class)
		? do {
		  my $object = shift @parameters;
		  SOAP::Server::Object->object(ref $class ? $class : $object)
		      ->$method_name(SOAP::Server::Object->objects(@parameters)),
			# send object back as a header
			# preserve name, specify URI
			SOAP::Header
			    ->uri($SOAP::Constants::NS_SL_HEADER => $object)
			    ->name($request->dataof($som->method.'/[1]')->name)
		}
		: $class->$method_name(SOAP::Server::Object->objects(@parameters))
        );
      };
      SOAP::Trace::result(@results);

      # let application errors pass through with 'Server' code
      die ref $@ ?
	$@ : $@ =~ /^Can't locate object method "$method_name"/ ?
          "Failed to locate method ($method_name) in class ($class)" :
	    SOAP::Fault->faultcode($SOAP::Constants::FAULT_SERVER)->faultstring($@)
		if $@;

    return $self->serializer
      ->prefix('s') # distinguish generated element names between client and server
      ->uri($method_uri)
      ->envelope(response => $method_name . 'Response', @results);
  };

    # void context
    return unless defined wantarray;

    # normal result
    return $result unless $@;

    # check fails, something wrong with message
    return $self->make_fault($SOAP::Constants::FAULT_CLIENT, $@) unless ref $@;

    # died with SOAP::Fault
    return $self->make_fault($@->faultcode   || $SOAP::Constants::FAULT_SERVER,
			     $@->faultstring || 'Application error',
			     $@->faultdetail, $@->faultactor)
      if UNIVERSAL::isa($@ => 'SOAP::Fault');

    # died with complex detail
    return $self->make_fault($SOAP::Constants::FAULT_SERVER, 'Application error' => $@);

  } # end of handle()

} # end of BEGIN block

sub SOAP::Transport::HTTP::Server::make_response {
  my $self = shift;
  my($code, $response) = @_;

  my $encoding = $1
    if $response =~ /^<\?xml(?: version="1.0"| encoding="([^"]+)")+\?>/;
  $response =~ s!(\?>)!$1<?xml-stylesheet type="text/css"?>!
    if $self->request->content_type eq 'multipart/form-data';

  $self->options->{is_compress} ||=
    exists $self->options->{compress_threshold} && eval { require Compress::Zlib };

  my $compressed = $self->options->{is_compress} &&
    grep(/\b($COMPRESS|\*)\b/, $self->request->header('Accept-Encoding')) &&
      ($self->options->{compress_threshold} || 0) < SOAP::Utils::bytelength $response;
  $response = Compress::Zlib::compress($response) if $compressed;
  my ($is_multipart) = ($response =~ /content-type:.* boundary="([^\"]*)"/im);
  $self->response(HTTP::Response->new(
     $code => undef,
     HTTP::Headers->new(
			'SOAPServer' => $self->product_tokens,
			$compressed ? ('Content-Encoding' => $COMPRESS) : (),
			'Content-Type' => join('; ', 'text/xml',
					       !$SOAP::Constants::DO_NOT_USE_CHARSET &&
					       $encoding ? 'charset=' . lc($encoding) : ()),
			'Content-Length' => SOAP::Utils::bytelength $response),
     $response,
  ));
  $self->response->headers->header('Content-Type' => 'Multipart/Related; type="text/xml"; start="<main_envelope>"; boundary="'.$is_multipart.'"') if $is_multipart;
}

sub SOAP::Serializer::envelope {
  SOAP::Trace::trace('()');
  my $self = shift->new;
  my $type = shift;

  # SOAP::MIME added the attachments bit here
  my(@parameters, @header, @attachments);
  for (@_) { 
    defined $_ && ref $_ && UNIVERSAL::isa($_ => 'SOAP::Header') ?
      push(@header, $_) :
	UNIVERSAL::isa($_ => 'MIME::Entity') ?
	    push(@attachments, $_) :
	      push(@parameters, $_);
  }
  my $header = @header ? SOAP::Data->set_value(@header) : undef;
  my($body,$parameters);
  if ($type eq 'method' || $type eq 'response') {
    SOAP::Trace::method(@parameters);
    my $method = shift(@parameters) or die "Unspecified method for SOAP call\n";
    $parameters = @parameters ? SOAP::Data->set_value(@parameters) : undef;
    $body = UNIVERSAL::isa($method => 'SOAP::Data') 
      ? $method : SOAP::Data->name($method)->uri($self->uri);
    $body->set_value($parameters ? \$parameters : ());
  } elsif ($type eq 'fault') {
    SOAP::Trace::fault(@parameters);
    $body = SOAP::Data
      -> name(SOAP::Serializer::qualify($self->envprefix => 'Fault'))
    # commented on 2001/03/28 because of failing in ApacheSOAP
    # need to find out more about it
    # -> attr({'xmlns' => ''})
      -> value(\SOAP::Data->set_value(
        SOAP::Data->name(faultcode => SOAP::Serializer::qualify($self->envprefix => $parameters[0])),
        SOAP::Data->name(faultstring => $parameters[1]),
        defined($parameters[2]) ? SOAP::Data->name(detail => do{my $detail = $parameters[2]; ref $detail ? \$detail : $detail}) : (),
        defined($parameters[3]) ? SOAP::Data->name(faultactor => $parameters[3]) : (),
      ));
  } elsif ($type eq 'freeform') {
    SOAP::Trace::freeform(@parameters);
    $body = SOAP::Data->set_value(@parameters);
  } else {
    die "Wrong type of envelope ($type) for SOAP call\n";
  }

  $self->seen({}); # reinitialize multiref table
  my($encoded) = $self->encode_object(
    SOAP::Data->name(SOAP::Serializer::qualify($self->envprefix => 'Envelope') => \SOAP::Data->value(
      ($header ? SOAP::Data->name(SOAP::Serializer::qualify($self->envprefix => 'Header') => \$header) : ()),
      SOAP::Data->name(SOAP::Serializer::qualify($self->envprefix => 'Body')   => \$body)
    ))->attr($self->attr)
  );
  $self->signature($parameters->signature) if ref $parameters;

  # IMHO multirefs should be encoded after Body, but only some
  # toolkits understand this encoding, so we'll keep them for now (04/15/2001)
  # as the last element inside the Body 
  #                 v -------------- subelements of Envelope
  #                      vv -------- last of them (Body)
  #                            v --- subelements
  push(@{$encoded->[2]->[-1]->[2]}, $self->encode_multirefs) if ref $encoded->[2]->[-1]->[2];

  # SOAP::MIME magic goes here...
  if (@attachments) {
    my $top = MIME::Entity->build(
				  'Type' => "Multipart/Related"
				 );
    $top->attach(
		 'Type'             => 'text/xml',
		 'Content-Transfer-Encoding' => '8bit',
		 'Content-Location' => '/main_envelope',



( run in 2.076 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )