Bug 1474517: merge rsdparsa from upstream r=johannes.willbold+610943
authorNils Ohlmeier [:drno] <drno@ohlmeier.org>
Mon, 09 Jul 2018 23:56:42 -0700
changeset 426598 ff25d41b504f
parent 426597 d48e40cba0b4
child 426599 04dd259d71db
push id34276
push userncsoregi@mozilla.com
push dateSat, 14 Jul 2018 09:41:08 +0000
treeherdermozilla-central@04dd259d71db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjohannes
bugs1474517, 610943
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1474517: merge rsdparsa from upstream r=johannes.willbold+610943 Updated rsdparsa to 75d5c6df6728fbab502db06940062e0358536f9f from github upstream MozReview-Commit-ID: 9hr7DV6KTkK
Cargo.lock
media/webrtc/signaling/src/sdp/rsdparsa/Cargo.toml
media/webrtc/signaling/src/sdp/rsdparsa/src/attribute_type.rs
media/webrtc/signaling/src/sdp/rsdparsa/src/lib.rs
media/webrtc/signaling/src/sdp/rsdparsa/src/media_type.rs
media/webrtc/signaling/src/sdp/rsdparsa/tests/unit_tests.rs
media/webrtc/signaling/src/sdp/rsdparsa_capi/src/lib.rs
media/webrtc/signaling/src/sdp/rsdparsa_capi/src/media_section.rs
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1729,16 +1729,21 @@ version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "rsdparsa"
 version = "0.1.0"
+dependencies = [
+ "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.66 (git+https://github.com/servo/serde?branch=deserialize_from_enums8)",
+]
 
 [[package]]
 name = "rsdparsa_capi"
 version = "0.1.0"
 dependencies = [
  "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "nserror 0.1.0",
--- a/media/webrtc/signaling/src/sdp/rsdparsa/Cargo.toml
+++ b/media/webrtc/signaling/src/sdp/rsdparsa/Cargo.toml
@@ -1,7 +1,18 @@
 [package]
 name = "rsdparsa"
 version = "0.1.0"
 authors = ["Nils Ohlmeier <github@ohlmeier.org>"]
 
 [features]
 default = []
+# serializability
+serialize = ["serde", "serde_derive"]
+
+[dependencies]
+# clippy = {version = "*", optional = true}
+log = {version = "*"}
+serde = {version = "1.0" , optional = true}
+serde_derive = {version = "1.0" , optional = true}
+
+[dev-dependencies]
+# serde_json = {version = "1.0"}
--- a/media/webrtc/signaling/src/sdp/rsdparsa/src/attribute_type.rs
+++ b/media/webrtc/signaling/src/sdp/rsdparsa/src/attribute_type.rs
@@ -768,17 +768,16 @@ fn parse_single_direction(to_parse: &str
         "send" => Ok(SdpSingleDirection::Send),
         "recv" => Ok(SdpSingleDirection::Recv),
         x @ _ => Err(SdpParserInternalError::Generic(
             format!("Unknown direction description found: '{:}'",x).to_string()
         ))
     }
 }
 
-
 fn parse_sctp_port(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
     let port = to_parse.parse()?;
     if port > 65535 {
         return Err(SdpParserInternalError::Generic(format!("Sctpport port {} can only be a bit 16bit number",
                                                            port)));
     }
     Ok(SdpAttribute::SctpPort(port))
 }
@@ -1097,16 +1096,17 @@ fn parse_fmtp(to_parse: &str) -> Result<
         }
     }
 
     Ok(SdpAttribute::Fmtp(SdpAttributeFmtp {
                               payload_type: payload_token.parse::<u8>()?,
                               parameters: parameters,
                           }))
 }
+
 fn parse_group(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
     let mut tokens = to_parse.split_whitespace();
     let semantics = match tokens.next() {
         None => {
             return Err(SdpParserInternalError::Generic("Group attribute is missing semantics token"
                                                            .to_string()))
         }
         Some(x) => {
@@ -1993,17 +1993,40 @@ fn test_parse_attribute_rtcp() {
     assert!(parse_attribute("rtcp:70000").is_err());
     assert!(parse_attribute("rtcp:9 IN").is_err());
     assert!(parse_attribute("rtcp:9 IN IP4").is_err());
     assert!(parse_attribute("rtcp:9 IN IP4 ::1").is_err());
 }
 
 #[test]
 fn test_parse_attribute_rtcp_fb() {
-    assert!(parse_attribute("rtcp-fb:101 ccm fir").is_ok())
+    assert!(parse_attribute("rtcp-fb:101 ack rpsi").is_ok());
+    assert!(parse_attribute("rtcp-fb:101 ack app").is_ok());
+    assert!(parse_attribute("rtcp-fb:101 ccm").is_ok());
+    assert!(parse_attribute("rtcp-fb:101 ccm fir").is_ok());
+    assert!(parse_attribute("rtcp-fb:101 ccm tmmbr").is_ok());
+    assert!(parse_attribute("rtcp-fb:101 ccm tstr").is_ok());
+    assert!(parse_attribute("rtcp-fb:101 ccm vbcm").is_ok());
+    assert!(parse_attribute("rtcp-fb:101 nack").is_ok());
+    assert!(parse_attribute("rtcp-fb:101 nack sli").is_ok());
+    assert!(parse_attribute("rtcp-fb:101 nack pli").is_ok());
+    assert!(parse_attribute("rtcp-fb:101 nack rpsi").is_ok());
+    assert!(parse_attribute("rtcp-fb:101 nack app").is_ok());
+    assert!(parse_attribute("rtcp-fb:101 trr-int 1").is_ok());
+    assert!(parse_attribute("rtcp-fb:101 goog-remb").is_ok());
+    assert!(parse_attribute("rtcp-fb:101 transport-cc").is_ok());
+
+    assert!(parse_attribute("rtcp-fb:101 unknown").is_err());
+    assert!(parse_attribute("rtcp-fb:101 ack").is_err());
+    assert!(parse_attribute("rtcp-fb:101 ccm unknwon").is_err());
+    assert!(parse_attribute("rtcp-fb:101 nack unknown").is_err());
+    assert!(parse_attribute("rtcp-fb:101 trr-int").is_err());
+    assert!(parse_attribute("rtcp-fb:101 trr-int a").is_err());
+    assert!(parse_attribute("rtcp-fb:101 goog-remb unknown").is_err());
+    assert!(parse_attribute("rtcp-fb:101 transport-cc unknown").is_err());
 }
 
 #[test]
 fn test_parse_attribute_rtcp_mux() {
     assert!(parse_attribute("rtcp-mux").is_ok());
     assert!(parse_attribute("rtcp-mux foobar").is_err());
 }
 
--- a/media/webrtc/signaling/src/sdp/rsdparsa/src/lib.rs
+++ b/media/webrtc/signaling/src/sdp/rsdparsa/src/lib.rs
@@ -1,10 +1,12 @@
 #![cfg_attr(feature="clippy", feature(plugin))]
 
+#[macro_use]
+extern crate log;
 #[cfg(feature="serialize")]
 #[macro_use]
 extern crate serde_derive;
 #[cfg(feature="serialize")]
 extern crate serde;
 
 use std::net::IpAddr;
 use std::str::FromStr;
@@ -133,17 +135,17 @@ impl SdpSession {
     pub fn get_version(&self) -> u64 {
         self.version
     }
 
     pub fn get_origin(&self) -> &SdpOrigin {
         &self.origin
     }
 
-    pub fn get_session(&self) -> &String {
+    pub fn get_session(&self) -> &str {
         &self.session
     }
 
     pub fn get_connection(&self) -> &Option<SdpConnection> {
         &self.connection
     }
 
     pub fn set_connection(&mut self, c: &SdpConnection) {
@@ -165,32 +167,20 @@ impl SdpSession {
         };
         Ok(self.attribute.push(a.clone()))
     }
 
     pub fn extend_media(&mut self, v: Vec<SdpMedia>) {
         self.media.extend(v)
     }
 
-    pub fn has_timing(&self) -> bool {
-        self.timing.is_some()
-    }
-
-    pub fn has_attributes(&self) -> bool {
-        !self.attribute.is_empty()
-    }
-
     pub fn get_attribute(&self, t: SdpAttributeType) -> Option<&SdpAttribute> {
        self.attribute.iter().filter(|a| SdpAttributeType::from(*a) == t).next()
     }
 
-    pub fn has_media(&self) -> bool {
-        !self.media.is_empty()
-    }
-
     pub fn add_media(&mut self, media_type: SdpMediaValue, direction: SdpAttribute, port: u32,
                      protocol: SdpProtocolValue, addr: String)
                      -> Result<(),SdpParserInternalError> {
        let mut media = SdpMedia::new(SdpMediaLine {
            media: media_type,
            port,
            port_count: 1,
            proto: protocol,
@@ -207,33 +197,33 @@ impl SdpSession {
 
        self.media.push(media);
 
        Ok(())
     }
 }
 
 fn parse_session(value: &str) -> Result<SdpType, SdpParserInternalError> {
-    println!("session: {}", value);
+    trace!("session: {}", value);
     Ok(SdpType::Session(String::from(value)))
 }
 
 #[test]
 fn test_session_works() {
     assert!(parse_session("topic").is_ok());
 }
 
 
 fn parse_version(value: &str) -> Result<SdpType, SdpParserInternalError> {
     let ver = value.parse::<u64>()?;
     if ver != 0 {
         return Err(SdpParserInternalError::Generic(format!("version type contains unsupported value {}",
                                                            ver)));
     };
-    println!("version: {}", ver);
+    trace!("version: {}", ver);
     Ok(SdpType::Version(ver))
 }
 
 #[test]
 fn test_version_works() {
     assert!(parse_version("0").is_ok());
 }
 
@@ -295,17 +285,17 @@ fn parse_origin(value: &str) -> Result<S
                                                        .to_string()));
     }
     let o = SdpOrigin {
         username: String::from(username),
         session_id,
         session_version,
         unicast_addr,
     };
-    println!("{}", o);
+    trace!("origin: {}", o);
     Ok(SdpType::Origin(o))
 }
 
 #[test]
 fn test_origin_works() {
     assert!(parse_origin("mozilla 506705521068071134 0 IN IP4 0.0.0.0").is_ok());
     assert!(parse_origin("mozilla 506705521068071134 0 IN IP6 ::1").is_ok());
 }
@@ -357,17 +347,17 @@ fn parse_connection(value: &str) -> Resu
         addr_token = addr_tokens[0];
     }
     let addr = parse_unicast_addr(addr_token)?;
     if !addrtype.same_protocol(&addr) {
         return Err(SdpParserInternalError::Generic("connection addrtype does not match address."
                                                        .to_string()));
     }
     let c = SdpConnection { addr, ttl, amount };
-    println!("connection: {}", c.addr);
+    trace!("connection: {}", c.addr);
     Ok(SdpType::Connection(c))
 }
 
 #[test]
 fn connection_works() {
     assert!(parse_connection("IN IP4 127.0.0.1").is_ok());
     assert!(parse_connection("IN IP4 127.0.0.1/10/10").is_ok());
 }
@@ -412,17 +402,17 @@ fn parse_bandwidth(value: &str) -> Resul
     }
     let bandwidth = bv[1].parse::<u32>()?;
     let bw = match bv[0].to_uppercase().as_ref() {
         "AS" => SdpBandwidth::As(bandwidth),
         "CT" => SdpBandwidth::Ct(bandwidth),
         "TIAS" => SdpBandwidth::Tias(bandwidth),
         _ => SdpBandwidth::Unknown(String::from(bv[0]), bandwidth),
     };
-    println!("bandwidth: {}, {}", bv[0], bandwidth);
+    trace!("bandwidth: {}, {}", bv[0], bandwidth);
     Ok(SdpType::Bandwidth(bw))
 }
 
 #[test]
 fn bandwidth_works() {
     assert!(parse_bandwidth("AS:1").is_ok());
     assert!(parse_bandwidth("CT:123").is_ok());
     assert!(parse_bandwidth("TIAS:12345").is_ok());
@@ -443,17 +433,17 @@ fn parse_timing(value: &str) -> Result<S
     let tv: Vec<&str> = value.split_whitespace().collect();
     if tv.len() != 2 {
         return Err(SdpParserInternalError::Generic("timing attribute must have two tokens"
                                                        .to_string()));
     }
     let start = tv[0].parse::<u64>()?;
     let stop = tv[1].parse::<u64>()?;
     let t = SdpTiming { start, stop };
-    println!("timing: {}, {}", t.start, t.stop);
+    trace!("timing: {}, {}", t.start, t.stop);
     Ok(SdpType::Timing(t))
 }
 
 #[test]
 fn test_timing_works() {
     assert!(parse_timing("0 0").is_ok());
 }
 
@@ -621,33 +611,33 @@ fn test_parse_sdp_line_invalid_a_line() 
 }
 
 fn sanity_check_sdp_session(session: &SdpSession) -> Result<(), SdpParserError> {
     let make_error = |x: &str| SdpParserError::Sequence {
         message: x.to_string(),
         line_number: 0,
     };
 
-    if !session.has_timing() {
+    if !session.timing.is_some() {
         return Err(SdpParserError::Sequence {
                        message: "Missing timing type".to_string(),
                        line_number: 0,
                    });
     }
 
-    if !session.has_media() {
+    if session.media.is_empty() {
         return Err(SdpParserError::Sequence {
-                       message: "Missing media setion".to_string(),
+                       message: "Missing media section".to_string(),
                        line_number: 0,
                    });
     }
 
     if session.get_connection().is_none() {
         for msection in &session.media {
-            if !msection.has_connection() {
+            if msection.get_connection().is_none() {
                 return Err(SdpParserError::Sequence {
                     message: "Each media section must define a connection
                               if it is not defined on session level".to_string(),
                     line_number: 0,
                 });
             }
         }
     }
@@ -912,17 +902,17 @@ fn parse_sdp_vector(lines: &[SdpLine]) -
             SdpType::Email(_) |
             SdpType::Information(_) |
             SdpType::Key(_) |
             SdpType::Phone(_) |
             SdpType::Repeat(_) |
             SdpType::Uri(_) |
             SdpType::Zone(_) => (),
         };
-        if sdp_session.has_media() {
+        if !sdp_session.media.is_empty() {
             break;
         };
     }
     sanity_check_sdp_session(&sdp_session)?;
     Ok(sdp_session)
 }
 
 pub fn parse_sdp(sdp: &str, fail_on_warning: bool) -> Result<SdpSession, SdpParserError> {
@@ -1001,17 +991,17 @@ pub fn parse_sdp(sdp: &str, fail_on_warn
     if let Some(e) = errors.pop() {
         return Err(e);
     };
 
     let mut session = parse_sdp_vector(&sdp_lines)?;
     session.warnings = warnings;
 
     for warning in &session.warnings {
-        println!("Warning: {}", &warning);
+        warn!("Warning: {}", &warning);
     }
 
     Ok(session)
 }
 
 #[test]
 fn test_parse_sdp_zero_length_string_fails() {
     assert!(parse_sdp("", true).is_err());
--- a/media/webrtc/signaling/src/sdp/rsdparsa/src/media_type.rs
+++ b/media/webrtc/signaling/src/sdp/rsdparsa/src/media_type.rs
@@ -113,32 +113,24 @@ impl SdpMedia {
     pub fn get_proto(&self) -> &SdpProtocolValue {
         &self.media.proto
     }
 
     pub fn get_formats(&self) -> &SdpFormatList {
         &self.media.formats
     }
 
-    pub fn has_bandwidth(&self) -> bool {
-        !self.bandwidth.is_empty()
-    }
-
     pub fn get_bandwidth(&self) -> &Vec<SdpBandwidth> {
         &self.bandwidth
     }
 
     pub fn add_bandwidth(&mut self, bw: &SdpBandwidth) {
         self.bandwidth.push(bw.clone())
     }
 
-    pub fn has_attributes(&self) -> bool {
-        !self.attribute.is_empty()
-    }
-
     pub fn get_attributes(&self) -> &Vec<SdpAttribute> {
         &self.attribute
     }
 
     pub fn add_attribute(&mut self, attr: &SdpAttribute) -> Result<(), SdpParserInternalError> {
         if !attr.allowed_at_media_level() {
             return Err(SdpParserInternalError::Generic(format!("{} not allowed at media level",
                                                                attr)));
@@ -185,20 +177,16 @@ impl SdpMedia {
         self.add_attribute(&SdpAttribute::Rtpmap(rtpmap))?;
         Ok(())
     }
 
     pub fn get_attributes_of_type(&self, t: SdpAttributeType) -> Vec<&SdpAttribute> {
         self.attribute.iter().filter(|a| SdpAttributeType::from(*a) == t).collect()
     }
 
-    pub fn has_connection(&self) -> bool {
-        self.connection.is_some()
-    }
-
     pub fn get_connection(&self) -> &Option<SdpConnection> {
         &self.connection
     }
 
     pub fn set_connection(&mut self, c: &SdpConnection) -> Result<(), SdpParserInternalError> {
         if self.connection.is_some() {
             return Err(SdpParserInternalError::Generic("connection type already exists at this media level"
                                .to_string(),
@@ -367,17 +355,17 @@ pub fn parse_media(value: &str) -> Resul
     };
     let m = SdpMediaLine {
         media,
         port,
         port_count,
         proto,
         formats,
     };
-    println!("media: {}, {}, {}, {}", m.media, m.port, m.proto, m.formats);
+    trace!("media: {}, {}, {}, {}", m.media, m.port, m.proto, m.formats);
     Ok(SdpType::Media(m))
 }
 
 #[test]
 fn test_media_works() {
     assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 109").is_ok());
     assert!(parse_media("video 9 UDP/TLS/RTP/SAVPF 126").is_ok());
     assert!(parse_media("application 9 DTLS/SCTP 5000").is_ok());
@@ -494,9 +482,102 @@ pub fn parse_media_vector(lines: &[SdpLi
             SdpType::Key(_) => (),
         };
     }
 
     media_sections.push(sdp_media);
 
     Ok(media_sections)
 }
-// TODO add unit tests for parse_media_vector
+
+#[test]
+fn test_media_vector_first_line_failure() {
+    let mut sdp_lines: Vec<SdpLine> = Vec::new();
+    let line = SdpLine {
+        line_number: 0,
+        sdp_type: SdpType::Session("hello".to_string())
+    };
+    sdp_lines.push(line);
+    assert!(parse_media_vector(&sdp_lines).is_err());
+}
+
+#[test]
+fn test_media_vector_multiple_connections() {
+    let mut sdp_lines: Vec<SdpLine> = Vec::new();
+    let media_line = SdpMediaLine {
+        media: SdpMediaValue::Audio,
+        port: 9,
+        port_count: 0,
+        proto: SdpProtocolValue::RtpSavpf,
+        formats: SdpFormatList::Integers(Vec::new()),
+    };
+    let media = SdpLine {
+        line_number: 0,
+        sdp_type: SdpType::Media(media_line)
+    };
+    sdp_lines.push(media);
+    use network::{parse_unicast_addr};
+    let addr = parse_unicast_addr("127.0.0.1").unwrap();
+    let c = SdpConnection {
+        addr,
+        ttl: None,
+        amount: None };
+    let c1 = SdpLine {
+        line_number: 1,
+        sdp_type: SdpType::Connection(c.clone())
+    };
+    sdp_lines.push(c1);
+    let c2 = SdpLine {
+        line_number: 2,
+        sdp_type: SdpType::Connection(c)
+    };
+    sdp_lines.push(c2);
+    assert!(parse_media_vector(&sdp_lines).is_err());
+}
+
+#[test]
+fn test_media_vector_invalid_types() {
+    let mut sdp_lines: Vec<SdpLine> = Vec::new();
+    let media_line = SdpMediaLine {
+        media: SdpMediaValue::Audio,
+        port: 9,
+        port_count: 0,
+        proto: SdpProtocolValue::RtpSavpf,
+        formats: SdpFormatList::Integers(Vec::new()),
+    };
+    let media = SdpLine {
+        line_number: 0,
+        sdp_type: SdpType::Media(media_line)
+    };
+    sdp_lines.push(media);
+    use {SdpTiming};
+    let t = SdpTiming { start: 0, stop: 0 };
+    let tline = SdpLine {
+        line_number: 1,
+        sdp_type: SdpType::Timing(t)
+    };
+    sdp_lines.push(tline);
+    assert!(parse_media_vector(&sdp_lines).is_err());
+}
+
+#[test]
+fn test_media_vector_invalid_media_level_attribute() {
+    let mut sdp_lines: Vec<SdpLine> = Vec::new();
+    let media_line = SdpMediaLine {
+        media: SdpMediaValue::Audio,
+        port: 9,
+        port_count: 0,
+        proto: SdpProtocolValue::RtpSavpf,
+        formats: SdpFormatList::Integers(Vec::new()),
+    };
+    let media = SdpLine {
+        line_number: 0,
+        sdp_type: SdpType::Media(media_line)
+    };
+    sdp_lines.push(media);
+    let a = SdpAttribute::IceLite;
+    let aline = SdpLine {
+        line_number: 1,
+        sdp_type: SdpType::Attribute(a)
+    };
+    sdp_lines.push(aline);
+    assert!(parse_media_vector(&sdp_lines).is_err());
+}
--- a/media/webrtc/signaling/src/sdp/rsdparsa/tests/unit_tests.rs
+++ b/media/webrtc/signaling/src/sdp/rsdparsa/tests/unit_tests.rs
@@ -20,19 +20,18 @@ m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n";
     assert_eq!(sdp.media.len(), 1);
 
     let msection = &(sdp.media[0]);
     assert_eq!(*msection.get_type(),
                rsdparsa::media_type::SdpMediaValue::Audio);
     assert_eq!(msection.get_port(), 0);
     assert_eq!(*msection.get_proto(),
                rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf);
-    assert!(!msection.has_attributes());
-    assert!(!msection.has_bandwidth());
-    assert!(!msection.has_connection());
+    assert!(msection.get_attributes().is_empty());
+    assert!(msection.get_bandwidth().is_empty());
     assert!(msection.get_connection().is_none());
 }
 
 #[test]
 fn parse_minimal_sdp_with_emtpy_lines() {
     let sdp = "v=0\r\n
 \r\n
 o=- 0 0 IN IP4 0.0.0.0\r\n
@@ -68,16 +67,50 @@ m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n";
     assert!(sdp_opt.is_some());
     let sdp = sdp_opt.unwrap();
     assert_eq!(sdp.version, 0);
     assert_eq!(sdp.session, "-");
     assert!(sdp.get_connection().is_some());
 }
 
 #[test]
+fn parse_minimal_sdp_with_most_media_types() {
+    let sdp = "v=0\r\n
+o=- 0 0 IN IP4 0.0.0.0\r\n
+s=-\r\n
+t=0 0\r\n
+m=video 0 UDP/TLS/RTP/SAVPF 0\r\n
+b=AS:1\r\n
+b=CT:123\r\n
+b=TIAS:12345\r\n
+c=IN IP4 0.0.0.0\r\n
+a=sendrecv\r\n";
+    let sdp_res = rsdparsa::parse_sdp(sdp, false);
+    assert!(sdp_res.is_ok());
+    let sdp_opt = sdp_res.ok();
+    assert!(sdp_opt.is_some());
+    let sdp = sdp_opt.unwrap();
+    assert_eq!(sdp.version, 0);
+    assert_eq!(sdp.session, "-");
+    assert_eq!(sdp.attribute.len(), 0);
+    assert_eq!(sdp.media.len(), 1);
+
+    let msection = &(sdp.media[0]);
+    assert_eq!(*msection.get_type(),
+               rsdparsa::media_type::SdpMediaValue::Video);
+    assert_eq!(msection.get_port(), 0);
+    assert_eq!(*msection.get_proto(),
+               rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf);
+    assert!(!msection.get_bandwidth().is_empty());
+    assert!(!msection.get_connection().is_none());
+    assert!(!msection.get_attributes().is_empty());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sendrecv).is_some());
+}
+
+#[test]
 fn parse_firefox_audio_offer() {
     let sdp = "v=0\r\n
 o=mozilla...THIS_IS_SDPARTA-52.0a1 506705521068071134 0 IN IP4 0.0.0.0\r\n
 s=-\r\n
 t=0 0\r\n
 a=fingerprint:sha-256 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC:BF:2F:E3:91:CB:57:A9:9D:4A:A2:0B:40\r\n
 a=group:BUNDLE sdparta_0\r\n
 a=ice-options:trickle\r\n
@@ -107,20 +140,31 @@ a=ssrc:2655508255 cname:{735484ea-4f6c-f
     assert_eq!(sdp.media.len(), 1);
 
     let msection = &(sdp.media[0]);
     assert_eq!(*msection.get_type(),
                rsdparsa::media_type::SdpMediaValue::Audio);
     assert_eq!(msection.get_port(), 9);
     assert_eq!(*msection.get_proto(),
                rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf);
-    assert!(msection.has_attributes());
-    assert!(msection.has_connection());
     assert!(msection.get_connection().is_some());
-    assert!(!msection.has_bandwidth());
+    assert!(msection.get_bandwidth().is_empty());
+    assert!(!msection.get_attributes().is_empty());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sendrecv).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Extmap).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Fmtp).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IcePwd).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IceUfrag).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Msid).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::RtcpMux).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtpmap).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Setup).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Ssrc).is_some());
 }
 
 #[test]
 fn parse_firefox_video_offer() {
     let sdp = "v=0\r\n
 o=mozilla...THIS_IS_SDPARTA-52.0a1 506705521068071134 0 IN IP4 0.0.0.0\r\n
 s=-\r\n
 t=0 0\r\n
@@ -164,16 +208,32 @@ a=ssrc:2709871439 cname:{735484ea-4f6c-f
     assert_eq!(sdp.media.len(), 1);
 
     let msection = &(sdp.media[0]);
     assert_eq!(*msection.get_type(),
                rsdparsa::media_type::SdpMediaValue::Video);
     assert_eq!(msection.get_port(), 9);
     assert_eq!(*msection.get_proto(),
                rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf);
+    assert!(msection.get_connection().is_some());
+    assert!(msection.get_bandwidth().is_empty());
+    assert!(!msection.get_attributes().is_empty());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Recvonly).is_some());
+    assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Extmap).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Fmtp).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IcePwd).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IceUfrag).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some());
+    assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Msid).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtcpfb).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::RtcpMux).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtpmap).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Setup).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Ssrc).is_some());
 }
 
 #[test]
 fn parse_firefox_datachannel_offer() {
     let sdp = "v=0\r\n
 o=mozilla...THIS_IS_SDPARTA-52.0a2 3327975756663609975 0 IN IP4 0.0.0.0\r\n
 s=-\r\n
 t=0 0\r\n
@@ -201,16 +261,32 @@ a=ssrc:3376683177 cname:{62f78ee0-620f-a
     assert_eq!(sdp.media.len(), 1);
 
     let msection = &(sdp.media[0]);
     assert_eq!(*msection.get_type(),
                rsdparsa::media_type::SdpMediaValue::Application);
     assert_eq!(msection.get_port(), 49760);
     assert_eq!(*msection.get_proto(),
                rsdparsa::media_type::SdpProtocolValue::DtlsSctp);
+    assert!(msection.get_connection().is_some());
+    assert!(msection.get_bandwidth().is_empty());
+    assert!(!msection.get_attributes().is_empty());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sendrecv).is_some());
+    assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Extmap).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IcePwd).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IceUfrag).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::EndOfCandidates).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some());
+    assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Msid).is_some());
+    assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtcpfb).is_some());
+    assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::RtcpMux).is_some());
+    assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtpmap).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sctpmap).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Setup).is_some());
+    assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Ssrc).is_some());
 }
 
 #[test]
 fn parse_chrome_audio_video_offer() {
     let sdp = "v=0\r\n
 o=- 3836772544440436510 2 IN IP4 127.0.0.1\r\n
 s=-\r\n
 t=0 0\r\n
@@ -306,29 +382,29 @@ a=ssrc:2673335628 label:b6ec5178-c611-40
     assert_eq!(sdp.media.len(), 2);
 
     let msection1 = &(sdp.media[0]);
     assert_eq!(*msection1.get_type(),
                rsdparsa::media_type::SdpMediaValue::Audio);
     assert_eq!(msection1.get_port(), 9);
     assert_eq!(*msection1.get_proto(),
                rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf);
-    assert!(msection1.has_attributes());
-    assert!(msection1.has_connection());
-    assert!(!msection1.has_bandwidth());
+    assert!(!msection1.get_attributes().is_empty());
+    assert!(msection1.get_connection().is_some());
+    assert!(msection1.get_bandwidth().is_empty());
 
     let msection2 = &(sdp.media[1]);
     assert_eq!(*msection2.get_type(),
                rsdparsa::media_type::SdpMediaValue::Video);
     assert_eq!(msection2.get_port(), 9);
     assert_eq!(*msection2.get_proto(),
                rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf);
-    assert!(msection2.has_attributes());
-    assert!(msection2.has_connection());
-    assert!(!msection2.has_bandwidth());
+    assert!(!msection2.get_attributes().is_empty());
+    assert!(msection2.get_connection().is_some());
+    assert!(msection2.get_bandwidth().is_empty());
 }
 
 #[test]
 fn parse_firefox_simulcast_offer() {
     let sdp = "v=0\r\n
 o=mozilla...THIS_IS_SDPARTA-55.0a1 983028567300715536 0 IN IP4 0.0.0.0\r\n
 s=-\r\n
 t=0 0\r\n
--- a/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/lib.rs
+++ b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/lib.rs
@@ -104,17 +104,17 @@ pub unsafe extern "C" fn get_version(ses
 
 #[no_mangle]
 pub unsafe extern "C" fn sdp_get_origin(session: *const SdpSession) ->  RustSdpOrigin {
     origin_view_helper((*session).get_origin())
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn session_view(session: *const SdpSession) -> StringView {
-    StringView::from((*session).get_session().as_str())
+    StringView::from((*session).get_session())
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn sdp_session_has_connection(session: *const SdpSession) -> bool {
     (*session).connection.is_some()
 }
 
 #[no_mangle]
--- a/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/media_section.rs
+++ b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/media_section.rs
@@ -129,17 +129,17 @@ pub unsafe extern "C" fn sdp_get_media_b
 
 #[no_mangle]
 pub unsafe extern "C" fn sdp_get_media_bandwidth_vec(sdp_media: *const SdpMedia) -> *const Vec<SdpBandwidth> {
     (*sdp_media).get_bandwidth()
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn sdp_media_has_connection(sdp_media: *const SdpMedia) -> bool {
-    (*sdp_media).has_connection()
+    (*sdp_media).get_connection().is_some()
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn sdp_get_media_connection(sdp_media: *const SdpMedia, ret: *mut RustSdpConnection) -> nsresult {
     if let &Some(ref connection) = (*sdp_media).get_connection() {
         *ret = RustSdpConnection::from(connection);
         return NS_OK;
     }