summaryrefslogtreecommitdiffstats
path: root/netwerk
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk')
-rw-r--r--netwerk/base/Dashboard.cpp16
-rw-r--r--netwerk/base/LoadInfo.cpp6
-rw-r--r--netwerk/base/LoadInfo.h1
-rw-r--r--netwerk/base/nsICryptoHash.idl3
-rw-r--r--netwerk/base/nsISocketTransport.idl2
-rw-r--r--netwerk/base/nsITimedChannel.idl2
-rw-r--r--netwerk/base/nsLoadGroup.cpp13
-rw-r--r--netwerk/base/nsSocketTransport2.cpp16
-rw-r--r--netwerk/base/nsSocketTransportService2.cpp11
-rw-r--r--netwerk/base/nsStandardURL.cpp13
-rw-r--r--netwerk/base/rust-url-capi/.gitignore2
-rw-r--r--netwerk/base/rust-url-capi/Cargo.toml19
-rw-r--r--netwerk/base/rust-url-capi/src/error_mapping.rs68
-rw-r--r--netwerk/base/rust-url-capi/src/lib.rs477
-rw-r--r--netwerk/base/rust-url-capi/src/rust-url-capi.h45
-rw-r--r--netwerk/base/rust-url-capi/src/string_utils.rs57
-rw-r--r--netwerk/base/rust-url-capi/test/Makefile4
-rw-r--r--netwerk/base/rust-url-capi/test/test.cpp141
-rw-r--r--netwerk/base/security-prefs.js2
-rw-r--r--netwerk/ipc/NeckoMessageUtils.h13
-rw-r--r--netwerk/locales/en-US/necko.properties2
-rw-r--r--netwerk/protocol/ftp/nsFtpConnectionThread.cpp2
-rw-r--r--netwerk/protocol/http/ASpdySession.cpp5
-rw-r--r--netwerk/protocol/http/ASpdySession.h3
-rw-r--r--netwerk/protocol/http/Http2Session.cpp170
-rw-r--r--netwerk/protocol/http/Http2Session.h9
-rw-r--r--netwerk/protocol/http/Http2Stream.cpp40
-rw-r--r--netwerk/protocol/http/Http2Stream.h7
-rw-r--r--netwerk/protocol/http/HttpBaseChannel.cpp15
-rw-r--r--netwerk/protocol/http/HttpChannelChild.cpp1
-rw-r--r--netwerk/protocol/http/HttpChannelParent.cpp3
-rw-r--r--netwerk/protocol/http/HttpChannelParent.h2
-rw-r--r--netwerk/protocol/http/NullHttpChannel.cpp8
-rw-r--r--netwerk/protocol/http/NullHttpTransaction.cpp24
-rw-r--r--netwerk/protocol/http/NullHttpTransaction.h4
-rw-r--r--netwerk/protocol/http/TimingStruct.h1
-rw-r--r--netwerk/protocol/http/nsAHttpTransaction.h5
-rw-r--r--netwerk/protocol/http/nsHttpChannel.cpp35
-rw-r--r--netwerk/protocol/http/nsHttpChannel.h1
-rw-r--r--netwerk/protocol/http/nsHttpConnection.cpp254
-rw-r--r--netwerk/protocol/http/nsHttpConnection.h15
-rw-r--r--netwerk/protocol/http/nsHttpConnectionMgr.cpp5
-rw-r--r--netwerk/protocol/http/nsHttpHandler.cpp83
-rw-r--r--netwerk/protocol/http/nsHttpHandler.h4
-rw-r--r--netwerk/protocol/http/nsHttpTransaction.cpp91
-rw-r--r--netwerk/protocol/http/nsHttpTransaction.h7
-rw-r--r--netwerk/sctp/datachannel/DataChannel.cpp5
-rw-r--r--netwerk/test/TestUDPSocket.cpp13
-rw-r--r--netwerk/test/mochitests/mochitest.ini1
-rw-r--r--netwerk/test/mochitests/test_1396395.html52
-rw-r--r--netwerk/wifi/moz.build1
-rw-r--r--netwerk/wifi/nsWifiMonitor.h2
-rw-r--r--netwerk/wifi/nsWifiScannerWin.cpp11
-rw-r--r--netwerk/wifi/win_wifiScanner.h13
-rw-r--r--netwerk/wifi/win_xp_wifiScanner.cpp399
-rw-r--r--netwerk/wifi/win_xp_wifiScanner.h25
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