소스 검색

Merge pull request #1905 from aria2/bt-bencode-allow-empty-dict-name

Allow empty dist name in bencode which is needed for hybrid torrent
Tatsuhiro Tsujikawa 3 년 전
부모
커밋
998f203288

+ 7 - 2
src/GenericParser.h

@@ -42,9 +42,14 @@
 
 namespace aria2 {
 
-template <typename Parser, typename ParserStateMachine> class GenericParser {
+template <typename Parser, typename ParserStateMachine,
+          bool allowEmptyName = false>
+class GenericParser {
 public:
-  GenericParser() : parser_{&psm_} {}
+  GenericParser() : parser_{&psm_}
+  {
+    psm_.setAllowEmptyMemberName(allowEmptyName);
+  }
 
   ~GenericParser() = default;
 

+ 1 - 1
src/ValueBaseBencodeParser.h

@@ -43,7 +43,7 @@ namespace aria2 {
 
 namespace bittorrent {
 
-typedef GenericParser<BencodeParser, ValueBaseStructParserStateMachine>
+typedef GenericParser<BencodeParser, ValueBaseStructParserStateMachine, true>
     ValueBaseBencodeParser;
 
 } // namespace bittorrent

+ 5 - 0
src/ValueBaseStructParserStateMachine.cc

@@ -213,4 +213,9 @@ void ValueBaseStructParserStateMachine::pushNullState()
   stateStack_.push(nullState);
 }
 
+void ValueBaseStructParserStateMachine::setAllowEmptyMemberName(bool b)
+{
+  ctrl_->setAllowEmptyMemberName(b);
+}
+
 } // namespace aria2

+ 2 - 0
src/ValueBaseStructParserStateMachine.h

@@ -106,6 +106,8 @@ public:
   void pushBoolState();
   void pushNullState();
 
+  void setAllowEmptyMemberName(bool b);
+
 private:
   std::unique_ptr<rpc::XmlRpcRequestParserController> ctrl_;
   std::stack<ValueBaseStructParserState*> stateStack_;

+ 6 - 1
src/XmlRpcRequestParserController.cc

@@ -54,7 +54,7 @@ void XmlRpcRequestParserController::popStructFrame()
   Dict* dict = downcast<Dict>(parentFrame.value_);
   assert(dict);
   frameStack_.pop();
-  if (currentFrame_.validMember()) {
+  if (currentFrame_.validMember(allowEmptyMemberName_)) {
     dict->put(std::move(currentFrame_.name_), std::move(currentFrame_.value_));
   }
   currentFrame_ = std::move(parentFrame);
@@ -110,6 +110,11 @@ void XmlRpcRequestParserController::setMethodName(std::string methodName)
   methodName_ = std::move(methodName);
 }
 
+void XmlRpcRequestParserController::setAllowEmptyMemberName(bool b)
+{
+  allowEmptyMemberName_ = b;
+}
+
 } // namespace rpc
 
 } // namespace aria2

+ 10 - 1
src/XmlRpcRequestParserController.h

@@ -52,7 +52,10 @@ private:
     std::unique_ptr<ValueBase> value_;
     std::string name_;
 
-    bool validMember() const { return value_ && !name_.empty(); }
+    bool validMember(bool allowEmptyMemberName) const
+    {
+      return value_ && (allowEmptyMemberName || !name_.empty());
+    }
 
     void reset()
     {
@@ -67,7 +70,11 @@ private:
 
   std::string methodName_;
 
+  bool allowEmptyMemberName_;
+
 public:
+  XmlRpcRequestParserController() : allowEmptyMemberName_(false) {}
+
   void pushFrame();
 
   // Pops StateFrame p from frameStack_ and set p[currentFrame_.name_]
@@ -90,6 +97,8 @@ public:
 
   const std::string& getMethodName() const { return methodName_; }
 
+  void setAllowEmptyMemberName(bool b);
+
   void reset();
 };
 

+ 10 - 0
test/ValueBaseBencodeParserTest.cc

@@ -208,6 +208,16 @@ void ValueBaseBencodeParserTest::testParseUpdate()
     // Get trailing garbage position
     CPPUNIT_ASSERT_EQUAL((ssize_t)7, error);
   }
+  {
+    // dict, empty member name
+    std::string src = "d0:i123ee";
+    std::shared_ptr<ValueBase> d =
+        parser.parseFinal(src.c_str(), src.size(), error);
+    Dict* dict = downcast<Dict>(d);
+    CPPUNIT_ASSERT(dict);
+    CPPUNIT_ASSERT(dict->get(""));
+    CPPUNIT_ASSERT_EQUAL((int64_t)123, downcast<Integer>(dict->get(""))->i());
+  }
 }
 
 } // namespace aria2