Commit 5443b73b authored by zijiehe's avatar zijiehe Committed by Commit bot

[Chromoting] Plugin message in JingleMessage

This change adds plugin message in JingleMessage, which is an action indepenent
xml node, placed before or after other messages.

The plugin message will be used to send and receive host attributes and
experiment configuration.

This is part of host experiment framework.

BUG=650926

Review-Url: https://codereview.chromium.org/2567953002
Cr-Commit-Position: refs/heads/master@{#438945}
parent 8cb43c2a
per-file *_messages.cc=set noparent
per-file *_messages.cc=file://ipc/SECURITY_OWNERS
per-file *_messages*.h=set noparent
per-file *_messages*.h=file://ipc/SECURITY_OWNERS
per-file jingle_messages.h=file://remoting/OWNERS
per-file jingle_messages.cc=file://remoting/OWNERS
...@@ -342,15 +342,28 @@ bool JingleMessage::ParseXml(const buzz::XmlElement* stanza, ...@@ -342,15 +342,28 @@ bool JingleMessage::ParseXml(const buzz::XmlElement* stanza,
return false; return false;
} }
const XmlElement* attachments_tag =
jingle_tag->FirstNamed(QName(kChromotingXmlNamespace, "attachments"));
if (attachments_tag) {
attachments.reset(new XmlElement(*attachments_tag));
} else {
attachments.reset();
}
if (action == SESSION_INFO) { if (action == SESSION_INFO) {
// session-info messages may contain arbitrary information not // session-info messages may contain arbitrary information not
// defined by the Jingle protocol. We don't need to parse it. // defined by the Jingle protocol. We don't need to parse it.
const XmlElement* child = jingle_tag->FirstElement(); const XmlElement* child = jingle_tag->FirstElement();
// Plugin messages are action independent, which should not be considered as
// session-info.
if (child == attachments_tag) {
child = child->NextElement();
}
if (child) { if (child) {
// session-info is allowed to be empty. // session-info is allowed to be empty.
info.reset(new XmlElement(*child)); info.reset(new XmlElement(*child));
} else { } else {
info.reset(nullptr); info.reset();
} }
return true; return true;
} }
...@@ -374,8 +387,9 @@ bool JingleMessage::ParseXml(const buzz::XmlElement* stanza, ...@@ -374,8 +387,9 @@ bool JingleMessage::ParseXml(const buzz::XmlElement* stanza,
} }
} }
if (action == SESSION_TERMINATE) if (action == SESSION_TERMINATE) {
return true; return true;
}
const XmlElement* content_tag = const XmlElement* content_tag =
jingle_tag->FirstNamed(QName(kJingleNamespace, "content")); jingle_tag->FirstNamed(QName(kJingleNamespace, "content"));
...@@ -396,7 +410,7 @@ bool JingleMessage::ParseXml(const buzz::XmlElement* stanza, ...@@ -396,7 +410,7 @@ bool JingleMessage::ParseXml(const buzz::XmlElement* stanza,
transport_info.reset(new buzz::XmlElement(*webrtc_transport_tag)); transport_info.reset(new buzz::XmlElement(*webrtc_transport_tag));
} }
description.reset(nullptr); description.reset();
if (action == SESSION_INITIATE || action == SESSION_ACCEPT) { if (action == SESSION_INITIATE || action == SESSION_ACCEPT) {
const XmlElement* description_tag = content_tag->FirstNamed( const XmlElement* description_tag = content_tag->FirstNamed(
QName(kChromotingXmlNamespace, "description")); QName(kChromotingXmlNamespace, "description"));
...@@ -439,18 +453,25 @@ std::unique_ptr<buzz::XmlElement> JingleMessage::ToXml() const { ...@@ -439,18 +453,25 @@ std::unique_ptr<buzz::XmlElement> JingleMessage::ToXml() const {
SetAddress(root.get(), jingle_tag, from, true); SetAddress(root.get(), jingle_tag, from, true);
const char* action_attr = ValueToName(kActionTypes, action); const char* action_attr = ValueToName(kActionTypes, action);
if (!action_attr) if (!action_attr) {
LOG(FATAL) << "Invalid action value " << action; LOG(FATAL) << "Invalid action value " << action;
}
jingle_tag->AddAttr(QName(kEmptyNamespace, "action"), action_attr); jingle_tag->AddAttr(QName(kEmptyNamespace, "action"), action_attr);
if (attachments) {
jingle_tag->AddElement(new XmlElement(*attachments));
}
if (action == SESSION_INFO) { if (action == SESSION_INFO) {
if (info.get()) if (info.get()) {
jingle_tag->AddElement(new XmlElement(*info.get())); jingle_tag->AddElement(new XmlElement(*info.get()));
}
return root; return root;
} }
if (action == SESSION_INITIATE) if (action == SESSION_INITIATE) {
jingle_tag->AddAttr(QName(kEmptyNamespace, "initiator"), initiator); jingle_tag->AddAttr(QName(kEmptyNamespace, "initiator"), initiator);
}
if (reason != UNKNOWN_REASON) { if (reason != UNKNOWN_REASON) {
XmlElement* reason_tag = new XmlElement(QName(kJingleNamespace, "reason")); XmlElement* reason_tag = new XmlElement(QName(kJingleNamespace, "reason"));
...@@ -475,8 +496,9 @@ std::unique_ptr<buzz::XmlElement> JingleMessage::ToXml() const { ...@@ -475,8 +496,9 @@ std::unique_ptr<buzz::XmlElement> JingleMessage::ToXml() const {
ContentDescription::kChromotingContentName); ContentDescription::kChromotingContentName);
content_tag->AddAttr(QName(kEmptyNamespace, "creator"), "initiator"); content_tag->AddAttr(QName(kEmptyNamespace, "creator"), "initiator");
if (description) if (description) {
content_tag->AddElement(description->ToXml()); content_tag->AddElement(description->ToXml());
}
if (transport_info) { if (transport_info) {
content_tag->AddElement(new XmlElement(*transport_info)); content_tag->AddElement(new XmlElement(*transport_info));
...@@ -573,8 +595,9 @@ std::unique_ptr<buzz::XmlElement> JingleMessageReply::ToXml( ...@@ -573,8 +595,9 @@ std::unique_ptr<buzz::XmlElement> JingleMessageReply::ToXml(
NOTREACHED(); NOTREACHED();
} }
if (!text.empty()) if (!text.empty()) {
error_text = text; error_text = text;
}
error->SetAttr(QName(kEmptyNamespace, "type"), type); error->SetAttr(QName(kEmptyNamespace, "type"), type);
...@@ -604,8 +627,9 @@ IceTransportInfo::~IceTransportInfo() {} ...@@ -604,8 +627,9 @@ IceTransportInfo::~IceTransportInfo() {}
bool IceTransportInfo::ParseXml( bool IceTransportInfo::ParseXml(
const buzz::XmlElement* element) { const buzz::XmlElement* element) {
if (element->Name() != QName(kIceTransportNamespace, "transport")) if (element->Name() != QName(kIceTransportNamespace, "transport")) {
return false; return false;
}
ice_credentials.clear(); ice_credentials.clear();
candidates.clear(); candidates.clear();
...@@ -615,8 +639,9 @@ bool IceTransportInfo::ParseXml( ...@@ -615,8 +639,9 @@ bool IceTransportInfo::ParseXml(
credentials_tag; credentials_tag;
credentials_tag = credentials_tag->NextNamed(qn_credentials)) { credentials_tag = credentials_tag->NextNamed(qn_credentials)) {
IceTransportInfo::IceCredentials credentials; IceTransportInfo::IceCredentials credentials;
if (!ParseIceCredentials(credentials_tag, &credentials)) if (!ParseIceCredentials(credentials_tag, &credentials)) {
return false; return false;
}
ice_credentials.push_back(credentials); ice_credentials.push_back(credentials);
} }
...@@ -624,8 +649,9 @@ bool IceTransportInfo::ParseXml( ...@@ -624,8 +649,9 @@ bool IceTransportInfo::ParseXml(
for (const XmlElement* candidate_tag = element->FirstNamed(qn_candidate); for (const XmlElement* candidate_tag = element->FirstNamed(qn_candidate);
candidate_tag; candidate_tag = candidate_tag->NextNamed(qn_candidate)) { candidate_tag; candidate_tag = candidate_tag->NextNamed(qn_candidate)) {
IceTransportInfo::NamedCandidate candidate; IceTransportInfo::NamedCandidate candidate;
if (!ParseIceCandidate(candidate_tag, &candidate)) if (!ParseIceCandidate(candidate_tag, &candidate)) {
return false; return false;
}
candidates.push_back(candidate); candidates.push_back(candidate);
} }
......
...@@ -101,6 +101,10 @@ struct JingleMessage { ...@@ -101,6 +101,10 @@ struct JingleMessage {
// Content of session-info messages. // Content of session-info messages.
std::unique_ptr<buzz::XmlElement> info; std::unique_ptr<buzz::XmlElement> info;
// Content of plugin message. The node is read or written by all plugins, and
// ActionType independent.
std::unique_ptr<buzz::XmlElement> attachments;
// Value from the <reason> tag if it is present in the // Value from the <reason> tag if it is present in the
// message. Useful mainly for session-terminate messages, but Jingle // message. Useful mainly for session-terminate messages, but Jingle
// spec allows it in any message. // spec allows it in any message.
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/strings/string_util.h"
#include "remoting/protocol/content_description.h" #include "remoting/protocol/content_description.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -600,5 +601,70 @@ TEST(JingleMessageTest, RemotingErrorCode) { ...@@ -600,5 +601,70 @@ TEST(JingleMessageTest, RemotingErrorCode) {
} }
} }
TEST(JingleMessageTest, AttachmentsMessage) {
// Ordering of the "attachments" tag and other tags are irrelevent. But the
// JingleMessage implementation always puts it before other tags, so we do the
// same thing in test cases.
const char* kMessageWithPluginTag =
"<cli:iq from='user@gmail.com/chromoting016DBB07' "
"to='user@gmail.com/chromiumsy5C6A652D' type='set' "
"xmlns:cli='jabber:client'><jingle action='$1' "
"sid='2227053353' xmlns='urn:xmpp:jingle:1'>"
"<gr:attachments xmlns:gr='google:remoting'>"
"<gr:sometag>some-message</gr:sometag>"
"</gr:attachments>$2</jingle></cli:iq>";
for (int i = JingleMessage::SESSION_INITIATE;
i <= JingleMessage::TRANSPORT_INFO; i++) {
JingleMessage::ActionType action_type =
static_cast<JingleMessage::ActionType>(i);
std::vector<std::string> substitutes = {
JingleMessage::GetActionName(action_type)
};
if (action_type == JingleMessage::SESSION_INFO) {
substitutes.push_back("<test-info>test-message</test-info>");
} else if (action_type == JingleMessage::SESSION_TERMINATE) {
substitutes.emplace_back();
} else if (action_type == JingleMessage::TRANSPORT_INFO) {
substitutes.push_back(
"<content name='chromoting' creator='initiator'>"
"<transport xmlns='google:remoting:webrtc'>"
"<credentials channel='event' ufrag='tPUyEAmQrEw3y7hi' "
"password='2iRdhLfawKZC5ydJ'/>"
"<credentials channel='video' ufrag='EPK3CXo5sTLJSez0' "
"password='eM0VUfUkZ+1Pyi0M'/>"
"<candidate name='event' foundation='725747215' "
"address='172.23.164.186' port='59089' type='local' "
"protocol='udp' priority='2122194688' generation='0'/>"
"<candidate name='video' foundation='3623806809' "
"address='172.23.164.186' port='57040' type='local' "
"protocol='udp' priority='2122194688' generation='0'/>"
"</transport>"
"</content>");
} else {
substitutes.push_back("<content name='chromoting' creator='initiator'>"
"<description xmlns='google:remoting'>"
"<authentication><auth-token>"
"j7whCMii0Z0AAPwj7whCM/j7whCMii0Z0AAPw="
"</auth-token></authentication>"
"</description>"
"<transport xmlns='google:remoting:webrtc' />"
"</content>");
}
std::string message_str = base::ReplaceStringPlaceholders(
kMessageWithPluginTag, substitutes, nullptr);
JingleMessage message;
ParseFormatAndCompare(message_str.c_str(), &message);
EXPECT_TRUE(message.attachments);
XmlElement expected(QName("google:remoting", "attachments"));
expected.AddElement(new XmlElement(QName("google:remoting", "sometag")));
expected.FirstElement()->SetBodyText("some-message");
std::string error;
EXPECT_TRUE(VerifyXml(&expected, message.attachments.get(), &error))
<< error;
}
}
} // namespace protocol } // namespace protocol
} // namespace remoting } // namespace remoting
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment