From 4ed8d6813ad021a83839a99f9e0384b55dd62b9d Mon Sep 17 00:00:00 2001 From: Christian Kerl Date: Fri, 8 Oct 2010 16:58:14 +0200 Subject: [PATCH] added initial support for incoming mtom/xop message handling --- Soap/SoapAttachment.php | 32 +++++++++++ Soap/SoapRequest.php | 121 +++++++++++++++++++++++++++++++++++++++- SoapKernel.php | 2 +- 3 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 Soap/SoapAttachment.php diff --git a/Soap/SoapAttachment.php b/Soap/SoapAttachment.php new file mode 100644 index 0000000..4103652 --- /dev/null +++ b/Soap/SoapAttachment.php @@ -0,0 +1,32 @@ +id = $id; + $this->type = $type; + $this->content = $content; + } + + public function getId() + { + return $this->id; + } + + public function getType() + { + return $this->type; + } + + public function getContent() + { + return $this->content; + } +} \ No newline at end of file diff --git a/Soap/SoapRequest.php b/Soap/SoapRequest.php index cbc8b89..5be7a4b 100644 --- a/Soap/SoapRequest.php +++ b/Soap/SoapRequest.php @@ -14,6 +14,9 @@ use Bundle\WebServiceBundle\Util\Collection; use Symfony\Component\HttpFoundation\Request; +use Zend\Mime\Mime; +use Zend\Mime\Message; + /** * SoapRequest. * @@ -26,6 +29,11 @@ class SoapRequest extends Request */ protected $rawContent; + /** + * @var string + */ + protected $soapMessage; + /** * @var string */ @@ -37,20 +45,22 @@ class SoapRequest extends Request protected $soapHeaders; /** - * @var unknown + * @var \Bundle\WebServiceBundle\Util\Collection */ - protected $soapArguments; + protected $soapAttachments; public function __construct($rawContent = null, array $query = null, array $attributes = null, array $cookies = null, array $server = null) { parent::__construct($query, null, $attributes, $cookies, null, $server); $this->rawContent = $rawContent != null ? $rawContent : $this->loadRawContent(); + $this->soapMessage = null; $this->soapHeaders = new Collection('getName'); + $this->soapAttachments = new Collection('getId'); } /** - * Gets the SOAP XML content. + * Gets raw data send to the server. * * @return string */ @@ -59,11 +69,31 @@ class SoapRequest extends Request return $this->rawContent; } + /** + * Gets the XML string of the SOAP message. + * + * @return string + */ + public function getSoapMessage() + { + if($this->soapMessage === null) + { + $this->soapMessage = $this->initializeSoapMessage(); + } + + return $this->soapMessage; + } + public function getSoapHeaders() { return $this->soapHeaders; } + public function getSoapAttachments() + { + return $this->soapAttachments; + } + /** * Loads the plain HTTP POST data. * @@ -73,4 +103,89 @@ class SoapRequest extends Request { return isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : file_get_contents('php://input'); } + + protected function initializeSoapMessage() + { + if($this->server->has('CONTENT_TYPE')) + { + $type = $this->splitContentTypeHeader($this->server->get('CONTENT_TYPE')); + + switch($type['_type']) + { + case 'multipart/related': + if($type['type'] == 'application/xop+xml') + { + return $this->initializeMtomSoapMessage($type, $this->rawContent); + } + else + { + //log error + } + break; + case 'application/soap+xml': + // goto fallback + break; + default: + // log error + break; + } + } + + // fallback + return $this->rawContent; + } + + protected function initializeMtomSoapMessage(array $contentTypeHeader, $content) + { + if(!isset($contentTypeHeader['start']) || !isset($contentTypeHeader['boundary'])) + { + throw new \InvalidArgumentException(); + } + + $mimeMessage = Message::createFromMessage($content, $contentTypeHeader['boundary']); + $mimeParts = $mimeMessage->getParts(); + + $soapMimePartId = $contentTypeHeader['start']; + $soapMimePartType = $this->splitContentTypeHeader($contentTypeHeader['start-info']); + + $rootPart = array_shift($mimeParts); + $rootPartType = $this->splitContentTypeHeader($rootPart->type); + + // TODO: add more checks to achieve full compatibility to MTOM spec + // http://www.w3.org/TR/soap12-mtom/ + if($rootPart->id != $soapMimePartId || $rootPartType['_type'] != 'application/xop+xml' || $rootPartType['type'] != $soapMimePartType['type']) + { + throw new \InvalidArgumentException(); + } + + foreach($mimeParts as $mimePart) + { + $this->soapAttachments->add(new SoapAttachment( + trim($mimePart->id, '<>'), + $mimePart->type, + // handle content decoding / prevent encoding + $mimePart->getContent() + )); + } + + // handle content decoding / prevent encoding + return $rootPart->getContent(); + } + + protected function splitContentTypeHeader($header) + { + $result = array(); + $parts = explode(';', strtolower($header)); + + $result['_type'] = array_shift($parts); + + foreach($parts as $part) + { + list($key, $value) = explode('=', trim($part), 2); + + $result[$key] = trim($value, '"'); + } + + return $result; + } } \ No newline at end of file diff --git a/SoapKernel.php b/SoapKernel.php index ba80ca4..6e67b1f 100644 --- a/SoapKernel.php +++ b/SoapKernel.php @@ -78,7 +78,7 @@ class SoapKernel implements HttpKernelInterface $this->soapRequest = $this->checkRequest($request); ob_start(); - $this->soapServer->handle($this->soapRequest->getRawContent()); + $this->soapServer->handle($this->soapRequest->getSoapMessage()); $soapResponseContent = ob_get_clean(); $this->soapResponse->setContent($soapResponseContent);