151 var $_value; |
151 var $_value; |
152 var $_currentTag; |
152 var $_currentTag; |
153 var $_currentTagContents; |
153 var $_currentTagContents; |
154 // The XML parser |
154 // The XML parser |
155 var $_parser; |
155 var $_parser; |
156 function IXR_Message ($message) { |
156 function IXR_Message (&$message) { |
157 $this->message = $message; |
157 $this->message = &$message; |
158 } |
158 } |
159 function parse() { |
159 function parse() { |
160 // first remove the XML declaration |
160 // first remove the XML declaration |
161 $this->message = preg_replace('/<\?xml.*?\?'.'>/', '', $this->message); |
161 // this method avoids the RAM usage of preg_replace on very large messages |
|
162 $header = preg_replace( '/<\?xml.*?\?'.'>/', '', substr( $this->message, 0, 100 ), 1 ); |
|
163 $this->message = substr_replace($this->message, $header, 0, 100); |
162 if (trim($this->message) == '') { |
164 if (trim($this->message) == '') { |
163 return false; |
165 return false; |
164 } |
166 } |
165 $this->_parser = xml_parser_create(); |
167 $this->_parser = xml_parser_create(); |
166 // Set XML parser to take the case of tags in to account |
168 // Set XML parser to take the case of tags in to account |
167 xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false); |
169 xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false); |
168 // Set XML parser callback functions |
170 // Set XML parser callback functions |
169 xml_set_object($this->_parser, $this); |
171 xml_set_object($this->_parser, $this); |
170 xml_set_element_handler($this->_parser, 'tag_open', 'tag_close'); |
172 xml_set_element_handler($this->_parser, 'tag_open', 'tag_close'); |
171 xml_set_character_data_handler($this->_parser, 'cdata'); |
173 xml_set_character_data_handler($this->_parser, 'cdata'); |
172 if (!xml_parse($this->_parser, $this->message)) { |
174 $chunk_size = 262144; // 256Kb, parse in chunks to avoid the RAM usage on very large messages |
173 /* die(sprintf('XML error: %s at line %d', |
175 do { |
174 xml_error_string(xml_get_error_code($this->_parser)), |
176 if ( strlen($this->message) <= $chunk_size ) |
175 xml_get_current_line_number($this->_parser))); */ |
177 $final=true; |
176 return false; |
178 $part = substr( $this->message, 0, $chunk_size ); |
177 } |
179 $this->message = substr( $this->message, $chunk_size ); |
178 xml_parser_free($this->_parser); |
180 if ( !xml_parse( $this->_parser, $part, $final ) ) |
|
181 return false; |
|
182 if ( $final ) |
|
183 break; |
|
184 } while ( true ); |
|
185 xml_parser_free($this->_parser); |
179 // Grab the error messages, if any |
186 // Grab the error messages, if any |
180 if ($this->messageType == 'fault') { |
187 if ($this->messageType == 'fault') { |
181 $this->faultCode = $this->params[0]['faultCode']; |
188 $this->faultCode = $this->params[0]['faultCode']; |
182 $this->faultString = $this->params[0]['faultString']; |
189 $this->faultString = $this->params[0]['faultString']; |
183 } |
190 } |
184 return true; |
191 return true; |
185 } |
192 } |
186 function tag_open($parser, $tag, $attr) { |
193 function tag_open($parser, $tag, $attr) { |
187 $this->_currentTagContents = ''; |
194 $this->_currentTagContents = ''; |
188 $this->currentTag = $tag; |
195 $this->currentTag = $tag; |
302 global $HTTP_RAW_POST_DATA; |
309 global $HTTP_RAW_POST_DATA; |
303 if (!$HTTP_RAW_POST_DATA) { |
310 if (!$HTTP_RAW_POST_DATA) { |
304 header( 'Content-Type: text/plain' ); |
311 header( 'Content-Type: text/plain' ); |
305 die('XML-RPC server accepts POST requests only.'); |
312 die('XML-RPC server accepts POST requests only.'); |
306 } |
313 } |
307 $data = $HTTP_RAW_POST_DATA; |
314 $data = &$HTTP_RAW_POST_DATA; |
308 } |
315 } |
309 $this->message = new IXR_Message($data); |
316 $this->message = new IXR_Message($data); |
310 if (!$this->message->parse()) { |
317 if (!$this->message->parse()) { |
311 $this->error(-32700, 'parse error. not well formed'); |
318 $this->error(-32700, 'parse error. not well formed'); |
312 } |
319 } |