Fixing issue where description contains empty ICE ufrag/pwd.

The issue occurred when deserializing and then serializing a rejected
content description, which doesn't have the ICE ufrag/pwd in the first
place.

BUG=webrtc:5105

Review URL: https://codereview.webrtc.org/1534363002

Cr-Commit-Position: refs/heads/master@{#11134}
diff --git a/talk/app/webrtc/webrtcsdp.cc b/talk/app/webrtc/webrtcsdp.cc
index 60cc539..07a4eb9 100644
--- a/talk/app/webrtc/webrtcsdp.cc
+++ b/talk/app/webrtc/webrtcsdp.cc
@@ -1295,13 +1295,17 @@
     // ice-pwd-att           = "ice-pwd" ":" password
     // ice-ufrag-att         = "ice-ufrag" ":" ufrag
     // ice-ufrag
-    InitAttrLine(kAttributeIceUfrag, &os);
-    os << kSdpDelimiterColon << transport_info->description.ice_ufrag;
-    AddLine(os.str(), message);
+    if (!transport_info->description.ice_ufrag.empty()) {
+      InitAttrLine(kAttributeIceUfrag, &os);
+      os << kSdpDelimiterColon << transport_info->description.ice_ufrag;
+      AddLine(os.str(), message);
+    }
     // ice-pwd
-    InitAttrLine(kAttributeIcePwd, &os);
-    os << kSdpDelimiterColon << transport_info->description.ice_pwd;
-    AddLine(os.str(), message);
+    if (!transport_info->description.ice_pwd.empty()) {
+      InitAttrLine(kAttributeIcePwd, &os);
+      os << kSdpDelimiterColon << transport_info->description.ice_pwd;
+      AddLine(os.str(), message);
+    }
 
     // draft-petithuguenin-mmusic-ice-attributes-level-03
     BuildIceOptions(transport_info->description.transport_options, message);
diff --git a/talk/app/webrtc/webrtcsdp_unittest.cc b/talk/app/webrtc/webrtcsdp_unittest.cc
index 97b6a26..1bf3e68 100644
--- a/talk/app/webrtc/webrtcsdp_unittest.cc
+++ b/talk/app/webrtc/webrtcsdp_unittest.cc
@@ -80,11 +80,13 @@
 static const uint32_t kCandidatePriority = 2130706432U;  // pref = 1.0
 static const char kCandidateUfragVoice[] = "ufrag_voice";
 static const char kCandidatePwdVoice[] = "pwd_voice";
+static const char kAttributeIceUfragVoice[] = "a=ice-ufrag:ufrag_voice\r\n";
 static const char kAttributeIcePwdVoice[] = "a=ice-pwd:pwd_voice\r\n";
 static const char kCandidateUfragVideo[] = "ufrag_video";
 static const char kCandidatePwdVideo[] = "pwd_video";
 static const char kCandidateUfragData[] = "ufrag_data";
 static const char kCandidatePwdData[] = "pwd_data";
+static const char kAttributeIceUfragVideo[] = "a=ice-ufrag:ufrag_video\r\n";
 static const char kAttributeIcePwdVideo[] = "a=ice-pwd:pwd_video\r\n";
 static const uint32_t kCandidateGeneration = 2;
 static const char kCandidateFoundation1[] = "a0+B/1";
@@ -525,10 +527,14 @@
 static void ReplaceRejected(bool audio_rejected, bool video_rejected,
                             std::string* message) {
   if (audio_rejected) {
-    Replace("m=audio 2345", "m=audio 0", message);
+    Replace("m=audio 9", "m=audio 0", message);
+    Replace(kAttributeIceUfragVoice, "", message);
+    Replace(kAttributeIcePwdVoice, "", message);
   }
   if (video_rejected) {
-    Replace("m=video 3457", "m=video 0", message);
+    Replace("m=video 9", "m=video 0", message);
+    Replace(kAttributeIceUfragVideo, "", message);
+    Replace(kAttributeIcePwdVideo, "", message);
   }
 }
 
@@ -985,6 +991,18 @@
     desc_.AddTransportInfo(transport_info);
   }
 
+  void SetIceUfragPwd(const std::string& content_name,
+                      const std::string& ice_ufrag,
+                      const std::string& ice_pwd) {
+    ASSERT_TRUE(desc_.GetTransportInfoByName(content_name) != NULL);
+    cricket::TransportInfo transport_info =
+        *(desc_.GetTransportInfoByName(content_name));
+    desc_.RemoveTransportInfoByName(content_name);
+    transport_info.description.ice_ufrag = ice_ufrag;
+    transport_info.description.ice_pwd = ice_pwd;
+    desc_.AddTransportInfo(transport_info);
+  }
+
   void AddFingerprint() {
     desc_.RemoveTransportInfoByName(kAudioContentName);
     desc_.RemoveTransportInfoByName(kVideoContentName);
@@ -1056,15 +1074,22 @@
                      audio_desc_);
     desc_.AddContent(kVideoContentName, NS_JINGLE_RTP, video_rejected,
                      video_desc_);
-    std::string new_sdp = kSdpFullString;
+    SetIceUfragPwd(kAudioContentName,
+                   audio_rejected ? "" : kCandidateUfragVoice,
+                   audio_rejected ? "" : kCandidatePwdVoice);
+    SetIceUfragPwd(kVideoContentName,
+                   video_rejected ? "" : kCandidateUfragVideo,
+                   video_rejected ? "" : kCandidatePwdVideo);
+
+    std::string new_sdp = kSdpString;
     ReplaceRejected(audio_rejected, video_rejected, &new_sdp);
 
-    if (!jdesc_.Initialize(desc_.Copy(),
-                           jdesc_.session_id(),
-                           jdesc_.session_version())) {
+    JsepSessionDescription jdesc_no_candidates(kDummyString);
+    if (!jdesc_no_candidates.Initialize(desc_.Copy(), kSessionId,
+                                        kSessionVersion)) {
       return false;
     }
-    std::string message = webrtc::SdpSerialize(jdesc_);
+    std::string message = webrtc::SdpSerialize(jdesc_no_candidates);
     EXPECT_EQ(new_sdp, message);
     return true;
   }
@@ -1127,11 +1152,11 @@
   }
 
   bool TestDeserializeRejected(bool audio_rejected, bool video_rejected) {
-    std::string new_sdp = kSdpFullString;
+    std::string new_sdp = kSdpString;
     ReplaceRejected(audio_rejected, video_rejected, &new_sdp);
     JsepSessionDescription new_jdesc(JsepSessionDescription::kOffer);
-
     EXPECT_TRUE(SdpDeserialize(new_sdp, &new_jdesc));
+
     audio_desc_ = static_cast<AudioContentDescription*>(
         audio_desc_->Copy());
     video_desc_ = static_cast<VideoContentDescription*>(
@@ -1142,12 +1167,18 @@
                      audio_desc_);
     desc_.AddContent(kVideoContentName, NS_JINGLE_RTP, video_rejected,
                      video_desc_);
-    if (!jdesc_.Initialize(desc_.Copy(),
-                           jdesc_.session_id(),
-                           jdesc_.session_version())) {
+    SetIceUfragPwd(kAudioContentName,
+                   audio_rejected ? "" : kCandidateUfragVoice,
+                   audio_rejected ? "" : kCandidatePwdVoice);
+    SetIceUfragPwd(kVideoContentName,
+                   video_rejected ? "" : kCandidateUfragVideo,
+                   video_rejected ? "" : kCandidatePwdVideo);
+    JsepSessionDescription jdesc_no_candidates(kDummyString);
+    if (!jdesc_no_candidates.Initialize(desc_.Copy(), jdesc_.session_id(),
+                                        jdesc_.session_version())) {
       return false;
     }
-    EXPECT_TRUE(CompareSessionDescription(jdesc_, new_jdesc));
+    EXPECT_TRUE(CompareSessionDescription(jdesc_no_candidates, new_jdesc));
     return true;
   }
 
@@ -1546,8 +1577,8 @@
 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithoutCandidates) {
   // JsepSessionDescription with desc but without candidates.
   JsepSessionDescription jdesc_no_candidates(kDummyString);
-  ASSERT_TRUE(jdesc_no_candidates.Initialize(desc_.Copy(),
-                                             kSessionId, kSessionVersion));
+  ASSERT_TRUE(jdesc_no_candidates.Initialize(desc_.Copy(), kSessionId,
+                                             kSessionVersion));
   std::string message = webrtc::SdpSerialize(jdesc_no_candidates);
   EXPECT_EQ(std::string(kSdpString), message);
 }