diff options
Diffstat (limited to 'netwerk')
56 files changed, 778 insertions, 1451 deletions
diff --git a/netwerk/base/Dashboard.cpp b/netwerk/base/Dashboard.cpp index f5d0880ae..83da7d6a4 100644 --- a/netwerk/base/Dashboard.cpp +++ b/netwerk/base/Dashboard.cpp @@ -892,13 +892,15 @@ typedef struct #define ERROR(key, val) {key, #key} ErrorEntry socketTransportStatuses[] = { - ERROR(NS_NET_STATUS_RESOLVING_HOST, FAILURE(3)), - ERROR(NS_NET_STATUS_RESOLVED_HOST, FAILURE(11)), - ERROR(NS_NET_STATUS_CONNECTING_TO, FAILURE(7)), - ERROR(NS_NET_STATUS_CONNECTED_TO, FAILURE(4)), - ERROR(NS_NET_STATUS_SENDING_TO, FAILURE(5)), - ERROR(NS_NET_STATUS_WAITING_FOR, FAILURE(10)), - ERROR(NS_NET_STATUS_RECEIVING_FROM, FAILURE(6)), + ERROR(NS_NET_STATUS_RESOLVING_HOST, FAILURE(3)), + ERROR(NS_NET_STATUS_RESOLVED_HOST, FAILURE(11)), + ERROR(NS_NET_STATUS_CONNECTING_TO, FAILURE(7)), + ERROR(NS_NET_STATUS_CONNECTED_TO, FAILURE(4)), + ERROR(NS_NET_STATUS_TLS_HANDSHAKE_STARTING, FAILURE(12)), + ERROR(NS_NET_STATUS_TLS_HANDSHAKE_ENDED, FAILURE(13)), + ERROR(NS_NET_STATUS_SENDING_TO, FAILURE(5)), + ERROR(NS_NET_STATUS_WAITING_FOR, FAILURE(10)), + ERROR(NS_NET_STATUS_RECEIVING_FROM, FAILURE(6)), }; #undef ERROR diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp index 216cf559c..42fdea4a1 100644 --- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp @@ -859,6 +859,12 @@ LoadInfo::SetIsPreflight() mIsPreflight = true; } +void +LoadInfo::SetUpgradeInsecureRequests() +{ + mUpgradeInsecureRequests = true; +} + NS_IMETHODIMP LoadInfo::GetIsPreflight(bool* aIsPreflight) { diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h index 261f85349..3e1b92ff4 100644 --- a/netwerk/base/LoadInfo.h +++ b/netwerk/base/LoadInfo.h @@ -78,6 +78,7 @@ public: already_AddRefed<nsILoadInfo> CloneForNewRequest() const; void SetIsPreflight(); + void SetUpgradeInsecureRequests(); private: // private constructor that is only allowed to be called from within diff --git a/netwerk/base/nsICryptoHash.idl b/netwerk/base/nsICryptoHash.idl index cd865a3a9..ddd3103af 100644 --- a/netwerk/base/nsICryptoHash.idl +++ b/netwerk/base/nsICryptoHash.idl @@ -10,7 +10,7 @@ interface nsIInputStream; * This interface provides crytographic hashing algorithms. */ -[scriptable, uuid(1e5b7c43-4688-45ce-92e1-77ed931e3bbe)] +[scriptable, uuid(0a248513-dfa7-4474-8777-8c452d60dd04)] interface nsICryptoHash : nsISupports { /** @@ -25,6 +25,7 @@ interface nsICryptoHash : nsISupports const short SHA256 = 4; /* String value: "sha256" */ const short SHA384 = 5; /* String value: "sha384" */ const short SHA512 = 6; /* String value: "sha512" */ + const short SHA224 = 7; /* String value: "sha224" */ /** * Initialize the hashing object. This method may be diff --git a/netwerk/base/nsISocketTransport.idl b/netwerk/base/nsISocketTransport.idl index 6395d6b5f..9b5bc23fb 100644 --- a/netwerk/base/nsISocketTransport.idl +++ b/netwerk/base/nsISocketTransport.idl @@ -162,6 +162,8 @@ interface nsISocketTransport : nsITransport const unsigned long STATUS_SENDING_TO = 0x804b0005; const unsigned long STATUS_WAITING_FOR = 0x804b000a; const unsigned long STATUS_RECEIVING_FROM = 0x804b0006; + const unsigned long STATUS_TLS_HANDSHAKE_STARTING = 0x804b000c; + const unsigned long STATUS_TLS_HANDSHAKE_ENDED = 0x804b000d; /** * connectionFlags is a bitmask that can be used to modify underlying diff --git a/netwerk/base/nsITimedChannel.idl b/netwerk/base/nsITimedChannel.idl index 6ec2d1ff8..13b65e7b8 100644 --- a/netwerk/base/nsITimedChannel.idl +++ b/netwerk/base/nsITimedChannel.idl @@ -31,6 +31,7 @@ interface nsITimedChannel : nsISupports { [noscript] readonly attribute TimeStamp domainLookupStart; [noscript] readonly attribute TimeStamp domainLookupEnd; [noscript] readonly attribute TimeStamp connectStart; + [noscript] readonly attribute TimeStamp secureConnectionStart; [noscript] readonly attribute TimeStamp connectEnd; [noscript] readonly attribute TimeStamp requestStart; [noscript] readonly attribute TimeStamp responseStart; @@ -69,6 +70,7 @@ interface nsITimedChannel : nsISupports { readonly attribute PRTime domainLookupStartTime; readonly attribute PRTime domainLookupEndTime; readonly attribute PRTime connectStartTime; + readonly attribute PRTime secureConnectionStartTime; readonly attribute PRTime connectEndTime; readonly attribute PRTime requestStartTime; readonly attribute PRTime responseStartTime; diff --git a/netwerk/base/nsLoadGroup.cpp b/netwerk/base/nsLoadGroup.cpp index 3b8cf4434..7b75f7942 100644 --- a/netwerk/base/nsLoadGroup.cpp +++ b/netwerk/base/nsLoadGroup.cpp @@ -888,6 +888,11 @@ nsLoadGroup::TelemetryReportChannel(nsITimedChannel *aTimedChannel, if (NS_FAILED(rv)) return; + TimeStamp secureConnectionStart; + rv = aTimedChannel->GetSecureConnectionStart(&secureConnectionStart); + if (NS_FAILED(rv)) + return; + TimeStamp connectEnd; rv = aTimedChannel->GetConnectEnd(&connectEnd); if (NS_FAILED(rv)) @@ -921,9 +926,15 @@ nsLoadGroup::TelemetryReportChannel(nsITimedChannel *aTimedChannel, domainLookupStart, domainLookupEnd); \ } \ \ + if (!secureConnectionStart.IsNull() && !connectEnd.IsNull()) { \ + Telemetry::AccumulateTimeDelta( \ + Telemetry::HTTP_##prefix##_TLS_HANDSHAKE, \ + secureConnectionStart, connectEnd); \ + } \ + \ if (!connectStart.IsNull() && !connectEnd.IsNull()) { \ Telemetry::AccumulateTimeDelta( \ - Telemetry::HTTP_##prefix##_TCP_CONNECTION, \ + Telemetry::HTTP_##prefix##_TCP_CONNECTION_2, \ connectStart, connectEnd); \ } \ \ diff --git a/netwerk/base/nsSocketTransport2.cpp b/netwerk/base/nsSocketTransport2.cpp index 1bfd1fc91..184757d33 100644 --- a/netwerk/base/nsSocketTransport2.cpp +++ b/netwerk/base/nsSocketTransport2.cpp @@ -40,7 +40,6 @@ #include "xpcpublic.h" #if defined(XP_WIN) -#include "mozilla/WindowsVersion.h" #include "ShutdownLayer.h" #endif @@ -1724,21 +1723,6 @@ nsSocketTransport::OnSocketConnected() NS_ASSERTION(mFDref == 1, "wrong socket ref count"); SetSocketName(mFD); mFDconnected = true; - -#ifdef XP_WIN - if (!IsWin2003OrLater()) { // windows xp - PRSocketOptionData opt; - opt.option = PR_SockOpt_RecvBufferSize; - if (PR_GetSocketOption(mFD, &opt) == PR_SUCCESS) { - SOCKET_LOG(("%p checking rwin on xp originally=%u\n", - this, opt.value.recv_buffer_size)); - if (opt.value.recv_buffer_size < 65535) { - opt.value.recv_buffer_size = 65535; - PR_SetSocketOption(mFD, &opt); - } - } - } -#endif } // Ensure keepalive is configured correctly if previously enabled. diff --git a/netwerk/base/nsSocketTransportService2.cpp b/netwerk/base/nsSocketTransportService2.cpp index d2f20651e..068bf0eca 100644 --- a/netwerk/base/nsSocketTransportService2.cpp +++ b/netwerk/base/nsSocketTransportService2.cpp @@ -28,10 +28,6 @@ #include "nsIWidget.h" #include "mozilla/dom/FlyWebService.h" -#if defined(XP_WIN) -#include "mozilla/WindowsVersion.h" -#endif - namespace mozilla { namespace net { @@ -1204,12 +1200,7 @@ nsSocketTransportService::UpdateSendBufferPref(nsIPrefBranch *pref) } #if defined(XP_WIN) - // If the pref is not set but this is windows set it depending on windows version - if (!IsWin2003OrLater()) { // windows xp - mSendBufferSize = 131072; - } else { // vista or later - mSendBufferSize = 131072 * 4; - } + mSendBufferSize = 131072 * 4; #endif } diff --git a/netwerk/base/nsStandardURL.cpp b/netwerk/base/nsStandardURL.cpp index 922d8a3ba..bc1350f28 100644 --- a/netwerk/base/nsStandardURL.cpp +++ b/netwerk/base/nsStandardURL.cpp @@ -65,19 +65,6 @@ static LazyLogModule gStandardURLLog("nsStandardURL"); //---------------------------------------------------------------------------- -#ifdef MOZ_RUST_URLPARSE -extern "C" int32_t c_fn_set_size(void * container, size_t size) -{ - ((nsACString *) container)->SetLength(size); - return 0; -} - -extern "C" char * c_fn_get_buffer(void * container) -{ - return ((nsACString *) container)->BeginWriting(); -} -#endif - static nsresult EncodeString(nsIUnicodeEncoder *encoder, const nsAFlatString &str, nsACString &result) { diff --git a/netwerk/base/rust-url-capi/.gitignore b/netwerk/base/rust-url-capi/.gitignore deleted file mode 100644 index 4fffb2f89..000000000 --- a/netwerk/base/rust-url-capi/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -/Cargo.lock diff --git a/netwerk/base/rust-url-capi/Cargo.toml b/netwerk/base/rust-url-capi/Cargo.toml deleted file mode 100644 index ecdb53058..000000000 --- a/netwerk/base/rust-url-capi/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] - -name = "rust_url_capi" -version = "0.0.1" -authors = ["Valentin Gosu <valentin.gosu@gmail.com>"] - -[profile.dev] -opt-level = 3 -debug = true -rpath = true -lto = true - -[lib] -name = "rust_url_capi" - - -[dependencies] -libc = "0.2.0" -url = "1.2.1" diff --git a/netwerk/base/rust-url-capi/src/error_mapping.rs b/netwerk/base/rust-url-capi/src/error_mapping.rs deleted file mode 100644 index f20afb263..000000000 --- a/netwerk/base/rust-url-capi/src/error_mapping.rs +++ /dev/null @@ -1,68 +0,0 @@ -use url::ParseError; - -pub trait ErrorCode { - fn error_code(&self) -> i32; -} - -impl<T: ErrorCode> ErrorCode for Result<(), T> { - fn error_code(&self) -> i32 { - match *self { - Ok(_) => 0, - Err(ref error) => error.error_code(), - } - } -} - -impl ErrorCode for () { - fn error_code(&self) -> i32 { - return -1; - } -} -impl ErrorCode for ParseError { - fn error_code(&self) -> i32 { - return -1; -// match *self { -// ParseError::EmptyHost => -1, -// ParseError::InvalidScheme => -2, -// ParseError::InvalidPort => -3, -// ParseError::InvalidIpv6Address => -4, -// ParseError::InvalidDomainCharacter => -5, -// ParseError::InvalidCharacter => -6, -// ParseError::InvalidBackslash => -7, -// ParseError::InvalidPercentEncoded => -8, -// ParseError::InvalidAtSymbolInUser => -9, -// ParseError::ExpectedTwoSlashes => -10, -// ParseError::ExpectedInitialSlash => -11, -// ParseError::NonUrlCodePoint => -12, -// ParseError::RelativeUrlWithScheme => -13, -// ParseError::RelativeUrlWithoutBase => -14, -// ParseError::RelativeUrlWithNonRelativeBase => -15, -// ParseError::NonAsciiDomainsNotSupportedYet => -16, -// ParseError::CannotSetJavascriptFragment => -17, -// ParseError::CannotSetPortWithFileLikeScheme => -18, -// ParseError::CannotSetUsernameWithNonRelativeScheme => -19, -// ParseError::CannotSetPasswordWithNonRelativeScheme => -20, -// ParseError::CannotSetHostPortWithNonRelativeScheme => -21, -// ParseError::CannotSetHostWithNonRelativeScheme => -22, -// ParseError::CannotSetPortWithNonRelativeScheme => -23, -// ParseError::CannotSetPathWithNonRelativeScheme => -24, -// } - } -} - -pub enum NSError { - OK, - InvalidArg, - Failure, -} - -impl ErrorCode for NSError { - #[allow(overflowing_literals)] - fn error_code(&self) -> i32 { - match *self { - NSError::OK => 0, - NSError::InvalidArg => 0x80070057, - NSError::Failure => 0x80004005 - } - } -} diff --git a/netwerk/base/rust-url-capi/src/lib.rs b/netwerk/base/rust-url-capi/src/lib.rs deleted file mode 100644 index e2997ce46..000000000 --- a/netwerk/base/rust-url-capi/src/lib.rs +++ /dev/null @@ -1,477 +0,0 @@ -extern crate url; -use url::{Url, ParseError, ParseOptions}; -use url::quirks; -extern crate libc; -use libc::size_t; - - -use std::mem; -use std::str; - -#[allow(non_camel_case_types)] -pub type rusturl_ptr = *const libc::c_void; - -mod string_utils; -pub use string_utils::*; - -mod error_mapping; -use error_mapping::*; - -fn parser<'a>() -> ParseOptions<'a> { - Url::options() -} - -fn default_port(scheme: &str) -> Option<u32> { - match scheme { - "ftp" => Some(21), - "gopher" => Some(70), - "http" => Some(80), - "https" => Some(443), - "ws" => Some(80), - "wss" => Some(443), - "rtsp" => Some(443), - "moz-anno" => Some(443), - "android" => Some(443), - _ => None, - } -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_new(spec: *mut libc::c_char, len: size_t) -> rusturl_ptr { - let slice = std::slice::from_raw_parts(spec as *const libc::c_uchar, len as usize); - let url_spec = match str::from_utf8(slice) { - Ok(spec) => spec, - Err(_) => return 0 as rusturl_ptr - }; - - let url = match parser().parse(url_spec) { - Ok(url) => url, - Err(_) => return 0 as rusturl_ptr - }; - - let url = Box::new(url); - Box::into_raw(url) as rusturl_ptr -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_free(urlptr: rusturl_ptr) { - if urlptr.is_null() { - return (); - } - let url: Box<Url> = Box::from_raw(urlptr as *mut url::Url); - drop(url); -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_get_spec(urlptr: rusturl_ptr, cont: *mut libc::c_void) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let url: &Url = mem::transmute(urlptr); - cont.assign(&url.to_string()) -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_get_scheme(urlptr: rusturl_ptr, cont: *mut libc::c_void) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let url: &Url = mem::transmute(urlptr); - cont.assign(&url.scheme()) -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_get_username(urlptr: rusturl_ptr, cont: *mut libc::c_void) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let url: &Url = mem::transmute(urlptr); - if url.cannot_be_a_base() { - cont.set_size(0) - } else { - cont.assign(url.username()) - } -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_get_password(urlptr: rusturl_ptr, cont: *mut libc::c_void) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let url: &Url = mem::transmute(urlptr); - match url.password() { - Some(p) => cont.assign(&p.to_string()), - None => cont.set_size(0) - } -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_get_host(urlptr: rusturl_ptr, cont: *mut libc::c_void) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let url: &Url = mem::transmute(urlptr); - - match url.host() { - Some(h) => cont.assign(&h.to_string()), - None => cont.set_size(0) - } -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_get_port(urlptr: rusturl_ptr) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let url: &Url = mem::transmute(urlptr); - - match url.port() { - Some(port) => port as i32, - None => -1 - } -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_get_path(urlptr: rusturl_ptr, cont: *mut libc::c_void) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let url: &Url = mem::transmute(urlptr); - if url.cannot_be_a_base() { - cont.set_size(0) - } else { - cont.assign(url.path()) - } -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_get_query(urlptr: rusturl_ptr, cont: *mut libc::c_void) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let url: &Url = mem::transmute(urlptr); - match url.query() { - Some(ref s) => cont.assign(s), - None => cont.set_size(0) - } -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_get_fragment(urlptr: rusturl_ptr, cont: *mut libc::c_void) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let url: &Url = mem::transmute(urlptr); - - match url.fragment() { - Some(ref fragment) => cont.assign(fragment), - None => cont.set_size(0) - } -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_has_fragment(urlptr: rusturl_ptr) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let url: &Url = mem::transmute(urlptr); - - match url.fragment() { - Some(_) => return 1, - None => return 0 - } -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_set_scheme(urlptr: rusturl_ptr, scheme: *mut libc::c_char, len: size_t) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let mut url: &mut Url = mem::transmute(urlptr); - let slice = std::slice::from_raw_parts(scheme as *const libc::c_uchar, len as usize); - - let scheme_ = match str::from_utf8(slice).ok() { - Some(p) => p, - None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed - }; - - quirks::set_protocol(url, scheme_).error_code() -} - - -#[no_mangle] -pub unsafe extern "C" fn rusturl_set_username(urlptr: rusturl_ptr, username: *mut libc::c_char, len: size_t) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let mut url: &mut Url = mem::transmute(urlptr); - let slice = std::slice::from_raw_parts(username as *const libc::c_uchar, len as usize); - - let username_ = match str::from_utf8(slice).ok() { - Some(p) => p, - None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed - }; - - quirks::set_username(url, username_).error_code() -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_set_password(urlptr: rusturl_ptr, password: *mut libc::c_char, len: size_t) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let mut url: &mut Url = mem::transmute(urlptr); - let slice = std::slice::from_raw_parts(password as *const libc::c_uchar, len as usize); - - let password_ = match str::from_utf8(slice).ok() { - Some(p) => p, - None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed - }; - - quirks::set_password(url, password_).error_code() -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_set_host_and_port(urlptr: rusturl_ptr, host_and_port: *mut libc::c_char, len: size_t) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let mut url: &mut Url = mem::transmute(urlptr); - let slice = std::slice::from_raw_parts(host_and_port as *const libc::c_uchar, len as usize); - - let host_and_port_ = match str::from_utf8(slice).ok() { - Some(p) => p, - None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed - }; - - quirks::set_host(url, host_and_port_).error_code() -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_set_host(urlptr: rusturl_ptr, host: *mut libc::c_char, len: size_t) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let mut url: &mut Url = mem::transmute(urlptr); - let slice = std::slice::from_raw_parts(host as *const libc::c_uchar, len as usize); - - let hostname = match str::from_utf8(slice).ok() { - Some(h) => h, - None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed - }; - - quirks::set_hostname(url, hostname).error_code() -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_set_port(urlptr: rusturl_ptr, port: *mut libc::c_char, len: size_t) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let mut url: &mut Url = mem::transmute(urlptr); - let slice = std::slice::from_raw_parts(port as *const libc::c_uchar, len as usize); - - let port_ = match str::from_utf8(slice).ok() { - Some(p) => p, - None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed - }; - - quirks::set_port(url, port_).error_code() -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_set_port_no(urlptr: rusturl_ptr, new_port: i32) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let mut url: &mut Url = mem::transmute(urlptr); - if url.cannot_be_a_base() { - -100 - } else { - if url.scheme() == "file" { - return -100; - } - match default_port(url.scheme()) { - Some(def_port) => if new_port == def_port as i32 { - let _ = url.set_port(None); - return NSError::OK.error_code(); - }, - None => {} - }; - if new_port > std::u16::MAX as i32 || new_port < 0 { - let _ = url.set_port(None); - } else { - let _ = url.set_port(Some(new_port as u16)); - } - NSError::OK.error_code() - } -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_set_path(urlptr: rusturl_ptr, path: *mut libc::c_char, len: size_t) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let mut url: &mut Url = mem::transmute(urlptr); - let slice = std::slice::from_raw_parts(path as *const libc::c_uchar, len as usize); - - let path_ = match str::from_utf8(slice).ok() { - Some(p) => p, - None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed - }; - - quirks::set_pathname(url, path_).error_code() -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_set_query(urlptr: rusturl_ptr, query: *mut libc::c_char, len: size_t) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let mut url: &mut Url = mem::transmute(urlptr); - let slice = std::slice::from_raw_parts(query as *const libc::c_uchar, len as usize); - - let query_ = match str::from_utf8(slice).ok() { - Some(p) => p, - None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed - }; - - quirks::set_search(url, query_).error_code() -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_set_fragment(urlptr: rusturl_ptr, fragment: *mut libc::c_char, len: size_t) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let mut url: &mut Url = mem::transmute(urlptr); - let slice = std::slice::from_raw_parts(fragment as *const libc::c_uchar, len as usize); - - let fragment_ = match str::from_utf8(slice).ok() { - Some(p) => p, - None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed - }; - - quirks::set_hash(url, fragment_).error_code() -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_resolve(urlptr: rusturl_ptr, resolve: *mut libc::c_char, len: size_t, cont: *mut libc::c_void) -> i32 { - if urlptr.is_null() { - return NSError::InvalidArg.error_code(); - } - let url: &mut Url = mem::transmute(urlptr); - - let slice = std::slice::from_raw_parts(resolve as *const libc::c_uchar, len as usize); - - let resolve_ = match str::from_utf8(slice).ok() { - Some(p) => p, - None => return NSError::Failure.error_code() - }; - - match parser().base_url(Some(&url)).parse(resolve_).ok() { - Some(u) => cont.assign(&u.to_string()), - None => cont.set_size(0) - } -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_common_base_spec(urlptr1: rusturl_ptr, urlptr2: rusturl_ptr, cont: *mut libc::c_void) -> i32 { - if urlptr1.is_null() || urlptr2.is_null() { - return NSError::InvalidArg.error_code(); - } - let url1: &Url = mem::transmute(urlptr1); - let url2: &Url = mem::transmute(urlptr2); - - if url1 == url2 { - return cont.assign(&url1.to_string()); - } - - if url1.scheme() != url2.scheme() || - url1.host() != url2.host() || - url1.username() != url2.username() || - url1.password() != url2.password() || - url1.port() != url2.port() { - return cont.set_size(0); - } - - let path1 = match url1.path_segments() { - Some(path) => path, - None => return cont.set_size(0) - }; - let path2 = match url2.path_segments() { - Some(path) => path, - None => return cont.set_size(0) - }; - - let mut url = url1.clone(); - url.set_query(None); - let _ = url.set_host(None); - { - let mut new_segments = if let Ok(segments) = url.path_segments_mut() { - segments - } else { - return cont.set_size(0) - }; - - for (p1, p2) in path1.zip(path2) { - if p1 != p2 { - break; - } else { - new_segments.push(p1); - } - } - } - - cont.assign(&url.to_string()) -} - -#[no_mangle] -pub unsafe extern "C" fn rusturl_relative_spec(urlptr1: rusturl_ptr, urlptr2: rusturl_ptr, cont: *mut libc::c_void) -> i32 { - if urlptr1.is_null() || urlptr2.is_null() { - return NSError::InvalidArg.error_code(); - } - let url1: &Url = mem::transmute(urlptr1); - let url2: &Url = mem::transmute(urlptr2); - - if url1 == url2 { - return cont.set_size(0); - } - - if url1.scheme() != url2.scheme() || - url1.host() != url2.host() || - url1.username() != url2.username() || - url1.password() != url2.password() || - url1.port() != url2.port() { - return cont.assign(&url2.to_string()); - } - - let mut path1 = match url1.path_segments() { - Some(path) => path, - None => return cont.assign(&url2.to_string()) - }; - let mut path2 = match url2.path_segments() { - Some(path) => path, - None => return cont.assign(&url2.to_string()) - }; - - // TODO: file:// on WIN? - - // Exhaust the part of the iterators that match - while let (Some(ref p1), Some(ref p2)) = (path1.next(), path2.next()) { - if p1 != p2 { - break; - } - } - - let mut buffer: String = "".to_string(); - for _ in path1 { - buffer = buffer + "../"; - } - for p2 in path2 { - buffer = buffer + p2 + "/"; - } - - return cont.assign(&buffer); -} - diff --git a/netwerk/base/rust-url-capi/src/rust-url-capi.h b/netwerk/base/rust-url-capi/src/rust-url-capi.h deleted file mode 100644 index 8d7a05aed..000000000 --- a/netwerk/base/rust-url-capi/src/rust-url-capi.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef __RUST_URL_CAPI -#define __RUST_URL_CAPI -#include <stdlib.h> - -#ifdef __cplusplus -extern "C" { -#endif - -struct rusturl; -typedef struct rusturl* rusturl_ptr; - -rusturl_ptr rusturl_new(const char *spec, size_t src_len); -void rusturl_free(rusturl_ptr url); - -int32_t rusturl_get_spec(rusturl_ptr url, void*); -int32_t rusturl_get_scheme(rusturl_ptr url, void*); -int32_t rusturl_get_username(rusturl_ptr url, void*); -int32_t rusturl_get_password(rusturl_ptr url, void*); -int32_t rusturl_get_host(rusturl_ptr url, void*); -int32_t rusturl_get_port(rusturl_ptr url); // returns port or -1 -int32_t rusturl_get_path(rusturl_ptr url, void*); -int32_t rusturl_get_query(rusturl_ptr url, void*); -int32_t rusturl_get_fragment(rusturl_ptr url, void*); -int32_t rusturl_has_fragment(rusturl_ptr url); // 1 true, 0 false, < 0 error - -int32_t rusturl_set_scheme(rusturl_ptr url, const char *scheme, size_t len); -int32_t rusturl_set_username(rusturl_ptr url, const char *user, size_t len); -int32_t rusturl_set_password(rusturl_ptr url, const char *pass, size_t len); -int32_t rusturl_set_host_and_port(rusturl_ptr url, const char *hostport, size_t len); -int32_t rusturl_set_host(rusturl_ptr url, const char *host, size_t len); -int32_t rusturl_set_port(rusturl_ptr url, const char *port, size_t len); -int32_t rusturl_set_port_no(rusturl_ptr url, const int32_t port); -int32_t rusturl_set_path(rusturl_ptr url, const char *path, size_t len); -int32_t rusturl_set_query(rusturl_ptr url, const char *path, size_t len); -int32_t rusturl_set_fragment(rusturl_ptr url, const char *path, size_t len); - -int32_t rusturl_resolve(rusturl_ptr url, const char *relative, size_t len, void*); -int32_t rusturl_common_base_spec(rusturl_ptr url1, rusturl_ptr url2, void*); -int32_t rusturl_relative_spec(rusturl_ptr url1, rusturl_ptr url2, void*); - -#ifdef __cplusplus -} -#endif - -#endif // __RUST_URL_CAPI
\ No newline at end of file diff --git a/netwerk/base/rust-url-capi/src/string_utils.rs b/netwerk/base/rust-url-capi/src/string_utils.rs deleted file mode 100644 index ae68a60dc..000000000 --- a/netwerk/base/rust-url-capi/src/string_utils.rs +++ /dev/null @@ -1,57 +0,0 @@ -extern crate libc; -use libc::size_t; - -extern crate std; -use std::ptr; - -use error_mapping::*; - -extern "C" { - fn c_fn_set_size(user: *mut libc::c_void, size: size_t) -> i32; - fn c_fn_get_buffer(user: *mut libc::c_void) -> *mut libc::c_char; -} - -pub trait StringContainer { - fn set_size(&self, size_t) -> i32; - fn get_buffer(&self) -> *mut libc::c_char; - fn assign(&self, content: &str) -> i32; -} - -impl StringContainer for *mut libc::c_void { - fn set_size(&self, size: size_t) -> i32 { - if (*self).is_null() { - return NSError::InvalidArg.error_code(); - } - unsafe { - c_fn_set_size(*self, size); - } - - return NSError::OK.error_code(); - } - fn get_buffer(&self) -> *mut libc::c_char { - if (*self).is_null() { - return 0 as *mut libc::c_char; - } - unsafe { - c_fn_get_buffer(*self) - } - } - fn assign(&self, content: &str) -> i32 { - if (*self).is_null() { - return NSError::InvalidArg.error_code(); - } - - unsafe { - let slice = content.as_bytes(); - c_fn_set_size(*self, slice.len()); - let buf = c_fn_get_buffer(*self); - if buf.is_null() { - return NSError::Failure.error_code(); - } - - ptr::copy(slice.as_ptr(), buf as *mut u8, slice.len()); - } - - NSError::OK.error_code() - } -} diff --git a/netwerk/base/rust-url-capi/test/Makefile b/netwerk/base/rust-url-capi/test/Makefile deleted file mode 100644 index a4e2fd0cf..000000000 --- a/netwerk/base/rust-url-capi/test/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -all: - cd .. && cargo build - g++ -Wall -o test test.cpp ../target/debug/librust*.a -ldl -lpthread -lrt -lgcc_s -lpthread -lc -lm -std=c++0x - ./test diff --git a/netwerk/base/rust-url-capi/test/test.cpp b/netwerk/base/rust-url-capi/test/test.cpp deleted file mode 100644 index 6e90ea43b..000000000 --- a/netwerk/base/rust-url-capi/test/test.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include "../src/rust-url-capi.h" - -class StringContainer -{ -public: - StringContainer() - { - mBuffer = nullptr; - mLength = 0; - } - - ~StringContainer() - { - free(mBuffer); - mBuffer = nullptr; - } - - void SetSize(size_t size) - { - mLength = size; - if (mBuffer) { - mBuffer = (char *)realloc(mBuffer, size); - return; - } - mBuffer = (char *)malloc(size); - } - - char * GetBuffer() - { - return mBuffer; - } - - void CheckEquals(const char * ref) { - int32_t refLen = strlen(ref); - printf("CheckEquals: %s (len:%d)\n", ref, refLen); - if (refLen != mLength || strncmp(mBuffer, ref, mLength)) { - printf("\t--- ERROR ---\n"); - printf("Got : "); - fwrite(mBuffer, mLength, 1, stdout); - printf(" (len:%d)\n", mLength); - exit(-1); - } - printf("-> OK\n"); - } -private: - int32_t mLength; - char * mBuffer; -}; - -extern "C" int32_t c_fn_set_size(void * container, size_t size) -{ - ((StringContainer *) container)->SetSize(size); - return 0; -} - -extern "C" char * c_fn_get_buffer(void * container) -{ - return ((StringContainer *) container)->GetBuffer(); -} - -#define TEST_CALL(func, expected) \ -{ \ - int32_t code = func; \ - printf("%s -> code %d\n", #func, code); \ - assert(code == expected); \ - printf("-> OK\n"); \ -} \ - - -int main() { - // Create URL - rusturl_ptr url = rusturl_new("http://example.com/path/some/file.txt", - strlen("http://example.com/path/some/file.txt")); - assert(url); // Check we have a URL - - StringContainer container; - - TEST_CALL(rusturl_get_spec(url, &container), 0); - container.CheckEquals("http://example.com/path/some/file.txt"); - TEST_CALL(rusturl_set_host(url, "test.com", strlen("test.com")), 0); - TEST_CALL(rusturl_get_host(url, &container), 0); - container.CheckEquals("test.com"); - TEST_CALL(rusturl_get_path(url, &container), 0); - container.CheckEquals("/path/some/file.txt"); - TEST_CALL(rusturl_set_path(url, "hello/../else.txt", strlen("hello/../else.txt")), 0); - TEST_CALL(rusturl_get_path(url, &container), 0); - container.CheckEquals("/else.txt"); - TEST_CALL(rusturl_resolve(url, "./bla/file.txt", strlen("./bla/file.txt"), &container), 0); - container.CheckEquals("http://test.com/bla/file.txt"); - TEST_CALL(rusturl_get_scheme(url, &container), 0); - container.CheckEquals("http"); - TEST_CALL(rusturl_set_username(url, "user", strlen("user")), 0); - TEST_CALL(rusturl_get_username(url, &container), 0); - container.CheckEquals("user"); - TEST_CALL(rusturl_get_spec(url, &container), 0); - container.CheckEquals("http://user@test.com/else.txt"); - TEST_CALL(rusturl_set_password(url, "pass", strlen("pass")), 0); - TEST_CALL(rusturl_get_password(url, &container), 0); - container.CheckEquals("pass"); - TEST_CALL(rusturl_get_spec(url, &container), 0); - container.CheckEquals("http://user:pass@test.com/else.txt"); - TEST_CALL(rusturl_set_username(url, "", strlen("")), 0); - TEST_CALL(rusturl_set_password(url, "", strlen("")), 0); - TEST_CALL(rusturl_get_spec(url, &container), 0); - container.CheckEquals("http://test.com/else.txt"); - TEST_CALL(rusturl_set_host_and_port(url, "example.org:1234", strlen("example.org:1234")), 0); - TEST_CALL(rusturl_get_host(url, &container), 0); - container.CheckEquals("example.org"); - assert(rusturl_get_port(url) == 1234); - TEST_CALL(rusturl_set_port(url, "9090", strlen("9090")), 0); - assert(rusturl_get_port(url) == 9090); - TEST_CALL(rusturl_set_query(url, "x=1", strlen("x=1")), 0); - TEST_CALL(rusturl_get_query(url, &container), 0); - container.CheckEquals("x=1"); - TEST_CALL(rusturl_set_fragment(url, "fragment", strlen("fragment")), 0); - TEST_CALL(rusturl_get_fragment(url, &container), 0); - container.CheckEquals("fragment"); - TEST_CALL(rusturl_get_spec(url, &container), 0); - container.CheckEquals("http://example.org:9090/else.txt?x=1#fragment"); - - // Free the URL - rusturl_free(url); - - url = rusturl_new("http://example.com/#", - strlen("http://example.com/#")); - assert(url); // Check we have a URL - - assert(rusturl_has_fragment(url) == 1); - TEST_CALL(rusturl_set_fragment(url, "", 0), 0); - assert(rusturl_has_fragment(url) == 0); - TEST_CALL(rusturl_get_spec(url, &container), 0); - container.CheckEquals("http://example.com/"); - - rusturl_free(url); - - printf("SUCCESS\n"); - return 0; -}
\ No newline at end of file diff --git a/netwerk/base/security-prefs.js b/netwerk/base/security-prefs.js index 329a4c6b7..d1b56ce35 100644 --- a/netwerk/base/security-prefs.js +++ b/netwerk/base/security-prefs.js @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ pref("security.tls.version.min", 1); -pref("security.tls.version.max", 3); +pref("security.tls.version.max", 4); pref("security.tls.version.fallback-limit", 3); pref("security.tls.insecure_fallback_hosts", ""); pref("security.tls.unrestricted_rc4_fallback", false); diff --git a/netwerk/ipc/NeckoMessageUtils.h b/netwerk/ipc/NeckoMessageUtils.h index 273f049a2..1633b82b6 100644 --- a/netwerk/ipc/NeckoMessageUtils.h +++ b/netwerk/ipc/NeckoMessageUtils.h @@ -14,11 +14,6 @@ #include "mozilla/net/DNS.h" #include "TimingStruct.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#include "nsPrintfCString.h" -#endif - namespace IPC { // nsIPermissionManager utilities @@ -102,12 +97,6 @@ struct ParamTraits<mozilla::net::NetAddr> aMsg->WriteBytes(aParam.local.path, sizeof(aParam.local.path)); #endif } else { -#ifdef MOZ_CRASHREPORTER - if (XRE_IsParentProcess()) { - nsPrintfCString msg("%d", aParam.raw.family); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Unknown NetAddr socket family"), msg); - } -#endif NS_RUNTIMEABORT("Unknown socket family"); } } @@ -147,6 +136,7 @@ struct ParamTraits<mozilla::net::ResourceTimingStruct> WriteParam(aMsg, aParam.domainLookupStart); WriteParam(aMsg, aParam.domainLookupEnd); WriteParam(aMsg, aParam.connectStart); + WriteParam(aMsg, aParam.secureConnectionStart); WriteParam(aMsg, aParam.connectEnd); WriteParam(aMsg, aParam.requestStart); WriteParam(aMsg, aParam.responseStart); @@ -169,6 +159,7 @@ struct ParamTraits<mozilla::net::ResourceTimingStruct> return ReadParam(aMsg, aIter, &aResult->domainLookupStart) && ReadParam(aMsg, aIter, &aResult->domainLookupEnd) && ReadParam(aMsg, aIter, &aResult->connectStart) && + ReadParam(aMsg, aIter, &aResult->secureConnectionStart) && ReadParam(aMsg, aIter, &aResult->connectEnd) && ReadParam(aMsg, aIter, &aResult->requestStart) && ReadParam(aMsg, aIter, &aResult->responseStart) && diff --git a/netwerk/locales/en-US/necko.properties b/netwerk/locales/en-US/necko.properties index 60607241d..0c39bc433 100644 --- a/netwerk/locales/en-US/necko.properties +++ b/netwerk/locales/en-US/necko.properties @@ -17,6 +17,8 @@ 9=Wrote %1$S 10=Waiting for %1$S… 11=Looked up %1$S… +12=Performing a TLS handshake to %1$S… +13=The TLS handshake finished for %1$S… 27=Beginning FTP transaction… 28=Finished FTP transaction diff --git a/netwerk/protocol/ftp/nsFtpConnectionThread.cpp b/netwerk/protocol/ftp/nsFtpConnectionThread.cpp index d428b093c..1119fcff5 100644 --- a/netwerk/protocol/ftp/nsFtpConnectionThread.cpp +++ b/netwerk/protocol/ftp/nsFtpConnectionThread.cpp @@ -2028,6 +2028,8 @@ nsFtpState::OnTransportStatus(nsITransport *transport, nsresult status, case NS_NET_STATUS_RESOLVED_HOST: case NS_NET_STATUS_CONNECTING_TO: case NS_NET_STATUS_CONNECTED_TO: + case NS_NET_STATUS_TLS_HANDSHAKE_STARTING: + case NS_NET_STATUS_TLS_HANDSHAKE_ENDED: break; default: return NS_OK; diff --git a/netwerk/protocol/http/ASpdySession.cpp b/netwerk/protocol/http/ASpdySession.cpp index 6bd54c7c0..f22c326d1 100644 --- a/netwerk/protocol/http/ASpdySession.cpp +++ b/netwerk/protocol/http/ASpdySession.cpp @@ -32,7 +32,8 @@ ASpdySession::~ASpdySession() = default; ASpdySession * ASpdySession::NewSpdySession(uint32_t version, - nsISocketTransport *aTransport) + nsISocketTransport *aTransport, + bool attemptingEarlyData) { // This is a necko only interface, so we can enforce version // requests as a precondition @@ -46,7 +47,7 @@ ASpdySession::NewSpdySession(uint32_t version, Telemetry::Accumulate(Telemetry::SPDY_VERSION2, version); - return new Http2Session(aTransport, version); + return new Http2Session(aTransport, version, attemptingEarlyData); } SpdyInformation::SpdyInformation() diff --git a/netwerk/protocol/http/ASpdySession.h b/netwerk/protocol/http/ASpdySession.h index e116d423b..a3db61d15 100644 --- a/netwerk/protocol/http/ASpdySession.h +++ b/netwerk/protocol/http/ASpdySession.h @@ -28,8 +28,9 @@ public: virtual PRIntervalTime IdleTime() = 0; virtual uint32_t ReadTimeoutTick(PRIntervalTime now) = 0; virtual void DontReuse() = 0; + virtual uint32_t SpdyVersion() = 0; - static ASpdySession *NewSpdySession(uint32_t version, nsISocketTransport *); + static ASpdySession *NewSpdySession(uint32_t version, nsISocketTransport *, bool); // MaybeReTunnel() is called by the connection manager when it cannot // dispatch a tunneled transaction. That might be because the tunnels it diff --git a/netwerk/protocol/http/Http2Session.cpp b/netwerk/protocol/http/Http2Session.cpp index a2721017d..4f350af83 100644 --- a/netwerk/protocol/http/Http2Session.cpp +++ b/netwerk/protocol/http/Http2Session.cpp @@ -64,7 +64,7 @@ do { \ return NS_ERROR_ILLEGAL_VALUE; \ } while (0) -Http2Session::Http2Session(nsISocketTransport *aSocketTransport, uint32_t version) +Http2Session::Http2Session(nsISocketTransport *aSocketTransport, uint32_t version, bool attemptingEarlyData) : mSocketTransport(aSocketTransport) , mSegmentReader(nullptr) , mSegmentWriter(nullptr) @@ -112,6 +112,7 @@ Http2Session::Http2Session(nsISocketTransport *aSocketTransport, uint32_t versio , mWaitingForSettingsAck(false) , mGoAwayOnPush(false) , mUseH2Deps(false) + , mAttemptingEarlyData(attemptingEarlyData) { MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); @@ -501,6 +502,12 @@ Http2Session::SetWriteCallbacks() void Http2Session::RealignOutputQueue() { + if (mAttemptingEarlyData) { + // We can't realign right now, because we may need what's in there if early + // data fails. + return; + } + mOutputQueueUsed -= mOutputQueueSent; memmove(mOutputQueueBuffer.get(), mOutputQueueBuffer.get() + mOutputQueueSent, @@ -518,6 +525,14 @@ Http2Session::FlushOutputQueue() uint32_t countRead; uint32_t avail = mOutputQueueUsed - mOutputQueueSent; + if (!avail && mAttemptingEarlyData) { + // This is kind of a hack, but there are cases where we'll have already + // written the data we want whlie doing early data, but we get called again + // with a reader, and we need to avoid calling the reader when there's + // nothing for it to read. + return; + } + rv = mSegmentReader-> OnReadSegment(mOutputQueueBuffer.get() + mOutputQueueSent, avail, &countRead); @@ -528,14 +543,18 @@ Http2Session::FlushOutputQueue() if (NS_FAILED(rv)) return; + mOutputQueueSent += countRead; + + if (mAttemptingEarlyData) { + return; + } + if (countRead == avail) { mOutputQueueUsed = 0; mOutputQueueSent = 0; return; } - mOutputQueueSent += countRead; - // If the output queue is close to filling up and we have sent out a good // chunk of data from the beginning then realign it. @@ -555,6 +574,12 @@ Http2Session::DontReuse() } uint32_t +Http2Session::SpdyVersion() +{ + return HTTP_VERSION_2; +} + +uint32_t Http2Session::GetWriteQueueSize() { MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); @@ -1019,6 +1044,15 @@ Http2Session::CleanupStream(Http2Stream *aStream, nsresult aResult, return; } + Http2PushedStream *pushSource = aStream->PushSource(); + if (pushSource) { + // aStream is a synthetic attached to an even push + MOZ_ASSERT(pushSource->GetConsumerStream() == aStream); + MOZ_ASSERT(!aStream->StreamID()); + MOZ_ASSERT(!(pushSource->StreamID() & 0x1)); + aStream->ClearPushSource(); + } + if (aStream->DeferCleanup(aResult)) { LOG3(("Http2Session::CleanupStream 0x%X deferred\n", aStream->StreamID())); return; @@ -1029,15 +1063,6 @@ Http2Session::CleanupStream(Http2Stream *aStream, nsresult aResult, return; } - Http2PushedStream *pushSource = aStream->PushSource(); - if (pushSource) { - // aStream is a synthetic attached to an even push - MOZ_ASSERT(pushSource->GetConsumerStream() == aStream); - MOZ_ASSERT(!aStream->StreamID()); - MOZ_ASSERT(!(pushSource->StreamID() & 0x1)); - pushSource->SetConsumerStream(nullptr); - } - // don't reset a stream that has recevied a fin or rst if (!aStream->RecvdFin() && !aStream->RecvdReset() && aStream->StreamID() && !(mInputFrameFinal && (aStream == mInputFrameDataStream))) { // !(recvdfin with mark pending) @@ -2248,8 +2273,19 @@ Http2Session::OnTransportStatus(nsITransport* aTransport, case NS_NET_STATUS_RESOLVED_HOST: case NS_NET_STATUS_CONNECTING_TO: case NS_NET_STATUS_CONNECTED_TO: + case NS_NET_STATUS_TLS_HANDSHAKE_STARTING: + case NS_NET_STATUS_TLS_HANDSHAKE_ENDED: { Http2Stream *target = mStreamIDHash.Get(1); + if (!target) { + // any transaction will do if we can't find the low numbered one + // generally this happens when the initial transaction hasn't been + // assigned a stream id yet. + auto iter = mStreamTransactionHash.Iter(); + if (!iter.Done()) { + target = iter.Data(); + } + } nsAHttpTransaction *transaction = target ? target->Transaction() : nullptr; if (transaction) transaction->OnTransportStatus(aTransport, aStatus, aProgress); @@ -2320,9 +2356,44 @@ Http2Session::ReadSegmentsAgain(nsAHttpSegmentReader *reader, if (!stream) { LOG3(("Http2Session %p could not identify a stream to write; suspending.", this)); + uint32_t availBeforeFlush = mOutputQueueUsed - mOutputQueueSent; FlushOutputQueue(); + uint32_t availAfterFlush = mOutputQueueUsed - mOutputQueueSent; + if (availBeforeFlush != availAfterFlush) { + LOG3(("Http2Session %p ResumeRecv After early flush in ReadSegments", this)); + Unused << ResumeRecv(); + } SetWriteCallbacks(); - return NS_BASE_STREAM_WOULD_BLOCK; + if (mAttemptingEarlyData) { + // We can still try to send our preamble as early-data + *countRead = mOutputQueueUsed - mOutputQueueSent; + } + return *countRead ? NS_OK : NS_BASE_STREAM_WOULD_BLOCK; + } + + uint32_t earlyDataUsed = 0; + if (mAttemptingEarlyData) { + if (!stream->Do0RTT()) { + LOG3(("Http2Session %p will not get early data from Http2Stream %p 0x%X", + this, stream, stream->StreamID())); + FlushOutputQueue(); + SetWriteCallbacks(); + // We can still send our preamble + *countRead = mOutputQueueUsed - mOutputQueueSent; + return *countRead ? NS_OK : NS_BASE_STREAM_WOULD_BLOCK; + } + + if (!m0RTTStreams.Contains(stream->StreamID())) { + m0RTTStreams.AppendElement(stream->StreamID()); + } + + // Need to adjust this to only take as much as we can fit in with the + // preamble/settings/priority stuff + count -= (mOutputQueueUsed - mOutputQueueSent); + + // Keep track of this to add it into countRead later, as + // stream->ReadSegments will likely change the value of mOutputQueueUsed. + earlyDataUsed = mOutputQueueUsed - mOutputQueueSent; } LOG3(("Http2Session %p will write from Http2Stream %p 0x%X " @@ -2331,6 +2402,13 @@ Http2Session::ReadSegmentsAgain(nsAHttpSegmentReader *reader, rv = stream->ReadSegments(this, count, countRead); + if (earlyDataUsed) { + // Do this here because countRead could get reset somewhere down the rabbit + // hole of stream->ReadSegments, and we want to make sure we return the + // proper value to our caller. + *countRead += earlyDataUsed; + } + // Not every permutation of stream->ReadSegents produces data (and therefore // tries to flush the output queue) - SENDING_FIN_STREAM can be an example // of that. But we might still have old data buffered that would be good @@ -2887,6 +2965,58 @@ Http2Session::WriteSegments(nsAHttpSegmentWriter *writer, } nsresult +Http2Session::Finish0RTT(bool aRestart, bool aAlpnChanged) +{ + MOZ_ASSERT(mAttemptingEarlyData); + LOG3(("Http2Session::Finish0RTT %p aRestart=%d aAlpnChanged=%d", this, + aRestart, aAlpnChanged)); + + for (size_t i = 0; i < m0RTTStreams.Length(); ++i) { + // Instead of passing (aRestart, aAlpnChanged) here, we use aAlpnChanged for + // both arguments because as long as the alpn token stayed the same, we can + // just reuse what we have in our buffer to send instead of having to have + // the transaction rewind and read it all over again. We only need to rewind + // the transaction if we're switching to a new protocol, because our buffer + // won't get used in that case. + Http2Stream *stream = mStreamIDHash.Get(m0RTTStreams[i]); + if (stream) { + stream->Finish0RTT(aAlpnChanged, aAlpnChanged); + } + } + + if (aRestart) { + // 0RTT failed + if (aAlpnChanged) { + // This is a slightly more involved case - we need to get all our streams/ + // transactions back in the queue so they can restart as http/1 + + // These must be set this way to ensure we gracefully restart all streams + mGoAwayID = 0; + mCleanShutdown = true; + + // Close takes care of the rest of our work for us. The reason code here + // doesn't matter, as we aren't actually going to send a GOAWAY frame, but + // we use NS_ERROR_NET_RESET as it's closest to the truth. + Close(NS_ERROR_NET_RESET); + } else { + // This is the easy case - early data failed, but we're speaking h2, so + // we just need to rewind to the beginning of the preamble and try again. + mOutputQueueSent = 0; + } + } else { + // 0RTT succeeded + // Make sure we look for any incoming data in repsonse to our early data. + ResumeRecv(); + } + + mAttemptingEarlyData = false; + m0RTTStreams.Clear(); + RealignOutputQueue(); + + return NS_OK; +} + +nsresult Http2Session::ProcessConnectedPush(Http2Stream *pushConnectedStream, nsAHttpSegmentWriter * writer, uint32_t count, uint32_t *countWritten) @@ -3094,7 +3224,9 @@ Http2Session::Close(nsresult aReason) } else { goAwayReason = INTERNAL_ERROR; } - GenerateGoAway(goAwayReason); + if (!mAttemptingEarlyData) { + GenerateGoAway(goAwayReason); + } mConnection = nullptr; mSegmentReader = nullptr; mSegmentWriter = nullptr; @@ -3144,7 +3276,7 @@ Http2Session::OnReadSegment(const char *buf, // If we can release old queued data then we can try and write the new // data directly to the network without using the output queue at all - if (mOutputQueueUsed) + if (mOutputQueueUsed && !mAttemptingEarlyData) FlushOutputQueue(); if (!mOutputQueueUsed && mSegmentReader) { @@ -3515,12 +3647,18 @@ Http2Session::ALPNCallback(nsISupports *securityInfo) nsresult Http2Session::ConfirmTLSProfile() { - if (mTLSProfileConfirmed) + if (mTLSProfileConfirmed) { return NS_OK; + } LOG3(("Http2Session::ConfirmTLSProfile %p mConnection=%p\n", this, mConnection.get())); + if (mAttemptingEarlyData) { + LOG3(("Http2Session::ConfirmTLSProfile %p temporarily passing due to early data\n", this)); + return NS_OK; + } + if (!gHttpHandler->EnforceHttp2TlsProfile()) { LOG3(("Http2Session::ConfirmTLSProfile %p passed due to configuration bypass\n", this)); mTLSProfileConfirmed = true; diff --git a/netwerk/protocol/http/Http2Session.h b/netwerk/protocol/http/Http2Session.h index 60986381b..b4ddeb5ec 100644 --- a/netwerk/protocol/http/Http2Session.h +++ b/netwerk/protocol/http/Http2Session.h @@ -43,12 +43,13 @@ public: NS_DECL_NSAHTTPSEGMENTREADER NS_DECL_NSAHTTPSEGMENTWRITER - Http2Session(nsISocketTransport *, uint32_t version); + Http2Session(nsISocketTransport *, uint32_t version, bool attemptingEarlyData); bool AddStream(nsAHttpTransaction *, int32_t, bool, nsIInterfaceRequestor *) override; bool CanReuse() override { return !mShouldGoAway && !mClosed; } bool RoomForMoreStreams() override; + uint32_t SpdyVersion() override; // When the connection is active this is called up to once every 1 second // return the interval (in seconds) that the connection next wants to @@ -235,6 +236,8 @@ public: // overload of nsAHttpTransaction nsresult ReadSegmentsAgain(nsAHttpSegmentReader *, uint32_t, uint32_t *, bool *) override final; nsresult WriteSegmentsAgain(nsAHttpSegmentWriter *, uint32_t , uint32_t *, bool *) override final; + bool Do0RTT() override final { return true; } + nsresult Finish0RTT(bool aRestart, bool aAlpnChanged) override final; private: @@ -492,6 +495,10 @@ private: bool mUseH2Deps; + bool mAttemptingEarlyData; + // The ID(s) of the stream(s) that we are getting 0RTT data from. + nsTArray<uint32_t> m0RTTStreams; + private: /// connect tunnels void DispatchOnTunnel(nsAHttpTransaction *, nsIInterfaceRequestor *); diff --git a/netwerk/protocol/http/Http2Stream.cpp b/netwerk/protocol/http/Http2Stream.cpp index 5c562557c..7a8f96855 100644 --- a/netwerk/protocol/http/Http2Stream.cpp +++ b/netwerk/protocol/http/Http2Stream.cpp @@ -70,6 +70,7 @@ Http2Stream::Http2Stream(nsAHttpTransaction *httpTransaction, , mTotalSent(0) , mTotalRead(0) , mPushSource(nullptr) + , mAttempting0RTT(false) , mIsTunnel(false) , mPlainTextTunnel(false) { @@ -102,10 +103,20 @@ Http2Stream::Http2Stream(nsAHttpTransaction *httpTransaction, Http2Stream::~Http2Stream() { + ClearPushSource(); ClearTransactionsBlockedOnTunnel(); mStreamID = Http2Session::kDeadStreamID; } +void +Http2Stream::ClearPushSource() +{ + if (mPushSource) { + mPushSource->SetConsumerStream(nullptr); + mPushSource = nullptr; + } +} + // ReadSegments() is used to write data down the socket. Generally, HTTP // request data is pulled from the approriate transaction and // converted to HTTP/2 data. Sometimes control data like a window-update is @@ -925,7 +936,9 @@ Http2Stream::TransmitFrame(const char *buf, *countUsed += mTxStreamFrameSize; } - mSession->FlushOutputQueue(); + if (!mAttempting0RTT) { + mSession->FlushOutputQueue(); + } // calling this will trigger waiting_for if mRequestBodyLenRemaining is 0 UpdateTransportSendEvents(mTxInlineFrameUsed + mTxStreamFrameSize); @@ -1080,6 +1093,10 @@ Http2Stream::ConvertPushHeaders(Http2Decompressor *decompressor, void Http2Stream::Close(nsresult reason) { + // In case we are connected to a push, make sure the push knows we are closed, + // so it doesn't try to give us any more DATA that comes on it after our close. + ClearPushSource(); + mTransaction->Close(reason); } @@ -1468,5 +1485,26 @@ Http2Stream::MapStreamToHttpConnection() mTransaction->ConnectionInfo()); } +// ----------------------------------------------------------------------------- +// mirror nsAHttpTransaction +// ----------------------------------------------------------------------------- + +bool +Http2Stream::Do0RTT() +{ + MOZ_ASSERT(mTransaction); + mAttempting0RTT = true; + return mTransaction->Do0RTT(); +} + +nsresult +Http2Stream::Finish0RTT(bool aRestart, bool aAlpnChanged) +{ + MOZ_ASSERT(mTransaction); + mAttempting0RTT = false; + return mTransaction->Finish0RTT(aRestart, aAlpnChanged); +} + + } // namespace net } // namespace mozilla diff --git a/netwerk/protocol/http/Http2Stream.h b/netwerk/protocol/http/Http2Stream.h index 452db5fe0..8783eefed 100644 --- a/netwerk/protocol/http/Http2Stream.h +++ b/netwerk/protocol/http/Http2Stream.h @@ -50,6 +50,7 @@ public: uint32_t StreamID() { return mStreamID; } Http2PushedStream *PushSource() { return mPushSource; } + void ClearPushSource(); stateType HTTPState() { return mState; } void SetHTTPState(stateType val) { mState = val; } @@ -154,6 +155,10 @@ public: const nsACString &origin, RefPtr<nsStandardURL> &url); + // Mirrors nsAHttpTransaction + bool Do0RTT(); + nsresult Finish0RTT(bool aRestart, bool aAlpnIgnored); + protected: static void CreatePushHashKey(const nsCString &scheme, const nsCString &hostHeader, @@ -328,6 +333,8 @@ private: // and flow control has not yet kicked in. SimpleBuffer mSimpleBuffer; + bool mAttempting0RTT; + /// connect tunnels public: bool IsTunnel() { return mIsTunnel; } diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index 66252b82f..278c94db0 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -2480,9 +2480,9 @@ HttpBaseChannel::GetFetchCacheMode(uint32_t* aFetchCacheMode) *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_RELOAD; } else if (mLoadFlags & VALIDATE_ALWAYS) { *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_NO_CACHE; - } else if (mLoadFlags & (LOAD_FROM_CACHE | nsICachingChannel::LOAD_ONLY_FROM_CACHE)) { + } else if (mLoadFlags & (VALIDATE_NEVER | nsICachingChannel::LOAD_ONLY_FROM_CACHE)) { *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_ONLY_IF_CACHED; - } else if (mLoadFlags & LOAD_FROM_CACHE) { + } else if (mLoadFlags & VALIDATE_NEVER) { *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_FORCE_CACHE; } else { *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_DEFAULT; @@ -2518,7 +2518,7 @@ HttpBaseChannel::SetFetchCacheMode(uint32_t aFetchCacheMode) break; case nsIHttpChannelInternal::FETCH_CACHE_MODE_FORCE_CACHE: // force-cache means don't validate unless if the response would vary. - mLoadFlags |= LOAD_FROM_CACHE; + mLoadFlags |= VALIDATE_NEVER; break; case nsIHttpChannelInternal::FETCH_CACHE_MODE_ONLY_IF_CACHED: // only-if-cached means only from cache, no network, no validation, generate @@ -2527,7 +2527,7 @@ HttpBaseChannel::SetFetchCacheMode(uint32_t aFetchCacheMode) // the user has things in their cache without any network traffic side // effects) are addressed in the Request constructor which enforces/requires // same-origin request mode. - mLoadFlags |= LOAD_FROM_CACHE | nsICachingChannel::LOAD_ONLY_FROM_CACHE; + mLoadFlags |= VALIDATE_NEVER | nsICachingChannel::LOAD_ONLY_FROM_CACHE; break; } @@ -3449,6 +3449,12 @@ HttpBaseChannel::GetConnectStart(TimeStamp* _retval) { } NS_IMETHODIMP +HttpBaseChannel::GetSecureConnectionStart(TimeStamp* _retval) { + *_retval = mTransactionTimings.secureConnectionStart; + return NS_OK; +} + +NS_IMETHODIMP HttpBaseChannel::GetConnectEnd(TimeStamp* _retval) { *_retval = mTransactionTimings.connectEnd; return NS_OK; @@ -3517,6 +3523,7 @@ IMPL_TIMING_ATTR(AsyncOpen) IMPL_TIMING_ATTR(DomainLookupStart) IMPL_TIMING_ATTR(DomainLookupEnd) IMPL_TIMING_ATTR(ConnectStart) +IMPL_TIMING_ATTR(SecureConnectionStart) IMPL_TIMING_ATTR(ConnectEnd) IMPL_TIMING_ATTR(RequestStart) IMPL_TIMING_ATTR(ResponseStart) diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index 0de6095e1..f0b9e2136 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -893,6 +893,7 @@ HttpChannelChild::OnStopRequest(const nsresult& channelStatus, mTransactionTimings.domainLookupStart = timing.domainLookupStart; mTransactionTimings.domainLookupEnd = timing.domainLookupEnd; mTransactionTimings.connectStart = timing.connectStart; + mTransactionTimings.secureConnectionStart = timing.secureConnectionStart; mTransactionTimings.connectEnd = timing.connectEnd; mTransactionTimings.requestStart = timing.requestStart; mTransactionTimings.responseStart = timing.responseStart; diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index 51da1ec8c..5f0859f28 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -1216,6 +1216,7 @@ HttpChannelParent::OnStopRequest(nsIRequest *aRequest, mChannel->GetDomainLookupStart(&timing.domainLookupStart); mChannel->GetDomainLookupEnd(&timing.domainLookupEnd); mChannel->GetConnectStart(&timing.connectStart); + mChannel->GetSecureConnectionStart(&timing.secureConnectionStart); mChannel->GetConnectEnd(&timing.connectEnd); mChannel->GetRequestStart(&timing.requestStart); mChannel->GetResponseStart(&timing.responseStart); @@ -1771,8 +1772,8 @@ HttpChannelParent::UpdateAndSerializeSecurityInfo(nsACString& aSerializedSecurit bool HttpChannelParent::DoSendDeleteSelf() { - bool rv = SendDeleteSelf(); mIPCClosed = true; + bool rv = SendDeleteSelf(); return rv; } diff --git a/netwerk/protocol/http/HttpChannelParent.h b/netwerk/protocol/http/HttpChannelParent.h index 51fae5a82..a3b377d49 100644 --- a/netwerk/protocol/http/HttpChannelParent.h +++ b/netwerk/protocol/http/HttpChannelParent.h @@ -209,7 +209,7 @@ private: RefPtr<nsHttpChannel> mChannel; nsCOMPtr<nsICacheEntry> mCacheEntry; nsCOMPtr<nsIAssociatedContentSecurity> mAssociatedContentSecurity; - bool mIPCClosed; // PHttpChannel actor has been Closed() + Atomic<bool> mIPCClosed; // PHttpChannel actor has been Closed() nsCOMPtr<nsIChannel> mRedirectChannel; nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback; diff --git a/netwerk/protocol/http/NullHttpChannel.cpp b/netwerk/protocol/http/NullHttpChannel.cpp index 8c048a6b5..61efe3956 100644 --- a/netwerk/protocol/http/NullHttpChannel.cpp +++ b/netwerk/protocol/http/NullHttpChannel.cpp @@ -586,6 +586,13 @@ NullHttpChannel::GetConnectStart(mozilla::TimeStamp *aConnectStart) } NS_IMETHODIMP +NullHttpChannel::GetSecureConnectionStart(mozilla::TimeStamp *aSecureConnectionStart) +{ + *aSecureConnectionStart = mAsyncOpenTime; + return NS_OK; +} + +NS_IMETHODIMP NullHttpChannel::GetConnectEnd(mozilla::TimeStamp *aConnectEnd) { *aConnectEnd = mAsyncOpenTime; @@ -757,6 +764,7 @@ IMPL_TIMING_ATTR(AsyncOpen) IMPL_TIMING_ATTR(DomainLookupStart) IMPL_TIMING_ATTR(DomainLookupEnd) IMPL_TIMING_ATTR(ConnectStart) +IMPL_TIMING_ATTR(SecureConnectionStart) IMPL_TIMING_ATTR(ConnectEnd) IMPL_TIMING_ATTR(RequestStart) IMPL_TIMING_ATTR(ResponseStart) diff --git a/netwerk/protocol/http/NullHttpTransaction.cpp b/netwerk/protocol/http/NullHttpTransaction.cpp index 965ffcc2c..bb32a8098 100644 --- a/netwerk/protocol/http/NullHttpTransaction.cpp +++ b/netwerk/protocol/http/NullHttpTransaction.cpp @@ -162,6 +162,30 @@ void NullHttpTransaction::OnTransportStatus(nsITransport* transport, nsresult status, int64_t progress) { + if (status == NS_NET_STATUS_RESOLVING_HOST) { + if (mTimings.domainLookupStart.IsNull()) { + mTimings.domainLookupStart = TimeStamp::Now(); + } + } else if (status == NS_NET_STATUS_RESOLVED_HOST) { + if (mTimings.domainLookupEnd.IsNull()) { + mTimings.domainLookupEnd = TimeStamp::Now(); + } + } else if (status == NS_NET_STATUS_CONNECTING_TO) { + if (mTimings.connectStart.IsNull()) { + mTimings.connectStart = TimeStamp::Now(); + } + } else if (status == NS_NET_STATUS_CONNECTED_TO) { + if (mTimings.connectEnd.IsNull()) { + mTimings.connectEnd = TimeStamp::Now(); + } + } else if (status == NS_NET_STATUS_TLS_HANDSHAKE_ENDED) { + if (mTimings.secureConnectionStart.IsNull() && + !mTimings.connectEnd.IsNull()) { + mTimings.secureConnectionStart = mTimings.connectEnd; + } + mTimings.connectEnd = TimeStamp::Now();; + } + if (mActivityDistributor) { NS_DispatchToMainThread(new CallObserveActivity(mActivityDistributor, mConnectionInfo->GetOrigin(), diff --git a/netwerk/protocol/http/NullHttpTransaction.h b/netwerk/protocol/http/NullHttpTransaction.h index 04f80a9b3..b613ecfba 100644 --- a/netwerk/protocol/http/NullHttpTransaction.h +++ b/netwerk/protocol/http/NullHttpTransaction.h @@ -9,6 +9,7 @@ #include "nsAHttpTransaction.h" #include "mozilla/Attributes.h" +#include "TimingStruct.h" // This is the minimal nsAHttpTransaction implementation. A NullHttpTransaction // can be used to drive connection level semantics (such as SSL handshakes @@ -49,6 +50,8 @@ public: return PR_SecondsToInterval(15); } + TimingStruct Timings() { return mTimings; } + protected: virtual ~NullHttpTransaction(); @@ -68,6 +71,7 @@ private: Atomic<uint32_t> mCapsToClear; bool mIsDone; bool mClaimed; + TimingStruct mTimings; protected: RefPtr<nsAHttpConnection> mConnection; diff --git a/netwerk/protocol/http/TimingStruct.h b/netwerk/protocol/http/TimingStruct.h index b177eee8e..19133c311 100644 --- a/netwerk/protocol/http/TimingStruct.h +++ b/netwerk/protocol/http/TimingStruct.h @@ -14,6 +14,7 @@ struct TimingStruct { TimeStamp domainLookupStart; TimeStamp domainLookupEnd; TimeStamp connectStart; + TimeStamp secureConnectionStart; TimeStamp connectEnd; TimeStamp requestStart; TimeStamp responseStart; diff --git a/netwerk/protocol/http/nsAHttpTransaction.h b/netwerk/protocol/http/nsAHttpTransaction.h index 7e42d191a..df998699a 100644 --- a/netwerk/protocol/http/nsAHttpTransaction.h +++ b/netwerk/protocol/http/nsAHttpTransaction.h @@ -216,8 +216,11 @@ public: // If aRestart parameter is true we need to restart the transaction, // otherwise the erly-data has been accepted and we can continue the // transaction. + // If aAlpnChanged is true (and we were assuming http/2), we'll need to take + // the transactions out of the session, rewind them all, and start them back + // over as http/1 transactions // The function will return success or failure of the transaction restart. - virtual nsresult Finish0RTT(bool aRestart) { + virtual nsresult Finish0RTT(bool aRestart, bool aAlpnChanged) { return NS_ERROR_NOT_IMPLEMENTED; } }; diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index 0e570e8cb..94b0d9bf9 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -1152,7 +1152,7 @@ ProcessXCTO(nsIURI* aURI, nsHttpResponseHead* aResponseHead, nsILoadInfo* aLoadI } if (aLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_SCRIPT) { - if (nsContentUtils::IsScriptType(contentType)) { + if (nsContentUtils::IsJavascriptMIMEType(NS_ConvertUTF8toUTF16(contentType))) { return NS_OK; } ReportTypeBlocking(aURI, aLoadInfo, "MimeTypeMismatch"); @@ -6430,6 +6430,15 @@ nsHttpChannel::GetConnectStart(TimeStamp* _retval) { } NS_IMETHODIMP +nsHttpChannel::GetSecureConnectionStart(TimeStamp* _retval) { + if (mTransaction) + *_retval = mTransaction->GetSecureConnectionStart(); + else + *_retval = mTransactionTimings.secureConnectionStart; + return NS_OK; +} + +NS_IMETHODIMP nsHttpChannel::GetConnectEnd(TimeStamp* _retval) { if (mTransaction) *_retval = mTransaction->GetConnectEnd(); @@ -8335,9 +8344,31 @@ nsHttpChannel::ResumeInternal() LOG(("nsHttpChannel::ResumeInternal [this=%p]\n", this)); if (--mSuspendCount == 0 && mCallOnResume) { - nsresult rv = AsyncCall(mCallOnResume); + // Resume the interrupted procedure first, then resume + // the pump to continue process the input stream. + RefPtr<nsRunnableMethod<nsHttpChannel>> callOnResume= + NewRunnableMethod(this, mCallOnResume); + // Should not resume pump that created after resumption. + RefPtr<nsInputStreamPump> transactionPump = mTransactionPump; + RefPtr<nsInputStreamPump> cachePump = mCachePump; + + nsresult rv = + NS_DispatchToCurrentThread(NS_NewRunnableFunction( + [callOnResume, transactionPump, cachePump]() { + callOnResume->Run(); + + if (transactionPump) { + transactionPump->Resume(); + } + + if (cachePump) { + cachePump->Resume(); + } + }) + ); mCallOnResume = nullptr; NS_ENSURE_SUCCESS(rv, rv); + return rv; } nsresult rvTransaction = NS_OK; diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h index ad8156ec0..7578b1173 100644 --- a/netwerk/protocol/http/nsHttpChannel.h +++ b/netwerk/protocol/http/nsHttpChannel.h @@ -165,6 +165,7 @@ public: NS_IMETHOD GetDomainLookupStart(mozilla::TimeStamp *aDomainLookupStart) override; NS_IMETHOD GetDomainLookupEnd(mozilla::TimeStamp *aDomainLookupEnd) override; NS_IMETHOD GetConnectStart(mozilla::TimeStamp *aConnectStart) override; + NS_IMETHOD GetSecureConnectionStart(mozilla::TimeStamp *aSecureConnectionStart) override; NS_IMETHOD GetConnectEnd(mozilla::TimeStamp *aConnectEnd) override; NS_IMETHOD GetRequestStart(mozilla::TimeStamp *aRequestStart) override; NS_IMETHOD GetResponseStart(mozilla::TimeStamp *aResponseStart) override; diff --git a/netwerk/protocol/http/nsHttpConnection.cpp b/netwerk/protocol/http/nsHttpConnection.cpp index 916d1249c..c4564cd8b 100644 --- a/netwerk/protocol/http/nsHttpConnection.cpp +++ b/netwerk/protocol/http/nsHttpConnection.cpp @@ -87,6 +87,7 @@ nsHttpConnection::nsHttpConnection() , mWaitingFor0RTTResponse(false) , mContentBytesWritten0RTT(0) , mEarlyDataNegotiated(false) + , mDid0RTTSpdy(false) { LOG(("Creating nsHttpConnection @%p\n", this)); @@ -158,16 +159,113 @@ nsHttpConnection::Init(nsHttpConnectionInfo *info, return NS_OK; } +nsresult +nsHttpConnection::TryTakeSubTransactions(nsTArray<RefPtr<nsAHttpTransaction> > &list) +{ + nsresult rv = mTransaction->TakeSubTransactions(list); + + if (rv == NS_ERROR_ALREADY_OPENED) { + // Has the interface for TakeSubTransactions() changed? + LOG(("TakeSubTransactions somehow called after " + "nsAHttpTransaction began processing\n")); + MOZ_ASSERT(false, + "TakeSubTransactions somehow called after " + "nsAHttpTransaction began processing"); + mTransaction->Close(NS_ERROR_ABORT); + return rv; + } + + if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) { + // Has the interface for TakeSubTransactions() changed? + LOG(("unexpected rv from nnsAHttpTransaction::TakeSubTransactions()")); + MOZ_ASSERT(false, + "unexpected result from " + "nsAHttpTransaction::TakeSubTransactions()"); + mTransaction->Close(NS_ERROR_ABORT); + return rv; + } + + return rv; +} + +nsresult +nsHttpConnection::MoveTransactionsToSpdy(nsresult status, nsTArray<RefPtr<nsAHttpTransaction> > &list) +{ + if (NS_FAILED(status)) { // includes NS_ERROR_NOT_IMPLEMENTED + MOZ_ASSERT(list.IsEmpty(), "sub transaction list not empty"); + + // This is ok - treat mTransaction as a single real request. + // Wrap the old http transaction into the new spdy session + // as the first stream. + LOG(("nsHttpConnection::MoveTransactionsToSpdy moves single transaction %p " + "into SpdySession %p\n", mTransaction.get(), mSpdySession.get())); + nsresult rv = AddTransaction(mTransaction, mPriority); + if (NS_FAILED(rv)) { + return rv; + } + } else { + int32_t count = list.Length(); + + LOG(("nsHttpConnection::MoveTransactionsToSpdy moving transaction list len=%d " + "into SpdySession %p\n", count, mSpdySession.get())); + + if (!count) { + mTransaction->Close(NS_ERROR_ABORT); + return NS_ERROR_ABORT; + } + + for (int32_t index = 0; index < count; ++index) { + nsresult rv = AddTransaction(list[index], mPriority); + if (NS_FAILED(rv)) { + return rv; + } + } + } + + return NS_OK; +} + +void +nsHttpConnection::Start0RTTSpdy(uint8_t spdyVersion) +{ + LOG(("nsHttpConnection::Start0RTTSpdy [this=%p]", this)); + mDid0RTTSpdy = true; + mUsingSpdyVersion = spdyVersion; + mSpdySession = ASpdySession::NewSpdySession(spdyVersion, mSocketTransport, + true); + + nsTArray<RefPtr<nsAHttpTransaction> > list; + nsresult rv = TryTakeSubTransactions(list); + if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) { + LOG(("nsHttpConnection::Start0RTTSpdy [this=%p] failed taking " + "subtransactions rv=%" PRIx32 , this, static_cast<uint32_t>(rv))); + return; + } + + rv = MoveTransactionsToSpdy(rv, list); + if (NS_FAILED(rv)) { + LOG(("nsHttpConnection::Start0RTTSpdy [this=%p] failed moving " + "transactions rv=%" PRIx32 , this, static_cast<uint32_t>(rv))); + return; + } + + mTransaction = mSpdySession; +} + void nsHttpConnection::StartSpdy(uint8_t spdyVersion) { - LOG(("nsHttpConnection::StartSpdy [this=%p]\n", this)); + LOG(("nsHttpConnection::StartSpdy [this=%p, mDid0RTTSpdy=%d]\n", this, mDid0RTTSpdy)); - MOZ_ASSERT(!mSpdySession); + MOZ_ASSERT(!mSpdySession || mDid0RTTSpdy); mUsingSpdyVersion = spdyVersion; mEverUsedSpdy = true; - mSpdySession = ASpdySession::NewSpdySession(spdyVersion, mSocketTransport); + + if (!mDid0RTTSpdy) { + mSpdySession = ASpdySession::NewSpdySession(spdyVersion, mSocketTransport, + false); + } if (!mReportedSpdy) { mReportedSpdy = true; @@ -185,27 +283,13 @@ nsHttpConnection::StartSpdy(uint8_t spdyVersion) // pack them all into a new spdy session. nsTArray<RefPtr<nsAHttpTransaction> > list; - nsresult rv = mTransaction->TakeSubTransactions(list); - - if (rv == NS_ERROR_ALREADY_OPENED) { - // Has the interface for TakeSubTransactions() changed? - LOG(("TakeSubTransactions somehow called after " - "nsAHttpTransaction began processing\n")); - MOZ_ASSERT(false, - "TakeSubTransactions somehow called after " - "nsAHttpTransaction began processing"); - mTransaction->Close(NS_ERROR_ABORT); - return; - } + nsresult rv = NS_OK; + if (!mDid0RTTSpdy) { + rv = TryTakeSubTransactions(list); - if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) { - // Has the interface for TakeSubTransactions() changed? - LOG(("unexpected rv from nnsAHttpTransaction::TakeSubTransactions()")); - MOZ_ASSERT(false, - "unexpected result from " - "nsAHttpTransaction::TakeSubTransactions()"); - mTransaction->Close(NS_ERROR_ABORT); - return; + if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) { + return; + } } if (NeedSpdyTunnel()) { @@ -227,35 +311,11 @@ nsHttpConnection::StartSpdy(uint8_t spdyVersion) mConnInfo = wildCardProxyCi; } - if (NS_FAILED(rv)) { // includes NS_ERROR_NOT_IMPLEMENTED - MOZ_ASSERT(list.IsEmpty(), "sub transaction list not empty"); - - // This is ok - treat mTransaction as a single real request. - // Wrap the old http transaction into the new spdy session - // as the first stream. - LOG(("nsHttpConnection::StartSpdy moves single transaction %p " - "into SpdySession %p\n", mTransaction.get(), mSpdySession.get())); - rv = AddTransaction(mTransaction, mPriority); + if (!mDid0RTTSpdy) { + rv = MoveTransactionsToSpdy(rv, list); if (NS_FAILED(rv)) { return; } - } else { - int32_t count = list.Length(); - - LOG(("nsHttpConnection::StartSpdy moving transaction list len=%d " - "into SpdySession %p\n", count, mSpdySession.get())); - - if (!count) { - mTransaction->Close(NS_ERROR_ABORT); - return; - } - - for (int32_t index = 0; index < count; ++index) { - rv = AddTransaction(list[index], mPriority); - if (NS_FAILED(rv)) { - return; - } - } } // Disable TCP Keepalives - use SPDY ping instead. @@ -313,6 +373,13 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue, if (NS_FAILED(rv)) goto npnComplete; + if (!m0RTTChecked) { + // We reuse m0RTTChecked. We want to send this status only once. + mTransaction->OnTransportStatus(mSocketTransport, + NS_NET_STATUS_TLS_HANDSHAKE_STARTING, + 0); + } + rv = ssl->GetNegotiatedNPN(negotiatedNPN); if (!m0RTTChecked && (rv == NS_ERROR_NOT_CONNECTED) && !mConnInfo->UsingProxy()) { @@ -321,8 +388,7 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue, // (AlpnEarlySelection), we are using HTTP/1, and the request data can // be safely retried. m0RTTChecked = true; - nsAutoCString earlyNegotiatedNPN; - nsresult rvEarlyAlpn = ssl->GetAlpnEarlySelection(earlyNegotiatedNPN); + nsresult rvEarlyAlpn = ssl->GetAlpnEarlySelection(mEarlyNegotiatedALPN); if (NS_FAILED(rvEarlyAlpn)) { // if ssl->DriveHandshake() has never been called the value // for AlpnEarlySelection is still not set. So call it here and @@ -339,7 +405,7 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue, // Check NegotiatedNPN first. rv = ssl->GetNegotiatedNPN(negotiatedNPN); if (rv == NS_ERROR_NOT_CONNECTED) { - rvEarlyAlpn = ssl->GetAlpnEarlySelection(earlyNegotiatedNPN); + rvEarlyAlpn = ssl->GetAlpnEarlySelection(mEarlyNegotiatedALPN); } } @@ -349,19 +415,26 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue, mEarlyDataNegotiated = false; } else { LOG(("nsHttpConnection::EnsureNPNComplete %p -" - "early selected alpn: %s", this, earlyNegotiatedNPN.get())); + "early selected alpn: %s", this, mEarlyNegotiatedALPN.get())); uint32_t infoIndex; const SpdyInformation *info = gHttpHandler->SpdyInfo(); - // We are doing 0RTT only with Http/1 right now! - if (NS_FAILED(info->GetNPNIndex(earlyNegotiatedNPN, &infoIndex))) { + if (NS_FAILED(info->GetNPNIndex(mEarlyNegotiatedALPN, &infoIndex))) { + // This is the HTTP/1 case. // Check if early-data is allowed for this transaction. if (mTransaction->Do0RTT()) { LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - We " - "can do 0RTT!", this)); + "can do 0RTT (http/1)!", this)); mWaitingFor0RTTResponse = true; } - mEarlyDataNegotiated = true; + } else { + // We have h2, we can at least 0-RTT the preamble and opening + // SETTINGS, etc, and maybe some of the first request + LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - Starting " + "0RTT for h2!", this)); + mWaitingFor0RTTResponse = true; + Start0RTTSpdy(info->Version[infoIndex]); } + mEarlyDataNegotiated = true; } } @@ -391,16 +464,17 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue, this, mConnInfo->HashKey().get(), negotiatedNPN.get(), mTLSFilter ? " [Double Tunnel]" : "")); - bool ealyDataAccepted = false; + bool earlyDataAccepted = false; if (mWaitingFor0RTTResponse) { // Check if early data has been accepted. - rv = ssl->GetEarlyDataAccepted(&ealyDataAccepted); + rv = ssl->GetEarlyDataAccepted(&earlyDataAccepted); LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - early data " - "that was sent during 0RTT %s been accepted.", - this, ealyDataAccepted ? "has" : "has not")); + "that was sent during 0RTT %s been accepted [rv=%" PRIx32 "].", + this, earlyDataAccepted ? "has" : "has not", static_cast<uint32_t>(rv))); if (NS_FAILED(rv) || - NS_FAILED(mTransaction->Finish0RTT(!ealyDataAccepted))) { + NS_FAILED(mTransaction->Finish0RTT(!earlyDataAccepted, negotiatedNPN != mEarlyNegotiatedALPN))) { + LOG(("nsHttpConection::EnsureNPNComplete [this=%p] closing transaction %p", this, mTransaction.get())); mTransaction->Close(NS_ERROR_NET_RESET); goto npnComplete; } @@ -416,16 +490,17 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue, : TLS_EARLY_DATA_AVAILABLE_BUT_NOT_USED)); if (mWaitingFor0RTTResponse) { Telemetry::Accumulate(Telemetry::TLS_EARLY_DATA_ACCEPTED, - ealyDataAccepted); + earlyDataAccepted); } - if (ealyDataAccepted) { + if (earlyDataAccepted) { Telemetry::Accumulate(Telemetry::TLS_EARLY_DATA_BYTES_WRITTEN, mContentBytesWritten0RTT); } } mWaitingFor0RTTResponse = false; - if (!ealyDataAccepted) { + if (!earlyDataAccepted) { + LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] early data not accepted", this)); uint32_t infoIndex; const SpdyInformation *info = gHttpHandler->SpdyInfo(); if (NS_SUCCEEDED(info->GetNPNIndex(negotiatedNPN, &infoIndex))) { @@ -435,21 +510,52 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue, LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - %d bytes " "has been sent during 0RTT.", this, mContentBytesWritten0RTT)); mContentBytesWritten = mContentBytesWritten0RTT; + if (mSpdySession) { + // We had already started 0RTT-spdy, now we need to fully set up + // spdy, since we know we're sticking with it. + LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - finishing " + "StartSpdy for 0rtt spdy session %p", this, mSpdySession.get())); + StartSpdy(mSpdySession->SpdyVersion()); + } } Telemetry::Accumulate(Telemetry::SPDY_NPN_CONNECT, UsingSpdy()); } npnComplete: - LOG(("nsHttpConnection::EnsureNPNComplete setting complete to true")); + LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] setting complete to true", this)); mNPNComplete = true; + + mTransaction->OnTransportStatus(mSocketTransport, + NS_NET_STATUS_TLS_HANDSHAKE_ENDED, 0); + + // this is happening after the bootstrap was originally written to. so update it. + if (mBootstrappedTimings.secureConnectionStart.IsNull() && + !mBootstrappedTimings.connectEnd.IsNull()) { + mBootstrappedTimings.secureConnectionStart = mBootstrappedTimings.connectEnd; + mBootstrappedTimings.connectEnd = TimeStamp::Now(); + } + if (mWaitingFor0RTTResponse) { + // Didn't get 0RTT OK, back out of the "attempting 0RTT" state mWaitingFor0RTTResponse = false; - if (NS_FAILED(mTransaction->Finish0RTT(true))) { + LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] 0rtt failed", this)); + if (NS_FAILED(mTransaction->Finish0RTT(true, negotiatedNPN != mEarlyNegotiatedALPN))) { mTransaction->Close(NS_ERROR_NET_RESET); } mContentBytesWritten0RTT = 0; } + + if (mDid0RTTSpdy && negotiatedNPN != mEarlyNegotiatedALPN) { + // Reset the work done by Start0RTTSpdy + LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] resetting Start0RTTSpdy", this)); + mUsingSpdyVersion = 0; + mTransaction = nullptr; + mSpdySession = nullptr; + // We have to reset this here, just in case we end up starting spdy again, + // so it can actually do everything it needs to do. + mDid0RTTSpdy = false; + } return true; } @@ -473,8 +579,14 @@ nsHttpConnection::Activate(nsAHttpTransaction *trans, uint32_t caps, int32_t pri LOG(("nsHttpConnection::Activate [this=%p trans=%p caps=%x]\n", this, trans, caps)); - if (!trans->IsNullTransaction()) + if (!mExperienced && !trans->IsNullTransaction()) { mExperienced = true; + nsHttpTransaction *hTrans = trans->QueryHttpTransaction(); + if (hTrans) { + hTrans->BootstrapTimings(mBootstrappedTimings); + } + mBootstrappedTimings = TimingStruct(); + } mTransactionCaps = caps; mPriority = pri; @@ -2315,5 +2427,11 @@ nsHttpConnection::CheckForTraffic(bool check) } } +void +nsHttpConnection::BootstrapTimings(TimingStruct times) +{ + mBootstrappedTimings = times; +} + } // namespace net } // namespace mozilla diff --git a/netwerk/protocol/http/nsHttpConnection.h b/netwerk/protocol/http/nsHttpConnection.h index 783b080b3..08eea1de2 100644 --- a/netwerk/protocol/http/nsHttpConnection.h +++ b/netwerk/protocol/http/nsHttpConnection.h @@ -16,6 +16,7 @@ #include "TunnelUtils.h" #include "mozilla/Mutex.h" #include "ARefBase.h" +#include "TimingStruct.h" #include "nsIAsyncInputStream.h" #include "nsIAsyncOutputStream.h" @@ -248,6 +249,13 @@ private: // Start the Spdy transaction handler when NPN indicates spdy/* void StartSpdy(uint8_t versionLevel); + // Like the above, but do the bare minimum to do 0RTT data, so we can back + // it out, if necessary + void Start0RTTSpdy(uint8_t versionLevel); + + // Helpers for Start*Spdy + nsresult TryTakeSubTransactions(nsTArray<RefPtr<nsAHttpTransaction> > &list); + nsresult MoveTransactionsToSpdy(nsresult status, nsTArray<RefPtr<nsAHttpTransaction> > &list); // Directly Add a transaction to an active connection for SPDY nsresult AddTransaction(nsAHttpTransaction *, int32_t); @@ -370,6 +378,13 @@ private: // the handsake. int64_t mContentBytesWritten0RTT; bool mEarlyDataNegotiated; //Only used for telemetry + nsCString mEarlyNegotiatedALPN; + bool mDid0RTTSpdy; + +public: + void BootstrapTimings(TimingStruct times); +private: + TimingStruct mBootstrappedTimings; }; } // namespace net diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp index abae51e2f..9271b49af 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -3314,6 +3314,11 @@ nsHalfOpenSocket::OnOutputStreamReady(nsIAsyncOutputStream *out) LOG(("nsHalfOpenSocket::OnOutputStreamReady " "Created new nshttpconnection %p\n", conn.get())); + NullHttpTransaction *nullTrans = mTransaction->QueryNullTransaction(); + if (nullTrans) { + conn->BootstrapTimings(nullTrans->Timings()); + } + // Some capabilities are needed before a transaciton actually gets // scheduled (e.g. how to negotiate false start) conn->SetTransactionCaps(mTransaction->Caps()); diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp index 1ddffabff..67e29a029 100644 --- a/netwerk/protocol/http/nsHttpHandler.cpp +++ b/netwerk/protocol/http/nsHttpHandler.cpp @@ -199,8 +199,9 @@ nsHttpHandler::nsHttpHandler() , mSessionStartTime(0) , mLegacyAppName("Mozilla") , mLegacyAppVersion("5.0") - , mProduct("Gecko") + , mProduct("Goanna") , mCompatFirefoxEnabled(false) + , mCompatFirefoxVersion("52.9") , mUserAgentIsDirty(true) , mPromptTempRedirect(true) , mEnablePersistentHttpsCaching(false) @@ -316,9 +317,13 @@ nsHttpHandler::Init() nsHttpChannelAuthProvider::InitializePrefs(); - mMisc.AssignLiteral("rv:" MOZILLA_UAVERSION); + // rv: should have the Firefox/Gecko compatversion for web compatibility + mMisc.AssignLiteral("rv:"); + mMisc += mCompatFirefoxVersion; - mCompatFirefox.AssignLiteral("Firefox/" MOZILLA_UAVERSION); + mCompatGecko.AssignLiteral("Gecko/20100101"); + mCompatFirefox.AssignLiteral("Firefox/"); + mCompatFirefox += mCompatFirefoxVersion; nsCOMPtr<nsIXULAppInfo> appInfo = do_GetService("@mozilla.org/xre/app-info;1"); @@ -330,12 +335,30 @@ nsHttpHandler::Init() if (mAppName.Length() == 0) { appInfo->GetName(mAppName); } - appInfo->GetVersion(mAppVersion); mAppName.StripChars(R"( ()<>@,;:\"/[]?={})"); + } + + nsCString dynamicBuildID; + if (appInfo) { + appInfo->GetPlatformBuildID(dynamicBuildID); + if (dynamicBuildID.Length() > 8 ) + dynamicBuildID.Left(dynamicBuildID, 8); + } + + if (mAppVersionIsBuildID) { + // Override BuildID + mAppVersion.AssignLiteral(MOZ_UA_BUILDID); + } else if (appInfo) { + appInfo->GetVersion(mAppVersion); } else { - mAppVersion.AssignLiteral(MOZ_APP_UA_VERSION); + // Fall back to platform if appInfo is unavailable + mAppVersion.AssignLiteral(MOZILLA_UAVERSION); } + // If there's no override set, set it to the dynamic BuildID + if (mAppVersion.IsEmpty()) + mAppVersion.Assign(dynamicBuildID); + mSessionStartTime = NowInSeconds(); mHandlerActive = true; @@ -351,11 +374,11 @@ nsHttpHandler::Init() mRequestContextService = do_GetService("@mozilla.org/network/request-context-service;1"); -#if defined(ANDROID) || defined(MOZ_MULET) + // Goanna slice version mProductSub.AssignLiteral(MOZILLA_UAVERSION); -#else - mProductSub.AssignLiteral("20100101"); -#endif + + if (mProductSub.IsEmpty()) + mProductSub.Assign(dynamicBuildID); #if DEBUG // dump user agent prefs @@ -369,6 +392,7 @@ nsHttpHandler::Init() LOG(("> app-name = %s\n", mAppName.get())); LOG(("> app-version = %s\n", mAppVersion.get())); LOG(("> compat-firefox = %s\n", mCompatFirefox.get())); + LOG(("> compat-gecko = %s\n", mCompatGecko.get())); LOG(("> user-agent = %s\n", UserAgent().get())); #endif @@ -678,9 +702,10 @@ nsHttpHandler::BuildUserAgent() mAppName.Length() + mAppVersion.Length() + mCompatFirefox.Length() + + mCompatGecko.Length() + mCompatDevice.Length() + mDeviceModelId.Length() + - 13); + 14); // Application portion mUserAgent.Assign(mLegacyAppName); @@ -710,6 +735,12 @@ nsHttpHandler::BuildUserAgent() } mUserAgent += mMisc; mUserAgent += ')'; + + if(mCompatGeckoEnabled) { + // Provide frozen Gecko/20100101 slice + mUserAgent += ' '; + mUserAgent += mCompatGecko; + } // Product portion mUserAgent += ' '; @@ -719,7 +750,7 @@ nsHttpHandler::BuildUserAgent() bool isFirefox = mAppName.EqualsLiteral("Firefox"); if (isFirefox || mCompatFirefoxEnabled) { - // "Firefox/x.y" (compatibility) app token + // Provide "Firefox/x.y" (compatibility) app token mUserAgent += ' '; mUserAgent += mCompatFirefox; } @@ -966,16 +997,44 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref) bool cVar = false; + if (PREF_CHANGED(UA_PREF("appVersionIsBuildID"))) { + rv = prefs->GetBoolPref(UA_PREF("appVersionIsBuildID"), &cVar); + mAppVersionIsBuildID = (NS_SUCCEEDED(rv) && cVar); + mUserAgentIsDirty = true; + } + + if (PREF_CHANGED(UA_PREF("compatMode.gecko"))) { + rv = prefs->GetBoolPref(UA_PREF("compatMode.gecko"), &cVar); + mCompatGeckoEnabled = (NS_SUCCEEDED(rv) && cVar); + mUserAgentIsDirty = true; + } + if (PREF_CHANGED(UA_PREF("compatMode.firefox"))) { rv = prefs->GetBoolPref(UA_PREF("compatMode.firefox"), &cVar); mCompatFirefoxEnabled = (NS_SUCCEEDED(rv) && cVar); mUserAgentIsDirty = true; } + // general.useragent.compatMode.version + // This is the version number used in rv: for Gecko compatibility + // and in the Firefox/nn.nn slice when compatMode.firefox is enabled. + if (PREF_CHANGED(UA_PREF("compatMode.version"))) { + prefs->GetCharPref(UA_PREF("compatMode.version"), + getter_Copies(mCompatFirefoxVersion)); + + // rebuild mMisc and compatMode slice + mMisc.AssignLiteral("rv:"); + mMisc += mCompatFirefoxVersion; + mCompatFirefox.AssignLiteral("Firefox/"); + mCompatFirefox += mCompatFirefoxVersion; + + mUserAgentIsDirty = true; + } + // general.useragent.override if (PREF_CHANGED(UA_PREF("override"))) { prefs->GetCharPref(UA_PREF("override"), - getter_Copies(mUserAgentOverride)); + getter_Copies(mUserAgentOverride)); mUserAgentIsDirty = true; } diff --git a/netwerk/protocol/http/nsHttpHandler.h b/netwerk/protocol/http/nsHttpHandler.h index 13cc72e8e..d51662db9 100644 --- a/netwerk/protocol/http/nsHttpHandler.h +++ b/netwerk/protocol/http/nsHttpHandler.h @@ -485,7 +485,11 @@ private: nsXPIDLCString mProductSub; nsXPIDLCString mAppName; nsXPIDLCString mAppVersion; + bool mAppVersionIsBuildID; + nsCString mCompatGecko; + bool mCompatGeckoEnabled; nsCString mCompatFirefox; + nsCString mCompatFirefoxVersion; bool mCompatFirefoxEnabled; nsXPIDLCString mCompatDevice; nsCString mDeviceModelId; diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp index ee3a88489..706710d89 100644 --- a/netwerk/protocol/http/nsHttpTransaction.cpp +++ b/netwerk/protocol/http/nsHttpTransaction.cpp @@ -39,6 +39,8 @@ #include "nsIOService.h" #include "nsIRequestContext.h" #include "nsIHttpAuthenticator.h" +#include "NSSErrorsService.h" +#include "sslerr.h" #include <algorithm> #ifdef MOZ_WIDGET_GONK @@ -144,6 +146,7 @@ nsHttpTransaction::nsHttpTransaction() , mIsInIsolatedMozBrowser(false) , mClassOfService(0) , m0RTTInProgress(false) + , mTransportStatus(NS_OK) { LOG(("Creating nsHttpTransaction @%p\n", this)); gHttpHandler->GetMaxPipelineObjectSize(&mMaxPipelineObjectSize); @@ -550,6 +553,50 @@ nsHttpTransaction::OnTransportStatus(nsITransport* transport, LOG(("nsHttpTransaction::OnSocketStatus [this=%p status=%x progress=%lld]\n", this, status, progress)); + // A transaction can given to multiple HalfOpen sockets (this is a bug in + // nsHttpConnectionMgr). We are going to fix it here as a work around to be + // able to uplift it. + switch(status) { + case NS_NET_STATUS_RESOLVING_HOST: + if (mTransportStatus != NS_OK) { + LOG(("nsHttpTransaction::OnSocketStatus - ignore socket events " + "from backup transport")); + return; + } + break; + case NS_NET_STATUS_RESOLVED_HOST: + if (mTransportStatus != NS_NET_STATUS_RESOLVING_HOST && + mTransportStatus != NS_OK) { + LOG(("nsHttpTransaction::OnSocketStatus - ignore socket events " + "from backup transport")); + return; + } + break; + case NS_NET_STATUS_CONNECTING_TO: + if (mTransportStatus != NS_NET_STATUS_RESOLVING_HOST && + mTransportStatus != NS_NET_STATUS_RESOLVED_HOST && + mTransportStatus != NS_OK) { + LOG(("nsHttpTransaction::OnSocketStatus - ignore socket events " + "from backup transport")); + return; + } + break; + case NS_NET_STATUS_CONNECTED_TO: + if (mTransportStatus != NS_NET_STATUS_RESOLVING_HOST && + mTransportStatus != NS_NET_STATUS_RESOLVED_HOST && + mTransportStatus != NS_NET_STATUS_CONNECTING_TO && + mTransportStatus != NS_OK) { + LOG(("nsHttpTransaction::OnSocketStatus - ignore socket events " + "from backup transport")); + return; + } + break; + default: + LOG(("nsHttpTransaction::OnSocketStatus - a new event")); + } + + mTransportStatus = status; + if (status == NS_NET_STATUS_CONNECTED_TO || status == NS_NET_STATUS_WAITING_FOR) { nsISocketTransport *socketTransport = @@ -574,7 +621,17 @@ nsHttpTransaction::OnTransportStatus(nsITransport* transport, } else if (status == NS_NET_STATUS_CONNECTING_TO) { SetConnectStart(TimeStamp::Now()); } else if (status == NS_NET_STATUS_CONNECTED_TO) { - SetConnectEnd(TimeStamp::Now()); + SetConnectEnd(TimeStamp::Now(), true); + } else if (status == NS_NET_STATUS_TLS_HANDSHAKE_ENDED) { + { + // before overwriting connectEnd, copy it to secureConnectionStart + MutexAutoLock lock(mLock); + if (mTimings.secureConnectionStart.IsNull() && + !mTimings.connectEnd.IsNull()) { + mTimings.secureConnectionStart = mTimings.connectEnd; + } + } + SetConnectEnd(TimeStamp::Now(), false); } } @@ -998,7 +1055,9 @@ nsHttpTransaction::Close(nsresult reason) // connection. It will break that connection and also confuse the channel's // auth provider, beliving the cached credentials are wrong and asking for // the password mistakenly again from the user. - if ((reason == NS_ERROR_NET_RESET || reason == NS_OK) && + if ((reason == NS_ERROR_NET_RESET || + reason == NS_OK || + reason == psm::GetXPCOMFromNSSError(SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA)) && (!(mCaps & NS_HTTP_STICKY_CONNECTION) || (mCaps & NS_HTTP_CONNECTION_RESTARTABLE))) { if (mForceRestart && NS_SUCCEEDED(Restart())) { @@ -1027,9 +1086,10 @@ nsHttpTransaction::Close(nsresult reason) bool reallySentData = mSentData && (!mConnection || mConnection->BytesWritten()); - if (!mReceivedData && + if (reason == psm::GetXPCOMFromNSSError(SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA) || + (!mReceivedData && ((mRequestHead && mRequestHead->IsSafeMethod()) || - !reallySentData || connReused)) { + !reallySentData || connReused))) { // if restarting fails, then we must proceed to close the pipe, // which will notify the channel that the transaction failed. @@ -1327,6 +1387,8 @@ nsHttpTransaction::Restart() } } + mTransportStatus = NS_OK; + return gHttpHandler->InitiateTransaction(this, mPriority); } @@ -2082,6 +2144,13 @@ nsHttpTransaction::Timings() } void +nsHttpTransaction::BootstrapTimings(TimingStruct times) +{ + mozilla::MutexAutoLock lock(mLock); + mTimings = times; +} + +void nsHttpTransaction::SetDomainLookupStart(mozilla::TimeStamp timeStamp, bool onlyIfNull) { mozilla::MutexAutoLock lock(mLock); @@ -2173,6 +2242,13 @@ nsHttpTransaction::GetConnectStart() } mozilla::TimeStamp +nsHttpTransaction::GetSecureConnectionStart() +{ + mozilla::MutexAutoLock lock(mLock); + return mTimings.secureConnectionStart; +} + +mozilla::TimeStamp nsHttpTransaction::GetConnectEnd() { mozilla::MutexAutoLock lock(mLock); @@ -2440,8 +2516,9 @@ nsHttpTransaction::Do0RTT() } nsresult -nsHttpTransaction::Finish0RTT(bool aRestart) +nsHttpTransaction::Finish0RTT(bool aRestart, bool aAlpnChanged /* ignored */) { + LOG(("nsHttpTransaction::Finish0RTT %p %d %d\n", this, aRestart, aAlpnChanged)); MOZ_ASSERT(m0RTTInProgress); m0RTTInProgress = false; if (aRestart) { @@ -2453,6 +2530,10 @@ nsHttpTransaction::Finish0RTT(bool aRestart) } else { return NS_ERROR_FAILURE; } + } else if (!mConnected) { + // this is code that was skipped in ::ReadSegments while in 0RTT + mConnected = true; + mConnection->GetSecurityInfo(getter_AddRefs(mSecurityInfo)); } return NS_OK; } diff --git a/netwerk/protocol/http/nsHttpTransaction.h b/netwerk/protocol/http/nsHttpTransaction.h index ab0b267a7..5bf97d41e 100644 --- a/netwerk/protocol/http/nsHttpTransaction.h +++ b/netwerk/protocol/http/nsHttpTransaction.h @@ -149,6 +149,7 @@ public: // Locked methods to get and set timing info const TimingStruct Timings(); + void BootstrapTimings(TimingStruct times); void SetDomainLookupStart(mozilla::TimeStamp timeStamp, bool onlyIfNull = false); void SetDomainLookupEnd(mozilla::TimeStamp timeStamp, bool onlyIfNull = false); void SetConnectStart(mozilla::TimeStamp timeStamp, bool onlyIfNull = false); @@ -160,6 +161,8 @@ public: mozilla::TimeStamp GetDomainLookupStart(); mozilla::TimeStamp GetDomainLookupEnd(); mozilla::TimeStamp GetConnectStart(); + mozilla::TimeStamp GetSecureConnectionStart(); + mozilla::TimeStamp GetConnectEnd(); mozilla::TimeStamp GetRequestStart(); mozilla::TimeStamp GetResponseStart(); @@ -168,7 +171,7 @@ public: int64_t GetTransferSize() { return mTransferSize; } bool Do0RTT() override; - nsresult Finish0RTT(bool aRestart) override; + nsresult Finish0RTT(bool aRestart, bool aAlpnChanged /* ignored */) override; private: friend class DeleteHttpTransaction; virtual ~nsHttpTransaction(); @@ -479,6 +482,8 @@ private: NetAddr mPeerAddr; bool m0RTTInProgress; + + nsresult mTransportStatus; }; } // namespace net diff --git a/netwerk/sctp/datachannel/DataChannel.cpp b/netwerk/sctp/datachannel/DataChannel.cpp index bf7790f51..d47a9d5ea 100644 --- a/netwerk/sctp/datachannel/DataChannel.cpp +++ b/netwerk/sctp/datachannel/DataChannel.cpp @@ -646,6 +646,7 @@ DataChannelConnection::SctpDtlsInput(TransportFlow *flow, } } // Pass the data to SCTP + MutexAutoLock lock(mLock); usrsctp_conninput(static_cast<void *>(this), data, len, 0); } @@ -1016,7 +1017,7 @@ DataChannelConnection::SendDeferredMessages() bool still_blocked = false; // This may block while something is modifying channels, but should not block for IO - MutexAutoLock lock(mLock); + mLock.AssertCurrentThreadOwns(); // XXX For total fairness, on a still_blocked we'd start next time at the // same index. Sorry, not going to bother for now. @@ -1923,7 +1924,7 @@ DataChannelConnection::ReceiveCallback(struct socket* sock, void *data, size_t d if (!data) { usrsctp_close(sock); // SCTP has finished shutting down } else { - MutexAutoLock lock(mLock); + mLock.AssertCurrentThreadOwns(); if (flags & MSG_NOTIFICATION) { HandleNotification(static_cast<union sctp_notification *>(data), datalen); } else { diff --git a/netwerk/test/TestUDPSocket.cpp b/netwerk/test/TestUDPSocket.cpp index 9236d2ea3..0ec43a650 100644 --- a/netwerk/test/TestUDPSocket.cpp +++ b/netwerk/test/TestUDPSocket.cpp @@ -13,9 +13,6 @@ #include "nsIScriptSecurityManager.h" #include "nsITimer.h" #include "mozilla/net/DNS.h" -#ifdef XP_WIN -#include "mozilla/WindowsVersion.h" -#endif #include "prerror.h" #define REQUEST 0x68656c6f @@ -334,16 +331,6 @@ main(int32_t argc, char *argv[]) } RefPtr<MulticastTimerCallback> timerCb = new MulticastTimerCallback(); - // The following multicast tests using multiple sockets require a firewall - // exception on Windows XP (the earliest version of Windows we now support) - // before they pass. For now, we'll skip them here. Later versions of Windows - // (Win2003 and onward) don't seem to have this issue. -#ifdef XP_WIN - if (!mozilla::IsWin2003OrLater()) { // i.e. if it is WinXP - goto close; - } -#endif - // Join multicast group printf("Joining multicast group\n"); phase = TEST_MULTICAST; diff --git a/netwerk/test/mochitests/mochitest.ini b/netwerk/test/mochitests/mochitest.ini index 98d406c80..f8a919031 100644 --- a/netwerk/test/mochitests/mochitest.ini +++ b/netwerk/test/mochitests/mochitest.ini @@ -24,3 +24,4 @@ support-files = [test_user_agent_updates_reset.html] [test_viewsource_unlinkable.html] [test_xhr_method_case.html] +[test_1396395.html] diff --git a/netwerk/test/mochitests/test_1396395.html b/netwerk/test/mochitests/test_1396395.html new file mode 100644 index 000000000..193ef219c --- /dev/null +++ b/netwerk/test/mochitests/test_1396395.html @@ -0,0 +1,52 @@ +<!DOCTYPE HTML> +<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: --> +<html> + <!-- Any copyright is dedicated to the Public Domain. + - http://creativecommons.org/publicdomain/zero/1.0/ --> +<head> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> +</head> +<body> + <iframe id="f" src="http://example.com"></iframe> + <script type="text/javascript"> +SimpleTest.waitForExplicitFinish(); + +var script = SpecialPowers.loadChromeScript(() => { + const Ci = Components.interfaces; + const Cc = Components.classes; + const Cu = Components.utils; + Cu.import('resource://gre/modules/Services.jsm'); + + Services.obs.addObserver(function onExamResp(subject, topic, data) { + let channel = subject.QueryInterface(Ci.nsIHttpChannel); + if (!channel.URI.spec.startsWith("http://example.org")) { + return; + } + Services.obs.removeObserver(onExamResp, 'http-on-examine-response'); + channel.suspend(); + Promise.resolve().then(() => { + channel.resume(); + }); + }, 'http-on-examine-response'); + + sendAsyncMessage('start-test'); +}); + +script.addMessageListener('start-test', () => { + const iframe = document.getElementById('f'); + + iframe.contentWindow.onunload = function () { + xhr = new XMLHttpRequest(); + xhr.open('GET', window.location, false); + xhr.send(null); + ok(true, 'complete without crash'); + script.destroy(); + SimpleTest.finish(); + } + + iframe.src = 'http://example.org'; +}); + </script> +</body> +</html> + diff --git a/netwerk/wifi/moz.build b/netwerk/wifi/moz.build index b6ddd2139..e3edb0842 100644 --- a/netwerk/wifi/moz.build +++ b/netwerk/wifi/moz.build @@ -45,7 +45,6 @@ elif CONFIG['OS_ARCH'] == 'WINNT': 'nsWifiScannerWin.cpp', 'win_wifiScanner.cpp', 'win_wlanLibrary.cpp', - 'win_xp_wifiScanner.cpp' ] elif CONFIG['OS_ARCH'] == 'SunOS': CXXFLAGS += CONFIG['GLIB_CFLAGS'] diff --git a/netwerk/wifi/nsWifiMonitor.h b/netwerk/wifi/nsWifiMonitor.h index 3783d38bd..665798efc 100644 --- a/netwerk/wifi/nsWifiMonitor.h +++ b/netwerk/wifi/nsWifiMonitor.h @@ -76,7 +76,7 @@ class nsWifiMonitor final : nsIRunnable, nsIWifiMonitor, nsIObserver mozilla::ReentrantMonitor mReentrantMonitor; #ifdef XP_WIN - nsAutoPtr<WindowsWifiScannerInterface> mWinWifiScanner; + nsAutoPtr<WinWifiScanner> mWinWifiScanner; #endif }; #else diff --git a/netwerk/wifi/nsWifiScannerWin.cpp b/netwerk/wifi/nsWifiScannerWin.cpp index ef18706e4..6089c45c6 100644 --- a/netwerk/wifi/nsWifiScannerWin.cpp +++ b/netwerk/wifi/nsWifiScannerWin.cpp @@ -12,8 +12,6 @@ #include "nsServiceManagerUtils.h" #include "nsWifiAccessPoint.h" #include "win_wifiScanner.h" -#include "win_xp_wifiScanner.h" -#include "mozilla/WindowsVersion.h" using namespace mozilla; @@ -31,14 +29,7 @@ nsresult nsWifiMonitor::DoScan() { if (!mWinWifiScanner) { - if (IsWin2003OrLater()) { - mWinWifiScanner = new WinWifiScanner(); - LOG(("Using Windows 2003+ wifi scanner.")); - } else { - mWinWifiScanner = new WinXPWifiScanner(); - LOG(("Using Windows XP wifi scanner.")); - } - + mWinWifiScanner = new WinWifiScanner(); if (!mWinWifiScanner) { // TODO: Probably return OOM error return NS_ERROR_FAILURE; diff --git a/netwerk/wifi/win_wifiScanner.h b/netwerk/wifi/win_wifiScanner.h index b43c23899..79b1bf132 100644 --- a/netwerk/wifi/win_wifiScanner.h +++ b/netwerk/wifi/win_wifiScanner.h @@ -11,19 +11,10 @@ class nsWifiAccessPoint; -// This class allows the wifi monitor to use WinWifiScanner and WinXPWifiScanner interchangeably. -class WindowsWifiScannerInterface { -public: - virtual ~WindowsWifiScannerInterface() {} - - virtual nsresult GetAccessPointsFromWLAN(nsCOMArray<nsWifiAccessPoint> &accessPoints) = 0; -}; - - -class WinWifiScanner : public WindowsWifiScannerInterface { +class WinWifiScanner final { public: WinWifiScanner(); - virtual ~WinWifiScanner(); + ~WinWifiScanner(); /** * GetAccessPointsFromWLAN diff --git a/netwerk/wifi/win_xp_wifiScanner.cpp b/netwerk/wifi/win_xp_wifiScanner.cpp deleted file mode 100644 index 4dcd34034..000000000 --- a/netwerk/wifi/win_xp_wifiScanner.cpp +++ /dev/null @@ -1,399 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Windows Vista uses the Native Wifi (WLAN) API for accessing WiFi cards. See -// http://msdn.microsoft.com/en-us/library/ms705945(VS.85).aspx. Windows XP -// Service Pack 3 (and Windows XP Service Pack 2, if upgraded with a hot fix) -// also support a limited version of the WLAN API. See -// http://msdn.microsoft.com/en-us/library/bb204766.aspx. The WLAN API uses -// wlanapi.h, which is not part of the SDK used by Gears, so is replicated -// locally using data from the MSDN. -//\ -// Windows XP from Service Pack 2 onwards supports the Wireless Zero -// Configuration (WZC) programming interface. See -// http://msdn.microsoft.com/en-us/library/ms706587(VS.85).aspx. -// -// The MSDN recommends that one use the WLAN API where available, and WZC -// otherwise. -// -// However, it seems that WZC fails for some wireless cards. Also, WLAN seems -// not to work on XP SP3. So we use WLAN on Vista, and use NDIS directly -// otherwise. - -// MOZILLA NOTE: -// This code is ported from chromium: -// https://chromium.googlesource.com/chromium/src/+/master/content/browser/geolocation/wifi_data_provider_win.cc -// Based on changeset 42c5878 - -#include "win_xp_wifiScanner.h" -#include "nsWifiAccessPoint.h" -#include <windows.h> -#include <winioctl.h> -#include <wlanapi.h> -#include <string> -#include <vector> - -// Taken from ndis.h for WinCE. -#define NDIS_STATUS_INVALID_LENGTH ((NDIS_STATUS)0xC0010014L) -#define NDIS_STATUS_BUFFER_TOO_SHORT ((NDIS_STATUS)0xC0010016L) - -namespace { -// The limits on the size of the buffer used for the OID query. -const int kInitialBufferSize = 2 << 12; // Good for about 50 APs. -const int kMaximumBufferSize = 2 << 20; // 2MB - -// Length for generic string buffers passed to Win32 APIs. -const int kStringLength = 512; - -// WlanOpenHandle -typedef DWORD (WINAPI* WlanOpenHandleFunction)(DWORD dwClientVersion, - PVOID pReserved, - PDWORD pdwNegotiatedVersion, - PHANDLE phClientHandle); - -// WlanEnumInterfaces -typedef DWORD (WINAPI* WlanEnumInterfacesFunction)( - HANDLE hClientHandle, - PVOID pReserved, - PWLAN_INTERFACE_INFO_LIST* ppInterfaceList); - -// WlanGetNetworkBssList -typedef DWORD (WINAPI* WlanGetNetworkBssListFunction)( - HANDLE hClientHandle, - const GUID* pInterfaceGuid, - const PDOT11_SSID pDot11Ssid, - DOT11_BSS_TYPE dot11BssType, - BOOL bSecurityEnabled, - PVOID pReserved, - PWLAN_BSS_LIST* ppWlanBssList -); - -// WlanFreeMemory -typedef VOID (WINAPI* WlanFreeMemoryFunction)(PVOID pMemory); - -// WlanCloseHandle -typedef DWORD (WINAPI* WlanCloseHandleFunction)(HANDLE hClientHandle, - PVOID pReserved); - -// Extracts data for an access point and converts to Gears format. -bool UndefineDosDevice(const std::string& device_name); -bool DefineDosDeviceIfNotExists(const std::string& device_name); -HANDLE GetFileHandle(const std::string& device_name); -// Makes the OID query and returns a Win32 error code. -int PerformQuery(HANDLE adapter_handle, std::vector<char>& buffer, DWORD* bytes_out); -bool ResizeBuffer(size_t requested_size, std::vector<char>& buffer); -// Gets the system directory and appends a trailing slash if not already -// present. -bool GetSystemDirectory(std::string* path); - -bool ConvertToAccessPointData(const NDIS_WLAN_BSSID& data, nsWifiAccessPoint* access_point_data); -int GetDataFromBssIdList(const NDIS_802_11_BSSID_LIST& bss_id_list, - int list_size, - nsCOMArray<nsWifiAccessPoint>& outData); -} // namespace - -class WindowsNdisApi -{ -public: - virtual ~WindowsNdisApi(); - static WindowsNdisApi* Create(); - virtual bool GetAccessPointData(nsCOMArray<nsWifiAccessPoint>& outData); - -private: - static bool GetInterfacesNDIS(std::vector<std::string>& interface_service_names_out); - // Swaps in content of the vector passed - explicit WindowsNdisApi(std::vector<std::string>* interface_service_names); - bool GetInterfaceDataNDIS(HANDLE adapter_handle, nsCOMArray<nsWifiAccessPoint>& outData); - // NDIS variables. - std::vector<std::string> interface_service_names_; - std::vector<char> _buffer; -}; - -// WindowsNdisApi -WindowsNdisApi::WindowsNdisApi( - std::vector<std::string>* interface_service_names) - : _buffer(kInitialBufferSize) { - interface_service_names_.swap(*interface_service_names); -} - -WindowsNdisApi::~WindowsNdisApi() { -} - -WindowsNdisApi* WindowsNdisApi::Create() { - std::vector<std::string> interface_service_names; - if (GetInterfacesNDIS(interface_service_names)) { - return new WindowsNdisApi(&interface_service_names); - } - return NULL; -} - -bool WindowsNdisApi::GetAccessPointData(nsCOMArray<nsWifiAccessPoint>& outData) { - int interfaces_failed = 0; - int interfaces_succeeded = 0; - - for (int i = 0; i < static_cast<int>(interface_service_names_.size()); ++i) { - // First, check that we have a DOS device for this adapter. - if (!DefineDosDeviceIfNotExists(interface_service_names_[i])) { - continue; - } - - // Get the handle to the device. This will fail if the named device is not - // valid. - HANDLE adapter_handle = GetFileHandle(interface_service_names_[i]); - if (adapter_handle == INVALID_HANDLE_VALUE) { - continue; - } - - // Get the data. - if (GetInterfaceDataNDIS(adapter_handle, outData)) { - ++interfaces_succeeded; - } else { - ++interfaces_failed; - } - - // Clean up. - CloseHandle(adapter_handle); - UndefineDosDevice(interface_service_names_[i]); - } - - // Return true if at least one interface succeeded, or at the very least none - // failed. - return interfaces_succeeded > 0 || interfaces_failed == 0; -} - -bool WindowsNdisApi::GetInterfacesNDIS(std::vector<std::string>& interface_service_names_out) { - HKEY network_cards_key = NULL; - if (RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - "Software\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards", - 0, - KEY_READ, - &network_cards_key) != ERROR_SUCCESS) { - return false; - } - if (!network_cards_key) { - return false; - } - - for (int i = 0; ; ++i) { - TCHAR name[kStringLength]; - DWORD name_size = kStringLength; - FILETIME time; - if (RegEnumKeyEx(network_cards_key, - i, - name, - &name_size, - NULL, - NULL, - NULL, - &time) != ERROR_SUCCESS) { - break; - } - HKEY hardware_key = NULL; - if (RegOpenKeyEx(network_cards_key, name, 0, KEY_READ, &hardware_key) != - ERROR_SUCCESS) { - break; - } - if (!hardware_key) { - return false; - } - - TCHAR service_name[kStringLength]; - DWORD service_name_size = kStringLength; - DWORD type = 0; - if (RegQueryValueEx(hardware_key, - "ServiceName", - NULL, - &type, - reinterpret_cast<LPBYTE>(service_name), - &service_name_size) == ERROR_SUCCESS) { - interface_service_names_out.push_back(service_name); - } - RegCloseKey(hardware_key); - } - - RegCloseKey(network_cards_key); - return true; -} - -bool WindowsNdisApi::GetInterfaceDataNDIS(HANDLE adapter_handle, - nsCOMArray<nsWifiAccessPoint>& outData) { - DWORD bytes_out; - int result; - - while (true) { - bytes_out = 0; - result = PerformQuery(adapter_handle, _buffer, &bytes_out); - if (result == ERROR_GEN_FAILURE || // Returned by some Intel cards. - result == ERROR_INSUFFICIENT_BUFFER || - result == ERROR_MORE_DATA || - result == NDIS_STATUS_INVALID_LENGTH || - result == NDIS_STATUS_BUFFER_TOO_SHORT) { - // The buffer we supplied is too small, so increase it. bytes_out should - // provide the required buffer size, but this is not always the case. - size_t newSize; - if (bytes_out > static_cast<DWORD>(_buffer.size())) { - newSize = bytes_out; - } else { - newSize = _buffer.size() * 2; - } - if (!ResizeBuffer(newSize, _buffer)) { - return false; - } - } else { - // The buffer is not too small. - break; - } - } - - if (result == ERROR_SUCCESS) { - NDIS_802_11_BSSID_LIST* bssid_list = - reinterpret_cast<NDIS_802_11_BSSID_LIST*>(&_buffer[0]); - GetDataFromBssIdList(*bssid_list, _buffer.size(), outData); - } - - return true; -} - -namespace { -#define uint8 unsigned char - -bool ConvertToAccessPointData(const NDIS_WLAN_BSSID& data, nsWifiAccessPoint* access_point_data) -{ - access_point_data->setMac(data.MacAddress); - access_point_data->setSignal(data.Rssi); - // Note that _NDIS_802_11_SSID::Ssid::Ssid is not null-terminated. - const unsigned char* ssid = data.Ssid.Ssid; - size_t len = data.Ssid.SsidLength; - access_point_data->setSSID(reinterpret_cast<const char*>(ssid), len); - return true; -} - -int GetDataFromBssIdList(const NDIS_802_11_BSSID_LIST& bss_id_list, - int list_size, - nsCOMArray<nsWifiAccessPoint>& outData) -{ - // Walk through the BSS IDs. - int found = 0; - const uint8* iterator = reinterpret_cast<const uint8*>(&bss_id_list.Bssid[0]); - const uint8* end_of_buffer = - reinterpret_cast<const uint8*>(&bss_id_list) + list_size; - for (int i = 0; i < static_cast<int>(bss_id_list.NumberOfItems); ++i) { - const NDIS_WLAN_BSSID *bss_id = - reinterpret_cast<const NDIS_WLAN_BSSID*>(iterator); - // Check that the length of this BSS ID is reasonable. - if (bss_id->Length < sizeof(NDIS_WLAN_BSSID) || - iterator + bss_id->Length > end_of_buffer) { - break; - } - nsWifiAccessPoint* ap = new nsWifiAccessPoint(); - if (ConvertToAccessPointData(*bss_id, ap)) { - outData.AppendObject(ap); - ++found; - } - // Move to the next BSS ID. - iterator += bss_id->Length; - } - return found; -} - - -bool UndefineDosDevice(const std::string& device_name) { - // We remove only the mapping we use, that is \Device\<device_name>. - std::string target_path = "\\Device\\" + device_name; - return DefineDosDevice( - DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE, - device_name.c_str(), - target_path.c_str()) == TRUE; -} - -bool DefineDosDeviceIfNotExists(const std::string& device_name) { - // We create a DOS device name for the device at \Device\<device_name>. - std::string target_path = "\\Device\\" + device_name; - - TCHAR target[kStringLength]; - if (QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 && - target_path.compare(target) == 0) { - // Device already exists. - return true; - } - - if (GetLastError() != ERROR_FILE_NOT_FOUND) { - return false; - } - - if (!DefineDosDevice(DDD_RAW_TARGET_PATH, - device_name.c_str(), - target_path.c_str())) { - return false; - } - - // Check that the device is really there. - return QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 && - target_path.compare(target) == 0; -} - -HANDLE GetFileHandle(const std::string& device_name) { - // We access a device with DOS path \Device\<device_name> at - // \\.\<device_name>. - std::string formatted_device_name = "\\\\.\\" + device_name; - - return CreateFile(formatted_device_name.c_str(), - GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, // share mode - 0, // security attributes - OPEN_EXISTING, - 0, // flags and attributes - INVALID_HANDLE_VALUE); -} - -int PerformQuery(HANDLE adapter_handle, - std::vector<char>& buffer, - DWORD* bytes_out) { - DWORD oid = OID_802_11_BSSID_LIST; - if (!DeviceIoControl(adapter_handle, - IOCTL_NDIS_QUERY_GLOBAL_STATS, - &oid, - sizeof(oid), - &buffer[0], - buffer.size(), - bytes_out, - NULL)) { - return GetLastError(); - } - return ERROR_SUCCESS; -} - -bool ResizeBuffer(size_t requested_size, std::vector<char>& buffer) { - if (requested_size > kMaximumBufferSize) { - buffer.resize(kInitialBufferSize); - return false; - } - - buffer.resize(requested_size); - return true; -} - -} // namespace - - -nsresult -WinXPWifiScanner::GetAccessPointsFromWLAN(nsCOMArray<nsWifiAccessPoint> &accessPoints) -{ - if (!mImplementation) { - mImplementation = WindowsNdisApi::Create(); - if (!mImplementation) { - return NS_ERROR_FAILURE; - } - } - - accessPoints.Clear(); - bool isOk = mImplementation->GetAccessPointData(accessPoints); - if (!isOk) { - mImplementation = 0; - return NS_ERROR_FAILURE; - } - - return NS_OK; -} diff --git a/netwerk/wifi/win_xp_wifiScanner.h b/netwerk/wifi/win_xp_wifiScanner.h deleted file mode 100644 index 33ae4cae4..000000000 --- a/netwerk/wifi/win_xp_wifiScanner.h +++ /dev/null @@ -1,25 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public -* License, v. 2.0. If a copy of the MPL was not distributed with this -* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef WINXPWIFISCANNER_H_ -#define WINXPWIFISCANNER_H_ - -#include "nsAutoPtr.h" -#include "nsCOMArray.h" -#include "win_wifiScanner.h" - -class nsWifiAccessPoint; -class WindowsNdisApi; - -// This class is wrapper into the Chromium WindowNdisApi class for scanning wifis -// on Windows XP. When Firefox drops XP support, this code can go. -class WinXPWifiScanner : public WindowsWifiScannerInterface { -public: - nsresult GetAccessPointsFromWLAN(nsCOMArray<nsWifiAccessPoint> &accessPoints); - virtual ~WinXPWifiScanner() {} -private: - nsAutoPtr<WindowsNdisApi> mImplementation; -}; - -#endif
\ No newline at end of file |