Merge inbound and m-c.

This commit is contained in:
Ryan VanderMeulen 2013-07-01 08:12:24 -04:00
commit c6e480b87f
64 changed files with 2746 additions and 421 deletions

View File

@ -605,6 +605,9 @@
@BINPATH@/res/EditorOverride.css
@BINPATH@/res/contenteditable.css
@BINPATH@/res/designmode.css
@BINPATH@/res/ImageDocument.css
@BINPATH@/res/TopLevelImageDocument.css
@BINPATH@/res/TopLevelVideoDocument.css
@BINPATH@/res/table-add-column-after-active.gif
@BINPATH@/res/table-add-column-after-hover.gif
@BINPATH@/res/table-add-column-after.gif

View File

@ -516,6 +516,41 @@ BrowserGlue.prototype = {
nb.PRIORITY_INFO_LOW, buttons);
},
/**
* Show a notification bar offering a reset if the profile has been unused for some time.
*/
_resetUnusedProfileNotification: function () {
let win = this.getMostRecentBrowserWindow();
if (!win)
return;
Cu.import("resource://gre/modules/ResetProfile.jsm");
if (!ResetProfile.resetSupported())
return;
let productName = Services.strings
.createBundle("chrome://branding/locale/brand.properties")
.GetStringFromName("brandShortName");
let resetBundle = Services.strings
.createBundle("chrome://global/locale/resetProfile.properties");
let message = resetBundle.formatStringFromName("resetUnusedProfile.message", [productName], 1);
let buttons = [
{
label: resetBundle.formatStringFromName("resetProfile.resetButton.label", [productName], 1),
accessKey: resetBundle.GetStringFromName("resetProfile.resetButton.accesskey"),
callback: function () {
ResetProfile.openConfirmationDialog(win);
}
},
];
let nb = win.document.getElementById("global-notificationbox");
nb.appendNotification(message, "reset-unused-profile",
"chrome://global/skin/icons/question-16.png",
nb.PRIORITY_INFO_LOW, buttons);
},
// the first browser window has finished initializing
_onFirstWindowLoaded: function BG__onFirstWindowLoaded() {
#ifdef XP_WIN
@ -530,6 +565,15 @@ BrowserGlue.prototype = {
#endif
this._trackSlowStartup();
// Offer to reset a user's profile if it hasn't been used for 60 days.
const OFFER_PROFILE_RESET_INTERVAL_MS = 60 * 24 * 60 * 60 * 1000;
let processStartupTime = Services.startup.getStartupInfo().process;
let lastUse = Services.appinfo.replacedLockTime;
if (processStartupTime && lastUse &&
processStartupTime.getTime() - lastUse >= OFFER_PROFILE_RESET_INTERVAL_MS) {
this._resetUnusedProfileNotification();
}
},
/**

View File

@ -4,7 +4,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/ForgetAboutSite.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ForgetAboutSite",
"resource://gre/modules/ForgetAboutSite.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");

View File

@ -4,8 +4,10 @@
* 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/. */
#include "mozilla/MemoryReporting.h"
#include "nsNullPrincipalURI.h"
#include "mozilla/MemoryReporting.h"
#include "nsNetUtil.h"
#include "nsEscape.h"
#include "nsCRT.h"

View File

@ -4340,7 +4340,7 @@ MOZ_ARG_WITH_STRING(google-api-keyfile,
if test -z "$MOZ_GOOGLE_API_KEY"; then
MOZ_GOOGLE_API_KEY=no-google-api-key
fi
AC_DEFINE_UNQUOTED(MOZ_GOOGLE_API_KEY, $MOZ_GOOGLE_API_KEY)
AC_SUBST(MOZ_GOOGLE_API_KEY)
# Allow the application to influence configure with a confvars.sh script.
AC_MSG_CHECKING([if app-specific confvars.sh exists])

View File

@ -8,8 +8,10 @@
* the two is unified to minimize footprint.
*/
#include "mozilla/MemoryReporting.h"
#include "nsAttrAndChildArray.h"
#include "mozilla/MemoryReporting.h"
#include "nsMappedAttributeElement.h"
#include "prbit.h"
#include "nsString.h"

View File

@ -20,8 +20,10 @@
* nsIAtom pointers, and the values are void pointers.
*/
#include "mozilla/MemoryReporting.h"
#include "nsPropertyTable.h"
#include "mozilla/MemoryReporting.h"
#include "pldhash.h"
#include "nsError.h"
#include "nsIAtom.h"

View File

@ -4,8 +4,9 @@
* 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/. */
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/HTMLAnchorElement.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/HTMLAnchorElementBinding.h"
#include "nsCOMPtr.h"

View File

@ -4,8 +4,9 @@
* 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/. */
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/HTMLAreaElement.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/HTMLAreaElementBinding.h"
#include "base/compiler_specific.h"

View File

@ -3,9 +3,9 @@
* 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/. */
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/HTMLLinkElement.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/HTMLLinkElementBinding.h"
#include "base/compiler_specific.h"
#include "nsGenericHTMLElement.h"

View File

@ -3,8 +3,10 @@
* 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/. */
#include "mozilla/MemoryReporting.h"
#include "gfxDWriteFonts.h"
#include "mozilla/MemoryReporting.h"
#include "gfxDWriteShaper.h"
#include "gfxHarfBuzzShaper.h"
#include <algorithm>

View File

@ -3,8 +3,10 @@
* 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/. */
#include "mozilla/MemoryReporting.h"
#include "gfxGDIFont.h"
#include "mozilla/MemoryReporting.h"
#include "gfxGDIShaper.h"
#include "gfxUniscribeShaper.h"
#include "gfxHarfBuzzShaper.h"

View File

@ -3,8 +3,10 @@
* 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/. */
#include "mozilla/MemoryReporting.h"
#include "gfxMacFont.h"
#include "mozilla/MemoryReporting.h"
#include "gfxCoreTextShaper.h"
#include "gfxHarfBuzzShaper.h"
#include <algorithm>

View File

@ -3,9 +3,10 @@
* 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/. */
#include "mozilla/MemoryReporting.h"
#include "ImageWrapper.h"
#include "mozilla/MemoryReporting.h"
using mozilla::layers::LayerManager;
using mozilla::layers::ImageContainer;

View File

@ -3,8 +3,10 @@
* 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/. */
#include "mozilla/MemoryReporting.h"
#include "FramePropertyTable.h"
#include "mozilla/MemoryReporting.h"
#include "prlog.h"
namespace mozilla {

View File

@ -2,9 +2,10 @@
* 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/. */
#include "mozilla/MemoryReporting.h"
#include "StackArena.h"
#include "mozilla/MemoryReporting.h"
namespace mozilla {
#define STACK_ARENA_MARK_INCREMENT 50

View File

@ -3,9 +3,10 @@
* 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/. */
#include "mozilla/MemoryReporting.h"
#include "nsTextRunTransformations.h"
#include "mozilla/MemoryReporting.h"
#include "nsTextFrameUtils.h"
#include "gfxSkipChars.h"
#include "nsGkAtoms.h"

View File

@ -9,8 +9,9 @@
* declarations
*/
#include "mozilla/MemoryReporting.h"
#include "mozilla/css/StyleRule.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/css/GroupRule.h"
#include "mozilla/css/Declaration.h"
#include "nsCSSStyleSheet.h"

View File

@ -3,8 +3,10 @@
* 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/. */
#include "mozilla/MemoryReporting.h"
#include "nsAnimationManager.h"
#include "mozilla/MemoryReporting.h"
#include "nsPresContext.h"
#include "nsRuleProcessorData.h"
#include "nsStyleSet.h"

View File

@ -20,6 +20,7 @@ import org.webrtc.videoengine.VideoCaptureDeviceInfoAndroid.AndroidVideoCaptureD
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
@ -27,6 +28,10 @@ import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.TextureView;
import android.view.TextureView.SurfaceTextureListener;
import android.view.View;
import org.mozilla.gecko.GeckoApp;
import org.mozilla.gecko.GeckoAppShell;
@ -50,6 +55,7 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
private boolean isCaptureRunning = false;
private boolean isSurfaceReady = false;
private SurfaceHolder surfaceHolder = null;
private SurfaceTexture surfaceTexture = null;
private final int numCaptureBuffers = 3;
private int expectedFrameSize = 0;
@ -64,9 +70,42 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
private int mCaptureWidth = -1;
private int mCaptureHeight = -1;
private int mCaptureFPS = -1;
private int mCaptureRotation = 0;
private AppStateListener mAppStateListener = null;
public class MySurfaceTextureListener implements TextureView.SurfaceTextureListener {
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Log.d(TAG, "VideoCaptureAndroid::onSurfaceTextureAvailable");
captureLock.lock();
isSurfaceReady = true;
surfaceTexture = surface;
tryStartCapture(mCaptureWidth, mCaptureHeight, mCaptureFPS);
captureLock.unlock();
}
public void onSurfaceTextureSizeChanged(SurfaceTexture surface,
int width, int height) {
// Ignored, Camera does all the work for us
// Note that for a TextureView we start on onSurfaceTextureAvailable,
// for a SurfaceView we start on surfaceChanged. TextureView
// will not give out an onSurfaceTextureSizeChanged during creation.
}
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
Log.d(TAG, "VideoCaptureAndroid::onSurfaceTextureDestroyed");
isSurfaceReady = false;
DetachCamera();
return true;
}
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
// Invoked every time there's a new Camera preview frame
}
}
public static
void DeleteVideoCaptureAndroid(VideoCaptureAndroid captureAndroid) {
Log.d(TAG, "DeleteVideoCaptureAndroid");
@ -78,8 +117,13 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
captureAndroid.camera = null;
captureAndroid.context = 0;
GeckoAppShell.getGeckoInterface().getCameraView().getHolder().
removeCallback(captureAndroid);
View cameraView = GeckoAppShell.getGeckoInterface().getCameraView();
if (cameraView instanceof SurfaceView) {
((SurfaceView)cameraView).getHolder().removeCallback(captureAndroid);
} else if (cameraView instanceof TextureView) {
// No need to explicitly remove the Listener:
// i.e. ((SurfaceView)cameraView).setSurfaceTextureListener(null);
}
ThreadUtils.getUiHandler().post(new Runnable() {
@Override
public void run() {
@ -102,9 +146,16 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
camera = in_camera;
cameraId = in_cameraId;
currentDevice = in_device;
mCaptureRotation = GetRotateAmount();
try {
GeckoAppShell.getGeckoInterface().getCameraView().getHolder().addCallback(this);
View cameraView = GeckoAppShell.getGeckoInterface().getCameraView();
if (cameraView instanceof SurfaceView) {
((SurfaceView)cameraView).getHolder().addCallback(this);
} else if (cameraView instanceof TextureView) {
MySurfaceTextureListener listener = new MySurfaceTextureListener();
((TextureView)cameraView).setSurfaceTextureListener(listener);
}
ThreadUtils.getUiHandler().post(new Runnable() {
@Override
public void run() {
@ -145,6 +196,10 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
tryStartCapture(mCaptureWidth, mCaptureHeight, mCaptureFPS);
captureLock.unlock();
}
@Override
public void onConfigurationChanged() {
mCaptureRotation = GetRotateAmount();
}
};
GeckoAppShell.getGeckoInterface().addAppStateListener(mAppStateListener);
@ -190,7 +245,10 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
}
try {
camera.setPreviewDisplay(surfaceHolder);
if (surfaceHolder != null)
camera.setPreviewDisplay(surfaceHolder);
if (surfaceTexture != null)
camera.setPreviewTexture(surfaceTexture);
CaptureCapabilityAndroid currentCapability =
new CaptureCapabilityAndroid();
@ -268,7 +326,8 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
return DetachCamera();
}
native void ProvideCameraFrame(byte[] data, int length, long captureObject);
native void ProvideCameraFrame(byte[] data, int length, int rotation,
long captureObject);
public void onPreviewFrame(byte[] data, Camera camera) {
previewBufferLock.lock();
@ -280,7 +339,8 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
// If StartCapture has been called but not StopCapture
// Call the C++ layer with the captured frame
if (data.length == expectedFrameSize) {
ProvideCameraFrame(data, expectedFrameSize, context);
ProvideCameraFrame(data, expectedFrameSize, mCaptureRotation,
context);
if (ownsBuffers) {
// Give the video buffer to the camera service again.
camera.addCallbackBuffer(data);
@ -290,46 +350,6 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
previewBufferLock.unlock();
}
// Sets the rotation of the preview render window.
// Does not affect the captured video image.
public void SetPreviewRotation(int rotation) {
Log.v(TAG, "SetPreviewRotation: " + rotation);
if (camera != null) {
previewBufferLock.lock();
int width = 0;
int height = 0;
int framerate = 0;
boolean wasCaptureRunning = isCaptureRunning;
if (isCaptureRunning) {
width = mCaptureWidth;
height = mCaptureHeight;
framerate = mCaptureFPS;
StopCapture();
}
int resultRotation = 0;
if (currentDevice.frontCameraType ==
VideoCaptureDeviceInfoAndroid.FrontFacingCameraType.Android23) {
// this is a 2.3 or later front facing camera.
// SetDisplayOrientation will flip the image horizontally
// before doing the rotation.
resultRotation=(360-rotation) % 360; // compensate the mirror
}
else {
// Back facing or 2.2 or previous front camera
resultRotation=rotation;
}
camera.setDisplayOrientation(resultRotation);
if (wasCaptureRunning) {
StartCapture(width, height, framerate);
}
previewBufferLock.unlock();
}
}
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
Log.d(TAG, "VideoCaptureAndroid::surfaceChanged");

View File

@ -92,7 +92,7 @@ WebRtc_Word32 VideoCaptureAndroid::SetAndroidObjects(void* javaVM,
return -1;
}
JNINativeMethod nativeFunctions =
{ "ProvideCameraFrame", "([BIJ)V",
{ "ProvideCameraFrame", "([BIIJ)V",
(void*) &VideoCaptureAndroid::ProvideCameraFrame };
if (env->RegisterNatives(g_javaCmClass, &nativeFunctions, 1) == 0) {
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, -1,
@ -251,11 +251,29 @@ void JNICALL VideoCaptureAndroid::ProvideCameraFrame(JNIEnv * env,
jobject,
jbyteArray javaCameraFrame,
jint length,
jint rotation,
jlong context) {
VideoCaptureAndroid* captureModule =
reinterpret_cast<VideoCaptureAndroid*>(context);
WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideoCapture,
-1, "%s: IncomingFrame %d", __FUNCTION__,length);
switch (rotation) {
case 90:
captureModule->SetCaptureRotation(kCameraRotate90);
break;
case 180:
captureModule->SetCaptureRotation(kCameraRotate180);
break;
case 270:
captureModule->SetCaptureRotation(kCameraRotate270);
break;
case 0:
default:
captureModule->SetCaptureRotation(kCameraRotate0);
break;
}
jbyte* cameraFrame= env->GetByteArrayElements(javaCameraFrame,NULL);
captureModule->IncomingFrame((WebRtc_UWord8*) cameraFrame,
length,captureModule->_frameInfo,0);
@ -451,7 +469,6 @@ WebRtc_Word32 VideoCaptureAndroid::StartCapture(
bool isAttached = false;
WebRtc_Word32 result = 0;
WebRtc_Word32 rotation = 0;
// get the JNI env for this thread
JNIEnv *env;
if (g_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
@ -498,21 +515,6 @@ WebRtc_Word32 VideoCaptureAndroid::StartCapture(
"%s: Failed to find StartCapture id", __FUNCTION__);
}
// get the method ID for the Android Java
// CaptureClass static GetRotateAmount method.
cid = env->GetMethodID(g_javaCmClass, "GetRotateAmount", "()I");
if (cid != NULL) {
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, -1,
"%s: Call GetRotateAmount", __FUNCTION__);
rotation = env->CallIntMethod(_javaCaptureObj, cid);
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, -1,
"%s, GetRotateAmount = %d", __FUNCTION__, rotation);
}
else {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1,
"%s: Failed to find GetRotateAmount id", __FUNCTION__);
}
// Detach this thread if it was attached
if (isAttached) {
if (g_jvm->DetachCurrentThread() < 0) {
@ -521,22 +523,6 @@ WebRtc_Word32 VideoCaptureAndroid::StartCapture(
}
}
switch (rotation) {
case 90:
SetCaptureRotation(kCameraRotate90);
break;
case 180:
SetCaptureRotation(kCameraRotate180);
break;
case 270:
SetCaptureRotation(kCameraRotate270);
break;
case 0:
default:
SetCaptureRotation(kCameraRotate0);
break;
}
if (result == 0) {
_requestedCapability = capability;
_captureStarted = true;
@ -618,65 +604,7 @@ WebRtc_Word32 VideoCaptureAndroid::CaptureSettings(
WebRtc_Word32 VideoCaptureAndroid::SetCaptureRotation(
VideoCaptureRotation rotation) {
CriticalSectionScoped cs(&_apiCs);
if (VideoCaptureImpl::SetCaptureRotation(rotation) == 0) {
if (!g_jvm)
return -1;
// get the JNI env for this thread
JNIEnv *env;
bool isAttached = false;
// get the JNI env for this thread
if (g_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
// try to attach the thread and get the env
// Attach this thread to JVM
jint res = g_jvm->AttachCurrentThread(&env, NULL);
if ((res < 0) || !env) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture,
_id,
"%s: Could not attach thread to JVM (%d, %p)",
__FUNCTION__, res, env);
return -1;
}
isAttached = true;
}
jmethodID cid = env->GetMethodID(g_javaCmClass, "SetPreviewRotation",
"(I)V");
if (cid == NULL) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1,
"%s: could not get java SetPreviewRotation ID",
__FUNCTION__);
return -1;
}
jint rotateFrame = 0;
switch (rotation) {
case kCameraRotate0:
rotateFrame = 0;
break;
case kCameraRotate90:
rotateFrame = 90;
break;
case kCameraRotate180:
rotateFrame = 180;
break;
case kCameraRotate270:
rotateFrame = 270;
break;
}
env->CallVoidMethod(_javaCaptureObj, cid, rotateFrame);
// Detach this thread if it was attached
if (isAttached) {
if (g_jvm->DetachCurrentThread() < 0) {
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioDevice,
_id, "%s: Could not detach thread from JVM",
__FUNCTION__);
}
}
}
return 0;
return VideoCaptureImpl::SetCaptureRotation(rotation);
}
} // namespace videocapturemodule

View File

@ -47,7 +47,9 @@ class VideoCaptureAndroid : public VideoCaptureImpl {
static void JNICALL ProvideCameraFrame (JNIEnv * env,
jobject,
jbyteArray javaCameraFrame,
jint length, jlong context);
jint length,
jint rotation,
jlong context);
DeviceInfoAndroid _capInfo;
jobject _javaCaptureObj; // Java Camera object.
VideoCaptureCapability _frameInfo;

View File

@ -83,6 +83,7 @@ import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
@ -163,7 +164,7 @@ abstract public class GeckoApp
protected RelativeLayout mMainLayout;
protected RelativeLayout mGeckoLayout;
public View getView() { return mGeckoLayout; }
public SurfaceView mCameraView;
private View mCameraView;
public List<GeckoAppShell.AppStateListener> mAppStateListeners;
private static GeckoApp sAppContext;
protected MenuPanel mMenuPanel;
@ -257,7 +258,7 @@ abstract public class GeckoApp
return GeckoApp.sAppContext.getSharedPreferences(PREFS_NAME, 0);
}
public SurfaceView getCameraView() {
public View getCameraView() {
return mCameraView;
}
@ -1303,8 +1304,12 @@ abstract public class GeckoApp
mFormAssistPopup = (FormAssistPopup) findViewById(R.id.form_assist_popup);
if (mCameraView == null) {
mCameraView = new SurfaceView(this);
mCameraView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
mCameraView = new SurfaceView(this);
((SurfaceView)mCameraView).getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
} else {
mCameraView = new TextureView(this);
}
}
if (mLayerView == null) {
@ -1688,12 +1693,23 @@ abstract public class GeckoApp
}
public void enableCameraView() {
if (mCameraView instanceof SurfaceView) {
// Try to make it fully transparent.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mCameraView.setAlpha(0.0f);
}
} else if (mCameraView instanceof TextureView) {
mCameraView.setAlpha(0.0f);
}
RelativeLayout mCameraLayout = (RelativeLayout) findViewById(R.id.camera_layout);
// Some phones (eg. nexus S) need at least a 8x16 preview size
mMainLayout.addView(mCameraView, new AbsoluteLayout.LayoutParams(8, 16, 0, 0));
mCameraLayout.addView(mCameraView,
new AbsoluteLayout.LayoutParams(8, 16, 0, 0));
}
public void disableCameraView() {
mMainLayout.removeView(mCameraView);
RelativeLayout mCameraLayout = (RelativeLayout) findViewById(R.id.camera_layout);
mCameraLayout.removeView(mCameraView);
}
public String getDefaultUAString() {
@ -2060,6 +2076,12 @@ abstract public class GeckoApp
mFormAssistPopup.hide();
refreshChrome();
}
if (mAppStateListeners != null) {
for (GeckoAppShell.AppStateListener listener: mAppStateListeners) {
listener.onConfigurationChanged();
}
}
}
@Override

View File

@ -69,6 +69,7 @@ import android.view.ContextThemeWrapper;
import android.view.HapticFeedbackConstants;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.TextureView;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.webkit.MimeTypeMap;
@ -1964,6 +1965,7 @@ public class GeckoAppShell
public interface AppStateListener {
public void onPause();
public void onResume();
public void onConfigurationChanged();
}
public interface GeckoInterface {
@ -1981,7 +1983,7 @@ public class GeckoAppShell
public void disableCameraView();
public void addAppStateListener(AppStateListener listener);
public void removeAppStateListener(AppStateListener listener);
public SurfaceView getCameraView();
public View getCameraView();
public void notifyWakeLockChanged(String topic, String state);
public FormAssistPopup getFormAssistPopup();
public boolean areTabsShown();
@ -2070,12 +2072,18 @@ public class GeckoAppShell
}
try {
if (getGeckoInterface() != null)
sCamera.setPreviewDisplay(getGeckoInterface().getCameraView().getHolder());
if (getGeckoInterface() != null) {
View cameraView = getGeckoInterface().getCameraView();
if (cameraView instanceof SurfaceView) {
sCamera.setPreviewDisplay(((SurfaceView)cameraView).getHolder());
} else if (cameraView instanceof TextureView) {
sCamera.setPreviewTexture(((TextureView)cameraView).getSurfaceTexture());
}
}
} catch(IOException e) {
Log.w(LOGTAG, "Error setPreviewDisplay:", e);
Log.w(LOGTAG, "Error setPreviewXXX:", e);
} catch(RuntimeException e) {
Log.w(LOGTAG, "Error setPreviewDisplay:", e);
Log.w(LOGTAG, "Error setPreviewXXX:", e);
}
sCamera.setParameters(params);

View File

@ -35,6 +35,13 @@
style="@style/FindBar"
android:visibility="gone"/>
<RelativeLayout android:id="@+id/camera_layout"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true">
</RelativeLayout>
<org.mozilla.gecko.BrowserToolbar android:id="@+id/browser_toolbar"
style="@style/BrowserToolbar"
android:layout_width="fill_parent"

View File

@ -12,8 +12,10 @@ pref("security.ssl.renego_unrestricted_hosts", "");
pref("security.ssl.treat_unsafe_negotiation_as_broken", false);
pref("security.ssl.require_safe_negotiation", false);
pref("security.ssl.warn_missing_rfc5746", 1);
pref("security.ssl.enable_false_start", false);
pref("security.ssl.enable_ocsp_stapling", true);
pref("security.ssl.enable_false_start", true);
pref("security.ssl.false_start.require-npn", true);
pref("security.ssl.false_start.require-forward-secrecy", false);
pref("security.ssl3.rsa_rc4_128_md5", true);
pref("security.ssl3.rsa_rc4_128_sha", true);

View File

@ -127,8 +127,8 @@ nsHttpConnection::PrintDiagnostics(nsCString &log)
{
log.AppendPrintf(" CanDirectlyActivate = %d\n", CanDirectlyActivate());
log.AppendPrintf(" npncomplete = %d setupNPNCalled = %d\n",
mNPNComplete, mSetupNPNCalled);
log.AppendPrintf(" npncomplete = %d setupSSLCalled = %d\n",
mNPNComplete, mSetupSSLCalled);
log.AppendPrintf(" spdyVersion = %d reportedSpdy = %d everspdy = %d\n",
mUsingSpdyVersion, mReportedSpdy, mEverUsedSpdy);

View File

@ -58,6 +58,11 @@ typedef uint8_t nsHttpVersion;
// group is currently blocking on some resources
#define NS_HTTP_LOAD_UNBLOCKED (1<<8)
// These flags allow a transaction to use TLS false start with
// weaker security profiles based on past history
#define NS_HTTP_ALLOW_RSA_FALSESTART (1<<9)
#define NS_HTTP_ALLOW_RC4_FALSESTART (1<<10)
//-----------------------------------------------------------------------------
// some default values
//-----------------------------------------------------------------------------

View File

@ -40,6 +40,14 @@
#include "NullHttpTransaction.h"
#include "mozilla/Attributes.h"
#include "mozilla/VisualEventTracer.h"
#include "nsISSLSocketControl.h"
#include "sslt.h"
#include "nsContentUtils.h"
#include "nsIPermissionManager.h"
#include "nsIPrincipal.h"
#include "nsIScriptSecurityManager.h"
#include "nsISSLStatus.h"
#include "nsISSLStatusProvider.h"
namespace mozilla { namespace net {
@ -391,6 +399,7 @@ nsHttpChannel::Connect()
return NS_ERROR_UNKNOWN_HOST;
// Consider opening a TCP connection right away
RetrieveSSLOptions();
SpeculativeConnect();
// Don't allow resuming when cache must be used
@ -527,8 +536,9 @@ nsHttpChannel::SpeculativeConnect()
mConnectionInfo->SetAnonymous((mLoadFlags & LOAD_ANONYMOUS) != 0);
mConnectionInfo->SetPrivate(mPrivateBrowsing);
gHttpHandler->SpeculativeConnect(mConnectionInfo,
callbacks);
gHttpHandler->SpeculativeConnect(
mConnectionInfo, callbacks,
mCaps & (NS_HTTP_ALLOW_RSA_FALSESTART | NS_HTTP_ALLOW_RC4_FALSESTART | NS_HTTP_DISALLOW_SPDY));
}
void
@ -693,6 +703,37 @@ nsHttpChannel::SetupTransactionLoadGroupInfo()
mTransaction->SetLoadGroupConnectionInfo(ci);
}
void
nsHttpChannel::RetrieveSSLOptions()
{
if (!IsHTTPS() || mPrivateBrowsing)
return;
nsIPrincipal *principal = GetPrincipal();
if (!principal)
return;
nsCOMPtr<nsIPermissionManager> permMgr =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
if (!permMgr)
return;
uint32_t perm;
nsresult rv = permMgr->TestPermissionFromPrincipal(principal,
"falsestart-rsa", &perm);
if (NS_SUCCEEDED(rv) && perm == nsIPermissionManager::ALLOW_ACTION) {
LOG(("nsHttpChannel::RetrieveSSLOptions [this=%p] "
"falsestart-rsa permission found\n", this));
mCaps |= NS_HTTP_ALLOW_RSA_FALSESTART;
}
rv = permMgr->TestPermissionFromPrincipal(principal, "falsestart-rc4", &perm);
if (NS_SUCCEEDED(rv) && perm == nsIPermissionManager::ALLOW_ACTION) {
LOG(("nsHttpChannel::RetrieveSSLOptions [this=%p] "
"falsestart-rc4 permission found\n", this));
mCaps |= NS_HTTP_ALLOW_RC4_FALSESTART;
}
}
nsresult
nsHttpChannel::SetupTransaction()
{
@ -1160,6 +1201,89 @@ nsHttpChannel::ProcessSTSHeader()
return NS_OK;
}
bool
nsHttpChannel::IsHTTPS()
{
bool isHttps;
if (NS_FAILED(mURI->SchemeIs("https", &isHttps)) || !isHttps)
return false;
return true;
}
void
nsHttpChannel::ProcessSSLInformation()
{
// If this is HTTPS, record any use of RSA so that Key Exchange Algorithm
// can be whitelisted for TLS False Start in future sessions. We could
// do the same for DH but its rarity doesn't justify the lookup.
// Also do the same for RC4 symmetric ciphers.
if (mCanceled || NS_FAILED(mStatus) || !mSecurityInfo ||
!IsHTTPS() || mPrivateBrowsing)
return;
nsCOMPtr<nsISSLSocketControl> ssl = do_QueryInterface(mSecurityInfo);
nsCOMPtr<nsISSLStatusProvider> statusProvider =
do_QueryInterface(mSecurityInfo);
if (!ssl || !statusProvider)
return;
nsCOMPtr<nsISSLStatus> sslstat;
statusProvider->GetSSLStatus(getter_AddRefs(sslstat));
if (!sslstat)
return;
// If certificate exceptions are being used don't record this information
// in the permission manager.
bool trustCheck;
if (NS_FAILED(sslstat->GetIsDomainMismatch(&trustCheck)) || trustCheck)
return;
if (NS_FAILED(sslstat->GetIsNotValidAtThisTime(&trustCheck)) || trustCheck)
return;
if (NS_FAILED(sslstat->GetIsUntrusted(&trustCheck)) || trustCheck)
return;
int16_t kea = ssl->GetKEAUsed();
int16_t symcipher = ssl->GetSymmetricCipherUsed();
nsIPrincipal *principal = GetPrincipal();
if (!principal)
return;
// set a permission manager flag that future transactions can
// use via RetrieveSSLOptions(()
nsCOMPtr<nsIPermissionManager> permMgr =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
if (!permMgr)
return;
// Allow this to stand for a week
int64_t expireTime = (PR_Now() / PR_USEC_PER_MSEC) +
(86400 * 7 * PR_MSEC_PER_SEC);
if (kea == ssl_kea_rsa) {
permMgr->AddFromPrincipal(principal, "falsestart-rsa",
nsIPermissionManager::ALLOW_ACTION,
nsIPermissionManager::EXPIRE_TIME,
expireTime);
LOG(("nsHttpChannel::ProcessSSLInformation [this=%p] "
"falsestart-rsa permission granted for this host\n", this));
} else {
permMgr->RemoveFromPrincipal(principal, "falsestart-rsa");
}
if (symcipher == ssl_calg_rc4) {
permMgr->AddFromPrincipal(principal, "falsestart-rc4",
nsIPermissionManager::ALLOW_ACTION,
nsIPermissionManager::EXPIRE_TIME,
expireTime);
LOG(("nsHttpChannel::ProcessSSLInformation [this=%p] "
"falsestart-rc4 permission granted for this host\n", this));
} else {
permMgr->RemoveFromPrincipal(principal, "falsestart-rc4");
}
}
nsresult
nsHttpChannel::ProcessResponse()
{
@ -1192,6 +1316,8 @@ nsHttpChannel::ProcessResponse()
MOZ_ASSERT(!mCachedContentIsValid);
ProcessSSLInformation();
// notify "http-on-examine-response" observers
gHttpHandler->OnExamineResponse(this);
@ -6037,6 +6163,30 @@ nsHttpChannel::ShouldSkipCache()
return true;
}
nsIPrincipal *
nsHttpChannel::GetPrincipal()
{
if (mPrincipal)
return mPrincipal;
nsIScriptSecurityManager *securityManager =
nsContentUtils::GetSecurityManager();
if (!securityManager)
return nullptr;
securityManager->GetChannelPrincipal(this, getter_AddRefs(mPrincipal));
if (!mPrincipal)
return nullptr;
// principals with unknown app ids do not work with the permission manager
if (mPrincipal->GetUnknownAppId())
mPrincipal = nullptr;
return mPrincipal;
}
NS_IMETHODIMP
nsHttpChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
{

View File

@ -34,6 +34,7 @@
#include "mozilla/Telemetry.h"
class nsAHttpConnection;
class nsIPrincipal;
namespace mozilla { namespace net {
@ -174,6 +175,9 @@ private:
nsresult ContinueProcessFallback(nsresult);
void HandleAsyncAbort();
nsresult EnsureAssocReq();
void ProcessSSLInformation();
bool IsHTTPS();
void RetrieveSSLOptions();
nsresult ContinueOnStartRequest1(nsresult);
nsresult ContinueOnStartRequest2(nsresult);
@ -373,6 +377,10 @@ protected:
private: // cache telemetry
bool mDidReval;
private:
nsIPrincipal *GetPrincipal();
nsCOMPtr<nsIPrincipal> mPrincipal;
};
} } // namespace mozilla::net

View File

@ -17,6 +17,7 @@
#include "nsISocketTransport.h"
#include "nsIServiceManager.h"
#include "nsISSLSocketControl.h"
#include "sslt.h"
#include "nsStringStream.h"
#include "netCore.h"
#include "nsNetCID.h"
@ -64,11 +65,12 @@ nsHttpConnection::nsHttpConnection()
, mRemainingConnectionUses(0xffffffff)
, mClassification(nsAHttpTransaction::CLASS_GENERAL)
, mNPNComplete(false)
, mSetupNPNCalled(false)
, mSetupSSLCalled(false)
, mUsingSpdyVersion(0)
, mPriority(nsISupportsPriority::PRIORITY_NORMAL)
, mReportedSpdy(false)
, mEverUsedSpdy(false)
, mTransactionCaps(0)
{
LOG(("Creating nsHttpConnection @%x\n", this));
@ -236,8 +238,6 @@ nsHttpConnection::StartSpdy(uint8_t spdyVersion)
bool
nsHttpConnection::EnsureNPNComplete()
{
// NPN is only used by SPDY right now.
//
// If for some reason the components to check on NPN aren't available,
// this function will just return true to continue on and disable SPDY
@ -308,6 +308,7 @@ nsHttpConnection::Activate(nsAHttpTransaction *trans, uint32_t caps, int32_t pri
LOG(("nsHttpConnection::Activate [this=%p trans=%x caps=%x]\n",
this, trans, caps));
mTransactionCaps = caps;
mPriority = pri;
if (mTransaction && mUsingSpdyVersion)
return AddTransaction(trans, pri);
@ -323,7 +324,7 @@ nsHttpConnection::Activate(nsAHttpTransaction *trans, uint32_t caps, int32_t pri
trans->GetSecurityCallbacks(getter_AddRefs(callbacks));
SetSecurityCallbacks(callbacks);
SetupNPN(caps); // only for spdy
SetupSSL(caps);
// take ownership of the transaction
mTransaction = trans;
@ -360,55 +361,70 @@ failed_activation:
}
void
nsHttpConnection::SetupNPN(uint32_t caps)
nsHttpConnection::SetupSSL(uint32_t caps)
{
if (mSetupNPNCalled) /* do only once */
LOG(("nsHttpConnection::SetupSSL %p caps=0x%X\n", this, caps));
if (mSetupSSLCalled) // do only once
return;
mSetupNPNCalled = true;
mSetupSSLCalled = true;
// Setup NPN Negotiation if necessary (only for SPDY)
if (!mNPNComplete) {
if (mNPNComplete)
return;
mNPNComplete = true;
// we flip this back to false if SetNPNList succeeds at the end
// of this function
mNPNComplete = true;
if (mConnInfo->UsingSSL()) {
LOG(("nsHttpConnection::SetupNPN Setting up "
"Next Protocol Negotiation"));
nsCOMPtr<nsISupports> securityInfo;
nsresult rv =
mSocketTransport->GetSecurityInfo(getter_AddRefs(securityInfo));
if (NS_FAILED(rv))
return;
if (!mConnInfo->UsingSSL())
return;
nsCOMPtr<nsISSLSocketControl> ssl =
do_QueryInterface(securityInfo, &rv);
if (NS_FAILED(rv))
return;
LOG(("nsHttpConnection::SetupSSL Setting up "
"Next Protocol Negotiation"));
nsCOMPtr<nsISupports> securityInfo;
nsresult rv =
mSocketTransport->GetSecurityInfo(getter_AddRefs(securityInfo));
if (NS_FAILED(rv))
return;
nsTArray<nsCString> protocolArray;
nsCOMPtr<nsISSLSocketControl> ssl = do_QueryInterface(securityInfo, &rv);
if (NS_FAILED(rv))
return;
// The first protocol is used as the fallback if none of the
// protocols supported overlap with the server's list.
// In the case of overlap, matching priority is driven by
// the order of the server's advertisement.
protocolArray.AppendElement(NS_LITERAL_CSTRING("http/1.1"));
if (caps & NS_HTTP_ALLOW_RSA_FALSESTART) {
LOG(("nsHttpConnection::SetupSSL %p "
">= RSA Key Exchange Expected\n", this));
ssl->SetKEAExpected(ssl_kea_rsa);
}
if (gHttpHandler->IsSpdyEnabled() &&
!(caps & NS_HTTP_DISALLOW_SPDY)) {
LOG(("nsHttpConnection::SetupNPN Allow SPDY NPN selection"));
if (gHttpHandler->SpdyInfo()->ProtocolEnabled(0))
protocolArray.AppendElement(
gHttpHandler->SpdyInfo()->VersionString[0]);
if (gHttpHandler->SpdyInfo()->ProtocolEnabled(1))
protocolArray.AppendElement(
gHttpHandler->SpdyInfo()->VersionString[1]);
}
if (caps & NS_HTTP_ALLOW_RC4_FALSESTART) {
LOG(("nsHttpConnection::SetupSSL %p "
">= RC4 Key Exchange Expected\n", this));
ssl->SetSymmetricCipherExpected(ssl_calg_rc4);
}
if (NS_SUCCEEDED(ssl->SetNPNList(protocolArray))) {
LOG(("nsHttpConnection::Init Setting up SPDY Negotiation OK"));
mNPNComplete = false;
}
}
nsTArray<nsCString> protocolArray;
// The first protocol is used as the fallback if none of the
// protocols supported overlap with the server's list.
// In the case of overlap, matching priority is driven by
// the order of the server's advertisement.
protocolArray.AppendElement(NS_LITERAL_CSTRING("http/1.1"));
if (gHttpHandler->IsSpdyEnabled() &&
!(caps & NS_HTTP_DISALLOW_SPDY)) {
LOG(("nsHttpConnection::SetupSSL Allow SPDY NPN selection"));
if (gHttpHandler->SpdyInfo()->ProtocolEnabled(0))
protocolArray.AppendElement(
gHttpHandler->SpdyInfo()->VersionString[0]);
if (gHttpHandler->SpdyInfo()->ProtocolEnabled(1))
protocolArray.AppendElement(
gHttpHandler->SpdyInfo()->VersionString[1]);
}
if (NS_SUCCEEDED(ssl->SetNPNList(protocolArray))) {
LOG(("nsHttpConnection::Init Setting up SPDY Negotiation OK"));
mNPNComplete = false;
}
}
@ -596,7 +612,7 @@ nsHttpConnection::IsAlive()
// SocketTransport::IsAlive can run the SSL state machine, so make sure
// the NPN options are set before that happens.
SetupNPN(0);
SetupSSL(mTransactionCaps);
bool alive;
nsresult rv = mSocketTransport->IsAlive(&alive);

View File

@ -158,6 +158,7 @@ public:
void SetSecurityCallbacks(nsIInterfaceRequestor* aCallbacks);
void PrintDiagnostics(nsCString &log);
void SetTransactionCaps(uint32_t aCaps) { mTransactionCaps = aCaps; }
private:
// called to cause the underlying socket to start speaking SSL
nsresult ProxyStartSSL();
@ -175,7 +176,7 @@ private:
// Makes certain the SSL handshake is complete and NPN negotiation
// has had a chance to happen
bool EnsureNPNComplete();
void SetupNPN(uint32_t caps);
void SetupSSL(uint32_t caps);
// Start the Spdy transaction handler when NPN indicates spdy/*
void StartSpdy(uint8_t versionLevel);
@ -240,7 +241,7 @@ private:
// SPDY related
bool mNPNComplete;
bool mSetupNPNCalled;
bool mSetupSSLCalled;
// version level in use, 0 if unused
uint8_t mUsingSpdyVersion;
@ -251,6 +252,9 @@ private:
// mUsingSpdyVersion is cleared when mSpdySession is freed, this is permanent
bool mEverUsedSpdy;
// The capabailities associated with the most recent transaction
uint32_t mTransactionCaps;
};
#endif // nsHttpConnection_h__

View File

@ -326,7 +326,8 @@ nsHttpConnectionMgr::DoShiftReloadConnectionCleanup(nsHttpConnectionInfo *aCI)
nsresult
nsHttpConnectionMgr::SpeculativeConnect(nsHttpConnectionInfo *ci,
nsIInterfaceRequestor *callbacks)
nsIInterfaceRequestor *callbacks,
uint32_t caps)
{
LOG(("nsHttpConnectionMgr::SpeculativeConnect [ci=%s]\n",
ci->HashKey().get()));
@ -336,7 +337,7 @@ nsHttpConnectionMgr::SpeculativeConnect(nsHttpConnectionInfo *ci,
nsCOMPtr<nsIInterfaceRequestor> wrappedCallbacks;
NS_NewInterfaceRequestorAggregation(callbacks, nullptr, getter_AddRefs(wrappedCallbacks));
uint32_t caps = ci->GetAnonymous() ? NS_HTTP_LOAD_ANONYMOUS : 0;
caps |= ci->GetAnonymous() ? NS_HTTP_LOAD_ANONYMOUS : 0;
nsRefPtr<NullHttpTransaction> trans =
new NullHttpTransaction(ci, wrappedCallbacks, caps);
@ -2814,6 +2815,10 @@ nsHalfOpenSocket::OnOutputStreamReady(nsIAsyncOutputStream *out)
LOG(("nsHalfOpenSocket::OnOutputStreamReady "
"Created new nshttpconnection %p\n", conn.get()));
// Some capabilities are needed before a transaciton actually gets
// scheduled (e.g. how to negotiate false start)
conn->SetTransactionCaps(mTransaction->Caps());
NetAddr peeraddr;
nsCOMPtr<nsIInterfaceRequestor> callbacks;
mTransaction->GetSecurityCallbacks(getter_AddRefs(callbacks));

View File

@ -113,7 +113,8 @@ public:
// connection manager, nor is the submitter obligated to actually submit a
// real transaction for this connectionInfo.
nsresult SpeculativeConnect(nsHttpConnectionInfo *,
nsIInterfaceRequestor *);
nsIInterfaceRequestor *,
uint32_t caps = 0);
// called when a connection is done processing a transaction. if the
// connection can be reused then it will be added to the idle list, else

View File

@ -181,9 +181,10 @@ public:
}
nsresult SpeculativeConnect(nsHttpConnectionInfo *ci,
nsIInterfaceRequestor *callbacks)
nsIInterfaceRequestor *callbacks,
uint32_t caps = 0)
{
return mConnMgr->SpeculativeConnect(ci, callbacks);
return mConnMgr->SpeculativeConnect(ci, callbacks, caps);
}
//

View File

@ -14,7 +14,7 @@ class nsCString;
%}
[ref] native nsCStringTArrayRef(nsTArray<nsCString>);
[scriptable, uuid(bb2bb490-3ba4-4254-b8f5-8b43c7b714ea)]
[scriptable, builtinclass, uuid(c5eb9af4-238c-4fc6-bdec-d5ab5e7dce68)]
interface nsISSLSocketControl : nsISupports {
attribute nsIInterfaceRequestor notificationCallbacks;
@ -52,6 +52,22 @@ interface nsISSLSocketControl : nsISupports {
in ACString hostname,
in long port);
/* The Key Exchange Algorithm and Symmetric Cipher
is used when determining whether or not to do false start.
After a handshake is complete it can be read from *Used,
before a handshake is started it may be set through *Expected.
The values correspond to the SSLKEAType and SSLCipherAlgorithm
enums in NSS or the *_UNKNOWN constant defined below.
*/
[infallible] readonly attribute short KEAUsed;
[infallible] attribute short KEAExpected;
[infallible] readonly attribute short SymmetricCipherUsed;
[infallible] attribute short SymmetricCipherExpected;
const short KEY_EXCHANGE_UNKNOWN = -1;
const short SYMMETRIC_CIPHER_UNKNOWN = -1;
/*
* The original flags from the socket provider.
*/

View File

@ -824,6 +824,186 @@ PK11PasswordPrompt(PK11SlotInfo* slot, PRBool retry, void* arg)
return runnable->mResult;
}
// call with shutdown prevention lock held
static void
PreliminaryHandshakeDone(PRFileDesc* fd)
{
nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
if (!infoObject)
return;
if (infoObject->IsPreliminaryHandshakeDone())
return;
infoObject->SetPreliminaryHandshakeDone();
infoObject->SetFirstServerHelloReceived();
// Get the NPN value.
SSLNextProtoState state;
unsigned char npnbuf[256];
unsigned int npnlen;
if (SSL_GetNextProto(fd, &state, npnbuf, &npnlen, 256) == SECSuccess) {
if (state == SSL_NEXT_PROTO_NEGOTIATED) {
infoObject->SetNegotiatedNPN(reinterpret_cast<char *>(npnbuf), npnlen);
}
else {
infoObject->SetNegotiatedNPN(nullptr, 0);
}
mozilla::Telemetry::Accumulate(Telemetry::SSL_NPN_TYPE, state);
}
else {
infoObject->SetNegotiatedNPN(nullptr, 0);
}
}
SECStatus
CanFalseStartCallback(PRFileDesc* fd, void* client_data, PRBool *canFalseStart)
{
*canFalseStart = false;
nsNSSShutDownPreventionLock locker;
nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
if (!infoObject) {
PR_SetError(PR_INVALID_STATE_ERROR, 0);
return SECFailure;
}
if (infoObject->isAlreadyShutDown()) {
MOZ_CRASH("SSL socket used after NSS shut down");
PR_SetError(PR_INVALID_STATE_ERROR, 0);
return SECFailure;
}
PreliminaryHandshakeDone(fd);
SSLChannelInfo channelInfo;
if (SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo)) != SECSuccess) {
return SECSuccess;
}
SSLCipherSuiteInfo cipherInfo;
if (SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
sizeof (cipherInfo)) != SECSuccess) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] failed - "
" KEA %d\n", fd,
static_cast<int32_t>(cipherInfo.keaType)));
return SECSuccess;
}
if (channelInfo.protocolVersion < SSL_LIBRARY_VERSION_TLS_1_0) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] failed - "
"SSL Version must be >= TLS1 %x\n", fd,
static_cast<int32_t>(channelInfo.protocolVersion)));
return SECSuccess;
}
// never do false start without one of these key exchange algorithms
if (cipherInfo.keaType != ssl_kea_rsa &&
cipherInfo.keaType != ssl_kea_dh &&
cipherInfo.keaType != ssl_kea_ecdh) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] failed - "
"unsupported KEA %d\n", fd,
static_cast<int32_t>(cipherInfo.keaType)));
return SECSuccess;
}
// never do false start without at least 80 bits of key material. This should
// be redundant to an NSS precondition
if (cipherInfo.effectiveKeyBits < 80) {
MOZ_CRASH("NSS is not enforcing the precondition that the effective "
"key size must be >= 80 bits for false start");
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] failed - "
"key too small %d\n", fd,
static_cast<int32_t>(cipherInfo.effectiveKeyBits)));
PR_SetError(PR_INVALID_STATE_ERROR, 0);
return SECFailure;
}
// XXX: An attacker can choose which protocols are advertised in the
// NPN extension. TODO(Bug 861311): We should restrict the ability
// of an attacker leverage this capability by restricting false start
// to the same protocol we previously saw for the server, after the
// first successful connection to the server.
// Enforce NPN to do false start if policy requires it. Do this as an
// indicator if server compatibility.
nsSSLIOLayerHelpers& helpers = infoObject->SharedState().IOLayerHelpers();
if (helpers.mFalseStartRequireNPN) {
nsAutoCString negotiatedNPN;
if (NS_FAILED(infoObject->GetNegotiatedNPN(negotiatedNPN)) ||
!negotiatedNPN.Length()) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] failed - "
"NPN cannot be verified\n", fd));
return SECSuccess;
}
}
// If we're not using eliptical curve kea then make sure we've seen the
// same kea from this host in the past, to limit the potential for downgrade
// attacks.
if (cipherInfo.keaType != ssl_kea_ecdh) {
if (helpers.mFalseStartRequireForwardSecrecy) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] failed - "
"KEA used is %d, but "
"require-forward-secrecy configured.\n",
fd, static_cast<int32_t>(cipherInfo.keaType)));
return SECSuccess;
}
int16_t expected = infoObject->GetKEAExpected();
if (cipherInfo.keaType != expected) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] failed - "
"KEA used is %d, expected %d\n", fd,
static_cast<int32_t>(cipherInfo.keaType),
static_cast<int32_t>(expected)));
return SECSuccess;
}
// whitelist the expected key exchange algorithms that are
// acceptable for false start when seen before.
if (expected != ssl_kea_rsa && expected != ssl_kea_dh &&
expected != ssl_kea_ecdh) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] failed - "
"KEA used, %d, "
"is not supported with False Start.\n",
fd, static_cast<int32_t>(expected)));
return SECSuccess;
}
}
// If we're not using AES then verify that this is the historically expected
// symmetrical cipher for this host, to limit potential for downgrade attacks.
if (cipherInfo.symCipher != ssl_calg_aes) {
int16_t expected = infoObject->GetSymmetricCipherExpected();
if (cipherInfo.symCipher != expected) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] failed - "
"Symmetric cipher used is %d, expected %d\n",
fd, static_cast<int32_t>(cipherInfo.symCipher),
static_cast<int32_t>(expected)));
return SECSuccess;
}
// whitelist the expected ciphers that are
// acceptable for false start when seen before.
if ((expected != ssl_calg_rc4) && (expected != ssl_calg_3des) &&
(expected != ssl_calg_aes)) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] failed - "
"Symmetric cipher used, %d, "
"is not supported with False Start.\n",
fd, static_cast<int32_t>(expected)));
return SECSuccess;
}
}
infoObject->NoteTimeUntilReady();
*canFalseStart = true;
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] ok\n", fd));
return SECSuccess;
}
void HandshakeCallback(PRFileDesc* fd, void* client_data) {
nsNSSShutDownPreventionLock locker;
int32_t sslStatus;
@ -834,11 +1014,14 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
// certificate validation sets FirstServerHelloReceived, so if that flag
// is absent at handshake time we have a resumed session.
// is absent at handshake time we have a resumed session. Check this before
// PreliminaryHandshakeDone() because that function also sets that flag.
bool isResumedSession = !(infoObject->GetFirstServerHelloReceived());
// This is the first callback on resumption handshakes
infoObject->SetFirstServerHelloReceived();
// Do the bookkeeping that needs to be done after the
// server's ServerHello...ServerHelloDone have been processed, but that doesn't
// need the handshake to be completed.
PreliminaryHandshakeDone(fd);
// If the handshake completed, then we know the site is TLS tolerant (if this
// was a TLS connection).
@ -930,21 +1113,6 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
status->mSecretKeyLength = encryptBits;
status->mCipherName.Assign(cipherName);
// Get the NPN value.
SSLNextProtoState state;
unsigned char npnbuf[256];
unsigned int npnlen;
if (SSL_GetNextProto(fd, &state, npnbuf, &npnlen, 256) == SECSuccess) {
if (state == SSL_NEXT_PROTO_NEGOTIATED)
infoObject->SetNegotiatedNPN(reinterpret_cast<char *>(npnbuf), npnlen);
else
infoObject->SetNegotiatedNPN(nullptr, 0);
mozilla::Telemetry::Accumulate(Telemetry::SSL_NPN_TYPE, state);
}
else
infoObject->SetNegotiatedNPN(nullptr, 0);
SSLChannelInfo channelInfo;
if (SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo)) == SECSuccess) {
// Get the protocol version for telemetry
@ -954,13 +1122,16 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
SSLCipherSuiteInfo cipherInfo;
if (SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
sizeof (cipherInfo)) == SECSuccess) {
sizeof (cipherInfo)) == SECSuccess) {
// keyExchange null=0, rsa=1, dh=2, fortezza=3, ecdh=4
Telemetry::Accumulate(Telemetry::SSL_KEY_EXCHANGE_ALGORITHM,
cipherInfo.keaType);
infoObject->SetKEAUsed(cipherInfo.keaType);
infoObject->SetSymmetricCipherUsed(cipherInfo.symCipher);
}
}
infoObject->NoteTimeUntilReady();
infoObject->SetHandshakeCompleted(isResumedSession);
PORT_Free(cipherName);

View File

@ -23,6 +23,8 @@ char*
PK11PasswordPrompt(PK11SlotInfo *slot, PRBool retry, void* arg);
void HandshakeCallback(PRFileDesc *fd, void *client_data);
SECStatus CanFalseStartCallback(PRFileDesc* fd, void* client_data,
PRBool *canFalseStart);
SECStatus RegisterMyOCSPAIAInfoCallback();
SECStatus UnregisterMyOCSPAIAInfoCallback();

View File

@ -83,12 +83,18 @@ nsNSSSocketInfo::nsNSSSocketInfo(SharedSSLState& aState, uint32_t providerFlags)
mHandshakeInProgress(false),
mAllowTLSIntoleranceTimeout(true),
mRememberClientAuthCertificate(false),
mPreliminaryHandshakeDone(false),
mHandshakeStartTime(0),
mFirstServerHelloReceived(false),
mNPNCompleted(false),
mHandshakeCompleted(false),
mJoined(false),
mSentClientCert(false),
mNotedTimeUntilReady(false),
mKEAUsed(nsISSLSocketControl::KEY_EXCHANGE_UNKNOWN),
mKEAExpected(nsISSLSocketControl::KEY_EXCHANGE_UNKNOWN),
mSymmetricCipherUsed(nsISSLSocketControl::SYMMETRIC_CIPHER_UNKNOWN),
mSymmetricCipherExpected(nsISSLSocketControl::SYMMETRIC_CIPHER_UNKNOWN),
mProviderFlags(providerFlags),
mSocketCreationTimestamp(TimeStamp::Now()),
mPlaintextBytesRead(0)
@ -106,6 +112,48 @@ nsNSSSocketInfo::GetProviderFlags(uint32_t* aProviderFlags)
return NS_OK;
}
NS_IMETHODIMP
nsNSSSocketInfo::GetKEAUsed(int16_t *aKea)
{
*aKea = mKEAUsed;
return NS_OK;
}
NS_IMETHODIMP
nsNSSSocketInfo::GetKEAExpected(int16_t *aKea)
{
*aKea = mKEAExpected;
return NS_OK;
}
NS_IMETHODIMP
nsNSSSocketInfo::SetKEAExpected(int16_t aKea)
{
mKEAExpected = aKea;
return NS_OK;
}
NS_IMETHODIMP
nsNSSSocketInfo::GetSymmetricCipherUsed(int16_t *aSymmetricCipher)
{
*aSymmetricCipher = mSymmetricCipherUsed;
return NS_OK;
}
NS_IMETHODIMP
nsNSSSocketInfo::GetSymmetricCipherExpected(int16_t *aSymmetricCipher)
{
*aSymmetricCipher = mSymmetricCipherExpected;
return NS_OK;
}
NS_IMETHODIMP
nsNSSSocketInfo::SetSymmetricCipherExpected(int16_t aSymmetricCipher)
{
mSymmetricCipherExpected = aSymmetricCipher;
return NS_OK;
}
nsresult
nsNSSSocketInfo::GetHandshakePending(bool *aHandshakePending)
{
@ -197,12 +245,27 @@ getSecureBrowserUI(nsIInterfaceRequestor * callbacks,
}
#endif
void
nsNSSSocketInfo::NoteTimeUntilReady()
{
if (mNotedTimeUntilReady)
return;
mNotedTimeUntilReady = true;
// This will include TCP and proxy tunnel wait time
Telemetry::AccumulateTimeDelta(Telemetry::SSL_TIME_UNTIL_READY,
mSocketCreationTimestamp, TimeStamp::Now());
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
("[%p] nsNSSSocketInfo::NoteTimeUntilReady\n", mFd));
}
void
nsNSSSocketInfo::SetHandshakeCompleted(bool aResumedSession)
{
if (!mHandshakeCompleted) {
// This will include TCP and proxy tunnel wait time
Telemetry::AccumulateTimeDelta(Telemetry::SSL_TIME_UNTIL_READY,
Telemetry::AccumulateTimeDelta(Telemetry::SSL_TIME_UNTIL_HANDSHAKE_FINISHED,
mSocketCreationTimestamp, TimeStamp::Now());
// If the handshake is completed for the first time from just 1 callback
@ -220,6 +283,9 @@ nsNSSSocketInfo::SetHandshakeCompleted(bool aResumedSession)
}
mHandshakeCompleted = true;
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
("[%p] nsNSSSocketInfo::SetHandshakeCompleted\n", (void*)mFd));
}
}
@ -1095,6 +1161,8 @@ nsSSLIOLayerHelpers::nsSSLIOLayerHelpers()
, mRenegoUnrestrictedSites(nullptr)
, mTreatUnsafeNegotiationAsBroken(false)
, mWarnLevelMissingRFC5746(1)
, mFalseStartRequireNPN(true)
, mFalseStartRequireForwardSecrecy(false)
{
}
@ -1285,6 +1353,12 @@ PrefObserver::Observe(nsISupports *aSubject, const char *aTopic,
int32_t warnLevel = 1;
Preferences::GetInt("security.ssl.warn_missing_rfc5746", &warnLevel);
mOwner->setWarnLevelMissingRFC5746(warnLevel);
} else if (prefName.Equals("security.ssl.false_start.require-npn")) {
Preferences::GetBool("security.ssl.false_start.require-npn",
&mOwner->mFalseStartRequireNPN);
} else if (prefName.Equals("security.ssl.false_start.require-forward-secrecy")) {
Preferences::GetBool("security.ssl.false_start.require-forward-secrecy",
&mOwner->mFalseStartRequireForwardSecrecy);
}
}
return NS_OK;
@ -1312,6 +1386,8 @@ nsSSLIOLayerHelpers::~nsSSLIOLayerHelpers()
Preferences::RemoveObserver(mPrefObserver, "security.ssl.renego_unrestricted_hosts");
Preferences::RemoveObserver(mPrefObserver, "security.ssl.treat_unsafe_negotiation_as_broken");
Preferences::RemoveObserver(mPrefObserver, "security.ssl.warn_missing_rfc5746");
Preferences::RemoveObserver(mPrefObserver, "security.ssl.false_start.require-npn");
Preferences::RemoveObserver(mPrefObserver, "security.ssl.false_start.require-forward-secrecy");
}
nsresult nsSSLIOLayerHelpers::Init()
@ -1386,6 +1462,11 @@ nsresult nsSSLIOLayerHelpers::Init()
Preferences::GetInt("security.ssl.warn_missing_rfc5746", &warnLevel);
setWarnLevelMissingRFC5746(warnLevel);
Preferences::GetBool("security.ssl.false_start.require-npn",
&mFalseStartRequireNPN);
Preferences::GetBool("security.ssl.false_start.require-forward-secrecy",
&mFalseStartRequireForwardSecrecy);
mPrefObserver = new PrefObserver(this);
Preferences::AddStrongObserver(mPrefObserver,
"security.ssl.renego_unrestricted_hosts");
@ -1393,7 +1474,10 @@ nsresult nsSSLIOLayerHelpers::Init()
"security.ssl.treat_unsafe_negotiation_as_broken");
Preferences::AddStrongObserver(mPrefObserver,
"security.ssl.warn_missing_rfc5746");
Preferences::AddStrongObserver(mPrefObserver,
"security.ssl.false_start.require-npn");
Preferences::AddStrongObserver(mPrefObserver,
"security.ssl.false_start.require-forward-secrecy");
return NS_OK;
}
@ -2479,6 +2563,7 @@ nsSSLIOLayerImportFD(PRFileDesc *fd,
}
SSL_SetPKCS11PinArg(sslSock, (nsIInterfaceRequestor*)infoObject);
SSL_HandshakeCallback(sslSock, HandshakeCallback, infoObject);
SSL_SetCanFalseStartCallback(sslSock, CanFalseStartCallback, infoObject);
// Disable this hook if we connect anonymously. See bug 466080.
uint32_t flags = 0;

View File

@ -61,6 +61,7 @@ public:
void SetNegotiatedNPN(const char *value, uint32_t length);
void SetHandshakeCompleted(bool aResumedSession);
void NoteTimeUntilReady();
bool GetJoined() { return mJoined; }
void SetSentClientCert() { mSentClientCert = true; }
@ -93,6 +94,30 @@ public:
void SetTLSEnabled(bool enabled) { mTLSEnabled = enabled; }
void AddPlaintextBytesRead(uint64_t val) { mPlaintextBytesRead += val; }
bool IsPreliminaryHandshakeDone() const { return mPreliminaryHandshakeDone; }
void SetPreliminaryHandshakeDone() { mPreliminaryHandshakeDone = true; }
void SetKEAUsed(PRUint16 kea) { mKEAUsed = kea; }
inline int16_t GetKEAExpected() // infallible in nsISSLSocketControl
{
int16_t result;
mozilla::DebugOnly<nsresult> rv = GetKEAExpected(&result);
MOZ_ASSERT(NS_SUCCEEDED(rv));
return result;
}
void SetSymmetricCipherUsed(PRUint16 symmetricCipher)
{
mSymmetricCipherUsed = symmetricCipher;
}
inline int16_t GetSymmetricCipherExpected() // infallible in nsISSLSocketControl
{
int16_t result;
mozilla::DebugOnly<nsresult> rv = GetSymmetricCipherExpected(&result);
MOZ_ASSERT(NS_SUCCEEDED(rv));
return result;
}
private:
PRFileDesc* mFd;
@ -107,6 +132,7 @@ private:
bool mHandshakeInProgress;
bool mAllowTLSIntoleranceTimeout;
bool mRememberClientAuthCertificate;
bool mPreliminaryHandshakeDone; // after false start items are complete
PRIntervalTime mHandshakeStartTime;
bool mFirstServerHelloReceived;
@ -117,6 +143,14 @@ private:
bool mHandshakeCompleted;
bool mJoined;
bool mSentClientCert;
bool mNotedTimeUntilReady;
// mKEA* and mSymmetricCipher* are used in false start detetermination
// values are from nsISSLSocketControl
PRInt16 mKEAUsed;
PRInt16 mKEAExpected;
PRInt16 mSymmetricCipherUsed;
PRInt16 mSymmetricCipherExpected;
uint32_t mProviderFlags;
mozilla::TimeStamp mSocketCreationTimestamp;
@ -164,6 +198,9 @@ public:
bool isRenegoUnrestrictedSite(const nsCString &str);
void clearStoredData();
bool mFalseStartRequireNPN;
bool mFalseStartRequireForwardSecrecy;
private:
nsCOMPtr<nsIObserver> mPrefObserver;
};

View File

@ -10,3 +10,4 @@
*/
#error "Do not include this header file."

View File

@ -163,3 +163,10 @@ SSL_SetStapledOCSPResponses;
;+ local:
;+*;
;+};
;+NSS_3.15.2 { # NSS 3.15.2 release
;+ global:
SSL_SetCanFalseStartCallback;
SSL_DefaultCanFalseStart;
;+ local:
;+*;
;+};

View File

@ -121,14 +121,22 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
#define SSL_ENABLE_FALSE_START 22 /* Enable SSL false start (off by */
/* default, applies only to */
/* clients). False start is a */
/* mode where an SSL client will start sending application data before */
/* verifying the server's Finished message. This means that we could end up */
/* sending data to an imposter. However, the data will be encrypted and */
/* only the true server can derive the session key. Thus, so long as the */
/* cipher isn't broken this is safe. Because of this, False Start will only */
/* occur on RSA or DH ciphersuites where the cipher's key length is >= 80 */
/* bits. The advantage of False Start is that it saves a round trip for */
/* client-speaks-first protocols when performing a full handshake. */
/* mode where an SSL client will start sending application data before
* verifying the server's Finished message. This means that we could end up
* sending data to an imposter. However, the data will be encrypted and
* only the true server can derive the session key. Thus, so long as the
* cipher isn't broken this is safe. The advantage of false start is that
* it saves a round trip for client-speaks-first protocols when performing a
* full handshake.
*
* See SSL_DefaultCanFalseStart for the default criteria that NSS uses to
* determine whether to false start or not. See SSL_SetCanFalseStartCallback
* for how to change that criteria. In addition to those criteria, false start
* will only be done when the server selects a cipher suite with an effective
* key length of 80 bits or more (including RC4-128). Also, see
* SSL_HandshakeCallback for a description on how false start affects when the
* handshake callback gets called.
*/
/* For SSL 3.0 and TLS 1.0, by default we prevent chosen plaintext attacks
* on SSL CBC mode cipher suites (see RFC 4346 Section F.3) by splitting
@ -653,14 +661,59 @@ SSL_IMPORT SECStatus SSL_SetMaxServerCacheLocks(PRUint32 maxLocks);
SSL_IMPORT SECStatus SSL_InheritMPServerSIDCache(const char * envString);
/*
** Set the callback on a particular socket that gets called when we finish
** performing a handshake.
** Set the callback that normally gets called when the TLS handshake
** is complete. If false start is not enabled, then the handshake callback is
** called after verifying the peer's Finished message and before sending
** outgoing application data and before processing incoming application data.
**
** If false start is enabled and there is a custom CanFalseStartCallback
** callback set, then the handshake callback gets called after the peer's
** Finished message has been verified, which may be after application data is
** sent.
**
** If false start is enabled and there is not a custom CanFalseStartCallback
** callback established with SSL_SetCanFalseStartCallback then the handshake
** callback gets called before any application data is sent, which may be
** before the peer's Finished message has been verified.
*/
typedef void (PR_CALLBACK *SSLHandshakeCallback)(PRFileDesc *fd,
void *client_data);
SSL_IMPORT SECStatus SSL_HandshakeCallback(PRFileDesc *fd,
SSLHandshakeCallback cb, void *client_data);
/* Applications that wish to customize TLS false start should set this callback
** function. NSS will invoke the functon to determine if a particular
** connection should use false start or not. SECSuccess indicates that the
** callback completed successfully, and if so *canFalseStart indicates if false
** start can be used. If the callback does not return SECSuccess then the
** handshake will be canceled.
**
** Applications that do not set the callback will use an internal set of
** criteria to determine if the connection should false start. If
** the callback is set false start will never be used without invoking the
** callback function, but some connections (e.g. resumed connections) will
** never use false start and therefore will not invoke the callback.
**
** NSS's internal criteria for this connection can be evaluated by calling
** SSL_DefaultCanFalseStart() from the custom callback.
**
** See the description of SSL_HandshakeCallback for important information on
** how registering a custom false start callback affects when the handshake
** callback gets called.
**/
typedef SECStatus (PR_CALLBACK *SSLCanFalseStartCallback)(
PRFileDesc *fd, void *arg, PRBool *canFalseStart);
SSL_IMPORT SECStatus SSL_SetCanFalseStartCallback(
PRFileDesc *fd, SSLCanFalseStartCallback callback, void *arg);
/* A utility function that can be called from a custom CanFalseStartCallback
** function to determine what NSS would have done for this connection if the
** custom callback was not implemented.
**/
SSL_IMPORT SECStatus SSL_DefaultCanFalseStart(PRFileDesc *fd,
PRBool *canFalseStart);
/*
** For the server, request a new handshake. For the client, begin a new
** handshake. If flushCache is non-zero, the SSL3 cache entry will be

View File

@ -6669,35 +6669,51 @@ done:
return rv;
}
PRBool
ssl3_CanFalseStart(sslSocket *ss) {
PRBool rv;
static SECStatus
ssl3_CheckFalseStart(sslSocket *ss)
{
SECStatus rv;
PRBool maybeFalseStart = PR_TRUE;
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
PORT_Assert( !ss->ssl3.hs.authCertificatePending );
/* XXX: does not take into account whether we are waiting for
* SSL_AuthCertificateComplete or SSL_RestartHandshakeAfterCertReq. If/when
* that is done, this function could return different results each time it
* would be called.
*/
/* An attacker can control the selected ciphersuite so we only wish to
* do False Start in the case that the selected ciphersuite is
* sufficiently strong that the attack can gain no advantage.
* Therefore we always require an 80-bit cipher. */
ssl_GetSpecReadLock(ss);
rv = ss->opt.enableFalseStart &&
!ss->sec.isServer &&
!ss->ssl3.hs.isResuming &&
ss->ssl3.cwSpec &&
/* An attacker can control the selected ciphersuite so we only wish to
* do False Start in the case that the selected ciphersuite is
* sufficiently strong that the attack can gain no advantage.
* Therefore we require an 80-bit cipher and a forward-secret key
* exchange. */
ss->ssl3.cwSpec->cipher_def->secret_key_size >= 10 &&
(ss->ssl3.hs.kea_def->kea == kea_dhe_dss ||
ss->ssl3.hs.kea_def->kea == kea_dhe_rsa ||
ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa ||
ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa);
if (ss->ssl3.cwSpec->cipher_def->secret_key_size < 10) {
ss->ssl3.hs.canFalseStart = PR_FALSE;
maybeFalseStart = PR_FALSE;
}
ssl_ReleaseSpecReadLock(ss);
if (!maybeFalseStart) {
return SECSuccess;
}
if (!ss->canFalseStartCallback) {
rv = SSL_DefaultCanFalseStart(ss->fd, &ss->ssl3.hs.canFalseStart);
if (rv == SECSuccess &&
ss->ssl3.hs.canFalseStart && ss->handshakeCallback) {
/* Call the handshake callback here for backwards compatibility
* with applications that were using false start before
* canFalseStartCallback was added.
*/
(ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
}
} else {
rv = (ss->canFalseStartCallback)(ss->fd,
ss->canFalseStartCallbackData,
&ss->ssl3.hs.canFalseStart);
}
if (rv != SECSuccess) {
ss->ssl3.hs.canFalseStart = PR_FALSE;
}
return rv;
}
@ -6727,6 +6743,7 @@ ssl3_HandleServerHelloDone(sslSocket *ss)
return SECFailure;
}
ss->enoughFirstHsDone = PR_TRUE;
rv = ssl3_SendClientSecondRound(ss);
return rv;
@ -6825,6 +6842,23 @@ ssl3_SendClientSecondRound(sslSocket *ss)
if (rv != SECSuccess) {
goto loser; /* err code was set. */
}
if (ss->opt.enableFalseStart) {
if (!ss->ssl3.hs.authCertificatePending) {
rv = ssl3_CheckFalseStart(ss);
if (rv != SECSuccess) {
goto loser;
}
} else {
/* The certificate authentication and the server's Finished
* message are going to race each other. If the certificate
* authentication wins, then we will try to false start. If the
* server's Finished message wins, then ssl3_HandleFinished will
* reset restartTarget to ssl3_FinishHandshake.
*/
ss->ssl3.hs.restartTarget = ssl3_CheckFalseStart;
}
}
}
rv = ssl3_SendFinished(ss, 0);
@ -6839,11 +6873,6 @@ ssl3_SendClientSecondRound(sslSocket *ss)
else
ss->ssl3.hs.ws = wait_change_cipher;
/* Do the handshake callback for sslv3 here, if we can false start. */
if (ss->handshakeCallback != NULL && ssl3_CanFalseStart(ss)) {
(ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
}
return SECSuccess;
loser:
@ -9416,13 +9445,6 @@ ssl3_AuthCertificate(sslSocket *ss)
ss->ssl3.hs.authCertificatePending = PR_TRUE;
rv = SECSuccess;
/* XXX: Async cert validation and False Start don't work together
* safely yet; if we leave False Start enabled, we may end up false
* starting (sending application data) before we
* SSL_AuthCertificateComplete has been called.
*/
ss->opt.enableFalseStart = PR_FALSE;
}
if (rv != SECSuccess) {
@ -10070,6 +10092,11 @@ xmit_loser:
ss->ssl3.hs.cacheSID = rv == SECSuccess;
}
/* Cancel false start check since we already completed the handshake */
if (ss->ssl3.hs.restartTarget == ssl3_CheckFalseStart) {
ss->ssl3.hs.restartTarget = NULL;
}
if (ss->ssl3.hs.authCertificatePending) {
if (ss->ssl3.hs.restartTarget) {
PR_NOT_REACHED("ssl3_HandleFinished: unexpected restartTarget");
@ -10088,6 +10115,8 @@ xmit_loser:
SECStatus
ssl3_FinishHandshake(sslSocket * ss)
{
PRBool falseStarted;
PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
PORT_Assert( ss->ssl3.hs.restartTarget == NULL );
@ -10095,6 +10124,7 @@ ssl3_FinishHandshake(sslSocket * ss)
/* The first handshake is now completed. */
ss->handshake = NULL;
ss->firstHsDone = PR_TRUE;
ss->enoughFirstHsDone = PR_TRUE;
if (ss->ssl3.hs.cacheSID) {
(*ss->sec.cache)(ss->sec.ci.sid);
@ -10102,9 +10132,14 @@ ssl3_FinishHandshake(sslSocket * ss)
}
ss->ssl3.hs.ws = idle_handshake;
falseStarted = ss->ssl3.hs.canFalseStart;
ss->ssl3.hs.canFalseStart = PR_FALSE; /* False Start phase is complete */
/* Do the handshake callback for sslv3 here, if we cannot false start. */
if (ss->handshakeCallback != NULL && !ssl3_CanFalseStart(ss)) {
/* Call the handshake callback for sslv3 here, unless we called it already
* for the case where false start was done without a canFalseStartCallback.
*/
if (ss->handshakeCallback != NULL &&
!(falseStarted && !ss->canFalseStartCallback)) {
(ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
}

View File

@ -374,9 +374,7 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
*/
if (ss->opt.enableFalseStart) {
ssl_GetSSL3HandshakeLock(ss);
canFalseStart = (ss->ssl3.hs.ws == wait_change_cipher ||
ss->ssl3.hs.ws == wait_new_session_ticket) &&
ssl3_CanFalseStart(ss);
canFalseStart = ss->ssl3.hs.canFalseStart;
ssl_ReleaseSSL3HandshakeLock(ss);
}
} while (ss->ssl3.hs.ws != idle_handshake &&

View File

@ -60,7 +60,6 @@ SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1,
sslSocket *ss;
const char *cipherName;
PRBool isDes = PR_FALSE;
PRBool enoughFirstHsDone = PR_FALSE;
ss = ssl_FindSocket(fd);
if (!ss) {
@ -78,14 +77,7 @@ SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1,
*op = SSL_SECURITY_STATUS_OFF;
}
if (ss->firstHsDone) {
enoughFirstHsDone = PR_TRUE;
} else if (ss->version >= SSL_LIBRARY_VERSION_3_0 &&
ssl3_CanFalseStart(ss)) {
enoughFirstHsDone = PR_TRUE;
}
if (ss->opt.useSecurity && enoughFirstHsDone) {
if (ss->opt.useSecurity && ss->enoughFirstHsDone) {
if (ss->version < SSL_LIBRARY_VERSION_3_0) {
cipherName = ssl_cipherName[ss->sec.cipherType];
} else {

View File

@ -868,6 +868,8 @@ const ssl3CipherSuiteDef *suite_def;
PRUint32 rtTimeoutMs; /* The length of the current timeout
* used for backoff (in ms) */
PRUint32 rtRetries; /* The retry counter */
PRBool canFalseStart; /* Can/did we False Start */
} SSL3HandshakeState;
@ -1116,6 +1118,10 @@ struct sslSocketStr {
unsigned long clientAuthRequested;
unsigned long delayDisabled; /* Nagle delay disabled */
unsigned long firstHsDone; /* first handshake is complete. */
unsigned long enoughFirstHsDone; /* enough of the handshake is done
* for callbacks to be able to
* retrieve channel security
* parameters from callback functions. */
unsigned long handshakeBegun;
unsigned long lastWriteBlocked;
unsigned long recvdCloseNotify; /* received SSL EOF. */
@ -1156,6 +1162,8 @@ const unsigned char * preferredCipher;
void *badCertArg;
SSLHandshakeCallback handshakeCallback;
void *handshakeCallbackData;
SSLCanFalseStartCallback canFalseStartCallback;
void *canFalseStartCallbackData;
void *pkcs11PinArg;
SSLNextProtoCallback nextProtoCallback;
void *nextProtoArg;
@ -1358,7 +1366,6 @@ extern void ssl3_SetAlwaysBlock(sslSocket *ss);
extern SECStatus ssl_EnableNagleDelay(sslSocket *ss, PRBool enabled);
extern PRBool ssl3_CanFalseStart(sslSocket *ss);
extern SECStatus
ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec,
PRBool isServer,

View File

@ -26,7 +26,6 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
sslSocket * ss;
SSLChannelInfo inf;
sslSessionID * sid;
PRBool enoughFirstHsDone = PR_FALSE;
if (!info || len < sizeof inf.length) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
@ -43,14 +42,7 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
memset(&inf, 0, sizeof inf);
inf.length = PR_MIN(sizeof inf, len);
if (ss->firstHsDone) {
enoughFirstHsDone = PR_TRUE;
} else if (ss->version >= SSL_LIBRARY_VERSION_3_0 &&
ssl3_CanFalseStart(ss)) {
enoughFirstHsDone = PR_TRUE;
}
if (ss->opt.useSecurity && enoughFirstHsDone) {
if (ss->opt.useSecurity && ss->enoughFirstHsDone) {
sid = ss->sec.ci.sid;
inf.protocolVersion = ss->version;
inf.authKeyBits = ss->sec.authKeyBits;

View File

@ -77,7 +77,6 @@ SSL_HandshakeNegotiatedExtension(PRFileDesc * socket,
{
/* some decisions derived from SSL_GetChannelInfo */
sslSocket * sslsocket = NULL;
PRBool enoughFirstHsDone = PR_FALSE;
if (!pYes) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
@ -93,14 +92,8 @@ SSL_HandshakeNegotiatedExtension(PRFileDesc * socket,
*pYes = PR_FALSE;
if (sslsocket->firstHsDone) {
enoughFirstHsDone = PR_TRUE;
} else if (sslsocket->ssl3.initialized && ssl3_CanFalseStart(sslsocket)) {
enoughFirstHsDone = PR_TRUE;
}
/* according to public API SSL_GetChannelInfo, this doesn't need a lock */
if (sslsocket->opt.useSecurity && enoughFirstHsDone) {
if (sslsocket->opt.useSecurity && sslsocket->enoughFirstHsDone) {
if (sslsocket->ssl3.initialized) { /* SSL3 and TLS */
/* now we know this socket went through ssl3_InitState() and
* ss->xtnData got initialized, which is the only member accessed by

View File

@ -108,10 +108,12 @@ ssl_Do1stHandshake(sslSocket *ss)
if ((ss->handshakeCallback != NULL) && /* has callback */
(!ss->firstHsDone) && /* only first time */
(ss->version < SSL_LIBRARY_VERSION_3_0)) { /* not ssl3 */
ss->firstHsDone = PR_TRUE;
ss->firstHsDone = PR_TRUE;
ss->enoughFirstHsDone = PR_TRUE;
(ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
}
ss->firstHsDone = PR_TRUE;
ss->firstHsDone = PR_TRUE;
ss->enoughFirstHsDone = PR_TRUE;
ss->gs.writeOffset = 0;
ss->gs.readOffset = 0;
break;
@ -206,6 +208,7 @@ SSL_ResetHandshake(PRFileDesc *s, PRBool asServer)
ssl_Get1stHandshakeLock(ss);
ss->firstHsDone = PR_FALSE;
ss->enoughFirstHsDone = PR_FALSE;
if ( asServer ) {
ss->handshake = ssl2_BeginServerHandshake;
ss->handshaking = sslHandshakingAsServer;
@ -221,6 +224,8 @@ SSL_ResetHandshake(PRFileDesc *s, PRBool asServer)
ssl_ReleaseRecvBufLock(ss);
ssl_GetSSL3HandshakeLock(ss);
ss->ssl3.hs.canFalseStart = PR_FALSE;
ss->ssl3.hs.restartTarget = NULL;
/*
** Blow away old security state and get a fresh setup.
@ -331,6 +336,74 @@ SSL_HandshakeCallback(PRFileDesc *fd, SSLHandshakeCallback cb,
return SECSuccess;
}
/* Register an application callback to be called when false start may happen.
** Acquires and releases HandshakeLock.
*/
SECStatus
SSL_SetCanFalseStartCallback(PRFileDesc *fd, SSLCanFalseStartCallback cb,
void *client_data)
{
sslSocket *ss;
ss = ssl_FindSocket(fd);
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetCanFalseStartCallback",
SSL_GETPID(), fd));
return SECFailure;
}
if (!ss->opt.useSecurity) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
ssl_Get1stHandshakeLock(ss);
ssl_GetSSL3HandshakeLock(ss);
ss->canFalseStartCallback = cb;
ss->canFalseStartCallbackData = client_data;
ssl_ReleaseSSL3HandshakeLock(ss);
ssl_Release1stHandshakeLock(ss);
return SECSuccess;
}
/* A utility function that can be called from a custom CanFalseStartCallback
** function to determine what NSS would have done for this connection if the
** custom callback was not implemented.
*/
SECStatus
SSL_DefaultCanFalseStart(PRFileDesc *fd, PRBool *canFalseStart)
{
sslSocket *ss;
*canFalseStart = PR_FALSE;
ss = ssl_FindSocket(fd);
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in SSL_DefaultCanFalseStart",
SSL_GETPID(), fd));
return SECFailure;
}
if (!ss->ssl3.initialized) {
PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
return SECFailure;
}
if (ss->version <= SSL_LIBRARY_VERSION_3_0) {
PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION);
return SECFailure;
}
/* Require a forward-secret key exchange. */
*canFalseStart = ss->ssl3.hs.kea_def->kea == kea_dhe_dss ||
ss->ssl3.hs.kea_def->kea == kea_dhe_rsa ||
ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa ||
ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa;
return SECSuccess;
}
/* Try to make progress on an SSL handshake by attempting to read the
** next handshake from the peer, and sending any responses.
** For non-blocking sockets, returns PR_ERROR_WOULD_BLOCK if it cannot
@ -1195,12 +1268,7 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
ssl_Get1stHandshakeLock(ss);
if (ss->version >= SSL_LIBRARY_VERSION_3_0) {
ssl_GetSSL3HandshakeLock(ss);
if ((ss->ssl3.hs.ws == wait_change_cipher ||
ss->ssl3.hs.ws == wait_finished ||
ss->ssl3.hs.ws == wait_new_session_ticket) &&
ssl3_CanFalseStart(ss)) {
canFalseStart = PR_TRUE;
}
canFalseStart = ss->ssl3.hs.canFalseStart;
ssl_ReleaseSSL3HandshakeLock(ss);
}
if (!canFalseStart &&

View File

@ -2341,9 +2341,13 @@ ssl_Poll(PRFileDesc *fd, PRInt16 how_flags, PRInt16 *p_out_flags)
} else if (new_flags & PR_POLL_WRITE) {
/* The caller is trying to write, but the handshake is
** blocked waiting for data to read, and the first
** handshake has been sent. so do NOT to poll on write.
** handshake has been sent. So do NOT to poll on write
** unless we did false start.
*/
new_flags ^= PR_POLL_WRITE; /* don't select on write. */
if (!(ss->version >= SSL_LIBRARY_VERSION_3_0 &&
ss->ssl3.hs.canFalseStart)) {
new_flags ^= PR_POLL_WRITE; /* don't select on write. */
}
new_flags |= PR_POLL_READ; /* do select on read. */
}
}

View File

@ -1,2 +1,6 @@
This directory contains patches that were added locally
on top of the NSS release.
bug-658222-false-start.patch: First iteration of false start. The patch will be
further modified to make it work for Chromium and
other projects before being checked in.

File diff suppressed because it is too large Load Diff

View File

@ -843,6 +843,12 @@
"extended_statistics_ok": true,
"description": "ms of SSL wait time including TCP and proxy tunneling"
},
"SSL_TIME_UNTIL_HANDSHAKE_FINISHED": {
"kind": "exponential",
"high": "60000",
"n_buckets": 200,
"description": "ms of SSL wait time for full handshake including TCP and proxy tunneling"
},
"SSL_BYTES_BEFORE_CERT_CALLBACK": {
"kind": "exponential",
"high": "32000",

View File

@ -25,8 +25,6 @@ DEFINES += \
-DCXX_VERSION="$(CXX_VERSION)" \
-DCXXFLAGS="$(CXXFLAGS)" \
-DCPPFLAGS="$(CPPFLAGS)" \
-DMOZ_APP_NAME=$(MOZ_APP_NAME) \
-DMOZ_BUILD_APP=$(MOZ_BUILD_APP) \
$(NULL)
MOZ_SOURCE_STAMP ?= $(shell hg -R $(topsrcdir) parent --template="{node|short}\n" 2>/dev/null)

View File

@ -6,6 +6,7 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/Troubleshoot.jsm");
Components.utils.import("resource://gre/modules/ResetProfile.jsm");
window.addEventListener("load", function onload(event) {
window.removeEventListener("load", onload, false);
@ -516,31 +517,6 @@ function showUpdateHistory() {
* Profile reset is only supported for the default profile if the appropriate migrator exists.
*/
function populateResetBox() {
if (resetSupported())
if (ResetProfile.resetSupported())
$("reset-box").style.visibility = "visible";
}
/**
* Restart the application to reset the profile.
*/
function resetProfileAndRestart() {
let branding = Services.strings.createBundle("chrome://branding/locale/brand.properties");
let brandShortName = branding.GetStringFromName("brandShortName");
// Prompt the user to confirm.
let retVals = {
reset: false,
};
window.openDialog("chrome://global/content/resetProfile.xul", null,
"chrome,modal,centerscreen,titlebar,dialog=yes", retVals);
if (!retVals.reset)
return;
// Set the reset profile environment variable.
let env = Cc["@mozilla.org/process/environment;1"]
.getService(Ci.nsIEnvironment);
env.set("MOZ_RESET_PROFILE_RESTART", "1");
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
appStartup.quit(Ci.nsIAppStartup.eForceQuit | Ci.nsIAppStartup.eRestart);
}

View File

@ -30,7 +30,7 @@
<div id="reset-box" style="visibility: hidden">
<h3>&resetProfile.title;</h3>
<p>&resetProfile.description;</p>
<button onclick="resetProfileAndRestart()">
<button onclick="ResetProfile.openConfirmationDialog(window)">
&resetProfile.button.label2;
</button>
</div>

View File

@ -43,7 +43,7 @@ toolkit.jar:
+ content/global/mozilla.xhtml (mozilla.xhtml)
content/global/nsDragAndDrop.js (nsDragAndDrop.js)
content/global/resetProfile.css (resetProfile.css)
* content/global/resetProfile.js (resetProfile.js)
content/global/resetProfile.js (resetProfile.js)
content/global/resetProfile.xul (resetProfile.xul)
content/global/resetProfileProgress.xul (resetProfileProgress.xul)
content/global/treeUtils.js (treeUtils.js)

View File

@ -2,16 +2,18 @@
* 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/. */
Components.utils.import("resource://gre/modules/Services.jsm");
"use strict";
let Cc = Components.classes;
let Ci = Components.interfaces;
let Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/ResetProfile.jsm");
// based on onImportItemsPageShow from migration.js
function populateResetPane(aContainerID) {
let resetProfileItems = document.getElementById(aContainerID);
try {
let dataTypes = getMigratedData();
let dataTypes = ResetProfile.getMigratedData();
for (let dataType of dataTypes) {
let label = document.createElement("label");
label.setAttribute("value", dataType);
@ -26,59 +28,6 @@ function onResetProfileLoad() {
populateResetPane("migratedItems");
}
/**
* Check if reset is supported for the currently running profile.
*
* @return boolean whether reset is supported.
*/
function resetSupported() {
let profileService = Cc["@mozilla.org/toolkit/profile-service;1"].
getService(Ci.nsIToolkitProfileService);
let currentProfileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
#expand const MOZ_APP_NAME = "__MOZ_APP_NAME__";
#expand const MOZ_BUILD_APP = "__MOZ_BUILD_APP__";
// Reset is only supported for the default profile if the self-migrator used for reset exists.
try {
return currentProfileDir.equals(profileService.selectedProfile.rootDir) &&
("@mozilla.org/profile/migrator;1?app=" + MOZ_BUILD_APP + "&type=" + MOZ_APP_NAME in Cc);
} catch (e) {
// Catch exception when there is no selected profile.
Cu.reportError(e);
}
return false;
}
function getMigratedData() {
Components.utils.import("resource:///modules/MigrationUtils.jsm");
#expand const MOZ_BUILD_APP = "__MOZ_BUILD_APP__";
#expand const MOZ_APP_NAME = "__MOZ_APP_NAME__";
// From migration.properties
const MIGRATED_TYPES = [
128,// Windows/Tabs
4, // History and Bookmarks
16, // Passwords
8, // Form History
2, // Cookies
];
// Loop over possible data to migrate to give the user a list of what will be preserved.
let dataTypes = [];
for (let itemID of MIGRATED_TYPES) {
try {
let typeName = MigrationUtils.getLocalizedString(itemID + "_" + MOZ_APP_NAME);
dataTypes.push(typeName);
} catch (x) {
// Catch exceptions when the string for a data type doesn't exist.
Components.utils.reportError(x);
}
}
return dataTypes;
}
function onResetProfileAccepted() {
let retVals = window.arguments[0];
retVals.reset = true;

View File

@ -0,0 +1,12 @@
# 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/.
# LOCALIZATION NOTE: These strings are used for profile reset.
# LOCALIZATION NOTE (resetUnusedProfile.message): %S is brandShortName.
resetUnusedProfile.message=It looks like you haven't started %S in a while. Do you want to clean it up for a fresh, like-new experience? And by the way, welcome back!
# LOCALIZATION NOTE (resetProfile.resetButton.label): %S is brandShortName.
resetProfile.resetButton.label=Reset %S…
resetProfile.resetButton.accesskey=e

View File

@ -58,6 +58,7 @@
locale/@AB_CD@/global/printProgress.dtd (%chrome/global/printProgress.dtd)
locale/@AB_CD@/global/regionNames.properties (%chrome/global/regionNames.properties)
locale/@AB_CD@/global/resetProfile.dtd (%chrome/global/resetProfile.dtd)
locale/@AB_CD@/global/resetProfile.properties (%chrome/global/resetProfile.properties)
locale/@AB_CD@/global/dialog.properties (%chrome/global/dialog.properties)
locale/@AB_CD@/global/tree.dtd (%chrome/global/tree.dtd)
locale/@AB_CD@/global/textcontext.dtd (%chrome/global/textcontext.dtd)

View File

@ -13,8 +13,14 @@ ifdef MOZ_TOOLKIT_SEARCH
DEFINES += -DMOZ_TOOLKIT_SEARCH
endif
DEFINES += \
-DMOZ_APP_NAME=$(MOZ_APP_NAME) \
-DMOZ_BUILD_APP=$(MOZ_BUILD_APP) \
$(NULL)
EXTRA_PP_JS_MODULES = \
CertUtils.jsm \
ResetProfile.jsm \
Services.jsm \
Troubleshoot.jsm \
UpdateChannel.jsm \

View File

@ -0,0 +1,84 @@
/* 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/. */
"use strict";
this.EXPORTED_SYMBOLS = ["ResetProfile"];
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
#expand const MOZ_APP_NAME = "__MOZ_APP_NAME__";
#expand const MOZ_BUILD_APP = "__MOZ_BUILD_APP__";
Cu.import("resource://gre/modules/Services.jsm");
this.ResetProfile = {
/**
* Check if reset is supported for the currently running profile.
*
* @return boolean whether reset is supported.
*/
resetSupported: function() {
let profileService = Cc["@mozilla.org/toolkit/profile-service;1"].
getService(Ci.nsIToolkitProfileService);
let currentProfileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
// Reset is only supported for the default profile if the self-migrator used for reset exists.
try {
return currentProfileDir.equals(profileService.selectedProfile.rootDir) &&
("@mozilla.org/profile/migrator;1?app=" + MOZ_BUILD_APP + "&type=" + MOZ_APP_NAME in Cc);
} catch (e) {
// Catch exception when there is no selected profile.
Cu.reportError(e);
}
return false;
},
getMigratedData: function() {
Cu.import("resource:///modules/MigrationUtils.jsm");
// From migration.properties
const MIGRATED_TYPES = [
128,// Windows/Tabs
4, // History and Bookmarks
16, // Passwords
8, // Form History
2, // Cookies
];
// Loop over possible data to migrate to give the user a list of what will be preserved.
let dataTypes = [];
for (let itemID of MIGRATED_TYPES) {
try {
let typeName = MigrationUtils.getLocalizedString(itemID + "_" + MOZ_APP_NAME);
dataTypes.push(typeName);
} catch (x) {
// Catch exceptions when the string for a data type doesn't exist.
Cu.reportError(x);
}
}
return dataTypes;
},
/**
* Ask the user if they wish to restart the application to reset the profile.
*/
openConfirmationDialog: function(window) {
// Prompt the user to confirm.
let params = {
reset: false,
};
window.openDialog("chrome://global/content/resetProfile.xul", null,
"chrome,modal,centerscreen,titlebar,dialog=yes", params);
if (!params.reset)
return;
// Set the reset profile environment variable.
let env = Cc["@mozilla.org/process/environment;1"]
.getService(Ci.nsIEnvironment);
env.set("MOZ_RESET_PROFILE_RESTART", "1");
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
appStartup.quit(Ci.nsIAppStartup.eForceQuit | Ci.nsIAppStartup.eRestart);
},
};

View File

@ -3,8 +3,10 @@
* 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/. */
#include "mozilla/MemoryReporting.h"
#include "nsCOMArray.h"
#include "mozilla/MemoryReporting.h"
#include "nsCOMPtr.h"
// This specialization is private to nsCOMArray.