Browse Source

If no data type tag is used in XML-RPC, treat the data as string.

Tatsuhiro Tsujikawa 14 years ago
parent
commit
211c4ea9f4

+ 15 - 1
src/XmlRpcRequestParserStateImpl.cc

@@ -168,7 +168,20 @@ void ValueXmlRpcRequestParserState::beginElement
     stm->pushUnknownElementState();
   }
 }
-  
+
+void ValueXmlRpcRequestParserState::endElement
+(XmlRpcRequestParserStateMachine* stm,
+ const std::string& name,
+ const std::string& characters)
+{
+  // XML-RPC specification says that if no data type tag is used, the
+  // data must be treated as string.  To prevent from overwriting
+  // current frame value, we first check it is still null.
+  if(!stm->getCurrentFrameValue() && !characters.empty()) {
+    stm->setCurrentFrameValue(String::g(characters));
+  }
+}
+
 // IntXmlRpcRequestParserState
 
 void IntXmlRpcRequestParserState::beginElement
@@ -321,6 +334,7 @@ void ArrayValueXmlRpcRequestParserState::endElement
  const std::string& name,
  const std::string& characters)
 {
+  ValueXmlRpcRequestParserState::endElement(stm, name, characters);
   stm->popArrayFrame();
 }
 

+ 3 - 3
src/XmlRpcRequestParserStateImpl.h

@@ -121,12 +121,12 @@ class ValueXmlRpcRequestParserState:public XmlRpcRequestParserState {
   virtual void beginElement(XmlRpcRequestParserStateMachine* stm,
                             const std::string& name,
                             const std::map<std::string, std::string>& attrs);
-  
+protected:
   virtual void endElement(XmlRpcRequestParserStateMachine* stm,
                           const std::string& name,
-                          const std::string& characters) {}
+                          const std::string& characters);
 
-  virtual bool needsCharactersBuffering() const { return false; }
+  virtual bool needsCharactersBuffering() const { return true; }
 };
 
 class IntXmlRpcRequestParserState:public XmlRpcRequestParserState {

+ 54 - 0
test/XmlRpcRequestProcessorTest.cc

@@ -14,6 +14,7 @@ class XmlRpcRequestProcessorTest:public CppUnit::TestFixture {
   CPPUNIT_TEST_SUITE(XmlRpcRequestProcessorTest);
   CPPUNIT_TEST(testParseMemory);
   CPPUNIT_TEST(testParseMemory_shouldFail);
+  CPPUNIT_TEST(testParseMemory_withoutStringTag);
   CPPUNIT_TEST_SUITE_END();
 public:
   void setUp() {}
@@ -22,6 +23,7 @@ public:
 
   void testParseMemory();
   void testParseMemory_shouldFail();
+  void testParseMemory_withoutStringTag();
 };
 
 
@@ -114,6 +116,58 @@ void XmlRpcRequestProcessorTest::testParseMemory_shouldFail()
   }
 }
 
+void XmlRpcRequestProcessorTest::testParseMemory_withoutStringTag()
+{
+  XmlRpcRequestProcessor proc;
+  RpcRequest req =
+    proc.parseMemory("<?xml version=\"1.0\"?>"
+                     "<methodCall>"
+                     "  <methodName>aria2.addUri</methodName>"
+                     "    <params>"
+                     "      <param>"
+                     "        <value>http://aria2.sourceforge.net</value>"
+                     "      </param>"
+                     "      <param>"
+                     "        <value>http://aria2.<foo/>sourceforge.net</value>"
+                     "      </param>"
+                     "      <param>"
+                     "       <value>"
+                     "         <struct>"
+                     "           <member>"
+                     "             <name>hello</name>"
+                     "             <value>world</value>"
+                     "           </member>"
+                     "         </struct>"
+                     "       </value>"
+                     "     </param>"
+                     "     <param>"
+                     "       <value>"
+                     "         <array>"
+                     "           <data>"
+                     "             <value>apple</value>"
+                     "             <value>banana</value>"
+                     "             <value><string>lemon</string>peanuts</value>"
+                     "           </data>"
+                     "         </array>"
+                     "       </value>"
+                     "     </param>"
+                     "   </params>"
+                     "</methodCall>");
+
+  CPPUNIT_ASSERT_EQUAL((size_t)4, req.params->size());
+  CPPUNIT_ASSERT_EQUAL(std::string("http://aria2.sourceforge.net"),
+                       asString(req.params->get(0))->s());
+  CPPUNIT_ASSERT_EQUAL(std::string("http://aria2.sourceforge.net"),
+                       asString(req.params->get(1))->s());
+  const Dict* dict = asDict(req.params->get(2));
+  CPPUNIT_ASSERT_EQUAL(std::string("world"),
+                       asString(dict->get("hello"))->s());
+  const List* list = asList(req.params->get(3));
+  CPPUNIT_ASSERT_EQUAL(std::string("apple"), asString(list->get(0))->s());
+  CPPUNIT_ASSERT_EQUAL(std::string("banana"), asString(list->get(1))->s());
+  CPPUNIT_ASSERT_EQUAL(std::string("lemon"), asString(list->get(2))->s());
+}
+
 } // namespace rpc
 
 } // namespace aria2