Branch 'kolab-syncroton-2.2' - lib/ext

Aleksander Machniak machniak at kolabsys.com
Tue Oct 8 11:45:00 CEST 2013


 lib/ext/Syncroton/Server.php         |   40 +++++++++++++++++++++++++++++------
 lib/ext/Syncroton/Wbxml/Abstract.php |    3 +-
 lib/ext/Syncroton/Wbxml/Decoder.php  |   21 ++++++++++--------
 lib/ext/Syncroton/Wbxml/Encoder.php  |   24 +++++++++++++++------
 4 files changed, 66 insertions(+), 22 deletions(-)

New commits:
commit 3ca69420f45b564e68655e2178714d862239c124
Author: Aleksander Machniak <alec at alec.pl>
Date:   Tue Oct 8 11:44:33 2013 +0200

    Fix encoder memory issue (Bug #2032)

diff --git a/lib/ext/Syncroton/Server.php b/lib/ext/Syncroton/Server.php
index 7b681a0..114db4d 100644
--- a/lib/ext/Syncroton/Server.php
+++ b/lib/ext/Syncroton/Server.php
@@ -172,9 +172,7 @@ class Syncroton_Server
         
         if ($response instanceof DOMDocument) {
             if ($this->_logger instanceof Zend_Log) {
-                $response->formatOutput = true;
-                $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " xml response:\n" . $response->saveXML());
-                $response->formatOutput = false;
+                $this->_logDomDocument(Zend_Log::DEBUG, $response, __METHOD__, __LINE__);
             }
             
             if (isset($command) && $command instanceof Syncroton_Command_ICommand) {
@@ -190,7 +188,7 @@ class Syncroton_Server
             } catch (Syncroton_Wbxml_Exception $swe) {
                 if ($this->_logger instanceof Zend_Log) {
                     $this->_logger->err(__METHOD__ . '::' . __LINE__ . " Could not encode output: " . $swe);
-                    $this->_logger->err(__METHOD__ . '::' . __LINE__ . " xml response:\n" . $response->saveXML());
+                    $this->_logDomDocument(Zend_Log::ERR, $response, __METHOD__, __LINE__);
                 }
                 
                 header("HTTP/1.1 500 Internal server error");
@@ -227,7 +225,7 @@ class Syncroton_Server
                 
                 echo $header;
             }
-                        
+            
             // output body
             rewind($outputStream);
             fpassthru($outputStream);
@@ -240,7 +238,37 @@ class Syncroton_Server
                 }
             }
         }
-    }    
+    }
+    
+    /**
+     * write (possible big) DOMDocument in smaller chunks to log file
+     * 
+     * @param unknown     $priority
+     * @param DOMDocument $dom
+     * @param string      $method
+     * @param string      $method
+     */
+    protected function _logDomDocument($priority, DOMDocument $dom, $method, $method)
+    {
+        $loops = 0;
+        
+        $tempStream = fopen('php://temp/maxmemory:5242880', 'r+');
+                
+        $dom->formatOutput = true;
+        fwrite($tempStream, $dom->saveXML());
+        $dom->formatOutput = false;
+        
+        rewind($tempStream);
+        
+        // log data in 1MByte chunks
+        while (!feof($tempStream)) {
+            $this->_logger->log($method . '::' . $method . " xml response($loops):\n" . fread($tempStream, 1048576), $priority);
+            
+            $loops++;
+        }
+        
+        fclose($tempStream);
+    }
     
     /**
      * return request params
diff --git a/lib/ext/Syncroton/Wbxml/Abstract.php b/lib/ext/Syncroton/Wbxml/Abstract.php
index bec61f1..1ffa640 100644
--- a/lib/ext/Syncroton/Wbxml/Abstract.php
+++ b/lib/ext/Syncroton/Wbxml/Abstract.php
@@ -166,7 +166,8 @@ abstract class Syncroton_Wbxml_Abstract
                 $string .= $chunk;
                 $_length -= $len;
             }
-            else if (feof($this->_stream)) {
+            
+            if (feof($this->_stream)) {
                 break;
             }
         }
diff --git a/lib/ext/Syncroton/Wbxml/Decoder.php b/lib/ext/Syncroton/Wbxml/Decoder.php
index 130d84f..8b845e4 100644
--- a/lib/ext/Syncroton/Wbxml/Decoder.php
+++ b/lib/ext/Syncroton/Wbxml/Decoder.php
@@ -129,8 +129,6 @@ class Syncroton_Wbxml_Decoder extends Syncroton_Wbxml_Abstract
                 case Syncroton_Wbxml_Abstract::OPAQUE:
                     $length = $this->_getMultibyteUInt();
                     if($length > 0) {
-                        // @TODO: handle big data with streams
-                        // E.g. in SendMail command "opaqued" <Mime> contains full email body
                         $opaque = $this->_getOpaque($length);
                         try {
                             // let see if we can decode it. maybe the opaque data is wbxml encoded content
@@ -173,28 +171,33 @@ class Syncroton_Wbxml_Decoder extends Syncroton_Wbxml_Abstract
                     // get rid of bit 7+8
                     $tagHexCode         = $byte & 0x3F;
 
-                    $tag        = $this->_codePage->getTag($tagHexCode);
-                    $nameSpace  = $this->_codePage->getNameSpace();
+                    try {
+                        $tag = $this->_codePage->getTag($tagHexCode);
+                    } catch (Syncroton_Wbxml_Exception $swe) {
+                        // tag can not be converted to ASCII name
+                        $tag = sprintf('unknown tag 0x%x', $tagHexCode);
+                    }
+                    $nameSpace    = $this->_codePage->getNameSpace();
                     $codePageName = $this->_codePage->getCodePageName();
                     
                     #echo "Tag: $nameSpace:$tag\n";
                     
-                    if($node === NULL) {
+                    if ($node === NULL) {
                         // create the domdocument
-                        $node = $this->_createDomDocument($nameSpace, $tag);
+                        $node    = $this->_createDomDocument($nameSpace, $tag);
                         $newNode = $node->documentElement;
                     } else {
-                        if(!$this->_dom->isDefaultNamespace($nameSpace)) {
+                        if (!$this->_dom->isDefaultNamespace($nameSpace)) {
                             $this->_dom->documentElement->setAttribute('xmlns:' . $codePageName, $nameSpace);
                         }
                         $newNode = $node->appendChild($this->_dom->createElementNS('uri:' . $codePageName, $tag));
                     }
                     
-                    if($tagHasAttributes) {
+                    if ($tagHasAttributes) {
                         $attributes = $this->_getAttributes();
                     }
                     
-                    if($tagHasContent == true) {
+                    if ($tagHasContent == true) {
                         $node = $newNode;
                         $openTags++;
                     }
diff --git a/lib/ext/Syncroton/Wbxml/Encoder.php b/lib/ext/Syncroton/Wbxml/Encoder.php
index 746ea67..f17db83 100644
--- a/lib/ext/Syncroton/Wbxml/Encoder.php
+++ b/lib/ext/Syncroton/Wbxml/Encoder.php
@@ -151,6 +151,10 @@ class Syncroton_Wbxml_Encoder extends Syncroton_Wbxml_Abstract
     {
         $_dom->formatOutput = false;
         
+        $tempStream = fopen('php://temp/maxmemory:5242880', 'r+');
+        fwrite($tempStream, $_dom->saveXML());
+        rewind($tempStream);
+        
         $this->_initialize($_dom);
         
         $parser = xml_parser_create_ns($this->_charSet, ';');
@@ -159,14 +163,22 @@ class Syncroton_Wbxml_Encoder extends Syncroton_Wbxml_Abstract
         xml_set_character_data_handler($parser, '_handleCharacters');
         xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
         
-        if (!xml_parse($parser, $_dom->saveXML())) {
-            #file_put_contents(tempnam(sys_get_temp_dir(), "xmlerrors"), $_dom->saveXML());
-            throw new Syncroton_Wbxml_Exception(sprintf('XML error: %s at line %d',
-                xml_error_string(xml_get_error_code($parser)),
-                xml_get_current_line_number($parser)
-            ));
+        while (!feof($tempStream)) {
+            if (!xml_parse($parser, fread($tempStream, 1048576), feof($tempStream))) {
+                // uncomment to write xml document to file
+                #rewind($tempStream);
+                #$xmlStream = fopen(tempnam(sys_get_temp_dir(), "xmlerrors"), 'r+');
+                #stream_copy_to_stream($tempStream, $xmlStream);
+                #fclose($xmlStream);
+                
+                throw new Syncroton_Wbxml_Exception(sprintf('XML error: %s at line %d',
+                    xml_error_string(xml_get_error_code($parser)),
+                    xml_get_current_line_number($parser)
+                ));
+            }
         }
 
+        fclose($tempStream);
         xml_parser_free($parser);
     }
 




More information about the commits mailing list