summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com>2022-04-08 23:29:13 +0900
committerGitHub <noreply@github.com>2022-04-08 23:29:13 +0900
commit998f203288e399d371a91c6ecfb22f9ce2b26105 (patch)
tree6110994e4a9f28608da92e41b235990257ba13eb
parent37a7419fed8e6035a77c30bef456e36cbfd60245 (diff)
parentba36a38a6c4be38fe4e09cc95a40b58a48daed79 (diff)
Merge pull request #1905 from aria2/bt-bencode-allow-empty-dict-name
Allow empty dist name in bencode which is needed for hybrid torrent
-rw-r--r--src/GenericParser.h9
-rw-r--r--src/ValueBaseBencodeParser.h2
-rw-r--r--src/ValueBaseStructParserStateMachine.cc5
-rw-r--r--src/ValueBaseStructParserStateMachine.h2
-rw-r--r--src/XmlRpcRequestParserController.cc7
-rw-r--r--src/XmlRpcRequestParserController.h11
-rw-r--r--test/ValueBaseBencodeParserTest.cc10
7 files changed, 41 insertions, 5 deletions
diff --git a/src/GenericParser.h b/src/GenericParser.h
index 86c6ca92..7373b066 100644
--- a/src/GenericParser.h
+++ b/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;
diff --git a/src/ValueBaseBencodeParser.h b/src/ValueBaseBencodeParser.h
index cfc43145..91cfc37b 100644
--- a/src/ValueBaseBencodeParser.h
+++ b/src/ValueBaseBencodeParser.h
@@ -43,7 +43,7 @@ namespace aria2 {
namespace bittorrent {
-typedef GenericParser<BencodeParser, ValueBaseStructParserStateMachine>
+typedef GenericParser<BencodeParser, ValueBaseStructParserStateMachine, true>
ValueBaseBencodeParser;
} // namespace bittorrent
diff --git a/src/ValueBaseStructParserStateMachine.cc b/src/ValueBaseStructParserStateMachine.cc
index b026758a..caf6296e 100644
--- a/src/ValueBaseStructParserStateMachine.cc
+++ b/src/ValueBaseStructParserStateMachine.cc
@@ -213,4 +213,9 @@ void ValueBaseStructParserStateMachine::pushNullState()
stateStack_.push(nullState);
}
+void ValueBaseStructParserStateMachine::setAllowEmptyMemberName(bool b)
+{
+ ctrl_->setAllowEmptyMemberName(b);
+}
+
} // namespace aria2
diff --git a/src/ValueBaseStructParserStateMachine.h b/src/ValueBaseStructParserStateMachine.h
index a049de3a..c309cfb6 100644
--- a/src/ValueBaseStructParserStateMachine.h
+++ b/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_;
diff --git a/src/XmlRpcRequestParserController.cc b/src/XmlRpcRequestParserController.cc
index 25a5addc..a3c9a857 100644
--- a/src/XmlRpcRequestParserController.cc
+++ b/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
diff --git a/src/XmlRpcRequestParserController.h b/src/XmlRpcRequestParserController.h
index 7892147b..b84a7de1 100644
--- a/src/XmlRpcRequestParserController.h
+++ b/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();
};
diff --git a/test/ValueBaseBencodeParserTest.cc b/test/ValueBaseBencodeParserTest.cc
index 30cca2f4..2e12ec49 100644
--- a/test/ValueBaseBencodeParserTest.cc
+++ b/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