diff --git a/build/unix/run-mozilla.sh b/build/unix/run-mozilla.sh index fbd9f7a8..2e407334 100644 --- a/build/unix/run-mozilla.sh +++ b/build/unix/run-mozilla.sh @@ -328,34 +328,34 @@ if [ -z "$MRE_HOME" ]; then fi ## ## Set LD_LIBRARY_PATH -LD_LIBRARY_PATH=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/plugins:${MRE_HOME}${LD_LIBRARY_PATH+":$LD_LIBRARY_PATH"} +LD_LIBRARY_PATH=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/plugins:${MRE_HOME}${LD_LIBRARY_PATH:+":$LD_LIBRARY_PATH"} if [ -n "$LD_LIBRARYN32_PATH" ] then - LD_LIBRARYN32_PATH=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/plugins:${MRE_HOME}${LD_LIBRARYN32_PATH+":$LD_LIBRARYN32_PATH"} + LD_LIBRARYN32_PATH=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/plugins:${MRE_HOME}${LD_LIBRARYN32_PATH:+":$LD_LIBRARYN32_PATH"} fi if [ -n "$LD_LIBRARYN64_PATH" ] then - LD_LIBRARYN64_PATH=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/plugins:${MRE_HOME}${LD_LIBRARYN64_PATH+":$LD_LIBRARYN64_PATH"} + LD_LIBRARYN64_PATH=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/plugins:${MRE_HOME}${LD_LIBRARYN64_PATH:+":$LD_LIBRARYN64_PATH"} fi if [ -n "$LD_LIBRARY_PATH_64" ]; then - LD_LIBRARY_PATH_64=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/plugins:${MRE_HOME}${LD_LIBRARY_PATH_64+":$LD_LIBRARY_PATH_64"} + LD_LIBRARY_PATH_64=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/plugins:${MRE_HOME}${LD_LIBRARY_PATH_64:+":$LD_LIBRARY_PATH_64"} fi # # ## Set SHLIB_PATH for HPUX -SHLIB_PATH=${MOZ_DIST_BIN}:${MRE_HOME}${SHLIB_PATH+":$SHLIB_PATH"} +SHLIB_PATH=${MOZ_DIST_BIN}:${MRE_HOME}${SHLIB_PATH:+":$SHLIB_PATH"} # ## Set LIBPATH for AIX -LIBPATH=${MOZ_DIST_BIN}:${MRE_HOME}${LIBPATH+":$LIBPATH"} +LIBPATH=${MOZ_DIST_BIN}:${MRE_HOME}${LIBPATH:+":$LIBPATH"} # ## Set DYLD_LIBRARY_PATH for Mac OS X (Darwin) -DYLD_LIBRARY_PATH=${MOZ_DIST_BIN}:${MRE_HOME}${DYLD_LIBRARY_PATH+":$DYLD_LIBRARY_PATH"} +DYLD_LIBRARY_PATH=${MOZ_DIST_BIN}:${MRE_HOME}${DYLD_LIBRARY_PATH:+":$DYLD_LIBRARY_PATH"} # ## Set LIBRARY_PATH for BeOS -LIBRARY_PATH=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/components:${MRE_HOME}${LIBRARY_PATH+":$LIBRARY_PATH"} +LIBRARY_PATH=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/components:${MRE_HOME}${LIBRARY_PATH:+":$LIBRARY_PATH"} # ## Set ADDON_PATH for BeOS -ADDON_PATH=${MOZ_DIST_BIN}${ADDON_PATH+":$ADDON_PATH"} +ADDON_PATH=${MOZ_DIST_BIN}${ADDON_PATH:+":$ADDON_PATH"} # ## Solaris Xserver(Xsun) tuning - use shared memory transport if available if [ "$XSUNTRANSPORT" = "" ] diff --git a/chrome/src/nsChromeRegistry.cpp b/chrome/src/nsChromeRegistry.cpp index a1e3a918..71622c70 100644 --- a/chrome/src/nsChromeRegistry.cpp +++ b/chrome/src/nsChromeRegistry.cpp @@ -666,13 +666,33 @@ nsChromeRegistry::Canonify(nsIURL* aChromeURL) aChromeURL->SetPath(path); } else { - nsCAutoString filePath; - rv = aChromeURL->GetFilePath(filePath); - NS_ENSURE_SUCCESS(rv, rv); - - if (filePath.Find(NS_LITERAL_CSTRING("..")) != -1 || - filePath.FindChar(':') != -1) { - return NS_ERROR_DOM_BAD_URI; + // prevent directory traversals ("..") + // path is already unescaped once, but uris can get unescaped twice + const char* pos = path.BeginReading(); + const char* end = path.EndReading(); + while (pos < end) { + switch (*pos) { + case ':': + return NS_ERROR_DOM_BAD_URI; + case '.': + if (pos[1] == '.') + return NS_ERROR_DOM_BAD_URI; + break; + case '%': + // chrome: URIs with double-escapes are trying to trick us. + // watch for %2e, and %25 in case someone triple unescapes + if (pos[1] == '2' && + ( pos[2] == 'e' || pos[2] == 'E' || + pos[2] == '5' )) + return NS_ERROR_DOM_BAD_URI; + break; + case '?': + case '#': + // ignore query or ref part, we're done + pos = end; + continue; + } + ++pos; } } @@ -1965,7 +1985,7 @@ CheckVersionFlag(const nsSubstring& aFlag, const nsSubstring& aData, const nsSubstring& aValue, nsIVersionComparator* aChecker, TriState& aResult) { - if (! (aData.Length() > aFlag.Length() + 2)) + if (aData.Length() < aFlag.Length() + 2) return PR_FALSE; if (!StringBeginsWith(aData, aFlag)) @@ -2006,6 +2026,9 @@ CheckVersionFlag(const nsSubstring& aFlag, const nsSubstring& aData, return PR_FALSE; } + if (testdata.Length() == 0) + return PR_FALSE; + if (aResult != eOK) { if (!aChecker) { aResult = eBad; @@ -2388,7 +2411,7 @@ nsChromeRegistry::ProcessManifestBuffer(char *buf, PRInt32 length, nsCOMPtr chromeuri, resolveduri; rv = io->NewURI(nsDependentCString(chrome), nsnull, nsnull, getter_AddRefs(chromeuri)); - rv |= io->NewURI(nsDependentCString(resolved), nsnull, nsnull, + rv |= io->NewURI(nsDependentCString(resolved), nsnull, manifestURI, getter_AddRefs(resolveduri)); if (NS_FAILED(rv)) continue; diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h index 7bdbb8d7..f4290bf2 100644 --- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -81,6 +81,7 @@ class nsIJSRuntimeService; class nsIScriptGlobalObject; struct JSRuntime; class nsPIDOMWindow; +class nsPIDOMEventTarget; #ifdef MOZ_XTF class nsIXTFService; #endif @@ -706,6 +707,9 @@ public: ~nsCxPusher() { Pop(); } // Returns PR_FALSE if something erroneous happened. PRBool Push(nsISupports *aCurrentTarget); + // If nothing has been pushed to stack, this works like Push. + // Otherwise if context will change, Pop and Push will be called. + PRBool RePush(nsISupports *aCurrentTarget); void Pop(); private: diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 69688013..5e1bbad1 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -997,7 +997,7 @@ nsContentUtils::ReparentContentWrappersInScope(nsIScriptGlobalObject *aOldScope, NS_ERROR("Weird things are happening in XPConnect"); return NS_ERROR_FAILURE; } - return xpconnect18->ReparentScopeAwareWrappers(cx, oldScopeObj, newScopeObj); + return xpconnect18->MoveWrappers(cx, oldScopeObj, newScopeObj); } nsIDocShell * @@ -2395,6 +2395,47 @@ nsCxPusher::Push(nsISupports *aCurrentTarget) return PR_TRUE; } +PRBool +nsCxPusher::RePush(nsISupports *aCurrentTarget) +{ + if (!mScx) { + return Push(aCurrentTarget); + } + + if (aCurrentTarget) { + nsIScriptContext* scx = nsnull; + nsCOMPtr sgo; + nsCOMPtr content(do_QueryInterface(aCurrentTarget)); + + if (content) { + nsCOMPtr ownerDoc = content->GetOwnerDoc(); + if (ownerDoc) { + nsCOMPtr branch3doc = + do_QueryInterface(ownerDoc); + NS_ASSERTION(branch3doc, + "Document must implement nsIDocument_MOZILLA_1_8_BRANCH3!!!"); + PRBool hasHadScriptObject = PR_TRUE; + sgo = branch3doc->GetScriptHandlingObject(hasHadScriptObject); + } + } else { + sgo = do_QueryInterface(aCurrentTarget); + } + + if (sgo) { + scx = sgo->GetContext(); + // If we have the same script context and native context is still + // alive, no need to Pop/Push. + if (scx && scx == mScx && + scx->GetNativeContext()) { + return PR_TRUE; + } + } + } + + Pop(); + return Push(aCurrentTarget); +} + void nsCxPusher::Pop() { diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 191726e3..3c622400 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -3710,13 +3710,9 @@ nsDocument::CloneNode(PRBool aDeep, nsIDOMNode** aReturn) NS_IMETHODIMP nsDocument::Normalize() { - PRInt32 count = mChildren.ChildCount(); - for (PRInt32 i = 0; i < count; ++i) { + for (PRInt32 i = 0; i < mChildren.ChildCount(); ++i) { nsCOMPtr node(do_QueryInterface(mChildren.ChildAt(i))); - - if (node) { - node->Normalize(); - } + node->Normalize(); } return NS_OK; diff --git a/content/base/src/nsFrameLoader.cpp b/content/base/src/nsFrameLoader.cpp index 530197a6..7461a6fb 100644 --- a/content/base/src/nsFrameLoader.cpp +++ b/content/base/src/nsFrameLoader.cpp @@ -235,7 +235,9 @@ nsFrameLoader::Destroy() // Let our window know that we are gone nsCOMPtr win_private(do_GetInterface(mDocShell)); if (win_private) { + nsIDOMElement* frameElement = win_private->GetFrameElementInternal(); win_private->SetFrameElementInternal(nsnull); + NS_IF_RELEASE(frameElement); } nsCOMPtr base_win(do_QueryInterface(mDocShell)); @@ -402,7 +404,11 @@ nsFrameLoader::EnsureDocShell() nsCOMPtr win_private(do_GetInterface(mDocShell)); NS_ENSURE_TRUE(win_private, NS_ERROR_UNEXPECTED); + nsIDOMElement* oldFrame = win_private->GetFrameElementInternal(); win_private->SetFrameElementInternal(frame_element); + nsIDOMElement* fe = frame_element.get(); + NS_ADDREF(fe); + NS_IF_RELEASE(oldFrame); nsCOMPtr base_win(do_QueryInterface(mDocShell)); NS_ENSURE_TRUE(base_win, NS_ERROR_UNEXPECTED); diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index 4562fd0f..c44420e3 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -2797,15 +2797,16 @@ doInsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify, NS_PRECONDITION(!aParent || aParent->GetCurrentDoc() == aDocument, "Incorrect aDocument"); + nsMutationGuard::DidMutate(); + + // Do this before checking the child-count since this could cause mutations + mozAutoDocUpdate updateBatch(aDocument, UPDATE_CONTENT_MODEL, aNotify); + PRUint32 childCount = aChildArray.ChildCount(); NS_ENSURE_TRUE(aIndex <= childCount, NS_ERROR_ILLEGAL_VALUE); - nsMutationGuard::DidMutate(); - PRBool isAppend = (aIndex == childCount); - mozAutoDocUpdate updateBatch(aDocument, UPDATE_CONTENT_MODEL, aNotify); - // Note that SetRootContent already deals with binding, so if we plan to call // it we shouldn't bind ourselves. // XXXbz this doesn't put aKid in the right spot, really... We really need a diff --git a/content/events/src/nsEventListenerManager.cpp b/content/events/src/nsEventListenerManager.cpp index 2a4bd545..a9c86230 100644 --- a/content/events/src/nsEventListenerManager.cpp +++ b/content/events/src/nsEventListenerManager.cpp @@ -1645,11 +1645,7 @@ nsEventListenerManager::HandleEventSubType(nsListenerStruct* aListenerStruct, } } - // nsCxPusher will push and pop (automatically) the current cx onto the - // context stack - nsCxPusher pusher; - - if (NS_SUCCEEDED(result) && pusher.Push(aCurrentTarget)) { + if (NS_SUCCEEDED(result)) { nsCOMPtr aPrivDOMEvent(do_QueryInterface(aDOMEvent)); aPrivDOMEvent->SetCurrentTarget(aCurrentTarget); result = aListener->HandleEvent(aDOMEvent); @@ -1727,6 +1723,7 @@ nsEventListenerManager::HandleEvent(nsPresContext* aPresContext, } if (NS_SUCCEEDED(ret)) { + nsCxPusher pusher; PRInt32 count = listeners->Count(); nsVoidArray originalListeners(count); originalListeners = *listeners; @@ -1746,14 +1743,17 @@ nsEventListenerManager::HandleEvent(nsPresContext* aPresContext, if (eventListener) { // Try the type-specific listener interface PRBool hasInterface = PR_FALSE; - if (typeData) + if (typeData) { + pusher.Pop(); DispatchToInterface(*aDOMEvent, eventListener, dispData->method, *typeData->iid, &hasInterface); + } // If it doesn't implement that, call the generic HandleEvent() - if (!hasInterface && (ls->mSubType == NS_EVENT_BITS_NONE || - ls->mSubType & dispData->bits)) { + if (!hasInterface && + (ls->mSubType == NS_EVENT_BITS_NONE || ls->mSubType & dispData->bits) && + pusher.RePush(aCurrentTarget)) { HandleEventSubType(ls, eventListener, *aDOMEvent, aCurrentTarget, dispData ? dispData->bits : NS_EVENT_BITS_NONE, aFlags); diff --git a/content/events/src/nsEventStateManager.cpp b/content/events/src/nsEventStateManager.cpp index 70e082a8..853b78ea 100644 --- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -2100,7 +2100,7 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext, } nsIFrame* currFrame = mCurrentTarget; - nsIContent* activeContent = nsnull; + nsCOMPtr activeContent; if (mCurrentTarget) activeContent = mCurrentTarget->GetContent(); diff --git a/content/html/content/public/nsIFrameSetElement.h b/content/html/content/public/nsIFrameSetElement.h index 9cf3632e..0ddce3f1 100644 --- a/content/html/content/public/nsIFrameSetElement.h +++ b/content/html/content/public/nsIFrameSetElement.h @@ -65,6 +65,12 @@ struct nsFramesetSpec { nscoord mValue; }; +/** + * The maximum number of entries allowed in the frame set element row + * or column spec. + */ +#define NS_MAX_FRAMESET_SPEC_COUNT 16000 + /** * This interface is used by the nsFramesetFrame to access the parsed * values of the "rows" and "cols" attributes diff --git a/content/html/content/src/nsHTMLFrameSetElement.cpp b/content/html/content/src/nsHTMLFrameSetElement.cpp index 5ba3b876..7353c78a 100644 --- a/content/html/content/src/nsHTMLFrameSetElement.cpp +++ b/content/html/content/src/nsHTMLFrameSetElement.cpp @@ -43,6 +43,7 @@ #include "nsIFrameSetElement.h" #include "nsIHTMLDocument.h" #include "nsIDocument.h" +#include "nspr.h" class nsHTMLFrameSetElement : public nsGenericHTMLElement, public nsIDOMHTMLFrameSetElement, @@ -312,10 +313,11 @@ nsHTMLFrameSetElement::ParseRowCol(const nsAString & aValue, spec.StripChars(" \n\r\t\"\'"); spec.Trim(","); - // Count the commas + // Count the commas. Don't count more than X commas (bug 576447). + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT * sizeof(nsFramesetSpec) < (1 << 30)); PRInt32 commaX = spec.FindChar(sComma); PRInt32 count = 1; - while (commaX != kNotFound) { + while (commaX != kNotFound && count < NS_MAX_FRAMESET_SPEC_COUNT) { count++; commaX = spec.FindChar(sComma, commaX + 1); } diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index cec77869..c590f2a9 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -2944,8 +2944,13 @@ nsHTMLDocument::GetSelection(nsAString& aReturn) consoleService->LogStringMessage(NS_LITERAL_STRING("Deprecated method document.getSelection() called. Please use window.getSelection() instead.").get()); } - nsIDOMWindow *window = GetWindow(); - NS_ENSURE_TRUE(window, NS_OK); + nsCOMPtr window = do_QueryInterface(GetScopeObject()); + nsCOMPtr pwin = do_QueryInterface(window); + NS_ENSURE_TRUE(pwin, NS_OK); + NS_ASSERTION(pwin->IsInnerWindow(), "Should have inner window here!"); + NS_ENSURE_TRUE(pwin->GetOuterWindow() && + pwin->GetOuterWindow()->GetCurrentInnerWindow() == pwin, + NS_OK); nsCOMPtr selection; nsresult rv = window->GetSelection(getter_AddRefs(selection)); diff --git a/content/xbl/src/nsBindingManager.cpp b/content/xbl/src/nsBindingManager.cpp index 8cbcf555..555db8fd 100644 --- a/content/xbl/src/nsBindingManager.cpp +++ b/content/xbl/src/nsBindingManager.cpp @@ -383,6 +383,9 @@ nsBindingManager::SetBinding(nsIContent* aContent, nsXBLBinding* aBinding) SetWrappedJS(aContent, nsnull); SetContentListFor(aContent, nsnull); SetAnonymousNodesFor(aContent, nsnull); + if (oldBinding) { + oldBinding->SetBoundElement(nsnull); + } } return result ? NS_OK : NS_ERROR_FAILURE; diff --git a/content/xbl/src/nsXBLBinding.cpp b/content/xbl/src/nsXBLBinding.cpp index 01e3158d..ccbcaebe 100644 --- a/content/xbl/src/nsXBLBinding.cpp +++ b/content/xbl/src/nsXBLBinding.cpp @@ -1217,7 +1217,7 @@ nsXBLBinding::AllowScripts() return PR_FALSE; } - nsIDocument* doc = mBoundElement->GetOwnerDoc(); + nsIDocument* doc = mBoundElement ? mBoundElement->GetOwnerDoc() : nsnull; if (!doc) { return PR_FALSE; } diff --git a/content/xul/document/src/nsXULCommandDispatcher.cpp b/content/xul/document/src/nsXULCommandDispatcher.cpp index 50c93173..fc63ecbd 100644 --- a/content/xul/document/src/nsXULCommandDispatcher.cpp +++ b/content/xul/document/src/nsXULCommandDispatcher.cpp @@ -383,6 +383,8 @@ nsXULCommandDispatcher::UpdateCommands(const nsAString& aEventName) free(actionString); } #endif + + nsCOMArray updaters; for (Updater* updater = mUpdaters; updater != nsnull; updater = updater->mNext) { nsCOMPtr element; @@ -401,6 +403,12 @@ nsXULCommandDispatcher::UpdateCommands(const nsAString& aEventName) NS_ASSERTION(content != nsnull, "not an nsIContent"); if (! content) return NS_ERROR_UNEXPECTED; + + updaters.AppendObject(content); + } + + for (PRUint32 u = 0; u < updaters.Count(); u++) { + nsIContent* content = updaters[u]; nsCOMPtr document = content->GetDocument(); @@ -414,7 +422,7 @@ nsXULCommandDispatcher::UpdateCommands(const nsAString& aEventName) CopyUTF16toUTF8(aEventName, aeventnameC); PR_LOG(gLog, PR_LOG_NOTICE, ("xulcmd[%p] update %p event=%s", - this, element.get(), + this, content, aeventnameC.get())); } #endif @@ -500,4 +508,3 @@ nsXULCommandDispatcher::SetSuppressFocusScroll(PRBool aSuppressFocusScroll) return mFocusController->SetSuppressFocusScroll(aSuppressFocusScroll); } - diff --git a/content/xul/templates/src/Makefile.in b/content/xul/templates/src/Makefile.in index fd635862..c8c04ca3 100644 --- a/content/xul/templates/src/Makefile.in +++ b/content/xul/templates/src/Makefile.in @@ -96,7 +96,8 @@ FORCE_STATIC_LIB = 1 include $(topsrcdir)/config/rules.mk LOCAL_INCLUDES = -I$(srcdir)/../../../base/src \ - -I$(srcdir)/../../content/src \ - $(NULL) + -I$(srcdir)/../../content/src \ + -I$(srcdir)/../../../../layout/xul/base/src/tree/src \ + $(NULL) DEFINES += -D_IMPL_NS_LAYOUT diff --git a/content/xul/templates/src/nsXULTreeBuilder.cpp b/content/xul/templates/src/nsXULTreeBuilder.cpp index 1ef43384..455f3b29 100644 --- a/content/xul/templates/src/nsXULTreeBuilder.cpp +++ b/content/xul/templates/src/nsXULTreeBuilder.cpp @@ -72,6 +72,8 @@ #include "nsUnicharUtils.h" #include "nsINameSpaceManager.h" #include "nsIDOMClassInfo.h" +#include "nsTreeContentView.h" +#include "nsDOMError.h" // For security check #include "nsIDocument.h" @@ -482,6 +484,9 @@ nsXULTreeBuilder::GetSelection(nsITreeSelection** aSelection) NS_IMETHODIMP nsXULTreeBuilder::SetSelection(nsITreeSelection* aSelection) { + NS_ENSURE_TRUE(!aSelection || + nsTreeContentView::CanTrustTreeSelection(aSelection), + NS_ERROR_DOM_SECURITY_ERR); mSelection = aSelection; return NS_OK; } diff --git a/db/sqlite3/src/os_win.c b/db/sqlite3/src/os_win.c index 147ded35..7a61ec7f 100644 --- a/db/sqlite3/src/os_win.c +++ b/db/sqlite3/src/os_win.c @@ -123,6 +123,163 @@ int sqlite3_os_type = 0; } #endif /* OS_WINCE */ +/*** UTF16<-->UTF8 functions minicking MultiByteToWideChar/WideCharToMultiByte ***/ +int utf8GetMaskIndex(unsigned char n) { + if((unsigned char)(n + 2) < 0xc2) return 1; // 00~10111111, fe, ff + if(n < 0xe0) return 2; // 110xxxxx + if(n < 0xf0) return 3; // 1110xxxx + if(n < 0xf8) return 4; // 11110xxx + if(n < 0xfc) return 5; // 111110xx + return 6; // 1111110x +} + +int wc2Utf8Len(wchar_t ** n, int *len) { + wchar_t *ch = *n, ch2; + int qch; + if((0xD800 <= *ch && *ch <= 0xDBFF) && *len) { + ch2 = *(ch + 1); + if(0xDC00 <= ch2 && ch2 <= 0xDFFF) { + qch = 0x10000 + (((*ch - 0xD800) & 0x3ff) << 10) + ((ch2 - 0xDC00) & 0x3ff); + (*n)++; + (*len)--; + } + } + else + qch = (int) *ch; + + if (qch <= 0x7f) return 1; + else if (qch <= 0x7ff) return 2; + else if (qch <= 0xffff) return 3; + else if (qch <= 0x1fffff) return 4; + else if (qch <= 0x3ffffff) return 5; + else return 6; +} + +int Utf8ToWideChar(unsigned int unused1, unsigned long unused2, char *sb, int ss, wchar_t * wb, int ws) { + static const unsigned char utf8mask[] = { 0, 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; + char *p = (char *)(sb); + char *e = (char *)(sb + ss); + wchar_t *w = wb; + int cnt = 0, t, qch; + + if (ss < 1) { + ss = lstrlenA(sb); + e = (char *)(sb + ss); + } + + if (wb && ws) { + for (; p < e; ++w) { + t = utf8GetMaskIndex(*p); + qch = (*p++ & utf8mask[t]); + while(p < e && --t) + qch <<= 6, qch |= (*p++) & 0x3f; + if(qch < 0x10000) { + if(cnt <= ws) + *w = (wchar_t) qch; + cnt++; + } else { + if (cnt + 2 <= ws) { + *w++ = (wchar_t) (0xD800 + (((qch - 0x10000) >> 10) & 0x3ff)), + *w = (wchar_t) (0xDC00 + (((qch - 0x10000)) & 0x3ff)); + } + cnt += 2; + } + } + if(cnt < ws) { + *(wb+cnt) = 0; + return cnt; + } else { + *(wb+ws) = 0; + return ws; + } + } else { + for (t; p < e;) { + t = utf8GetMaskIndex(*p); + qch = (*p++ & utf8mask[t]); + while (p < e && --t) + qch <<= 6, qch |= (*p++) & 0x3f; + if (qch < 0x10000) + cnt++; + else + cnt += 2; + } + return cnt+1; + } +} + +int WideCharToUtf8(unsigned int unused1, unsigned long unused2, wchar_t * wb, int ws, char *sb, int ss) { + wchar_t *p = (wchar_t *)(wb); + wchar_t *e = (wchar_t *)(wb + ws); + wchar_t *oldp; + char *s = sb; + int cnt = 0, qch, t; + + if (ws < 1) { + ws = lstrlenW(wb); + e = (wchar_t *)(wb + ws); + } + + if (sb && ss) { + for (t; p < e; ++p) { + oldp = p; + t = wc2Utf8Len(&p, &ws); + + if (p != oldp) { /* unicode surrogates encountered */ + qch = 0x10000 + (((*oldp - 0xD800) & 0x3ff) << 10) + ((*p - 0xDC00) & 0x3ff); + } else + qch = *p; + + if (qch <= 0x7f) + *s++ = (char) (qch), + cnt++; + else if (qch <= 0x7ff) + *s++ = 0xc0 | (char) (qch >> 6), + *s++ = 0x80 | (char) (qch & 0x3f), + cnt += 2; + else if (qch <= 0xffff) + *s++ = 0xe0 | (char) (qch >> 12), + *s++ = 0x80 | (char) ((qch >> 6) & 0x3f), + *s++ = 0x80 | (char) (qch & 0x3f), + cnt += 3; + else if (qch <= 0x1fffff) + *s++ = 0xf0 | (char) (qch >> 18), + *s++ = 0x80 | (char) ((qch >> 12) & 0x3f), + *s++ = 0x80 | (char) ((qch >> 6) & 0x3f), + *s++ = 0x80 | (char) (qch & 0x3f), + cnt += 4; + else if (qch <= 0x3ffffff) + *s++ = 0xf8 | (char) (qch >> 24), + *s++ = 0x80 | (char) ((qch >> 18) & 0x3f), + *s++ = 0x80 | (char) ((qch >> 12) & 0x3f), + *s++ = 0x80 | (char) ((qch >> 6) & 0x3f), + *s++ = 0x80 | (char) (qch & 0x3f), + cnt += 5; + else + *s++ = 0xfc | (char) (qch >> 30), + *s++ = 0x80 | (char) ((qch >> 24) & 0x3f), + *s++ = 0x80 | (char) ((qch >> 18) & 0x3f), + *s++ = 0x80 | (char) ((qch >> 12) & 0x3f), + *s++ = 0x80 | (char) ((qch >> 6) & 0x3f), + *s++ = 0x80 | (char) (qch & 0x3f), + cnt += 6; + } + if(cnt < ss) { + *(sb+cnt) = 0; + return cnt; + } else { + *(sb+ss) = 0; + return ss; + } + } else { + for (t; p < e; ++p) { + t = wc2Utf8Len(&p, &ws); + cnt += t; + } + return cnt+1; + } +} +/*** Ends ***/ + /* ** Convert a UTF-8 string to UTF-32. Space to hold the returned string ** is obtained from sqliteMalloc. @@ -132,20 +289,12 @@ static WCHAR *utf8ToUnicode(const char *zFilename){ int nCharcpy; WCHAR *zWideFilename; - nCharcpy = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0); - if( zFilename!=0 && nCharcpy == 0) { - /* UTF8 conversion failed. This happens on NT 3.51 and 95. Make do with ACP conversion instead. */ - nCharcpy = MultiByteToWideChar(CP_ACP, 0, zFilename, -1, NULL, 0); - } + nCharcpy = Utf8ToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0); zWideFilename = sqliteMalloc( nCharcpy*sizeof(zWideFilename[0]) ); if( zWideFilename==0 ){ return 0; } - nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nCharcpy); - if( zFilename!=0 && nChar == 0) { - /* UTF8 conversion failed. This happens on NT 3.51 and 95. Make do with ACP conversion instead. */ - nChar = MultiByteToWideChar(CP_ACP, 0, zFilename, -1, zWideFilename, nCharcpy); - } + nChar = Utf8ToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nCharcpy); if( nChar==0 ){ sqliteFree(zWideFilename); @@ -163,22 +312,13 @@ static char *unicodeToUtf8(const WCHAR *zWideFilename){ int nBytecpy; char *zFilename; - nBytecpy = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0); - if( zWideFilename!=0 && nBytecpy == 0) { - /* UTF8 conversion failed. This happens on NT 3.51 and 95. Make do with ACP conversion instead. */ - nBytecpy = WideCharToMultiByte(CP_ACP, 0, zWideFilename, -1, 0, 0, 0, 0); - } + nBytecpy = WideCharToUtf8(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0); zFilename = sqliteMalloc( nBytecpy ); if( zFilename==0 ){ return 0; } - nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nBytecpy, + nByte = WideCharToUtf8(CP_UTF8, 0, zWideFilename, -1, zFilename, nBytecpy, 0, 0); - if( zWideFilename!=0 && nByte == 0) { - /* UTF8 conversion failed. This happens on NT 3.51 and 95. Make do with ACP conversion instead. */ - nByte = WideCharToMultiByte(CP_ACP, 0, zWideFilename, -1, zFilename, nBytecpy, - 0, 0); - } if( nByte == 0 ){ sqliteFree(zFilename); zFilename = 0; diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 54474d16..438da45e 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -56,6 +56,7 @@ #include "nsPIDOMStorage.h" #include "nsIDocumentViewer.h" #include "nsIDocumentLoaderFactory.h" +#include "nsIJARURI.h" #include "nsCURILoader.h" #include "nsDocShellCID.h" #include "nsLayoutCID.h" @@ -639,6 +640,7 @@ nsDocShell::LoadURI(nsIURI * aURI, nsCOMPtr headersStream; nsCOMPtr owner; PRBool inheritOwner = PR_FALSE; + PRBool ownerIsExplicit = PR_FALSE; PRBool sendReferrer = PR_TRUE; nsCOMPtr shEntry; nsXPIDLString target; @@ -662,6 +664,12 @@ nsDocShell::LoadURI(nsIURI * aURI, aLoadInfo->GetPostDataStream(getter_AddRefs(postStream)); aLoadInfo->GetHeadersStream(getter_AddRefs(headersStream)); aLoadInfo->GetSendReferrer(&sendReferrer); + + nsCOMPtr info19 = + do_QueryInterface(aLoadInfo); + if (info19) { + info19->GetOwnerIsExplicit(&ownerIsExplicit); + } } #if defined(PR_LOGGING) && defined(DEBUG) @@ -774,81 +782,98 @@ nsDocShell::LoadURI(nsIURI * aURI, ("nsDocShell[%p]: loading from session history", this)); #endif - rv = LoadHistoryEntry(shEntry, loadType); + return LoadHistoryEntry(shEntry, loadType); } - // Perform the load... - else { - // We need an owner (a referring principal). 4 possibilities: - // (1) If the system principal was passed in and we're a typeContent - // docshell, inherit the principal from the current document - // instead. - // (2) In all other cases when the principal passed in is not null, - // use that principal. - // (3) If the caller has allowed inheriting from the current - // document, or if we're being called from chrome (if there's - // system JS on the stack), then inheritOwner should be true and - // InternalLoad will get an owner from the current document. If - // none of these things are true, then - // (4) we pass a null owner into the channel, and an owner will be - // created later from the channel's internal data. - nsCOMPtr secMan = - do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - // Just to compare, not to use! - nsCOMPtr sysPrin; - rv = secMan->GetSystemPrincipal(getter_AddRefs(sysPrin)); - NS_ENSURE_SUCCESS(rv, rv); - - if (owner == sysPrin && mItemType != typeChrome) { + // Perform the load... + + // We need an owner (a referring principal). + // + // If ownerIsExplicit is not set there are 4 possibilities: + // (1) If the system principal was passed in and we're a typeContent + // docshell, inherit the principal from the current document + // instead. + // (2) In all other cases when the principal passed in is not null, + // use that principal. + // (3) If the caller has allowed inheriting from the current document, + // or if we're being called from system code (eg chrome JS or pure + // C++) then inheritOwner should be true and InternalLoad will get + // an owner from the current document. If none of these things are + // true, then + // (4) we pass a null owner into the channel, and an owner will be + // created later from the channel's internal data. + // + // If ownerIsExplicit *is* set, there are 4 possibilities + // (1) If the system principal was passed in and we're a typeContent + // docshell, return an error. + // (2) In all other cases when the principal passed in is not null, + // use that principal. + // (3) If the caller has allowed inheriting from the current document, + // then inheritOwner should be true and InternalLoad will get an owner + // from the current document. If none of these things are true, then + // (4) we pass a null owner into the channel, and an owner will be + // created later from the channel's internal data. + // + // NOTE: This all only works because the only thing the owner is used + // for in InternalLoad is data:, javascript:, and about:blank + // URIs. For other URIs this would all be dead wrong! + + nsCOMPtr secMan = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr sysPrin; + rv = secMan->GetSystemPrincipal(getter_AddRefs(sysPrin)); + NS_ENSURE_SUCCESS(rv, rv); + + if (owner && mItemType != typeChrome) { + nsCOMPtr ownerPrincipal = do_QueryInterface(owner); + PRBool isSystem = ownerPrincipal == sysPrin; + + if (isSystem) { + if (ownerIsExplicit) { + return NS_ERROR_DOM_SECURITY_ERR; + } owner = nsnull; inheritOwner = PR_TRUE; } - else if (!owner && !inheritOwner) { - // See if there's system or chrome JS code running - if (NS_SUCCEEDED(rv)) { - nsCOMPtr subjectPrin; - - rv = secMan->GetSubjectPrincipal(getter_AddRefs(subjectPrin)); - // If there's no subject principal, there's no JS running, so - // we're in system code. - if (NS_SUCCEEDED(rv) && - (!subjectPrin || sysPrin == subjectPrin)) { - inheritOwner = PR_TRUE; - } - } + } + if (!owner && !inheritOwner && !ownerIsExplicit) { + // See if there's system or chrome JS code running + rv = secMan->SubjectPrincipalIsSystem(&inheritOwner); + if (NS_FAILED(rv)) { + // Set it back to false + inheritOwner = PR_FALSE; } - - PRUint32 flags = 0; - - if (inheritOwner) - flags |= INTERNAL_LOAD_FLAGS_INHERIT_OWNER; - - if (!sendReferrer) - flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER; - - if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) - flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; - - if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD) - flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD; - - rv = InternalLoad(aURI, - referrer, - owner, - flags, - target.get(), - nsnull, // No type hint - postStream, - headersStream, - loadType, - nsnull, // No SHEntry - aFirstParty, - nsnull, // No nsIDocShell - nsnull); // No nsIRequest } - return rv; + PRUint32 flags = 0; + + if (inheritOwner) + flags |= INTERNAL_LOAD_FLAGS_INHERIT_OWNER; + + if (!sendReferrer) + flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER; + + if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) + flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; + + if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD) + flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD; + + return InternalLoad(aURI, + referrer, + owner, + flags, + target.get(), + nsnull, // No type hint + postStream, + headersStream, + loadType, + nsnull, // No SHEntry + aFirstParty, + nsnull, // No nsIDocShell + nsnull); // No nsIRequest } NS_IMETHODIMP @@ -3314,6 +3339,12 @@ nsDocShell::Reload(PRUint32 aReloadFlags) NS_IMETHODIMP nsDocShell::Stop(PRUint32 aStopFlags) { + if (mLoadType == LOAD_ERROR_PAGE && mLSHE) { + // Since error page loads never unset mLSHE, do so now + SetHistoryEntry(&mOSHE, mLSHE); + SetHistoryEntry(&mLSHE, nsnull); + } + if (nsIWebNavigation::STOP_CONTENT & aStopFlags) { // Revoke any pending plevents related to content viewer restoration nsCOMPtr uiThreadQueue; @@ -4495,6 +4526,25 @@ nsDocShell::SetupRefreshURIFromHeader(nsIURI * aBaseURI, rv = securityManager->CheckLoadURI(aBaseURI, uri, nsIScriptSecurityManager:: DISALLOW_FROM_MAIL); + + if (NS_SUCCEEDED(rv)) { + nsCOMPtr innerURI = uri; + nsCOMPtr jarURI(do_QueryInterface(innerURI)); + while (jarURI) { + jarURI->GetJARFile(getter_AddRefs(innerURI)); + jarURI = do_QueryInterface(innerURI); + } + NS_ENSURE_TRUE(innerURI, NS_ERROR_FAILURE); + + PRBool isjs = PR_TRUE; + rv = innerURI->SchemeIs("javascript", &isjs); + NS_ENSURE_SUCCESS(rv, rv); + + if (isjs) { + return NS_ERROR_FAILURE; + } + } + if (NS_SUCCEEDED(rv)) { // Since we can't travel back in time yet, just pretend // negative numbers do nothing at all. @@ -4831,6 +4881,12 @@ nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel, return; // nothing to tell anybody about AddToGlobalHistory(oldURI, PR_TRUE, aOldChannel); } + + if (!(aStateFlags & nsIChannelEventSink::REDIRECT_INTERNAL) && + mLoadType & (LOAD_CMD_RELOAD | LOAD_CMD_HISTORY)) { + mLoadType = LOAD_NORMAL_REPLACE; + SetHistoryEntry(&mLSHE, nsnull); + } } NS_IMETHODIMP @@ -8781,6 +8837,7 @@ NS_INTERFACE_MAP_BEGIN(nsRefreshTimer) NS_INTERFACE_MAP_ENTRY(nsITimerCallback) NS_INTERFACE_MAP_END_THREADSAFE + ///***************************************************************************** // nsRefreshTimer::nsITimerCallback //***************************************************************************** @@ -8820,46 +8877,46 @@ nsRefreshTimer::Notify(nsITimer * aTimer) */ loadInfo->SetReferrer(currURI); + /* Don't ever "guess" on which owner to use to avoid picking + * the current owner. + */ + nsCOMPtr info19 = + do_QueryInterface(loadInfo); + NS_ENSURE_TRUE(info19, NS_ERROR_NO_INTERFACE); + info19->SetOwnerIsExplicit(PR_TRUE); + /* Check if this META refresh causes a redirection - * to another site. + * to another site. */ PRBool equalUri = PR_FALSE; nsresult rv = mURI->Equals(currURI, &equalUri); - if (NS_SUCCEEDED(rv) && (!equalUri) && mMetaRefresh) { + if (NS_SUCCEEDED(rv) && (!equalUri) && mMetaRefresh && + mDelay <= REFRESH_REDIRECT_TIMER) { - /* It is a META refresh based redirection. Now check if it happened within - * the threshold time we have in mind(15000 ms as defined by REFRESH_REDIRECT_TIMER). - * If so, pass a REPLACE flag to LoadURI(). + /* It is a META refresh based redirection within the threshold time + * we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER). + * Pass a REPLACE flag to LoadURI(). */ - if (delay <= REFRESH_REDIRECT_TIMER) { - loadInfo->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace); - - /* for redirects we mimic HTTP, which passes the - * original referrer - */ - nsCOMPtr internalReferrer; - nsCOMPtr webNav = - do_QueryInterface(mDocShell); - if (webNav) { - webNav->GetReferringURI(getter_AddRefs(internalReferrer)); - if (internalReferrer) { - loadInfo->SetReferrer(internalReferrer); - } - } + loadInfo->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace); + + /* for redirects we mimic HTTP, which passes the + * original referrer + */ + nsCOMPtr internalReferrer; + + webNav->GetReferringURI(getter_AddRefs(internalReferrer)); + if (internalReferrer) { + loadInfo->SetReferrer(internalReferrer); } - else - loadInfo->SetLoadType(nsIDocShellLoadInfo::loadRefresh); - /* - * LoadURL(...) will cancel all refresh timers... This causes the Timer and - * its refreshData instance to be released... - */ - mDocShell->LoadURI(mURI, loadInfo, - nsIWebNavigation::LOAD_FLAGS_NONE, PR_TRUE); - return NS_OK; - } - else + else { loadInfo->SetLoadType(nsIDocShellLoadInfo::loadRefresh); + } + + /* + * LoadURI(...) will cancel all refresh timers... This causes the + * Timer and its refreshData instance to be released... + */ mDocShell->LoadURI(mURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, PR_TRUE); } return NS_OK; diff --git a/docshell/base/nsDocShellEnumerator.cpp b/docshell/base/nsDocShellEnumerator.cpp index 2eb60d3d..31afabab 100644 --- a/docshell/base/nsDocShellEnumerator.cpp +++ b/docshell/base/nsDocShellEnumerator.cpp @@ -43,16 +43,15 @@ nsDocShellEnumerator::nsDocShellEnumerator(PRInt32 inEnumerationDirection) : mRootItem(nsnull) -, mItemArray(nsnull) , mCurIndex(0) , mDocShellType(nsIDocShellTreeItem::typeAll) +, mArrayValid(PR_FALSE) , mEnumerationDirection(inEnumerationDirection) { } nsDocShellEnumerator::~nsDocShellEnumerator() { - delete mItemArray; } NS_IMPL_ISUPPORTS1(nsDocShellEnumerator, nsISimpleEnumerator) @@ -66,19 +65,15 @@ NS_IMETHODIMP nsDocShellEnumerator::GetNext(nsISupports **outCurItem) nsresult rv = EnsureDocShellArray(); if (NS_FAILED(rv)) return rv; - - if (mCurIndex >= 0 && mCurIndex < mItemArray->Count()) - { - nsIDocShellTreeItem* thisItem = NS_REINTERPRET_CAST(nsIDocShellTreeItem*, mItemArray->ElementAt(mCurIndex)); - rv = thisItem->QueryInterface(NS_GET_IID(nsISupports), (void **)outCurItem); - if (NS_FAILED(rv)) return rv; - } - else + + if (mCurIndex >= mItemArray.Length()) { return NS_ERROR_FAILURE; - - mCurIndex ++; - - return NS_OK; + } + + // post-increment is important here + nsCOMPtr item = do_QueryReferent(mItemArray[mCurIndex++], &rv); + item.forget(outCurItem); + return rv; } /* boolean hasMoreElements (); */ @@ -90,21 +85,21 @@ NS_IMETHODIMP nsDocShellEnumerator::HasMoreElements(PRBool *outHasMore) nsresult rv = EnsureDocShellArray(); if (NS_FAILED(rv)) return rv; - *outHasMore = (mCurIndex < mItemArray->Count()); + *outHasMore = (mCurIndex < mItemArray.Length()); return NS_OK; } nsresult nsDocShellEnumerator::GetEnumerationRootItem(nsIDocShellTreeItem * *aEnumerationRootItem) { NS_ENSURE_ARG_POINTER(aEnumerationRootItem); - *aEnumerationRootItem = mRootItem; - NS_IF_ADDREF(*aEnumerationRootItem); + nsCOMPtr item = do_QueryReferent(mRootItem); + item.forget(aEnumerationRootItem); return NS_OK; } nsresult nsDocShellEnumerator::SetEnumerationRootItem(nsIDocShellTreeItem * aEnumerationRootItem) { - mRootItem = aEnumerationRootItem; + mRootItem = do_GetWeakReference(aEnumerationRootItem); ClearState(); return NS_OK; } @@ -131,12 +126,10 @@ nsresult nsDocShellEnumerator::First() nsresult nsDocShellEnumerator::EnsureDocShellArray() { - if (!mItemArray) + if (!mArrayValid) { - mItemArray = new nsVoidArray; - if (!mItemArray) return NS_ERROR_OUT_OF_MEMORY; - - return BuildDocShellArray(*mItemArray); + mArrayValid = PR_TRUE; + return BuildDocShellArray(mItemArray); } return NS_OK; @@ -144,21 +137,21 @@ nsresult nsDocShellEnumerator::EnsureDocShellArray() nsresult nsDocShellEnumerator::ClearState() { - delete mItemArray; - mItemArray = nsnull; - + mItemArray.Clear(); + mArrayValid = PR_FALSE; mCurIndex = 0; return NS_OK; } -nsresult nsDocShellEnumerator::BuildDocShellArray(nsVoidArray& inItemArray) +nsresult nsDocShellEnumerator::BuildDocShellArray(nsTArray& inItemArray) { NS_ENSURE_TRUE(mRootItem, NS_ERROR_NOT_INITIALIZED); inItemArray.Clear(); - return BuildArrayRecursive(mRootItem, inItemArray); + nsCOMPtr item = do_QueryReferent(mRootItem); + return BuildArrayRecursive(item, inItemArray); } -nsresult nsDocShellForwardsEnumerator::BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsVoidArray& inItemArray) +nsresult nsDocShellForwardsEnumerator::BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsTArray& inItemArray) { nsresult rv; nsCOMPtr itemAsNode = do_QueryInterface(inItem, &rv); @@ -169,8 +162,8 @@ nsresult nsDocShellForwardsEnumerator::BuildArrayRecursive(nsIDocShellTreeItem* if ((mDocShellType == nsIDocShellTreeItem::typeAll) || (NS_SUCCEEDED(inItem->GetItemType(&itemType)) && (itemType == mDocShellType))) { - rv = inItemArray.AppendElement((void *)inItem); - if (NS_FAILED(rv)) return rv; + if (!inItemArray.AppendElement(do_GetWeakReference(inItem))) + return NS_ERROR_OUT_OF_MEMORY; } PRInt32 numChildren; @@ -191,7 +184,7 @@ nsresult nsDocShellForwardsEnumerator::BuildArrayRecursive(nsIDocShellTreeItem* } -nsresult nsDocShellBackwardsEnumerator::BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsVoidArray& inItemArray) +nsresult nsDocShellBackwardsEnumerator::BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsTArray& inItemArray) { nsresult rv; nsCOMPtr itemAsNode = do_QueryInterface(inItem, &rv); @@ -216,12 +209,10 @@ nsresult nsDocShellBackwardsEnumerator::BuildArrayRecursive(nsIDocShellTreeItem* if ((mDocShellType == nsIDocShellTreeItem::typeAll) || (NS_SUCCEEDED(inItem->GetItemType(&itemType)) && (itemType == mDocShellType))) { - rv = inItemArray.AppendElement((void *)inItem); - if (NS_FAILED(rv)) return rv; + if (!inItemArray.AppendElement(do_GetWeakReference(inItem))) + return NS_ERROR_OUT_OF_MEMORY; } return NS_OK; } - - diff --git a/docshell/base/nsDocShellEnumerator.h b/docshell/base/nsDocShellEnumerator.h index aa4758a0..eba22137 100644 --- a/docshell/base/nsDocShellEnumerator.h +++ b/docshell/base/nsDocShellEnumerator.h @@ -42,7 +42,9 @@ #include "nsIEnumerator.h" #include "nsCOMPtr.h" -#include "nsVoidArray.h" +#include "nsTArray.h" +#include "nsIWeakReference.h" +#include "nsIWeakReferenceUtils.h" class nsIDocShellTreeItem; @@ -98,17 +100,18 @@ protected: nsresult EnsureDocShellArray(); nsresult ClearState(); - nsresult BuildDocShellArray(nsVoidArray& inItemArray); - virtual nsresult BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsVoidArray& inItemArray) = 0; + nsresult BuildDocShellArray(nsTArray& inItemArray); + virtual nsresult BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsTArray& inItemArray) = 0; protected: - nsIDocShellTreeItem* mRootItem; // weak ref! + nsWeakPtr mRootItem; // weak ref! - nsVoidArray* mItemArray; // flattened list of items with matching type - PRInt32 mCurIndex; + nsTArray mItemArray; // flattened list of items with matching type + PRUint32 mCurIndex; PRInt32 mDocShellType; // only want shells of this type + PRPackedBool mArrayValid; // is mItemArray up to date? const PRInt8 mEnumerationDirection; }; @@ -125,7 +128,7 @@ public: protected: - virtual nsresult BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsVoidArray& inItemArray); + virtual nsresult BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsTArray& inItemArray); }; @@ -139,6 +142,6 @@ public: } protected: - virtual nsresult BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsVoidArray& inItemArray); + virtual nsresult BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsTArray& inItemArray); }; diff --git a/docshell/base/nsDocShellLoadInfo.cpp b/docshell/base/nsDocShellLoadInfo.cpp index e1d634f2..c919e60a 100644 --- a/docshell/base/nsDocShellLoadInfo.cpp +++ b/docshell/base/nsDocShellLoadInfo.cpp @@ -49,6 +49,7 @@ nsDocShellLoadInfo::nsDocShellLoadInfo() : mInheritOwner(PR_FALSE), + mOwnerIsExplicit(PR_FALSE), mSendReferrer(PR_TRUE), mLoadType(nsIDocShellLoadInfo::loadNormal) { @@ -68,6 +69,7 @@ NS_IMPL_RELEASE(nsDocShellLoadInfo) NS_INTERFACE_MAP_BEGIN(nsDocShellLoadInfo) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocShellLoadInfo) NS_INTERFACE_MAP_ENTRY(nsIDocShellLoadInfo) + NS_INTERFACE_MAP_ENTRY(nsIDocShellLoadInfo_1_9_0_BRANCH) NS_INTERFACE_MAP_END //***************************************************************************** @@ -118,6 +120,18 @@ NS_IMETHODIMP nsDocShellLoadInfo::SetInheritOwner(PRBool aInheritOwner) return NS_OK; } +NS_IMETHODIMP nsDocShellLoadInfo::GetOwnerIsExplicit(PRBool* aOwnerIsExplicit) +{ + *aOwnerIsExplicit = mOwnerIsExplicit; + return NS_OK; +} + +NS_IMETHODIMP nsDocShellLoadInfo::SetOwnerIsExplicit(PRBool aOwnerIsExplicit) +{ + mOwnerIsExplicit = aOwnerIsExplicit; + return NS_OK; +} + NS_IMETHODIMP nsDocShellLoadInfo::GetLoadType(nsDocShellInfoLoadType * aLoadType) { NS_ENSURE_ARG_POINTER(aLoadType); diff --git a/docshell/base/nsDocShellLoadInfo.h b/docshell/base/nsDocShellLoadInfo.h index c3701a68..e7d2cb54 100644 --- a/docshell/base/nsDocShellLoadInfo.h +++ b/docshell/base/nsDocShellLoadInfo.h @@ -51,13 +51,14 @@ #include "nsIInputStream.h" #include "nsISHEntry.h" -class nsDocShellLoadInfo : public nsIDocShellLoadInfo +class nsDocShellLoadInfo : public nsIDocShellLoadInfo_1_9_0_BRANCH { public: nsDocShellLoadInfo(); NS_DECL_ISUPPORTS NS_DECL_NSIDOCSHELLLOADINFO + NS_DECL_NSIDOCSHELLLOADINFO_1_9_0_BRANCH protected: virtual ~nsDocShellLoadInfo(); @@ -66,6 +67,7 @@ protected: nsCOMPtr mReferrer; nsCOMPtr mOwner; PRPackedBool mInheritOwner; + PRPackedBool mOwnerIsExplicit; PRPackedBool mSendReferrer; nsDocShellInfoLoadType mLoadType; nsCOMPtr mSHEntry; diff --git a/docshell/base/nsIDocShellLoadInfo.idl b/docshell/base/nsIDocShellLoadInfo.idl index dcbf325d..92dbc2ed 100644 --- a/docshell/base/nsIDocShellLoadInfo.idl +++ b/docshell/base/nsIDocShellLoadInfo.idl @@ -103,3 +103,15 @@ interface nsIDocShellLoadInfo : nsISupports */ attribute boolean sendReferrer; }; + +[scriptable, uuid(b66d94ba-4457-41b1-9507-79c1cd873da0)] +interface nsIDocShellLoadInfo_1_9_0_BRANCH : nsIDocShellLoadInfo +{ + /** If this attribute is true only ever use the owner specify by + * the owner and inheritOwner attributes. + * If there are security reasons for why this is unsafe, such + * as trying to use a systemprincipal owner for a content docshell + * the load fails. + */ + attribute boolean ownerIsExplicit; +}; diff --git a/docshell/base/nsWebShell.cpp b/docshell/base/nsWebShell.cpp index d49e2a4e..f2610b83 100644 --- a/docshell/base/nsWebShell.cpp +++ b/docshell/base/nsWebShell.cpp @@ -532,6 +532,10 @@ nsWebShell::OnLinkClickSync(nsIContent *aContent, nsCOMPtr anchor(do_QueryInterface(aContent)); if (anchor) { anchor->GetType(typeHint); + NS_ConvertUTF16toUTF8 utf8Hint(typeHint); + nsCAutoString type, dummy; + NS_ParseContentType(utf8Hint, type, dummy); + CopyUTF8toUTF16(type, typeHint); } switch(aVerb) { diff --git a/dom/public/base/nsPIDOMWindow.h b/dom/public/base/nsPIDOMWindow.h index 60104edf..473d9e6d 100644 --- a/dom/public/base/nsPIDOMWindow.h +++ b/dom/public/base/nsPIDOMWindow.h @@ -173,6 +173,7 @@ public: return mFrameElement; } + // Caller must release the old frame element and addref the new one. void SetFrameElementInternal(nsIDOMElement *aFrameElement) { if (IsOuterWindow()) { diff --git a/dom/public/nsIDOMClassInfo.h b/dom/public/nsIDOMClassInfo.h index cfb9b6e2..eed55e0a 100644 --- a/dom/public/nsIDOMClassInfo.h +++ b/dom/public/nsIDOMClassInfo.h @@ -191,7 +191,6 @@ enum nsDOMClassInfoID { // Crypto classes eDOMClassInfo_Crypto_id, eDOMClassInfo_CRMFObject_id, - eDOMClassInfo_Pkcs11_id, // DOM Traversal classes eDOMClassInfo_TreeWalker_id, diff --git a/dom/src/base/nsBarProps.cpp b/dom/src/base/nsBarProps.cpp index 157b657a..645671fc 100644 --- a/dom/src/base/nsBarProps.cpp +++ b/dom/src/base/nsBarProps.cpp @@ -51,8 +51,11 @@ // // Basic (virtual) BarProp class implementation // -nsBarProp::nsBarProp() : mBrowserChrome(nsnull) +nsBarProp::nsBarProp(nsGlobalWindow *aWindow) { + mDOMWindow = aWindow; + nsISupports *supwin = static_cast(aWindow); + mDOMWindowWeakref = do_GetWeakReference(supwin); } nsBarProp::~nsBarProp() @@ -71,25 +74,19 @@ NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsBarProp) NS_IMPL_RELEASE(nsBarProp) - -NS_IMETHODIMP -nsBarProp::SetWebBrowserChrome(nsIWebBrowserChrome* aBrowserChrome) -{ - mBrowserChrome = aBrowserChrome; - return NS_OK; -} - NS_IMETHODIMP nsBarProp::GetVisibleByFlag(PRBool *aVisible, PRUint32 aChromeFlag) { - NS_ENSURE_TRUE(mBrowserChrome, NS_ERROR_FAILURE); - - PRUint32 chromeFlags; *aVisible = PR_FALSE; - NS_ENSURE_SUCCESS(mBrowserChrome->GetChromeFlags(&chromeFlags), + nsCOMPtr browserChrome = GetBrowserChrome(); + NS_ENSURE_TRUE(browserChrome, NS_OK); + + PRUint32 chromeFlags; + + NS_ENSURE_SUCCESS(browserChrome->GetChromeFlags(&chromeFlags), NS_ERROR_FAILURE); - if(chromeFlags & aChromeFlag) + if (chromeFlags & aChromeFlag) *aVisible = PR_TRUE; return NS_OK; @@ -98,9 +95,10 @@ nsBarProp::GetVisibleByFlag(PRBool *aVisible, PRUint32 aChromeFlag) NS_IMETHODIMP nsBarProp::SetVisibleByFlag(PRBool aVisible, PRUint32 aChromeFlag) { - NS_ENSURE_TRUE(mBrowserChrome, NS_ERROR_FAILURE); + nsCOMPtr browserChrome = GetBrowserChrome(); + NS_ENSURE_TRUE(browserChrome, NS_OK); - PRBool enabled = PR_FALSE; + PRBool enabled = PR_FALSE; nsCOMPtr securityManager(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID)); @@ -111,23 +109,37 @@ nsBarProp::SetVisibleByFlag(PRBool aVisible, PRUint32 aChromeFlag) PRUint32 chromeFlags; - NS_ENSURE_SUCCESS(mBrowserChrome->GetChromeFlags(&chromeFlags), + NS_ENSURE_SUCCESS(browserChrome->GetChromeFlags(&chromeFlags), NS_ERROR_FAILURE); - if(aVisible) + if (aVisible) chromeFlags |= aChromeFlag; else chromeFlags &= ~aChromeFlag; - NS_ENSURE_SUCCESS(mBrowserChrome->SetChromeFlags(chromeFlags), + NS_ENSURE_SUCCESS(browserChrome->SetChromeFlags(chromeFlags), NS_ERROR_FAILURE); return NS_OK; } +already_AddRefed +nsBarProp::GetBrowserChrome() +{ + // Check that the window is still alive. + nsCOMPtr domwin(do_QueryReferent(mDOMWindowWeakref)); + if (!domwin) + return nsnull; + + nsIWebBrowserChrome *browserChrome = nsnull; + mDOMWindow->GetWebBrowserChrome(&browserChrome); + return browserChrome; +} + // // MenubarProp class implementation // -nsMenubarProp::nsMenubarProp() +nsMenubarProp::nsMenubarProp(nsGlobalWindow *aWindow) + : nsBarProp(aWindow) { } @@ -153,7 +165,8 @@ nsMenubarProp::SetVisible(PRBool aVisible) // ToolbarProp class implementation // -nsToolbarProp::nsToolbarProp() +nsToolbarProp::nsToolbarProp(nsGlobalWindow *aWindow) + : nsBarProp(aWindow) { } @@ -179,7 +192,8 @@ nsToolbarProp::SetVisible(PRBool aVisible) // LocationbarProp class implementation // -nsLocationbarProp::nsLocationbarProp() +nsLocationbarProp::nsLocationbarProp(nsGlobalWindow *aWindow) + : nsBarProp(aWindow) { } @@ -207,7 +221,8 @@ nsLocationbarProp::SetVisible(PRBool aVisible) // PersonalbarProp class implementation // -nsPersonalbarProp::nsPersonalbarProp() +nsPersonalbarProp::nsPersonalbarProp(nsGlobalWindow *aWindow) + : nsBarProp(aWindow) { } @@ -235,7 +250,8 @@ nsPersonalbarProp::SetVisible(PRBool aVisible) // StatusbarProp class implementation // -nsStatusbarProp::nsStatusbarProp() +nsStatusbarProp::nsStatusbarProp(nsGlobalWindow *aWindow) + : nsBarProp(aWindow) { } @@ -262,10 +278,8 @@ nsStatusbarProp::SetVisible(PRBool aVisible) // nsScrollbarsProp::nsScrollbarsProp(nsGlobalWindow *aWindow) +: nsBarProp(aWindow) { - mDOMWindow = aWindow; - nsISupports *supwin = NS_STATIC_CAST(nsIScriptGlobalObject *, aWindow); - mDOMWindowWeakref = do_GetWeakReference(supwin); } nsScrollbarsProp::~nsScrollbarsProp() @@ -339,7 +353,7 @@ nsScrollbarsProp::SetVisible(PRBool aVisible) } /* Notably absent is the part where we notify the chrome window using - mBrowserChrome->SetChromeFlags(). Given the possibility of multiple + GetBrowserChrome()->SetChromeFlags(). Given the possibility of multiple DOM windows (multiple top-level windows, even) within a single chrome window, the historical concept of a single "has scrollbars" flag in the chrome is inapplicable, and we can't tell at this level @@ -354,4 +368,3 @@ nsScrollbarsProp::SetVisible(PRBool aVisible) return NS_OK; } - diff --git a/dom/src/base/nsBarProps.h b/dom/src/base/nsBarProps.h index 80cc6838..f032c10e 100644 --- a/dom/src/base/nsBarProps.h +++ b/dom/src/base/nsBarProps.h @@ -56,26 +56,34 @@ class nsIWebBrowserChrome; class nsBarProp : public nsIDOMBarProp { public: - nsBarProp(); + explicit nsBarProp(nsGlobalWindow *aWindow); virtual ~nsBarProp(); NS_DECL_ISUPPORTS - NS_IMETHOD SetWebBrowserChrome(nsIWebBrowserChrome* aBrowserChrome); - NS_IMETHOD GetVisibleByFlag(PRBool *aVisible, PRUint32 aChromeFlag); NS_IMETHOD SetVisibleByFlag(PRBool aVisible, PRUint32 aChromeFlag); protected: - // Weak Reference - nsIWebBrowserChrome* mBrowserChrome; + already_AddRefed GetBrowserChrome(); + + nsGlobalWindow *mDOMWindow; + nsCOMPtr mDOMWindowWeakref; + /* Note the odd double reference to the owning global window. + Since the corresponding DOM window nominally owns this object, + but refcounted ownership of this object can be handed off to + owners unknown, we need a weak ref back to the DOM window. + However we also need access to properties of the DOM Window + that aren't available through interfaces. Then it's either + a weak ref and some skanky casting, or this funky double ref. + Funky beats skanky, so here we are. */ }; // Script "menubar" object class nsMenubarProp : public nsBarProp { public: - nsMenubarProp(); + explicit nsMenubarProp(nsGlobalWindow *aWindow); virtual ~nsMenubarProp(); NS_DECL_NSIDOMBARPROP @@ -85,7 +93,7 @@ public: class nsToolbarProp : public nsBarProp { public: - nsToolbarProp(); + explicit nsToolbarProp(nsGlobalWindow *aWindow); virtual ~nsToolbarProp(); NS_DECL_NSIDOMBARPROP @@ -95,7 +103,7 @@ public: class nsLocationbarProp : public nsBarProp { public: - nsLocationbarProp(); + explicit nsLocationbarProp(nsGlobalWindow *aWindow); virtual ~nsLocationbarProp(); NS_DECL_NSIDOMBARPROP @@ -105,7 +113,7 @@ public: class nsPersonalbarProp : public nsBarProp { public: - nsPersonalbarProp(); + explicit nsPersonalbarProp(nsGlobalWindow *aWindow); virtual ~nsPersonalbarProp(); NS_DECL_NSIDOMBARPROP @@ -115,31 +123,20 @@ public: class nsStatusbarProp : public nsBarProp { public: - nsStatusbarProp(); + explicit nsStatusbarProp(nsGlobalWindow *aWindow); virtual ~nsStatusbarProp(); NS_DECL_NSIDOMBARPROP }; // Script "scrollbars" object -class nsScrollbarsProp : public nsBarProp { +class nsScrollbarsProp : public nsBarProp +{ public: - nsScrollbarsProp(nsGlobalWindow *aWindow); + explicit nsScrollbarsProp(nsGlobalWindow *aWindow); virtual ~nsScrollbarsProp(); NS_DECL_NSIDOMBARPROP - -private: - nsGlobalWindow *mDOMWindow; - nsCOMPtr mDOMWindowWeakref; - /* Note the odd double reference to the owning global window. - Since the corresponding DOM window nominally owns this object, - yet refcounted ownership of this object can be handed off to - owners unknown, we need a weak ref to back to the DOM window. - However we also need access to properties of the DOM Window - that aren't available through interfaces. Then it's either - a weak ref and some skanky casting, or this funky double ref. - Funky beats skanky, so here we are. */ }; #endif /* nsBarProps_h___ */ diff --git a/dom/src/base/nsDOMClassInfo.cpp b/dom/src/base/nsDOMClassInfo.cpp index 5b3e0937..6399d6d7 100644 --- a/dom/src/base/nsDOMClassInfo.cpp +++ b/dom/src/base/nsDOMClassInfo.cpp @@ -309,7 +309,6 @@ #include "nsIDOMXULCommandDispatcher.h" #include "nsIDOMCrypto.h" #include "nsIDOMCRMFObject.h" -#include "nsIDOMPkcs11.h" #include "nsIControllers.h" #include "nsISelection.h" #include "nsIBoxObject.h" @@ -557,8 +556,7 @@ static nsDOMClassInfoData sClassInfoData[] = { DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(DOMException, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) - NS_DEFINE_CLASSINFO_DATA(DocumentFragment, nsDOMGenericSH, - DOM_DEFAULT_SCRIPTABLE_FLAGS) + NS_DEFINE_CLASSINFO_DATA(DocumentFragment, nsNodeSH, NODE_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(Element, nsElementSH, ELEMENT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(Attr, nsDOMGenericSH, @@ -806,8 +804,6 @@ static nsDOMClassInfoData sClassInfoData[] = { DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(CRMFObject, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) - NS_DEFINE_CLASSINFO_DATA(Pkcs11, nsDOMGenericSH, - DOM_DEFAULT_SCRIPTABLE_FLAGS) // DOM Traversal classes NS_DEFINE_CLASSINFO_DATA(TreeWalker, nsDOMGCParticipantSH, @@ -2418,10 +2414,6 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_ENTRY(nsIDOMCRMFObject) DOM_CLASSINFO_MAP_END - DOM_CLASSINFO_MAP_BEGIN(Pkcs11, nsIDOMPkcs11) - DOM_CLASSINFO_MAP_ENTRY(nsIDOMPkcs11) - DOM_CLASSINFO_MAP_END - DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XMLStylesheetProcessingInstruction, nsIDOMProcessingInstruction) DOM_CLASSINFO_MAP_ENTRY(nsIDOMProcessingInstruction) DOM_CLASSINFO_MAP_ENTRY(nsIDOMLinkStyle) @@ -6020,13 +6012,61 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, return NS_OK; } + JSString *str = JSVAL_TO_STRING(id); + + if (id == sLocation_id) { + // This must be done even if we're just getting the value of + // window.location (i.e. no checking flags & JSRESOLVE_ASSIGNING + // here) since we must define window.location to prevent the + // getter from being overriden (for security reasons). + + nsCOMPtr location; + rv = win->GetLocation(getter_AddRefs(location)); + NS_ENSURE_SUCCESS(rv, rv); + + // Make sure we wrap the location object in the inner window's + // scope if we've got an inner window. + JSObject *scope = nsnull; + if (win->IsOuterWindow()) { + nsGlobalWindow *innerWin = win->GetCurrentInnerWindowInternal(); + + if (innerWin) { + scope = innerWin->GetGlobalJSObject(); + } + } + + if (!scope) { + wrapper->GetJSObject(&scope); + } + + jsval v; + nsCOMPtr holder; + rv = WrapNative(cx, scope, location, NS_GET_IID(nsIDOMLocation), &v, + getter_AddRefs(holder)); + NS_ENSURE_SUCCESS(rv, rv); + + PRBool doSecurityCheckInAddProperty = sDoSecurityCheckInAddProperty; + sDoSecurityCheckInAddProperty = PR_FALSE; + + JSBool ok = ::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), + ::JS_GetStringLength(str), v, nsnull, + nsnull, JSPROP_ENUMERATE); + + sDoSecurityCheckInAddProperty = doSecurityCheckInAddProperty; + + if (!ok) { + return NS_ERROR_FAILURE; + } + + *objp = obj; + + return NS_OK; + } // Hmm, we do an awful lot of QIs here; maybe we should add a // method on an interface that would let us just call into the // window code directly... - JSString *str = JSVAL_TO_STRING(id); - // Don't resolve named iframes on native wrappers if (!ObjectIsNativeWrapper(cx, obj)) { nsCOMPtr dsn(do_QueryInterface(win->GetDocShell())); @@ -6145,55 +6185,6 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, return NS_OK; } - if (id == sLocation_id) { - // This must be done even if we're just getting the value of - // window.location (i.e. no checking flags & JSRESOLVE_ASSIGNING - // here) since we must define window.location to prevent the - // getter from being overriden (for security reasons). - - nsCOMPtr location; - rv = win->GetLocation(getter_AddRefs(location)); - NS_ENSURE_SUCCESS(rv, rv); - - // Make sure we wrap the location object in the inner window's - // scope if we've got an inner window. - JSObject *scope = nsnull; - if (win->IsOuterWindow()) { - nsGlobalWindow *innerWin = win->GetCurrentInnerWindowInternal(); - - if (innerWin) { - scope = innerWin->GetGlobalJSObject(); - } - } - - if (!scope) { - wrapper->GetJSObject(&scope); - } - - jsval v; - nsCOMPtr holder; - rv = WrapNative(cx, scope, location, NS_GET_IID(nsIDOMLocation), &v, - getter_AddRefs(holder)); - NS_ENSURE_SUCCESS(rv, rv); - - PRBool doSecurityCheckInAddProperty = sDoSecurityCheckInAddProperty; - sDoSecurityCheckInAddProperty = PR_FALSE; - - JSBool ok = ::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), v, nsnull, - nsnull, JSPROP_ENUMERATE); - - sDoSecurityCheckInAddProperty = doSecurityCheckInAddProperty; - - if (!ok) { - return NS_ERROR_FAILURE; - } - - *objp = obj; - - return NS_OK; - } - if (flags & JSRESOLVE_ASSIGNING) { if (IsReadonlyReplaceable(id) || (!(flags & JSRESOLVE_QUALIFIED) && IsWritableReplaceable(id))) { @@ -6760,17 +6751,6 @@ nsEventReceiverSH::AddEventListenerHelper(JSContext *cx, JSObject *obj, return JS_FALSE; } - // Can't use the macro OBJ_TO_INNER_OBJECT here due to it using the - // non-exported function js_GetSlotThreadSafe(). - { - JSClass *clasp = JS_GET_CLASS(cx, obj); - if (clasp->flags & JSCLASS_IS_EXTENDED) { - JSExtendedClass *xclasp = (JSExtendedClass*)clasp; - if (xclasp->innerObject) - obj = xclasp->innerObject(cx, obj); - } - } - nsCOMPtr wrapper; nsresult rv = sXPConnect->GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrapper)); @@ -6784,6 +6764,26 @@ nsEventReceiverSH::AddEventListenerHelper(JSContext *cx, JSObject *obj, // event listener. wrapper->GetJSObject(&obj); + // Can't use the macro OBJ_TO_INNER_OBJECT here due to it using the + // non-exported function js_GetSlotThreadSafe(). + { + JSClass *clasp = JS_GET_CLASS(cx, obj); + if (clasp->flags & JSCLASS_IS_EXTENDED) { + JSExtendedClass *xclasp = (JSExtendedClass*)clasp; + if (xclasp->innerObject) + obj = xclasp->innerObject(cx, obj); + } + } + if (!obj) { + return JS_FALSE; + } + rv = sXPConnect->GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrapper)); + + if (NS_FAILED(rv)) { + nsDOMClassInfo::ThrowJSException(cx, rv); + return JS_FALSE; + } + // Check that the caller has permission to call obj's addEventListener. if (NS_FAILED(sSecMan->CheckPropertyAccess(cx, obj, JS_GET_CLASS(cx, obj)->name, diff --git a/dom/src/base/nsGlobalWindow.cpp b/dom/src/base/nsGlobalWindow.cpp index 89ef1ea2..3be51293 100644 --- a/dom/src/base/nsGlobalWindow.cpp +++ b/dom/src/base/nsGlobalWindow.cpp @@ -97,7 +97,6 @@ #include "nsIDOMEvent.h" #include "nsIDOMKeyEvent.h" #include "nsIDOMPopupBlockedEvent.h" -#include "nsIDOMPkcs11.h" #include "nsDOMString.h" #include "nsIEmbeddingSiteWindow2.h" #include "nsIEventQueueService.h" @@ -444,6 +443,7 @@ nsGlobalWindow::~nsGlobalWindow() } } + NS_IF_RELEASE(mFrameElement); mDocument = nsnull; // Forces Release NS_ASSERTION(!mArguments, "mArguments wasn't cleaned up properly!"); @@ -1539,12 +1539,6 @@ nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell) mScreen->SetDocShell(aDocShell); if (mDocShell) { - // tell our member elements about the new browserwindow - if (mMenubar) { - nsCOMPtr browserChrome; - GetWebBrowserChrome(getter_AddRefs(browserChrome)); - mMenubar->SetWebBrowserChrome(browserChrome); - } // Get our enclosing chrome shell and retrieve its global window impl, so // that we can do some forwarding to the chrome document. @@ -2168,15 +2162,10 @@ nsGlobalWindow::GetMenubar(nsIDOMBarProp** aMenubar) *aMenubar = nsnull; if (!mMenubar) { - mMenubar = new nsMenubarProp(); + mMenubar = new nsMenubarProp(this); if (!mMenubar) { return NS_ERROR_OUT_OF_MEMORY; } - - nsCOMPtr browserChrome; - GetWebBrowserChrome(getter_AddRefs(browserChrome)); - - mMenubar->SetWebBrowserChrome(browserChrome); } NS_ADDREF(*aMenubar = mMenubar); @@ -2192,15 +2181,10 @@ nsGlobalWindow::GetToolbar(nsIDOMBarProp** aToolbar) *aToolbar = nsnull; if (!mToolbar) { - mToolbar = new nsToolbarProp(); + mToolbar = new nsToolbarProp(this); if (!mToolbar) { return NS_ERROR_OUT_OF_MEMORY; } - - nsCOMPtr browserChrome; - GetWebBrowserChrome(getter_AddRefs(browserChrome)); - - mToolbar->SetWebBrowserChrome(browserChrome); } NS_ADDREF(*aToolbar = mToolbar); @@ -2216,15 +2200,10 @@ nsGlobalWindow::GetLocationbar(nsIDOMBarProp** aLocationbar) *aLocationbar = nsnull; if (!mLocationbar) { - mLocationbar = new nsLocationbarProp(); + mLocationbar = new nsLocationbarProp(this); if (!mLocationbar) { return NS_ERROR_OUT_OF_MEMORY; } - - nsCOMPtr browserChrome; - GetWebBrowserChrome(getter_AddRefs(browserChrome)); - - mLocationbar->SetWebBrowserChrome(browserChrome); } NS_ADDREF(*aLocationbar = mLocationbar); @@ -2240,15 +2219,10 @@ nsGlobalWindow::GetPersonalbar(nsIDOMBarProp** aPersonalbar) *aPersonalbar = nsnull; if (!mPersonalbar) { - mPersonalbar = new nsPersonalbarProp(); + mPersonalbar = new nsPersonalbarProp(this); if (!mPersonalbar) { return NS_ERROR_OUT_OF_MEMORY; } - - nsCOMPtr browserChrome; - GetWebBrowserChrome(getter_AddRefs(browserChrome)); - - mPersonalbar->SetWebBrowserChrome(browserChrome); } NS_ADDREF(*aPersonalbar = mPersonalbar); @@ -2264,15 +2238,10 @@ nsGlobalWindow::GetStatusbar(nsIDOMBarProp** aStatusbar) *aStatusbar = nsnull; if (!mStatusbar) { - mStatusbar = new nsStatusbarProp(); + mStatusbar = new nsStatusbarProp(this); if (!mStatusbar) { return NS_ERROR_OUT_OF_MEMORY; } - - nsCOMPtr browserChrome; - GetWebBrowserChrome(getter_AddRefs(browserChrome)); - - mStatusbar->SetWebBrowserChrome(browserChrome); } NS_ADDREF(*aStatusbar = mStatusbar); @@ -2292,11 +2261,6 @@ nsGlobalWindow::GetScrollbars(nsIDOMBarProp** aScrollbars) if (!mScrollbars) { return NS_ERROR_OUT_OF_MEMORY; } - - nsCOMPtr browserChrome; - GetWebBrowserChrome(getter_AddRefs(browserChrome)); - - mScrollbars->SetWebBrowserChrome(browserChrome); } NS_ADDREF(*aScrollbars = mScrollbars); @@ -2358,14 +2322,7 @@ nsGlobalWindow::GetCrypto(nsIDOMCrypto** aCrypto) NS_IMETHODIMP nsGlobalWindow::GetPkcs11(nsIDOMPkcs11** aPkcs11) { - FORWARD_TO_OUTER(GetPkcs11, (aPkcs11), NS_ERROR_NOT_INITIALIZED); - - if (!mPkcs11) { - mPkcs11 = do_CreateInstance(kPkcs11ContractID); - } - - NS_IF_ADDREF(*aPkcs11 = mPkcs11); - + *aPkcs11 = nsnull; return NS_OK; } @@ -3301,6 +3258,9 @@ nsGlobalWindow::EnsureReflowFlushAndPaint() NS_ASSERTION(mDocShell, "EnsureReflowFlushAndPaint() called with no " "docshell!"); + if (!mDocShell) + return; + nsCOMPtr presShell; mDocShell->GetPresShell(getter_AddRefs(presShell)); @@ -5153,6 +5113,7 @@ nsGlobalWindow::FindInternal(const nsAString& aStr, PRBool caseSensitive, *aDidFind = PR_FALSE; nsCOMPtr finder(do_GetInterface(mDocShell)); + NS_ENSURE_TRUE(finder, NS_ERROR_FAILURE); // Set the options of the search rv = finder->SetSearchString(PromiseFlatString(aStr).get()); @@ -7920,6 +7881,10 @@ nsNavigator::nsNavigator(nsIDocShell *aDocShell) nsNavigator::~nsNavigator() { sPrefInternal_id = JSVAL_VOID; + if (mMimeTypes) + mMimeTypes->Invalidate(); + if (mPlugins) + mPlugins->Invalidate(); } //***************************************************************************** @@ -8464,8 +8429,15 @@ nsNavigator::LoadingNewDocument() // Release these so that they will be recreated for the // new document (if requested). The plugins or mime types // arrays may have changed. See bug 150087. - mMimeTypes = nsnull; - mPlugins = nsnull; + if (mMimeTypes) { + mMimeTypes->Invalidate(); + mMimeTypes = nsnull; + } + + if (mPlugins) { + mPlugins->Invalidate(); + mPlugins = nsnull; + } } nsresult diff --git a/dom/src/base/nsGlobalWindow.h b/dom/src/base/nsGlobalWindow.h index b7647088..f5c3d3b5 100644 --- a/dom/src/base/nsGlobalWindow.h +++ b/dom/src/base/nsGlobalWindow.h @@ -82,7 +82,6 @@ #include "nsIEventListenerManager.h" #include "nsIDOMDocument.h" #include "nsIDOMCrypto.h" -#include "nsIDOMPkcs11.h" #include "nsIPrincipal.h" #include "nsPluginArray.h" #include "nsMimeTypeArray.h" @@ -319,6 +318,8 @@ public: friend class WindowStateHolder; protected: + friend class nsBarProp; + // Object Management virtual ~nsGlobalWindow(); void CleanUp(); @@ -537,7 +538,6 @@ protected: nsIScriptGlobalObjectOwner* mGlobalObjectOwner; // Weak Reference nsIDocShell* mDocShell; // Weak Reference nsCOMPtr mCrypto; - nsCOMPtr mPkcs11; nsCOMPtr gGlobalStorageList; diff --git a/dom/src/base/nsJSEnvironment.cpp b/dom/src/base/nsJSEnvironment.cpp index 5215ea13..ce6012b5 100644 --- a/dom/src/base/nsJSEnvironment.cpp +++ b/dom/src/base/nsJSEnvironment.cpp @@ -248,6 +248,13 @@ NS_ScriptErrorReporter(JSContext *cx, } else { errorevent.errorMsg = xoriginMsg.get(); errorevent.lineNr = 0; + // FIXME: once the principal of the script is not tied to + // the filename, we can stop using the post-redirect + // filename if we want and remove this line. Note that + // apparently we can't handle null filenames in the error + // event dispatching code. + static PRUnichar nullFilename[] = { PRUnichar(0) }; + errorevent.fileName = nullFilename; } // HandleDOMEvent() must be synchronous for the recursion block diff --git a/dom/src/base/nsMimeTypeArray.cpp b/dom/src/base/nsMimeTypeArray.cpp index cacb5bae..26389fc5 100644 --- a/dom/src/base/nsMimeTypeArray.cpp +++ b/dom/src/base/nsMimeTypeArray.cpp @@ -1,4 +1,5 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 sw=2 et tw=79: */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -197,6 +198,9 @@ nsresult nsMimeTypeArray::GetMimeTypes() { NS_PRECONDITION(!mMimeTypeArray && mMimeTypeCount==0, "already initialized"); + if (!mNavigator) { + return NS_ERROR_NOT_AVAILABLE; + } nsIDOMPluginArray* pluginArray = nsnull; nsresult rv = mNavigator->GetPlugins(&pluginArray); @@ -225,14 +229,14 @@ nsresult nsMimeTypeArray::GetMimeTypes() PRUint32 mimeTypeIndex = 0; PRUint32 k; for (k = 0; k < pluginCount; k++) { - nsIDOMPlugin* plugin = nsnull; - if (pluginArray->Item(k, &plugin) == NS_OK) { + nsCOMPtr plugin; + if (NS_SUCCEEDED(pluginArray->Item(k, getter_AddRefs(plugin))) && + plugin) { PRUint32 mimeTypeCount = 0; if (plugin->GetLength(&mimeTypeCount) == NS_OK) { for (PRUint32 j = 0; j < mimeTypeCount; j++) plugin->Item(j, &mMimeTypeArray[mimeTypeIndex++]); } - NS_RELEASE(plugin); } } } diff --git a/dom/src/base/nsMimeTypeArray.h b/dom/src/base/nsMimeTypeArray.h index 10604138..b64cf618 100644 --- a/dom/src/base/nsMimeTypeArray.h +++ b/dom/src/base/nsMimeTypeArray.h @@ -1,4 +1,5 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 sw=2 et tw=79: */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -45,6 +46,8 @@ class nsIDOMNavigator; +// NB: Due to weak references, nsNavigator has intimate knowledge of our +// members. class nsMimeTypeArray : public nsIDOMMimeTypeArray { public: @@ -58,6 +61,13 @@ public: NS_IMETHOD NamedItem(const nsAString& aName, nsIDOMMimeType** aReturn); nsresult Refresh(); + void Invalidate() + { + // NB: This will cause GetMimeTypes to fail from now on. + mNavigator = nsnull; + Clear(); + } + private: nsresult GetMimeTypes(); void Clear(); diff --git a/dom/src/base/nsPluginArray.cpp b/dom/src/base/nsPluginArray.cpp index 9670a105..dd133851 100644 --- a/dom/src/base/nsPluginArray.cpp +++ b/dom/src/base/nsPluginArray.cpp @@ -181,11 +181,18 @@ nsPluginArray::GetPluginHost(nsIPluginHost** aPluginHost) } void -nsPluginArray::SetDocShell(nsIDocShell* aDocShell) +nsPluginArray::SetDocShell(nsIDocShell *aDocShell) { mDocShell = aDocShell; } +void +nsPluginArray::Invalidate() +{ + mDocShell = nsnull; + mNavigator = nsnull; +} + NS_IMETHODIMP nsPluginArray::Refresh(PRBool aReloadDocuments) { diff --git a/dom/src/base/nsPluginArray.h b/dom/src/base/nsPluginArray.h index df1ed61c..a0f87591 100644 --- a/dom/src/base/nsPluginArray.h +++ b/dom/src/base/nsPluginArray.h @@ -47,6 +47,8 @@ class nsNavigator; class nsIDocShell; class nsIPluginHost; +// NB: Due to weak references, nsNavigator has intimate knowledge of our +// internals. class nsPluginArray : public nsIDOMPluginArray, public nsIDOMJSPluginArray { @@ -69,7 +71,8 @@ private: PRBool AllowPlugins(); public: - void SetDocShell(nsIDocShell* aDocShell); + void SetDocShell(nsIDocShell *aDocShell); + void Invalidate(); protected: nsNavigator* mNavigator; diff --git a/editor/composer/src/nsEditingSession.cpp b/editor/composer/src/nsEditingSession.cpp index 51651046..3f0f373e 100644 --- a/editor/composer/src/nsEditingSession.cpp +++ b/editor/composer/src/nsEditingSession.cpp @@ -1125,9 +1125,10 @@ nsEditingSession::EndDocumentLoad(nsIWebProgress *aWebProgress, if (NS_FAILED(rv)) return rv; mEditorStatus = eEditorCreationInProgress; + mDocShell = do_GetWeakReference(docShell); mLoadBlankDocTimer->InitWithFuncCallback( nsEditingSession::TimerCallback, - (void*)docShell, + static_cast (mDocShell.get()), 10, nsITimer::TYPE_ONE_SHOT); } } @@ -1139,7 +1140,7 @@ nsEditingSession::EndDocumentLoad(nsIWebProgress *aWebProgress, void nsEditingSession::TimerCallback(nsITimer* aTimer, void* aClosure) { - nsCOMPtr docShell = (nsIDocShell*)aClosure; + nsCOMPtr docShell = do_QueryReferent(static_cast (aClosure)); if (docShell) { nsCOMPtr webNav(do_QueryInterface(docShell)); diff --git a/editor/composer/src/nsEditingSession.h b/editor/composer/src/nsEditingSession.h index 7d40db33..33db4264 100644 --- a/editor/composer/src/nsEditingSession.h +++ b/editor/composer/src/nsEditingSession.h @@ -163,6 +163,9 @@ protected: PRUint32 mBaseCommandControllerId; PRUint32 mDocStateControllerId; PRUint32 mHTMLCommandControllerId; + + // Make sure the docshell we use is safe + nsWeakPtr mDocShell; }; diff --git a/editor/libeditor/base/nsEditor.cpp b/editor/libeditor/base/nsEditor.cpp index 81e8314c..2676d428 100644 --- a/editor/libeditor/base/nsEditor.cpp +++ b/editor/libeditor/base/nsEditor.cpp @@ -982,12 +982,12 @@ nsEditor::BeginPlaceHolderTransaction(nsIAtom *aName) mPlaceHolderName = aName; nsCOMPtr selection; nsresult res = GetSelection(getter_AddRefs(selection)); - if (NS_FAILED(res)) return res; - mSelState = new nsSelectionState(); - if (!mSelState) - return NS_ERROR_OUT_OF_MEMORY; - - mSelState->SaveSelection(selection); + if (NS_SUCCEEDED(res)) { + mSelState = new nsSelectionState(); + if (mSelState) { + mSelState->SaveSelection(selection); + } + } } mPlaceHolderBatch++; diff --git a/editor/libeditor/text/nsTextEditRules.cpp b/editor/libeditor/text/nsTextEditRules.cpp index 88d32635..2a3931a6 100644 --- a/editor/libeditor/text/nsTextEditRules.cpp +++ b/editor/libeditor/text/nsTextEditRules.cpp @@ -201,6 +201,12 @@ nsTextEditRules::BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection) nsAutoLockRulesSniffing lockIt(this); mDidExplicitlySetInterline = PR_FALSE; + if (!mActionNesting) + { + // let rules remember the top level action + mTheAction = action; + } + mActionNesting++; // get the selection and cache the position before editing nsCOMPtr selection; @@ -211,12 +217,6 @@ nsTextEditRules::BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection) selection->GetAnchorNode(getter_AddRefs(mCachedSelectionNode)); selection->GetAnchorOffset(&mCachedSelectionOffset); - if (!mActionNesting) - { - // let rules remember the top level action - mTheAction = action; - } - mActionNesting++; return NS_OK; } diff --git a/embedding/components/windowwatcher/src/nsPromptService.cpp b/embedding/components/windowwatcher/src/nsPromptService.cpp index 4ce7f19d..0346e561 100644 --- a/embedding/components/windowwatcher/src/nsPromptService.cpp +++ b/embedding/components/windowwatcher/src/nsPromptService.cpp @@ -652,6 +652,8 @@ nsPromptService::DoDialog(nsIDOMWindow *aParent, aParent = activeParent; } + aParamBlock->SetInt(eButtonPressed, 1); + nsCOMPtr arguments(do_QueryInterface(aParamBlock)); nsCOMPtr dialog; rv = mWatcher->OpenWindow(aParent, aChromeURL, "_blank", diff --git a/extensions/transformiix/source/xpath/Expr.h b/extensions/transformiix/source/xpath/Expr.h index 7aea1524..608d80d5 100644 --- a/extensions/transformiix/source/xpath/Expr.h +++ b/extensions/transformiix/source/xpath/Expr.h @@ -169,7 +169,8 @@ protected: /* * Evaluates the given Expression and converts its result to a number. */ - double evaluateToNumber(Expr* aExpr, txIEvalContext* aContext); + static nsresult evaluateToNumber(Expr* aExpr, txIEvalContext* aContext, + double* aResult); /* * Evaluates the given Expression and converts its result to a boolean. diff --git a/extensions/transformiix/source/xpath/FunctionCall.cpp b/extensions/transformiix/source/xpath/FunctionCall.cpp index bf0cb92d..93b6243d 100644 --- a/extensions/transformiix/source/xpath/FunctionCall.cpp +++ b/extensions/transformiix/source/xpath/FunctionCall.cpp @@ -99,15 +99,19 @@ void FunctionCall::evaluateToString(Expr* aExpr, txIEvalContext* aContext, /* * Evaluates the given Expression and converts its result to a number. */ -double FunctionCall::evaluateToNumber(Expr* aExpr, txIEvalContext* aContext) +// static +nsresult +FunctionCall::evaluateToNumber(Expr* aExpr, txIEvalContext* aContext, + double* aResult) { NS_ASSERTION(aExpr, "missing expression"); nsRefPtr exprResult; nsresult rv = aExpr->evaluate(aContext, getter_AddRefs(exprResult)); - if (NS_FAILED(rv)) - return Double::NaN; + NS_ENSURE_SUCCESS(rv, rv); - return exprResult->numberValue(); + *aResult = exprResult->numberValue(); + + return NS_OK; } /* diff --git a/extensions/transformiix/source/xpath/NumberFunctionCall.cpp b/extensions/transformiix/source/xpath/NumberFunctionCall.cpp index 2fdd011e..04e710ae 100644 --- a/extensions/transformiix/source/xpath/NumberFunctionCall.cpp +++ b/extensions/transformiix/source/xpath/NumberFunctionCall.cpp @@ -79,7 +79,10 @@ NumberFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) switch (mType) { case CEILING: { - double dbl = evaluateToNumber((Expr*)iter.next(), aContext); + double dbl; + nsresult rv = evaluateToNumber((Expr*)iter.next(), aContext, &dbl); + NS_ENSURE_SUCCESS(rv, rv); + if (!Double::isNaN(dbl) && !Double::isInfinite(dbl)) { if (Double::isNeg(dbl) && dbl > -1) { dbl *= 0; @@ -93,7 +96,10 @@ NumberFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) } case FLOOR: { - double dbl = evaluateToNumber((Expr*)iter.next(), aContext); + double dbl; + nsresult rv = evaluateToNumber((Expr*)iter.next(), aContext, &dbl); + NS_ENSURE_SUCCESS(rv, rv); + if (!Double::isNaN(dbl) && !Double::isInfinite(dbl) && !(dbl == 0 && Double::isNeg(dbl))) { @@ -104,7 +110,10 @@ NumberFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) } case ROUND: { - double dbl = evaluateToNumber((Expr*)iter.next(), aContext); + double dbl; + nsresult rv = evaluateToNumber((Expr*)iter.next(), aContext, &dbl); + NS_ENSURE_SUCCESS(rv, rv); + if (!Double::isNaN(dbl) && !Double::isInfinite(dbl)) { if (Double::isNeg(dbl) && dbl >= -0.5) { dbl *= 0; @@ -136,7 +145,8 @@ NumberFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) { double res; if (iter.hasNext()) { - res = evaluateToNumber((Expr*)iter.next(), aContext); + nsresult rv = evaluateToNumber((Expr*)iter.next(), aContext, &res); + NS_ENSURE_SUCCESS(rv, rv); } else { nsAutoString resultStr; diff --git a/extensions/transformiix/source/xpath/StringFunctionCall.cpp b/extensions/transformiix/source/xpath/StringFunctionCall.cpp index f9b66d2b..a78a3dda 100644 --- a/extensions/transformiix/source/xpath/StringFunctionCall.cpp +++ b/extensions/transformiix/source/xpath/StringFunctionCall.cpp @@ -193,7 +193,8 @@ StringFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) nsAutoString src; double start, end; evaluateToString((Expr*)iter.next(), aContext, src); - start = evaluateToNumber((Expr*)iter.next(), aContext); + rv = evaluateToNumber((Expr*)iter.next(), aContext, &start); + NS_ENSURE_SUCCESS(rv, rv); // check for NaN or +/-Inf if (Double::isNaN(start) || @@ -206,8 +207,10 @@ StringFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) start = floor(start + 0.5) - 1; if (iter.hasNext()) { - end = start + evaluateToNumber((Expr*)iter.next(), - aContext); + rv = evaluateToNumber((Expr*)iter.next(), aContext, &end); + NS_ENSURE_SUCCESS(rv, rv); + + end += start; if (Double::isNaN(end) || end < 0) { aContext->recycler()->getEmptyStringResult(aResult); diff --git a/extensions/transformiix/source/xpath/XFormsFunctionCall.cpp b/extensions/transformiix/source/xpath/XFormsFunctionCall.cpp index bcf7af57..eb0c5524 100644 --- a/extensions/transformiix/source/xpath/XFormsFunctionCall.cpp +++ b/extensions/transformiix/source/xpath/XFormsFunctionCall.cpp @@ -625,8 +625,8 @@ XFormsFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; double result = 0; - double base = evaluateToNumber((Expr*)iter.next(), aContext); - double exponent = evaluateToNumber((Expr*)iter.next(), aContext); + double base = evaluateToNumber((Expr*)iter.next(), aContext, &result); + double exponent = evaluateToNumber((Expr*)iter.next(), aContext, &result); // If base is negative and exponent is not an integral value, or if base // is zero and exponent is negative, a domain error occurs, setting the @@ -712,7 +712,8 @@ XFormsFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) if (!requireParams(1, 1, aContext)) return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; - double days = evaluateToNumber((Expr*)iter.next(), aContext); + double res; + double days = evaluateToNumber((Expr*)iter.next(), aContext, &res); nsAutoString date; if (!Double::isNaN(days)) { @@ -745,7 +746,8 @@ XFormsFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) if (!requireParams(1, 1, aContext)) return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; - double seconds = evaluateToNumber((Expr*)iter.next(), aContext); + double res; + double seconds = evaluateToNumber((Expr*)iter.next(), aContext, &res); nsAutoString dateTime; if (!Double::isNaN(seconds)) { diff --git a/extensions/transformiix/source/xslt/functions/txFormatNumberFunctionCall.cpp b/extensions/transformiix/source/xslt/functions/txFormatNumberFunctionCall.cpp index 83d12c65..89f9ce36 100644 --- a/extensions/transformiix/source/xslt/functions/txFormatNumberFunctionCall.cpp +++ b/extensions/transformiix/source/xslt/functions/txFormatNumberFunctionCall.cpp @@ -89,7 +89,9 @@ txFormatNumberFunctionCall::evaluate(txIEvalContext* aContext, nsAutoString formatStr; txExpandedName formatName; - value = evaluateToNumber((Expr*)iter.next(), aContext); + rv = evaluateToNumber((Expr*)iter.next(), aContext, &value); + NS_ENSURE_SUCCESS(rv, rv); + evaluateToString((Expr*)iter.next(), aContext, formatStr); if (iter.hasNext()) { nsAutoString formatQName; diff --git a/extensions/transformiix/source/xslt/functions/txKeyFunctionCall.cpp b/extensions/transformiix/source/xslt/functions/txKeyFunctionCall.cpp index 3098aab3..00a1cfb0 100644 --- a/extensions/transformiix/source/xslt/functions/txKeyFunctionCall.cpp +++ b/extensions/transformiix/source/xslt/functions/txKeyFunctionCall.cpp @@ -416,10 +416,10 @@ nsresult txXSLKey::testNode(const txXPathNode& aNode, nsRefPtr exprResult; rv = key->useExpr->evaluate(evalContext, getter_AddRefs(exprResult)); - NS_ENSURE_SUCCESS(rv, rv); - delete aEs.popEvalContext(); + NS_ENSURE_SUCCESS(rv, rv); + if (exprResult->getResultType() == txAExprResult::NODESET) { txNodeSet* res = NS_STATIC_CAST(txNodeSet*, NS_STATIC_CAST(txAExprResult*, diff --git a/extensions/transformiix/source/xslt/txExecutionState.cpp b/extensions/transformiix/source/xslt/txExecutionState.cpp index 07aa633c..0deb225c 100644 --- a/extensions/transformiix/source/xslt/txExecutionState.cpp +++ b/extensions/transformiix/source/xslt/txExecutionState.cpp @@ -100,10 +100,13 @@ txExecutionState::txExecutionState(txStylesheet* aStylesheet, mKeyHash(aStylesheet->getKeyMap()), mDisableLoads(aDisableLoads) { + MOZ_COUNT_CTOR(txExecutionState); } txExecutionState::~txExecutionState() { + MOZ_COUNT_DTOR(txExecutionState); + delete mResultHandler; delete mLocalVariables; delete mEvalContext; @@ -203,7 +206,11 @@ txExecutionState::init(const txXPathNode& aNode, nsresult txExecutionState::end(nsresult aResult) { - popTemplateRule(); + NS_ASSERTION(NS_FAILED(aResult) || mTemplateRuleCount == 1, + "Didn't clean up template rules properly"); + if (NS_SUCCEEDED(aResult)) { + popTemplateRule(); + } mOutputHandler->endDocument(aResult); return NS_OK; @@ -276,9 +283,9 @@ txExecutionState::getVariable(PRInt32 aNamespace, nsIAtom* aLName, txVariableMap* oldVars = mLocalVariables; mLocalVariables = nsnull; rv = var->mExpr->evaluate(getEvalContext(), &aResult); - NS_ENSURE_SUCCESS(rv, rv); - mLocalVariables = oldVars; + + NS_ENSURE_SUCCESS(rv, rv); } else { nsAutoPtr rtfHandler(new txRtfHandler); @@ -448,9 +455,12 @@ txExecutionState::pushTemplateRule(txStylesheet::ImportFrame* aFrame, void txExecutionState::popTemplateRule() { + NS_PRECONDITION(mTemplateRuleCount > 0, "No rules to pop"); // decrement outside of RELEASE, that would decrement twice - --mTemplateRuleCount; - NS_IF_RELEASE(mTemplateRules[mTemplateRuleCount].mModeLocalName); + if(mTemplateRuleCount > 0) { + --mTemplateRuleCount; + NS_IF_RELEASE(mTemplateRules[mTemplateRuleCount].mModeLocalName); + } } txIEvalContext* @@ -514,7 +524,9 @@ txExecutionState::getKeyNodes(const txExpandedName& aKeyName, txExecutionState::TemplateRule* txExecutionState::getCurrentTemplateRule() { - return mTemplateRules + mTemplateRuleCount - 1; + NS_PRECONDITION(mTemplateRuleCount > 0, "No current rule!"); + // better to crash that underrun + return mTemplateRuleCount > 0 ? mTemplateRules + mTemplateRuleCount - 1 : NULL; } txInstruction* diff --git a/extensions/transformiix/source/xslt/txMozillaXSLTProcessor.cpp b/extensions/transformiix/source/xslt/txMozillaXSLTProcessor.cpp index b453c69c..879929fa 100644 --- a/extensions/transformiix/source/xslt/txMozillaXSLTProcessor.cpp +++ b/extensions/transformiix/source/xslt/txMozillaXSLTProcessor.cpp @@ -634,10 +634,12 @@ txMozillaXSLTProcessor::TransformToDoc(nsIDOMDocument *aOutputDoc, mObserver); es.mOutputHandlerFactory = &handlerFactory; - es.init(*sourceNode, &mVariables); + nsresult rv = es.init(*sourceNode, &mVariables); // Process root of XML source document - nsresult rv = txXSLTProcessor::execute(es); + if (NS_SUCCEEDED(rv)) { + rv = txXSLTProcessor::execute(es); + } es.end(rv); if (NS_SUCCEEDED(rv)) { if (aResult) { @@ -686,10 +688,12 @@ txMozillaXSLTProcessor::TransformToFragment(nsIDOMNode *aSource, txToFragmentHandlerFactory handlerFactory(*aResult); es.mOutputHandlerFactory = &handlerFactory; - es.init(*sourceNode, &mVariables); + rv = es.init(*sourceNode, &mVariables); // Process root of XML source document - rv = txXSLTProcessor::execute(es); + if (NS_SUCCEEDED(rv)) { + rv = txXSLTProcessor::execute(es); + } // XXX setup exception context, bug 204658 es.end(rv); diff --git a/extensions/transformiix/source/xslt/txVariableMap.h b/extensions/transformiix/source/xslt/txVariableMap.h index 29964a80..7d8afe36 100644 --- a/extensions/transformiix/source/xslt/txVariableMap.h +++ b/extensions/transformiix/source/xslt/txVariableMap.h @@ -64,11 +64,14 @@ inline txVariableMap::txVariableMap() : mMap(MB_FALSE) { + MOZ_COUNT_CTOR(txVariableMap); } inline txVariableMap::~txVariableMap() { + MOZ_COUNT_DTOR(txVariableMap); + txExpandedNameMap::iterator iter(mMap); while (iter.next()) { txAExprResult* res = NS_STATIC_CAST(txAExprResult*, iter.value()); diff --git a/extensions/transformiix/source/xslt/util/txNodeSorter.cpp b/extensions/transformiix/source/xslt/util/txNodeSorter.cpp index be6b7388..a5371e07 100644 --- a/extensions/transformiix/source/xslt/util/txNodeSorter.cpp +++ b/extensions/transformiix/source/xslt/util/txNodeSorter.cpp @@ -190,7 +190,15 @@ txNodeSorter::sortNodeSet(txNodeSet* aNodes, txExecutionState* aEs, // Create and set up memoryblock for sort-values and indexarray PRUint32 len = NS_STATIC_CAST(PRUint32, aNodes->size()); - void* mem = PR_Malloc(len * (sizeof(PRUint32) + mNKeys * sizeof(TxObject*))); + + // Don't overflow when calculating the length of the sort buffer. + PRUint32 itemSize = sizeof(PRUint32) + mNKeys * sizeof(TxObject*); + if (mNKeys > (PR_UINT32_MAX - sizeof(PRUint32)) / sizeof(TxObject*) || + len >= PR_UINT32_MAX / itemSize) { + return NS_ERROR_OUT_OF_MEMORY; + } + + void* mem = PR_Malloc(len * itemSize); NS_ENSURE_TRUE(mem, NS_ERROR_OUT_OF_MEMORY); PRUint32* indexes = NS_STATIC_CAST(PRUint32*, mem); diff --git a/intl/uconv/src/nsConverterInputStream.cpp b/intl/uconv/src/nsConverterInputStream.cpp index 362c087b..e059b0af 100644 --- a/intl/uconv/src/nsConverterInputStream.cpp +++ b/intl/uconv/src/nsConverterInputStream.cpp @@ -255,7 +255,8 @@ nsConverterInputStream::Fill(nsresult * aErrorCode) NS_ASSERTION(srcConsumed <= mByteData->GetLength(), "Whoa. The converter should have returned NS_OK_UDEC_MOREINPUT before this point!"); } while (mReplacementChar && - NS_FAILED(*aErrorCode)); + NS_FAILED(*aErrorCode) && + mUnicharData->GetBufferSize() > mUnicharDataLength); mLeftOverBytes = mByteData->GetLength() - srcConsumed; diff --git a/intl/uconv/src/nsUTF8ToUnicode.cpp b/intl/uconv/src/nsUTF8ToUnicode.cpp index 6563dbdc..9bcc6997 100644 --- a/intl/uconv/src/nsUTF8ToUnicode.cpp +++ b/intl/uconv/src/nsUTF8ToUnicode.cpp @@ -64,6 +64,15 @@ NS_IMETHODIMP NS_NewUTF8ToUnicode(nsISupports* aOuter, return res; } +static PRUnichar* EmitSurrogatePair(PRUint32 ucs4, PRUnichar* aDest) +{ + NS_ASSERTION(ucs4 > 0xFFFF, "Should be a supplementary character"); + ucs4 -= 0x00010000; + *aDest++ = 0xD800 | (0x000003FF & (ucs4 >> 10)); + *aDest++ = 0xDC00 | (0x000003FF & ucs4); + return aDest; +} + //---------------------------------------------------------------------- // Class nsUTF8ToUnicode [implementation] @@ -136,12 +145,28 @@ NS_IMETHODIMP nsUTF8ToUnicode::Convert(const char * aSrc, nsresult res = NS_OK; // conversion result + out = aDest; + if (mState == 0xFF) { + // Emit supplementary character left over from previous iteration. If the + // buffer size is insufficient, treat it as an illegal character. + if (aDestLen < 2) { + NS_ERROR("Output buffer insufficient to hold supplementary character"); + mState = 0; + return NS_ERROR_ILLEGAL_INPUT; + } + out = EmitSurrogatePair(mUcs4, out); + mUcs4 = 0; + mState = 0; + mBytes = 1; + mFirst = PR_FALSE; + } + // Set mFirst to PR_FALSE now so we don't have to every time through the ASCII // branch within the loop. if (mFirst && aSrcLen && (0 == (0x80 & (*aSrc)))) mFirst = PR_FALSE; - for (in = aSrc, out = aDest; ((in < inend) && (out < outend)); ++in) { + for (in = aSrc; ((in < inend) && (out < outend)); ++in) { if (0 == mState) { // When mState is zero we expect either a US-ASCII character or a // multi-octet sequence. @@ -227,9 +252,15 @@ NS_IMETHODIMP nsUTF8ToUnicode::Convert(const char * aSrc, } if (mUcs4 > 0xFFFF) { // mUcs4 is in the range 0x10000 - 0x10FFFF. Output a UTF-16 pair - mUcs4 -= 0x00010000; - *out++ = 0xD800 | (0x000003FF & (mUcs4 >> 10)); - *out++ = 0xDC00 | (0x000003FF & mUcs4); + if (out + 2 > outend) { + // insufficient space left in the buffer. Keep mUcs4 for the + // next iteration. + mState = 0xFF; + ++in; + res = NS_OK_UDEC_MOREOUTPUT; + break; + } + out = EmitSurrogatePair(mUcs4, out); } else if (UNICODE_BYTE_ORDER_MARK != mUcs4 || !mFirst) { // Don't output the BOM only if it is the first character *out++ = mUcs4; diff --git a/intl/uconv/ucvcn/nsGBKToUnicode.cpp b/intl/uconv/ucvcn/nsGBKToUnicode.cpp index b56f42f6..fb2925c2 100644 --- a/intl/uconv/ucvcn/nsGBKToUnicode.cpp +++ b/intl/uconv/ucvcn/nsGBKToUnicode.cpp @@ -206,8 +206,7 @@ NS_IMETHODIMP nsGBKToUnicode::ConvertNoBuff(const char* aSrc, *aDest = UCS2_NO_MAPPING; } else { // let's try supplement mapping - NS_ASSERTION(( (iDestlen+1) <= (*aDestLength) ), "no enouth output memory"); - if ( (iDestlen+1) <= (*aDestLength) ) + if ( (iDestlen+1) < (*aDestLength) ) { if(DecodeToSurrogate(aSrc, aDest)) { @@ -218,7 +217,13 @@ NS_IMETHODIMP nsGBKToUnicode::ConvertNoBuff(const char* aSrc, *aDest = UCS2_NO_MAPPING; } } else { - *aDest = UCS2_NO_MAPPING; + if (*aDestLength < 2) { + NS_ERROR("insufficient space in output buffer"); + *aDest = UCS2_NO_MAPPING; + } else { + rv = NS_OK_UDEC_MOREOUTPUT; + break; + } } } } else { diff --git a/intl/uconv/ucvja/nsJapaneseToUnicode.cpp b/intl/uconv/ucvja/nsJapaneseToUnicode.cpp index 629884f9..af9c87e8 100644 --- a/intl/uconv/ucvja/nsJapaneseToUnicode.cpp +++ b/intl/uconv/ucvja/nsJapaneseToUnicode.cpp @@ -50,6 +50,8 @@ static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CI #define SJIS_INDEX mMapIndex[0] #define JIS0208_INDEX mMapIndex[1] #define JIS0212_INDEX gJIS0212Index +#define SJIS_UNMAPPED 0x30FB +#define UNICODE_REPLACEMENT_CHARACTER 0xfffd void nsJapaneseToUnicode::setMapMode() { @@ -153,7 +155,7 @@ NS_IMETHODIMP nsShiftJISToUnicode::Convert( break; default: - *dest++ = 0x30FB; + *dest++ = SJIS_UNMAPPED; } if(dest >= destEnd) goto error1; @@ -176,13 +178,20 @@ NS_IMETHODIMP nsShiftJISToUnicode::Convert( case 1: // Index to table { + + // Error handling: in the case where the second octet is not in the + // valid ranges 0x40-0x7E 0x80-0xFC, unconsume the invalid octet and + // interpret it as the ASCII value. In the case where the second + // octet is in the valid range but there is no mapping for the + // 2-octet sequence, do not unconsume. PRUint8 off = sbIdx[*src]; if(0xFF == off) { - *dest++ = 0x30FB; + src--; + *dest++ = UNICODE_REPLACEMENT_CHARACTER; } else { PRUnichar ch = gJapaneseMap[mData+off]; if(ch == 0xfffd) - ch = 0x30fb; + ch = SJIS_UNMAPPED; *dest++ = ch; } mState = 0; @@ -194,8 +203,10 @@ NS_IMETHODIMP nsShiftJISToUnicode::Convert( case 2: // EUDC { PRUint8 off = sbIdx[*src]; + // Error handling as in case 1 if(0xFF == off) { - *dest++ = 0x30fb; + src--; + *dest++ = UNICODE_REPLACEMENT_CHARACTER; } else { *dest++ = mData + off; } @@ -322,10 +333,10 @@ NS_IMETHODIMP nsEUCJPToUnicodeV2::Convert( if(0xFF == off) { *dest++ = 0xFFFD; // if the first byte is valid for EUC-JP but the second - // is not while being a valid US-ASCII(i.e. < 0xc0), save it + // is not while being a valid US-ASCII, save it // instead of eating it up ! - if ( ! (*src & 0xc0) ) - *dest++ = (PRUnichar) *src;; + if ( (PRUint8)*src < (PRUint8)0x7f ) + --src; } else { *dest++ = gJapaneseMap[mData+off]; } @@ -344,7 +355,7 @@ NS_IMETHODIMP nsEUCJPToUnicodeV2::Convert( // if 0x8e is not followed by a valid JIS X 0201 byte // but by a valid US-ASCII, save it instead of eating it up. if ( (PRUint8)*src < (PRUint8)0x7f ) - *dest++ = (PRUnichar) *src; + --src; } mState = 0; if(dest >= destEnd) diff --git a/intl/uconv/ucvlatin/nsUCS2BEToUnicode.cpp b/intl/uconv/ucvlatin/nsUCS2BEToUnicode.cpp index 9b39262b..a89dcdbf 100644 --- a/intl/uconv/ucvlatin/nsUCS2BEToUnicode.cpp +++ b/intl/uconv/ucvlatin/nsUCS2BEToUnicode.cpp @@ -42,14 +42,16 @@ #include #include "prtypes.h" -#define STATE_NORMAL 0 -#define STATE_HALF_CODE_POINT 1 -#define STATE_FIRST_CALL 2 -#define STATE_FOUND_BOM 3 +#define STATE_NORMAL 0 +#define STATE_HALF_CODE_POINT 1 +#define STATE_FIRST_CALL 2 +#define STATE_FOUND_BOM 3 +#define STATE_ODD_SURROGATE_PAIR 4 static nsresult UTF16ConvertToUnicode(PRUint8& aState, PRUint8& aOddByte, - PRUnichar& aOddHighSurrogate, const char * aSrc, + PRUnichar& aOddHighSurrogate, PRUnichar& aOddLowSurrogate, + const char * aSrc, PRInt32 * aSrcLength, PRUnichar * aDest, PRInt32 * aDestLength, PRBool aSwapBytes) @@ -59,32 +61,47 @@ UTF16ConvertToUnicode(PRUint8& aState, PRUint8& aOddByte, PRUnichar* dest = aDest; PRUnichar* destEnd = aDest + *aDestLength; - if(STATE_FOUND_BOM == aState) // caller found a BOM - { - if (*aSrcLength < 2) - return NS_ERROR_ILLEGAL_INPUT; - src+=2; - aState = STATE_NORMAL; - } else if(STATE_FIRST_CALL == aState) { // first time called - if (*aSrcLength < 2) - return NS_ERROR_ILLEGAL_INPUT; - - // Eliminate BOM (0xFEFF). Note that different endian case is taken care of - // in |Convert| of LE and BE converters. Here, we only have to - // deal with the same endian case. That is, 0xFFFE (byte-swapped BOM) is - // illegal. - if(0xFEFF == *((PRUnichar*)src)) { + switch(aState) { + case STATE_FOUND_BOM: + NS_ASSERTION(*aSrcLength > 1, "buffer too short"); src+=2; - } else if(0xFFFE == *((PRUnichar*)src)) { - *aSrcLength=0; - *aDestLength=0; - return NS_ERROR_ILLEGAL_INPUT; - } - aState = STATE_NORMAL; + aState = STATE_NORMAL; + break; + case STATE_FIRST_CALL: // first time called + NS_ASSERTION(*aSrcLength > 1, "buffer too short"); + // Eliminate BOM (0xFEFF). Note that different endian case is taken care + // of in |Convert| of LE and BE converters. Here, we only have to + // deal with the same endian case. That is, 0xFFFE (byte-swapped BOM) is + // illegal. + if(0xFEFF == *((PRUnichar*)src)) { + src+=2; + } else if(0xFFFE == *((PRUnichar*)src)) { + *aSrcLength=0; + *aDestLength=0; + return NS_ERROR_ILLEGAL_INPUT; + } + aState = STATE_NORMAL; + break; + + case STATE_ODD_SURROGATE_PAIR: + if (*aDestLength < 2) + *dest++ = UCS2_REPLACEMENT_CHAR; + else { + *dest++ = aOddHighSurrogate; + *dest++ = aOddLowSurrogate; + aOddHighSurrogate = aOddLowSurrogate = 0; + aState = STATE_NORMAL; + } + break; + + case STATE_NORMAL: + case STATE_HALF_CODE_POINT: + default: + break; } if (src == srcEnd) { - *aDestLength = 0; + *aDestLength = dest - aDest; return NS_OK; } @@ -136,17 +153,19 @@ have_codepoint: oddHighSurrogate = u; } else /* if (IS_LOW_SURROGATE(u)) */ { - if (oddHighSurrogate) { - if (dest == destEnd - 1) { - *dest++ = UCS2_REPLACEMENT_CHAR; + if (oddHighSurrogate && *aDestLength > 1) { + if (dest + 1 >= destEnd) { + aOddLowSurrogate = u; + aOddHighSurrogate = oddHighSurrogate; + aState = STATE_ODD_SURROGATE_PAIR; goto error; } *dest++ = oddHighSurrogate; *dest++ = u; - oddHighSurrogate = 0; } else { *dest++ = UCS2_REPLACEMENT_CHAR; } + oddHighSurrogate = 0; } } if (src != srcEnd) { @@ -173,6 +192,7 @@ nsUTF16ToUnicodeBase::Reset() mState = STATE_FIRST_CALL; mOddByte = 0; mOddHighSurrogate = 0; + mOddLowSurrogate = 0; return NS_OK; } @@ -181,9 +201,11 @@ nsUTF16ToUnicodeBase::GetMaxLength(const char * aSrc, PRInt32 aSrcLength, PRInt32 * aDestLength) { // the left-over data of the previous run have to be taken into account. - *aDestLength = (aSrcLength + - ((STATE_HALF_CODE_POINT == mState) ? 1 : 0)) / 2 + - ((mOddHighSurrogate != 0) ? 1 : 0); + *aDestLength = (aSrcLength + ((STATE_HALF_CODE_POINT == mState) ? 1 : 0)) / 2; + if (mOddHighSurrogate) + (*aDestLength)++; + if (mOddLowSurrogate) + (*aDestLength)++; return NS_OK; } @@ -192,14 +214,19 @@ NS_IMETHODIMP nsUTF16BEToUnicode::Convert(const char * aSrc, PRInt32 * aSrcLength, PRUnichar * aDest, PRInt32 * aDestLength) { + if(STATE_FIRST_CALL == mState && *aSrcLength < 2) + { + nsresult res = (*aSrcLength == 0) ? NS_OK : NS_ERROR_ILLEGAL_INPUT; + *aSrcLength=0; + *aDestLength=0; + return res; + } #ifdef IS_LITTLE_ENDIAN // Remove the BOM if we're little-endian. The 'same endian' case with the // leading BOM will be taken care of by |UTF16ConvertToUnicode|. if(STATE_FIRST_CALL == mState) // Called for the first time. { mState = STATE_NORMAL; - if (*aSrcLength < 2) - return NS_ERROR_ILLEGAL_INPUT; if(0xFFFE == *((PRUnichar*)aSrc)) { // eliminate BOM (on LE machines, BE BOM is 0xFFFE) mState = STATE_FOUND_BOM; @@ -212,6 +239,7 @@ nsUTF16BEToUnicode::Convert(const char * aSrc, PRInt32 * aSrcLength, #endif nsresult rv = UTF16ConvertToUnicode(mState, mOddByte, mOddHighSurrogate, + mOddLowSurrogate, aSrc, aSrcLength, aDest, aDestLength, #ifdef IS_LITTLE_ENDIAN PR_TRUE @@ -226,14 +254,19 @@ NS_IMETHODIMP nsUTF16LEToUnicode::Convert(const char * aSrc, PRInt32 * aSrcLength, PRUnichar * aDest, PRInt32 * aDestLength) { + if(STATE_FIRST_CALL == mState && *aSrcLength < 2) + { + nsresult res = (*aSrcLength == 0) ? NS_OK : NS_ERROR_ILLEGAL_INPUT; + *aSrcLength=0; + *aDestLength=0; + return res; + } #ifdef IS_BIG_ENDIAN // Remove the BOM if we're big-endian. The 'same endian' case with the // leading BOM will be taken care of by |UTF16ConvertToUnicode|. if(STATE_FIRST_CALL == mState) // first time called { mState = STATE_NORMAL; - if (*aSrcLength < 2) - return NS_ERROR_ILLEGAL_INPUT; if(0xFFFE == *((PRUnichar*)aSrc)) { // eliminate BOM (on BE machines, LE BOM is 0xFFFE) mState = STATE_FOUND_BOM; @@ -246,6 +279,7 @@ nsUTF16LEToUnicode::Convert(const char * aSrc, PRInt32 * aSrcLength, #endif nsresult rv = UTF16ConvertToUnicode(mState, mOddByte, mOddHighSurrogate, + mOddLowSurrogate, aSrc, aSrcLength, aDest, aDestLength, #ifdef IS_BIG_ENDIAN PR_TRUE @@ -268,12 +302,16 @@ NS_IMETHODIMP nsUTF16ToUnicode::Convert(const char * aSrc, PRInt32 * aSrcLength, PRUnichar * aDest, PRInt32 * aDestLength) { + if(STATE_FIRST_CALL == mState && *aSrcLength < 2) + { + nsresult res = (*aSrcLength == 0) ? NS_OK : NS_ERROR_ILLEGAL_INPUT; + *aSrcLength=0; + *aDestLength=0; + return res; + } if(STATE_FIRST_CALL == mState) // first time called { mState = STATE_NORMAL; - if (*aSrcLength < 2) - return NS_ERROR_ILLEGAL_INPUT; - // check if BOM (0xFEFF) is at the beginning, remove it if found, and // set mEndian accordingly. if(0xFF == PRUint8(aSrc[0]) && 0xFE == PRUint8(aSrc[1])) { @@ -304,6 +342,7 @@ nsUTF16ToUnicode::Convert(const char * aSrc, PRInt32 * aSrcLength, } nsresult rv = UTF16ConvertToUnicode(mState, mOddByte, mOddHighSurrogate, + mOddLowSurrogate, aSrc, aSrcLength, aDest, aDestLength, #ifdef IS_BIG_ENDIAN (mEndian == kLittleEndian) diff --git a/intl/uconv/ucvlatin/nsUCS2BEToUnicode.h b/intl/uconv/ucvlatin/nsUCS2BEToUnicode.h index 0cf5bfea..7c3d2943 100644 --- a/intl/uconv/ucvlatin/nsUCS2BEToUnicode.h +++ b/intl/uconv/ucvlatin/nsUCS2BEToUnicode.h @@ -62,6 +62,8 @@ protected: PRUint8 mOddByte; // to store an odd high surrogate left over between runs PRUnichar mOddHighSurrogate; + // to store an odd low surrogate left over between runs + PRUnichar mOddLowSurrogate; }; // UTF-16 big endian diff --git a/js/src/jsapi.c b/js/src/jsapi.c index b2e27898..7a4e60fd 100644 --- a/js/src/jsapi.c +++ b/js/src/jsapi.c @@ -4829,7 +4829,7 @@ JS_SetRegExpInput(JSContext *cx, JSString *input, JSBool multiline) CHECK_REQUEST(cx); /* No locking required, cx is thread-private and input must be live. */ res = &cx->regExpStatics; - res->input = input; + res->pendingInput = input; res->multiline = multiline; cx->runtime->gcPoke = JS_TRUE; } @@ -4841,11 +4841,7 @@ JS_ClearRegExpStatics(JSContext *cx) /* No locking required, cx is thread-private and input must be live. */ res = &cx->regExpStatics; - res->input = NULL; - res->multiline = JS_FALSE; - res->parenCount = 0; - res->lastMatch = res->lastParen = js_EmptySubString; - res->leftContext = res->rightContext = js_EmptySubString; + js_RegExpStatics_clear(cx, res); cx->runtime->gcPoke = JS_TRUE; } @@ -4857,6 +4853,7 @@ JS_ClearRegExpRoots(JSContext *cx) /* No locking required, cx is thread-private and input must be live. */ res = &cx->regExpStatics; res->input = NULL; + res->pendingInput = NULL; cx->runtime->gcPoke = JS_TRUE; } diff --git a/js/src/jsbit.h b/js/src/jsbit.h index 87bb0476..e612eb68 100644 --- a/js/src/jsbit.h +++ b/js/src/jsbit.h @@ -190,6 +190,25 @@ js_FloorLog2wImpl(JSUword n); #endif +/* + * Macros for rotate left. There is no rotate operation in the C Language so + * the construct (a << 4) | (a >> 28) is used instead. Most compilers convert + * this to a rotate instruction but some versions of MSVC don't without a + * little help. To get MSVC to generate a rotate instruction, we have to use + * the _rotl intrinsic and use a pragma to make _rotl inline. + * + * MSVC in VS2005 will do an inline rotate instruction on the above construct. + */ + +#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || \ + defined(_M_X64)) +#include +#pragma intrinsic(_rotl) +#define JS_ROTATE_LEFT32(a, bits) _rotl(a, bits) +#else +#define JS_ROTATE_LEFT32(a, bits) (((a) << (bits)) | ((a) >> (32 - (bits)))) +#endif + JS_END_EXTERN_C #endif /* jsbit_h___ */ diff --git a/js/src/jscntxt.c b/js/src/jscntxt.c index 139ad9b8..257197ae 100644 --- a/js/src/jscntxt.c +++ b/js/src/jscntxt.c @@ -1220,7 +1220,7 @@ JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = { #undef MSG_DEF }; -const JSErrorFormatString * +JS_PUBLIC_API(const JSErrorFormatString *) js_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber) { if ((errorNumber > 0) && (errorNumber < JSErr_Limit)) diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index ee10d377..8f46eb14 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -912,7 +912,7 @@ typedef enum JSErrNum { JSErr_Limit } JSErrNum; -extern const JSErrorFormatString * +extern JS_PUBLIC_API(const JSErrorFormatString *) js_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber); #ifdef va_start diff --git a/js/src/jsdbgapi.c b/js/src/jsdbgapi.c index 7bcec506..93ff1146 100644 --- a/js/src/jsdbgapi.c +++ b/js/src/jsdbgapi.c @@ -587,21 +587,23 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id, attrs = sprop->attrs; flags = sprop->flags; shortid = sprop->shortid; + JS_UNLOCK_OBJ(cx, pobj); } else { - if (!OBJ_GET_PROPERTY(cx, pobj, id, &value) || - !OBJ_GET_ATTRIBUTES(cx, pobj, id, prop, &attrs)) { - OBJ_DROP_PROPERTY(cx, pobj, prop); + OBJ_DROP_PROPERTY(cx, pobj, prop); + + if (!OBJ_GET_PROPERTY(cx, pobj, propid, &value) || + !OBJ_GET_ATTRIBUTES(cx, pobj, propid, NULL, &attrs)) { return JS_FALSE; } getter = setter = NULL; flags = 0; shortid = 0; } - OBJ_DROP_PROPERTY(cx, pobj, prop); /* Recall that obj is native, whether or not pobj is native. */ - if (!js_DefineNativeProperty(cx, obj, propid, value, getter, setter, - attrs, flags, shortid, &prop)) { + if (!js_DefineNativeProperty(cx, obj, propid, value, + getter, setter, attrs, flags, + shortid, &prop)) { return JS_FALSE; } sprop = (JSScopeProperty *) prop; diff --git a/js/src/jsobj.c b/js/src/jsobj.c index deecc603..232bb652 100644 --- a/js/src/jsobj.c +++ b/js/src/jsobj.c @@ -431,9 +431,7 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap) #if JS_HAS_GETTER_SETTER JSObject *obj2; JSProperty *prop; - uintN attrs; #endif - jsval val; int stackDummy; if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) { @@ -469,44 +467,60 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap) ok = JS_TRUE; for (i = 0, length = ida->length; i < length; i++) { + JSTempValueRooter v; + JSTempValueRooter setter; + PRBool hasGetter, hasSetter; + id = ida->vector[i]; + JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_VOID, &v); #if JS_HAS_GETTER_SETTER ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop); if (!ok) - break; + goto brk; if (!prop) - continue; - ok = OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &attrs); - if (ok) { - if (OBJ_IS_NATIVE(obj2) && - (attrs & (JSPROP_GETTER | JSPROP_SETTER))) { - val = JSVAL_NULL; - if (attrs & JSPROP_GETTER) - val = (jsval) ((JSScopeProperty*)prop)->getter; - if (attrs & JSPROP_SETTER) { - if (val != JSVAL_NULL) { - /* Mark the getter, then set val to setter. */ - ok = (MarkSharpObjects(cx, JSVAL_TO_OBJECT(val), - NULL) - != NULL); - } - val = (jsval) ((JSScopeProperty*)prop)->setter; - } - } else { - ok = OBJ_GET_PROPERTY(cx, obj, id, &val); - } + goto cont; + JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_VOID, &setter); + if (!OBJ_IS_NATIVE(obj2)) { + OBJ_DROP_PROPERTY(cx, obj2, prop); + hasGetter = hasSetter = PR_FALSE; + } else { + JSScopeProperty *sprop = (JSScopeProperty *) prop; + uintN attrs = sprop->attrs; + hasGetter = (attrs & JSPROP_GETTER); + hasSetter = (attrs & JSPROP_SETTER); + if (hasGetter) + v.u.value = (jsval) ((JSScopeProperty*)sprop)->getter; + if (hasSetter) + setter.u.value = (jsval) ((JSScopeProperty*)sprop)->setter; + JS_UNLOCK_OBJ(cx, obj2); } - OBJ_DROP_PROPERTY(cx, obj2, prop); + if (hasSetter) { + /* Mark the getter, then set value to setter. */ + if (hasGetter && !JSVAL_IS_PRIMITIVE(v.u.value)) { + ok = !!MarkSharpObjects(cx, JSVAL_TO_OBJECT(v.u.value), NULL); + } + if (ok) + v.u.value = setter.u.value; + } else if (!hasGetter) { + ok = OBJ_GET_PROPERTY(cx, obj, id, &(v.u.value)); + } + JS_POP_TEMP_ROOT(cx, &setter); #else - ok = OBJ_GET_PROPERTY(cx, obj, id, &val); + ok = OBJ_GET_PROPERTY(cx, obj, id, &(v.u.value)); #endif if (!ok) - break; - if (!JSVAL_IS_PRIMITIVE(val) && - !MarkSharpObjects(cx, JSVAL_TO_OBJECT(val), NULL)) { + goto brk; + if (!JSVAL_IS_PRIMITIVE(v.u.value) && + !MarkSharpObjects(cx, JSVAL_TO_OBJECT(v.u.value), NULL)) { ok = JS_FALSE; - break; + goto brk; } + cont: + JS_POP_TEMP_ROOT(cx, &v); + continue; + brk: + JS_POP_TEMP_ROOT(cx, &v); + break; } if (!ok || !idap) JS_DestroyIdArray(cx, ida); @@ -866,13 +880,9 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, valcnt = 0; if (prop) { - ok = OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &attrs); - if (!ok) { - OBJ_DROP_PROPERTY(cx, obj2, prop); - goto error; - } - if (OBJ_IS_NATIVE(obj2) && - (attrs & (JSPROP_GETTER | JSPROP_SETTER))) { + if (OBJ_IS_NATIVE(obj2)) { + JSScopeProperty *sprop = (JSScopeProperty *) prop; + attrs = sprop->attrs; if (attrs & JSPROP_GETTER) { val[valcnt] = (jsval) ((JSScopeProperty *)prop)->getter; gsopold[valcnt] = @@ -889,13 +899,18 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, ATOM_TO_STRING(cx->runtime->atomState.setAtom); valcnt++; } + JS_UNLOCK_OBJ(cx, obj2); } else { + OBJ_DROP_PROPERTY(cx, obj2, prop); + } + if (!valcnt) { valcnt = 1; gsop[0] = NULL; gsopold[0] = NULL; ok = OBJ_GET_PROPERTY(cx, obj, id, &val[0]); + if (!ok) + goto error; } - OBJ_DROP_PROPERTY(cx, obj2, prop); } #else /* !JS_HAS_GETTER_SETTER */ @@ -911,11 +926,11 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, gsopold[0] = NULL; ok = OBJ_GET_PROPERTY(cx, obj, id, &val[0]); -#endif /* !JS_HAS_GETTER_SETTER */ - if (!ok) goto error; +#endif /* !JS_HAS_GETTER_SETTER */ + /* * If id is a string that's not an identifier, then it needs to be * quoted. Also, negative integer ids must be quoted. @@ -3204,6 +3219,7 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, const JSCodeSpec *cs; uint32 format; JSBool ok; + JSTempValueRooter tvr, tvr2; /* * Handle old bug that took empty string as zero index. Also convert @@ -3296,7 +3312,9 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, if (!MAP_IS_NATIVE(&scope->map)) { /* Whoops, newresolve handed back a foreign obj2. */ JS_ASSERT(obj2 != obj); + JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(obj2), &tvr); ok = OBJ_LOOKUP_PROPERTY(cx, obj2, id, objp, propp); + JS_POP_TEMP_ROOT(cx, &tvr); if (!ok || *propp) goto cleanup; JS_LOCK_OBJ(cx, obj2); @@ -3356,8 +3374,13 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, JS_UNLOCK_OBJ(cx, obj); if (!proto) break; - if (!OBJ_IS_NATIVE(proto)) - return OBJ_LOOKUP_PROPERTY(cx, proto, id, objp, propp); + if (!OBJ_IS_NATIVE(proto)) { + JSBool ret; + JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(proto), &tvr2); + ret = OBJ_LOOKUP_PROPERTY(cx, proto, id, objp, propp); + JS_POP_TEMP_ROOT(cx, &tvr2); + return ret; + } obj = proto; } @@ -4601,7 +4624,7 @@ js_ValueToObject(JSContext *cx, jsval v, JSObject **objp) obj = JSVAL_TO_OBJECT(v); if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_OBJECT, &v)) return JS_FALSE; - if (JSVAL_IS_OBJECT(v)) + if (!JSVAL_IS_PRIMITIVE(v)) obj = JSVAL_TO_OBJECT(v); } else { if (JSVAL_IS_STRING(v)) { @@ -4983,6 +5006,12 @@ js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v) return JS_TRUE; } +JS_FRIEND_API(void) +js_SetObjectWeakRoot(JSContext *cx, JSObject *obj) +{ + cx->weakRoots.newborn[GCX_OBJECT] = obj; +} + #ifdef DEBUG /* Routines to print out values during debugging. */ diff --git a/js/src/jsobj.h b/js/src/jsobj.h index a67e7327..74805670 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -597,6 +597,9 @@ extern const char * js_ComputeFilename(JSContext *cx, JSStackFrame *caller, JSPrincipals *principals, uintN *linenop); +JS_FRIEND_API(void) +js_SetObjectWeakRoot(JSContext *cx, JSObject *obj); + JS_END_EXTERN_C #endif /* jsobj_h___ */ diff --git a/js/src/jsregexp.c b/js/src/jsregexp.c index febc289b..d3c9f132 100644 --- a/js/src/jsregexp.c +++ b/js/src/jsregexp.c @@ -2684,7 +2684,7 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) jsbytecode *nextpc, *testpc; REOp nextop; RECapture *cap; - REProgState *curState; + REProgState *curState=NULL; const jschar *startcp; size_t parenIndex, k; size_t parenSoFar = 0; @@ -2809,7 +2809,8 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) * Occurs at (successful) end of REOP_ALT, */ case REOP_JUMP: - --gData->stateStackTop; + if(gData->stateStackTop) + --gData->stateStackTop; pc += GET_OFFSET(pc); op = (REOp) *pc++; continue; @@ -2818,7 +2819,8 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) * Occurs at last (successful) end of REOP_ALT, */ case REOP_ENDALT: - --gData->stateStackTop; + if(gData->stateStackTop) + --gData->stateStackTop; op = (REOp) *pc++; continue; @@ -2895,7 +2897,8 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) continue; case REOP_ASSERTTEST: - --gData->stateStackTop; + if(gData->stateStackTop) + --gData->stateStackTop; --curState; x->cp = gData->cpbegin + curState->index; gData->backTrackSP = @@ -2907,7 +2910,8 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) break; case REOP_ASSERTNOTTEST: - --gData->stateStackTop; + if(gData->stateStackTop) + --gData->stateStackTop; --curState; x->cp = gData->cpbegin + curState->index; gData->backTrackSP = @@ -2987,7 +2991,8 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) CHECK_BRANCH(); --curState; do { - --gData->stateStackTop; + if(gData->stateStackTop) + --gData->stateStackTop; if (!result) { /* Failed, see if we have enough children. */ if (curState->u.quantifier.min == 0) @@ -3075,7 +3080,8 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) pc, x, x->cp, 0, 0)) { return NULL; } - --gData->stateStackTop; + if(gData->stateStackTop) + --gData->stateStackTop; pc = pc + GET_OFFSET(pc); op = (REOp) *pc++; } @@ -3083,7 +3089,8 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) case REOP_MINIMALREPEAT: CHECK_BRANCH(); - --gData->stateStackTop; + if(gData->stateStackTop) + --gData->stateStackTop; --curState; if (!result) { @@ -3135,7 +3142,8 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) parenSoFar - curState->parenSoFar)) { return NULL; } - --gData->stateStackTop; + if(gData->stateStackTop) + --gData->stateStackTop; pc = pc + GET_OFFSET(pc); op = (REOp) *pc++; continue; @@ -3162,6 +3170,7 @@ ExecuteREBytecode(REGlobalData *gData, REMatchState *x) pc = backTrackData->backtrack_pc; op = backTrackData->backtrack_op; gData->stateStackTop = backTrackData->saveStateStackTop; + JS_ASSERT(gData->stateStackTop); memcpy(gData->stateStack, backTrackData + 1, @@ -3270,6 +3279,21 @@ bad: return NULL; } +void +js_RegExpStatics_clear(JSContext *cx, JSRegExpStatics *res) +{ + res->input = NULL; + res->pendingInput = NULL; + res->multiline = JS_FALSE; + res->parenCount = 0; + res->lastMatch = res->lastParen = js_EmptySubString; + res->leftContext = res->rightContext = js_EmptySubString; + if (res->moreParens) { + JS_free(cx, res->moreParens); + res->moreParens = NULL; + } +} + JSBool js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp, JSBool test, jsval *rval) @@ -3375,7 +3399,7 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp, } res = &cx->regExpStatics; - res->input = str; + res->pendingInput = res->input = str; res->parenCount = re->parenCount; if (re->parenCount == 0) { res->lastParen = js_EmptySubString; @@ -3478,6 +3502,8 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp, res->rightContext.length = gData.cpend - ep; out: + if (!ok) + js_RegExpStatics_clear(cx,res); JS_FinishArenaPool(&gData.pool); return ok; } @@ -3580,8 +3606,11 @@ enum regexp_static_tinyid { JSBool js_InitRegExpStatics(JSContext *cx, JSRegExpStatics *res) { + JSBool in, pd; JS_ClearRegExpStatics(cx); - return js_AddRoot(cx, &res->input, "res->input"); + in = js_AddRoot(cx, &res->input, "res->input"); + pd = js_AddRoot(cx, &res->pendingInput, "res->input"); + return in && pd; } void @@ -3592,6 +3621,7 @@ js_FreeRegExpStatics(JSContext *cx, JSRegExpStatics *res) res->moreParens = NULL; } js_RemoveRoot(cx->runtime, &res->input); + js_RemoveRoot(cx->runtime, &res->pendingInput); } static JSBool @@ -3608,8 +3638,8 @@ regexp_static_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) slot = JSVAL_TO_INT(id); switch (slot) { case REGEXP_STATIC_INPUT: - *vp = res->input ? STRING_TO_JSVAL(res->input) - : JS_GetEmptyStringValue(cx); + *vp = res->pendingInput ? STRING_TO_JSVAL(res->pendingInput) + : JS_GetEmptyStringValue(cx); return JS_TRUE; case REGEXP_STATIC_MULTILINE: *vp = BOOLEAN_TO_JSVAL(res->multiline); @@ -3651,7 +3681,7 @@ regexp_static_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) !JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp)) { return JS_FALSE; } - res->input = JSVAL_TO_STRING(*vp); + res->pendingInput = JSVAL_TO_STRING(*vp); } else if (JSVAL_TO_INT(id) == REGEXP_STATIC_MULTILINE) { if (!JSVAL_IS_BOOLEAN(*vp) && !JS_ConvertValue(cx, *vp, JSTYPE_BOOLEAN, vp)) { @@ -4018,7 +4048,7 @@ regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, /* Now that obj is unlocked, it's safe to (potentially) grab the GC lock. */ if (argc == 0) { - str = cx->regExpStatics.input; + str = cx->regExpStatics.pendingInput; if (!str) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_INPUT, diff --git a/js/src/jsregexp.h b/js/src/jsregexp.h index 50789832..2996fbbe 100644 --- a/js/src/jsregexp.h +++ b/js/src/jsregexp.h @@ -52,6 +52,7 @@ struct JSRegExpStatics { JSString *input; /* input string to match (perl $_, GC root) */ + JSString *pendingInput; /* pending input string to match */ JSBool multiline; /* whether input contains newlines (perl $*) */ uint16 parenCount; /* number of valid elements in parens[] */ uint16 moreLength; /* number of allocated elements in moreParens */ @@ -63,6 +64,9 @@ struct JSRegExpStatics { JSSubString rightContext; /* input to right of last match (perl $') */ }; +void +js_RegExpStatics_clear(JSContext *cx, JSRegExpStatics *res); + /* * This struct holds a bitmap representation of a class from a regexp. * There's a list of these referenced by the classList field in the JSRegExp diff --git a/js/src/jsxml.c b/js/src/jsxml.c index a07cc69d..c7f53c9b 100644 --- a/js/src/jsxml.c +++ b/js/src/jsxml.c @@ -6028,7 +6028,8 @@ xml_elements(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, nameqn = ToXMLName(cx, name, &funid); if (!nameqn) return JS_FALSE; - argv[0] = OBJECT_TO_JSVAL(nameqn->object); + if (argc) + argv[0] = OBJECT_TO_JSVAL(nameqn->object); list = xml_list_helper(cx, xml, rval); if (!list) diff --git a/js/src/liveconnect/jsj_JavaArray.c b/js/src/liveconnect/jsj_JavaArray.c index 38e80631..a327d768 100644 --- a/js/src/liveconnect/jsj_JavaArray.c +++ b/js/src/liveconnect/jsj_JavaArray.c @@ -254,6 +254,7 @@ JavaArray_lookupProperty(JSContext *cx, JSObject *obj, jsid id, if (access_java_array_element(cx, jEnv, obj, id, NULL, JS_FALSE)) { *objp = obj; *propp = (JSProperty*)1; + js_SetObjectWeakRoot(cx, obj); } else { *objp = NULL; *propp = NULL; diff --git a/js/src/liveconnect/jsj_JavaClass.c b/js/src/liveconnect/jsj_JavaClass.c index ebf7104b..27b981e7 100644 --- a/js/src/liveconnect/jsj_JavaClass.c +++ b/js/src/liveconnect/jsj_JavaClass.c @@ -321,6 +321,7 @@ JavaClass_lookupProperty(JSContext *cx, JSObject *obj, jsid id, if (lookup_static_member_by_id(cx, jEnv, obj, NULL, id, NULL)) { *objp = obj; *propp = (JSProperty*)1; + js_SetObjectWeakRoot(cx, obj); } else { *objp = NULL; *propp = NULL; diff --git a/js/src/liveconnect/jsj_JavaObject.c b/js/src/liveconnect/jsj_JavaObject.c index 91209213..59e8b83a 100644 --- a/js/src/liveconnect/jsj_JavaObject.c +++ b/js/src/liveconnect/jsj_JavaObject.c @@ -832,6 +832,7 @@ JavaObject_lookupProperty(JSContext *cx, JSObject *obj, jsid id, *objp = obj; *propp = (JSProperty*)1; } + js_SetObjectWeakRoot(cx, *objp); } else { *objp = NULL; *propp = NULL; diff --git a/js/src/xpconnect/idl/nsIXPConnect.idl b/js/src/xpconnect/idl/nsIXPConnect.idl index eaf5eb91..5352760a 100644 --- a/js/src/xpconnect/idl/nsIXPConnect.idl +++ b/js/src/xpconnect/idl/nsIXPConnect.idl @@ -688,9 +688,9 @@ interface nsIXPConnect : nsISupports interface nsIXPConnect_MOZILLA_1_8_BRANCH : nsIXPConnect { void - reparentScopeAwareWrappers(in JSContextPtr aJSContext, - in JSObjectPtr aOldScope, - in JSObjectPtr aNewScope); + moveWrappers(in JSContextPtr aJSContext, + in JSObjectPtr aOldScope, + in JSObjectPtr aNewScope); /** * Create a sandbox for evaluating code in isolation using diff --git a/js/src/xpconnect/src/Makefile.in b/js/src/xpconnect/src/Makefile.in index abfe5402..36602ebc 100644 --- a/js/src/xpconnect/src/Makefile.in +++ b/js/src/xpconnect/src/Makefile.in @@ -65,6 +65,7 @@ REQUIRES = xpcom \ caps \ necko \ dom \ + widget \ $(NULL) CPPSRCS = \ diff --git a/js/src/xpconnect/src/XPCNativeWrapper.cpp b/js/src/xpconnect/src/XPCNativeWrapper.cpp index 6bcf2694..47632d03 100644 --- a/js/src/xpconnect/src/XPCNativeWrapper.cpp +++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp @@ -1127,9 +1127,16 @@ MirrorWrappedNativeParent(JSContext *cx, XPCWrappedNative *wrapper, XPCWrappedNative *parent_wrapper = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, wn_parent); - *result = XPCNativeWrapper::GetNewOrUsed(cx, parent_wrapper, nsnull, nsnull); - if (!*result) - return JS_FALSE; + // parent_wrapper can be null if we're in a Components.utils.evalInSandbox + // scope. In that case, the best we can do is just use the + // non-native-wrapped sandbox global object for our parent. + if (parent_wrapper) { + *result = XPCNativeWrapper::GetNewOrUsed(cx, parent_wrapper, nsnull, nsnull); + if (!*result) + return JS_FALSE; + } else { + *result = nsnull; + } } return JS_TRUE; } diff --git a/js/src/xpconnect/src/nsXPConnect.cpp b/js/src/xpconnect/src/nsXPConnect.cpp index 00013239..4631356f 100644 --- a/js/src/xpconnect/src/nsXPConnect.cpp +++ b/js/src/xpconnect/src/nsXPConnect.cpp @@ -779,11 +779,11 @@ MoveableWrapperFinder(JSDHashTable *table, JSDHashEntryHdr *hdr, return JS_DHASH_NEXT; } -/* void reparentScopeAwareWrappers(in JSContextPtr aJSContext, in JSObjectPtr aOldScope, in JSObjectPtr aNewScope); */ +/* void moveWrappers(in JSContextPtr aJSContext, in JSObjectPtr aOldScope, in JSObjectPtr aNewScope); */ NS_IMETHODIMP -nsXPConnect::ReparentScopeAwareWrappers(JSContext *aJSContext, - JSObject *aOldScope, - JSObject *aNewScope) +nsXPConnect::MoveWrappers(JSContext *aJSContext, + JSObject *aOldScope, + JSObject *aNewScope) { XPCCallContext ccx(NATIVE_CALLER, aJSContext); if(!ccx.IsValid()) @@ -840,35 +840,41 @@ nsXPConnect::ReparentScopeAwareWrappers(JSContext *aJSContext, if(NS_FAILED(rv)) return NS_ERROR_FAILURE; + JSObject *newParent = aOldScope; + // If the wrapper doesn't want precreate, then we don't need to // worry about reparenting it. if(!sciWrapper.GetFlags().WantPreCreate()) continue; - JSObject *newParent = aOldScope; rv = sciWrapper.GetCallback()->PreCreate(identity, ccx, aOldScope, &newParent); if(NS_FAILED(rv)) return rv; - if(newParent != aOldScope) + if(newParent == aOldScope) { - // The wrapper returned a new parent. If the new parent is in - // a different scope, then we need to reparent it, otherwise, - // the old scope is fine. + // The old scope still works for this wrapper. We have to assume + // that the wrapper will continue to return the old scope from + // PreCreate, so don't move it. + continue; + } - XPCWrappedNativeScope *betterScope = - XPCWrappedNativeScope::FindInJSObjectScope(ccx, newParent); - if(betterScope == oldScope) - continue; - - NS_ASSERTION(betterScope == newScope, "Weird scope returned"); - } - else - { - // The old scope still works for this wrapper. - continue; - } + // The wrapper returned a new parent. If the new parent is in + // a different scope, then we need to reparent it, otherwise, + // the old scope is fine. + + XPCWrappedNativeScope *betterScope = + XPCWrappedNativeScope::FindInJSObjectScope(ccx, newParent); + if(betterScope == oldScope) + { + // The wrapper asked for a different object, but that object + // was in the same scope. We assume here that the new parent + // simply hasn't been reparented yet. + newParent = nsnull; + } + else + NS_ASSERTION(betterScope == newScope, "Weird scope returned"); // Now, reparent the wrapper, since we know that it wants to be // reparented. diff --git a/js/src/xpconnect/src/xpccomponents.cpp b/js/src/xpconnect/src/xpccomponents.cpp index 0407c27e..f8006652 100644 --- a/js/src/xpconnect/src/xpccomponents.cpp +++ b/js/src/xpconnect/src/xpccomponents.cpp @@ -1910,7 +1910,14 @@ nsXPCComponents_Utils::LookupMethod() return NS_ERROR_XPC_BAD_CONVERT_JS; JSObject* obj = JSVAL_TO_OBJECT(argv[0]); + { + XPCWrappedNative *wn = + XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj); + if(!wn) + return NS_ERROR_XPC_BAD_CONVERT_JS; + obj = wn->GetFlatJSObject(); + } // Can't use the macro OBJ_TO_INNER_OBJECT here due to it using // the non-exported function js_GetSlotThreadSafe(). { @@ -1921,6 +1928,8 @@ nsXPCComponents_Utils::LookupMethod() obj = xclasp->innerObject(cx, obj); } } + if(!obj) + return NS_ERROR_XPC_BAD_CONVERT_JS; // second param must be a string if(!JSVAL_IS_STRING(argv[1])) diff --git a/js/src/xpconnect/src/xpcthreadcontext.cpp b/js/src/xpconnect/src/xpcthreadcontext.cpp index bf3c5c3b..8c38de30 100644 --- a/js/src/xpconnect/src/xpcthreadcontext.cpp +++ b/js/src/xpconnect/src/xpcthreadcontext.cpp @@ -42,6 +42,8 @@ /* Implement global service to track stack of JSContext per thread. */ #include "xpcprivate.h" +#include "nsIScriptGlobalObject.h" +#include "nsIScriptContext.h" /***************************************************************************/ @@ -117,6 +119,20 @@ XPCJSContextStack::Pop(JSContext * *_retval) return NS_OK; } +static nsIPrincipal* +GetPrincipalFromCx(JSContext *cx) +{ + nsIScriptContext* scriptContext = GetScriptContextFromJSContext(cx); + if (scriptContext) + { + nsCOMPtr globalData = + do_QueryInterface(scriptContext->GetGlobalObject()); + if (globalData) + return globalData->GetPrincipal(); + } + return nsnull; +} + /* void push (in JSContext cx); */ NS_IMETHODIMP XPCJSContextStack::Push(JSContext * cx) @@ -126,8 +142,33 @@ XPCJSContextStack::Push(JSContext * cx) if(mStack.Length() > 1) { JSContextAndFrame & e = mStack[mStack.Length() - 2]; - if(e.cx && e.cx != cx) - e.frame = JS_SaveFrameChain(e.cx); + if(e.cx) + { + if (e.cx == cx) + { nsresult rv; + nsCOMPtr ssm = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv) && ssm) + { + nsIPrincipal* globalObjectPrincipal = + GetPrincipalFromCx(cx); + if (globalObjectPrincipal) + { + nsCOMPtr subjectPrincipal; + ssm->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal)); + + PRBool equals = PR_FALSE; + globalObjectPrincipal->Equals(subjectPrincipal, &equals); + if (equals) + { + return NS_OK; + } + } + } + } + + e.frame = JS_SaveFrameChain(e.cx); + } } return NS_OK; } diff --git a/js/src/xpconnect/src/xpcvariant.cpp b/js/src/xpconnect/src/xpcvariant.cpp index f3054c9a..1de0a842 100644 --- a/js/src/xpconnect/src/xpcvariant.cpp +++ b/js/src/xpconnect/src/xpcvariant.cpp @@ -239,6 +239,13 @@ XPCArrayHomogenizer::GetTypeForArray(XPCCallContext& ccx, JSObject* array, JSBool XPCVariant::InitializeData(XPCCallContext& ccx) { + int stackDummy; + + if (!JS_CHECK_STACK_SIZE(ccx.GetJSContext(), stackDummy)) { + JS_ReportErrorNumber(ccx.GetJSContext(), js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED); + return JS_FALSE; + } + if(JSVAL_IS_INT(mJSVal)) return NS_SUCCEEDED(nsVariant::SetFromInt32(&mData, JSVAL_TO_INT(mJSVal))); @@ -763,5 +770,3 @@ NS_IMETHODIMP XPCVariant::GetAsWStringWithSize(PRUint32 *size, PRUnichar **str) { return nsVariant::ConvertToWStringWithSize(mData, size, str); } - - diff --git a/js/src/xpconnect/src/xpcwrappedjsclass.cpp b/js/src/xpconnect/src/xpcwrappedjsclass.cpp index 344d7a5c..d10b8221 100644 --- a/js/src/xpconnect/src/xpcwrappedjsclass.cpp +++ b/js/src/xpconnect/src/xpcwrappedjsclass.cpp @@ -238,6 +238,29 @@ nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(XPCCallContext& ccx, jsid funid; jsval fun; + // Don't call the actual function on a content object. We'll determine + // whether or not a content object is capable of implementing the + // interface (i.e. whether the interface is scriptable) and most content + // objects don't have QI implementations anyway. Also see bug 503926. + if(!JS_IsSystemObject(ccx, jsobj)) + { + nsCOMPtr objPrin; + + nsXPConnect *xpc = nsXPConnect::GetXPConnect(); + nsCOMPtr ssm = + do_QueryInterface(xpc->GetDefaultSecurityManager()); + if(ssm) + { + nsresult rv = ssm->GetObjectPrincipal(ccx, jsobj, getter_AddRefs(objPrin)); + NS_ENSURE_SUCCESS(rv, nsnull); + + nsCOMPtr systemPrin; + rv = ssm->GetSystemPrincipal(getter_AddRefs(systemPrin)); + if(systemPrin != objPrin) + return nsnull; + } + } + // check upfront for the existence of the function property funid = mRuntime->GetStringID(XPCJSRuntime::IDX_QUERY_INTERFACE); if(!OBJ_GET_PROPERTY(cx, jsobj, funid, &fun) || JSVAL_IS_PRIMITIVE(fun)) diff --git a/js/src/xpconnect/src/xpcwrappednative.cpp b/js/src/xpconnect/src/xpcwrappednative.cpp index 524db3eb..2907e5fd 100644 --- a/js/src/xpconnect/src/xpcwrappednative.cpp +++ b/js/src/xpconnect/src/xpcwrappednative.cpp @@ -1143,7 +1143,7 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx, // Now we can just fix up the parent and return the wrapper - if(!JS_SetParent(ccx, wrapper->GetFlatJSObject(), aNewParent)) + if(aNewParent && !JS_SetParent(ccx, wrapper->GetFlatJSObject(), aNewParent)) { NS_RELEASE(wrapper); return NS_ERROR_FAILURE; diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index e8f771b6..f09a9b72 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -8572,6 +8572,32 @@ nsCSSFrameConstructor::FindNextSibling(nsIContent* aContainer, return nsnull; } +#ifdef MOZ_XUL + +static +nsIListBoxObject* +MaybeGetListBoxBodyFrame(nsIContent* aContainer, nsIContent* aChild) +{ + NS_PRECONDITION(aContainer, "Must have container here"); + + if (aContainer->IsContentOfType(nsIContent::eXUL) && + aChild->IsContentOfType(nsIContent::eXUL) && + aContainer->Tag() == nsXULAtoms::listbox && + aChild->Tag() == nsXULAtoms::listitem) { + nsCOMPtr xulElement = do_QueryInterface(aContainer); + nsCOMPtr boxObject; + xulElement->GetBoxObject(getter_AddRefs(boxObject)); + nsCOMPtr listBoxObject = do_QueryInterface(boxObject); + if (listBoxObject) { + return listBoxObject->GetListBoxBody(PR_FALSE); + } + } + + return nsnull; +} + +#endif + inline PRBool ShouldIgnoreSelectChild(nsIContent* aContainer) { @@ -8727,6 +8753,20 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, PRUint32 containerCount = aContainer->GetChildCount(); for (PRUint32 i = aNewIndexInContainer; i < containerCount; i++) { nsIContent *child = aContainer->GetChildAt(i); + nsIFrame* primaryFrame = nsnull; + mPresShell->GetPrimaryFrameFor(child,&primaryFrame); + if (primaryFrame +#ifdef MOZ_XUL + // Except listboxes suck, so do NOT skip anything here if + // we plan to notify a listbox. + && !MaybeGetListBoxBodyFrame(aContainer, child) +#endif + ) { + // Already have a frame for this content; a previous ContentInserted + // in this loop must have reconstructed its insertion parent. Skip + // it. + continue; + } if (multiple) { // Filters are in effect, so the insertion point needs to be refetched for // each child. @@ -9203,37 +9243,28 @@ PRBool NotifyListBoxBody(nsPresContext* aPresContext, PRBool aUseXBLForms, content_operation aOperation) { - if (!aContainer) + if (!aContainer) { return PR_FALSE; + } - if (aContainer->IsContentOfType(nsIContent::eXUL) && - aChild->IsContentOfType(nsIContent::eXUL) && - aContainer->Tag() == nsXULAtoms::listbox && - aChild->Tag() == nsXULAtoms::listitem) { - nsCOMPtr xulElement = do_QueryInterface(aContainer); - nsCOMPtr boxObject; - xulElement->GetBoxObject(getter_AddRefs(boxObject)); - nsCOMPtr listBoxObject = do_QueryInterface(boxObject); - if (listBoxObject) { - nsIListBoxObject* listboxBody = listBoxObject->GetListBoxBody(PR_FALSE); - if (listboxBody) { - nsListBoxBodyFrame *listBoxBodyFrame = NS_STATIC_CAST(nsListBoxBodyFrame*, listboxBody); - if (aOperation == CONTENT_REMOVED) { - // Except if we have an aChildFrame and its parent is not the right - // thing, then we don't do this. Pseudo frames are so much fun.... - if (!aChildFrame || aChildFrame->GetParent() == listBoxBodyFrame) { - listBoxBodyFrame->OnContentRemoved(aPresContext, aChildFrame, - aIndexInContainer); - return PR_TRUE; - } - } else { - listBoxBodyFrame->OnContentInserted(aPresContext, aChild); - return PR_TRUE; - } + nsIListBoxObject* listboxBody = MaybeGetListBoxBodyFrame(aContainer, aChild); + if (listboxBody) { + nsListBoxBodyFrame *listBoxBodyFrame = static_cast(listboxBody); + if (aOperation == CONTENT_REMOVED) { + // Except if we have an aChildFrame and its parent is not the right + // thing, then we don't do this. Pseudo frames are so much fun.... + if (!aChildFrame || aChildFrame->GetParent() == listBoxBodyFrame) { + listBoxBodyFrame->OnContentRemoved(aPresContext, aChildFrame, + aIndexInContainer); + return PR_TRUE; } + } else { + listBoxBodyFrame->OnContentInserted(aPresContext, aChild); + return PR_TRUE; } } + nsCOMPtr tag; PRInt32 namespaceID; aDocument->BindingManager()->ResolveTag(aContainer, &namespaceID, diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 9c958f49..443376f4 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -220,8 +220,6 @@ nsPresContext::nsPresContext(nsPresContextType aType) nsPresContext::~nsPresContext() { - mImageLoaders.Enumerate(destroy_loads); - NS_PRECONDITION(!mShell, "Presshell forgot to clear our mShell pointer"); SetShell(nsnull); @@ -775,6 +773,13 @@ nsPresContext::SetShell(nsIPresShell* aShell) UpdateCharSet(doc->GetDocumentCharacterSet()); } } + } else { + // Destroy image loaders now that the presshell is going away. + // This is important since imageloaders can have pointers to frames and + // we don't want those pointers to outlive the destruction of the frame + // arena. + mImageLoaders.Enumerate(destroy_loads, nsnull); + } } @@ -1037,6 +1042,8 @@ nsPresContext::SetTextZoomExternal(float aZoom) imgIRequest* nsPresContext::LoadImage(imgIRequest* aImage, nsIFrame* aTargetFrame) { + NS_ASSERTION(mShell, "Shouldn't load image after the shell is gone"); + // look and see if we have a loader for the target frame. nsVoidKey key(aTargetFrame); diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 3cfe13dd..b6f1b891 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -3236,6 +3236,8 @@ NS_IMETHODIMP PresShell::NotifyDestroyingFrame(nsIFrame* aFrame) { if (!mIgnoreFrameDestruction) { + mPresContext->StopImagesFor(aFrame); + mFrameConstructor->NotifyDestroyingFrame(aFrame); // Cancel any pending reflow commands targeted at this frame diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 3074727e..12040d85 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -752,17 +752,7 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext, // and we may even delete the line with the line cursor. ClearLineCursor(); - if (IsFrameTreeTooDeep(aReflowState, aMetrics)) { -#ifdef DEBUG_kipp - { - extern char* nsPresShell_ReflowStackPointerTop; - char marker; - char* newsp = (char*) ▮ - printf("XXX: frame tree is too deep; approx stack size = %d\n", - nsPresShell_ReflowStackPointerTop - newsp); - } -#endif - aStatus = NS_FRAME_COMPLETE; + if (IsFrameTreeTooDeep(aReflowState, aMetrics, aStatus)) { return NS_OK; } diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index ac067b30..afb60872 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -645,10 +645,6 @@ nsFrame::Destroy(nsPresContext* aPresContext) } } - //XXX Why is this done in nsFrame instead of some frame class - // that actually loads images? - aPresContext->StopImagesFor(this); - if (view) { // Break association between view and frame view->SetClientData(nsnull); @@ -2703,9 +2699,11 @@ nsFrame::CheckInvalidateSizeChange(nsPresContext* aPresContext, PRBool nsFrame::IsFrameTreeTooDeep(const nsHTMLReflowState& aReflowState, - nsHTMLReflowMetrics& aMetrics) + nsHTMLReflowMetrics& aMetrics, + nsReflowStatus& aStatus) { if (aReflowState.mReflowDepth > MAX_FRAME_DEPTH) { + NS_WARNING("frame tree too deep; setting zero size and returning"); mState |= NS_FRAME_IS_UNFLOWABLE; mState &= ~NS_FRAME_OUTSIDE_CHILDREN; aMetrics.width = 0; @@ -2720,6 +2718,16 @@ nsFrame::IsFrameTreeTooDeep(const nsHTMLReflowState& aReflowState, if (aMetrics.mComputeMEW) { aMetrics.mMaxElementWidth = 0; } + + if (GetNextInFlow()) { + // Reflow depth might vary between reflows, so we might have + // successfully reflowed and split this frame before. If so, we + // shouldn't delete its continuations. + aStatus = NS_FRAME_NOT_COMPLETE; + } else { + aStatus = NS_FRAME_COMPLETE; + } + return PR_TRUE; } mState &= ~NS_FRAME_IS_UNFLOWABLE; diff --git a/layout/generic/nsFrame.h b/layout/generic/nsFrame.h index 42605f41..cc5e9ee8 100644 --- a/layout/generic/nsFrame.h +++ b/layout/generic/nsFrame.h @@ -350,13 +350,14 @@ public: nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState); - // Helper function that tests if the frame tree is too deep; if it - // is it marks the frame as "unflowable" and zeros out the metrics - // and returns PR_TRUE. Otherwise, the frame is unmarked - // "unflowable" and the metrics are not touched and PR_FALSE is - // returned. + // Helper function that tests if the frame tree is too deep; if it is + // it marks the frame as "unflowable", zeroes out the metrics, sets + // the reflow status, and returns PR_TRUE. Otherwise, the frame is + // unmarked "unflowable" and the metrics and reflow status are not + // touched and PR_FALSE is returned. PRBool IsFrameTreeTooDeep(const nsHTMLReflowState& aReflowState, - nsHTMLReflowMetrics& aMetrics); + nsHTMLReflowMetrics& aMetrics, + nsReflowStatus& aStatus); // Do the work for getting the parent style context frame so that // other frame's |GetParentStyleContextFrame| methods can call this diff --git a/layout/generic/nsFrameFrame.cpp b/layout/generic/nsFrameFrame.cpp index 4c4ea11f..a339503c 100644 --- a/layout/generic/nsFrameFrame.cpp +++ b/layout/generic/nsFrameFrame.cpp @@ -767,26 +767,6 @@ nsSubDocumentFrame::ShowDocShell() baseWindow->SetVisibility(PR_TRUE); } - // Trigger editor re-initialization if midas is turned on in the - // sub-document. This shouldn't be necessary, but given the way our - // editor works, it is. See - // https://bugzilla.mozilla.org/show_bug.cgi?id=284245 - docShell->GetPresShell(getter_AddRefs(presShell)); - if (presShell) { - nsCOMPtr doc = - do_QueryInterface(presShell->GetDocument()); - - if (doc) { - nsAutoString designMode; - doc->GetDesignMode(designMode); - - if (designMode.EqualsLiteral("on")) { - doc->SetDesignMode(NS_LITERAL_STRING("off")); - doc->SetDesignMode(NS_LITERAL_STRING("on")); - } - } - } - return NS_OK; } diff --git a/layout/generic/nsFrameSetFrame.cpp b/layout/generic/nsFrameSetFrame.cpp index 0c3e7ad0..c142c885 100644 --- a/layout/generic/nsFrameSetFrame.cpp +++ b/layout/generic/nsFrameSetFrame.cpp @@ -355,13 +355,19 @@ nsHTMLFramesetFrame::Init(nsPresContext* aPresContext, NS_ENSURE_SUCCESS(result, result); result = ourContent->GetColSpec(&mNumCols, &colSpecs); NS_ENSURE_SUCCESS(result, result); + + // Maximum value of mNumRows and mNumCols is NS_MAX_FRAMESET_SPEC_COUNT + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT < UINT_MAX / sizeof(nscoord)); mRowSizes = new nscoord[mNumRows]; mColSizes = new nscoord[mNumCols]; if (!mRowSizes || !mColSizes) return NS_ERROR_OUT_OF_MEMORY; + // Ensure we can't overflow numCells + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT < PR_INT32_MAX / NS_MAX_FRAMESET_SPEC_COUNT); PRInt32 numCells = mNumRows*mNumCols; + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT < UINT_MAX / sizeof(nsHTMLFramesetBorderFrame*)); mVerBorders = new nsHTMLFramesetBorderFrame*[mNumCols]; // 1 more than number of ver borders if (!mVerBorders) return NS_ERROR_OUT_OF_MEMORY; @@ -375,7 +381,13 @@ nsHTMLFramesetFrame::Init(nsPresContext* aPresContext, for (int horX = 0; horX < mNumRows; horX++) mHorBorders[horX] = nsnull; - + + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT + < UINT_MAX / sizeof(PRInt32) / NS_MAX_FRAMESET_SPEC_COUNT); + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT + < UINT_MAX / sizeof(nsFrameborder) / NS_MAX_FRAMESET_SPEC_COUNT); + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT + < UINT_MAX / sizeof(nsBorderColor) / NS_MAX_FRAMESET_SPEC_COUNT); mChildTypes = new PRInt32[numCells]; mChildFrameborder = new nsFrameborder[numCells]; mChildBorderColors = new nsBorderColor[numCells]; @@ -550,6 +562,9 @@ void nsHTMLFramesetFrame::CalculateRowCol(nsPresContext* aPresContext, const nsFramesetSpec* aSpecs, nscoord* aValues) { + // aNumSpecs maximum value is NS_MAX_FRAMESET_SPEC_COUNT + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT < UINT_MAX / sizeof(PRInt32)); + PRInt32 fixedTotal = 0; PRInt32 numFixed = 0; PRInt32* fixed = new PRInt32[aNumSpecs]; @@ -1045,6 +1060,11 @@ nsHTMLFramesetFrame::Reflow(nsPresContext* aPresContext, nsFrameborder frameborder = GetFrameBorder(); if (firstTime) { + // Check for overflow in memory allocations using mNumCols and mNumRows + // which have a maxium value of NS_MAX_FRAMESET_SPEC_COUNT. + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT < UINT_MAX / sizeof(PRBool)); + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT < UINT_MAX / sizeof(nscolor)); + verBordersVis = new PRBool[mNumCols]; verBorderColors = new nscolor[mNumCols]; for (int verX = 0; verX < mNumCols; verX++) { @@ -1360,7 +1380,10 @@ nsHTMLFramesetFrame::RecalculateBorderResize() return; } + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT < PR_INT32_MAX / NS_MAX_FRAMESET_SPEC_COUNT); PRInt32 numCells = mNumRows * mNumCols; // max number of cells + PR_STATIC_ASSERT(NS_MAX_FRAMESET_SPEC_COUNT + < UINT_MAX / sizeof(PRInt32) / NS_MAX_FRAMESET_SPEC_COUNT); PRInt32* childTypes = new PRInt32[numCells]; PRUint32 childIndex, frameOrFramesetChildIndex = 0; diff --git a/layout/generic/nsInlineFrame.cpp b/layout/generic/nsInlineFrame.cpp index 59a8304e..9aeee318 100644 --- a/layout/generic/nsInlineFrame.cpp +++ b/layout/generic/nsInlineFrame.cpp @@ -457,17 +457,7 @@ nsInlineFrame::Reflow(nsPresContext* aPresContext, } } - if (IsFrameTreeTooDeep(aReflowState, aMetrics)) { -#ifdef DEBUG_kipp - { - extern char* nsPresShell_ReflowStackPointerTop; - char marker; - char* newsp = (char*) ▮ - printf("XXX: frame tree is too deep; approx stack size = %d\n", - nsPresShell_ReflowStackPointerTop - newsp); - } -#endif - aStatus = NS_FRAME_COMPLETE; + if (IsFrameTreeTooDeep(aReflowState, aMetrics, aStatus)) { return NS_OK; } diff --git a/layout/generic/nsObjectFrame.cpp b/layout/generic/nsObjectFrame.cpp index 16d2ba49..94293f19 100644 --- a/layout/generic/nsObjectFrame.cpp +++ b/layout/generic/nsObjectFrame.cpp @@ -3293,12 +3293,13 @@ nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays() // Nav 4.x would simply replace the "data" with "src". Because some plugins correctly // look for "data", lets instead copy the "data" attribute and add another entry // to the bottom of the array if there isn't already a "src" specified. - PRInt16 numRealAttrs = mNumCachedAttrs; + PRUint16 numRealAttrs = mNumCachedAttrs; nsAutoString data; nsIAtom *tag = content->Tag(); if (nsHTMLAtoms::object == tag && !content->HasAttr(kNameSpaceID_None, nsHTMLAtoms::src) - && NS_CONTENT_ATTR_NOT_THERE != content->GetAttr(kNameSpaceID_None, nsHTMLAtoms::data, data)) { + && NS_CONTENT_ATTR_NOT_THERE != content->GetAttr(kNameSpaceID_None, nsHTMLAtoms::data, data) + && !data.IsEmpty()) { mNumCachedAttrs++; } @@ -3309,7 +3310,7 @@ nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays() NS_ENSURE_TRUE(mCachedAttrParamValues, NS_ERROR_OUT_OF_MEMORY); // let's fill in our attributes - PRInt16 c = 0; + PRUint32 nextAttrParamIndex = 0; // Some plugins (eg Flash, see bug 234675.) are actually sensitive to the // attribute order. So we want to make sure we give the plugin the @@ -3317,7 +3318,7 @@ nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays() // other browsers. Now in HTML, the storage order is the reverse of the // source order, while in XML and XHTML it's the same as the source order // (see the AddAttributes functions in the HTML and XML content sinks). - PRInt16 start, end, increment; + PRInt32 start, end, increment; if (content->IsContentOfType(nsIContent::eHTML) && content->GetNodeInfo()->NamespaceEquals(kNameSpaceID_None)) { // HTML. Walk attributes in reverse order. @@ -3330,7 +3331,7 @@ nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays() end = numRealAttrs; increment = 1; } - for (PRInt16 index = start; index != end; index += increment) { + for (PRInt32 index = start; index != end; index += increment) { PRInt32 nameSpaceID; nsCOMPtr atom; nsCOMPtr prefix; @@ -3344,25 +3345,26 @@ nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays() mOwner->FixUpURLS(name, value); - mCachedAttrParamNames [c] = ToNewUTF8String(name); - mCachedAttrParamValues[c] = ToNewUTF8String(value); - c++; + mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(name); + mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(value); + nextAttrParamIndex++; } } // if the conditions above were met, copy the "data" attribute to a "src" array entry - if (data.Length()) { - mCachedAttrParamNames [mNumCachedAttrs-1] = ToNewUTF8String(NS_LITERAL_STRING("SRC")); - mCachedAttrParamValues[mNumCachedAttrs-1] = ToNewUTF8String(data); + if (!data.IsEmpty()) { + mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("SRC")); + mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(data); + nextAttrParamIndex++; } // add our PARAM and null separator - mCachedAttrParamNames [mNumCachedAttrs] = ToNewUTF8String(NS_LITERAL_STRING("PARAM")); - mCachedAttrParamValues[mNumCachedAttrs] = nsnull; + mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("PARAM")); + mCachedAttrParamValues[nextAttrParamIndex] = nsnull; + nextAttrParamIndex++; // now fill in the PARAM name/value pairs from the cached DOM nodes - c = 0; - for (PRInt16 idx = 0; idx < mNumCachedParams; idx++) { + for (PRUint16 idx = 0; idx < mNumCachedParams; idx++) { nsCOMPtr param = do_QueryElementAt(ourParams, idx); if (param) { nsAutoString name; @@ -3384,9 +3386,9 @@ nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays() */ name.Trim(" \n\r\t\b", PR_TRUE, PR_TRUE, PR_FALSE); value.Trim(" \n\r\t\b", PR_TRUE, PR_TRUE, PR_FALSE); - mCachedAttrParamNames [mNumCachedAttrs + 1 + c] = ToNewUTF8String(name); - mCachedAttrParamValues[mNumCachedAttrs + 1 + c] = ToNewUTF8String(value); - c++; // rules! + mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(name); + mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(value); + nextAttrParamIndex++; } } diff --git a/layout/generic/nsSelection.cpp b/layout/generic/nsSelection.cpp index 0242c863..5119c646 100644 --- a/layout/generic/nsSelection.cpp +++ b/layout/generic/nsSelection.cpp @@ -6312,6 +6312,9 @@ nsTypedSelection::Collapse(nsIDOMNode* aParentNode, PRInt32 aOffset) return NS_ERROR_INVALID_ARG; if (!mFrameSelection) return NS_ERROR_NOT_INITIALIZED; // Can't do selection + + nsCOMPtr kungfuDeathGrip = aParentNode; + mFrameSelection->InvalidateDesiredX(); if (!IsValidSelectionPoint(mFrameSelection, aParentNode)) return NS_ERROR_FAILURE; diff --git a/layout/style/nsCSSLoader.cpp b/layout/style/nsCSSLoader.cpp index f561bf0a..ac15769a 100644 --- a/layout/style/nsCSSLoader.cpp +++ b/layout/style/nsCSSLoader.cpp @@ -1495,10 +1495,11 @@ CSSLoaderImpl::SheetComplete(SheetLoadData* aLoadData, PRBool aSucceeded) data = data->mNext; } - // Now that it's marked complete, put the sheet in our cache + // Now that it's marked complete, put the sheet in our cache, but + // only if we parsed it case-sensitively. if (aSucceeded && aLoadData->mURI) { #ifdef MOZ_XUL - if (IsChromeURI(aLoadData->mURI)) { + if (IsChromeURI(aLoadData->mURI) && mCaseSensitive) { nsCOMPtr cache(do_GetService("@mozilla.org/xul/xul-prototype-cache;1")); if (cache) { PRBool enabled; diff --git a/layout/tables/nsCellMap.cpp b/layout/tables/nsCellMap.cpp index f811605d..56ab2623 100644 --- a/layout/tables/nsCellMap.cpp +++ b/layout/tables/nsCellMap.cpp @@ -324,7 +324,9 @@ nsTableCellMap::Synchronize(nsTableFrame* aTableFrame) if (map) { if (!maps.AppendElement(map)) { delete map; + map = nsnull; NS_WARNING("Could not AppendElement"); + break; } } } diff --git a/layout/xul/base/src/nsListBoxBodyFrame.cpp b/layout/xul/base/src/nsListBoxBodyFrame.cpp index 32992aa7..0b7b9354 100644 --- a/layout/xul/base/src/nsListBoxBodyFrame.cpp +++ b/layout/xul/base/src/nsListBoxBodyFrame.cpp @@ -1194,6 +1194,9 @@ nsListBoxBodyFrame::GetNextItemBox(nsIBox* aBox, PRInt32 aOffset, nsIFrame* existingFrame = nsnull; mPresContext->GetPresShell()->GetPrimaryFrameFor(nextContent, &existingFrame); + + if (existingFrame && existingFrame->GetParent() != this) + return GetNextItemBox(aBox, ++aOffset, aCreated); if (!existingFrame) { // Either append the new frame, or insert it after the current frame @@ -1450,14 +1453,14 @@ void nsListBoxBodyFrame::RemoveChildFrame(nsBoxLayoutState &aState, nsIFrame *aFrame) { + if (!mFrames.ContainsFrame(aFrame)) { + NS_ERROR("tried to remove a child frame which isn't our child"); + return; + } + mFrameConstructor->RemoveMappingsForFrameSubtree(aFrame, nsnull); -#ifdef DEBUG - PRBool removed = -#endif - mFrames.RemoveFrame(aFrame); - NS_ASSERTION(removed, - "Going to destroy a frame we didn't remove. Prepare to crash"); + mFrames.RemoveFrame(aFrame); if (mLayoutManager) mLayoutManager->ChildrenRemoved(this, aState, aFrame); aFrame->Destroy(mPresContext); diff --git a/layout/xul/base/src/tree/public/nsITreeSelection.idl b/layout/xul/base/src/tree/public/nsITreeSelection.idl index 32c58285..cc18c068 100644 --- a/layout/xul/base/src/tree/public/nsITreeSelection.idl +++ b/layout/xul/base/src/tree/public/nsITreeSelection.idl @@ -144,3 +144,14 @@ interface nsITreeSelection : nsISupports */ readonly attribute long shiftSelectPivot; }; + +/** + * The following interface is not scriptable and MUST NEVER BE MADE scriptable. + * Native treeselections implement it, and we use this to check whether a + * treeselection is native (and therefore suitable for use by untrusted content). + */ +[uuid(1bd59678-5cb3-4316-b246-31a91b19aabe)] +interface nsINativeTreeSelection : nsITreeSelection +{ + [noscript] void ensureNative(); +}; diff --git a/layout/xul/base/src/tree/src/nsTreeContentView.cpp b/layout/xul/base/src/tree/src/nsTreeContentView.cpp index 1932e40f..64e3d9ca 100644 --- a/layout/xul/base/src/tree/src/nsTreeContentView.cpp +++ b/layout/xul/base/src/tree/src/nsTreeContentView.cpp @@ -47,6 +47,8 @@ #include "nsIDOMClassInfo.h" #include "nsIEventStateManager.h" #include "nsINodeInfo.h" +#include "nsContentUtils.h" +#include "nsDOMError.h" // A content model view implementation for the tree. @@ -185,9 +187,22 @@ nsTreeContentView::GetSelection(nsITreeSelection** aSelection) return NS_OK; } +PRBool +nsTreeContentView::CanTrustTreeSelection(nsISupports* aValue) +{ + // Untrusted content is only allowed to specify known-good views + if (nsContentUtils::IsCallerTrustedForWrite()) + return PR_TRUE; + nsCOMPtr nativeTreeSel = do_QueryInterface(aValue); + return nativeTreeSel && NS_SUCCEEDED(nativeTreeSel->EnsureNative()); +} + NS_IMETHODIMP nsTreeContentView::SetSelection(nsITreeSelection* aSelection) { + NS_ENSURE_TRUE(!aSelection || CanTrustTreeSelection(aSelection), + NS_ERROR_DOM_SECURITY_ERR); + mSelection = aSelection; if (mUpdateSelection) { @@ -969,9 +984,14 @@ nsTreeContentView::ContentInserted(nsIDocument *aDocument, } else if (childTag == nsHTMLAtoms::option) { PRInt32 parentIndex = FindContent(aContainer); - PRInt32 count = InsertRow(parentIndex, aIndexInContainer, aChild); - if (mBoxObject) - mBoxObject->RowCountChanged(parentIndex + aIndexInContainer + 1, count); + + if (parentIndex >= 0) { + PRInt32 index = 0; + GetIndexInSubtree(aContainer, aChild, &index); + PRInt32 count = InsertRow(parentIndex, index, aChild); + if (mBoxObject) + mBoxObject->RowCountChanged(parentIndex + index + 1, count); + } } } diff --git a/layout/xul/base/src/tree/src/nsTreeContentView.h b/layout/xul/base/src/tree/src/nsTreeContentView.h index d9046f98..0b9d5e64 100644 --- a/layout/xul/base/src/tree/src/nsTreeContentView.h +++ b/layout/xul/base/src/tree/src/nsTreeContentView.h @@ -88,6 +88,8 @@ class nsTreeContentView : public nsINativeTreeView, nsIContent* aChild, PRInt32 aIndexInContainer); virtual void DocumentWillBeDestroyed(nsIDocument *aDocument); + static PRBool CanTrustTreeSelection(nsISupports* aValue); + protected: // Recursive methods which deal with serializing of nested content. void Serialize(nsIContent* aContent, PRInt32 aParentIndex, PRInt32* aIndex, nsVoidArray& aRows); diff --git a/layout/xul/base/src/tree/src/nsTreeSelection.cpp b/layout/xul/base/src/tree/src/nsTreeSelection.cpp index cf1cb232..3c6aeac1 100644 --- a/layout/xul/base/src/tree/src/nsTreeSelection.cpp +++ b/layout/xul/base/src/tree/src/nsTreeSelection.cpp @@ -54,6 +54,7 @@ #include "nsINameSpaceManager.h" #include "nsXULAtoms.h" #include "nsPLDOMEvent.h" +#include "nsTArray.h" // A helper class for managing our ranges of selection. struct nsTreeRange @@ -212,17 +213,39 @@ struct nsTreeRange return total; }; + static void CollectRanges(nsTreeRange* aRange, nsTArray& aRanges) + { + nsTreeRange* cur = aRange; + while (cur) { + aRanges.AppendElement(cur->mMin); + aRanges.AppendElement(cur->mMax); + cur = cur->mNext; + } + } + + static void InvalidateRanges(nsITreeBoxObject* aTree, + nsTArray& aRanges) + { + if (aTree) { + nsCOMPtr tree = aTree; + for (PRUint32 i = 0; i < aRanges.Length(); i += 2) { + aTree->InvalidateRange(aRanges[i], aRanges[i + 1]); + } + } + } + void Invalidate() { - mSelection->mTree->InvalidateRange(mMin, mMax); - if (mNext) - mNext->Invalidate(); + nsTArray ranges; + CollectRanges(this, ranges); + InvalidateRanges(mSelection->mTree, ranges); }; void RemoveAllBut(PRInt32 aIndex) { if (aIndex >= mMin && aIndex <= mMax) { // Invalidate everything in this list. - mSelection->mFirstRange->Invalidate(); + nsTArray ranges; + CollectRanges(mSelection->mFirstRange, ranges); mMin = aIndex; mMax = aIndex; @@ -238,6 +261,7 @@ struct nsTreeRange delete mSelection->mFirstRange; mSelection->mFirstRange = this; } + InvalidateRanges(mSelection->mTree, ranges); } else if (mNext) mNext->RemoveAllBut(aIndex); @@ -272,6 +296,7 @@ nsTreeSelection::~nsTreeSelection() // QueryInterface implementation for nsBoxObject NS_INTERFACE_MAP_BEGIN(nsTreeSelection) NS_INTERFACE_MAP_ENTRY(nsITreeSelection) + NS_INTERFACE_MAP_ENTRY(nsINativeTreeSelection) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_ENTRY_DOM_CLASSINFO(TreeSelection) NS_INTERFACE_MAP_END @@ -281,8 +306,7 @@ NS_IMPL_RELEASE(nsTreeSelection) NS_IMETHODIMP nsTreeSelection::GetTree(nsITreeBoxObject * *aTree) { - NS_IF_ADDREF(mTree); - *aTree = mTree; + NS_IF_ADDREF(*aTree = mTree); return NS_OK; } @@ -292,13 +316,20 @@ NS_IMETHODIMP nsTreeSelection::SetTree(nsITreeBoxObject * aTree) mSelectTimer->Cancel(); mSelectTimer = nsnull; } - mTree = aTree; // WEAK + + // Make sure aTree really implements nsITreeBoxObject! + mTree = do_QueryInterface(aTree); + NS_ENSURE_STATE(mTree || !aTree); return NS_OK; } NS_IMETHODIMP nsTreeSelection::GetSingle(PRBool* aSingle) { + if (!mTree) + return NS_ERROR_NULL_POINTER; + nsCOMPtr boxObject = do_QueryInterface(mTree); + NS_ENSURE_STATE(boxObject); nsCOMPtr element; boxObject->GetElement(getter_AddRefs(element)); nsCOMPtr content = do_QueryInterface(element); @@ -399,8 +430,8 @@ NS_IMETHODIMP nsTreeSelection::ToggleSelect(PRInt32 aIndex) else { if (!mFirstRange->Contains(aIndex)) { PRBool single; - GetSingle(&single); - if (!single) + rv = GetSingle(&single); + if (NS_SUCCEEDED(rv) && !single) rv = mFirstRange->Add(aIndex); } else @@ -418,7 +449,10 @@ NS_IMETHODIMP nsTreeSelection::ToggleSelect(PRInt32 aIndex) NS_IMETHODIMP nsTreeSelection::RangedSelect(PRInt32 aStartIndex, PRInt32 aEndIndex, PRBool aAugment) { PRBool single; - GetSingle(&single); + nsresult rv = GetSingle(&single); + if (NS_FAILED(rv)) + return rv; + if ((mFirstRange || (aStartIndex != aEndIndex)) && single) return NS_OK; @@ -427,6 +461,7 @@ NS_IMETHODIMP nsTreeSelection::RangedSelect(PRInt32 aStartIndex, PRInt32 aEndInd if (mFirstRange) { mFirstRange->Invalidate(); delete mFirstRange; + mFirstRange = nsnull; } } @@ -503,6 +538,10 @@ NS_IMETHODIMP nsTreeSelection::InvertSelection() NS_IMETHODIMP nsTreeSelection::SelectAll() { + if (!mTree) { + return NS_OK; + } + nsCOMPtr view; mTree->GetView(getter_AddRefs(view)); if (!view) @@ -511,7 +550,10 @@ NS_IMETHODIMP nsTreeSelection::SelectAll() PRInt32 rowCount; view->GetRowCount(&rowCount); PRBool single; - GetSingle(&single); + nsresult rv = GetSingle(&single); + if (NS_FAILED(rv)) + return rv; + if (rowCount == 0 || (rowCount > 1 && single)) return NS_OK; @@ -592,6 +634,9 @@ NS_IMETHODIMP nsTreeSelection::GetCurrentIndex(PRInt32 *aCurrentIndex) NS_IMETHODIMP nsTreeSelection::SetCurrentIndex(PRInt32 aIndex) { + if (!mTree) + return NS_ERROR_NULL_POINTER; + if (mCurrentIndex == aIndex) { return NS_OK; } @@ -633,7 +678,12 @@ NS_IMETHODIMP nsTreeSelection::SetCurrentIndex(PRInt32 aIndex) #define ADD_NEW_RANGE(macro_range, macro_selection, macro_start, macro_end) \ { \ - nsTreeRange* macro_new_range = new nsTreeRange(macro_selection, (macro_start), (macro_end)); \ + PRInt32 start = macro_start; \ + PRInt32 end = macro_end; \ + if (start > end) { \ + end = start; \ + } \ + nsTreeRange* macro_new_range = new nsTreeRange(macro_selection, start, end); \ if (macro_range) \ macro_range->Insert(macro_new_range); \ else \ @@ -671,27 +721,27 @@ nsTreeSelection::AdjustSelection(PRInt32 aIndex, PRInt32 aCount) // no selection, so nothing to do. if (!mFirstRange) return NS_OK; - nsTreeRange* newRange = nsnull; - PRBool selChanged = PR_FALSE; + nsTreeRange* oldFirstRange = mFirstRange; nsTreeRange* curr = mFirstRange; + mFirstRange = nsnull; while (curr) { if (aCount > 0) { // inserting if (aIndex > curr->mMax) { // adjustment happens after the range, so no change - ADD_NEW_RANGE(newRange, this, curr->mMin, curr->mMax); + ADD_NEW_RANGE(mFirstRange, this, curr->mMin, curr->mMax); } else if (aIndex <= curr->mMin) { // adjustment happens before the start of the range, so shift down - ADD_NEW_RANGE(newRange, this, curr->mMin + aCount, curr->mMax + aCount); + ADD_NEW_RANGE(mFirstRange, this, curr->mMin + aCount, curr->mMax + aCount); selChanged = PR_TRUE; } else { // adjustment happen inside the range. // break apart the range and create two ranges - ADD_NEW_RANGE(newRange, this, curr->mMin, aIndex - 1); - ADD_NEW_RANGE(newRange, this, aIndex + aCount, curr->mMax + aCount); + ADD_NEW_RANGE(mFirstRange, this, curr->mMin, aIndex - 1); + ADD_NEW_RANGE(mFirstRange, this, aIndex + aCount, curr->mMax + aCount); selChanged = PR_TRUE; } } @@ -699,7 +749,7 @@ nsTreeSelection::AdjustSelection(PRInt32 aIndex, PRInt32 aCount) // deleting if (aIndex > curr->mMax) { // adjustment happens after the range, so no change - ADD_NEW_RANGE(newRange, this, curr->mMin, curr->mMax); + ADD_NEW_RANGE(mFirstRange, this, curr->mMin, curr->mMax); } else { // remember, aCount is negative @@ -708,31 +758,30 @@ nsTreeSelection::AdjustSelection(PRInt32 aIndex, PRInt32 aCount) if (aIndex <= curr->mMin) { if (lastIndexOfAdjustment < curr->mMin) { // adjustment happens before the start of the range, so shift up - ADD_NEW_RANGE(newRange, this, curr->mMin + aCount, curr->mMax + aCount); + ADD_NEW_RANGE(mFirstRange, this, curr->mMin + aCount, curr->mMax + aCount); } else if (lastIndexOfAdjustment >= curr->mMax) { // adjustment contains the range. remove the range by not adding it to the newRange } else { // adjustment starts before the range, and ends in the middle of it, so trim the range - ADD_NEW_RANGE(newRange, this, aIndex, curr->mMax + aCount) + ADD_NEW_RANGE(mFirstRange, this, aIndex, curr->mMax + aCount) } } else if (lastIndexOfAdjustment >= curr->mMax) { // adjustment starts in the middle of the current range, and contains the end of the range, so trim the range - ADD_NEW_RANGE(newRange, this, curr->mMin, aIndex - 1) + ADD_NEW_RANGE(mFirstRange, this, curr->mMin, aIndex - 1) } else { // range contains the adjustment, so shorten the range - ADD_NEW_RANGE(newRange, this, curr->mMin, curr->mMax + aCount) + ADD_NEW_RANGE(mFirstRange, this, curr->mMin, curr->mMax + aCount) } } } curr = curr->mNext; } - delete mFirstRange; - mFirstRange = newRange; + delete oldFirstRange; // Fire the select event if (selChanged) @@ -760,7 +809,7 @@ nsTreeSelection::GetShiftSelectPivot(PRInt32* aIndex) nsresult nsTreeSelection::FireOnSelectHandler() { - if (mSuppressed) + if (mSuppressed || !mTree) return NS_OK; nsCOMPtr boxObject = do_QueryInterface(mTree); diff --git a/layout/xul/base/src/tree/src/nsTreeSelection.h b/layout/xul/base/src/tree/src/nsTreeSelection.h index 0130f9bd..fc62bff6 100644 --- a/layout/xul/base/src/tree/src/nsTreeSelection.h +++ b/layout/xul/base/src/tree/src/nsTreeSelection.h @@ -48,7 +48,7 @@ class nsITreeBoxObject; struct nsTreeRange; -class nsTreeSelection : public nsITreeSelection +class nsTreeSelection : public nsINativeTreeSelection { public: nsTreeSelection(nsITreeBoxObject* aTree); @@ -57,6 +57,9 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSITREESELECTION + // nsINativeTreeSelection: Untrusted code can use us + NS_IMETHOD EnsureNative() { return NS_OK; } + friend struct nsTreeRange; protected: @@ -65,7 +68,7 @@ protected: protected: // Members - nsITreeBoxObject* mTree; // [Weak]. The tree will hold on to us through the view and let go when it dies. + nsCOMPtr mTree; // The tree will hold on to us through the view and let go when it dies. PRBool mSuppressed; // Whether or not we should be firing onselect events. PRInt32 mCurrentIndex; // The item to draw the rect around. The last one clicked, etc. diff --git a/mailnews/addrbook/src/nsAddrDatabase.cpp b/mailnews/addrbook/src/nsAddrDatabase.cpp index 2e838159..4379493a 100644 --- a/mailnews/addrbook/src/nsAddrDatabase.cpp +++ b/mailnews/addrbook/src/nsAddrDatabase.cpp @@ -3153,19 +3153,19 @@ nsresult nsAddrDatabase::GetListFromDB(nsIAbDirectory *newList, nsIMdbRow* listR return err; } -class nsAddrDBEnumerator : public nsIEnumerator +class nsAddrDBEnumerator : public nsIEnumerator, public nsIAddrDBListener { public: NS_DECL_ISUPPORTS // nsIEnumerator methods: NS_DECL_NSIENUMERATOR - + NS_DECL_NSIADDRDBLISTENER // nsAddrDBEnumerator methods: nsAddrDBEnumerator(nsAddrDatabase* db); virtual ~nsAddrDBEnumerator(); - + void Clear(); protected: nsCOMPtr mDB; nsCOMPtr mResultList; @@ -3183,14 +3183,25 @@ nsAddrDBEnumerator::nsAddrDBEnumerator(nsAddrDatabase* db) { mDbTable = mDB->GetPabTable(); mCurrentRowIsList = PR_FALSE; + if (mDB) + mDB->AddListener(this); } nsAddrDBEnumerator::~nsAddrDBEnumerator() { - NS_IF_RELEASE(mRowCursor); + Clear(); } -NS_IMPL_ISUPPORTS1(nsAddrDBEnumerator, nsIEnumerator) +void nsAddrDBEnumerator::Clear() +{ + NS_IF_RELEASE(mRowCursor); + mCurrentRow = nsnull; + mDbTable = nsnull; + if (mDB) + mDB->RemoveListener(this); +} + +NS_IMPL_ISUPPORTS2(nsAddrDBEnumerator, nsIEnumerator, nsIAddrDBListener) NS_IMETHODIMP nsAddrDBEnumerator::First(void) { @@ -3277,6 +3288,30 @@ NS_IMETHODIMP nsAddrDBEnumerator::IsDone(void) return mDone ? NS_OK : NS_ERROR_FAILURE; } +NS_IMETHODIMP nsAddrDBEnumerator::OnCardAttribChange(PRUint32 abCode) +{ + return NS_OK; +} + +/* void onCardEntryChange (in unsigned long aAbCode, in nsIAbCard aCard, in nsIAbDirectory aParent); */ +NS_IMETHODIMP nsAddrDBEnumerator::OnCardEntryChange(PRUint32 aAbCode, nsIAbCard *aCard) +{ + return NS_OK; +} + +/* void onListEntryChange (in unsigned long abCode, in nsIAbDirectory list); */ +NS_IMETHODIMP nsAddrDBEnumerator::OnListEntryChange(PRUint32 abCode, nsIAbDirectory *list) +{ + return NS_OK; +} + +/* void onAnnouncerGoingAway (); */ +NS_IMETHODIMP nsAddrDBEnumerator::OnAnnouncerGoingAway() +{ + Clear(); + return NS_OK; +} + class nsListAddressEnumerator : public nsIEnumerator { public: diff --git a/mailnews/base/search/src/nsMsgFilter.cpp b/mailnews/base/search/src/nsMsgFilter.cpp index 9832f16b..d45be1d3 100644 --- a/mailnews/base/search/src/nsMsgFilter.cpp +++ b/mailnews/base/search/src/nsMsgFilter.cpp @@ -553,6 +553,7 @@ nsMsgFilter::MatchHdr(nsIMsgDBHdr *msgHdr, nsIMsgFolder *folder, PRUint32 headersSize, PRBool *pResult) { NS_ENSURE_ARG_POINTER(folder); + NS_ENSURE_ARG_POINTER(msgHdr); // use offlineMail because nsXPIDLCString folderCharset; folder->GetCharset(getter_Copies(folderCharset)); diff --git a/mailnews/base/src/nsMsgQuickSearchDBView.cpp b/mailnews/base/src/nsMsgQuickSearchDBView.cpp index 3913ba6c..f45abe52 100644 --- a/mailnews/base/src/nsMsgQuickSearchDBView.cpp +++ b/mailnews/base/src/nsMsgQuickSearchDBView.cpp @@ -427,6 +427,8 @@ nsresult nsMsgQuickSearchDBView::SortThreads(nsMsgViewSortTypeValue sortType, ns continue; // it would be nice if GetInsertIndexHelper always found the hdr, but it doesn't. threadHdr->GetChildHdrAt(0, getter_AddRefs(rootHdr)); + if (!rootHdr) + continue; threadRootIndex = GetInsertIndexHelper(rootHdr, &threadRootIds, nsMsgViewSortOrder::ascending, nsMsgViewSortType::byId); threadRootIds.InsertAt(threadRootIndex, rootKey); } diff --git a/mailnews/base/util/nsMsgDBFolder.cpp b/mailnews/base/util/nsMsgDBFolder.cpp index d5e2b6db..7f490987 100644 --- a/mailnews/base/util/nsMsgDBFolder.cpp +++ b/mailnews/base/util/nsMsgDBFolder.cpp @@ -1974,6 +1974,7 @@ nsMsgDBFolder::CallFilterPlugins(nsIMsgWindow *aMsgWindow, PRBool *aFiltersRun) { rv = GetDatabase(nsnull); // XXX is nsnull a reasonable arg here? NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(mDatabase, NS_ERROR_NOT_AVAILABLE); } // get the list of new messages @@ -2035,8 +2036,10 @@ nsMsgDBFolder::CallFilterPlugins(nsIMsgWindow *aMsgWindow, PRBool *aFiltersRun) nsXPIDLCString junkScore; nsCOMPtr msgHdr; nsMsgKey msgKey = newMessageKeys.GetAt(i); - rv = mDatabase->GetMsgHdrForKey(msgKey, getter_AddRefs(msgHdr)); - if (!NS_SUCCEEDED(rv)) + NS_ASSERTION(mDatabase, "null database"); + if (mDatabase) + rv = mDatabase->GetMsgHdrForKey(msgKey, getter_AddRefs(msgHdr)); + if (!mDatabase || !NS_SUCCEEDED(rv)) continue; nsXPIDLCString author; nsXPIDLCString authorEmailAddress; diff --git a/mailnews/base/util/nsMsgMailNewsUrl.cpp b/mailnews/base/util/nsMsgMailNewsUrl.cpp index e7e169fc..511f2e77 100644 --- a/mailnews/base/util/nsMsgMailNewsUrl.cpp +++ b/mailnews/base/util/nsMsgMailNewsUrl.cpp @@ -914,12 +914,13 @@ NS_IMETHODIMP nsMsgSaveAsListener::OnDataAvailable(nsIRequest* request, while (start && end) { - if (PL_strncasecmp(start, "X-Mozilla-Status:", 17) && + if (m_outputStream && + PL_strncasecmp(start, "X-Mozilla-Status:", 17) && PL_strncasecmp(start, "X-Mozilla-Status2:", 18) && PL_strncmp(start, "From - ", 7)) { rv = m_outputStream->Write(start, end-start, &writeCount); - rv = m_outputStream->Write(lineEnding, lineEndingLength, &writeCount); + rv |= m_outputStream->Write(lineEnding, lineEndingLength, &writeCount); } start = end+linebreak_len; if (start >= m_dataBuffer + m_leftOver) diff --git a/mailnews/compose/src/nsMsgAttachmentHandler.cpp b/mailnews/compose/src/nsMsgAttachmentHandler.cpp index 23c01fb9..d7b1a814 100644 --- a/mailnews/compose/src/nsMsgAttachmentHandler.cpp +++ b/mailnews/compose/src/nsMsgAttachmentHandler.cpp @@ -1029,20 +1029,21 @@ nsMsgAttachmentHandler::LoadDataFromFile(nsFileSpec& fSpec, nsString &sigData, P nsresult nsMsgAttachmentHandler::Abort() { + nsCOMPtr saveRequest = mRequest; + mRequest = nsnull; NS_ASSERTION(m_mime_delivery_state != nsnull, "not-null m_mime_delivery_state"); if (m_done) return NS_OK; - if (mRequest) - return mRequest->Cancel(NS_ERROR_ABORT); + if (saveRequest) + return saveRequest->Cancel(NS_ERROR_ABORT); else if (m_mime_delivery_state) { m_mime_delivery_state->SetStatus(NS_ERROR_ABORT); m_mime_delivery_state->NotifyListenerOnStopSending(nsnull, NS_ERROR_ABORT, 0, nsnull); } - return NS_OK; } diff --git a/mailnews/compose/src/nsMsgAttachmentHandler.h b/mailnews/compose/src/nsMsgAttachmentHandler.h index 2b10eb1c..bcb675bc 100644 --- a/mailnews/compose/src/nsMsgAttachmentHandler.h +++ b/mailnews/compose/src/nsMsgAttachmentHandler.h @@ -102,7 +102,7 @@ public: nsCOMPtr mURL; nsFileSpec *mFileSpec; // The temp file to which we save it nsCOMPtr mOutFile; - nsIRequest *mRequest; // The live request used while fetching an attachment + nsCOMPtr mRequest; // The live request used while fetching an attachment nsMsgCompFields *mCompFields; // Message composition fields for the sender PRBool m_bogus_attachment; // This is to catch problem children... diff --git a/mailnews/imap/src/nsImapIncomingServer.cpp b/mailnews/imap/src/nsImapIncomingServer.cpp index ce7d204f..2023d597 100644 --- a/mailnews/imap/src/nsImapIncomingServer.cpp +++ b/mailnews/imap/src/nsImapIncomingServer.cpp @@ -1182,6 +1182,8 @@ NS_IMETHODIMP nsImapIncomingServer::PossibleImapMailbox(const char *folderPath, if (dupFolderPath.Last() == hierarchyDelimiter) { dupFolderPath.SetLength(dupFolderPath.Length()-1); + if (dupFolderPath.IsEmpty()) + return NS_ERROR_FAILURE; // *** this is what we did in 4.x in order to list uw folder only // mailbox in order to get the \NoSelect flag explicitlyVerify = !(boxFlags & kNameSpace); @@ -1305,7 +1307,8 @@ NS_IMETHODIMP nsImapIncomingServer::PossibleImapMailbox(const char *folderPath, } } - hostFolder->CreateClientSubfolderInfo(dupFolderPath.get(), hierarchyDelimiter,boxFlags, PR_FALSE); + rv = hostFolder->CreateClientSubfolderInfo(dupFolderPath.get(), hierarchyDelimiter,boxFlags, PR_FALSE); + NS_ENSURE_SUCCESS(rv, rv); caseInsensitive = (nsCRT::strcasecmp("INBOX", dupFolderPath.get())== 0); a_nsIFolder->GetChildWithURI(uri.get(), PR_TRUE, caseInsensitive , getter_AddRefs(child)); } diff --git a/mailnews/imap/src/nsImapMailFolder.cpp b/mailnews/imap/src/nsImapMailFolder.cpp index 347ffd52..c9a9d14c 100644 --- a/mailnews/imap/src/nsImapMailFolder.cpp +++ b/mailnews/imap/src/nsImapMailFolder.cpp @@ -7178,7 +7178,7 @@ nsImapFolderCopyState::OnStopRunningUrl(nsIURI *aUrl, nsresult aExitCode) nsCOMPtr msgSupportsArray; NS_NewISupportsArray(getter_AddRefs(msgSupportsArray)); - PRBool hasMoreElements; + PRBool hasMoreElements = PR_FALSE; nsCOMPtr aSupport; if (messages) diff --git a/mailnews/imap/src/nsImapUtils.cpp b/mailnews/imap/src/nsImapUtils.cpp index de558516..56d8d663 100644 --- a/mailnews/imap/src/nsImapUtils.cpp +++ b/mailnews/imap/src/nsImapUtils.cpp @@ -389,7 +389,15 @@ void AllocateImapUidString(PRUint32 *msgUids, PRUint32 &msgCount, { PRBool foundIt; flagState->GetMessageFlagsFromUID(curSequenceEnd, &foundIt, &curFlagStateIndex); - NS_ASSERTION(foundIt, "flag state missing key"); + if (!foundIt) + { + NS_WARNING("flag state missing key"); + // The start of this sequence is missing from flag state, so move + // on to the next key. + curFlagStateIndex = -1; + curSequenceEnd = startSequence = nextKey; + continue; + } } curFlagStateIndex++; PRUint32 nextUidInFlagState; diff --git a/mailnews/mime/src/mimeenc.cpp b/mailnews/mime/src/mimeenc.cpp index 48c240d3..55d22a6a 100644 --- a/mailnews/mime/src/mimeenc.cpp +++ b/mailnews/mime/src/mimeenc.cpp @@ -1153,7 +1153,7 @@ mime_encode_qp_buffer (MimeEncoderData *data, const char *buffer, PRInt32 size) out = out_buffer; /* If it's CRLF, swallow two chars instead of one. */ - if (in[0] == nsCRT::CR && in[1] == nsCRT::LF) + if (in + 1 < end && in[0] == '\r' && in[1] == '\n') in++; out = out_buffer; diff --git a/modules/libjar/nsJARChannel.cpp b/modules/libjar/nsJARChannel.cpp index 122a8cfe..d6a55254 100644 --- a/modules/libjar/nsJARChannel.cpp +++ b/modules/libjar/nsJARChannel.cpp @@ -49,6 +49,8 @@ #include "nsIFileURL.h" #include "nsIViewSourceChannel.h" #include "nsIJAR.h" +#include "nsChannelProperties.h" + static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID); @@ -190,6 +192,9 @@ nsJARInputThunk::IsNonBlocking(PRBool *nonBlocking) } //----------------------------------------------------------------------------- +// nsJARChannel +//----------------------------------------------------------------------------- + nsJARChannel::nsJARChannel() : mContentLength(-1) @@ -218,19 +223,24 @@ nsJARChannel::~nsJARChannel() NS_RELEASE(handler); // NULL parameter } -NS_IMPL_ISUPPORTS7(nsJARChannel, - nsIRequest, - nsIChannel, - nsIStreamListener, - nsIRequestObserver, - nsIDownloadObserver, - nsIJARChannel, - nsIJARChannel_MOZILLA_1_8_BRANCH) +NS_IMPL_ISUPPORTS_INHERITED7(nsJARChannel, + nsHashPropertyBag, + nsIRequest, + nsIChannel, + nsIStreamListener, + nsIRequestObserver, + nsIDownloadObserver, + nsIJARChannel, + nsIJARChannel_MOZILLA_1_8_BRANCH) nsresult nsJARChannel::Init(nsIURI *uri) { nsresult rv; + rv = nsHashPropertyBag::Init(); + if (NS_FAILED(rv)) + return rv; + mJarURI = do_QueryInterface(uri, &rv); if (NS_FAILED(rv)) return rv; @@ -736,6 +746,11 @@ nsJARChannel::OnDownloadComplete(nsIDownloader *downloader, mIsUnsafe = !(contentType.Equals(channelContentType) && (contentType.EqualsLiteral("application/java-archive") || contentType.EqualsLiteral("application/x-jar"))); + rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Disposition"), + header); + if (NS_SUCCEEDED(rv)) + SetPropertyAsACString(NS_CHANNEL_PROP_CONTENT_DISPOSITION, header); + } else { nsCOMPtr innerJARChannel(do_QueryInterface(channel)); if (innerJARChannel) { diff --git a/modules/libjar/nsJARChannel.h b/modules/libjar/nsJARChannel.h index 6f067d60..d8859c62 100644 --- a/modules/libjar/nsJARChannel.h +++ b/modules/libjar/nsJARChannel.h @@ -47,6 +47,7 @@ #include "nsIZipReader.h" #include "nsIDownloader.h" #include "nsILoadGroup.h" +#include "nsHashPropertyBag.h" #include "nsIFile.h" #include "nsIURI.h" #include "nsCOMPtr.h" @@ -61,6 +62,7 @@ class nsJARChannel : public nsIJARChannel , public nsIJARChannel_MOZILLA_1_8_BRANCH , public nsIDownloadObserver , public nsIStreamListener + , public nsHashPropertyBag { public: NS_DECL_ISUPPORTS diff --git a/modules/libjar/nsWildCard.cpp b/modules/libjar/nsWildCard.cpp index ca73d556..206871b9 100644 --- a/modules/libjar/nsWildCard.cpp +++ b/modules/libjar/nsWildCard.cpp @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -16,10 +15,13 @@ * * The Initial Developer of the Original Code is * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 + * Portions created by the Initial Developer are Copyright (C) 1998-2009 * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Rob McCool (original author) + * Ken Key + * Nelson Bolyard * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -36,14 +38,13 @@ * ***** END LICENSE BLOCK ***** */ /* * - * * * shexp.c: shell-like wildcard match routines * * See shexp.h for public documentation. * * Rob McCool - * + * */ #include "nsWildCard.h" @@ -52,87 +53,87 @@ /* ----------------------------- shexp_valid ------------------------------ */ - -static int -_valid_subexp(char *expr, char stop) +static int +_valid_subexp(const char *expr, char stop1, char stop2) { - register int x,y,t; - int nsc,np,tld; + register int x; + int nsc = 0; /* Number of special characters */ + int np; /* Number of pipe characters in union */ + int tld = 0; /* Number of tilde characters */ - x=0;nsc=0;tld=0; - - while(expr[x] && (expr[x] != stop)) { + for (x = 0; expr[x] && (expr[x] != stop1) && (expr[x] != stop2); ++x) { switch(expr[x]) { - case '~': - if(tld) return INVALID_SXP; - else ++tld; - case '*': - case '?': - case '^': - case '$': + case '~': + if(tld) /* at most one exclusion */ + return INVALID_SXP; + if (stop1) /* no exclusions within unions */ + return INVALID_SXP; + if (!expr[x+1]) /* exclusion cannot be last character */ + return INVALID_SXP; + if (!x) /* exclusion cannot be first character */ + return INVALID_SXP; + ++tld; + /* fall through */ + case '*': + case '?': + case '$': ++nsc; break; - case '[': + case '[': ++nsc; if((!expr[++x]) || (expr[x] == ']')) return INVALID_SXP; - for(++x;expr[x] && (expr[x] != ']');++x) - if(expr[x] == '\\') - if(!expr[++x]) - return INVALID_SXP; + for(; expr[x] && (expr[x] != ']'); ++x) { + if(expr[x] == '\\' && !expr[++x]) + return INVALID_SXP; + } if(!expr[x]) return INVALID_SXP; break; - case '(': - ++nsc;np = 0; - while(1) { - if(expr[++x] == ')') - return INVALID_SXP; - for(y=x;(expr[y]) && (expr[y] != '|') && (expr[y] != ')');++y) - if(expr[y] == '\\') - if(!expr[++y]) - return INVALID_SXP; - if(!expr[y]) - return INVALID_SXP; - if(expr[y] == '|') - ++np; - t = _valid_subexp(&expr[x],expr[y]); - if(t == INVALID_SXP) + case '(': + ++nsc; + if (stop1) /* no nested unions */ + return INVALID_SXP; + np = -1; + do { + int t = _valid_subexp(&expr[++x], ')', '|'); + if(t == 0 || t == INVALID_SXP) return INVALID_SXP; x+=t; - if(expr[x] == ')') { - if(!np) - return INVALID_SXP; - break; - } - } + if(!expr[x]) + return INVALID_SXP; + ++np; + } while (expr[x] == '|' ); + if(np < 1) /* must be at least one pipe */ + return INVALID_SXP; break; - case ')': - case ']': + case ')': + case ']': + case '|': return INVALID_SXP; - case '\\': + case '\\': + ++nsc; if(!expr[++x]) return INVALID_SXP; - default: + break; + default: break; } - ++x; } - if((!stop) && (!nsc)) + if((!stop1) && (!nsc)) /* must be at least one special character */ return NON_SXP; - return ((expr[x] == stop) ? x : INVALID_SXP); + return ((expr[x] == stop1 || expr[x] == stop2) ? x : INVALID_SXP); } -int -NS_WildCardValid(char *expr) +int +NS_WildCardValid(const char *expr) { int x; - x = _valid_subexp(expr, '\0'); + x = _valid_subexp(expr, '\0', '\0'); return (x < 0 ? x : VALID_SXP); } - /* ----------------------------- shexp_match ----------------------------- */ @@ -140,152 +141,266 @@ NS_WildCardValid(char *expr) #define NOMATCH 1 #define ABORTED -1 -static int _shexp_match(char *str, char *expr, PRBool case_insensitive); +static int +_shexp_match(const char *str, const char *expr, PRBool case_insensitive, + unsigned int level); -static int -_handle_union(char *str, char *expr, PRBool case_insensitive) +/* Count characters until we reach a NUL character or either of the + * two delimiter characters, stop1 or stop2. If we encounter a bracketed + * expression, look only for NUL or ']' inside it. Do not look for stop1 + * or stop2 inside it. Return ABORTED if bracketed expression is unterminated. + * Handle all escaping. + * Return index in input string of first stop found, or ABORTED if not found. + * If "dest" is non-NULL, copy counted characters to it and NUL terminate. + */ +static int +_scan_and_copy(const char *expr, char stop1, char stop2, char *dest) { - char *e2 = (char *) PR_Malloc(sizeof(char)*strlen(expr)); - register int t,p2,p1 = 1; - int cp; + register int sx; /* source index */ + register char cc; - while(1) { - for(cp=1;expr[cp] != ')';cp++) - if(expr[cp] == '\\') - ++cp; - for(p2 = 0;(expr[p1] != '|') && (p1 != cp);p1++,p2++) { - if(expr[p1] == '\\') - e2[p2++] = expr[p1++]; - e2[p2] = expr[p1]; + for (sx = 0; (cc = expr[sx]) && cc != stop1 && cc != stop2; sx++) { + if (cc == '\\') { + if (!expr[++sx]) + return ABORTED; /* should be impossible */ } - for (t=cp+1; ((e2[p2] = expr[t]) != 0); ++t,++p2) {} - if(_shexp_match(str,e2, case_insensitive) == MATCH) { - PR_Free(e2); - return MATCH; + else if (cc == '[') { + while ((cc = expr[++sx]) && cc != ']') { + if(cc == '\\' && !expr[++sx]) + return ABORTED; + } + if (!cc) + return ABORTED; /* should be impossible */ } - if(p1 == cp) { - PR_Free(e2); - return NOMATCH; - } - else ++p1; } + if (dest && sx) { + /* Copy all but the closing delimiter. */ + memcpy(dest, expr, sx); + dest[sx] = 0; + } + return cc ? sx : ABORTED; /* index of closing delimiter */ } - -static int -_shexp_match(char *str, char *expr, PRBool case_insensitive) +/* On input, expr[0] is the opening parenthesis of a union. + * See if any of the alternatives in the union matches as a pattern. + * The strategy is to take each of the alternatives, in turn, and append + * the rest of the expression (after the closing ')' that marks the end of + * this union) to that alternative, and then see if the resultant expression + * matches the input string. Repeat this until some alternative matches, + * or we have an abort. + */ +static int +_handle_union(const char *str, const char *expr, PRBool case_insensitive, + unsigned int level) { - register int x,y; + register int sx; /* source index */ + int cp; /* source index of closing parenthesis */ + int count; + int ret = NOMATCH; + char *e2; + + /* Find the closing parenthesis that ends this union in the expression */ + cp = _scan_and_copy(expr, ')', '\0', NULL); + if (cp == ABORTED || cp < 4) /* must be at least "(a|b" before ')' */ + return ABORTED; + ++cp; /* now index of char after closing parenthesis */ + e2 = (char *) PR_Malloc(1 + strlen(expr)); + if (!e2) + return ABORTED; + for (sx = 1; ; ++sx) { + /* Here, expr[sx] is one character past the preceeding '(' or '|'. */ + /* Copy everything up to the next delimiter to e2 */ + count = _scan_and_copy(expr + sx, ')', '|', e2); + if (count == ABORTED || !count) { + ret = ABORTED; + break; + } + sx += count; + /* Append everything after closing parenthesis to e2. This is safe. */ + strcpy(e2+count, expr+cp); + ret = _shexp_match(str, e2, case_insensitive, level + 1); + if (ret != NOMATCH || !expr[sx] || expr[sx] == ')') + break; + } + PR_Free(e2); + if (sx < 2) + ret = ABORTED; + return ret; +} + +/* returns 1 if val is in range from start..end, case insensitive. */ +static int +_is_char_in_range(int start, int end, int val) +{ + char map[256]; + memset(map, 0, sizeof map); + while (start <= end) + map[tolower(start++)] = 1; + return map[tolower(val)]; +} + +static int +_shexp_match(const char *str, const char *expr, PRBool case_insensitive, + unsigned int level) +{ + register int x; /* input string index */ + register int y; /* expression index */ int ret,neg; - ret = 0; - for(x=0,y=0;expr[y];++y,++x) { - if((!str[x]) && (expr[y] != '(') && (expr[y] != '$') && (expr[y] != '*')) - ret = ABORTED; - else { - switch(expr[y]) { - case '$': - if( (str[x]) ) - ret = NOMATCH; - else - --x; /* we don't want loop to increment x */ - break; - case '*': - while(expr[++y] == '*'){} - if(!expr[y]) + if (level > 20) /* Don't let the stack get too deep. */ + return ABORTED; + for(x = 0, y = 0; expr[y]; ++y, ++x) { + if((!str[x]) && (expr[y] != '$') && (expr[y] != '*')) { + return NOMATCH; + } + switch(expr[y]) { + case '$': + if(str[x]) + return NOMATCH; + --x; /* we don't want loop to increment x */ + break; + case '*': + while(expr[++y] == '*'){} + if(!expr[y]) + return MATCH; + while(str[x]) { + ret = _shexp_match(&str[x++], &expr[y], case_insensitive, + level + 1); + switch(ret) { + case NOMATCH: + continue; + case ABORTED: + return ABORTED; + default: return MATCH; - while(str[x]) { - switch(_shexp_match(&str[x++],&expr[y], case_insensitive)) { - case NOMATCH: - continue; - case ABORTED: - ret = ABORTED; - break; - default: - return MATCH; - } - break; } - if((expr[y] == '$') && (expr[y+1] == '\0') && (!str[x])) - return MATCH; - else - ret = ABORTED; - break; - case '[': - neg = ((expr[++y] == '^') && (expr[y+1] != ']')); - if (neg) - ++y; - - if ((isalnum(expr[y])) && (expr[y+1] == '-') && - (isalnum(expr[y+2])) && (expr[y+3] == ']')) - { - int start = expr[y], end = expr[y+2]; - - /* Droolproofing for pinheads not included */ - if(neg ^ ((str[x] < start) || (str[x] > end))) { - ret = NOMATCH; - break; - } - y+=3; - } - else { - int matched; - - for (matched=0;expr[y] != ']';y++) - matched |= (str[x] == expr[y]); - if (neg ^ (!matched)) - ret = NOMATCH; - } - break; - case '(': - return _handle_union(&str[x],&expr[y], case_insensitive); - break; - case '?': - break; - case '\\': + } + if((expr[y] == '$') && (expr[y+1] == '\0') && (!str[x])) + return MATCH; + else + return NOMATCH; + case '[': { + int start, end = 0, i; + neg = ((expr[++y] == '^') && (expr[y+1] != ']')); + if (neg) ++y; - default: - if(case_insensitive) - { - if(toupper(str[x]) != toupper(expr[y])) - ret = NOMATCH; - } - else - { - if(str[x] != expr[y]) - ret = NOMATCH; - } - break; + i = y; + start = (unsigned char)(expr[i++]); + if (start == '\\') + start = (unsigned char)(expr[i++]); + if (isalnum(start) && expr[i++] == '-') { + end = (unsigned char)(expr[i++]); + if (end == '\\') + end = (unsigned char)(expr[i++]); + } + if (isalnum(end) && expr[i] == ']') { + /* This is a range form: a-b */ + int val = (unsigned char)(str[x]); + if (end < start) { /* swap them */ + start ^= end; + end ^= start; + start ^= end; + } + if (case_insensitive && isalpha(val)) { + val = _is_char_in_range(start, end, val); + if (neg == val) + return NOMATCH; + } + else if (neg != ((val < start) || (val > end))) { + return NOMATCH; + } + y = i; + } + else { + /* Not range form */ + int matched = 0; + for (; expr[y] != ']'; y++) { + if (expr[y] == '\\') + ++y; + if(case_insensitive) { + matched |= (toupper(str[x]) == toupper(expr[y])); + } + else { + matched |= (str[x] == expr[y]); + } + } + if (neg == matched) + return NOMATCH; } } - if(ret) + break; + case '(': + if (!expr[y+1]) + return ABORTED; + return _handle_union(&str[x], &expr[y], case_insensitive, level); + case '?': break; - } - return (ret ? ret : (str[x] ? NOMATCH : MATCH)); -} - -int -NS_WildCardMatch(char *str, char *xp, PRBool case_insensitive) { - register int x; - char *expr = PL_strdup(xp); - - if(!expr) - return 1; - - for(x=strlen(expr)-1;x;--x) { - if((expr[x] == '~') && (expr[x-1] != '\\')) { - expr[x] = '\0'; - if(_shexp_match(str,&expr[++x], case_insensitive) == MATCH) - goto punt; + case ')': + case ']': + case '|': + return ABORTED; + case '\\': + ++y; + /* fall through */ + default: + if(case_insensitive) { + if(toupper(str[x]) != toupper(expr[y])) + return NOMATCH; + } + else { + if(str[x] != expr[y]) + return NOMATCH; + } break; } } - if(_shexp_match(str,expr, case_insensitive) == MATCH) { - PR_Free(expr); - return 0; - } - - punt: - PR_Free(expr); - return 1; + return (str[x] ? NOMATCH : MATCH); } + +static int +ns_WildCardMatch(const char *str, const char *xp, PRBool case_insensitive) +{ + char *expr = 0; + int x, ret = MATCH; + + if (!strchr(xp, '~')) + return _shexp_match(str, xp, case_insensitive, 0); + + expr = PL_strdup(xp); + if(!expr) + return NOMATCH; + + x = _scan_and_copy(expr, '~', '\0', NULL); + if (x != ABORTED && expr[x] == '~') { + expr[x++] = '\0'; + ret = _shexp_match(str, &expr[x], case_insensitive, 0); + switch (ret) { + case NOMATCH: ret = MATCH; break; + case MATCH: ret = NOMATCH; break; + default: break; + } + } + if (ret == MATCH) + ret = _shexp_match(str, expr, case_insensitive, 0); + + PR_Free(expr); + return ret; +} + + +int +NS_WildCardMatch(const char *str, const char *expr, PRBool case_insensitive) +{ + int is_valid = NS_WildCardValid(expr); + switch(is_valid) { + case INVALID_SXP: + return -1; + case NON_SXP: + if (case_insensitive) + return (PL_strcasecmp(expr,str) ? NOMATCH : MATCH); + return (strcmp(expr,str) ? NOMATCH : MATCH); + default: + return ns_WildCardMatch(str, expr, case_insensitive); + } +} + diff --git a/modules/libjar/nsWildCard.h b/modules/libjar/nsWildCard.h index 9cefdd8c..ddbbcd75 100644 --- a/modules/libjar/nsWildCard.h +++ b/modules/libjar/nsWildCard.h @@ -16,10 +16,11 @@ * * The Initial Developer of the Original Code is * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 + * Portions created by the Initial Developer are Copyright (C) 1998-2009 * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Nelson Bolyard * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -83,7 +84,7 @@ #define INVALID_SXP -2 #define VALID_SXP 1 -extern int NS_WildCardValid(char *expr); +extern int NS_WildCardValid(const char *expr); /* return values for the search routines */ @@ -99,7 +100,8 @@ extern int NS_WildCardValid(char *expr); * Returns 0 on match and 1 on non-match. */ -extern int NS_WildCardMatch(char *str, char *expr, PRBool case_insensitive); +extern int +NS_WildCardMatch(const char *str, const char *expr, PRBool case_insensitive); /* * Same as above, but validates the exp first. 0 on match, 1 on non-match, diff --git a/modules/libpr0n/decoders/png/nsPNGDecoder.cpp b/modules/libpr0n/decoders/png/nsPNGDecoder.cpp index 22947c1c..77ff496c 100644 --- a/modules/libpr0n/decoders/png/nsPNGDecoder.cpp +++ b/modules/libpr0n/decoders/png/nsPNGDecoder.cpp @@ -406,6 +406,11 @@ row_callback(png_structp png_ptr, png_bytep new_row, */ nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr)); + PRInt32 height; + decoder->mFrame->GetHeight(&height); + if (row_num >= height) + return; + PRUint32 bpr, abpr; decoder->mFrame->GetImageBytesPerRow(&bpr); decoder->mFrame->GetAlphaBytesPerRow(&abpr); diff --git a/modules/libpr0n/src/imgRequest.cpp b/modules/libpr0n/src/imgRequest.cpp index d0c95c8e..85429730 100644 --- a/modules/libpr0n/src/imgRequest.cpp +++ b/modules/libpr0n/src/imgRequest.cpp @@ -146,8 +146,11 @@ nsresult imgRequest::AddProxy(imgRequestProxy *proxy, PRBool aNotify) nsresult imgRequest::RemoveProxy(imgRequestProxy *proxy, nsresult aStatus, PRBool aNotify) { LOG_SCOPE_WITH_PARAM(gImgLog, "imgRequest::RemoveProxy", "proxy", proxy); - - mObservers.RemoveElement(NS_STATIC_CAST(void*, proxy)); + + if (!mObservers.RemoveElement(NS_STATIC_CAST(void*, proxy))) { + // Not one of our proxies; we're done + return NS_OK; + } /* Check mState below before we potentially call Cancel() below. Since Cancel() may result in OnStopRequest being called back before Cancel() diff --git a/modules/libpr0n/src/imgRequestProxy.cpp b/modules/libpr0n/src/imgRequestProxy.cpp index 32a4e144..34790945 100644 --- a/modules/libpr0n/src/imgRequestProxy.cpp +++ b/modules/libpr0n/src/imgRequestProxy.cpp @@ -218,7 +218,16 @@ NS_IMETHODIMP imgRequestProxy::GetStatus(nsresult *aStatus) /* void cancel (in nsresult status); */ NS_IMETHODIMP imgRequestProxy::Cancel(nsresult status) { - if (mCanceled || !mOwner) + if (!mOwner) + return NS_ERROR_FAILURE; + + // If mCanceled is true but mListener is non-null, that means + // someone called Cancel() on us but the imgCancelRunnable is still + // pending. We still need to null out mListener before returning + // from this function in this case. That means we want to do the + // RemoveProxy call right now, because we need to deliver the + // onStopRequest. + if (mCanceled && !mListener) return NS_ERROR_FAILURE; LOG_SCOPE(gImgLog, "imgRequestProxy::Cancel"); diff --git a/modules/oji/src/ProxyJNI.cpp b/modules/oji/src/ProxyJNI.cpp index 49a75e35..3da564aa 100644 --- a/modules/oji/src/ProxyJNI.cpp +++ b/modules/oji/src/ProxyJNI.cpp @@ -47,6 +47,7 @@ #include "nsVoidArray.h" #include "plstr.h" #include "ProxyClassLoader.h" +#include "nsCSecurityContext.h" #include "ProxyJNI.h" #include "nsDataHashtable.h" @@ -282,6 +283,7 @@ private: nsISecureEnv* mSecureEnv; nsISecurityContext* mContext; jbool mInProxyFindClass; + nsXPIDLCString mFakeOrigin; static ProxyJNIEnv& GetProxyEnv(JNIEnv* env) { return *(ProxyJNIEnv*)env; } @@ -294,6 +296,27 @@ private: } } + // Don't generate a new fake origin on every call to + // nsCSecurityContext::GetOrigin(). + nsresult getOrSetFakeOrigin(nsCSecurityContext *securityContext) + { + if (!securityContext) + return NS_OK; + if (!mFakeOrigin.IsVoid()) + securityContext->SetFakeOrigin(mFakeOrigin); + char origin[256]; + nsresult rv = securityContext->GetOrigin(origin, 256); + if (NS_FAILED(rv)) + return rv; + if (mFakeOrigin.IsVoid()) { + const nsCString& contextFakeOrigin = + securityContext->GetFakeOrigin(); + if (!contextFakeOrigin.IsVoid()) + mFakeOrigin.Assign(contextFakeOrigin); + } + return NS_OK; + } + static jint JNICALL GetVersion(JNIEnv* env) { jint version = 0; @@ -500,10 +523,10 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult result; - result = secureEnv->NewObject(clazz, method->mMethodID, jargs, &outObject, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + secureEnv->NewObject(clazz, method->mMethodID, jargs, &outObject, securityContext); NS_IF_RELEASE(securityContext); - return outObject; } @@ -514,8 +537,9 @@ private: nsISecureEnv* secureEnv = GetSecureEnv(env); JNIMethod* method = (JNIMethod*)methodID; nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult result; - result = secureEnv->NewObject(clazz, method->mMethodID, args, &outObject, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + secureEnv->NewObject(clazz, method->mMethodID, args, &outObject, securityContext); NS_IF_RELEASE(securityContext); return outObject; } @@ -569,7 +593,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult rv = secureEnv->CallMethod(method->mReturnType, obj, method->mMethodID, args, &outValue, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + rv = secureEnv->CallMethod(method->mReturnType, obj, method->mMethodID, args, &outValue, securityContext); NS_IF_RELEASE(securityContext); return NS_SUCCEEDED(rv) ? outValue : kErrorValue; } @@ -587,8 +613,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult result; - result = secureEnv->CallMethod(jvoid_type, obj, method->mMethodID, args, &unusedValue, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + secureEnv->CallMethod(jvoid_type, obj, method->mMethodID, args, &unusedValue, securityContext); NS_IF_RELEASE(securityContext); } @@ -676,7 +703,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult rv = secureEnv->CallNonvirtualMethod(method->mReturnType, obj, clazz, method->mMethodID, args, &outValue, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + rv = secureEnv->CallNonvirtualMethod(method->mReturnType, obj, clazz, method->mMethodID, args, &outValue, securityContext); NS_IF_RELEASE(securityContext); return NS_SUCCEEDED(rv) ? outValue : kErrorValue; } @@ -694,8 +723,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult result; - result = secureEnv->CallNonvirtualMethod(jvoid_type, obj, clazz, method->mMethodID, args, &unusedValue, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + secureEnv->CallNonvirtualMethod(jvoid_type, obj, clazz, method->mMethodID, args, &unusedValue, securityContext); NS_IF_RELEASE(securityContext); } @@ -781,7 +811,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult rv = secureEnv->GetField(field->mFieldType, obj, field->mFieldID, &outValue, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + rv = secureEnv->GetField(field->mFieldType, obj, field->mFieldID, &outValue, securityContext); NS_IF_RELEASE(securityContext); return NS_SUCCEEDED(rv) ? outValue : kErrorValue; } @@ -809,8 +841,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult result; - result = secureEnv->SetField(field->mFieldType, obj, field->mFieldID, value, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + secureEnv->SetField(field->mFieldType, obj, field->mFieldID, value, securityContext); NS_IF_RELEASE(securityContext); } @@ -865,7 +898,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult rv = secureEnv->CallStaticMethod(method->mReturnType, clazz, method->mMethodID, args, &outValue, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + rv = secureEnv->CallStaticMethod(method->mReturnType, clazz, method->mMethodID, args, &outValue, securityContext); NS_IF_RELEASE(securityContext); return NS_SUCCEEDED(rv) ? outValue : kErrorValue; } @@ -883,8 +918,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult result; - result = secureEnv->CallStaticMethod(jvoid_type, clazz, method->mMethodID, args, &unusedValue, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + secureEnv->CallStaticMethod(jvoid_type, clazz, method->mMethodID, args, &unusedValue, securityContext); NS_IF_RELEASE(securityContext); } @@ -970,7 +1006,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult rv = secureEnv->GetStaticField(field->mFieldType, clazz, field->mFieldID, &outValue, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + rv = secureEnv->GetStaticField(field->mFieldType, clazz, field->mFieldID, &outValue, securityContext); NS_IF_RELEASE(securityContext); return NS_SUCCEEDED(rv) ? outValue : kErrorValue; } @@ -998,8 +1036,9 @@ private: ProxyJNIEnv& proxyEnv = GetProxyEnv(env); nsISecureEnv* secureEnv = GetSecureEnv(env); nsISecurityContext* securityContext = proxyEnv.getContext(); - nsresult result; - result = secureEnv->SetStaticField(field->mFieldType, clazz, field->mFieldID, value, securityContext); + nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext); + if (NS_SUCCEEDED(rv)) + secureEnv->SetStaticField(field->mFieldType, clazz, field->mFieldID, value, securityContext); NS_IF_RELEASE(securityContext); } @@ -1735,9 +1774,8 @@ ProxyJNIEnv::ProxyJNIEnv(nsIJVMPlugin* jvmPlugin, nsISecureEnv* secureEnv) ProxyJNIEnv::~ProxyJNIEnv() { this->functions = NULL; - - if (mSecureEnv != NULL) - mSecureEnv->Release(); + + NS_IF_RELEASE(mSecureEnv); } JNIEnv* CreateProxyJNI(nsIJVMPlugin* jvmPlugin, nsISecureEnv* inSecureEnv) diff --git a/modules/oji/src/nsCSecurityContext.cpp b/modules/oji/src/nsCSecurityContext.cpp index 3856f1f9..2827335c 100644 --- a/modules/oji/src/nsCSecurityContext.cpp +++ b/modules/oji/src/nsCSecurityContext.cpp @@ -57,6 +57,7 @@ #include "nsIScriptSecurityManager.h" #include "nsIServiceManager.h" #include "nsCRT.h" +#include "nsNetUtil.h" #include "nsTraceRefcnt.h" @@ -103,38 +104,70 @@ nsCSecurityContext::Implies(const char* target, const char* action, PRBool *bAll return NS_OK; } - -NS_METHOD -nsCSecurityContext::GetOrigin(char* buf, int buflen) +nsresult +nsCSecurityContext::GetOriginImpl(nsXPIDLCString& origin) { + nsresult rv = NS_OK; + if (!m_pPrincipal) { // Get the Script Security Manager. - nsresult rv = NS_OK; nsCOMPtr secMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); - if (NS_FAILED(rv) || !secMan) { + if (NS_FAILED(rv) || !secMan) return NS_ERROR_FAILURE; - } secMan->GetSubjectPrincipal(getter_AddRefs(m_pPrincipal)); - if (!m_pPrincipal) { + if (!m_pPrincipal) return NS_ERROR_FAILURE; - } } - nsXPIDLCString origin; m_pPrincipal->GetOrigin(getter_Copies(origin)); + if (origin.IsEmpty()) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +// This method is called from the OJI plugin without checking its return +// value (from getAndPackSecurityInfo() in remotejni.cpp). So we need to +// set the origin appropriately except in the very worst of circumstances, +// and only then do an error return. +NS_METHOD +nsCSecurityContext::GetOrigin(char* buf, int buflen) +{ + nsXPIDLCString origin; + PRBool javaCompatible = PR_FALSE; + + if (NS_SUCCEEDED(GetOriginImpl(origin))) { + if (NS_FAILED(NS_CheckIsJavaCompatibleURLString(origin, &javaCompatible))) + javaCompatible = PR_FALSE; + } else { + javaCompatible = PR_FALSE; + } PRInt32 originlen = origin.Length(); - if (origin.IsEmpty() || originlen > buflen - 1) { - return NS_ERROR_FAILURE; + + // Don't pass back a value that Java won't be able to understand or + // won't handle correctly. Instead pass back something that Java will + // understand but won't be able to use to access the network, and for + // which same-origin checks will always fail. + if (!javaCompatible) { + if (mFakeOrigin.IsVoid()) { + if (NS_FAILED(NS_MakeRandomInvalidURLString(mFakeOrigin))) + return NS_ERROR_FAILURE; + } + origin.Assign(mFakeOrigin); + originlen = origin.Length(); } + if (originlen > buflen - 1) + return NS_ERROR_FAILURE; + // Copy the string into to user supplied buffer. Is there a better // way to do this? memcpy(buf, origin, originlen); - buf[originlen] = nsnull; // Gotta terminate it. + buf[originlen] = '\0'; // Gotta terminate it. return NS_OK; } diff --git a/modules/oji/src/nsCSecurityContext.h b/modules/oji/src/nsCSecurityContext.h index 99c13b58..abb0312d 100644 --- a/modules/oji/src/nsCSecurityContext.h +++ b/modules/oji/src/nsCSecurityContext.h @@ -50,6 +50,7 @@ #include "nsISecurityContext.h" #include "nsIPrincipal.h" #include "nsCOMPtr.h" +#include "nsString.h" struct JSContext; @@ -105,13 +106,22 @@ public: nsCSecurityContext(nsIPrincipal* principal); virtual ~nsCSecurityContext(void); + //////////////////////////////////////////////////////////////////////////// + // Miscellaneous + + const nsCString& GetFakeOrigin() const { return mFakeOrigin; } + void SetFakeOrigin(nsCString& fakeOrigin) { mFakeOrigin.Assign(fakeOrigin); } + protected: JSStackFrame *m_pJStoJavaFrame; JSContext *m_pJSCX; private: + nsresult GetOriginImpl(nsXPIDLCString& origin); + nsCOMPtr m_pPrincipal; PRBool m_HasUniversalJavaCapability; PRBool m_HasUniversalBrowserReadCapability; + nsXPIDLCString mFakeOrigin; }; #endif // nsCSecurityContext_h___ diff --git a/modules/plugin/base/src/ns4xPlugin.cpp b/modules/plugin/base/src/ns4xPlugin.cpp index 9d427da1..a70630ec 100644 --- a/modules/plugin/base/src/ns4xPlugin.cpp +++ b/modules/plugin/base/src/ns4xPlugin.cpp @@ -66,6 +66,10 @@ #include "jscntxt.h" #include "nsIXPConnect.h" +#include "nsXPIDLString.h" +#include "nsString.h" + +#include "nsNetUtil.h" #if defined(XP_MACOSX) #include @@ -1837,8 +1841,88 @@ _getproperty(NPP npp, NPObject* npobj, NPIdentifier property, NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_GetProperty(npp %p, npobj %p, property %p) called\n", npp, npobj, property)); + + if (!npobj->_class->getProperty(npobj, property, result)) + return false; - return npobj->_class->getProperty(npobj, property, result); + // If a Java plugin tries to get the document.URL or document.documentURI + // property from us, don't pass back a value that Java won't be able to + // understand -- one that will make the URL(String) constructor throw a + // MalformedURL exception. Passing such a value causes Java Plugin2 to + // crash (to throw a RuntimeException in Plugin2Manager.getDocumentBase()). + // Also don't pass back a value that Java is likely to mishandle. + + ns4xPluginInstance* inst = (ns4xPluginInstance*) npp->ndata; + if (!inst) + return false; + if (!inst->mIsJavaPlugin) + return true; + + if (!NPVARIANT_IS_STRING(*result)) + return true; + + NPUTF8* propertyName = _utf8fromidentifier(property); + if (!propertyName) + return true; + bool notURL = + (PL_strcasecmp(propertyName, "URL") && + PL_strcasecmp(propertyName, "documentURI")); + _memfree(propertyName); + if (notURL) + return true; + + NPObject* window_obj = _getwindowobject(npp); + if (!window_obj) + return true; + + NPVariant doc_v; + NPObject* document_obj = nsnull; + NPIdentifier doc_id = _getstringidentifier("document"); + bool ok = npobj->_class->getProperty(window_obj, doc_id, &doc_v); + _releaseobject(window_obj); + if (ok) { + if (NPVARIANT_IS_OBJECT(doc_v)) { + document_obj = NPVARIANT_TO_OBJECT(doc_v); + } else { + _releasevariantvalue(&doc_v); + return true; + } + } else { + return true; + } + _releaseobject(document_obj); + if (document_obj != npobj) + return true; + + NPString urlnp = NPVARIANT_TO_STRING(*result); + nsXPIDLCString url; + url.Assign(urlnp.utf8characters, urlnp.utf8length); + + PRBool javaCompatible = PR_FALSE; + if (NS_FAILED(NS_CheckIsJavaCompatibleURLString(url, &javaCompatible))) + javaCompatible = PR_FALSE; + if (javaCompatible) + return true; + + // If Java won't be able to interpret the original value of document.URL or + // document.documentURI, or is likely to mishandle it, pass back something + // that Java will understand but won't be able to use to access the network, + // and for which same-origin checks will always fail. + + if (inst->mFakeURL.IsVoid()) { + // Abort (do an error return) if NS_MakeRandomInvalidURLString() fails. + if (NS_FAILED(NS_MakeRandomInvalidURLString(inst->mFakeURL))) { + _releasevariantvalue(result); + return false; + } + } + + _releasevariantvalue(result); + char* fakeurl = (char *) _memalloc(inst->mFakeURL.Length() + 1); + strcpy(fakeurl, inst->mFakeURL); + STRINGZ_TO_NPVARIANT(fakeurl, *result); + + return true; } bool NP_EXPORT diff --git a/modules/plugin/base/src/ns4xPluginInstance.cpp b/modules/plugin/base/src/ns4xPluginInstance.cpp index e60e1afb..fdad51f2 100644 --- a/modules/plugin/base/src/ns4xPluginInstance.cpp +++ b/modules/plugin/base/src/ns4xPluginInstance.cpp @@ -835,6 +835,7 @@ ns4xPluginInstance::ns4xPluginInstance(NPPluginFuncs* callbacks, mStarted = PR_FALSE; mStreams = nsnull; mCached = PR_FALSE; + mIsJavaPlugin = PR_FALSE; PLUGIN_LOG(PLUGIN_LOG_BASIC, ("ns4xPluginInstance ctor: this=%p\n",this)); } @@ -1027,6 +1028,17 @@ ns4xPluginInstance::GetDOMWindow() return window; } +PRBool IsJavaMIMEType(const char* aType) +{ + return aType && + ((0 == PL_strncasecmp(aType, "application/x-java-vm", + sizeof("application/x-java-vm") - 1)) || + (0 == PL_strncasecmp(aType, "application/x-java-applet", + sizeof("application/x-java-applet") - 1)) || + (0 == PL_strncasecmp(aType, "application/x-java-bean", + sizeof("application/x-java-bean") - 1))); +} + //////////////////////////////////////////////////////////////////////// nsresult ns4xPluginInstance::InitializePlugin(nsIPluginInstancePeer* peer) { @@ -1184,6 +1196,8 @@ nsresult ns4xPluginInstance::InitializePlugin(nsIPluginInstancePeer* peer) } } + mIsJavaPlugin = IsJavaMIMEType(mimetype); + // Assign mPeer now and mark this instance as started before calling NPP_New // because the plugin may call other NPAPI functions, like NPN_GetURLNotify, // that assume these are set before returning. If the plugin returns failure, diff --git a/modules/plugin/base/src/ns4xPluginInstance.h b/modules/plugin/base/src/ns4xPluginInstance.h index 57fedf75..843ef527 100644 --- a/modules/plugin/base/src/ns4xPluginInstance.h +++ b/modules/plugin/base/src/ns4xPluginInstance.h @@ -56,6 +56,8 @@ #include "nsIPluginTagInfo2.h" #include "nsIScriptablePlugin.h" #include "nsIPluginInstanceInternal.h" +#include "nsXPIDLString.h" +#include "nsString.h" #include "npupp.h" #ifdef OJI @@ -230,10 +232,14 @@ protected: PRPackedBool mCached; public: + PRPackedBool mIsJavaPlugin; + PRLibrary* fLibrary; nsInstanceStream *mStreams; nsVoidArray mPopupStates; + + nsXPIDLCString mFakeURL; }; #endif // ns4xPluginInstance_h__ diff --git a/modules/plugin/base/src/nsJSNPRuntime.cpp b/modules/plugin/base/src/nsJSNPRuntime.cpp index 28a154ea..a35749f0 100644 --- a/modules/plugin/base/src/nsJSNPRuntime.cpp +++ b/modules/plugin/base/src/nsJSNPRuntime.cpp @@ -815,7 +815,8 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JSObject *obj) NPObject *npobj = (NPObject *)::JS_GetPrivate(cx, obj); - return _retainobject(npobj); + if (LookupNPP(npobj) == npp) + return _retainobject(npobj); } if (!sJSObjWrappers.ops) { @@ -1536,14 +1537,10 @@ static NPP LookupNPP(NPObject *npobj) { if (npobj->_class == &nsJSObjWrapper::sJSObjWrapperNPClass) { - NS_ERROR("NPP requested for NPObject of class " - "nsJSObjWrapper::sJSObjWrapperNPClass!\n"); - - return nsnull; + nsJSObjWrapper* o = static_cast(npobj); + return o->mNpp; } - - NPObjWrapperHashEntry *entry = NS_STATIC_CAST(NPObjWrapperHashEntry *, PL_DHashTableOperate(&sNPObjWrappers, npobj, @@ -1750,6 +1747,11 @@ NPObjectMember_Mark(JSContext *cx, JSObject *obj, void *arg) "NPObject Member => fieldValue", arg); } + if (!JSVAL_IS_PRIMITIVE(memberPrivate->methodName)) { + ::JS_MarkGCThing(cx, JSVAL_TO_OBJECT(memberPrivate->methodName), + "NPObject Member => methodName", arg); + } + // There's no strong reference from our private data to the // NPObject, so make sure to mark the NPObject wrapper to keep the // NPObject alive as long as this NPObjectMember is alive. diff --git a/netwerk/base/public/nsChannelProperties.h b/netwerk/base/public/nsChannelProperties.h index 48d344d0..1b62ccea 100644 --- a/netwerk/base/public/nsChannelProperties.h +++ b/netwerk/base/public/nsChannelProperties.h @@ -58,11 +58,21 @@ */ #define NS_CHANNEL_PROP_CONTENT_LENGTH_STR "content-length" +/** + * MIME Content-Disposition header of channel. + * Not available before onStartRequest. + * Type: nsACString + */ +#define NS_CHANNEL_PROP_CONTENT_DISPOSITION_STR "content-disposition" + #ifdef IMPL_NS_NET #define NS_CHANNEL_PROP_CONTENT_LENGTH gNetStrings->kContentLength +#define NS_CHANNEL_PROP_CONTENT_DISPOSITION gNetStrings->kContentDisposition #else #define NS_CHANNEL_PROP_CONTENT_LENGTH \ NS_LITERAL_STRING(NS_CHANNEL_PROP_CONTENT_LENGTH_STR) +#define NS_CHANNEL_PROP_CONTENT_DISPOSITION \ + NS_LITERAL_STRING(NS_CHANNEL_PROP_CONTENT_DISPOSITION_STR) #endif #endif diff --git a/netwerk/base/public/nsNetStrings.h b/netwerk/base/public/nsNetStrings.h index 603457a1..44d63a77 100644 --- a/netwerk/base/public/nsNetStrings.h +++ b/netwerk/base/public/nsNetStrings.h @@ -49,6 +49,7 @@ public: /** "content-length" */ const nsLiteralString kContentLength; + const nsLiteralString kContentDisposition; }; extern NS_HIDDEN_(nsNetStrings*) gNetStrings; diff --git a/netwerk/base/public/nsNetUtil.h b/netwerk/base/public/nsNetUtil.h index a0b82cc7..41752eeb 100644 --- a/netwerk/base/public/nsNetUtil.h +++ b/netwerk/base/public/nsNetUtil.h @@ -41,17 +41,21 @@ #ifndef nsNetUtil_h__ #define nsNetUtil_h__ +#include + #include "nsNetError.h" #include "nsNetCID.h" #include "nsReadableUtils.h" #include "nsString.h" #include "nsMemory.h" #include "nsCOMPtr.h" +#include "nsCRT.h" #include "prio.h" // for read/write flags, permissions, etc. #include "nsIURI.h" #include "nsIInputStream.h" #include "nsIOutputStream.h" +#include "nsIURLParser.h" #include "nsISafeOutputStream.h" #include "nsIStreamListener.h" #include "nsIRequestObserverProxy.h" @@ -63,6 +67,7 @@ #include "nsIIOService.h" #include "nsIServiceManager.h" #include "nsIChannel.h" +#include "nsChannelProperties.h" #include "nsIInputStreamChannel.h" #include "nsITransport.h" #include "nsIStreamTransportService.h" @@ -87,6 +92,8 @@ #include "nsInterfaceRequestorAgg.h" #include "nsInt64.h" #include "nsINetUtil.h" +#include "nsIPropertyBag2.h" +#include "nsAutoLock.h" // Helper, to simplify getting the I/O service. inline const nsGetServiceByCIDWithError @@ -185,6 +192,19 @@ NS_NewChannel(nsIChannel **result, return rv; } +// For now, works only with JARChannel. Future: with all channels that may +// have Content-Disposition header (JAR, nsIHttpChannel, and nsIMultiPartChannel). +inline nsresult +NS_GetContentDisposition(nsIRequest *channel, + nsACString &result) +{ + nsCOMPtr props(do_QueryInterface(channel)); + if (props) + return props->GetPropertyAsACString(NS_CHANNEL_PROP_CONTENT_DISPOSITION, + result); + return NS_ERROR_NOT_AVAILABLE; +} + // Use this function with CAUTION. It creates a stream that blocks when you // Read() from it and blocking the UI thread is a bad idea. If you don't want // to implement a full blown asynchronous consumer (via nsIStreamListener) look @@ -1016,4 +1036,134 @@ NS_NewNotificationCallbacksAggregation(nsIInterfaceRequestor *aCallbacks, return NS_NewInterfaceRequestorAggregation(aCallbacks, cbs, aResult); } +#define NSID_LENGTH 39 + +inline nsresult +GenerateUUIDInPlace(nsID* id) +{ + static PRLock* mLock = NULL; + if(!mLock) { + mLock = PR_NewLock(); + NS_ENSURE_TRUE(mLock, NS_ERROR_OUT_OF_MEMORY); + } + + // The various code in this method is probably not threadsafe, so lock + // across the whole method. + nsAutoLock lock(mLock); + + PRUint8 mRBytes = 4; +#ifdef RAND_MAX + if ((unsigned long) RAND_MAX < (unsigned long)0xffffffff) + mRBytes = 3; + if ((unsigned long) RAND_MAX < (unsigned long)0x00ffffff) + mRBytes = 2; + if ((unsigned long) RAND_MAX < (unsigned long)0x0000ffff) + mRBytes = 1; + if ((unsigned long) RAND_MAX < (unsigned long)0x000000ff) + return NS_ERROR_FAILURE; +#endif + + PRSize bytesLeft = sizeof(nsID); + while (bytesLeft > 0) { + long rval = rand(); + + PRUint8 *src = (PRUint8*)&rval; + // We want to grab the mRBytes least significant bytes of rval, since + // mRBytes less than sizeof(rval) means the high bytes are 0. +#ifdef IS_BIG_ENDIAN + src += sizeof(rval) - mRBytes; +#endif + PRUint8 *dst = ((PRUint8*) id) + (sizeof(nsID) - bytesLeft); + PRSize toWrite = (bytesLeft < mRBytes ? bytesLeft : mRBytes); + for (PRSize i = 0; i < toWrite; i++) + dst[i] = src[i]; + + bytesLeft -= toWrite; + } + + /* Put in the version */ + id->m2 &= 0x0fff; + id->m2 |= 0x4000; + + /* Put in the variant */ + id->m3[0] &= 0x3f; + id->m3[0] |= 0x80; + + return NS_OK; +} + +/** + * Helper function to create a random URL string that's properly formed + * but guaranteed to be invalid. + */ +#define NU_FAKE_SCHEME "http://" +#define NU_FAKE_TLD ".invalid" +inline nsresult +NS_MakeRandomInvalidURLString(nsCString& result) +{ + nsresult rv; + + nsID idee; + rv = GenerateUUIDInPlace(&idee); + NS_ENSURE_SUCCESS(rv, rv); + + char chars[NSID_LENGTH]; + strncpy(chars, idee.ToString(), NSID_LENGTH); + + result.AssignLiteral(NU_FAKE_SCHEME); + // Strip off the '{' and '}' at the beginning and end of the UUID + result.Append(chars + 1, NSID_LENGTH - 3); + result.AppendLiteral(NU_FAKE_TLD); + + return NS_OK; +} +#undef NU_FAKE_SCHEME +#undef NU_FAKE_TLD + +/** + * Helper function to determine whether urlString is Java-compatible -- + * whether it can be passed to the Java URL(String) constructor without the + * latter throwing a MalformedURLException, or without Java otherwise + * mishandling it. + */ +inline nsresult +NS_CheckIsJavaCompatibleURLString(nsCString& urlString, PRBool *result) +{ + *result = PR_FALSE; // Default to "no" + + nsresult rv = NS_OK; + nsCOMPtr urlParser = + do_GetService(NS_STDURLPARSER_CONTRACTID, &rv); + if (NS_FAILED(rv) || !urlParser) + return NS_ERROR_FAILURE; + + PRBool compatible = PR_TRUE; + PRUint32 schemePos = 0; + PRInt32 schemeLen = 0; + urlParser->ParseURL(urlString.get(), -1, &schemePos, &schemeLen, + nsnull, nsnull, nsnull, nsnull); + if (schemeLen != -1) { + nsCString scheme; + scheme.Assign(urlString.get() + schemePos, schemeLen); + // By default Java only understands a small number of URL schemes, and of + // these only some are likely to represent user input (for example from a + // link or the location bar) that Java can legitimately be expected to + // handle. (Besides those listed below, Java also understands the "jar", + // "mailto" and "netdoc" schemes. But it probably doesn't expect these + // from a browser, and is therefore likely to mishandle them.) + if (nsCRT::strcasecmp(scheme.get(), "http") && + nsCRT::strcasecmp(scheme.get(), "https") && + nsCRT::strcasecmp(scheme.get(), "file") && + nsCRT::strcasecmp(scheme.get(), "ftp") && + nsCRT::strcasecmp(scheme.get(), "gopher")) + compatible = PR_FALSE; + } else { + compatible = PR_FALSE; + } + + *result = compatible; + + return NS_OK; +} + #endif // !nsNetUtil_h__ diff --git a/netwerk/base/src/nsNetStrings.cpp b/netwerk/base/src/nsNetStrings.cpp index b8d47d8f..d28e9b96 100644 --- a/netwerk/base/src/nsNetStrings.cpp +++ b/netwerk/base/src/nsNetStrings.cpp @@ -40,7 +40,8 @@ NS_HIDDEN_(nsNetStrings*) gNetStrings; nsNetStrings::nsNetStrings() - : NS_LITERAL_STRING_INIT(kContentLength, NS_CHANNEL_PROP_CONTENT_LENGTH_STR) + : NS_LITERAL_STRING_INIT(kContentLength, NS_CHANNEL_PROP_CONTENT_LENGTH_STR), + NS_LITERAL_STRING_INIT(kContentDisposition, NS_CHANNEL_PROP_CONTENT_DISPOSITION_STR) {} diff --git a/netwerk/base/src/nsURLHelper.cpp b/netwerk/base/src/nsURLHelper.cpp index 087da144..d281974f 100644 --- a/netwerk/base/src/nsURLHelper.cpp +++ b/netwerk/base/src/nsURLHelper.cpp @@ -913,3 +913,94 @@ net_IsValidHostName(const nsCSubstring &host) // @ \ ^ { | } ~ DEL "\x40\x5c\x5e\x7b\x7c\x7d\x7e\x7f") == end; } + +PRBool +net_IsValidIPv4Addr(const char *addr, PRInt32 addrLen) +{ + const char *p; + + PRInt32 octet = -1; // means no digit yet + PRInt32 dotCount = 0; // number of dots in the address + + for (p = addr; addrLen; ++p, --addrLen) { + if (*p == '.') { + dotCount++; + if (octet == -1) { + // invalid octet + return PR_FALSE; + } + octet = -1; + } else if (*p >= '0' && *p <='9') { + if (octet == 0) { + // leading 0 is not allowed + return PR_FALSE; + } else if (octet == -1) { + octet = *p - '0'; + } else { + octet *= 10; + octet += *p - '0'; + if (octet > 255) + return PR_FALSE; + } + } else { + // invalid character + return PR_FALSE; + } + } + + return (dotCount == 3 && octet != -1); +} + +PRBool +net_IsValidIPv6Addr(const char *addr, PRInt32 addrLen) +{ + const char *p; + + PRInt32 digits = 0; // number of digits in current block + PRInt32 colons = 0; // number of colons in a row during parsing + PRInt32 blocks = 0; // number of hexadecimal blocks + PRBool haveZeros = PR_FALSE; // true if double colon is present in the address + + for (p = addr; addrLen; ++p, --addrLen) { + if (*p == ':') { + if (colons == 0) { + if (digits != 0) { + digits = 0; + blocks++; + } + } else if (colons == 1) { + if (haveZeros) + return PR_FALSE; // only one occurrence is allowed + haveZeros = PR_TRUE; + } else { + // too many colons in a row + return PR_FALSE; + } + colons++; + } else if ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || + (*p >= 'A' && *p <= 'F')) { + if (colons == 1 && blocks == 0) // starts with a single colon + return PR_FALSE; + if (digits == 4) // too many digits + return PR_FALSE; + colons = 0; + digits++; + } else if (*p == '.') { + // check valid IPv4 from the beginning of the last block + if (!net_IsValidIPv4Addr(p - digits, addrLen + digits)) + return PR_FALSE; + return (haveZeros && blocks < 6) || (!haveZeros && blocks == 6); + } else { + // invalid character + return PR_FALSE; + } + } + + if (colons == 1) // ends with a single colon + return PR_FALSE; + + if (digits) // there is a block at the end + blocks++; + + return (haveZeros && blocks < 8) || (!haveZeros && blocks == 8); +} diff --git a/netwerk/base/src/nsURLHelper.h b/netwerk/base/src/nsURLHelper.h index f7232fbd..02602b49 100644 --- a/netwerk/base/src/nsURLHelper.h +++ b/netwerk/base/src/nsURLHelper.h @@ -235,4 +235,14 @@ inline char *net_RFindCharNotInSet(const char *str, const char *set) */ NS_HIDDEN_(PRBool) net_IsValidHostName(const nsCSubstring &host); +/** + * Checks whether the IPv4 address is valid according to RFC 3986 section 3.2.2. + */ +NS_HIDDEN_(PRBool) net_IsValidIPv4Addr(const char *addr, PRInt32 addrLen); + +/** + * Checks whether the IPv6 address is valid according to RFC 3986 section 3.2.2. + */ +NS_HIDDEN_(PRBool) net_IsValidIPv6Addr(const char *addr, PRInt32 addrLen); + #endif // !nsURLHelper_h__ diff --git a/netwerk/base/src/nsURLParsers.cpp b/netwerk/base/src/nsURLParsers.cpp index 1203ce86..dac39350 100644 --- a/netwerk/base/src/nsURLParsers.cpp +++ b/netwerk/base/src/nsURLParsers.cpp @@ -631,6 +631,13 @@ nsAuthURLParser::ParseServerInfo(const char *serverinfo, PRInt32 serverinfoLen, if (port) *port = -1; } + + // In case of IPv6 address check its validity + if (*hostnameLen > 1 && *(serverinfo + *hostnamePos) == '[' && + *(serverinfo + *hostnamePos + *hostnameLen - 1) == ']' && + !net_IsValidIPv6Addr(serverinfo + *hostnamePos + 1, *hostnameLen - 2)) + return NS_ERROR_MALFORMED_URI; + return NS_OK; } diff --git a/netwerk/protocol/http/src/nsHttpAtomList.h b/netwerk/protocol/http/src/nsHttpAtomList.h index 77096dae..f11c724d 100644 --- a/netwerk/protocol/http/src/nsHttpAtomList.h +++ b/netwerk/protocol/http/src/nsHttpAtomList.h @@ -62,6 +62,7 @@ HTTP_ATOM(Authorization, "Authorization") HTTP_ATOM(Cache_Control, "Cache-Control") HTTP_ATOM(Connection, "Connection") HTTP_ATOM(Content_Base, "Content-Base") +HTTP_ATOM(Content_Disposition, "Content-Disposition") HTTP_ATOM(Content_Encoding, "Content-Encoding") HTTP_ATOM(Content_Language, "Content-Language") HTTP_ATOM(Content_Length, "Content-Length") diff --git a/netwerk/protocol/http/src/nsHttpChannel.cpp b/netwerk/protocol/http/src/nsHttpChannel.cpp index 36174539..efd8ff65 100644 --- a/netwerk/protocol/http/src/nsHttpChannel.cpp +++ b/netwerk/protocol/http/src/nsHttpChannel.cpp @@ -706,8 +706,12 @@ nsresult nsHttpChannel::CallOnStartRequest() { if (mResponseHead && mResponseHead->ContentType().IsEmpty()) { + NS_ASSERTION(mConnectionInfo, "Should have connection info here"); if (!mContentTypeHint.IsEmpty()) mResponseHead->SetContentType(mContentTypeHint); + else if (mResponseHead->Version() == NS_HTTP_VERSION_0_9 && + mConnectionInfo->Port() != mConnectionInfo->DefaultPort()) + mResponseHead->SetContentType(NS_LITERAL_CSTRING(TEXT_PLAIN)); else { // Uh-oh. We had better find out what type we are! diff --git a/netwerk/socket/base/nsSOCKSIOLayer.cpp b/netwerk/socket/base/nsSOCKSIOLayer.cpp index 7e0f75c2..a714cd61 100644 --- a/netwerk/socket/base/nsSOCKSIOLayer.cpp +++ b/netwerk/socket/base/nsSOCKSIOLayer.cpp @@ -162,21 +162,41 @@ nsSOCKSSocketInfo::SetInternalProxyAddr(PRNetAddr *aInternalProxyAddr) return NS_OK; } +static PRInt32 +pr_RecvAll(PRFileDesc *fd, unsigned char *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + PRInt32 bytesRead = 0; + PRInt32 offset = 0; + + while (offset < amount) { + bytesRead = PR_Recv(fd, buf + offset, amount - offset, flags, timeout); + if (bytesRead > 0) { + offset += bytesRead; + } else if (bytesRead == 0 || offset != 0) { + return offset; + } else { + return bytesRead; + } + } + return offset; +} // Negotiate a SOCKS 5 connection. Assumes the TCP connection to the socks // server port has been established. static nsresult ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRIntervalTime timeout) { + int request_len = 0; + int response_len = 0; + int desired_len = 0; + unsigned char request[22]; + unsigned char response[262]; + NS_ENSURE_TRUE(fd, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(addr, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(extAddr, NS_ERROR_NOT_INITIALIZED); - unsigned char request[22]; - int request_len = 0; - unsigned char response[22]; - int response_len = 0; - request[0] = 0x05; // SOCKS version 5 request[1] = 0x01; // number of auth procotols we recognize // auth protocols @@ -197,11 +217,11 @@ ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRInter return NS_ERROR_FAILURE; } - // get the server's response. Use PR_Recv() instead of - response_len = 2; - response_len = PR_Recv(fd, response, response_len, 0, timeout); + // get the server's response. + desired_len = 2; + response_len = pr_RecvAll(fd, response, desired_len, 0, timeout); - if (response_len <= 0) { + if (response_len < desired_len) { LOGERROR(("PR_Recv() failed. response_len = %d.", response_len)); return NS_ERROR_FAILURE; @@ -357,17 +377,14 @@ ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRInter return NS_ERROR_FAILURE; } - response_len = 22; - response_len = PR_Recv(fd, response, response_len, 0, timeout); - if (response_len <= 0) { - - // bad read + desired_len = 5; + response_len = pr_RecvAll(fd, response, desired_len, 0, timeout); + if (response_len < desired_len) { // bad read LOGERROR(("PR_Recv() failed getting connect command reply. response_len = %d.", response_len)); return NS_ERROR_FAILURE; } if (response[0] != 0x05) { - // bad response LOGERROR(("Not a SOCKS 5 reply. Expected: 5; received: %x", response[0])); return NS_ERROR_FAILURE; @@ -397,6 +414,26 @@ ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRInter } + switch (response[3]) { + case 0x01: // IPv4 + desired_len = 4 + 2 - 1; + break; + case 0x03: // FQDN + desired_len = response[4] + 2; + break; + case 0x04: // IPv6 + desired_len = 16 + 2 - 1; + break; + default: // unknown format + return NS_ERROR_FAILURE; + break; + } + response_len = pr_RecvAll(fd, response + 5, desired_len, 0, timeout); + if (response_len < desired_len) { // bad read + LOGERROR(("PR_Recv() failed getting connect command reply. response_len = %d.", response_len)); + return NS_ERROR_FAILURE; + } + response_len += 5; // get external bound address (this is what // the outside world sees as "us") @@ -434,17 +471,16 @@ ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRInter *ip++ = response[18]; *ip++ = response[19]; break; - case 0x03: // FQDN (should not get this back) - default: // unknown format + case 0x03: // FQDN // if we get here, we don't know our external address. // however, as that's possibly not critical to the user, // we let it slide. - PR_InitializeNetAddr(PR_IpAddrNull, 0, extAddr); - //return NS_ERROR_FAILURE; + extPort = (response[response_len - 2] << 8) | + response[response_len - 1]; + PR_InitializeNetAddr(PR_IpAddrNull, extPort, extAddr); break; } return NS_OK; - } // Negotiate a SOCKS 4 connection. Assumes the TCP connection to the socks @@ -452,15 +488,16 @@ ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRInter static nsresult ConnectSOCKS4(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) { - NS_ENSURE_TRUE(fd, NS_ERROR_NOT_INITIALIZED); - NS_ENSURE_TRUE(addr, NS_ERROR_NOT_INITIALIZED); - - unsigned char request[12]; int request_len = 0; int write_len; - unsigned char response[10]; int response_len = 0; + int desired_len = 0; char *ip = nsnull; + unsigned char request[12]; + unsigned char response[10]; + + NS_ENSURE_TRUE(fd, NS_ERROR_NOT_INITIALIZED); + NS_ENSURE_TRUE(addr, NS_ERROR_NOT_INITIALIZED); request[0] = 0x04; // SOCKS version 4 request[1] = 0x01; // CD command code -- 1 for connect @@ -564,10 +601,9 @@ ConnectSOCKS4(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) } // get the server's response - response_len = 8; // size of the response - response_len = PR_Recv(fd, response, response_len, 0, timeout); - - if (response_len <= 0) { + desired_len = 8; // size of the response + response_len = pr_RecvAll(fd, response, desired_len, 0, timeout); + if (response_len < desired_len) { LOGERROR(("PR_Recv() failed. response_len = %d.", response_len)); return NS_ERROR_FAILURE; } diff --git a/netwerk/streamconv/converters/ParseFTPList.cpp b/netwerk/streamconv/converters/ParseFTPList.cpp index 9a14b924..4ee5646d 100644 --- a/netwerk/streamconv/converters/ParseFTPList.cpp +++ b/netwerk/streamconv/converters/ParseFTPList.cpp @@ -39,10 +39,17 @@ #include #include #include +#include "nsDebug.h" #include "ParseFTPList.h" /* ==================================================================== */ +static inline int ParsingFailed(struct list_state *state) +{ + if (state->parsed_one || state->lstyle) /* junk if we fail to parse */ + return '?'; /* this time but had previously parsed successfully */ + return '"'; /* its part of a comment or error message */ +} int ParseFTPList(const char *line, struct list_state *state, struct list_result *result ) @@ -122,6 +129,9 @@ int ParseFTPList(const char *line, struct list_state *state, } } + if (!numtoks) + return ParsingFailed(state); + linelen_sans_wsp = &(tokens[numtoks-1][toklen[numtoks-1]]) - tokens[0]; if (numtoks == (sizeof(tokens)/sizeof(tokens[0])) ) { @@ -355,11 +365,16 @@ int ParseFTPList(const char *line, struct list_state *state, pos++; p++; } - if (lstyle && pos < (toklen[0]-1) && *p == ']') + if (lstyle && pos < (toklen[0]-1)) { + /* ']' was found and there is at least one character after it */ + NS_ASSERTION(*p == ']', "unexpected state"); pos++; p++; tokmarker = pos; /* length of leading "[DIR1.DIR2.etc]" */ + } else { + /* not a CMU style listing */ + lstyle = 0; } } while (lstyle && pos < toklen[0] && *p != ';') @@ -386,7 +401,7 @@ int ParseFTPList(const char *line, struct list_state *state, pos -= tokmarker; /* => fnlength sans "[DIR1.DIR2.etc]" */ p = &(tokens[0][tokmarker]); /* offset of basename */ - if (!lstyle || pos > 80) /* VMS filenames can't be longer than that */ + if (!lstyle || pos == 0 || pos > 80) /* VMS filenames can't be longer than that */ { lstyle = 0; } @@ -1632,9 +1647,7 @@ int ParseFTPList(const char *line, struct list_state *state, } /* if (linelen > 0) */ - if (state->parsed_one || state->lstyle) /* junk if we fail to parse */ - return '?'; /* this time but had previously parsed sucessfully */ - return '"'; /* its part of a comment or error message */ + return ParsingFailed(state); } /* ==================================================================== */ @@ -1653,7 +1666,7 @@ static int do_it(FILE *outfile, char *p; int rc; - rc = ParseFTPLIST( line, state, &result ); + rc = ParseFTPList( line, state, &result ); if (!outfile) { diff --git a/netwerk/streamconv/converters/nsDirIndexParser.cpp b/netwerk/streamconv/converters/nsDirIndexParser.cpp index f687fe1e..ae1da935 100644 --- a/netwerk/streamconv/converters/nsDirIndexParser.cpp +++ b/netwerk/streamconv/converters/nsDirIndexParser.cpp @@ -179,8 +179,6 @@ nsDirIndexParser::ParseFormat(const char* aFormatStr) { // Parse a "200" format line, and remember the fields and their // ordering in mFormat. Multiple 200 lines stomp on each other. - delete[] mFormat; - // Lets find out how many elements we have. // easier to do this then realloc const char* pos = aFormatStr; @@ -203,6 +201,7 @@ nsDirIndexParser::ParseFormat(const char* aFormatStr) { } while (*pos); + delete[] mFormat; mFormat = new int[num+1]; // Prevent NULL Deref - Bug 443299 if (mFormat == nsnull) diff --git a/netwerk/streamconv/converters/nsIndexedToHTML.cpp b/netwerk/streamconv/converters/nsIndexedToHTML.cpp index b6219cd2..a9fe9ff4 100644 --- a/netwerk/streamconv/converters/nsIndexedToHTML.cpp +++ b/netwerk/streamconv/converters/nsIndexedToHTML.cpp @@ -133,6 +133,30 @@ nsIndexedToHTML::AsyncConvertData(const char *aFromType, NS_IMETHODIMP nsIndexedToHTML::OnStartRequest(nsIRequest* request, nsISupports *aContext) { + nsString buffer; + nsresult rv = DoOnStartRequest(request, aContext, buffer); + if (NS_FAILED(rv)) { + request->Cancel(rv); + } + + // Push buffer to the listener now, so the initial HTML will not + // be parsed in OnDataAvailable(). + + rv = mListener->OnStartRequest(request, aContext); + if (NS_FAILED(rv)) return rv; + + // The request may have been canceled, and if that happens, we want to + // suppress calls to OnDataAvailable. + request->GetStatus(&rv); + if (NS_FAILED(rv)) return rv; + + rv = FormatInputStream(request, aContext, buffer); + return rv; +} + +nsresult +nsIndexedToHTML::DoOnStartRequest(nsIRequest* request, nsISupports *aContext, + nsString& aBuffer) { nsresult rv; nsCOMPtr channel = do_QueryInterface(request); @@ -393,18 +417,7 @@ nsIndexedToHTML::OnStartRequest(nsIRequest* request, nsISupports *aContext) { buffer.AppendLiteral("\n"); } - // Push buffer to the listener now, so the initial HTML will not - // be parsed in OnDataAvailable(). - - rv = mListener->OnStartRequest(request, aContext); - if (NS_FAILED(rv)) return rv; - - // The request may have been canceled, and if that happens, we want to - // suppress calls to OnDataAvailable. - request->GetStatus(&rv); - if (NS_FAILED(rv)) return rv; - - rv = FormatInputStream(request, aContext, buffer); + aBuffer = buffer; return rv; } diff --git a/netwerk/streamconv/converters/nsIndexedToHTML.h b/netwerk/streamconv/converters/nsIndexedToHTML.h index 5829af96..52069b1a 100644 --- a/netwerk/streamconv/converters/nsIndexedToHTML.h +++ b/netwerk/streamconv/converters/nsIndexedToHTML.h @@ -76,7 +76,10 @@ public: protected: void FormatSizeString(PRInt64 inSize, nsString& outSizeString); - nsresult FormatInputStream(nsIRequest* aRequest, nsISupports *aContext, const nsAString &aBuffer); + nsresult FormatInputStream(nsIRequest* aRequest, nsISupports *aContext, const nsAString &aBuffer); + // Helper to properly implement OnStartRequest + nsresult DoOnStartRequest(nsIRequest* request, nsISupports *aContext, + nsString& aBuffer); protected: nsCOMPtr mParser; @@ -97,4 +100,3 @@ private: }; #endif - diff --git a/netwerk/streamconv/converters/nsMultiMixedConv.cpp b/netwerk/streamconv/converters/nsMultiMixedConv.cpp index ccefbcb4..cbf06554 100644 --- a/netwerk/streamconv/converters/nsMultiMixedConv.cpp +++ b/netwerk/streamconv/converters/nsMultiMixedConv.cpp @@ -48,6 +48,7 @@ #include "nsCRT.h" #include "nsIHttpChannelInternal.h" #include "nsURLHelper.h" +#include "nsIStreamConverterService.h" // // Helper function for determining the length of data bytes up to @@ -67,7 +68,10 @@ LengthToToken(const char *cursor, const char *token) return len; } -nsPartChannel::nsPartChannel(nsIChannel *aMultipartChannel, PRUint32 aPartID) : +nsPartChannel::nsPartChannel(nsIChannel *aMultipartChannel, PRUint32 aPartID, + nsIStreamListener* aListener) : + mMultipartChannel(aMultipartChannel), + mListener(aListener), mStatus(NS_OK), mContentLength(LL_MAXUINT), mIsByteRangeRequest(PR_FALSE), @@ -96,6 +100,26 @@ void nsPartChannel::InitializeByteRange(PRInt64 aStart, PRInt64 aEnd) mByteRangeEnd = aEnd; } +nsresult nsPartChannel::SendOnStartRequest(nsISupports* aContext) +{ + return mListener->OnStartRequest(this, aContext); +} + +nsresult nsPartChannel::SendOnDataAvailable(nsISupports* aContext, + nsIInputStream* aStream, + PRUint32 aOffset, PRUint32 aLen) +{ + return mListener->OnDataAvailable(this, aContext, aStream, aOffset, aLen); +} + +nsresult nsPartChannel::SendOnStopRequest(nsISupports* aContext, + nsresult aStatus) +{ + // Drop the listener + nsCOMPtr listener; + listener.swap(mListener); + return listener->OnStopRequest(this, aContext, aStatus); +} // // nsISupports implementation... @@ -734,15 +758,30 @@ nsresult nsMultiMixedConv::SendStart(nsIChannel *aChannel) { nsresult rv = NS_OK; - if (mContentType.IsEmpty()) + nsCOMPtr partListener(mFinalListener); + if (mContentType.IsEmpty()) { mContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE); + nsCOMPtr serv = + do_GetService("@mozilla.org/streamConverters;1", &rv); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr converter; + rv = serv->AsyncConvertData(UNKNOWN_CONTENT_TYPE, + "*/*", + mFinalListener, + mContext, + getter_AddRefs(converter)); + if (NS_SUCCEEDED(rv)) { + partListener = converter; + } + } + } // if we already have an mPartChannel, that means we never sent a Stop() // before starting up another "part." that would be bad. NS_ASSERTION(!mPartChannel, "tisk tisk, shouldn't be overwriting a channel"); nsPartChannel *newChannel; - newChannel = new nsPartChannel(aChannel, mCurrentPartID++); + newChannel = new nsPartChannel(aChannel, mCurrentPartID++, partListener); if (!newChannel) return NS_ERROR_OUT_OF_MEMORY; @@ -780,7 +819,7 @@ nsMultiMixedConv::SendStart(nsIChannel *aChannel) { // Let's start off the load. NOTE: we don't forward on the channel passed // into our OnDataAvailable() as it's the root channel for the raw stream. - return mFinalListener->OnStartRequest(mPartChannel, mContext); + return mPartChannel->SendOnStartRequest(mContext); } @@ -789,7 +828,7 @@ nsMultiMixedConv::SendStop(nsresult aStatus) { nsresult rv = NS_OK; if (mPartChannel) { - rv = mFinalListener->OnStopRequest(mPartChannel, mContext, aStatus); + rv = mPartChannel->SendOnStopRequest(mContext, aStatus); // don't check for failure here, we need to remove the channel from // the loadgroup. @@ -836,7 +875,7 @@ nsMultiMixedConv::SendData(char *aBuffer, PRUint32 aLen) { nsCOMPtr inStream(do_QueryInterface(ss, &rv)); if (NS_FAILED(rv)) return rv; - return mFinalListener->OnDataAvailable(mPartChannel, mContext, inStream, offset, aLen); + return mPartChannel->SendOnDataAvailable(mContext, inStream, offset, aLen); } PRInt32 diff --git a/netwerk/streamconv/converters/nsMultiMixedConv.h b/netwerk/streamconv/converters/nsMultiMixedConv.h index db96aaa1..a3664ccf 100644 --- a/netwerk/streamconv/converters/nsMultiMixedConv.h +++ b/netwerk/streamconv/converters/nsMultiMixedConv.h @@ -68,10 +68,15 @@ class nsPartChannel : public nsIChannel, public nsIMultiPartChannel { public: - nsPartChannel(nsIChannel *aMultipartChannel, PRUint32 aPartID); + nsPartChannel(nsIChannel *aMultipartChannel, PRUint32 aPartID, + nsIStreamListener* aListener); void InitializeByteRange(PRInt64 aStart, PRInt64 aEnd); void SetIsLastPart() { mIsLastPart = PR_TRUE; } + nsresult SendOnStartRequest(nsISupports* aContext); + nsresult SendOnDataAvailable(nsISupports* aContext, nsIInputStream* aStream, + PRUint32 aOffset, PRUint32 aLen); + nsresult SendOnStopRequest(nsISupports* aContext, nsresult aStatus); NS_DECL_ISUPPORTS NS_DECL_NSIREQUEST @@ -84,6 +89,7 @@ protected: protected: nsCOMPtr mMultipartChannel; + nsCOMPtr mListener; nsresult mStatus; nsLoadFlags mLoadFlags; diff --git a/netwerk/streamconv/converters/nsTXTToHTMLConv.cpp b/netwerk/streamconv/converters/nsTXTToHTMLConv.cpp index 4d5c1f94..16412924 100644 --- a/netwerk/streamconv/converters/nsTXTToHTMLConv.cpp +++ b/netwerk/streamconv/converters/nsTXTToHTMLConv.cpp @@ -37,6 +37,7 @@ #include "nsTXTToHTMLConv.h" #include "nsNetUtil.h" +#include "nsEscape.h" #include "nsIStringStream.h" #include "nsAutoPtr.h" @@ -315,11 +316,24 @@ nsTXTToHTMLConv::CatHTML(PRInt32 front, PRInt32 back) nsString linkText; // href is implied mBuffer.Mid(linkText, front, back-front); + mBuffer.Insert(NS_LITERAL_STRING("modText, cursor); - cursor += modLen-front+back; + cursor += modLen; + } + + NS_ConvertUTF16toUTF8 linkTextUTF8(linkText); + nsCString escaped; + if (NS_EscapeURL(linkTextUTF8.Data(), linkTextUTF8.Length(), esc_Minimal, escaped)) { + mBuffer.Cut(cursor, back - front); + CopyUTF8toUTF16(escaped, linkText); + mBuffer.Insert(linkText, cursor); + back = front + linkText.Length(); + } + + cursor += back-front; mBuffer.Insert(NS_LITERAL_STRING("\">"), cursor); cursor += 2; mBuffer.Insert(linkText, cursor); diff --git a/netwerk/streamconv/test/Makefile.in b/netwerk/streamconv/test/Makefile.in index cd287365..68f4f7c1 100644 --- a/netwerk/streamconv/test/Makefile.in +++ b/netwerk/streamconv/test/Makefile.in @@ -73,4 +73,3 @@ DEFINES += -DNGPREFS endif endif # WINNT -DEFINES += -DIMPL_NS_NET diff --git a/netwerk/test/unit/test_bug504014.js b/netwerk/test/unit/test_bug504014.js new file mode 100644 index 00000000..527a02a2 --- /dev/null +++ b/netwerk/test/unit/test_bug504014.js @@ -0,0 +1,73 @@ +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; + +var valid_URIs = [ "http://[::]/", + "http://[::1]/", + "http://[1::]/", + "http://[::]/", + "http://[::1]/", + "http://[1::]/", + "http://[1:2:3:4:5:6:7::]/", + "http://[::1:2:3:4:5:6:7]/", + "http://[1:2:a:B:c:D:e:F]/", + "http://[1::8]/", + "http://[1:2::8]/", + "http://[0000:0123:4567:89AB:CDEF:abcd:ef00:0000]/", + "http://[::192.168.1.1]/", + "http://[1::0.0.0.0]/", + "http://[1:2::255.255.255.255]/", + "http://[1:2:3::255.255.255.255]/", + "http://[1:2:3:4::255.255.255.255]/", + "http://[1:2:3:4:5::255.255.255.255]/", + "http://[1:2:3:4:5:6:255.255.255.255]/"]; + +var invalid_URIs = [ "http://[1]/", + "http://[192.168.1.1]/", + "http://[:::]/", + "http://[:::1]/", + "http://[1:::]/", + "http://[::1::]/", + "http://[1:2:3:4:5:6:7:]/", + "http://[:2:3:4:5:6:7:8]/", + "http://[1:2:3:4:5:6:7:8:]/", + "http://[:1:2:3:4:5:6:7:8]/", + "http://[1:2:3:4:5:6:7:8::]/", + "http://[::1:2:3:4:5:6:7:8]/", + "http://[1:2:3:4:5:6:7]/", + "http://[1:2:3:4:5:6:7:8:9]/", + "http://[00001:2:3:4:5:6:7:8]/", + "http://[0001:2:3:4:5:6:7:89abc]/", + "http://[A:b:C:d:E:f:G:h]/", + "http://[::192.168.1]/", + "http://[::192.168.1.]/", + "http://[::.168.1.1]/", + "http://[::192..1.1]/", + "http://[::0192.168.1.1]/", + "http://[::256.255.255.255]/", + "http://[::1x.255.255.255]/", + "http://[::192.4294967464.1.1]/", + "http://[1:2:3:4:5:6::255.255.255.255]/", + "http://[1:2:3:4:5:6:7:255.255.255.255]/"]; + +function run_test() { + var ios = Cc["@mozilla.org/network/io-service;1"]. + getService(Ci.nsIIOService); + + for (var i=0 ; i", type: "text/xml" } + ]; + +function responseHandler(request, buffer) +{ + do_check_eq(buffer, testData[testNum].data); + do_check_eq(request.QueryInterface(Ci.nsIChannel).contentType, + testData[testNum].type); + if (++testNum == numTests) + httpserver.stop(do_test_finished); +} + +var multipartListener = { + _buffer: "", + + QueryInterface: function(iid) { + if (iid.equals(Components.interfaces.nsIStreamListener) || + iid.equals(Components.interfaces.nsIRequestObserver) || + iid.equals(Components.interfaces.nsISupports)) + return this; + throw Components.results.NS_ERROR_NO_INTERFACE; + }, + + onStartRequest: function(request, context) { + this._buffer = ""; + }, + + onDataAvailable: function(request, context, stream, offset, count) { + try { + this._buffer = this._buffer.concat(read_stream(stream, count)); + dump("BUFFEEE: " + this._buffer + "\n\n"); + } catch (ex) { + do_throw("Error in onDataAvailable: " + ex); + } + }, + + onStopRequest: function(request, context, status) { + try { + responseHandler(request, this._buffer); + } catch (ex) { + do_throw("Error in closure function: " + ex); + } + } +}; + +function run_test() +{ + httpserver = new nsHttpServer(); + httpserver.registerPathHandler("/multipart", contentHandler); + httpserver.start(4444); + + var streamConv = Cc["@mozilla.org/streamConverters;1"] + .getService(Ci.nsIStreamConverterService); + var conv = streamConv.asyncConvertData("multipart/mixed", + "*/*", + multipartListener, + null); + + var chan = make_channel(uri); + chan.asyncOpen(conv, null); + do_test_pending(); +} diff --git a/security/manager/boot/src/nsSecureBrowserUIImpl.cpp b/security/manager/boot/src/nsSecureBrowserUIImpl.cpp index 3fe7bf0f..43eb429f 100644 --- a/security/manager/boot/src/nsSecureBrowserUIImpl.cpp +++ b/security/manager/boot/src/nsSecureBrowserUIImpl.cpp @@ -602,7 +602,15 @@ nsSecureBrowserUIImpl::OnStateChange(nsIWebProgress* aWebProgress, nsCOMPtr windowForProgress; aWebProgress->GetDOMWindow(getter_AddRefs(windowForProgress)); - const PRBool isToplevelProgress = (windowForProgress.get() == mWindow.get()); + PRBool isNoContentResponse = PR_FALSE; + nsCOMPtr httpChannel = do_QueryInterface(aRequest); + if (httpChannel) + { + PRUint32 response; + isNoContentResponse = NS_SUCCEEDED(httpChannel->GetResponseStatus(&response)) && + (response == 204 || response == 205); + } + const PRBool isToplevelProgress = (windowForProgress.get() == mWindow.get()) && !isNoContentResponse; #ifdef PR_LOGGING if (windowForProgress) diff --git a/security/manager/pki/resources/content/device_manager.js b/security/manager/pki/resources/content/device_manager.js index a70e2b2a..4957847e 100644 --- a/security/manager/pki/resources/content/device_manager.js +++ b/security/manager/pki/resources/content/device_manager.js @@ -47,6 +47,8 @@ const nsPK11TokenDB = "@mozilla.org/security/pk11tokendb;1"; const nsIPK11TokenDB = Components.interfaces.nsIPK11TokenDB; const nsIDialogParamBlock = Components.interfaces.nsIDialogParamBlock; const nsDialogParamBlock = "@mozilla.org/embedcomp/dialogparam;1"; +const nsIPKCS11 = Components.interfaces.nsIPKCS11; +const nsPKCS11ContractID = "@mozilla.org/security/pkcs11;1"; var bundle; var secmoddb; @@ -63,6 +65,31 @@ function LoadModules() RefreshDeviceList(); } +function getPKCS11() +{ + return Components.classes[nsPKCS11ContractID].getService(nsIPKCS11); +} + +function getNSSString(name) +{ + return srGetStrBundle("chrome://pipnss/locale/pipnss.properties"). + GetStringFromName(name); +} + +function doPrompt(msg) +{ + prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]. + getService(Components.interfaces.nsIPromptService); + prompts.alert(window, null, msg); +} + +function doConfirm(msg) +{ + prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]. + getService(Components.interfaces.nsIPromptService); + return prompts.confirm(window, null, msg); +} + function RefreshDeviceList() { var modules = secmoddb.listModules(); @@ -383,11 +410,27 @@ function doLoad() RefreshDeviceList(); } -function doUnload() +function deleteSelected() { getSelectedItem(); - if (selected_module) { - pkcs11.deletemodule(selected_module.name); + if (selected_module && + doConfirm(getNSSString("DelModuleWarning"))) { + try { + getPKCS11().deleteModule(selected_module.name); + } + catch (e) { + doPrompt(getNSSString("DelModuleError")); + return false; + } + selected_module = null; + return true; + } + return false; +} + +function doUnload() +{ + if (deleteSelected()) { ClearDeviceList(); RefreshDeviceList(); } @@ -436,7 +479,17 @@ function doLoadDevice() { var name_box = document.getElementById("device_name"); var path_box = document.getElementById("device_path"); - pkcs11.addmodule(name_box.value, path_box.value, 0,0); + try { + getPKCS11().addModule(name_box.value, path_box.value, 0,0); + } + catch (e) { + if (e.result == Components.results.NS_ERROR_ILLEGAL_VALUE) + doPrompt(getNSSString("AddModuleDup")); + else + doPrompt(getNSSString("AddModuleFailure")); + + return false; + } return true; } diff --git a/security/manager/ssl/public/Makefile.in b/security/manager/ssl/public/Makefile.in index 691982b1..6b57dd83 100644 --- a/security/manager/ssl/public/Makefile.in +++ b/security/manager/ssl/public/Makefile.in @@ -65,6 +65,7 @@ XPIDLSRCS = \ nsIX509Cert3.idl \ nsIX509Cert18Branch.idl \ nsIX509CertDB2.idl \ + nsIPKCS11.idl \ nsIPKCS11Slot.idl \ nsIPK11TokenDB.idl \ nsICertPickDialogs.idl \ diff --git a/security/manager/ssl/public/nsIPKCS11.idl b/security/manager/ssl/public/nsIPKCS11.idl new file mode 100644 index 00000000..50b68c1e --- /dev/null +++ b/security/manager/ssl/public/nsIPKCS11.idl @@ -0,0 +1,49 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Johnny Stenback + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +[scriptable, uuid(5743f870-958e-4f02-aef2-c0afeef67f05)] +interface nsIPKCS11 : nsISupports +{ + void deleteModule(in AString moduleName); + void addModule(in AString moduleName, + in AString libraryFullPath, + in long cryptoMechanismFlags, + in long cipherFlags); +}; diff --git a/security/manager/ssl/src/nsCrypto.cpp b/security/manager/ssl/src/nsCrypto.cpp index 8314a86d..6724c74a 100644 --- a/security/manager/ssl/src/nsCrypto.cpp +++ b/security/manager/ssl/src/nsCrypto.cpp @@ -215,9 +215,8 @@ NS_IMPL_RELEASE(nsCRMFObject) // QueryInterface implementation for nsPkcs11 NS_INTERFACE_MAP_BEGIN(nsPkcs11) - NS_INTERFACE_MAP_ENTRY(nsIDOMPkcs11) + NS_INTERFACE_MAP_ENTRY(nsIPKCS11) NS_INTERFACE_MAP_ENTRY(nsISupports) - NS_INTERFACE_MAP_ENTRY_DOM_CLASSINFO(Pkcs11) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsPkcs11) @@ -608,6 +607,9 @@ cryptojs_generateOneKeyPair(JSContext *cx, nsKeyPairInfo *keyPairInfo, void *keyGenParams = nsConvertToActualKeyGenParams(mechanism, params, (params) ? strlen(params):0, keySize); + if (!keyGenParams) { + return NS_ERROR_INVALID_ARG; + } // Make sure the token has password already set on it before trying // to generate the key. @@ -2559,33 +2561,18 @@ confirm_user(const PRUnichar *message) //Delete a PKCS11 module from the user's profile. NS_IMETHODIMP -nsPkcs11::Deletemodule(const nsAString& aModuleName, PRInt32* aReturn) +nsPkcs11::DeleteModule(const nsAString& aModuleName) { nsNSSShutDownPreventionLock locker; nsresult rv; nsString errorMessage; nsCOMPtr nssComponent(do_GetService(kNSSComponentCID, &rv)); + if (NS_FAILED(rv)) + return rv; + if (aModuleName.IsEmpty()) { - *aReturn = JS_ERR_BAD_MODULE_NAME; - nssComponent->GetPIPNSSBundleString("DelModuleBadName", errorMessage); - alertUser(errorMessage.get()); - return NS_OK; - } - nsString final; - nsAutoString temp; - //Make sure the user knows we're trying to do this. - nssComponent->GetPIPNSSBundleString("DelModuleWarning", final); - final.Append(NS_LITERAL_STRING("\n").get()); - PRUnichar *tempUni = ToNewUnicode(aModuleName); - const PRUnichar *formatStrings[1] = { tempUni }; - rv = nssComponent->PIPBundleFormatStringFromName("AddModuleName", - formatStrings, 1, temp); - nsMemory::Free(tempUni); - final.Append(temp); - if (!confirm_user(final.get())) { - *aReturn = JS_ERR_USER_CANCEL_ACTION; - return NS_OK; + return NS_ERROR_ILLEGAL_VALUE; } char *modName = ToNewCString(aModuleName); @@ -2597,69 +2584,25 @@ nsPkcs11::Deletemodule(const nsAString& aModuleName, PRInt32* aReturn) nssComponent->ShutdownSmartCardThread(module); SECMOD_DestroyModule(module); } - if (modType == SECMOD_EXTERNAL) { - nssComponent->GetPIPNSSBundleString("DelModuleExtSuccess", errorMessage); - *aReturn = JS_OK_DEL_EXTERNAL_MOD; - } else { - nssComponent->GetPIPNSSBundleString("DelModuleIntSuccess", errorMessage); - *aReturn = JS_OK_DEL_INTERNAL_MOD; - } + rv = NS_OK; } else { - *aReturn = JS_ERR_DEL_MOD; - nssComponent->GetPIPNSSBundleString("DelModuleError", errorMessage); + rv = NS_ERROR_FAILURE; } - alertUser(errorMessage.get()); - return NS_OK; + NS_Free(modName); + return rv; } //Add a new PKCS11 module to the user's profile. NS_IMETHODIMP -nsPkcs11::Addmodule(const nsAString& aModuleName, +nsPkcs11::AddModule(const nsAString& aModuleName, const nsAString& aLibraryFullPath, PRInt32 aCryptoMechanismFlags, - PRInt32 aCipherFlags, PRInt32* aReturn) + PRInt32 aCipherFlags) { nsNSSShutDownPreventionLock locker; nsresult rv; nsCOMPtr nssComponent(do_GetService(kNSSComponentCID, &rv)); - nsString final; - nsAutoString temp; - rv = nssComponent->GetPIPNSSBundleString("AddModulePrompt", final); - if (NS_FAILED(rv)) - return rv; - - final.Append(NS_LITERAL_STRING("\n").get()); - - PRUnichar *tempUni = ToNewUnicode(aModuleName); - const PRUnichar *formatStrings[1] = { tempUni }; - rv = nssComponent->PIPBundleFormatStringFromName("AddModuleName", - formatStrings, 1, temp); - nsMemory::Free(tempUni); - - if (NS_FAILED(rv)) - return rv; - - final.Append(temp); - final.Append(NS_LITERAL_STRING("\n").get()); - - tempUni = ToNewUnicode(aLibraryFullPath); - formatStrings[0] = tempUni; - rv = nssComponent->PIPBundleFormatStringFromName("AddModulePath", - formatStrings, 1, temp); - nsMemory::Free(tempUni); - if (NS_FAILED(rv)) - return rv; - - final.Append(temp); - final.Append(NS_LITERAL_STRING("\n").get()); - - if (!confirm_user(final.get())) { - // The user has canceled. So let's return now. - *aReturn = JS_ERR_USER_CANCEL_ACTION; - return NS_OK; - } - char *moduleName = ToNewCString(aModuleName); char *fullPath = ToNewCString(aLibraryFullPath); PRUint32 mechFlags = SECMOD_PubMechFlagstoInternal(aCryptoMechanismFlags); @@ -2681,22 +2624,13 @@ nsPkcs11::Addmodule(const nsAString& aModuleName, // what the return value for SEDMOD_AddNewModule is switch (srv) { case SECSuccess: - nssComponent->GetPIPNSSBundleString("AddModuleSuccess", final); - *aReturn = JS_OK_ADD_MOD; - break; + return NS_OK; case SECFailure: - nssComponent->GetPIPNSSBundleString("AddModuleFailure", final); - *aReturn = JS_ERR_ADD_MOD; - break; - case -2: - nssComponent->GetPIPNSSBundleString("AddModuleDup", final); - *aReturn = JS_ERR_ADD_DUPLICATE_MOD; - break; - default: - NS_ASSERTION(0,"Bogus return value, this should never happen"); return NS_ERROR_FAILURE; + case -2: + return NS_ERROR_ILLEGAL_VALUE; } - alertUser(final.get()); - return NS_OK; + NS_ASSERTION(0,"Bogus return value, this should never happen"); + return NS_ERROR_FAILURE; } diff --git a/security/manager/ssl/src/nsCrypto.h b/security/manager/ssl/src/nsCrypto.h index 9520ca10..cd003421 100644 --- a/security/manager/ssl/src/nsCrypto.h +++ b/security/manager/ssl/src/nsCrypto.h @@ -41,7 +41,7 @@ #include "nsCOMPtr.h" #include "nsIDOMCRMFObject.h" #include "nsIDOMCrypto.h" -#include "nsIDOMPkcs11.h" +#include "nsIPKCS11.h" #include "nsIRunnable.h" #include "nsString.h" #include "nsNSSEvent.h" @@ -97,14 +97,14 @@ private: PRBool mEnableSmartCardEvents; }; -class nsPkcs11 : public nsIDOMPkcs11 +class nsPkcs11 : public nsIPKCS11 { public: nsPkcs11(); virtual ~nsPkcs11(); NS_DECL_ISUPPORTS - NS_DECL_NSIDOMPKCS11 + NS_DECL_NSIPKCS11 }; diff --git a/security/manager/ssl/src/nsNSSCallbacks.cpp b/security/manager/ssl/src/nsNSSCallbacks.cpp index 22c4a5eb..6750a9b2 100644 --- a/security/manager/ssl/src/nsNSSCallbacks.cpp +++ b/security/manager/ssl/src/nsNSSCallbacks.cpp @@ -66,6 +66,7 @@ #include "ssl.h" #include "cert.h" #include "ocsp.h" +#include "secerr.h" static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); @@ -875,21 +876,136 @@ void PR_CALLBACK HandshakeCallback(PRFileDesc* fd, void* client_data) { PR_Free(signer); } +struct nsSerialBinaryBlacklistEntry +{ + unsigned int len; + const char *binary_serial; +}; + +// bug 642395 +static struct nsSerialBinaryBlacklistEntry myUTNBlacklistEntries[] = { + { 17, "\x00\x92\x39\xd5\x34\x8f\x40\xd1\x69\x5a\x74\x54\x70\xe1\xf2\x3f\x43" }, + { 17, "\x00\xd8\xf3\x5f\x4e\xb7\x87\x2b\x2d\xab\x06\x92\xe3\x15\x38\x2f\xb0" }, + { 16, "\x72\x03\x21\x05\xc5\x0c\x08\x57\x3d\x8e\xa5\x30\x4e\xfe\xe8\xb0" }, + { 17, "\x00\xb0\xb7\x13\x3e\xd0\x96\xf9\xb5\x6f\xae\x91\xc8\x74\xbd\x3a\xc0" }, + { 16, "\x39\x2a\x43\x4f\x0e\x07\xdf\x1f\x8a\xa3\x05\xde\x34\xe0\xc2\x29" }, + { 16, "\x3e\x75\xce\xd4\x6b\x69\x30\x21\x21\x88\x30\xae\x86\xa8\x2a\x71" }, + { 17, "\x00\xe9\x02\x8b\x95\x78\xe4\x15\xdc\x1a\x71\x0a\x2b\x88\x15\x44\x47" }, + { 17, "\x00\xd7\x55\x8f\xda\xf5\xf1\x10\x5b\xb2\x13\x28\x2b\x70\x77\x29\xa3" }, + { 16, "\x04\x7e\xcb\xe9\xfc\xa5\x5f\x7b\xd0\x9e\xae\x36\xe1\x0c\xae\x1e" }, + { 17, "\x00\xf5\xc8\x6a\xf3\x61\x62\xf1\x3a\x64\xf5\x4f\x6d\xc9\x58\x7c\x06" }, + { 0, 0 } // end marker +}; + +// Bug 682927: Do not trust any DigiNotar-issued certificates. +// We do this check after normal certificate validation because we do not +// want to override a "revoked" OCSP response. +PRErrorCode +PSM_SSL_BlacklistDigiNotar(CERTCertificate * serverCert, + CERTCertList * serverCertChain) +{ + PRBool isDigiNotarIssuedCert = PR_FALSE; + + for (CERTCertListNode *node = CERT_LIST_HEAD(serverCertChain); + !CERT_LIST_END(node, serverCertChain); + node = CERT_LIST_NEXT(node)) { + if (!node->cert->issuerName) + continue; + + if (strstr(node->cert->issuerName, "CN=DigiNotar")) { + isDigiNotarIssuedCert = PR_TRUE; + // Do not let the user override the error if the cert was + // chained from the "DigiNotar Root CA" cert and the cert was issued + // within the time window in which we think the mis-issuance(s) occurred. + if (strstr(node->cert->issuerName, "CN=DigiNotar Root CA")) { + PRTime cutoff = 0, notBefore = 0, notAfter = 0; + PRStatus status = PR_ParseTimeString("01-JUL-2011 00:00", PR_TRUE, &cutoff); + NS_ASSERTION(status == PR_SUCCESS, "PR_ParseTimeString failed"); + if (status != PR_SUCCESS || + CERT_GetCertTimes(serverCert, ¬Before, ¬After) != SECSuccess || + notBefore >= cutoff) { + return SEC_ERROR_REVOKED_CERTIFICATE; + } + } + } + } + + if (isDigiNotarIssuedCert) + return SEC_ERROR_UNTRUSTED_ISSUER; // user can override this + else + return 0; // No DigiNotor cert => carry on as normal +} + SECStatus PR_CALLBACK AuthCertificateCallback(void* client_data, PRFileDesc* fd, PRBool checksig, PRBool isServer) { nsNSSShutDownPreventionLock locker; + CERTCertificate *serverCert = SSL_PeerCertificate(fd); + if (serverCert && + serverCert->serialNumber.data && + serverCert->issuerName && + !strcmp(serverCert->issuerName, + "CN=UTN-USERFirst-Hardware,OU=http://www.usertrust.com,O=The USERTRUST Network,L=Salt Lake City,ST=UT,C=US")) { + + unsigned char *server_cert_comparison_start = (unsigned char*)serverCert->serialNumber.data; + unsigned int server_cert_comparison_len = serverCert->serialNumber.len; + + while (server_cert_comparison_len) { + if (*server_cert_comparison_start != 0) + break; + + ++server_cert_comparison_start; + --server_cert_comparison_len; + } + + nsSerialBinaryBlacklistEntry *walk = myUTNBlacklistEntries; + for ( ; walk && walk->len; ++walk) { + + unsigned char *locked_cert_comparison_start = (unsigned char*)walk->binary_serial; + unsigned int locked_cert_comparison_len = walk->len; + + while (locked_cert_comparison_len) { + if (*locked_cert_comparison_start != 0) + break; + + ++locked_cert_comparison_start; + --locked_cert_comparison_len; + } + + if (server_cert_comparison_len == locked_cert_comparison_len && + !memcmp(server_cert_comparison_start, locked_cert_comparison_start, locked_cert_comparison_len)) { + PR_SetError(SEC_ERROR_REVOKED_CERTIFICATE, 0); + return SECFailure; + } + } + } + // first the default action SECStatus rv = SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer); // We want to remember the CA certs in the temp db, so that the application can find the // complete chain at any time it might need it. // But we keep only those CA certs in the temp db, that we didn't already know. + + CERTCertList *certList = nsnull; + if (rv == SECSuccess) { + certList = CERT_GetCertChainFromCert(serverCert, PR_Now(), certUsageSSLCA); + if (!certList) { + rv = SECFailure; + } else { + PRErrorCode blacklistErrorCode = PSM_SSL_BlacklistDigiNotar(serverCert, + certList); + if (blacklistErrorCode != 0) { + nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret; + infoObject->SetCertIssuerBlacklisted(); + PORT_SetError(blacklistErrorCode); + rv = SECFailure; + } + } + } if (SECSuccess == rv) { - CERTCertificate *serverCert = SSL_PeerCertificate(fd); if (serverCert) { - CERTCertList *certList = CERT_GetCertChainFromCert(serverCert, PR_Now(), certUsageSSLCA); nsCOMPtr nssComponent; @@ -926,7 +1042,9 @@ SECStatus PR_CALLBACK AuthCertificateCallback(void* client_data, PRFileDesc* fd, } } - CERT_DestroyCertList(certList); + if(certList) { + CERT_DestroyCertList(certList); + } CERT_DestroyCertificate(serverCert); } } diff --git a/security/manager/ssl/src/nsNSSCallbacks.h b/security/manager/ssl/src/nsNSSCallbacks.h index 2c98dd2a..9da214a9 100644 --- a/security/manager/ssl/src/nsNSSCallbacks.h +++ b/security/manager/ssl/src/nsNSSCallbacks.h @@ -235,7 +235,7 @@ public: void unregisterHttpClient(); }; +PRErrorCode PSM_SSL_BlacklistDigiNotar(CERTCertificate * serverCert, + CERTCertList * serverCertChain); + #endif // _NSNSSCALLBACKS_H_ - - - diff --git a/security/manager/ssl/src/nsNSSIOLayer.cpp b/security/manager/ssl/src/nsNSSIOLayer.cpp index b5384546..d74165f7 100644 --- a/security/manager/ssl/src/nsNSSIOLayer.cpp +++ b/security/manager/ssl/src/nsNSSIOLayer.cpp @@ -194,7 +194,8 @@ nsNSSSocketInfo::nsNSSSocketInfo() mBadCertUIStatus(bcuis_not_shown), mHandshakeStartTime(0), mPort(0), - mCAChain(nsnull) + mCAChain(nsnull), + mIsCertIssuerBlacklisted(PR_FALSE) { mThreadData = new nsSSLSocketThreadData; } @@ -2658,6 +2659,10 @@ done: static SECStatus nsNSSBadCertHandler(void *arg, PRFileDesc *sslSocket) { + // cert was revoked, don't do anything else + if (PR_GetError() == SEC_ERROR_REVOKED_CERTIFICATE) + return SECFailure; + nsNSSShutDownPreventionLock locker; SECStatus rv = SECFailure; int error; @@ -2665,6 +2670,13 @@ nsNSSBadCertHandler(void *arg, PRFileDesc *sslSocket) CERTCertificate *peerCert; nsNSSCertificate *nssCert; + if (infoObject->IsCertIssuerBlacklisted()) { + error = SEC_ERROR_UNTRUSTED_CERT; + } + else { + error = PR_GetError(); + } + error = PR_GetError(); peerCert = SSL_PeerCertificate(sslSocket); nssCert = new nsNSSCertificate(peerCert); diff --git a/security/manager/ssl/src/nsNSSIOLayer.h b/security/manager/ssl/src/nsNSSIOLayer.h index d6f7dc19..2975f247 100644 --- a/security/manager/ssl/src/nsNSSIOLayer.h +++ b/security/manager/ssl/src/nsNSSIOLayer.h @@ -183,6 +183,12 @@ public: PRStatus CloseSocketAndDestroy(); + PRBool IsCertIssuerBlacklisted() const { + return mIsCertIssuerBlacklisted; + } + void SetCertIssuerBlacklisted() { + mIsCertIssuerBlacklisted = PR_TRUE; + } protected: nsCOMPtr mCallbacks; PRFileDesc* mFd; @@ -203,6 +209,7 @@ protected: PRInt32 mPort; nsXPIDLCString mHostName; CERTCertList *mCAChain; + PRErrorCode mIsCertIssuerBlacklisted; /* SSL Status */ nsCOMPtr mSSLStatus; diff --git a/security/nss/lib/certdb/certdb.c b/security/nss/lib/certdb/certdb.c index 54b6420b..aba2481f 100644 --- a/security/nss/lib/certdb/certdb.c +++ b/security/nss/lib/certdb/certdb.c @@ -1415,6 +1415,15 @@ sec_lower_string(char *s) return; } +static PRBool +cert_IsIPAddr(const char *hn) +{ + PRBool isIPaddr = PR_FALSE; + PRNetAddr netAddr; + isIPaddr = (PR_SUCCESS == PR_StringToNetAddr(hn, &netAddr)); + return isIPaddr; +} + /* ** Add a domain name to the list of names that the user has explicitly ** allowed (despite cert name mismatches) for use with a server cert. @@ -1888,7 +1897,17 @@ CERT_VerifyCertName(CERTCertificate *cert, const char *hn) cn = CERT_GetCommonName(&cert->subject); } if ( cn ) { - rv = cert_TestHostName(cn, hn); + PRBool isIPaddr = cert_IsIPAddr(hn); + if (isIPaddr) { + if (PORT_Strcasecmp(hn, cn) == 0) { + rv = SECSuccess; + } else { + PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN); + rv = SECFailure; + } + } else { + rv = cert_TestHostName(cn, hn); + } PORT_Free(cn); } else PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN); diff --git a/security/nss/lib/cryptohi/seckey.c b/security/nss/lib/cryptohi/seckey.c index 963b985d..2a341307 100644 --- a/security/nss/lib/cryptohi/seckey.c +++ b/security/nss/lib/cryptohi/seckey.c @@ -227,7 +227,17 @@ SECKEYPrivateKey * SECKEY_CreateDHPrivateKey(SECKEYDHParams *param, SECKEYPublicKey **pubk, void *cx) { SECKEYPrivateKey *privk; - PK11SlotInfo *slot = PK11_GetBestSlot(CKM_DH_PKCS_KEY_PAIR_GEN,cx); + PK11SlotInfo *slot; + + if (!param || !param->base.data || !param->prime.data || + param->prime.len < 512/8 || param->base.len == 0 || + param->base.len > param->prime.len + 1 || + (param->base.len == 1 && param->base.data[0] == 0)) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return NULL; + } + + slot = PK11_GetBestSlot(CKM_DH_PKCS_KEY_PAIR_GEN,cx); if (!slot) { return NULL; } @@ -1460,16 +1470,20 @@ SECKEY_PublicKeyStrength(const SECKEYPublicKey *pubk) /* interpret modulus length as key strength... in * fortezza that's the public key length */ - + if (!pubk) + goto loser; switch (pubk->keyType) { case rsaKey: + if (!pubk->u.rsa.modulus.data) break; b0 = pubk->u.rsa.modulus.data[0]; return b0 ? pubk->u.rsa.modulus.len : pubk->u.rsa.modulus.len - 1; case dsaKey: + if (!pubk->u.dsa.publicValue.data) break; b0 = pubk->u.dsa.publicValue.data[0]; return b0 ? pubk->u.dsa.publicValue.len : pubk->u.dsa.publicValue.len - 1; case dhKey: + if (!pubk->u.dh.publicValue.data) break; b0 = pubk->u.dh.publicValue.data[0]; return b0 ? pubk->u.dh.publicValue.len : pubk->u.dh.publicValue.len - 1; @@ -1482,6 +1496,7 @@ SECKEY_PublicKeyStrength(const SECKEYPublicKey *pubk) default: break; } +loser: PORT_SetError(SEC_ERROR_INVALID_KEY); return 0; } diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c index 7f332e9e..76ad8a29 100644 --- a/security/nss/lib/ssl/ssl3con.c +++ b/security/nss/lib/ssl/ssl3con.c @@ -4985,14 +4985,22 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) if (rv != SECSuccess) { goto loser; /* malformed. */ } + if (dh_p.len < 512/8) + goto alert_loser; rv = ssl3_ConsumeHandshakeVariable(ss, &dh_g, 2, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed. */ } + if (dh_g.len == 0 || dh_g.len > dh_p.len + 1 || + (dh_g.len == 1 && dh_g.data[0] == 0)) + goto alert_loser; rv = ssl3_ConsumeHandshakeVariable(ss, &dh_Ys, 2, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed. */ } + if (dh_Ys.len == 0 || dh_Ys.len > dh_p.len + 1 || + (dh_Ys.len == 1 && dh_Ys.data[0] == 0)) + goto alert_loser; rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed. */ diff --git a/toolkit/components/autocomplete/src/nsAutoCompleteController.cpp b/toolkit/components/autocomplete/src/nsAutoCompleteController.cpp index d4127f37..ec7cb244 100644 --- a/toolkit/components/autocomplete/src/nsAutoCompleteController.cpp +++ b/toolkit/components/autocomplete/src/nsAutoCompleteController.cpp @@ -995,6 +995,13 @@ nsAutoCompleteController::StartSearch() ++searchesFailed; --mSearchesOngoing; } + // nsIAutoCompleteSearch::StartSearch might cause us to be detached from + // our input field, so it's not safe to assume that it's safe to iterate + // over the next iteration. + if (!mInput) { + // The search operation has been finished. + return NS_OK; + } } if (searchesFailed == count) { diff --git a/toolkit/components/build/nsToolkitCompsCID.h b/toolkit/components/build/nsToolkitCompsCID.h index 92ffe624..65fb0a1a 100644 --- a/toolkit/components/build/nsToolkitCompsCID.h +++ b/toolkit/components/build/nsToolkitCompsCID.h @@ -80,6 +80,9 @@ #define NS_URLCLASSIFIERSTREAMUPDATER_CONTRACTID \ "@mozilla.org/url-classifier/streamupdater;1" +#define NS_URLCLASSIFIERUTILS_CONTRACTID \ + "@mozilla.org/url-classifier/utils;1" + #define NS_SCRIPTABLEUNESCAPEHTML_CONTRACTID "@mozilla.org/feed-unescapehtml;1" ///////////////////////////////////////////////////////////////////////////// @@ -131,6 +134,10 @@ #define NS_URLCLASSIFIERSTREAMUPDATER_CID \ { 0xc2be6dc0, 0xef1e, 0x4abd, { 0x86, 0xa2, 0x4f, 0x86, 0x4d, 0xdc, 0x57, 0xf6} } +// {b7b2ccec-7912-4ea6-a548-b038447004bd} +#define NS_URLCLASSIFIERUTILS_CID \ +{ 0xb7b2ccec, 0x7912, 0x4ea6, { 0xa5, 0x48, 0xb0, 0x38, 0x44, 0x70, 0x04, 0xbd} } + // {10f2f5f0-f103-4901-980f-ba11bd70d60d} #define NS_SCRIPTABLEUNESCAPEHTML_CID \ { 0x10f2f5f0, 0xf103, 0x4901, { 0x98, 0x0f, 0xba, 0x11, 0xbd, 0x70, 0xd6, 0x0d} } diff --git a/toolkit/components/build/nsToolkitCompsModule.cpp b/toolkit/components/build/nsToolkitCompsModule.cpp index d4c0b351..a3906359 100644 --- a/toolkit/components/build/nsToolkitCompsModule.cpp +++ b/toolkit/components/build/nsToolkitCompsModule.cpp @@ -76,6 +76,7 @@ #ifdef MOZ_URL_CLASSIFIER #include "nsUrlClassifierDBService.h" #include "nsUrlClassifierStreamUpdater.h" +#include "nsUrlClassifierUtils.h" #endif #ifdef MOZ_FEEDS #include "nsScriptableUnescapeHTML.h" @@ -117,6 +118,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsSingleSignonPrompt) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsUrlClassifierDBService, nsUrlClassifierDBService::GetInstance) NS_GENERIC_FACTORY_CONSTRUCTOR(nsUrlClassifierStreamUpdater) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsUrlClassifierUtils) #endif #ifdef MOZ_FEEDS NS_GENERIC_FACTORY_CONSTRUCTOR(nsScriptableUnescapeHTML) @@ -242,6 +244,10 @@ static const nsModuleComponentInfo components[] = NS_URLCLASSIFIERSTREAMUPDATER_CID, NS_URLCLASSIFIERSTREAMUPDATER_CONTRACTID, nsUrlClassifierStreamUpdaterConstructor }, + { "Url Classifier Utils", + NS_URLCLASSIFIERUTILS_CID, + NS_URLCLASSIFIERUTILS_CONTRACTID, + nsUrlClassifierUtilsConstructor }, #endif #ifdef MOZ_FEEDS { "Unescape HTML", diff --git a/toolkit/components/commandlines/public/Makefile.in b/toolkit/components/commandlines/public/Makefile.in index 64890e04..03420076 100644 --- a/toolkit/components/commandlines/public/Makefile.in +++ b/toolkit/components/commandlines/public/Makefile.in @@ -49,6 +49,7 @@ XPIDLSRCS = \ nsICommandLine.idl \ nsICommandLineRunner.idl \ nsICommandLineHandler.idl \ + nsICommandLineValidator.idl \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/toolkit/components/commandlines/public/nsICommandLineValidator.idl b/toolkit/components/commandlines/public/nsICommandLineValidator.idl new file mode 100644 index 00000000..327070d1 --- /dev/null +++ b/toolkit/components/commandlines/public/nsICommandLineValidator.idl @@ -0,0 +1,70 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Mozilla toolkit. + * + * The Initial Developer of the Original Code is + * Robert Strong + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +interface nsICommandLine; + +/** + * Validates arguments on the command line of an XUL application. + * + * Each validator is registered in the category "command-line-validator". + * The entries in this category are read in alphabetical order, and each + * category value is treated as a service contractid implementing this + * interface. + * + * By convention, validator with ordinary priority should begin with "m". + * + * Example: + * Category Entry Value + * command-line-validator b-browser @mozilla.org/browser/clh;1 + * command-line-validator m-edit @mozilla.org/composer/clh;1 + * command-line-validator m-irc @mozilla.org/chatzilla/clh;1 + * + */ + +[scriptable, uuid(5ecaa593-7660-4a3a-957a-92d5770671c7)] +interface nsICommandLineValidator : nsISupports +{ + /** + * Process the command-line validators in the proper order, calling + * "validate()" on each. + * + * @throws NS_ERROR_ABORT if any validator throws NS_ERROR_ABORT. All other + * errors thrown by validators will be silently ignored. + */ + void validate(in nsICommandLine aCommandLine); +}; diff --git a/toolkit/components/commandlines/src/nsCommandLine.cpp b/toolkit/components/commandlines/src/nsCommandLine.cpp index b8e2ebdd..926e9308 100644 --- a/toolkit/components/commandlines/src/nsCommandLine.cpp +++ b/toolkit/components/commandlines/src/nsCommandLine.cpp @@ -39,6 +39,7 @@ #include "nsICategoryManager.h" #include "nsICommandLineHandler.h" +#include "nsICommandLineValidator.h" #include "nsIDOMWindow.h" #include "nsIFile.h" #include "nsISimpleEnumerator.h" @@ -85,12 +86,17 @@ public: protected: ~nsCommandLine() { } - typedef nsresult (*EnumerateCallback)(nsICommandLineHandler* aHandler, + typedef nsresult (*EnumerateHandlersCallback)(nsICommandLineHandler* aHandler, + nsICommandLine* aThis, + void *aClosure); + typedef nsresult (*EnumerateValidatorsCallback)(nsICommandLineValidator* aValidator, nsICommandLine* aThis, void *aClosure); void appendArg(const char* arg); - nsresult EnumerateHandlers(EnumerateCallback aCallback, void *aClosure); + void resolveShortcutURL(nsILocalFile* aFile, nsACString& outURL); + nsresult EnumerateHandlers(EnumerateHandlersCallback aCallback, void *aClosure); + nsresult EnumerateValidators(EnumerateValidatorsCallback aCallback, void *aClosure); nsStringArray mArgs; PRUint32 mState; @@ -439,18 +445,27 @@ nsCommandLine::ResolveURI(const nsAString& aArgument, nsIURI* *aResult) nsCOMPtr io = do_GetIOService(); NS_ENSURE_TRUE(io, NS_ERROR_OUT_OF_MEMORY); + nsCOMPtr workingDirURI; + if (mWorkingDir) { + io->NewFileURI(mWorkingDir, getter_AddRefs(workingDirURI)); + } + nsCOMPtr lf (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); rv = lf->InitWithPath(aArgument); if (NS_SUCCEEDED(rv)) { lf->Normalize(); + nsCAutoString url; + // Try to resolve the url for .url files. + resolveShortcutURL(lf, url); + if (!url.IsEmpty()) { + return io->NewURI(url, + nsnull, + workingDirURI, + aResult); + } return io->NewFileURI(lf, aResult); } - nsCOMPtr workingDirURI; - if (mWorkingDir) { - io->NewFileURI(mWorkingDir, getter_AddRefs(workingDirURI)); - } - return io->NewURI(NS_ConvertUTF16toUTF8(aArgument), nsnull, workingDirURI, @@ -470,6 +485,22 @@ nsCommandLine::appendArg(const char* arg) mArgs.AppendString(warg); } +void +nsCommandLine::resolveShortcutURL(nsILocalFile* aFile, nsACString& outURL) +{ + nsCOMPtr fph; + nsresult rv = NS_GetFileProtocolHandler(getter_AddRefs(fph)); + if (NS_FAILED(rv)) + return; + + nsCOMPtr uri; + rv = fph->ReadURLFile(aFile, getter_AddRefs(uri)); + if (NS_FAILED(rv)) + return; + + uri->GetSpec(outURL); +} + NS_IMETHODIMP nsCommandLine::Init(PRInt32 argc, char** argv, nsIFile* aWorkingDir, PRUint32 aState) @@ -536,7 +567,7 @@ nsCommandLine::Init(PRInt32 argc, char** argv, nsIFile* aWorkingDir, } nsresult -nsCommandLine::EnumerateHandlers(EnumerateCallback aCallback, void *aClosure) +nsCommandLine::EnumerateHandlers(EnumerateHandlersCallback aCallback, void *aClosure) { nsresult rv; @@ -578,6 +609,55 @@ nsCommandLine::EnumerateHandlers(EnumerateCallback aCallback, void *aClosure) return rv; } +nsresult +nsCommandLine::EnumerateValidators(EnumerateValidatorsCallback aCallback, void *aClosure) +{ + nsresult rv; + + nsCOMPtr catman + (do_GetService(NS_CATEGORYMANAGER_CONTRACTID)); + NS_ENSURE_TRUE(catman, NS_ERROR_UNEXPECTED); + + nsCOMPtr entenum; + rv = catman->EnumerateCategory("command-line-validator", + getter_AddRefs(entenum)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr strenum (do_QueryInterface(entenum)); + NS_ENSURE_TRUE(strenum, NS_ERROR_UNEXPECTED); + + nsCAutoString entry; + PRBool hasMore; + while (NS_SUCCEEDED(strenum->HasMore(&hasMore)) && hasMore) { + strenum->GetNext(entry); + + nsXPIDLCString contractID; + rv = catman->GetCategoryEntry("command-line-validator", + entry.get(), + getter_Copies(contractID)); + if (!contractID) + continue; + + nsCOMPtr clv(do_GetService(contractID.get())); + if (!clv) + continue; + + rv = (aCallback)(clv, this, aClosure); + if (rv == NS_ERROR_ABORT) + break; + + rv = NS_OK; + } + + return rv; +} + +static nsresult +EnumValidate(nsICommandLineValidator* aValidator, nsICommandLine* aThis, void*) +{ + return aValidator->Validate(aThis); +} + static nsresult EnumRun(nsICommandLineHandler* aHandler, nsICommandLine* aThis, void*) { @@ -589,6 +669,10 @@ nsCommandLine::Run() { nsresult rv; + rv = EnumerateValidators(EnumValidate, nsnull); + if (rv == NS_ERROR_ABORT) + return rv; + rv = EnumerateHandlers(EnumRun, nsnull); if (rv == NS_ERROR_ABORT) return rv; diff --git a/toolkit/components/downloads/src/nsDownloadManager.cpp b/toolkit/components/downloads/src/nsDownloadManager.cpp index 720529a3..d74799ad 100644 --- a/toolkit/components/downloads/src/nsDownloadManager.cpp +++ b/toolkit/components/downloads/src/nsDownloadManager.cpp @@ -74,6 +74,12 @@ #include #endif +#if defined(_MSC_VER) && _MSC_VER < 1300 +#define BYTES_TO_KBYTES(bytes) ((PRFloat64)((PRInt64)(bytes >> 8) / 4 + .5)) +#else +#define BYTES_TO_KBYTES(bytes) ((PRFloat64)bytes / 1024.0 + .5) +#endif + /* Outstanding issues/todo: * 1. Implement pause/resume. */ @@ -480,8 +486,8 @@ nsDownloadManager::AssertProgressInfoFor(const PRUnichar* aPath) internalDownload->GetTransferInformation(); // convert from bytes to kbytes for progress display - PRInt64 current = (PRFloat64)transferInfo.mCurrBytes / 1024 + .5; - PRInt64 max = (PRFloat64)transferInfo.mMaxBytes / 1024 + .5; + PRInt64 current = BYTES_TO_KBYTES(transferInfo.mCurrBytes); + PRInt64 max = BYTES_TO_KBYTES(transferInfo.mMaxBytes); nsAutoString currBytes; currBytes.AppendInt(current); nsAutoString maxBytes; maxBytes.AppendInt(max); @@ -2330,14 +2336,14 @@ nsDownload::GetPercentComplete(PRInt32* aPercentComplete) NS_IMETHODIMP nsDownload::GetAmountTransferred(PRUint64* aAmountTransferred) { - *aAmountTransferred = ((PRFloat64)mCurrBytes / 1024.0 + .5); + *aAmountTransferred = BYTES_TO_KBYTES(mCurrBytes); return NS_OK; } NS_IMETHODIMP nsDownload::GetSize(PRUint64* aSize) { - *aSize = ((PRFloat64)mMaxBytes / 1024 + .5); + *aSize = BYTES_TO_KBYTES(mMaxBytes); return NS_OK; } diff --git a/toolkit/components/feeds/src/FeedProcessor.js b/toolkit/components/feeds/src/FeedProcessor.js index 2f199139..c10d3aae 100644 --- a/toolkit/components/feeds/src/FeedProcessor.js +++ b/toolkit/components/feeds/src/FeedProcessor.js @@ -333,7 +333,7 @@ Feed.prototype = { categories: ["categories", "dc:subject"], rights: ["atom03:rights","atom:rights"], cloud: ["cloud"], - image: ["image", "rss1:image"], + image: ["image", "rss1:image", "atom:logo"], textInput: ["textInput", "rss1:textinput"], skipDays: ["skipDays"], skipHours: ["skipHours"], @@ -355,6 +355,11 @@ Feed.prototype = { if (bagHasKey(this.fields, "links")) this._atomLinksToURI(); + // Resolve relative image links + if (this.image && bagHasKey(this.image, "url")) { + this._resolveImageLink(); + } + this._resetBagMembersToRawText([this.searchLists.subtitle, this.searchLists.title]); }, @@ -363,22 +368,36 @@ Feed.prototype = { var links = this.fields.getPropertyAsInterface("links", Ci.nsIArray); var alternates = findAtomLinks("alternate", links); if (alternates.length > 0) { - try { - var href = alternates[0].getPropertyAsAString("href"); - var base; - if (bagHasKey(alternates[0], "xml:base")) - base = strToURI(alternates[0].getPropertyAsAString("xml:base"), - this.baseURI); - else - base = this.baseURI; - this.link = strToURI(alternates[0].getPropertyAsAString("href"), base); - } - catch(e) { - LOG(e); - } + var href = alternates[0].getPropertyAsAString("href"); + var base; + if (bagHasKey(alternates[0], "xml:base")) + base = alternates[0].getPropertyAsAString("xml:base"); + this.link = this._resolveURI(href, base); } }, + _resolveImageLink: function Feed_resolveImageLink() { + var base; + if (bagHasKey(this.image, "xml:base")) + base = this.image.getPropertyAsAString("xml:base"); + var url = this._resolveURI(this.image.getPropertyAsAString("url"), base); + if (url) + this.image.setPropertyAsAString("url", url.spec); + }, + + _resolveURI: function Feed_resolveURI(linkSpec, baseSpec) { + var uri = null; + try { + var base = baseSpec ? strToURI(baseSpec, this.baseURI) : this.baseURI; + uri = strToURI(linkSpec, base); + } + catch(e) { + LOG(e); + } + + return uri; + }, + // reset the bag to raw contents, not text constructs _resetBagMembersToRawText: function Feed_resetBagMembers(fieldLists) { for (var i=0; i test title - http://example.org/logo.jpg + logo.jpg \ No newline at end of file diff --git a/toolkit/components/feeds/test/xml/rss2/item_guid_isPermaLink_false.xml b/toolkit/components/feeds/test/xml/rss2/item_guid_isPermaLink_false.xml new file mode 100644 index 00000000..c2a1ad86 --- /dev/null +++ b/toolkit/components/feeds/test/xml/rss2/item_guid_isPermaLink_false.xml @@ -0,0 +1,20 @@ + + + + + + + +jbb@dallas.example.com (Joe Bob Briggs) +test +http://www.example.org/ +bar + +I'm headed for France. I wasn't gonna go this year, but then last week <a href="http://www.imdb.com/title/tt0086525/">Valley Girl</a> came out and I said to myself, Joe Bob, you gotta get out of the country for a while. + + diff --git a/toolkit/components/feeds/test/xml/rss2/item_guid_isPermaLink_false_uppercase.xml b/toolkit/components/feeds/test/xml/rss2/item_guid_isPermaLink_false_uppercase.xml new file mode 100644 index 00000000..9ff2505c --- /dev/null +++ b/toolkit/components/feeds/test/xml/rss2/item_guid_isPermaLink_false_uppercase.xml @@ -0,0 +1,20 @@ + + + + + + + +jbb@dallas.example.com (Joe Bob Briggs) +test +http://www.example.org/ +bar + +I'm headed for France. I wasn't gonna go this year, but then last week <a href="http://www.imdb.com/title/tt0086525/">Valley Girl</a> came out and I said to myself, Joe Bob, you gotta get out of the country for a while. + + diff --git a/toolkit/components/feeds/test/xml/rss2/item_guid_isPermaLink_true_uppercase.xml b/toolkit/components/feeds/test/xml/rss2/item_guid_isPermaLink_true_uppercase.xml new file mode 100644 index 00000000..bc4fdc0e --- /dev/null +++ b/toolkit/components/feeds/test/xml/rss2/item_guid_isPermaLink_true_uppercase.xml @@ -0,0 +1,20 @@ + + + + + + + +jbb@dallas.example.com (Joe Bob Briggs) +test +http://www.example.org/ +bar + +I'm headed for France. I wasn't gonna go this year, but then last week <a href="http://www.imdb.com/title/tt0086525/">Valley Girl</a> came out and I said to myself, Joe Bob, you gotta get out of the country for a while. + + diff --git a/toolkit/components/feeds/test/xml/rss2/item_guid_isPermaLink_unknown_value.xml b/toolkit/components/feeds/test/xml/rss2/item_guid_isPermaLink_unknown_value.xml new file mode 100644 index 00000000..4dce8c39 --- /dev/null +++ b/toolkit/components/feeds/test/xml/rss2/item_guid_isPermaLink_unknown_value.xml @@ -0,0 +1,20 @@ + + + + + + + +jbb@dallas.example.com (Joe Bob Briggs) +test +http://www.example.org/ +bar + +I'm headed for France. I wasn't gonna go this year, but then last week <a href="http://www.imdb.com/title/tt0086525/">Valley Girl</a> came out and I said to myself, Joe Bob, you gotta get out of the country for a while. + + diff --git a/toolkit/components/help/content/help.js b/toolkit/components/help/content/help.js index d4ab24c3..714ad4b6 100644 --- a/toolkit/components/help/content/help.js +++ b/toolkit/components/help/content/help.js @@ -137,6 +137,12 @@ function init() { helpGlossaryPanel = document.getElementById("help-glossary-panel"); helpBrowser = document.getElementById("help-content"); + // Turn off unnecessary features for security + helpBrowser.docShell.allowJavascript = false; + helpBrowser.docShell.allowPlugins = false; + helpBrowser.docShell.allowSubframes = false; + helpBrowser.docShell.allowMetaRedirects = false; + strBundle = document.getElementById("bundle_help"); emptySearchText = strBundle.getString("emptySearchText"); diff --git a/toolkit/components/history/src/nsGlobalHistory.cpp b/toolkit/components/history/src/nsGlobalHistory.cpp index 852867a5..3fa2d0b1 100644 --- a/toolkit/components/history/src/nsGlobalHistory.cpp +++ b/toolkit/components/history/src/nsGlobalHistory.cpp @@ -1524,7 +1524,7 @@ nsGlobalHistory::GetSource(nsIRDFResource* aProperty, // XXX We could be more forgiving here, and check for literal // values as well. nsCOMPtr target = do_QueryInterface(aTarget); - if (IsURLInHistory(target)) + if (target && IsURLInHistory(target)) return CallQueryInterface(aTarget, aSource); } diff --git a/toolkit/components/nsDefaultCLH.js b/toolkit/components/nsDefaultCLH.js index 84e4423c..19f150a7 100644 --- a/toolkit/components/nsDefaultCLH.js +++ b/toolkit/components/nsDefaultCLH.js @@ -47,6 +47,9 @@ const nsIModule = Components.interfaces.nsIModule; const nsIPrefBranch = Components.interfaces.nsIPrefBranch; const nsISupportsString = Components.interfaces.nsISupportsString; const nsIWindowWatcher = Components.interfaces.nsIWindowWatcher; +const nsIProperties = Components.interfaces.nsIProperties; +const nsIFile = Components.interfaces.nsIFile; +const nsISimpleEnumerator = Components.interfaces.nsISimpleEnumerator; /** * This file provides a generic default command-line handler. @@ -59,6 +62,12 @@ const nsIWindowWatcher = Components.interfaces.nsIWindowWatcher; * It doesn't do anything if the pref "toolkit.defaultChromeURI" is unset. */ +function getDirectoryService() +{ + return Components.classes["@mozilla.org/file/directory_service;1"] + .getService(nsIProperties); +} + var nsDefaultCLH = { /* nsISupports */ @@ -74,8 +83,41 @@ var nsDefaultCLH = { /* nsICommandLineHandler */ handle : function clh_handle(cmdLine) { + + var printDir; + while (printDir = cmdLine.handleFlagWithParam("print-xpcom-dir", false)) { + var out = "print-xpcom-dir(\"" + printDir + "\"): "; + try { + out += getDirectoryService().get(printDir, nsIFile).path; + } + catch (e) { + out += ""; + } + + dump(out + "\n"); + Components.utils.reportError(out); + } + + var printDirList; + while (printDirList = cmdLine.handleFlagWithParam("print-xpcom-dirlist", + false)) { + out = "print-xpcom-dirlist(\"" + printDirList + "\"): "; + try { + var list = getDirectoryService().get(printDirList, + nsISimpleEnumerator); + while (list.hasMoreElements()) + out += list.getNext().QueryInterface(nsIFile).path + ";"; + } + catch (e) { + out += ""; + } + + dump(out + "\n"); + Components.utils.reportError(out); + } + if (cmdLine.preventDefault) - return; + return; var prefs = Components.classes["@mozilla.org/preferences-service;1"] .getService(nsIPrefBranch); @@ -86,9 +128,9 @@ var nsDefaultCLH = { .getService(Components.interfaces.nsIWindowMediator); var win = windowMediator.getMostRecentWindow(singletonWindowType); if (win) { - win.focus(); - cmdLine.preventDefault = true; - return; + win.focus(); + cmdLine.preventDefault = true; + return; } } catch (e) { } diff --git a/toolkit/components/passwordmgr/base/nsPasswordManager.cpp b/toolkit/components/passwordmgr/base/nsPasswordManager.cpp index cdb5dc58..e6038efd 100644 --- a/toolkit/components/passwordmgr/base/nsPasswordManager.cpp +++ b/toolkit/components/passwordmgr/base/nsPasswordManager.cpp @@ -373,6 +373,11 @@ nsPasswordManager::AddUser(const nsACString& aHost, if (aUser.IsEmpty() && aPassword.IsEmpty()) return NS_OK; + // Reject values that would cause problems when parsing the storage file + nsresult rv = CheckLoginValues(aHost, + EmptyString(), EmptyString(), EmptyCString()); + NS_ENSURE_SUCCESS(rv, rv); + // Check for an existing entry for this host + user if (!aHost.IsEmpty()) { SignonHashEntry *hashEnt; @@ -440,6 +445,11 @@ nsPasswordManager::RemoveUser(const nsACString& aHost, const nsAString& aUser) NS_IMETHODIMP nsPasswordManager::AddReject(const nsACString& aHost) { + // Reject values that would cause problems when parsing the storage file + nsresult rv = CheckLoginValues(aHost, + EmptyString(), EmptyString(), EmptyCString()); + NS_ENSURE_SUCCESS(rv, rv); + mRejectTable.Put(aHost, 1); WritePasswords(mSignonFile); return NS_OK; @@ -611,6 +621,11 @@ nsPasswordManager::AddUserFull(const nsACString& aKey, if (aUser.IsEmpty() && aPassword.IsEmpty()) return NS_OK; + // Reject values that would cause problems when parsing the storage file + nsresult rv = CheckLoginValues(aKey, aUserFieldName, + aPassFieldName, EmptyCString()); + NS_ENSURE_SUCCESS(rv, rv); + // Check for an existing entry for this host + user if (!aKey.IsEmpty()) { SignonHashEntry *hashEnt; @@ -795,7 +810,7 @@ nsPasswordManager::Observe(nsISupports* aSubject, obsService->AddObserver(this, "profile-after-change", PR_TRUE); } else if (!strcmp(aTopic, "profile-after-change")) - nsCOMPtr pm = do_GetService(NS_PASSWORDMANAGER_CONTRACTID); + LoadPasswords(); return NS_OK; } @@ -1023,10 +1038,14 @@ nsPasswordManager::Notify(nsIContent* aFormNode, if (NS_SUCCEEDED(GetActionRealm(formElement, formActionOrigin)) && !entry->actionOrigin.Equals(formActionOrigin)) { - // update the action URL - entry->actionOrigin.Assign(formActionOrigin); - writePasswords = PR_TRUE; + // Reject values that would cause problems when parsing the storage file + if (NS_SUCCEEDED(CheckLoginValues(EmptyCString(), EmptyString(), + EmptyString(), formActionOrigin))) { + // update the action URL + entry->actionOrigin.Assign(formActionOrigin); + writePasswords = PR_TRUE; + } } if (writePasswords) @@ -1101,9 +1120,23 @@ nsPasswordManager::Notify(nsIContent* aFormNode, return NS_OK; } + // Reject values that would cause problems when parsing the storage file + // We do this after prompting, lest any code somehow change the values + // during the prompting. + nsresult rv = CheckLoginValues(realm, + entry->userField, entry->passField, + entry->actionOrigin); + NS_ENSURE_SUCCESS(rv, NS_OK); + AddSignonData(realm, entry); WritePasswords(mSignonFile); } else if (selection == 2) { + // Reject values that would cause problems when parsing the storage file + // We do this after prompting, lest any code run from prompt context. + nsresult rv = CheckLoginValues(realm, EmptyString(), + EmptyString(), EmptyCString()); + NS_ENSURE_SUCCESS(rv, NS_OK); + AddReject(realm); } } @@ -1914,6 +1947,7 @@ nsPasswordManager::FillDocument(nsIDOMDocument* aDomDoc) inputField->GetValue(oldUserValue); userField = inputField; foundNode = inputField; + // Only the case differs, so CheckLoginValues() unneeded. e->userField.Assign(name); break; } @@ -1973,8 +2007,15 @@ nsPasswordManager::FillDocument(nsIDOMDocument* aDomDoc) temp->GetValue(oldPassValue); passField = temp; - if ((e->passField).IsEmpty()) - passField->GetName(e->passField); + if ((e->passField).IsEmpty()) { + nsAutoString passName; + passField->GetName(passName); + + // Reject values that would cause problems when parsing the storage file + if (NS_SUCCEEDED(CheckLoginValues(EmptyCString(), EmptyString(), + passName, EmptyCString()))) + e->passField.Assign(passName); + } } else { continue; } @@ -2098,8 +2139,9 @@ nsPasswordManager::FillPassword(nsIDOMEvent* aEvent) nsCOMPtr form = do_QueryInterface(formEl); nsCAutoString formActionOrigin; GetActionRealm(form, formActionOrigin); - if (NS_FAILED(GetActionRealm(form, formActionOrigin)) || - !foundEntry->actionOrigin.Equals(formActionOrigin)) + if (NS_FAILED(GetActionRealm(form, formActionOrigin))) + return NS_OK; + if (!foundEntry->actionOrigin.IsEmpty() && !foundEntry->actionOrigin.Equals(formActionOrigin)) return NS_OK; nsCOMPtr foundNode; @@ -2197,3 +2239,68 @@ nsPasswordManager::GetActionRealm(nsIForm* aForm, nsCString& aURL) aURL.Assign(formActionOrigin); return NS_OK; } + +/* static */ PRBool +nsPasswordManager::BadCharacterPresent(const nsAString &aString) +{ + if (aString.FindChar('\r') >= 0) + return PR_TRUE; + if (aString.FindChar('\n') >= 0) + return PR_TRUE; + if (aString.FindChar('\0') >= 0) + return PR_TRUE; + + return PR_FALSE; +} + +/* static */ nsresult +nsPasswordManager::CheckLoginValues(const nsACString &aHost, + const nsAString &aUserField, + const nsAString &aPassField, + const nsACString &aActionOrigin) +{ + // aHost + if (BadCharacterPresent(NS_ConvertUTF8toUTF16(aHost))) { + NS_WARNING("Login rejected, bad character in aHost"); + return NS_ERROR_FAILURE; + } + // The aHost arg is used for both login entry hostnames and reject entry + // hostnames ("never for this site"). A value of "." is not allowed for + // reject entries. It's technically ok for login entries, but to keep the + // code simple we'll disallow it anyway. + if (aHost.EqualsLiteral(".")) { + NS_WARNING("Login rejected, aHost can not be just a period"); + return NS_ERROR_FAILURE; + } + + + // aUserField + if (BadCharacterPresent(aUserField)) { + NS_WARNING("Login rejected, bad character in aUserField"); + return NS_ERROR_FAILURE; + } + if (aUserField.EqualsLiteral(".")) { + NS_WARNING("Login rejected, aUserField can not be just a period"); + return NS_ERROR_FAILURE; + } + + + // aPassField + if (BadCharacterPresent(aPassField)) { + NS_WARNING("Login rejected, bad character in aPassField"); + return NS_ERROR_FAILURE; + } + + + // aActionOrigin + if (BadCharacterPresent(NS_ConvertUTF8toUTF16(aActionOrigin))) { + NS_WARNING("Login rejected, bad character in aActionOrigin"); + return NS_ERROR_FAILURE; + } + if (aActionOrigin.EqualsLiteral(".")) { + NS_WARNING("Login rejected, aActionOrigin can not be just a period"); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} diff --git a/toolkit/components/passwordmgr/base/nsPasswordManager.h b/toolkit/components/passwordmgr/base/nsPasswordManager.h index 655d2b09..0d723cdd 100644 --- a/toolkit/components/passwordmgr/base/nsPasswordManager.h +++ b/toolkit/components/passwordmgr/base/nsPasswordManager.h @@ -153,6 +153,12 @@ protected: static nsresult GetActionRealm(nsIForm* aForm, nsCString& aURL); + static PRBool BadCharacterPresent(const nsAString &aString); + static nsresult CheckLoginValues(const nsACString &aHost, + const nsAString &aUserField, + const nsAString &aPassField, + const nsACString &aActionOrigin); + static PLDHashOperator PR_CALLBACK FindEntryEnumerator(const nsACString& aKey, SignonHashEntry* aEntry, void* aUserData); diff --git a/toolkit/components/remote/Makefile.in b/toolkit/components/remote/Makefile.in index 293663d9..87e4bb3b 100644 --- a/toolkit/components/remote/Makefile.in +++ b/toolkit/components/remote/Makefile.in @@ -71,7 +71,7 @@ CPPSRCS += nsGTKRemoteService.cpp endif ifeq (photon,$(MOZ_WIDGET_TOOLKIT)) -CPPSRCS += nsPhMozRemoteHelper.cpp +CPPSRCS += nsPhRemoteService.cpp endif include $(topsrcdir)/config/rules.mk diff --git a/toolkit/components/remote/nsPhRemoteService.cpp b/toolkit/components/remote/nsPhRemoteService.cpp new file mode 100644 index 00000000..d62ee298 --- /dev/null +++ b/toolkit/components/remote/nsPhRemoteService.cpp @@ -0,0 +1,193 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Christopher Blizzard. + * Portions created by Christopher Blizzard are Copyright (C) + * Christopher Blizzard. All Rights Reserved. + * + * Contributor(s): + * Adrian Mardare + * Max Feil + */ + +#include +#include +#include +#include "nsIGenericFactory.h" +#include "nsPhRemoteService.h" +#include "nsIServiceManager.h" +#include "nsCRT.h" + +#ifdef MOZ_XUL_APP +#include "nsICommandLineRunner.h" +#include "nsXULAppAPI.h" +#else +#include "nsISuiteRemoteService.h" +#endif + +#include + +NS_IMPL_QUERY_INTERFACE2(nsPhRemoteService, + nsIRemoteService, + nsIObserver) + +NS_IMETHODIMP_(nsrefcnt) +nsPhRemoteService::AddRef() +{ + return 1; +} + +NS_IMETHODIMP_(nsrefcnt) +nsPhRemoteService::Release() +{ + return 1; +} + +NS_IMETHODIMP +nsPhRemoteService::Startup(const char* aAppName, const char* aProfileName) +{ + NS_ASSERTION(aAppName, "Don't pass a null appname!"); + + if (mIsInitialized) + return NS_ERROR_ALREADY_INITIALIZED; + + mIsInitialized = PR_TRUE; + mAppName = aAppName; + ToLowerCase(mAppName); + + HandleCommandsFor(nsnull, nsnull); + + return NS_OK; +} + +NS_IMETHODIMP +nsPhRemoteService::RegisterWindow(nsIDOMWindow* aWindow) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsPhRemoteService::Shutdown() +{ + if (!mIsInitialized) + return NS_ERROR_NOT_INITIALIZED; + + mIsInitialized = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP +nsPhRemoteService::Observe(nsISupports* aSubject, + const char *aTopic, + const PRUnichar *aData) +{ + // This can be xpcom-shutdown or quit-application, but it's the same either + // way. + Shutdown(); + return NS_OK; +} + +#define MOZ_REMOTE_MSG_TYPE 100 + +static void const * RemoteMsgHandler( PtConnectionServer_t *connection, void *user_data, + unsigned long type, void const *msg, unsigned len, unsigned *reply_len ) +{ + nsresult rv; + + if( type != MOZ_REMOTE_MSG_TYPE ) return NULL; + + /* we are given strings and we reply with strings */ + char *response = NULL; + + // parse the command + nsCOMPtr cmdline + (do_CreateInstance("@mozilla.org/toolkit/command-line;1", &rv)); + if (!NS_FAILED(rv)) { + + // 1) Make sure that it looks remotely valid with parens + // 2) Treat ping() immediately and specially + + nsCAutoString command((char *)msg); + PRInt32 p1, p2; + p1 = command.FindChar('('); + p2 = command.FindChar(')'); + + if (p1 != kNotFound && p2 != kNotFound && p1 != 0 && p2 >= p1) { + command.Truncate(p1); + command.Trim(" ", PR_TRUE, PR_TRUE); + ToLowerCase(command); + + //printf("Processing xremote command: %s\n", command.get()); + + if (!command.EqualsLiteral("ping")) { + char* argv[3] = {"dummyappname", "-remote", (char *)msg}; + rv = cmdline->Init(3, argv, nsnull, nsICommandLine::STATE_REMOTE_EXPLICIT); + if (!NS_FAILED(rv)) { + rv = cmdline->Run(); + if (NS_ERROR_ABORT == rv) + response = "500 command not parseable"; + if (NS_FAILED(rv)) + response = "509 internal error"; + } else + response = "509 internal error"; + } + } else + response = "500 command not parseable"; + } else + response = "509 internal error"; + + PtConnectionReply( connection, response ? strlen(response) : 0, response ); + + return ( void * ) 1; /* return any non NULL value to indicate we handled the message */ +} + +static void client_connect( PtConnector_t *cntr, PtConnectionServer_t *csrvr, void *data ) +{ + static PtConnectionMsgHandler_t handlers[] = { { 0, RemoteMsgHandler } }; + PtConnectionAddMsgHandlers( csrvr, handlers, sizeof(handlers)/sizeof(handlers[0]) ); +} + + +void +nsPhRemoteService::HandleCommandsFor( nsIWidget *aWidget, nsIWeakReference* aWindow ) +{ + static PRBool ConnectorCreated = PR_FALSE; + +///* ATENTIE */ printf( "aProgram=%s aProfile=%s aWidget=%p\n", aProgram?aProgram:"NULL", aProfile?aProfile:"NULL", aWidget ); + + if( !ConnectorCreated ) { + char RemoteServerName[128]; + sprintf( RemoteServerName, "%s_RemoteServer", (char *) mAppName.get() ); + /* create a connector for the remote control */ + PtConnectorCreate( RemoteServerName, client_connect, NULL ); + ConnectorCreated = PR_TRUE; + } + return; +} + +// {C0773E90-5799-4eff-AD03-3EBCD85624AC} +#define NS_REMOTESERVICE_CID \ + { 0xc0773e90, 0x5799, 0x4eff, { 0xad, 0x3, 0x3e, 0xbc, 0xd8, 0x56, 0x24, 0xac } } + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsPhRemoteService) + +static const nsModuleComponentInfo components[] = +{ + { "Remote Service", + NS_REMOTESERVICE_CID, + "@mozilla.org/toolkit/remote-service;1", + nsPhRemoteServiceConstructor + } +}; + +NS_IMPL_NSGETMODULE(RemoteServiceModule, components) diff --git a/toolkit/components/remote/nsPhRemoteService.h b/toolkit/components/remote/nsPhRemoteService.h new file mode 100644 index 00000000..b6686b68 --- /dev/null +++ b/toolkit/components/remote/nsPhRemoteService.h @@ -0,0 +1,69 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright (C) Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adrian Mardare + * Max Feil + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __nsPhRemoteService_h__ +#define __nsPhRemoteService_h__ + +#include "nsIRemoteService.h" +#include "nsIObserver.h" +#include "nsString.h" + +class nsIWeakReference; + +class nsPhRemoteService : public nsIRemoteService, + public nsIObserver +{ +public: + // We will be a static singleton, so don't use the ordinary methods. + NS_DECL_ISUPPORTS + NS_DECL_NSIREMOTESERVICE + NS_DECL_NSIOBSERVER + + nsPhRemoteService() { mIsInitialized = PR_FALSE; } + +private: + ~nsPhRemoteService() { } + + void HandleCommandsFor(nsIWidget *aWidget, + nsIWeakReference* aWindow); + PRBool mIsInitialized; + nsCString mAppName; + +}; + +#endif /* __nsPhRemoteService_h__ */ diff --git a/toolkit/components/satchel/src/nsFormFillController.cpp b/toolkit/components/satchel/src/nsFormFillController.cpp index 29f5a269..f9ca10f7 100644 --- a/toolkit/components/satchel/src/nsFormFillController.cpp +++ b/toolkit/components/satchel/src/nsFormFillController.cpp @@ -468,36 +468,34 @@ nsFormFillController::OnSearchComplete() } NS_IMETHODIMP -nsFormFillController::OnTextEntered(PRBool *_retval) +nsFormFillController::OnTextEntered(PRBool* aPrevent) { + NS_ENSURE_ARG(aPrevent); + NS_ENSURE_TRUE(mFocusedInput, NS_OK); // Fire off a DOMAutoComplete event nsCOMPtr domDoc; mFocusedInput->GetOwnerDocument(getter_AddRefs(domDoc)); nsCOMPtr doc = do_QueryInterface(domDoc); + NS_ENSURE_STATE(doc); nsCOMPtr event; doc->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event)); - if (!event) { - NS_ERROR("Could not create DOM Event"); - return NS_ERROR_FAILURE; - } + nsCOMPtr privateEvent(do_QueryInterface(event)); + NS_ENSURE_STATE(privateEvent); event->InitEvent(NS_LITERAL_STRING("DOMAutoComplete"), PR_TRUE, PR_TRUE); - nsCOMPtr privateEvent(do_QueryInterface(event)); - if (privateEvent) { - // XXXjst: We mark this event as a trusted event, it's up to the - // callers of this to ensure that it's only called from trusted - // code. - privateEvent->SetTrusted(PR_TRUE); - } + // XXXjst: We mark this event as a trusted event, it's up to the + // callers of this to ensure that it's only called from trusted + // code. + privateEvent->SetTrusted(PR_TRUE); nsCOMPtr targ = do_QueryInterface(mFocusedInput); PRBool defaultActionEnabled; targ->DispatchEvent(event, &defaultActionEnabled); - + *aPrevent = !defaultActionEnabled; return NS_OK; } @@ -994,10 +992,6 @@ nsFormFillController::AddWindowListeners(nsIDOMWindow *aWindow) target->AddEventListener(NS_LITERAL_STRING("contextmenu"), NS_STATIC_CAST(nsIDOMContextMenuListener *, this), PR_TRUE); - - target->AddEventListener(NS_LITERAL_STRING("keypress"), - NS_STATIC_CAST(nsIDOMKeyListener *, this), - PR_TRUE); } void @@ -1053,10 +1047,32 @@ nsFormFillController::RemoveWindowListeners(nsIDOMWindow *aWindow) target->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), NS_STATIC_CAST(nsIDOMContextMenuListener *, this), PR_TRUE); +} - target->RemoveEventListener(NS_LITERAL_STRING("keypress"), - NS_STATIC_CAST(nsIDOMKeyListener *, this), - PR_TRUE); +void +nsFormFillController::AddKeyListener(nsIDOMHTMLInputElement *aInput) +{ + if (!aInput) + return; + + nsCOMPtr target = do_QueryInterface(aInput); + + target->AddEventListener(NS_LITERAL_STRING("keypress"), + NS_STATIC_CAST(nsIDOMKeyListener *, this), + PR_TRUE); + } + +void +nsFormFillController::RemoveKeyListener() +{ + if (!mFocusedInput) + return; + + nsCOMPtr target = do_QueryInterface(mFocusedInput); + + target->RemoveEventListener(NS_LITERAL_STRING("keypress"), + NS_STATIC_CAST(nsIDOMKeyListener *, this), + PR_TRUE); } void @@ -1074,6 +1090,7 @@ nsFormFillController::StartControllingInput(nsIDOMHTMLInputElement *aInput) // Cache the popup for the focused docShell mPopups->GetElementAt(index, getter_AddRefs(mFocusedPopup)); + AddKeyListener(aInput); mFocusedInput = aInput; // Now we are the autocomplete controller's bitch @@ -1083,6 +1100,8 @@ nsFormFillController::StartControllingInput(nsIDOMHTMLInputElement *aInput) void nsFormFillController::StopControllingInput() { + RemoveKeyListener(); + // Reset the controller's input, but not if it has been switched // to another input already, which might happen if the user switches // focus by clicking another autocomplete textbox diff --git a/toolkit/components/satchel/src/nsFormFillController.h b/toolkit/components/satchel/src/nsFormFillController.h index a0c25bf5..b57cf656 100644 --- a/toolkit/components/satchel/src/nsFormFillController.h +++ b/toolkit/components/satchel/src/nsFormFillController.h @@ -127,6 +127,9 @@ protected: void AddWindowListeners(nsIDOMWindow *aWindow); void RemoveWindowListeners(nsIDOMWindow *aWindow); + void AddKeyListener(nsIDOMHTMLInputElement *aInput); + void RemoveKeyListener(); + void StartControllingInput(nsIDOMHTMLInputElement *aInput); void StopControllingInput(); diff --git a/toolkit/components/satchel/src/nsFormHistory.cpp b/toolkit/components/satchel/src/nsFormHistory.cpp index f8c281cd..f9cbe0af 100644 --- a/toolkit/components/satchel/src/nsFormHistory.cpp +++ b/toolkit/components/satchel/src/nsFormHistory.cpp @@ -73,6 +73,10 @@ static void SwapBytes(PRUnichar* aDest, const PRUnichar* aSrc, PRUint32 aLen) #define PREF_FORMFILL_BRANCH "browser.formfill." #define PREF_FORMFILL_ENABLE "enable" +// upper bounds on saved form data, more isn't useful. +#define FORMFILL_NAME_MAX_LEN 1000 +#define FORMFILL_VALUE_MAX_LEN 4000 + static const char *kFormHistoryFileName = "formhistory.dat"; NS_INTERFACE_MAP_BEGIN(nsFormHistory) @@ -626,7 +630,11 @@ nsFormHistory::AppendRow(const nsAString &aName, const nsAString &aValue, nsIMdb if (!mTable) return NS_ERROR_NOT_INITIALIZED; - PRBool exists; + if (aName.Length() > FORMFILL_NAME_MAX_LEN || + aValue.Length() > FORMFILL_VALUE_MAX_LEN) + return NS_ERROR_INVALID_ARG; + + PRBool exists = PR_TRUE; EntryExists(aName, aValue, &exists); if (exists) return NS_OK; diff --git a/toolkit/components/satchel/src/nsStorageFormHistory.cpp b/toolkit/components/satchel/src/nsStorageFormHistory.cpp index cd5ba539..cb1aaf4d 100644 --- a/toolkit/components/satchel/src/nsStorageFormHistory.cpp +++ b/toolkit/components/satchel/src/nsStorageFormHistory.cpp @@ -228,7 +228,7 @@ nsFormHistory::AddEntry(const nsAString &aName, const nsAString &aValue) mozStorageTransaction transaction(mDBConn, PR_FALSE); - PRBool exists; + PRBool exists = PR_TRUE; EntryExists(aName, aValue, &exists); if (!exists) { mozStorageStatementScoper scope(mDBInsertNameValue); diff --git a/toolkit/components/url-classifier/content/enchash-decrypter.js b/toolkit/components/url-classifier/content/enchash-decrypter.js index 5d495012..3a25e70f 100644 --- a/toolkit/components/url-classifier/content/enchash-decrypter.js +++ b/toolkit/components/url-classifier/content/enchash-decrypter.js @@ -74,18 +74,15 @@ PROT_EnchashDecrypter.SALT_LENGTH = PROT_EnchashDecrypter.DATABASE_SALT.length; PROT_EnchashDecrypter.MAX_DOTS = 5; PROT_EnchashDecrypter.REs = {}; -PROT_EnchashDecrypter.REs.FIND_DODGY_CHARS = - new RegExp("[\x01-\x1f\x7f-\xff]+"); -PROT_EnchashDecrypter.REs.FIND_DODGY_CHARS_GLOBAL = +PROT_EnchashDecrypter.REs.FIND_DODGY_CHARS_GLOBAL = new RegExp("[\x01-\x1f\x7f-\xff]+", "g"); -PROT_EnchashDecrypter.REs.FIND_END_DOTS = new RegExp("^\\.+|\\.+$"); -PROT_EnchashDecrypter.REs.FIND_END_DOTS_GLOBAL = +PROT_EnchashDecrypter.REs.FIND_END_DOTS_GLOBAL = new RegExp("^\\.+|\\.+$", "g"); -PROT_EnchashDecrypter.REs.FIND_MULTIPLE_DOTS = new RegExp("\\.{2,}"); -PROT_EnchashDecrypter.REs.FIND_MULTIPLE_DOTS_GLOBAL = +PROT_EnchashDecrypter.REs.FIND_MULTIPLE_DOTS_GLOBAL = new RegExp("\\.{2,}", "g"); -PROT_EnchashDecrypter.REs.FIND_TRAILING_DOTS = new RegExp("\\.+$"); -PROT_EnchashDecrypter.REs.POSSIBLE_IP = +PROT_EnchashDecrypter.REs.FIND_TRAILING_SPACE = + new RegExp("^(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}) "); +PROT_EnchashDecrypter.REs.POSSIBLE_IP = new RegExp("^((?:0x[0-9a-f]+|[0-9\\.])+)$", "i"); PROT_EnchashDecrypter.REs.FIND_BAD_OCTAL = new RegExp("(^|\\.)0\\d*[89]"); PROT_EnchashDecrypter.REs.IS_OCTAL = new RegExp("^0[0-7]*$"); @@ -171,12 +168,17 @@ PROT_EnchashDecrypter.prototype.parseRegExps = function(data) { * type -url. * * @param url String to canonicalize + * @param opt_collapseSlashes Boolean true if we want to collapse slashes in + * the path * * @returns String containing the canonicalized url (maximally url-decoded * with hostname normalized, then specially url-encoded) */ -PROT_EnchashDecrypter.prototype.getCanonicalUrl = function(url) { - var escapedUrl = PROT_URLCanonicalizer.canonicalizeURL_(url); +PROT_EnchashDecrypter.prototype.getCanonicalUrl = function(url, + opt_collapseSlashes) { + var urlUtils = Cc["@mozilla.org/url-classifier/utils;1"] + .getService(Ci.nsIUrlClassifierUtils); + var escapedUrl = urlUtils.canonicalizeURL(url); // Normalize the host var host = this.getCanonicalHost(escapedUrl); if (!host) { @@ -189,6 +191,13 @@ PROT_EnchashDecrypter.prototype.getCanonicalUrl = function(url) { .getService(Ci.nsIIOService); var urlObj = ioService.newURI(escapedUrl, null, null); urlObj.host = host; + if (opt_collapseSlashes) { + // Collapse multiple slashes in the path into a single slash. + // We end up collapsing slashes in the query string, but it's unlikely + // that this would lead to a false positive and it's much simpler to do + // this. + urlObj.path = urlObj.path.replace(/\/+/g, "/"); + } return urlObj.asciiSpec; } @@ -243,8 +252,19 @@ PROT_EnchashDecrypter.prototype.getCanonicalHost = function(str, opt_maxDots) { } PROT_EnchashDecrypter.prototype.parseIPAddress_ = function(host) { - - host = host.replace(this.REs_.FIND_TRAILING_DOTS_GLOBAL, ""); + if (host.length <= 15) { + // The Windows resolver allows a 4-part dotted decimal IP address to + // have a space followed by any old rubbish, so long as the total length + // of the string doesn't get above 15 characters. So, "10.192.95.89 xy" + // is resolved to 10.192.95.89. + // If the string length is greater than 15 characters, e.g. + // "10.192.95.89 xy.wildcard.example.com", it will be resolved through + // DNS. + var match = this.REs_.FIND_TRAILING_SPACE.exec(host); + if (match) { + host = match[1]; + } + } if (!this.REs_.POSSIBLE_IP.test(host)) return ""; @@ -264,13 +284,14 @@ PROT_EnchashDecrypter.prototype.parseIPAddress_ = function(host) { } if (canon != "") parts[k] = canon; + else + return ""; } return parts.join("."); } PROT_EnchashDecrypter.prototype.canonicalNum_ = function(num, bytes, octal) { - if (bytes < 0) return ""; var temp_num; @@ -292,8 +313,10 @@ PROT_EnchashDecrypter.prototype.canonicalNum_ = function(num, bytes, octal) { temp_num = -1; } else if (this.REs_.IS_HEX.test(num)) { - - num = this.lastNChars_(num, 8); + var matches = this.REs_.IS_HEX.exec(num); + if (matches) { + num = matches[1]; + } temp_num = parseInt(num, 16); if (isNaN(temp_num)) diff --git a/toolkit/components/url-classifier/content/listmanager.js b/toolkit/components/url-classifier/content/listmanager.js index 9885ae10..6b2396b5 100644 --- a/toolkit/components/url-classifier/content/listmanager.js +++ b/toolkit/components/url-classifier/content/listmanager.js @@ -552,11 +552,14 @@ PROT_ListManager.prototype.downloadError_ = function(status) { status = 500; } status = parseInt(status, 10); - this.requestBackoff_.noteServerResponse(status); - - // Try again in a minute - this.currentUpdateChecker_ = - new G_Alarm(BindToObject(this.checkForUpdates, this), 60000); + var isError = this.requestBackoff_.noteServerResponse(status); + if (isError) { + // Try again in a minute. We'll hit backoff if this is an error. If + // it's not an error, we just ignore the response and try again during + // our regular check interval. + this.currentUpdateChecker_ = + new G_Alarm(BindToObject(this.checkForUpdates, this), 60000); + } } PROT_ListManager.prototype.QueryInterface = function(iid) { diff --git a/toolkit/components/url-classifier/content/request-backoff.js b/toolkit/components/url-classifier/content/request-backoff.js index b4ba54da..67598a70 100644 --- a/toolkit/components/url-classifier/content/request-backoff.js +++ b/toolkit/components/url-classifier/content/request-backoff.js @@ -87,10 +87,13 @@ RequestBackoff.prototype.canMakeRequest = function() { } /** - * Notify this object of the last server response. If it's an error, + * Notify this object of the last server response. If it's an error, we + * check to see if we should trigger a backoff. + * @return Boolean true if this counts as an error. */ RequestBackoff.prototype.noteServerResponse = function(status) { - if (this.isErrorStatus_(status)) { + var isError = this.isErrorStatus_(status); + if (isError) { var now = Date.now(); this.errorTimes_.push(now); @@ -117,6 +120,7 @@ RequestBackoff.prototype.noteServerResponse = function(status) { this.nextRequestTime_ = 0; this.backoffTriggered_ = false; } + return isError; } /** diff --git a/toolkit/components/url-classifier/content/trtable.js b/toolkit/components/url-classifier/content/trtable.js index 7f81db19..c077cd63 100644 --- a/toolkit/components/url-classifier/content/trtable.js +++ b/toolkit/components/url-classifier/content/trtable.js @@ -75,17 +75,18 @@ UrlClassifierTableUrl.inherits(UrlClassifierTable); * Look up a URL in a URL table */ UrlClassifierTableUrl.prototype.exists = function(url, callback) { - // PROT_URLCanonicalizer.canonicalizeURL_ is the old way of canonicalizing a - // URL. Unfortunately, it doesn't normalize numeric domains so alternate IP - // formats (hex, octal, etc) won't trigger a match. - // this.enchashDecrypter_.getCanonicalUrl does the right thing and - // normalizes a URL to 4 decimal numbers, but the update server may still be - // giving us encoded IP addresses. So to be safe, we check both cases. - var oldCanonicalized = PROT_URLCanonicalizer.canonicalizeURL_(url); - var canonicalized = this.enchashDecrypter_.getCanonicalUrl(url); - G_Debug(this, "Looking up: " + url + " (" + oldCanonicalized + " and " + - canonicalized + ")"); - (new ExistsMultiQuerier([oldCanonicalized, canonicalized], + var urlUtils = Cc["@mozilla.org/url-classifier/utils;1"] + .getService(Ci.nsIUrlClassifierUtils); + // We plan on having the server collapse multiple slashes in the path. + // Until this happens, we check both the raw url and the url with multiple + // slashes removed. + var urls = [ + this.enchashDecrypter_.getCanonicalUrl(url), + this.enchashDecrypter_.getCanonicalUrl(url, true) /* collapse slashes */ + ]; + + G_Debug(this, "Looking up: " + url + " (" + urls + ")"); + (new ExistsMultiQuerier(urls, this.name, callback)).run(); } diff --git a/toolkit/components/url-classifier/content/url-canonicalizer.js b/toolkit/components/url-classifier/content/url-canonicalizer.js deleted file mode 100644 index 474f88f8..00000000 --- a/toolkit/components/url-classifier/content/url-canonicalizer.js +++ /dev/null @@ -1,354 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Google Safe Browsing. - * - * The Initial Developer of the Original Code is Google Inc. - * Portions created by the Initial Developer are Copyright (C) 2006 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Fritz Schneider (original author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - - -// This is the class we use to canonicalize URLs for TRTables of type -// url. We maximally URL-decode the URL, treating +'s as if they're -// not special. We then specially URL-encode it (we encode ASCII -// values [0, 32] (whitespace or unprintable), 37 (%), [127, 255] -// (unprintable)). -// -// This mapping is not a function. That is, multiple URLs can map to -// the same canonical representation. However this is OK because -// collisions happen only when there are weird characters (e.g., -// nonprintables), and the canonical representation makes us robust -// to some weird kinds of encoding we could see. -// -// All members are static at this point -- this is basically a namespace. - - -/** - * Create a new URLCanonicalizer. Useless because members are static. - * - * @constructor - */ -function PROT_URLCanonicalizer() { - throw new Error("No need to instantiate a canonicalizer at this point."); -} - -PROT_URLCanonicalizer.debugZone = "urlcanonicalizer"; - -PROT_URLCanonicalizer.hexChars_ = "0123456789ABCDEF"; - -/** - * Helper funciton to (maybe) convert a two-character hex string into its - * decimal numerical equivalent - * - * @param hh String of length two that might be a valid hex sequence - * - * @returns Number: NaN if hh wasn't valid hex, else the appropriate decimal - * value - */ -PROT_URLCanonicalizer.hexPairToInt_ = function(hh) { - return Number("0x" + hh); -} - -/** - * Helper function to hex-encode a number - * - * @param val Number in range [0, 255] - * - * @returns String containing the hex representation of that number (sans 0x) - */ -PROT_URLCanonicalizer.toHex_ = function(val) { - var retVal = PROT_URLCanonicalizer.hexChars_.charAt((val >> 4) & 15) + - PROT_URLCanonicalizer.hexChars_.charAt(val & 15); - return retVal; -} - -/** - * Canonicalize a URL. DON'T USE THIS DIRECTLY. Use - * PROT_EnchashDecrypter.prototype.getCanonicalUrl instead. This method - * url-decodes a string, but it doesn't normalize the hostname. The method - * in EnchashDecrypter first calls this method, then normalizes the hostname. - * - * @param url String to canonicalize - * - * @returns String containing the canonicalized url (maximally url-decoded, - * then specially url-encoded) - */ -PROT_URLCanonicalizer.canonicalizeURL_ = function(url) { - var arrayOfASCIIVals = PROT_URLCanonicalizer.fullyDecodeURL_(url); - return PROT_URLCanonicalizer.specialEncodeURL_(arrayOfASCIIVals); -} - -/** - * Maximally URL-decode a URL. This breaks the semantics of the URL, but - * we don't care because we're using it for lookup, not for navigation. - * We break multi-byte UTF-8 escape sequences as well, but we don't care - * so long as they canonicalize the same way consistently (they do). - * - * @param url String containing the URL to maximally decode. Should ONLY - * contain characters with UCS codepoints U+0001 to U+00FF - * (the ASCII set minus null). - * - * @returns Array of ASCII values corresponding to the decoded sequence of - * characters in the url - */ -PROT_URLCanonicalizer.fullyDecodeURL_ = function(url) { - - // The goals here are: simplicity, correctness, and most of all - // portability; we want the same implementation of canonicalization - // wherever we use it so as to to minimize the chances of - // inconsistency. For example, we have to do this canonicalization - // on URLs we get from third parties, and at the lookup server when - // we get a request. - // - // The following implementation should translate easily to any - // language that supports arrays and pointers or references. Note - // that arrays are pointer types in JavaScript, so foo = [some, - // array] points foo at the array; it doesn't copy it. The - // implementation is efficient (linear) so long as most %'s in the - // url belong to valid escape sequences and there aren't too many - // doubly-escaped values. - - // The basic idea is to copy current input to output, decoding escape - // sequences as we see them, until we decode a %. At that point we start - // copying into the "next iteration buffer" instead of the output buffer; - // we do this so we can accomodate multiply-escaped strings. When we hit - // the end of the input, we take the "next iteration buffer" as our input, - // and start over. - - var nextIteration = url.split(""); - var output = []; - - while (nextIteration.length) { - - var decodedAPercent = false; - var thisIteration = nextIteration; - var nextIteration = []; - - var i = 0; - while (i < thisIteration.length) { - - var c = thisIteration[i]; - if (c == "%" && i + 2 < thisIteration.length) { - - // Peek ahead to see if we have a valid HH sequence - var asciiVal = - PROT_URLCanonicalizer.hexPairToInt_(thisIteration[i + 1] + - thisIteration[i + 2]); - if (!isNaN(asciiVal)) { - i += 2; // Valid HH sequence; consume it - - if (asciiVal == 0) // We special case nulls - asciiVal = 1; - - c = String.fromCharCode(asciiVal); - if (c == "%") - decodedAPercent = true; - } - } - - if (decodedAPercent) - nextIteration[nextIteration.length] = c; - else - output[output.length] = c.charCodeAt(0); - - ++i; - } - } - - return output; -} - -/** - * Maximally URL-decode a URL (same as fullyDecodeURL_ except that it - * returns a string). Useful for making unittests more readable. - * - * @param url String containing the URL to maximally decode. Should ONLY - * contain characters with UCS codepoints U+0001 to U+00FF - * (the ASCII set minus null). - * - * @returns String containing the decoded URL - */ -PROT_URLCanonicalizer.fullyDecodeURLAsString_ = function(url) { - var arrayOfASCIIVals = PROT_URLCanonicalizer.fullyDecodeURL_(url); - var s = ""; - for (var i = 0; i < arrayOfASCIIVals.length; i++) - s += String.fromCharCode(arrayOfASCIIVals[i]); - return s; -} - -/** - * Specially URL-encode the given array of ASCII values. We want to encode - * the charcters: [0, 32], 37, [127, 255]. - * - * @param arrayOfASCIIValues Array of ascii values (numbers) to encode - * - * @returns String corresonding to the escaped URL - */ -PROT_URLCanonicalizer.specialEncodeURL_ = function(arrayOfASCIIValues) { - - var output = []; - for (var i = 0; i < arrayOfASCIIValues.length; i++) { - var n = arrayOfASCIIValues[i]; - - if (n <= 32 || n == 37 || n >= 127) - output.push("%" + ((!n) ? "01" : PROT_URLCanonicalizer.toHex_(n))); - else - output.push(String.fromCharCode(n)); - } - - return output.join(""); -} - - -#ifdef DEBUG -/** - * Lame unittesting function - */ -function TEST_PROT_URLCanonicalizer() { - if (G_GDEBUG) { - var z = "urlcanonicalizer UNITTEST"; - G_debugService.enableZone(z); - - G_Debug(z, "Starting"); - - - // ------ TEST HEX GOTCHA ------ - - var hexify = PROT_URLCanonicalizer.toHex_; - var shouldHaveLeadingZeros = hexify(0) + hexify(1); - G_Assert(z, shouldHaveLeadingZeros == "0001", - "Need to append leading zeros to hex rep value <= 15 !") - - - // ------ TEST DECODING ------ - - // For convenience, shorten the function name - var dec = PROT_URLCanonicalizer.fullyDecodeURLAsString_; - - // Test empty string - G_Assert(z, dec("") == "", "decoding empty string"); - - // Test decoding of all characters - var allCharsEncoded = ""; - var allCharsEncodedLowercase = ""; - var allCharsAsString = ""; - // Special case null - allCharsEncoded += "%01"; - allCharsEncodedLowercase += "%01"; - allCharsAsString += String.fromCharCode(1); - for (var i = 1; i < 256; i++) { - allCharsEncoded += "%" + PROT_URLCanonicalizer.toHex_(i); - allCharsEncodedLowercase += "%" + - PROT_URLCanonicalizer.toHex_(i).toLowerCase(); - allCharsAsString += String.fromCharCode(i); - } - G_Assert(z, dec(allCharsEncoded) == allCharsAsString, "decoding escaped"); - G_Assert(z, dec(allCharsEncodedLowercase) == allCharsAsString, - "decoding lowercase"); - - // Test %-related edge cases - G_Assert(z, dec("%") == "%", "1 percent"); - G_Assert(z, dec("%xx") == "%xx", "1 percent, two non-hex"); - G_Assert(z, dec("%%") == "%%", "2 percent"); - G_Assert(z, dec("%%%") == "%%%", "3 percent"); - G_Assert(z, dec("%%%%") == "%%%%", "4 percent"); - G_Assert(z, dec("%1") == "%1", "1 percent, one nonhex"); - G_Assert(z, dec("%1z") == "%1z", "1 percent, two nonhex"); - G_Assert(z, dec("a%1z") == "a%1z", "nonhex, 1 percent, two nonhex"); - G_Assert(z, dec("abc%d%e%fg%hij%klmno%") == "abc%d%e%fg%hij%klmno%", - "lots of percents, no hex"); - - // Test repeated %-decoding. Note: %25 --> %, %32 --> 2, %35 --> 5 - G_Assert(z, dec("%25") == "%", "single-encoded %"); - G_Assert(z, dec("%25%32%35") == "%", "double-encoded %"); - G_Assert(z, dec("asdf%25%32%35asd") == "asdf%asd", "double-encoded % 2"); - G_Assert(z, dec("%%%25%32%35asd%%") == "%%%asd%%", "double-encoded % 3"); - G_Assert(z, dec("%25%32%35%25%32%35%25%32%35") == "%%%", - "sequenctial double-encoded %"); - G_Assert(z, dec("%2525252525252525") == "%", "many-encoded %"); - G_Assert(z, dec("%257Ea%2521b%2540c%2523d%2524e%25f%255E00%252611%252A22%252833%252944_55%252B") == "~a!b@c#d$e%f^00&11*22(33)44_55+", - "4x-encoded string"); - - - // ------ TEST ENCODING ------ - - // For convenience, shorten the function name - var enc = PROT_URLCanonicalizer.specialEncodeURL_; - - // Test empty string - G_Assert(z, enc([]) == "", "encoding empty array"); - - // Test that all characters we shouldn't encode ([33-36],[38,126]) are not. - var no = []; - var noAsString = ""; - for (var i = 33; i < 127; i++) - if (i != 37) { // skip % - no.push(i); - noAsString += String.fromCharCode(i); - } - G_Assert(z, enc(no) == noAsString, "chars to not encode"); - - // Test that all the chars that we should encode [0,32],37,[127,255] are - var yes = []; - var yesAsString = ""; - var yesExpectedString = ""; - // Special case 0 - yes.push(0); - yesAsString += String.fromCharCode(1); - yesExpectedString += "%01"; - for (var i = 1; i < 256; i++) - if (i < 33 || i == 37 || i > 126) { - yes.push(i); - yesAsString += String.fromCharCode(i); - var hex = i.toString(16).toUpperCase(); - yesExpectedString += "%" + ((i < 16) ? "0" : "") + hex; - } - G_Assert(z, enc(yes) == yesExpectedString, "chars to encode"); - // Can't use decodeURIComponent or encodeURIComponent to test b/c UTF-8 - - - // ------ TEST COMPOSITION ------ - - // For convenience, shorten function name: - var c = PROT_URLCanonicalizer.canonicalizeURL_; - - G_Assert(z, c("http://www.google.com") == "http://www.google.com", - "http://www.google.com"); - G_Assert(z, c("http://%31%36%38%2e%31%38%38%2e%39%39%2e%32%36/%2E%73%65%63%75%72%65/%77%77%77%2E%65%62%61%79%2E%63%6F%6D/") == "http://168.188.99.26/.secure/www.ebay.com/", - "fully encoded ebay"); - G_Assert(z, c("http://195.127.0.11/uploads/%20%20%20%20/.verify/.eBaysecure=updateuserdataxplimnbqmn-xplmvalidateinfoswqpcmlx=hgplmcx/") == "http://195.127.0.11/uploads/%20%20%20%20/.verify/.eBaysecure=updateuserdataxplimnbqmn-xplmvalidateinfoswqpcmlx=hgplmcx/", - "long url with spaces that stays same"); - - // TODO: MORE! - - G_Debug(z, "PASSED"); - } -} -#endif diff --git a/toolkit/components/url-classifier/public/Makefile.in b/toolkit/components/url-classifier/public/Makefile.in index a0a185bb..65193d2a 100644 --- a/toolkit/components/url-classifier/public/Makefile.in +++ b/toolkit/components/url-classifier/public/Makefile.in @@ -11,6 +11,7 @@ XPIDL_MODULE = url-classifier XPIDLSRCS = nsIUrlClassifierDBService.idl \ nsIUrlClassifierStreamUpdater.idl \ nsIUrlClassifierTable.idl \ + nsIUrlClassifierUtils.idl \ nsIUrlListManager.idl \ $(NULL) diff --git a/toolkit/components/url-classifier/public/nsIUrlClassifierUtils.idl b/toolkit/components/url-classifier/public/nsIUrlClassifierUtils.idl new file mode 100644 index 00000000..0795df79 --- /dev/null +++ b/toolkit/components/url-classifier/public/nsIUrlClassifierUtils.idl @@ -0,0 +1,57 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Google, Inc. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" +/** + * Some utility methods used by the url classifier. + */ + +[scriptable, uuid(9afd3add-eadc-409f-a187-e3bf60e47290)] +interface nsIUrlClassifierUtils : nsISupports +{ + /** + * Canonicalize a URL. DON'T USE THIS DIRECTLY. Use + * PROT_EnchashDecrypter.prototype.getCanonicalUrl instead. This method + * url-decodes a string, but it doesn't normalize the hostname. The method + * in EnchashDecrypter first calls this method, then normalizes the hostname. + * + * @param url String to canonicalize + * + * @returns String containing the canonicalized url (maximally url-decoded, + * then specially url-encoded) + */ + ACString canonicalizeURL(in ACString url); +}; diff --git a/toolkit/components/url-classifier/src/Makefile.in b/toolkit/components/url-classifier/src/Makefile.in index 705b3782..204f7bf3 100644 --- a/toolkit/components/url-classifier/src/Makefile.in +++ b/toolkit/components/url-classifier/src/Makefile.in @@ -21,6 +21,7 @@ REQUIRES = necko \ CPPSRCS = \ nsUrlClassifierDBService.cpp \ nsUrlClassifierStreamUpdater.cpp \ + nsUrlClassifierUtils.cpp \ $(NULL) LOCAL_INCLUDES = \ diff --git a/toolkit/components/url-classifier/src/nsUrlClassifierDBService.cpp b/toolkit/components/url-classifier/src/nsUrlClassifierDBService.cpp index bbe1ca30..f739fb87 100644 --- a/toolkit/components/url-classifier/src/nsUrlClassifierDBService.cpp +++ b/toolkit/components/url-classifier/src/nsUrlClassifierDBService.cpp @@ -86,6 +86,10 @@ static PRMonitor *gMonitor = nsnull; // Thread that we do the updates on. static PRThread* gDbBackgroundThread = nsnull; +// Once we've committed to shutting down, don't do work in the background +// thread. +static PRBool gShuttingDownThread = PR_FALSE; + static const char* kNEW_TABLE_SUFFIX = "_new"; @@ -264,6 +268,9 @@ nsUrlClassifierDBServiceWorker::Exists(const nsACString& tableName, const nsACString& key, nsIUrlClassifierCallback *c) { + if (gShuttingDownThread) + return NS_ERROR_NOT_INITIALIZED; + nsresult rv = OpenDb(); if (NS_FAILED(rv)) { NS_ERROR("Unable to open database"); @@ -309,6 +316,9 @@ NS_IMETHODIMP nsUrlClassifierDBServiceWorker::CheckTables(const nsACString & tableNames, nsIUrlClassifierCallback *c) { + if (gShuttingDownThread) + return NS_ERROR_NOT_INITIALIZED; + nsresult rv = OpenDb(); if (NS_FAILED(rv)) { NS_ERROR("Unable to open database"); @@ -351,6 +361,9 @@ NS_IMETHODIMP nsUrlClassifierDBServiceWorker::UpdateTables(const nsACString& updateString, nsIUrlClassifierCallback *c) { + if (gShuttingDownThread) + return NS_ERROR_NOT_INITIALIZED; + LOG(("Updating tables\n")); nsresult rv = OpenDb(); @@ -498,6 +511,11 @@ nsUrlClassifierDBServiceWorker::Finish(nsIUrlClassifierCallback *c) if (!mHasPendingUpdate) return NS_OK; + if (gShuttingDownThread) { + mConnection->RollbackTransaction(); + return NS_ERROR_NOT_INITIALIZED; + } + nsresult rv = NS_OK; for (PRUint32 i = 0; i < mTableUpdateLines.Length(); ++i) { rv = MaybeSwapTables(mTableUpdateLines[i]); @@ -843,8 +861,10 @@ PR_STATIC_CALLBACK(void) DestroyHandler(PLEvent *ev); nsUrlClassifierDBService::~nsUrlClassifierDBService() { sUrlClassifierDBService = nsnull; - PR_DestroyMonitor(gMonitor); - gMonitor = nsnull; + if (gMonitor) { + PR_DestroyMonitor(gMonitor); + gMonitor = nsnull; + } } nsresult @@ -883,7 +903,8 @@ nsUrlClassifierDBService::Init() if (!observerService) return NS_ERROR_FAILURE; - observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE); + observerService->AddObserver(this, "profile-before-change", PR_FALSE); + observerService->AddObserver(this, "xpcom-shutdown", PR_FALSE); return NS_OK; } @@ -1056,9 +1077,12 @@ NS_IMETHODIMP nsUrlClassifierDBService::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData) { - if (nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) { - Shutdown(); - } + NS_ASSERTION(strcmp(aTopic, "profile-before-change") == 0 || + strcmp(aTopic, "xpcom-shutdown") == 0, + "Unexpected observer topic"); + + Shutdown(); + return NS_OK; } @@ -1082,6 +1106,11 @@ nsUrlClassifierDBService::EnsureThreadStarted() nsresult nsUrlClassifierDBService::Shutdown() { + LOG(("shutting down db service\n")); + + if (!gDbBackgroundThread) + return NS_OK; + nsresult rv; EnsureThreadStarted(); @@ -1095,8 +1124,10 @@ nsUrlClassifierDBService::Shutdown() mWorker, PROXY_ASYNC, getter_AddRefs(proxy)); - proxy->CloseDb(); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_SUCCEEDED(rv)) { + rv = proxy->CloseDb(); + NS_ASSERTION(NS_SUCCEEDED(rv), "failed to post close db event"); + } } PLEvent* ev = new PLEvent; @@ -1107,8 +1138,9 @@ nsUrlClassifierDBService::Shutdown() } LOG(("joining background thread")); - rv = PR_JoinThread(gDbBackgroundThread); - NS_ASSERTION(NS_SUCCEEDED(rv), "failed to join background thread"); + gShuttingDownThread = PR_TRUE; + PRStatus ok = PR_JoinThread(gDbBackgroundThread); + NS_ASSERTION(ok == PR_SUCCESS, "failed to join background thread"); gDbBackgroundThread = nsnull; return NS_OK; diff --git a/toolkit/components/url-classifier/src/nsUrlClassifierTable.js b/toolkit/components/url-classifier/src/nsUrlClassifierTable.js index 5a2465e6..43b5ba64 100644 --- a/toolkit/components/url-classifier/src/nsUrlClassifierTable.js +++ b/toolkit/components/url-classifier/src/nsUrlClassifierTable.js @@ -42,7 +42,6 @@ const Ci = Components.interfaces; #include ../content/js/lang.js #include ../content/enchash-decrypter.js #include ../content/multi-querier.js -#include ../content/url-canonicalizer.js #include ../content/trtable.js var modScope = this; diff --git a/toolkit/components/url-classifier/src/nsUrlClassifierUtils.cpp b/toolkit/components/url-classifier/src/nsUrlClassifierUtils.cpp new file mode 100644 index 00000000..2a269abc --- /dev/null +++ b/toolkit/components/url-classifier/src/nsUrlClassifierUtils.cpp @@ -0,0 +1,103 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Url Classifier code + * + * The Initial Developer of the Original Code is + * Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsEscape.h" +#include "nsString.h" +#include "nsUrlClassifierUtils.h" + +static char int_to_hex_digit(PRInt32 i) +{ + NS_ASSERTION((i >= 0) && (i <= 15), "int too big in int_to_hex_digit"); + return NS_STATIC_CAST(char, ((i < 10) ? (i + '0') : ((i - 10) + 'A'))); +} + + +nsUrlClassifierUtils::nsUrlClassifierUtils() +{ +} + +NS_IMPL_ISUPPORTS1(nsUrlClassifierUtils, nsIUrlClassifierUtils) + +/* ACString canonicalizeURL (in ACString url); */ +NS_IMETHODIMP +nsUrlClassifierUtils::CanonicalizeURL(const nsACString & url, nsACString & _retval) +{ + nsCAutoString decodedUrl(url); + nsCAutoString temp; + while (NS_UnescapeURL(decodedUrl.get(), decodedUrl.Length(), 0, temp)) { + decodedUrl.Assign(temp); + temp.Truncate(); + } + SpecialEncode(decodedUrl, _retval); + return NS_OK; +} + +// This function will encode all "special" characters in typical url +// encoding, that is %hh where h is a valid hex digit. See the comment in +// the header file for details. +PRBool +nsUrlClassifierUtils::SpecialEncode(const nsACString & url, nsACString & _retval) +{ + PRBool changed = PR_FALSE; + const char* curChar = url.BeginReading(); + const char* end = url.EndReading(); + + while (curChar != end) { + unsigned char c = NS_STATIC_CAST(unsigned char, *curChar); + if (ShouldURLEscape(c)) { + // We don't want to deal with 0, as it can break certain strings, just + // encode as one. + if (c == 0) + c = 1; + + _retval.Append('%'); + _retval.Append(int_to_hex_digit(c / 16)); + _retval.Append(int_to_hex_digit(c % 16)); + + changed = PR_TRUE; + } else { + _retval.Append(*curChar); + } + curChar++; + } + return changed; +} + +PRBool +nsUrlClassifierUtils::ShouldURLEscape(const unsigned char c) const +{ + return c <= 32 || c == '%' || c >=127; +} diff --git a/toolkit/components/url-classifier/src/nsUrlClassifierUtils.h b/toolkit/components/url-classifier/src/nsUrlClassifierUtils.h new file mode 100644 index 00000000..e9b0958c --- /dev/null +++ b/toolkit/components/url-classifier/src/nsUrlClassifierUtils.h @@ -0,0 +1,67 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Url Classifier code + * + * The Initial Developer of the Original Code is + * Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsUrlClassifierUtils_h_ +#define nsUrlClassifierUtils_h_ + +#include "nsIUrlClassifierUtils.h" + +class nsUrlClassifierUtils : public nsIUrlClassifierUtils +{ +public: + nsUrlClassifierUtils(); + ~nsUrlClassifierUtils() {}; + + NS_DECL_ISUPPORTS + NS_DECL_NSIURLCLASSIFIERUTILS + + // This function will encode all "special" characters in typical url encoding, + // that is %hh where h is a valid hex digit. The characters which are encoded + // by this function are any ascii characters under 32(control characters and + // space), 37(%), and anything 127 or above (special characters). Url is the + // string to encode, ret is the encoded string. Function returns true if + // ret != url. + PRBool SpecialEncode(const nsACString & url, nsACString & _retval); + +private: + // Disallow copy constructor + nsUrlClassifierUtils(const nsUrlClassifierUtils&); + + // Function to tell if we should encode a character. + PRBool ShouldURLEscape(const unsigned char c) const; +}; + +#endif // nsUrlClassifierUtils_h_ diff --git a/toolkit/components/url-classifier/tests/Makefile.in b/toolkit/components/url-classifier/tests/Makefile.in index 6bc0c7f6..4b7bac8b 100644 --- a/toolkit/components/url-classifier/tests/Makefile.in +++ b/toolkit/components/url-classifier/tests/Makefile.in @@ -43,5 +43,39 @@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk +MODULE = test_url-classifier + +MOZILLA_INTERNAL_API = 1 + +REQUIRES = \ + string \ + url-classifier \ + xpcom \ + $(NULL) + +# simple c++ tests (no xpcom) +CPPSRCS = \ + TestUrlClassifierUtils.cpp \ + $(NULL) + +SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) + +LOCAL_INCLUDES = \ + -I$(srcdir)/../src \ + -I$(srcdir)/../public \ + $(NULL) + +LIBS = \ + ../src/$(LIB_PREFIX)urlclassifier_s.$(LIB_SUFFIX) \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + include $(topsrcdir)/config/rules.mk +check:: + @echo Running tests... + @$(EXIT_ON_ERROR) \ + for f in $(SIMPLE_PROGRAMS); do \ + $(RUN_TEST_PROGRAM) $(DIST)/bin/$$f; \ + done diff --git a/toolkit/components/url-classifier/tests/TestUrlClassifierUtils.cpp b/toolkit/components/url-classifier/tests/TestUrlClassifierUtils.cpp new file mode 100644 index 00000000..1d0f07da --- /dev/null +++ b/toolkit/components/url-classifier/tests/TestUrlClassifierUtils.cpp @@ -0,0 +1,195 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Url Classifier code + * + * The Initial Developer of the Original Code is + * Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include +#include "nsEscape.h" +#include "nsString.h" +#include "nsUrlClassifierUtils.h" + +static int gTotalTests = 0; +static int gPassedTests = 0; + +static char int_to_hex_digit(PRInt32 i) { + NS_ASSERTION((i >= 0) && (i <= 15), "int too big in int_to_hex_digit"); + return NS_STATIC_CAST(char, ((i < 10) ? (i + '0') : ((i - 10) + 'A'))); +} + +static void CheckEquals(nsCString & expected, nsCString & actual) +{ + if (!(expected).Equals((actual))) { + fprintf(stderr, "FAILED: expected |%s| but was |%s|\n", (expected).get(), + (actual).get()); + } else { + gPassedTests++; + } + gTotalTests++; +} + +void TestUnescapeHelper(const char* in, const char* expected) +{ + nsCString out, strIn(in), strExp(expected); + nsUrlClassifierUtils utils; + + NS_UnescapeURL(strIn.get(), strIn.Length(), esc_AlwaysCopy, out); + CheckEquals(strExp, out); +} + +// Make sure Unescape from nsEncode.h's unescape does what the server does. +void TestUnescape() +{ + // test empty string + TestUnescapeHelper("\0", "\0"); + + // Test docoding of all characters. + nsCString allCharsEncoded, allCharsEncodedLowercase, allCharsAsString; + for (PRInt32 i = 1; i < 256; ++i) { + allCharsEncoded.Append('%'); + allCharsEncoded.Append(int_to_hex_digit(i / 16)); + allCharsEncoded.Append((int_to_hex_digit(i % 16))); + + allCharsEncodedLowercase.Append('%'); + allCharsEncodedLowercase.Append(tolower(int_to_hex_digit(i / 16))); + allCharsEncodedLowercase.Append(tolower(int_to_hex_digit(i % 16))); + + allCharsAsString.Append(NS_STATIC_CAST(char, i)); + } + + nsUrlClassifierUtils utils; + nsCString out; + NS_UnescapeURL(allCharsEncoded.get(), allCharsEncoded.Length(), esc_AlwaysCopy, out); + CheckEquals(allCharsAsString, out); + + out.Truncate(); + NS_UnescapeURL(allCharsEncodedLowercase.get(), allCharsEncodedLowercase.Length(), esc_AlwaysCopy, out); + CheckEquals(allCharsAsString, out); + + // Test %-related edge cases + TestUnescapeHelper("%", "%"); + TestUnescapeHelper("%xx", "%xx"); + TestUnescapeHelper("%%", "%%"); + TestUnescapeHelper("%%%", "%%%"); + TestUnescapeHelper("%%%%", "%%%%"); + TestUnescapeHelper("%1", "%1"); + TestUnescapeHelper("%1z", "%1z"); + TestUnescapeHelper("a%1z", "a%1z"); + TestUnescapeHelper("abc%d%e%fg%hij%klmno%", "abc%d%e%fg%hij%klmno%"); + + // A few more tests + TestUnescapeHelper("%25", "%"); + TestUnescapeHelper("%25%32%35", "%25"); +} + +void TestEncodeHelper(const char* in, const char* expected) +{ + nsCString out, strIn(in), strExp(expected); + nsUrlClassifierUtils utils; + + utils.SpecialEncode(strIn, out); + CheckEquals(strExp, out); +} + +void TestEnc() +{ + // Test empty string + TestEncodeHelper("", ""); + + // Test that all characters we shouldn't encode ([33-36],[38,126]) are not. + nsCString noenc; + for (PRInt32 i = 33; i < 127; i++) { + if (i != 37) { // skip % + noenc.Append(NS_STATIC_CAST(char, i)); + } + } + nsUrlClassifierUtils utils; + nsCString out; + utils.SpecialEncode(noenc, out); + CheckEquals(noenc, out); + + // Test that all the chars that we should encode [0,32],37,[127,255] are + nsCString yesAsString, yesExpectedString; + for (PRInt32 i = 1; i < 256; i++) { + if (i < 33 || i == 37 || i > 126) { + yesAsString.Append(NS_STATIC_CAST(char, i)); + yesExpectedString.Append('%'); + yesExpectedString.Append(int_to_hex_digit(i / 16)); + yesExpectedString.Append(int_to_hex_digit(i % 16)); + } + } + + out.Truncate(); + utils.SpecialEncode(yesAsString, out); + CheckEquals(yesExpectedString, out); +} + +void TestCanonicalizeHelper(const char* in, const char* expected) +{ + nsCString out, strIn(in), strExp(expected); + nsUrlClassifierUtils utils; + + nsresult rv = utils.CanonicalizeURL(strIn, out); + NS_ASSERTION(rv == NS_OK, "com didn't return NS_OK"); + CheckEquals(strExp, out); +} + +void TestCanonicalize() +{ + // Test repeated %-decoding. Note: %25 --> %, %32 --> 2, %35 --> 5 + TestCanonicalizeHelper("%25", "%25"); + TestCanonicalizeHelper("%25%32%35", "%25"); + TestCanonicalizeHelper("asdf%25%32%35asd", "asdf%25asd"); + TestCanonicalizeHelper("%%%25%32%35asd%%", "%25%25%25asd%25%25"); + TestCanonicalizeHelper("%25%32%35%25%32%35%25%32%35", "%25%25%25"); + TestCanonicalizeHelper("%25", "%25"); + TestCanonicalizeHelper("%257Ea%2521b%2540c%2523d%2524e%25f%255E00%252611%252A22%252833%252944_55%252B", + "~a!b@c#d$e%25f^00&11*22(33)44_55+"); + + TestCanonicalizeHelper("", ""); + TestCanonicalizeHelper("http://www.google.com", "http://www.google.com"); + TestCanonicalizeHelper("http://%31%36%38%2e%31%38%38%2e%39%39%2e%32%36/%2E%73%65%63%75%72%65/%77%77%77%2E%65%62%61%79%2E%63%6F%6D/", + "http://168.188.99.26/.secure/www.ebay.com/"); + TestCanonicalizeHelper("http://195.127.0.11/uploads/%20%20%20%20/.verify/.eBaysecure=updateuserdataxplimnbqmn-xplmvalidateinfoswqpcmlx=hgplmcx/", + "http://195.127.0.11/uploads/%20%20%20%20/.verify/.eBaysecure=updateuserdataxplimnbqmn-xplmvalidateinfoswqpcmlx=hgplmcx/"); +} + +int main(int argc, char **argv) +{ + TestUnescape(); + TestEnc(); + TestCanonicalize(); + printf("%d of %d tests passed\n", gPassedTests, gTotalTests); + return (gPassedTests != gTotalTests); +} diff --git a/toolkit/content/charsetOverlay.js b/toolkit/content/charsetOverlay.js index 7dcbabf3..420936e1 100644 --- a/toolkit/content/charsetOverlay.js +++ b/toolkit/content/charsetOverlay.js @@ -126,21 +126,19 @@ function SetForcedCharset(charset) var gPrevCharset = null; function UpdateCurrentCharset() { - var menuitem = null; - - // exctract the charset from DOM + // extract the charset from DOM var wnd = document.commandDispatcher.focusedWindow; if ((window == wnd) || (wnd == null)) wnd = window.content; - menuitem = document.getElementById('charset.' + wnd.document.characterSet); + // Uncheck previous item + if (gPrevCharset) { + var pref_item = document.getElementById('charset.' + gPrevCharset); + if (pref_item) + pref_item.setAttribute('checked', 'false'); + } + + var menuitem = document.getElementById('charset.' + wnd.document.characterSet); if (menuitem) { - // uncheck previously checked item to workaround Mac checkmark problem - // bug 98625 - if (gPrevCharset) { - var pref_item = document.getElementById('charset.' + gPrevCharset); - if (pref_item) - pref_item.setAttribute('checked', 'false'); - } menuitem.setAttribute('checked', 'true'); } } diff --git a/toolkit/content/commonDialog.js b/toolkit/content/commonDialog.js index 4d1eac59..d4463f94 100644 --- a/toolkit/content/commonDialog.js +++ b/toolkit/content/commonDialog.js @@ -221,7 +221,7 @@ function commonDialogFocus(aEvent) var script = "document.documentElement.getButton('accept').disabled = false; "; script += "document.documentElement.getButton('extra1').disabled = false; "; script += "document.documentElement.getButton('extra2').disabled = false;"; - setTimeout(script, 250); + setTimeout(script, 1000); } } diff --git a/toolkit/content/contentAreaUtils.js b/toolkit/content/contentAreaUtils.js index 17c8425e..5361849b 100644 --- a/toolkit/content/contentAreaUtils.js +++ b/toolkit/content/contentAreaUtils.js @@ -334,7 +334,7 @@ function internalSave(aURL, aDocument, aDefaultFileName, aContentDisposition, saveAsType == kSaveAsType_Text) ? "text/plain" : aContentType, target : fileURL, - postData : isDocument ? getPostData() : null, + postData : isDocument ? getPostData(aDocument) : null, bypassCache : aShouldBypassCache }; @@ -707,14 +707,16 @@ function appendFiltersForContentType(aFilePicker, aContentType, aFileExtension, aFilePicker.appendFilters(Components.interfaces.nsIFilePicker.filterAll); } - -function getPostData() +function getPostData(aDocument) { try { - var sessionHistory = getWebNavigation().sessionHistory; - var entry = sessionHistory.getEntryAtIndex(sessionHistory.index, false); - entry = entry.QueryInterface(Components.interfaces.nsISHEntry); - return entry.postData; + var sessionHistory = aDocument.defaultView + .QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIWebNavigation) + .sessionHistory; + return sessionHistory.getEntryAtIndex(sessionHistory.index, false) + .QueryInterface(Components.interfaces.nsISHEntry) + .postData; } catch (e) { } @@ -900,6 +902,9 @@ function getNormalizedLeafName(aFile, aDefaultExtension) // Remove trailing dots and spaces on windows aFile = aFile.replace(/[\s.]+$/, ""); #endif + + // Remove leading dots + aFile = aFile.replace(/^\.+/, ""); // Fix up the file name we're saving to to include the default extension var i = aFile.lastIndexOf("."); diff --git a/toolkit/content/license.html b/toolkit/content/license.html index e8b63aab..ba93122d 100644 --- a/toolkit/content/license.html +++ b/toolkit/content/license.html @@ -701,11 +701,12 @@ under either the MPL or the [___] License."

- Aaron Leventhal, +Aaron Schulman, ActiveState Tool Corp, Akkana Peck, Alex Fritze, @@ -714,6 +715,7 @@ Alexander Surkov, Andreas Otte, Andreas Premstaller, Andrew Thompson, +ArentJan Banck, Asaf Romano, Axel Hecht, Ben Bucksch, @@ -727,9 +729,12 @@ Brendan Eich, Brian Bober, Brian Ryner, Brian Stell, +Bruce Davidson, Bruno Haible, +Calum Robinson, Cedric Chantepie, Chiaki Koufugata, +Chris McAfee, Christian Biesinger, Christopher A. Aillon, Christopher Blizzard, @@ -740,6 +745,7 @@ Conrad Carlen, Crocodile Clips Ltd, Cyrus Patel, Dainis Jonitis, +Dan Mosedale, Daniel Brooks, Daniel Glazman, Daniel Kouril, @@ -756,18 +762,20 @@ Digital Creations 2 Inc, Doron Rosenberg, Doug Turner, Elika J. Etemad, +Eric Belhaire, Eric Hodel, Esben Mose Hansen, Frank Schönheit, Fredrik Holmqvist, Gavin Sharp, +Geoff Beier, Gervase Markham, Giorgio Maone, -Google, Google Inc, +Håkan Waara, +Henri Torgemane, Heriot-Watt University, Hewlett-Packard Company, -Håkan Waara, i-DNS.net International, Ian Hickson, Ian Oeschger, @@ -780,8 +788,10 @@ James Ross, Jamie Zawinski, Jan Varga, Jason Barnabe, +Jean-Francois Ducarroz, Jeff Tsai, Jeff Walden, +Jefferson Software Inc, Joe Hewitt, Joey Minta, John B. Keiser, @@ -790,27 +800,36 @@ John Fairhurst, John Wolfe, Jonas Sicking, Jonathan Watt, +Josh Aas, Josh Soref, Juan Lang, Jungshik Shin, +Jussi Kukkonen, Karsten Düsterloh, Keith Visco, Ken Herron, +Kevin Gerich, Kipp E.B. Hickman, L. David Baron, Lixto GmbH, Makoto Kato, +Marc Bevand, Marco Manfredini, Marco Pesenti Gritti, Mark Hammond, Mark Mentovai, Markus G. Kuhn, +Matt Judy, +Matthew Willis, +Merle Sterling, Michael J. Fromberger, Michal Ceresna, Michiel van Leeuwen, Mike Connor, Mike Pinkerton, +Mike Potter, Mike Shaver, +MITRE Corporation, Mozdev Group, Mozilla Corporation, Mozilla Foundation, @@ -822,16 +841,21 @@ Netscape Commmunications Corp, Netscape Communications Corporation, New Dimensions Consulting, Novell Inc, +OEone Corporation, Olli Pettay, Oracle Corporation, Owen Taylor, Paul Ashford, -Paul Kocher of Cryptography Research, +Paul Kocher, Paul Sandoz, Peter Annema, Peter Hartshorn, Peter Van der Beken, +Phil Ringnalda, +Philipp Kewisch, Pierre Chanial, +Prachi Gauriar, +Qualcomm Inc, R.J. Keller, Rajiv Dayal, Ramalingam Saravanan, @@ -858,25 +882,29 @@ Sergei Dolgov, Seth Spitzer, Shy Shalom, Silverstone Interactive, +Simdesk Technologies Inc, Simon Bünzli, Simon Fraser, Simon Montagu, +Simon Paquet, Simon Wilkinson, +Sqlite Project, Srilatha Moturi, +Stefan Sitter, +Stephen Horlander, Steve Swanson, +Stuart Morgan, Stuart Parmenter, Sun Microsystems Inc, -The MITRE Corporation, -The Mozilla Corporation, -The sqlite Project, -The University of Queensland, Tim Copperfield, Tom Germeau, Tomas Müller, +University of Queensland, Vincent Béron, Vladimir Vukicevic, +Wolfgang Rosenauer, YAMASHITA Makoto, -Zack Rusin and +Zack Rusin, Zero-Knowledge Systems.

@@ -2175,8 +2203,13 @@ SOFTWARE.

Other Required Notices

-

This software is based in part on the work of the Independent - JPEG Group.

+
    +
  • This software is based in part on the work of the Independent + JPEG Group.
  • +
  • Portions of the OS/2 version of this software are copyright + ©1996-2002 The FreeType Project. + All rights reserved.
  • +

@@ -2213,7 +2246,7 @@ SOFTWARE. SupportSoft, Inc. All Rights Reserved.)
  • Image files containing the trademarks and logos of the Mozilla Foundation, which may not be reproduced without permission. - (Copyright ©2004-2007 The Mozilla Foundation. + (Copyright ©2004-2008 The Mozilla Foundation. All Rights Reserved.) diff --git a/toolkit/content/widgets/tabbrowser.xml b/toolkit/content/widgets/tabbrowser.xml index 77f8b99f..aad04106 100644 --- a/toolkit/content/widgets/tabbrowser.xml +++ b/toolkit/content/widgets/tabbrowser.xml @@ -599,12 +599,13 @@ // If location bar is hidden and the URL type supports a host, // add the scheme and host to the title to prevent spoofing. // XXX https://bugzilla.mozilla.org/show_bug.cgi?id=22183#c239 - // (only for schemes that support a host) try { if (docElement.getAttribute("chromehidden").indexOf("location") != -1) { var uri = this.mURIFixup.createExposableURI( this.mCurrentBrowser.currentURI); - if (uri.host) + if (uri.scheme == "about") + newTitle = uri.spec + sep + newTitle; + else newTitle = uri.prePath + sep + newTitle; } } catch (e) {} diff --git a/toolkit/content/widgets/textbox.xml b/toolkit/content/widgets/textbox.xml index 9eeb5e61..f35a9896 100644 --- a/toolkit/content/widgets/textbox.xml +++ b/toolkit/content/widgets/textbox.xml @@ -150,7 +150,7 @@ - + diff --git a/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in b/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in index 2773405e..01e16e0e 100644 --- a/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in +++ b/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in @@ -273,6 +273,10 @@ nsUnknownContentTypeDialog.prototype = { if (!aLocalFile || !aLocalFile.exists()) return null; + // Remove any leading periods, since we don't want to save hidden files + // automatically. + aLeafName = aLeafName.replace(/^\.+/, ""); + if (aLeafName == "") aLeafName = "unnamed" + (aFileExt ? "." + aFileExt : ""); aLocalFile.append(aLeafName); @@ -286,6 +290,7 @@ nsUnknownContentTypeDialog.prototype = { f.remove(false); this.makeFileUnique(aLocalFile); } + return aLocalFile; }, @@ -490,7 +495,7 @@ nsUnknownContentTypeDialog.prototype = { const nsITimer = Components.interfaces.nsITimer; this._timer = Components.classes["@mozilla.org/timer;1"] .createInstance(nsITimer); - this._timer.initWithCallback(this, 250, nsITimer.TYPE_ONE_SHOT); + this._timer.initWithCallback(this, 1000, nsITimer.TYPE_ONE_SHOT); }, _timer: null, @@ -591,7 +596,7 @@ nsUnknownContentTypeDialog.prototype = { this._blurred = false; if (this._delayExpired) { var script = "document.documentElement.getButton('accept').disabled = false"; - this.mDialog.setTimeout(script, 250); + this.mDialog.setTimeout(script, 1000); } }, diff --git a/toolkit/mozapps/extensions/content/extensions.js b/toolkit/mozapps/extensions/content/extensions.js index 0356437a..fd98f970 100644 --- a/toolkit/mozapps/extensions/content/extensions.js +++ b/toolkit/mozapps/extensions/content/extensions.js @@ -605,6 +605,11 @@ function Startup() catch (e) { if (window.arguments[0] == "updates-only") { gUpdatesOnly = true; +#ifdef MOZ_PHOENIX + // If we are a browser when updating on startup don't display context + // menuitems that can open a browser window. + gUpdateContextMenus = gUpdateContextMenusNoBrowser; +#endif document.getElementById("viewGroup").hidden = true; document.getElementById("extensionsView").setAttribute("norestart", ""); showView("updates"); @@ -1022,8 +1027,10 @@ var gAddonContextMenus = ["menuitem_useTheme", "menuitem_options", "menuitem_hom "menuitem_cancelUninstall", "menuitem_checkUpdate", "menuitem_enable", "menuitem_disable"]; var gUpdateContextMenus = ["menuitem_homepage", "menuitem_about", "menuseparator_1", - "menuitem_installUpdate", "menuitem_includeUpdate"] -var gInstallContextMenus = ["menuitem_homepage", "menuitem_about"] + "menuitem_installUpdate", "menuitem_includeUpdate"]; +// For browsers don't display context menuitems that can open a browser window. +var gUpdateContextMenusNoBrowser = ["menuitem_installUpdate", "menuitem_includeUpdate"]; +var gInstallContextMenus = ["menuitem_homepage", "menuitem_about"]; function buildContextMenu(aEvent) { diff --git a/toolkit/mozapps/extensions/src/nsExtensionManager.js.in b/toolkit/mozapps/extensions/src/nsExtensionManager.js.in index eb973956..c272533a 100644 --- a/toolkit/mozapps/extensions/src/nsExtensionManager.js.in +++ b/toolkit/mozapps/extensions/src/nsExtensionManager.js.in @@ -78,6 +78,9 @@ const PREF_BLOCKLIST_DETAILS_URL = "extensions.blocklist.detailsURL"; const PREF_BLOCKLIST_ENABLED = "extensions.blocklist.enabled"; const PREF_BLOCKLIST_INTERVAL = "extensions.blocklist.interval"; const PREF_UPDATE_NOTIFYUSER = "extensions.update.notifyUser"; +const PREF_GENERAL_USERAGENT_LOCALE = "general.useragent.locale"; +const PREF_PARTNER_BRANCH = "app.partner."; +const PREF_APP_UPDATE_CHANNEL = "app.update.channel"; const DIR_EXTENSIONS = "extensions"; const DIR_CHROME = "chrome"; @@ -166,6 +169,8 @@ var gPref = null; var gRDF = null; var gOS = null; var gXPCOMABI = null; +var gABI = null; +var gOSVersion = null; var gOSTarget = null; var gConsole = null; var gInstallManifestRoot = null; @@ -2328,6 +2333,60 @@ var StartupCache = { } }; +/** + * Gets the current value of the locale. It's possible for this preference to + * be localized, so we have to do a little extra work here. Similar code + * exists in nsHttpHandler.cpp when building the UA string. + */ +function getLocale() { + try { + // Get the default branch + var defaultPrefs = gPref.QueryInterface(Components.interfaces.nsIPrefService) + .getDefaultBranch(null); + return defaultPrefs.getCharPref(PREF_GENERAL_USERAGENT_LOCALE); + } catch (e) {} + + return gPref.getCharPref(PREF_GENERAL_USERAGENT_LOCALE); +} + +/** + * Read the update channel from defaults only. We do this to ensure that + * the channel is tightly coupled with the application and does not apply + * to other installations of the application that may use the same profile. + */ +function getUpdateChannel() { + var channel = "default"; + var prefName; + var prefValue; + + var defaults = + gPref.QueryInterface(Components.interfaces.nsIPrefService). + getDefaultBranch(null); + try { + channel = defaults.getCharPref(PREF_APP_UPDATE_CHANNEL); + } catch (e) { + // use default when pref not found + } + + try { + var partners = gPref.getChildList(PREF_PARTNER_BRANCH, { }); + if (partners.length) { + channel += "-cck"; + partners.sort(); + + for each (prefName in partners) { + prefValue = gPref.getCharPref(prefName); + channel += "-" + prefValue; + } + } + } + catch (e) { + Components.utils.reportError(e); + } + + return channel; +} + /** * Manages the Blocklist. The Blocklist is a representation of the contents of * blocklist.xml and allows us to remotely disable / re-enable blocklisted @@ -2366,6 +2425,19 @@ var Blocklist = { dsURI = dsURI.replace(/%APP_ID%/g, gApp.ID); dsURI = dsURI.replace(/%APP_VERSION%/g, gApp.version); + dsURI = dsURI.replace(/%PRODUCT%/g, gApp.name); + dsURI = dsURI.replace(/%VERSION%/g, gApp.version); + dsURI = dsURI.replace(/%BUILD_ID%/g, gApp.appBuildID); + dsURI = dsURI.replace(/%BUILD_TARGET%/g, gApp.OS + "_" + gABI); + dsURI = dsURI.replace(/%OS_VERSION%/g, gOSVersion); + dsURI = dsURI.replace(/%LOCALE%/g, getLocale()); + dsURI = dsURI.replace(/%CHANNEL%/g, getUpdateChannel()); + dsURI = dsURI.replace(/%PLATFORM_VERSION%/g, gApp.platformVersion); + // Distribution values are not present in 1.8 branch + dsURI = dsURI.replace(/%DISTRIBUTION%/g, "default"); + dsURI = dsURI.replace(/%DISTRIBUTION_VERSION%/g, "default"); + dsURI = dsURI.replace(/\+/g, "%2B"); + // Verify that the URI is valid try { var uri = newURI(dsURI); @@ -2658,6 +2730,38 @@ function ExtensionManager() { // transmitted to update URLs. gXPCOMABI = UNKNOWN_XPCOM_ABI; } + gABI = gXPCOMABI; + + var osVersion; + var sysInfo = Components.classes["@mozilla.org/system-info;1"] + .getService(Components.interfaces.nsIPropertyBag2); + try { + osVersion = sysInfo.getProperty("name") + " " + sysInfo.getProperty("version"); + } + catch (e) { + LOG("ExtensionManager: OS Version unknown."); + } + + if (osVersion) { + try { + osVersion += " (" + sysInfo.getProperty("secondaryLibrary") + ")"; + } + catch (e) { + // Not all platforms have a secondary widget library, so an error is nothing to worry about. + } + gOSVersion = encodeURIComponent(osVersion); + } + +#ifdef XP_MACOSX + // Mac universal build should report a different ABI than either macppc + // or mactel. + var macutils = Components.classes["@mozilla.org/xpcom/mac-utils;1"] + .getService(Components.interfaces.nsIMacUtils); + + if (macutils.isUniversalBinary) + gABI = "Universal-gcc3"; +#endif + gPref = Components.classes["@mozilla.org/preferences-service;1"] .getService(Components.interfaces.nsIPrefBranch2); @@ -2981,6 +3085,12 @@ ExtensionManager.prototype = { _installGlobalItem: function(file) { if (!file || !file.exists()) throw new Error("Unable to find the file specified on the command line!"); +#ifdef XP_WIN + // make sure the file is local on Windows + file.normalize(); + if (file.path[1] != ':') + throw new Error("Can't install global chrome from non-local file "+file.path); +#endif var installManifestFile = extractRDFFileToTempDir(file, FILE_INSTALL_MANIFEST, true); if (!installManifestFile.exists()) throw new Error("The package is missing an install manifest!"); @@ -3593,15 +3703,12 @@ ExtensionManager.prototype = { items = PendingOperations.getOperations(OP_NEEDS_UPGRADE); for (i = items.length - 1; i >= 0; --i) { id = items[i].id; - var oldLocation = this.getInstallLocation(id); var newLocation = InstallLocations.get(items[i].locationKey); - if (newLocation.priority <= oldLocation.priority) { - // check if there is updated app compatibility info - var newTargetAppInfo = ds.getUpdatedTargetAppInfo(id); - if (newTargetAppInfo) - updatedTargetAppInfos.push(newTargetAppInfo); - this._finalizeUpgrade(id); - } + // check if there is updated app compatibility info + var newTargetAppInfo = ds.getUpdatedTargetAppInfo(id); + if (newTargetAppInfo) + updatedTargetAppInfos.push(newTargetAppInfo); + this._finalizeUpgrade(id, newLocation); } PendingOperations.clearItems(OP_NEEDS_UPGRADE); @@ -4644,7 +4751,7 @@ ExtensionManager.prototype = { this._upgradeItem(installManifest, installData.id, installLocation, installData.type); if (!restartRequired) { - this._finalizeUpgrade(installData.id); + this._finalizeUpgrade(installData.id, installLocation); this._finalizeInstall(installData.id, stagedFile); } } @@ -4848,11 +4955,12 @@ ExtensionManager.prototype = { * Removes an item's metadata in preparation for an upgrade-install. * @param id * The GUID of the item to uninstall. + * @param installLocation + * The nsIInstallLocation of the item */ - _finalizeUpgrade: function(id) { + _finalizeUpgrade: function(id, installLocation) { // Retrieve the item properties *BEFORE* we clean the resource! var ds = this.datasource; - var installLocation = this.getInstallLocation(id); var stagedFile = null; if ("getStageFile" in installLocation) @@ -6132,12 +6240,15 @@ RDFItemUpdater.prototype = { this._versionUpdateOnly = aVersionUpdateOnly; this._item = aItem; - var itemStatus; + var itemStatus = "userEnabled"; if (emDS.getItemProperty(aItem.id, "userDisabled") == "true" || emDS.getItemProperty(aItem.id, "userDisabled") == OP_NEEDS_ENABLE) itemStatus = "userDisabled"; - else - itemStatus = "userEnabled"; + else if (emDS.getItemProperty(aItem.id, "type") == nsIUpdateItem.TYPE_THEME) { + var currentSkin = gPref.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN); + if (emDS.getItemProperty(aItem.id, "internalName") != currentSkin) + itemStatus = "userDisabled"; + } if (emDS.getItemProperty(aItem.id, "compatible") == "false") itemStatus += ",incompatible"; @@ -6926,16 +7037,6 @@ ExtensionsDataSource.prototype = { { // Update the Extensions datasource this.setTargetApplicationInfo(id, minVersion, maxVersion, null); - - var installLocation = InstallLocations.get(this.getInstallLocationKey(id)); - if (installLocation.name != KEY_APP_PROFILE) - return; - - var installManifestFile = installLocation.getItemFile(id, FILE_INSTALL_MANIFEST); - // Only update if the item exists and we can write to the location - if (installManifestFile.exists() && installLocation.canAccess) - this.setTargetApplicationInfo(id, minVersion, maxVersion, - getInstallManifest(installManifestFile)); }, /** diff --git a/toolkit/mozapps/installer/package-name.mk b/toolkit/mozapps/installer/package-name.mk index 64779b85..cda6e5e2 100644 --- a/toolkit/mozapps/installer/package-name.mk +++ b/toolkit/mozapps/installer/package-name.mk @@ -59,6 +59,25 @@ endif ifeq ($(OS_ARCH),OS2) MOZ_PKG_PLATFORM := os2 endif +ifeq ($(OS_ARCH), BeOS) +ifeq (,$(filter-out 6.%, $(OS_RELEASE))) +MOZ_PKG_PLATFORM := Zeta +else +ifeq (,$(filter-out 5.1, $(OS_RELEASE))) +MOZ_PKG_PLATFORM := BeOS-bone +else +ifeq (,$(filter-out 5.0.4, $(OS_RELEASE))) +MOZ_PKG_PLATFORM := BeOS-bone +else +ifeq (,$(filter-out 5.0, $(OS_RELEASE))) +MOZ_PKG_PLATFORM := BeOS-net_server +else +MOZ_PKG_PLATFORM := BeOS-$(OS_RELEASE) +endif # 5.0 +endif # 5.0.4 +endif # 5.1 +endif # 6. +endif # OS_ARCH BeOS # GTK2 is the default, so we mark gtk1 builds ifeq ($(MOZ_WIDGET_TOOLKIT),gtk) diff --git a/toolkit/mozapps/installer/packager.mk b/toolkit/mozapps/installer/packager.mk index 4a7a4312..51c13ec2 100644 --- a/toolkit/mozapps/installer/packager.mk +++ b/toolkit/mozapps/installer/packager.mk @@ -48,13 +48,15 @@ ifndef MOZ_PKG_FORMAT ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) MOZ_PKG_FORMAT = DMG else -ifeq (,$(filter-out OS2 WINNT, $(OS_ARCH))) +ifeq (,$(filter-out OS2 WINNT BeOS, $(OS_ARCH))) MOZ_PKG_FORMAT = ZIP ifeq ($(OS_ARCH),OS2) INSTALLER_DIR = os2 else +ifeq ($(OS_ARCH), WINNT) INSTALLER_DIR = windows endif +endif else ifeq (,$(filter-out SunOS, $(OS_ARCH))) MOZ_PKG_FORMAT = BZ2 @@ -125,8 +127,11 @@ _ABS_TOPSRCDIR = $(shell cd $(topsrcdir) && pwd) ifdef UNIVERSAL_BINARY STAGEPATH = universal/ endif +ifndef PKG_DMG_SOURCE +PKG_DMG_SOURCE = $(STAGEPATH)$(MOZ_PKG_APPNAME) +endif MAKE_PACKAGE = $(_ABS_TOPSRCDIR)/build/package/mac_osx/pkg-dmg \ - --source "$(STAGEPATH)$(MOZ_PKG_APPNAME)" --target "$(PACKAGE)" \ + --source "$(PKG_DMG_SOURCE)" --target "$(PACKAGE)" \ --volname "$(MOZ_APP_DISPLAYNAME)" $(PKG_DMG_FLAGS) UNMAKE_PACKAGE = \ set -ex; \ diff --git a/toolkit/mozapps/installer/windows/nsis/common.nsh b/toolkit/mozapps/installer/windows/nsis/common.nsh index 49c7a8eb..69205817 100644 --- a/toolkit/mozapps/installer/windows/nsis/common.nsh +++ b/toolkit/mozapps/installer/windows/nsis/common.nsh @@ -389,11 +389,11 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack !macroend !macro GetParentDir - Exch $R0 - Push $R1 - Push $R2 - Push $R3 - StrLen $R3 $R0 + Exch $R0 + Push $R1 + Push $R2 + Push $R3 + StrLen $R3 $R0 ${DoWhile} 1 > 0 IntOp $R1 $R1 - 1 ${If} $R1 <= -$R3 @@ -744,6 +744,7 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack * to this reg cleanup since the referenced key would be for an app that is no * longer installed on the system. * + * $R1 = stores the long path to $INSTDIR * $R2 = _KEY * $R3 = value returned from the outer loop's EnumRegKey * $R4 = value returned from the inner loop's EnumRegKey @@ -767,9 +768,11 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack Push $R5 Push $R6 Push $R7 + Push $R1 Push $R8 Push $R9 + ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR" $R1 StrCpy $R6 0 ; set the counter for the outer loop to 0 outerloop: @@ -797,8 +800,9 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack ${GetParentDir} Pop $R9 - IfFileExists "$R8" 0 +2 - StrCmp $R9 $INSTDIR 0 innerloop + IfFileExists "$R9" 0 +3 + ${${_MOZFUNC_UN}GetLongPath} "$R9" $R9 + StrCmp "$R9" "$R1" 0 innerloop ClearErrors DeleteRegKey SHCTX "$R2\$R3\$R4" IfErrors innerloop @@ -815,8 +819,9 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack ${GetParentDir} Pop $R9 - IfFileExists "$R8" 0 +2 - StrCmp $R9 $INSTDIR 0 outerloop + IfFileExists "$R9" 0 +3 + ${${_MOZFUNC_UN}GetLongPath} "$R9" $R9 + StrCmp "$R9" "$R1" 0 outerloop ClearErrors DeleteRegKey SHCTX "$R2\$R3" IfErrors outerloop @@ -830,6 +835,7 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack Pop $R9 Pop $R8 + Pop $R1 Pop $R7 Pop $R6 Pop $R5 @@ -877,6 +883,7 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack * Removes all registry keys from HKLM\Software\Windows\CurrentVersion\Uninstall * that reference this install location. * + * $R4 = stores the long path to $INSTDIR * $R5 = value returned from ReadRegStr * $R6 = string for the base reg key (e.g. Software\Microsoft\Windows\CurrentVersion\Uninstall) * $R7 = value returned from the EnumRegKey @@ -896,7 +903,9 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack Push $R7 Push $R6 Push $R5 + Push $R4 + ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR" $R4 StrCpy $R6 "Software\Microsoft\Windows\CurrentVersion\Uninstall" StrCpy $R8 0 StrCpy $R7 "" @@ -904,18 +913,19 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack loop: EnumRegKey $R7 HKLM $R6 $R8 StrCmp $R7 "" end - IntOp $R8 $R8 + 1 + IntOp $R8 $R8 + 1 ; Increment the counter ClearErrors ReadRegStr $R5 HKLM "$R6\$R7" "InstallLocation" IfErrors loop Push $R5 ${GetPathFromRegStr} Pop $R9 - StrCmp $R9 $INSTDIR 0 loop + ${${_MOZFUNC_UN}GetLongPath} "$R9" $R9 + StrCmp "$R9" "$R4" 0 loop ClearErrors DeleteRegKey HKLM "$R6\$R7" IfErrors loop - IntOp $R8 $R8 + 1 + IntOp $R8 $R8 - 1 ; Decrement the counter on successful deletion GoTo loop end: @@ -1071,6 +1081,9 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack /** * Writes a registry string using SHCTX and the supplied params and logs the * action to the install log and the uninstall log if _LOG_UNINSTALL equals 1. + * + * Define NO_LOG to prevent all logging when calling this from the uninstaller. + * * @param _ROOT * The registry key root as defined by NSIS (e.g. HKLM, HKCU, etc.). * This will only be used for logging. @@ -1176,6 +1189,9 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack /** * Writes a registry dword using SHCTX and the supplied params and logs the * action to the install log and the uninstall log if _LOG_UNINSTALL equals 1. + * + * Define NO_LOG to prevent all logging when calling this from the uninstaller. + * * @param _ROOT * The registry key root as defined by NSIS (e.g. HKLM, HKCU, etc.). * This will only be used for logging. @@ -1281,6 +1297,9 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack /** * Writes a registry string to HKCR using the supplied params and logs the * action to the install log and the uninstall log if _LOG_UNINSTALL equals 1. + * + * Define NO_LOG to prevent all logging when calling this from the uninstaller. + * * @param _ROOT * The registry key root as defined by NSIS (e.g. HKLM, HKCU, etc.). * This will only be used for logging. @@ -1399,6 +1418,9 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack * Creates a registry key. This will log the actions to the install and * uninstall logs. Alternatively you can set a registry value to create the key * and then delete the value. + * + * Define NO_LOG to prevent all logging when calling this from the uninstaller. + * * @param _ROOT * The registry key root as defined by NSIS (e.g. HKLM, HKCU, etc.). * @param _KEY @@ -1613,6 +1635,117 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack !endif !macroend +/** + * Finds an existing installation path of the application based on the + * application name so we can default to using this path for the install. If + * there is zero or more than one installation for the application then we + * default to the normal default path. This uses SHCTX to determine the + * registry hive so you must call SetShellVarContext first. + * + * IMPORTANT! $R9 will be overwritten by this macro with the return value so + * protect yourself! + * + * @param _KEY + * The registry subkey (typically this will be Software\Mozilla\App Name). + * @return _RESULT + * false if a single install location for this app name isn't found, + * path to the install directory if a single install location is found. + * + * $R5 = _KEY + * $R6 = value returned from EnumRegKey + * $R7 = value returned from ReadRegStr + * $R8 = counter for the loop's EnumRegKey + * $R9 = _RESULT + */ +!macro GetSingleInstallPath + + !ifndef ${_MOZFUNC_UN}GetSingleInstallPath + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}GetSingleInstallPath "!insertmacro ${_MOZFUNC_UN}GetSingleInstallPathCall" + + Function ${_MOZFUNC_UN}GetSingleInstallPath + Exch $R5 + Push $R6 + Push $R7 + Push $R8 + + StrCpy $R9 "false" + StrCpy $R8 0 ; set the counter for the loop to 0 + + loop: + ClearErrors + EnumRegKey $R6 SHCTX $R5 $R8 + IfErrors cleanup + StrCmp $R6 "" cleanup ; if empty there are no more keys to enumerate + IntOp $R8 $R8 + 1 ; increment the loop's counter + ClearErrors + ReadRegStr $R7 SHCTX "$R5\$R6\Main" "PathToExe" + IfErrors loop + GetFullPathName $R7 "$R7" + IfErrors loop + + + StrCmp "$R9" "false" 0 +3 + StrCpy $R9 "$R7" + GoTo Loop + + StrCpy $R9 "false" + + cleanup: + StrCmp $R9 "false" end + ${${_MOZFUNC_UN}GetParent} "$R9" $R9 + StrCpy $R8 $R9 "" -1 ; Copy the last char. + StrCmp $R8 '\' end ; Is it a \? + StrCpy $R9 "$R9\" ; Append \ to the string + + end: + ClearErrors + + Pop $R8 + Pop $R7 + Pop $R6 + Exch $R5 + Push $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro GetSingleInstallPathCall _KEY _RESULT + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_KEY}" + Call GetSingleInstallPath + Pop ${_RESULT} + !verbose pop +!macroend + +!macro un.GetSingleInstallPathCall _KEY _RESULT + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_KEY}" + Call un.GetSingleInstallPath + Pop ${_RESULT} + !verbose pop +!macroend + +!macro un.GetSingleInstallPath + !ifndef un.GetSingleInstallPath + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro GetSingleInstallPath + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + /** * Writes common registry values for a handler using SHCTX. * @param _KEY @@ -1673,9 +1806,13 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack DeleteRegValue SHCTX "$R4" "EditFlags" WriteRegDWord SHCTX "$R4" "EditFlags" 0x00000002 - StrCmp "$R9" "true" 0 +13 + StrCmp "$R6" "" +2 0 WriteRegStr SHCTX "$R4\DefaultIcon" "" "$R6" + + StrCmp "$R5" "" +2 0 WriteRegStr SHCTX "$R4\shell\open\command" "" "$R5" + + StrCmp "$R9" "true" 0 +11 WriteRegStr SHCTX "$R4\shell\open\ddeexec" "" "$\"%1$\",,0,0,,,," WriteRegStr SHCTX "$R4\shell\open\ddeexec" "NoActivateHandler" "" WriteRegStr SHCTX "$R4\shell\open\ddeexec\Application" "" "${DDEApplication}" @@ -1749,54 +1886,471 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack !macroend /** - * Displays a error message when a file can't be copied. - * - * $0 = file name inserted into the error message - */ -!macro DisplayCopyErrMsg +* Returns the path found within a passed in string. The path is quoted or not +* with the exception of an unquoted non 8dot3 path without arguments that is +* also not a DefaultIcon path, is a 8dot3 path or not, has command line +* arguments, or is a registry DefaultIcon path (e.g. ,# where # +* is the icon's resuorce id). The string does not need to be a valid path or +* exist. It is up to the caller to pass in a string of one of the forms noted +* above and to verify existence if necessary. +* +* IMPORTANT! $R9 will be overwritten by this macro with the return value so +* protect yourself! +* +* Examples: +* In: C:\PROGRA~1\MOZILL~1\FIREFOX.EXE -url "%1" -requestPending +* In: C:\PROGRA~1\MOZILL~1\FIREFOX.EXE,0 +* In: C:\PROGRA~1\MOZILL~1\FIREFOX.EXE +* In: "C:\PROGRA~1\MOZILL~1\FIREFOX.EXE" +* In: "C:\PROGRA~1\MOZILL~1\FIREFOX.EXE" -url "%1" -requestPending +* Out: C:\PROGRA~1\MOZILL~1\FIREFOX.EXE +* +* In: "C:\Program Files\Mozilla Firefox\firefox.exe" -url "%1" -requestPending +* In: C:\Program Files\Mozilla Firefox\firefox.exe,0 +* In: "C:\Program Files\Mozilla Firefox\firefox.exe" +* Out: C:\Program Files\Mozilla Firefox\firefox.exe +* +* @param _STRING +* The string containing the path +* @param _RESULT +* The register to store the path to. +* +* $R6 = counter for the outer loop's EnumRegKey +* $R7 = value returned from ReadRegStr +* $R8 = _STRING +* $R9 = _RESULT +*/ +!macro GetPathFromString - !ifndef ${_MOZFUNC_UN}DisplayCopyErrMsg + !ifndef ${_MOZFUNC_UN}GetPathFromString !verbose push !verbose ${_MOZFUNC_VERBOSE} - !define ${_MOZFUNC_UN}DisplayCopyErrMsg "!insertmacro ${_MOZFUNC_UN}DisplayCopyErrMsgCall" + !define ${_MOZFUNC_UN}GetPathFromString "!insertmacro ${_MOZFUNC_UN}GetPathFromStringCall" - Function ${_MOZFUNC_UN}DisplayCopyErrMsg - Exch $0 + Function ${_MOZFUNC_UN}GetPathFromString + Exch $R8 + Push $R7 + Push $R6 + ClearErrors - MessageBox MB_RETRYCANCEL|MB_ICONQUESTION "$(^FileError_NoIgnore)" IDRETRY +2 - Quit + StrCpy $R9 $R8 + StrCpy $R6 0 ; Set the counter to 0. - Exch $0 + ClearErrors + ; Handle quoted paths with arguments. + StrCpy $R7 $R9 1 ; Copy the first char. + StrCmp $R7 '"' +2 +1 ; Is it a "? + StrCmp $R7 "'" +1 +9 ; Is it a '? + StrCpy $R9 $R9 "" 1 ; Remove the first char. + IntOp $R6 $R6 + 1 ; Increment the counter. + StrCpy $R7 $R9 1 $R6 ; Starting from the counter copy the next char. + StrCmp $R7 "" end ; Are there no more chars? + StrCmp $R7 '"' +2 +1 ; Is it a " char? + StrCmp $R7 "'" +1 -4 ; Is it a ' char? + StrCpy $R9 $R9 $R6 ; Copy chars up to the counter. + GoTo end + + ; Handle DefaultIcon paths. DefaultIcon paths are not quoted and end with + ; a , and a number. + IntOp $R6 $R6 - 1 ; Decrement the counter. + StrCpy $R7 $R9 1 $R6 ; Copy one char from the end minus the counter. + StrCmp $R7 '' +4 ; Are there no more chars? + StrCmp $R7 ',' +1 -3 ; Is it a , char? + StrCpy $R9 $R9 $R6 ; Copy chars up to the end minus the counter. + GoTo end + + ; Handle unquoted paths with arguments. An unquoted path with arguments + ; must be an 8dot3 path. + StrCpy $R6 -1 ; Set the counter to -1 so it will start at 0. + IntOp $R6 $R6 + 1 ; Increment the counter. + StrCpy $R7 $R9 1 $R6 ; Starting from the counter copy the next char. + StrCmp $R7 "" end ; Are there no more chars? + StrCmp $R7 " " +1 -3 ; Is it a space char? + StrCpy $R9 $R9 $R6 ; Copy chars up to the counter. + + end: + + Pop $R6 + Pop $R7 + Exch $R8 + Push $R9 FunctionEnd !verbose pop !endif !macroend -!macro DisplayCopyErrMsgCall _FILE +!macro GetPathFromStringCall _STRING _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} - Push "${_FILE}" - Call DisplayCopyErrMsg + Push "${_STRING}" + Call GetPathFromString + Pop ${_RESULT} !verbose pop !macroend -!macro un.DisplayCopyErrMsgCall _FILE +!macro un.GetPathFromStringCall _STRING _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} - Push "${_FILE}" - Call un.DisplayCopyErrMsg + Push "${_STRING}" + Call un.GetPathFromString + Pop ${_RESULT} !verbose pop !macroend -!macro un.DisplayCopyErrMsg - !ifndef un.DisplayCopyErrMsg +!macro un.GetPathFromString + !ifndef un.GetPathFromString !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." - !insertmacro DisplayCopyErrMsg + !insertmacro GetPathFromString + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * If present removes the VirtualStore directory for this installation. Uses the + * program files directory path and the current install location to determine + * the sub-directory in the VirtualStore directory. + */ +!macro CleanVirtualStore + !ifndef ${_MOZFUNC_UN}CleanVirtualStore + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}CleanVirtualStore "!insertmacro ${_MOZFUNC_UN}CleanVirtualStoreCall" + + Function ${_MOZFUNC_UN}CleanVirtualStore + Push $R9 + Push $R8 + Push $R7 + + StrLen $R9 "$INSTDIR" + + ; Get the installation's directory name including the preceding slash + start: + IntOp $R8 $R8 - 1 + IntCmp $R8 -$R9 end end 0 + StrCpy $R7 "$INSTDIR" 1 $R8 + StrCmp $R7 "\" 0 start + + StrCpy $R9 "$INSTDIR" "" $R8 + + ClearErrors + GetFullPathName $R8 "$PROGRAMFILES$R9" + IfErrors end + GetFullPathName $R7 "$INSTDIR" + + ; Compare the installation's directory path with the path created by + ; concatenating the installation's directory name and the path to the + ; program files directory. + StrCmp "$R7" "$R8" 0 end + + StrCpy $R8 "$PROGRAMFILES" "" 2 ; Remove the drive letter and colon + StrCpy $R7 "$PROFILE\AppData\Local\VirtualStore$R8$R9" + + IfFileExists "$R7" 0 end + RmDir /r "$R7" + + end: + ClearErrors + + Pop $R7 + Pop $R8 + Pop $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro CleanVirtualStoreCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call CleanVirtualStore + !verbose pop +!macroend + +!macro un.CleanVirtualStoreCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call un.CleanVirtualStore + !verbose pop +!macroend + +!macro un.CleanVirtualStore + !ifndef un.CleanVirtualStore + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro CleanVirtualStore + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * Updates the uninstall.log with new files added by software update. + * + * Requires FileJoin, LineFind, TextCompare, and TrimNewLines. + * + * IMPORTANT! The LineFind docs claim that it uses all registers except $R0-$R3. + * Though it appears that this is not true all registers besides + * $R0-$R3 may be overwritten so protect yourself! + */ +!macro UpdateUninstallLog + + !ifndef ${_MOZFUNC_UN}UpdateUninstallLog + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}UpdateUninstallLog "!insertmacro ${_MOZFUNC_UN}UpdateUninstallLogCall" + + Function ${_MOZFUNC_UN}UpdateUninstallLog + Push $R3 + Push $R2 + Push $R1 + Push $R0 + + ClearErrors + + GetFullPathName $R3 "$INSTDIR\uninstall" + IfFileExists "$R3\uninstall.update" +2 0 + Return + + ${${_MOZFUNC_UN}LineFind} "$R3\uninstall.update" "" "1:-1" "${_MOZFUNC_UN}CleanupUpdateLog" + + GetTempFileName $R2 "$R3" + FileOpen $R1 $R2 w + ${${_MOZFUNC_UN}TextCompare} "$R3\uninstall.update" "$R3\uninstall.log" "SlowDiff" "${_MOZFUNC_UN}CreateUpdateDiff" + FileClose $R1 + + IfErrors +2 0 + ${${_MOZFUNC_UN}FileJoin} "$R3\uninstall.log" "$R2" "$R3\uninstall.log" + + ${DeleteFile} "$R2" + + ClearErrors + + Pop $R0 + Pop $R1 + Pop $R2 + Pop $R3 + FunctionEnd + + ; This callback MUST use labels vs. relative line numbers. + Function ${_MOZFUNC_UN}CleanupUpdateLog + StrCpy $R2 "$R9" 12 + StrCmp "$R2" "EXECUTE ADD " 0 skip + StrCpy $R9 "$R9" "" 12 + + Push $R6 + Push $R5 + Push $R4 + StrCpy $R4 "" ; Initialize to an empty string. + StrCpy $R6 -1 ; Set the counter to -1 so it will start at 0. + + loop: + IntOp $R6 $R6 + 1 ; Increment the counter. + StrCpy $R5 $R9 1 $R6 ; Starting from the counter copy the next char. + StrCmp $R5 "" copy ; Are there no more chars? + StrCmp $R5 "/" 0 +2 ; Is the char a /? + StrCpy $R5 "\" ; Replace the char with a \. + + StrCpy $R4 "$R4$R5" + GoTo loop + + copy: + StrCpy $R9 "File: \$R4" + Pop $R6 + Pop $R5 + Pop $R4 + GoTo end + + skip: + StrCpy $0 "SkipWrite" + + end: + Push $0 + FunctionEnd + + Function ${_MOZFUNC_UN}CreateUpdateDiff + ${${_MOZFUNC_UN}TrimNewLines} "$9" "$9" + StrCmp $9 "" +2 0 + FileWrite $R1 "$9$\r$\n" + + Push 0 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro UpdateUninstallLogCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call UpdateUninstallLog + !verbose pop +!macroend + +!macro un.UpdateUninstallLogCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call un.UpdateUninstallLog + !verbose pop +!macroend + +!macro un.UpdateUninstallLog + !ifndef un.UpdateUninstallLog + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro UpdateUninstallLog + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * Returns the long path for an existing file or directory. GetLongPathNameA + * may not be available on Win95 if Microsoft Layer for Unicode is not + * installed and GetFullPathName only returns a long path for the last file or + * directory that doesn't end with a \ in the path that it is passed. If the + * path does not exist on the file system this will return an empty string. To + * provide a consistent result trailing back-slashes are always removed. + * + * Note: 1024 used by GetLongPathNameA is the maximum NSIS string length. + * + * @param _IN_PATH + * The string containing the path. + * @param _OUT_PATH + * The register to store the long path. + * + * $R4 = counter value when the previous \ was found + * $R5 = directory or file name found during loop + * $R6 = return value from GetLongPathNameA and loop counter + * $R7 = long path from GetLongPathNameA and single char from path for comparison + * $R8 = _IN_PATH + * $R9 = _OUT_PATH + */ +!macro GetLongPath + + !ifndef ${_MOZFUNC_UN}GetLongPath + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}GetLongPath "!insertmacro ${_MOZFUNC_UN}GetLongPathCall" + + Function ${_MOZFUNC_UN}GetLongPath + Exch $R9 + Exch 1 + Exch $R8 + Push $R7 + Push $R6 + Push $R5 + Push $R4 + + ClearErrors + + StrCpy $R9 "" + GetFullPathName $R8 "$R8" + IfErrors end_GetLongPath +1 ; If the path doesn't exist return an empty string. + + ; Remove trailing \'s from the path. + StrCpy $R6 "$R8" "" -1 + StrCmp $R6 "\" +1 +2 + StrCpy $R9 "$R8" -1 + + System::Call 'kernel32::GetLongPathNameA(t r18, t .r17, i 1024)i .r16' + StrCmp "$R7" "" +4 +1 ; Empty string when GetLongPathNameA is not present. + StrCmp $R6 0 +3 +1 ; Should never equal 0 since the path exists. + StrCpy $R9 "$R7" + GoTo end_GetLongPath + + ; Do it the hard way. + StrCpy $R4 0 ; Stores the position in the string of the last \ found. + StrCpy $R6 -1 ; Set the counter to -1 so it will start at 0. + + loop_GetLongPath: + IntOp $R6 $R6 + 1 ; Increment the counter. + StrCpy $R7 $R8 1 $R6 ; Starting from the counter copy the next char. + StrCmp $R7 "" +2 ; Are there no more chars? + StrCmp $R7 "\" +1 -3 ; Is it a \? + + ; Copy chars starting from the previously found \ to the counter. + StrCpy $R5 $R8 $R6 $R4 + + ; If this is the first \ found we want to swap R9 with R5 so a \ will + ; be appended to the drive letter and colon (e.g. C: will become C:\). + StrCmp $R4 0 +1 +3 + StrCpy $R9 $R5 + StrCpy $R5 "" + + GetFullPathName $R9 "$R9\$R5" + + StrCmp $R7 "" end_GetLongPath ; Are there no more chars? + + ; Store the counter for the current \ and prefix it for StrCpy operations. + StrCpy $R4 "+$R6" + IntOp $R6 $R6 + 1 ; Increment the counter so we skip over the \. + StrCpy $R8 $R8 "" $R6 ; Copy chars starting from the counter to the end. + StrCpy $R6 -1 ; Reset the counter to -1 so it will start over at 0. + GoTo loop_GetLongPath + + end_GetLongPath: + ClearErrors + + Pop $R4 + Pop $R5 + Pop $R6 + Pop $R7 + Exch $R8 + Exch 1 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro GetLongPathCall _IN_PATH _OUT_PATH + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_IN_PATH}" + Push "${_OUT_PATH}" + Call GetLongPath + Pop ${_OUT_PATH} + !verbose pop +!macroend + +!macro un.GetLongPathCall _IN_PATH _OUT_PATH + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_IN_PATH}" + Push "${_OUT_PATH}" + Call un.GetLongPath + Pop ${_OUT_PATH} + !verbose pop +!macroend + +!macro un.GetLongPath + !ifndef un.GetLongPath + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro GetLongPath !undef _MOZFUNC_UN !define _MOZFUNC_UN diff --git a/toolkit/mozapps/installer/windows/nsis/makensis.mk b/toolkit/mozapps/installer/windows/nsis/makensis.mk index f2c99bac..1ea2c85a 100644 --- a/toolkit/mozapps/installer/windows/nsis/makensis.mk +++ b/toolkit/mozapps/installer/windows/nsis/makensis.mk @@ -81,8 +81,8 @@ uninstaller:: $(INSTALL) $(topsrcdir)/toolkit/mozapps/installer/windows/nsis/setup.ico $(CONFIG_DIR) cd $(CONFIG_DIR) && makensis.exe uninstaller.nsi $(NSINSTALL) -D $(DIST)/bin/uninstall -ifdef MOZ_PHOENIX - cp $(CONFIG_DIR)/helper.exe $(DIST)/bin/uninstall -else +ifdef MOZ_SUNBIRD cp $(CONFIG_DIR)/uninst.exe $(DIST)/bin/uninstall +else + cp $(CONFIG_DIR)/helper.exe $(DIST)/bin/uninstall endif diff --git a/toolkit/mozapps/installer/windows/nsis/version.nsh b/toolkit/mozapps/installer/windows/nsis/version.nsh index 454ba826..85e630d7 100644 --- a/toolkit/mozapps/installer/windows/nsis/version.nsh +++ b/toolkit/mozapps/installer/windows/nsis/version.nsh @@ -13,4 +13,5 @@ VIAddVersionKey "CompanyName" "${CompanyName}" VIAddVersionKey "LegalTrademarks" "${BrandShortName} is a Trademark of The Mozilla Foundation." VIAddVersionKey "LegalCopyright" "${CompanyName}" VIAddVersionKey "FileVersion" "${AppVersion}" +VIAddVersionKey "ProductVersion" "${AppVersion}" ;VIAddVersionKey "Comments" "Comments" diff --git a/toolkit/mozapps/plugins/content/pluginInstallerDatasource.js b/toolkit/mozapps/plugins/content/pluginInstallerDatasource.js index 8164000a..3c63e63d 100644 --- a/toolkit/mozapps/plugins/content/pluginInstallerDatasource.js +++ b/toolkit/mozapps/plugins/content/pluginInstallerDatasource.js @@ -48,6 +48,7 @@ function nsRDFItemUpdater(aClientOS, aChromeLocale){ .getService(Components.interfaces.nsIXULAppInfo); this.appID = app.ID; this.buildID = app.platformBuildID; + this.appRelease = app.version; this.clientOS = aClientOS; this.chromeLocale = aChromeLocale; @@ -64,6 +65,7 @@ nsRDFItemUpdater.prototype = { dsURI = dsURI.replace(/%PLUGIN_MIMETYPE%/g, encodeURIComponent(aPluginRequestItem.mimetype)); dsURI = dsURI.replace(/%APP_ID%/g, this.appID); dsURI = dsURI.replace(/%APP_VERSION%/g, this.buildID); + dsURI = dsURI.replace(/%APP_RELEASE%/g, this.appRelease); dsURI = dsURI.replace(/%CLIENT_OS%/g, this.clientOS); dsURI = dsURI.replace(/%CHROME_LOCALE%/g, this.chromeLocale); @@ -109,27 +111,31 @@ nsRDFItemUpdater.prototype = { target = child; } - function getPFSValueFromRDF(aValue, aDatasource, aRDFService){ + var rdfs = this._rdfService; + + function getPFSValueFromRDF(aValue){ var rv = null; - var myTarget = aDatasource.GetTarget(target, aRDFService.GetResource(PFS_NS + aValue), true); + var myTarget = aDatasource.GetTarget(target, rdfs.GetResource(PFS_NS + aValue), true); if (myTarget) rv = myTarget.QueryInterface(Components.interfaces.nsIRDFLiteral).Value; return rv; } - pluginInfo = new Object(); - pluginInfo.name = getPFSValueFromRDF("name", aDatasource, this._rdfService); - pluginInfo.pid = getPFSValueFromRDF("guid", aDatasource, this._rdfService); - pluginInfo.version = getPFSValueFromRDF("version", aDatasource, this._rdfService); - pluginInfo.IconUrl = getPFSValueFromRDF("IconUrl", aDatasource, this._rdfService); - pluginInfo.XPILocation = getPFSValueFromRDF("XPILocation", aDatasource, this._rdfService); - pluginInfo.InstallerShowsUI = getPFSValueFromRDF("InstallerShowsUI", aDatasource, this._rdfService); - pluginInfo.manualInstallationURL = getPFSValueFromRDF("manualInstallationURL", aDatasource, this._rdfService); - pluginInfo.requestedMimetype = getPFSValueFromRDF("requestedMimetype", aDatasource, this._rdfService); - pluginInfo.licenseURL = getPFSValueFromRDF("licenseURL", aDatasource, this._rdfService); - pluginInfo.needsRestart = getPFSValueFromRDF("needsRestart", aDatasource, this._rdfService); + pluginInfo = { + name: getPFSValueFromRDF("name"), + pid: getPFSValueFromRDF("guid"), + version: getPFSValueFromRDF("version"), + IconUrl: getPFSValueFromRDF("IconUrl"), + XPILocation: getPFSValueFromRDF("XPILocation"), + XPIHash: getPFSValueFromRDF("XPIHash"), + InstallerShowsUI: getPFSValueFromRDF("InstallerShowsUI"), + manualInstallationURL: getPFSValueFromRDF("manualInstallationURL"), + requestedMimetype: getPFSValueFromRDF("requestedMimetype"), + licenseURL: getPFSValueFromRDF("licenseURL"), + needsRestart: getPFSValueFromRDF("needsRestart") + }; } catch (ex){} } diff --git a/toolkit/mozapps/plugins/content/pluginInstallerService.js b/toolkit/mozapps/plugins/content/pluginInstallerService.js index ba4f49b7..02654077 100644 --- a/toolkit/mozapps/plugins/content/pluginInstallerService.js +++ b/toolkit/mozapps/plugins/content/pluginInstallerService.js @@ -43,12 +43,15 @@ var PluginInstallService = { pluginPidArray: null, - startPluginInsallation: function (aPluginXPIUrlsArray, aPluginPidArray) { + startPluginInstallation: function (aPluginXPIUrlsArray, + aPluginHashes, + aPluginPidArray) { this.pluginPidArray = aPluginPidArray; var xpiManager = Components.classes["@mozilla.org/xpinstall/install-manager;1"] .createInstance(Components.interfaces.nsIXPInstallManager); - xpiManager.initManagerFromChrome(aPluginXPIUrlsArray, aPluginXPIUrlsArray.length, this); + xpiManager.initManagerWithHashes(aPluginXPIUrlsArray, aPluginHashes, + aPluginXPIUrlsArray.length, this); }, // XPI progress listener stuff diff --git a/toolkit/mozapps/plugins/content/pluginInstallerWizard.js b/toolkit/mozapps/plugins/content/pluginInstallerWizard.js index c84d84b4..a5f1865b 100644 --- a/toolkit/mozapps/plugins/content/pluginInstallerWizard.js +++ b/toolkit/mozapps/plugins/content/pluginInstallerWizard.js @@ -342,6 +342,7 @@ nsPluginInstallerWizard.prototype.startPluginInstallation = function (){ // mimetype. So store the pids. var pluginURLArray = new Array(); + var pluginHashArray = new Array(); var pluginPidArray = new Array(); for (pluginInfoItem in this.mPluginInfoArray){ @@ -351,12 +352,15 @@ nsPluginInstallerWizard.prototype.startPluginInstallation = function (){ // will complain. if (pluginItem.toBeInstalled && pluginItem.XPILocation && pluginItem.licenseAccepted) { pluginURLArray.push(pluginItem.XPILocation); + pluginHashArray.push(pluginItem.XPIHash); pluginPidArray.push(pluginItem.pid); } } if (pluginURLArray.length > 0) - PluginInstallService.startPluginInsallation(pluginURLArray, pluginPidArray); + PluginInstallService.startPluginInstallation(pluginURLArray, + pluginHashArray, + pluginPidArray); else this.advancePage(null, true, false, false); } @@ -554,7 +558,8 @@ nsPluginInstallerWizard.prototype.showPluginResults = function (){ "&appID=" + app.ID + "&appVersion=" + app.platformBuildID + "&clientOS=" + this.getOS() + - "&chromeLocale=" + this.getChromeLocale(); + "&chromeLocale=" + this.getChromeLocale() + + "&appRelease=" + app.version; document.getElementById("moreInfoLink").addEventListener("click", function() { gPluginInstaller.loadURL("https://pfs.mozilla.org/plugins/" + notInstalledList) }, false); @@ -617,6 +622,7 @@ function PluginInfo(aResult) { this.version = aResult.version; this.IconUrl = aResult.IconUrl; this.XPILocation = aResult.XPILocation; + this.XPIHash = aResult.XPIHash; this.InstallerShowsUI = aResult.InstallerShowsUI; this.manualInstallationURL = aResult.manualInstallationURL; this.requestedMimetype = aResult.requestedMimetype; diff --git a/toolkit/mozapps/update/src/nsPostUpdateWin.js b/toolkit/mozapps/update/src/nsPostUpdateWin.js index e6f2429c..984670e2 100644 --- a/toolkit/mozapps/update/src/nsPostUpdateWin.js +++ b/toolkit/mozapps/update/src/nsPostUpdateWin.js @@ -46,8 +46,7 @@ const URI_BRAND_PROPERTIES = "chrome://branding/locale/brand.properties"; const KEY_APPDIR = "XCurProcD"; const KEY_TMPDIR = "TmpD"; -const KEY_LOCALDATA = "DefProfLRt"; -const KEY_PROGRAMFILES = "ProgF"; +const KEY_UPDROOT = "UpdRootD"; const KEY_UAPPDATA = "UAppData"; // see prio.h @@ -187,29 +186,15 @@ InstallLogWriter.prototype = { // See the local appdata first if app dir is under Program Files. var file = null; - var updRoot = getFile(KEY_APPDIR); - var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"] - .getService(Components.interfaces.nsIProperties); - // Fallback to previous behavior since getting ProgF - // (e.g. KEY_PROGRAMFILES) may fail on Win9x. try { - var programFilesDir = fileLocator.get(KEY_PROGRAMFILES, - Components.interfaces.nsILocalFile); - if (programFilesDir.contains(updRoot, true)) { - var relativePath = updRoot.QueryInterface(Components.interfaces.nsILocalFile). - getRelativeDescriptor(programFilesDir); - var userLocalDir = fileLocator.get(KEY_LOCALDATA, - Components.interfaces.nsILocalFile).parent; - updRoot.setRelativeDescriptor(userLocalDir, relativePath); - file = appendUpdateLogPath(updRoot); + file = appendUpdateLogPath(getFile(KEY_UPDROOT)); - // When updating from Fx 2.0.0.1 to 2.0.0.3 (or later) on Vista, - // we will have to see also user app data (see bug 351949). - if (!file) - file = appendUpdateLogPath(getFile(KEY_UAPPDATA)); - } + // When updating from Fx 2.0.0.1 to 2.0.0.3 (or later) on Vista, + // we will have to see also user app data (see bug 351949). + if (!file) + file = appendUpdateLogPath(getFile(KEY_UAPPDATA)); + } catch (e) { } - catch (e) {} // See the app dir if not found or app dir is out of Program Files. if (!file) @@ -540,12 +525,15 @@ function haveOldInstall(key, brandFullName, version) { function checkRegistry() { - // XXX todo - // this is firefox specific - // figure out what to do about tbird and sunbird, etc LOG("checkRegistry"); var result = false; + + // Firefox is the only toolkit app that needs to do this. + // return false for other applications. + var app = Components.classes["@mozilla.org/xre/app-info;1"]. + getService(Components.interfaces.nsIXULAppInfo); + if (app.name == "Firefox") { try { var key = new RegKey(); key.open(RegKey.prototype.ROOT_KEY_CLASSES_ROOT, "FirefoxHTML\\shell\\open\\command", key.ACCESS_READ); @@ -557,6 +545,7 @@ function checkRegistry() LOG("failed to open command key for FirefoxHTML: " + e); } key.close(); + } return result; } @@ -605,6 +594,16 @@ nsPostUpdateWin.prototype = { }, run: function() { + // When uninstall/uninstall.update exists the uninstaller has already + // updated the uninstall.log with the files added by software update. + var updateUninstallFile = getFile(KEY_APPDIR); + updateUninstallFile.append("uninstall"); + updateUninstallFile.append("uninstall.update"); + if (updateUninstallFile.exists()) { + LOG("nothing to do, uninstall.log has already been updated"); + return; + } + try { installLogWriter = new InstallLogWriter(); try { diff --git a/toolkit/mozapps/update/src/nsUpdateService.js.in b/toolkit/mozapps/update/src/nsUpdateService.js.in index 2778c53a..517118de 100644 --- a/toolkit/mozapps/update/src/nsUpdateService.js.in +++ b/toolkit/mozapps/update/src/nsUpdateService.js.in @@ -67,8 +67,7 @@ const URI_UPDATE_NS = "http://www.mozilla.org/2005/app-update"; const KEY_APPDIR = "XCurProcD"; #ifdef XP_WIN -const KEY_LOCALDATA = "DefProfLRt"; -const KEY_PROGRAMFILES = "ProgF"; +const KEY_UPDROOT = "UpdRootD"; const KEY_UAPPDATA = "UAppData"; #endif @@ -238,22 +237,13 @@ function getUpdateDir(pathArray) { function getDirInternal(key, pathArray, shouldCreate, update) { var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"] .getService(Components.interfaces.nsIProperties); - var dir = fileLocator.get(key, Components.interfaces.nsILocalFile); + var dir = fileLocator.get(key, Components.interfaces.nsIFile); #ifdef XP_WIN if (update) { - // Fallback to previous behavior since getting ProgF - // (e.g. KEY_PROGRAMFILES) may fail on Win9x. try { - var programFilesDir = fileLocator.get(KEY_PROGRAMFILES, - Components.interfaces.nsILocalFile); - if (programFilesDir.contains(dir, true)) { - var relativePath = dir.getRelativeDescriptor(programFilesDir); - var userLocalDir = fileLocator.get(KEY_LOCALDATA, - Components.interfaces.nsILocalFile).parent; - dir.setRelativeDescriptor(userLocalDir, relativePath); - } + dir = fileLocator.get(KEY_UPDROOT, Components.interfaces.nsIFile); + } catch (e) { } - catch (e) {} } #endif for (var i = 0; i < pathArray.length; ++i) { @@ -283,7 +273,7 @@ function getFile(key, pathArray) { } /** - * Gets the file at the speciifed hierarchy under the update root directory. + * Gets the file at the specified hierarchy under the update root directory. * @param pathArray * An array of path components to locate beneath the directory * specified by |key|. The last item in this array must be the @@ -358,23 +348,14 @@ function getUpdatesDir(key) { getService(Components.interfaces.nsIProperties); var appDir; if (key) - appDir = fileLocator.get(key, Components.interfaces.nsILocalFile); + appDir = fileLocator.get(key, Components.interfaces.nsIFile); else { - appDir = fileLocator.get(KEY_APPDIR, Components.interfaces.nsILocalFile); + appDir = fileLocator.get(KEY_APPDIR, Components.interfaces.nsIFile); #ifdef XP_WIN - // Fallback to previous behavior since getting ProgF - // (e.g. KEY_PROGRAMFILES) may fail on Win9x. try { - var programFilesDir = fileLocator.get(KEY_PROGRAMFILES, - Components.interfaces.nsILocalFile); - if (programFilesDir.contains(appDir, true)) { - var relativePath = appDir.getRelativeDescriptor(programFilesDir); - var userLocalDir = fileLocator.get(KEY_LOCALDATA, - Components.interfaces.nsILocalFile).parent; - appDir.setRelativeDescriptor(userLocalDir, relativePath); - } + appDir = fileLocator.get(KEY_UPDROOT, Components.interfaces.nsIFile); + } catch (e) { } - catch (e) {} #endif } appDir.append(DIR_UPDATES); @@ -512,8 +493,11 @@ function getPref(func, preference, defaultValue) { */ function getLocale() { try { - return gPref.getComplexValue(PREF_GENERAL_USERAGENT_LOCALE, - nsIPrefLocalizedString).data; + // Get the default branch + var prefs = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefService); + var defaultPrefs = prefs.getDefaultBranch(null); + return defaultPrefs.getCharPref(PREF_GENERAL_USERAGENT_LOCALE); } catch (e) {} return gPref.getCharPref(PREF_GENERAL_USERAGENT_LOCALE); @@ -1018,18 +1002,27 @@ function UpdateService() { LOG("UpdateService", "XPCOM ABI unknown: updates are not possible."); } - try { - var sysInfo = - Components.classes["@mozilla.org/system-info;1"] - .getService(Components.interfaces.nsIPropertyBag2); + var osVersion; + var sysInfo = Components.classes["@mozilla.org/system-info;1"] + .getService(Components.interfaces.nsIPropertyBag2); - gOSVersion = encodeURIComponent(sysInfo.getProperty("name") + " " + - sysInfo.getProperty("version")); + try { + osVersion = sysInfo.getProperty("name") + " " + sysInfo.getProperty("version"); } catch (e) { LOG("UpdateService", "OS Version unknown: updates are not possible."); } + if (osVersion) { + try { + osVersion += " (" + sysInfo.getProperty("secondaryLibrary") + ")"; + } + catch (e) { + // Not all platforms have a secondary widget library, so an error is nothing to worry about. + } + gOSVersion = encodeURIComponent(osVersion); + } + #ifdef XP_MACOSX // Mac universal build should report a different ABI than either macppc // or mactel. @@ -1199,12 +1192,10 @@ UpdateService.prototype = { LOG("UpdateService", "_postUpdateProcessing: Install Succeeded, Showing UI"); prompter.showUpdateInstalled(update); - -#ifdef MOZ_PHOENIX - // for now, this is firefox only. +#ifdef MOZ_SUNBIRD // we need to fix both nsPostUpdateWin.js and - // the uninstaller to work for thunderbird and sunbird - // + // the uninstaller to work for sunbird +#else // Perform platform-specific post-update processing. if (POST_UPDATE_CONTRACTID in Components.classes) { Components.classes[POST_UPDATE_CONTRACTID]. @@ -1519,6 +1510,7 @@ UpdateService.prototype = { get canUpdate() { try { var appDirFile = getUpdateFile([FILE_PERMS_TEST]); + LOG("UpdateService", "canUpdate? testing " + appDirFile.path); if (!appDirFile.exists()) { appDirFile.create(nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); appDirFile.remove(false); @@ -1526,12 +1518,45 @@ UpdateService.prototype = { var updateDir = getUpdatesDir(); var upDirFile = updateDir.clone(); upDirFile.append(FILE_PERMS_TEST); + LOG("UpdateService", "canUpdate? testing " + upDirFile.path); if (!upDirFile.exists()) { upDirFile.create(nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); upDirFile.remove(false); } +#ifdef XP_WIN + var sysInfo = + Components.classes["@mozilla.org/system-info;1"] + .getService(Components.interfaces.nsIPropertyBag2); + + // On Windows, we no longer store the update under the app dir + // if the app dir is under C:\Program Files. + // + // If we are on Windows, but not Vista, we need to check that + // we can create and remove files from the actual app directory + // (like C:\Program Files\Mozilla Firefox). If we can't, + // because this user is not an adminstrator, for example + // canUpdate() should return false (like it used to). + // + // For Vista, don't perform this check because non-admin users + // can update firefox (by granting the updater access via the + // UAC prompt) + var windowsVersion = sysInfo.getProperty("version"); + LOG("UpdateService", "canUpdate? version = " + windowsVersion); + // Example windowsVersion: Windows XP == 5.1 + if (parseFloat(windowsVersion) < 6) { + var actualAppDir = getDir(KEY_APPDIR, []); + var actualAppDirFile = actualAppDir.clone(); + actualAppDirFile.append(FILE_PERMS_TEST); + LOG("UpdateService", "canUpdate? testing " + actualAppDirFile.path); + if (!actualAppDirFile.exists()) { + actualAppDirFile.create(nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); + actualAppDirFile.remove(false); + } + } +#endif } catch (e) { + LOG("UpdateService", "can't update, no privileges: " + e); // No write privileges to install directory return false; } @@ -1539,17 +1564,24 @@ UpdateService.prototype = { // OFF - this is not just a user setting, so disable the manual // UI too. var enabled = getPref("getBoolPref", PREF_APP_UPDATE_ENABLED, true); - if (!enabled && gPref.prefIsLocked(PREF_APP_UPDATE_ENABLED)) + if (!enabled && gPref.prefIsLocked(PREF_APP_UPDATE_ENABLED)) { + LOG("UpdateService", "can't update, disabled by pref"); return false; + } // If we don't know the binary platform we're updating, we can't update. - if (!gABI) + if (!gABI) { + LOG("UpdateService", "can't update, unknown ABI"); return false; + } // If we don't know the OS version we're updating, we can't update. - if (!gOSVersion) + if (!gOSVersion) { + LOG("UpdateService", "can't update, unknown OS version"); return false; + } + LOG("UpdateService", "can update"); return true; }, @@ -1860,7 +1892,9 @@ Checker.prototype = { * The URL of the update service XML file to connect to that contains details * about available updates. */ - get updateURL() { + getUpdateURL: function(force) { + this._forced = force; + var defaults = gPref.QueryInterface(Components.interfaces.nsIPrefService). getDefaultBranch(null); @@ -1890,6 +1924,9 @@ Checker.prototype = { url = url.replace(/%CHANNEL%/g, getUpdateChannel()); url = url.replace(/\+/g, "%2B"); + if (force) + url += "?force=1" + LOG("Checker", "update url: " + url); return url; }, @@ -1901,13 +1938,13 @@ Checker.prototype = { if (!listener) throw Components.results.NS_ERROR_NULL_POINTER; - if (!this.updateURL || (!this.enabled && !force)) + if (!this.getUpdateURL(force) || (!this.enabled && !force)) return; this._request = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]. createInstance(Components.interfaces.nsIXMLHttpRequest); - this._request.open("GET", this.updateURL, true); + this._request.open("GET", this.getUpdateURL(force), true); this._request.channel.notificationCallbacks = new BadCertHandler(); this._request.overrideMimeType("text/xml"); this._request.setRequestHeader("Cache-Control", "no-cache"); @@ -1917,7 +1954,7 @@ Checker.prototype = { this._request.onload = function(event) { self.onLoad(event); }; this._request.onprogress = function(event) { self.onProgress(event); }; - LOG("Checker", "checkForUpdates: sending request to " + this.updateURL); + LOG("Checker", "checkForUpdates: sending request to " + this.getUpdateURL(force)); this._request.send(null); this._callback = listener; @@ -1962,7 +1999,7 @@ Checker.prototype = { LOG("Checker", "Invalid , ignoring..."); continue; } - update.serviceURL = this.updateURL; + update.serviceURL = this.getUpdateURL(this._forced); update.channel = getUpdateChannel(); updates.push(update); } diff --git a/toolkit/mozapps/update/src/updater/archivereader.cpp b/toolkit/mozapps/update/src/updater/archivereader.cpp index 20a25b32..c1ef0552 100644 --- a/toolkit/mozapps/update/src/updater/archivereader.cpp +++ b/toolkit/mozapps/update/src/updater/archivereader.cpp @@ -110,6 +110,11 @@ ArchiveReader::ExtractItemToStream(const MarItem *item, FILE *fp) offset = 0; for (;;) { + if (!item->length) { + ret = UNEXPECTED_ERROR; + break; + } + if (offset < (int) item->length && strm.avail_in == 0) { inlen = mar_read(mArchive, item, offset, inbuf, BUFSIZ); if (inlen <= 0) diff --git a/toolkit/mozapps/update/src/updater/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in b/toolkit/mozapps/update/src/updater/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in index 582404ad..4455b08f 100644 --- a/toolkit/mozapps/update/src/updater/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in +++ b/toolkit/mozapps/update/src/updater/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in @@ -1,4 +1,4 @@ /* Localized versions of Info.plist keys */ CFBundleName = "@APP_NAME@ Software Update"; -NSHumanReadableCopyright = "Copyright © 2005-2007 Mozilla Foundation"; +NSHumanReadableCopyright = "Copyright © 2005-2008 Mozilla Foundation"; diff --git a/toolkit/mozapps/update/src/updater/progressui_win.cpp b/toolkit/mozapps/update/src/updater/progressui_win.cpp index b80b5228..5dda5bac 100644 --- a/toolkit/mozapps/update/src/updater/progressui_win.cpp +++ b/toolkit/mozapps/update/src/updater/progressui_win.cpp @@ -47,6 +47,26 @@ #define TIMER_ID 1 #define TIMER_INTERVAL 100 +#define MAX_INFO_LENGTH 512 + +#define RESIZE_WINDOW(hwnd, extrax, extray) \ + { \ + RECT windowSize; \ + GetWindowRect(hwnd, &windowSize); \ + SetWindowPos(hwnd, 0, 0, 0, windowSize.right - windowSize.left + extrax, \ + windowSize.bottom - windowSize.top + extray, \ + SWP_NOMOVE | SWP_NOZORDER); \ + } + +#define MOVE_WINDOW(hwnd, dx, dy) \ + { \ + WINDOWPLACEMENT windowPos; \ + windowPos.length = sizeof(windowPos); \ + GetWindowPlacement(hwnd, &windowPos); \ + SetWindowPos(hwnd, 0, windowPos.rcNormalPosition.left + dx, windowPos.rcNormalPosition.top + dy, 0, 0, \ + SWP_NOSIZE | SWP_NOZORDER); \ + } + static float sProgress; // between 0 and 100 static BOOL sQuit = FALSE; static HFONT sSystemFont = 0; @@ -72,6 +92,52 @@ UpdateDialog(HWND hDlg) SendDlgItemMessage(hDlg, IDC_PROGRESS, PBM_SETPOS, pos, 0L); } +static void +ResizeDialogToFit(HWND hDlg) +{ + char text[MAX_INFO_LENGTH]; + RECT infoSize, textSize; + HFONT hInfoFont, hOldFont; + + HWND hWndInfo = GetDlgItem(hDlg, IDC_INFO); + HWND hWndPro = GetDlgItem(hDlg, IDC_PROGRESS); + + // Get the text that is displayed - this is what we're going to make fit. + if (!GetWindowText(hWndInfo, text, sizeof(text))) + return; + + // We need the current size and font to calculate the adjustment. + GetClientRect(hWndInfo, &infoSize); + HDC hDCInfo = GetDC(hWndInfo); + hInfoFont = (HFONT)SendMessage(hWndInfo, WM_GETFONT, 0, 0); + if (hInfoFont) + hOldFont = (HFONT)SelectObject(hDCInfo, hInfoFont); + + // Measure the space needed for the text - DT_CALCRECT means nothing is drawn. + if (DrawText(hDCInfo, text, -1, &textSize, + DT_CALCRECT | DT_NOCLIP | DT_SINGLELINE)) { + SIZE extra; + extra.cx = (textSize.right - textSize.left) - (infoSize.right - infoSize.left); + extra.cy = (textSize.bottom - textSize.top) - (infoSize.bottom - infoSize.top); + if (extra.cx < 0) + extra.cx = 0; + if (extra.cy < 0) + extra.cy = 0; + + if ((extra.cx > 0) || (extra.cy > 0)) { + RESIZE_WINDOW(hDlg, extra.cx, extra.cy); + RESIZE_WINDOW(hWndInfo, extra.cx, extra.cy); + RESIZE_WINDOW(hWndPro, extra.cx, 0); + MOVE_WINDOW(hWndPro, 0, extra.cy); + } + } + + if (hOldFont) + SelectObject(hDCInfo, hOldFont); + + ReleaseDC(hWndInfo, hDCInfo); +} + // The code in this function is from MSDN: // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/dialogboxes/usingdialogboxes.asp static void @@ -109,7 +175,7 @@ CenterDialog(HWND hDlg) static void SetItemText(HWND hwnd, const char *key, const char *ini) { - char text[512]; + char text[MAX_INFO_LENGTH]; if (!GetPrivateProfileString("Strings", key, NULL, text, sizeof(text), ini)) return; SetWindowText(hwnd, text); @@ -147,6 +213,9 @@ InitDialog(HWND hDlg) SendDlgItemMessage(hDlg, IDC_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); + // Resize dialog to fit all the text. + ResizeDialogToFit(hDlg); + CenterDialog(hDlg); // make dialog appear in the center of the screen SetTimer(hDlg, TIMER_ID, TIMER_INTERVAL, NULL); diff --git a/toolkit/mozapps/update/src/updater/updater.cpp b/toolkit/mozapps/update/src/updater/updater.cpp index 18031994..b773ae7c 100644 --- a/toolkit/mozapps/update/src/updater/updater.cpp +++ b/toolkit/mozapps/update/src/updater/updater.cpp @@ -245,11 +245,10 @@ public: return 0; } private: - static unsigned ThreadMain(void *p) + static void ThreadMain(void *p) { Thread *self = (Thread *) p; self->mThreadFunc(self->mThreadParam); - return 0; } int mThread; ThreadFunc mThreadFunc; @@ -264,6 +263,9 @@ private: static char* gSourcePath; static ArchiveReader gArchiveReader; +#ifdef XP_WIN +static bool gSucceeded = FALSE; +#endif static const char kWhitespace[] = " \t"; static const char kNL[] = "\r\n"; @@ -1007,6 +1009,61 @@ PatchIfFile::Finish(int status) #ifdef XP_WIN #include "nsWindowsRestart.cpp" + +static void +LaunchWinPostProcess(const char *appExe) +{ + // Launch helper.exe to perform post processing (e.g. registry and log file + // modifications) for the update. + char inifile[MAXPATHLEN]; + strcpy(inifile, appExe); + + char *slash = strrchr(inifile, '\\'); + if (!slash) + return; + + strcpy(slash + 1, "updater.ini"); + + char exefile[MAXPATHLEN]; + char exearg[MAXPATHLEN]; + if (!GetPrivateProfileString("PostUpdateWin", "ExeRelPath", NULL, exefile, + sizeof(exefile), inifile)) + return; + + if (!GetPrivateProfileString("PostUpdateWin", "ExeArg", NULL, exearg, + sizeof(exearg), inifile)) + return; + + char exefullpath[MAXPATHLEN]; + strcpy(exefullpath, appExe); + + slash = strrchr(exefullpath, '\\'); + strcpy(slash + 1, exefile); + + char dlogFile[MAXPATHLEN]; + strcpy(dlogFile, exefullpath); + + slash = strrchr(dlogFile, '\\'); + strcpy(slash + 1, "uninstall.update"); + + char slogFile[MAXPATHLEN]; + snprintf(slogFile, MAXPATHLEN, "%s/update.log", gSourcePath); + + // We want to launch the post update helper app to update the Windows + // registry even if there is a failure with removing the uninstall.update + // file or copying the update.log file. + ensure_remove(dlogFile); + copy_file(slogFile, dlogFile); + + static int argc = 2; + static char **argv = (char**) malloc(sizeof(char*) * (argc + 1)); + argv[0] = "argv0ignoredbywinlaunchchild"; + argv[1] = exearg; + argv[2] = "\0"; + + WinLaunchChild(exefullpath, argc, argv, 1); + free(argv); +} #endif static void @@ -1129,6 +1186,11 @@ int main(int argc, char **argv) LogFinish(); +#ifdef XP_WIN + if (gSucceeded && argc > 4) + LaunchWinPostProcess(argv[4]); +#endif + // The callback to execute is given as the last N arguments of our command // line. The first of those arguments specifies the working directory for // the callback. @@ -1234,6 +1296,11 @@ ActionList::Finish(int status) a = a->mNext; } +#ifdef XP_WIN + if (status == OK) + gSucceeded = TRUE; +#endif + UpdateProgressUI(100.0f); } diff --git a/toolkit/themes/pmstripe/global/jar.mn b/toolkit/themes/pmstripe/global/jar.mn index 9b5b6c18..1f5ef8cc 100644 --- a/toolkit/themes/pmstripe/global/jar.mn +++ b/toolkit/themes/pmstripe/global/jar.mn @@ -13,6 +13,10 @@ classic.jar: + skin/classic/global/arrow/arrow-dn-dis.gif (arrow/arrow-dn-dis.gif) + skin/classic/global/arrow/arrow-lft-dis.gif (arrow/arrow-lft-dis.gif) + skin/classic/global/arrow/arrow-rit-dis.gif (arrow/arrow-rit-dis.gif) ++ skin/classic/global/arrow/arrow-up-hov.gif (arrow/arrow-up.gif) ++ skin/classic/global/arrow/arrow-dn-hov.gif (arrow/arrow-dn.gif) ++ skin/classic/global/arrow/arrow-lft-hov.gif (arrow/arrow-lft.gif) ++ skin/classic/global/arrow/arrow-rit-hov.gif (arrow/arrow-rit.gif) + skin/classic/global/arrow/thumb-vrt.gif (arrow/thumb-vrt.gif) + skin/classic/global/arrow/thumb-hrz.gif (arrow/thumb-hrz.gif) + skin/classic/global/browser.css diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index c8b4234b..81863df8 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -40,6 +40,10 @@ * * ***** END LICENSE BLOCK ***** */ +#if defined(XP_OS2) && defined(MOZ_OS2_HIGH_MEMORY) +// os2safe.h has to be included before os2.h, needed for high mem +#include +#endif #define XPCOM_TRANSLATE_NSGM_ENTRY_POINT 1 @@ -306,6 +310,12 @@ strimatch(const char* lowerstr, const char* mixedstr) return PR_TRUE; } +enum RemoteResult { + REMOTE_NOT_FOUND = 0, + REMOTE_FOUND = 1, + REMOTE_ARG_BAD = 2 +}; + enum ArgResult { ARG_NONE = 0, ARG_FOUND = 1, @@ -328,13 +338,16 @@ static void RemoveArg(char **argv) * --arg (or /arg on win32/OS2). * * @param aArg the parameter to check. Must be lowercase. + * @param aCheckOSInt if true returns ARG_BAD if the osint argument is present + * when aArg is also present. * @param if non-null, the -arg will be stored in this pointer. This is *not* * allocated, but rather a pointer to the argv data. */ static ArgResult -CheckArg(const char* aArg, const char **aParam = nsnull) +CheckArg(const char* aArg, PRBool aCheckOSInt = PR_FALSE, const char **aParam = nsnull) { char **curarg = gArgv + 1; // skip argv[0] + ArgResult ar = ARG_NONE; while (*curarg) { char *arg = curarg[0]; @@ -351,7 +364,8 @@ CheckArg(const char* aArg, const char **aParam = nsnull) if (strimatch(aArg, arg)) { RemoveArg(curarg); if (!aParam) { - return ARG_FOUND; + ar = ARG_FOUND; + break; } if (*curarg) { @@ -364,7 +378,8 @@ CheckArg(const char* aArg, const char **aParam = nsnull) *aParam = *curarg; RemoveArg(curarg); - return ARG_FOUND; + ar = ARG_FOUND; + break; } return ARG_BAD; } @@ -373,7 +388,15 @@ CheckArg(const char* aArg, const char **aParam = nsnull) ++curarg; } - return ARG_NONE; + if (aCheckOSInt && ar == ARG_FOUND) { + ArgResult arOSInt = CheckArg("osint"); + if (arOSInt == ARG_FOUND) { + ar = ARG_BAD; + PR_fprintf(PR_STDERR, "Error: argument -osint is invalid\n"); + } + } + + return ar; } #if defined(XP_WIN) @@ -1115,14 +1138,14 @@ HandleRemoteArgument(const char* remote) ToLowerCase(program); const char *username = getenv("LOGNAME"); - ar = CheckArg("p", &profile); + ar = CheckArg("p", PR_FALSE, &profile); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument -p requires a profile name\n"); return 1; } const char *temp = nsnull; - ar = CheckArg("a", &temp); + ar = CheckArg("a", PR_FALSE, &temp); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n"); return 1; @@ -1130,7 +1153,7 @@ HandleRemoteArgument(const char* remote) program.Assign(temp); } - ar = CheckArg("u", &username); + ar = CheckArg("u", PR_FALSE, &username); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n"); return 1; @@ -1162,7 +1185,7 @@ HandleRemoteArgument(const char* remote) return 0; } -static PRBool +static RemoteResult RemoteCommandLine() { nsresult rv; @@ -1173,24 +1196,24 @@ RemoteCommandLine() const char *username = getenv("LOGNAME"); const char *temp = nsnull; - ar = CheckArg("a", &temp); + ar = CheckArg("a", PR_TRUE, &temp); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n"); - return PR_FALSE; + return REMOTE_ARG_BAD; } else if (ar == ARG_FOUND) { program.Assign(temp); } - ar = CheckArg("u", &username); + ar = CheckArg("u", PR_TRUE, &username); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n"); - return PR_FALSE; + return REMOTE_ARG_BAD; } XRemoteClient client; rv = client.Init(); if (NS_FAILED(rv)) - return PR_FALSE; + return REMOTE_NOT_FOUND; nsXPIDLCString response; PRBool success = PR_FALSE; @@ -1199,9 +1222,9 @@ RemoteCommandLine() getter_Copies(response), &success); // did the command fail? if (NS_FAILED(rv) || !success) - return PR_FALSE; + return REMOTE_NOT_FOUND; - return PR_TRUE; + return REMOTE_FOUND; } #endif // MOZ_ENABLE_XREMOTE @@ -1347,7 +1370,7 @@ XRE_GetBinaryPath(const char* argv0, nsILocalFile* *aResult) if (NS_FAILED(rv)) return rv; -#elif +#else #error Oops, you need platform-specific code here #endif @@ -1355,33 +1378,98 @@ XRE_GetBinaryPath(const char* argv0, nsILocalFile* *aResult) return NS_OK; } -// copied from nsXREDirProvider.cpp -#ifdef XP_WIN -static nsresult -GetShellFolderPath(int folder, char result[MAXPATHLEN]) -{ - LPITEMIDLIST pItemIDList = NULL; - - nsresult rv; - if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, folder, &pItemIDList)) && - SUCCEEDED(SHGetPathFromIDList(pItemIDList, result))) { - rv = NS_OK; - } else { - rv = NS_ERROR_NOT_AVAILABLE; - } - - CoTaskMemFree(pItemIDList); - - return rv; -} -#endif - #define NS_ERROR_LAUNCHED_CHILD_PROCESS NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_PROFILE, 200) #ifdef XP_WIN #include "nsWindowsRestart.cpp" #endif +#if defined(XP_OS2) && (__GNUC__ == 3 && __GNUC_MINOR__ == 3) // broken OS/2 GCC +// Copy the environment maintained by the C library into an ASCIIZ array +// that can be used to pass it on to the OS/2 Dos* APIs (which otherwise +// don't know anything about the stuff set by PR_SetEnv() or setenv()). +char *createEnv() +{ + // just allocate the maximum amount (24 kB = 0x60000 bytes), to be able to + // copy the existing environment + char *env = (char *)calloc(0x6000, sizeof(char)); + if (!env) { + return NULL; + } + + // walk along the environ string array of the C library and copy + // everything (that fits) into the output environment array, leaving + // null bytes between the entries + char *penv = env; // movable pointer to result environment ASCIIZ array + int i = 0, space = 0x6000; + while (environ[i] && environ[i][0]) { + int len = strlen(environ[i]); + if (space - len <= 0) { + break; + } + strcpy(penv, environ[i]); + i++; // next environment variable + penv += len + 1; // jump to after next null byte + space -= len - 1; // subtract consumed length from usable space + } + + return env; +} + +// OS2LaunchChild() is there to replace _execv() which is broken in the C +// runtime library that comes with GCC 3.3.5 on OS/2. It uses createEnv() +// to copy the process environment and add necessary variables +// +// returns -1 on failure and 0 on success +int OS2LaunchChild(const char *aExePath, int aArgc, char **aArgv) +{ + // find total length of aArgv + int len = 0; + for (int i = 0; i < aArgc; i++) { + len += strlen(aArgv[i]) + 1; // plus space in between + } + len++; // leave space for null byte at end + // allocate enough space for all strings and nulls, + // calloc helpfully initializes to null + char *args = (char *)calloc(len, sizeof(char)); + if (!args) { + return -1; + } + char *pargs = args; // extra pointer to after the last argument + // build argument list in the format the DosStartSession() wants, + // adding spaces between the arguments + for (int i = 0; i < aArgc; i++, *pargs++ = ' ') { + strcpy(pargs, aArgv[i]); + pargs += strlen(aArgv[i]); + } + if (aArgc > 1) { + *(pargs-1) = '\0'; // replace last space + } + *pargs = '\0'; + // make sure that the program is separated by null byte + pargs = strchr(args, ' '); + if (pargs) { + *pargs = '\0'; + } + + char *env = createEnv(); + + char error[CCHMAXPATH] = { 0 }; + RESULTCODES crc = { 0 }; + ULONG rc = DosExecPgm(error, sizeof(error), EXEC_ASYNC, args, env, + &crc, (PSZ)aExePath); + free(args); // done with the arguments + if (env) { + free(env); + } + if (rc != NO_ERROR) { + return -1; + } + + return 0; +} +#endif + // If aBlankCommandLine is true, then the application will be launched with a // blank command line instead of being launched with the same command line that // it was initially started with. @@ -1417,6 +1505,10 @@ static nsresult LaunchChild(nsINativeAppSupport* aNative, #if defined(XP_WIN) if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv, needElevation)) return NS_ERROR_FAILURE; +#elif defined(XP_OS2) && (__GNUC__ == 3 && __GNUC_MINOR__ == 3) + // implementation of _execv() is broken with GCC 3.3.x on OS/2 + if (OS2LaunchChild(exePath.get(), gRestartArgc, gRestartArgv) == -1) + return NS_ERROR_FAILURE; #elif defined(XP_OS2) if (_execv(exePath.get(), gRestartArgv) == -1) return NS_ERROR_FAILURE; @@ -1667,10 +1759,17 @@ SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative, *aResult = nsnull; *aStartOffline = PR_FALSE; + ar = CheckArg("offline", PR_TRUE); + if (ar == ARG_BAD) { + PR_fprintf(PR_STDERR, "Error: argument -offline is invalid when argument -osint is specified\n"); + return NS_ERROR_FAILURE; + } + arg = PR_GetEnv("XRE_START_OFFLINE"); - if ((arg && *arg) || CheckArg("offline")) + if ((arg && *arg) || ar) *aStartOffline = PR_TRUE; + arg = PR_GetEnv("XRE_PROFILE_PATH"); if (arg && *arg) { nsCOMPtr lf; @@ -1690,17 +1789,22 @@ SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative, // Clear out flags that we handled (or should have handled!) last startup. const char *dummy; - CheckArg("p", &dummy); - CheckArg("profile", &dummy); + CheckArg("p", PR_FALSE, &dummy); + CheckArg("profile", PR_FALSE, &dummy); CheckArg("profilemanager"); return NS_LockProfilePath(lf, localDir, nsnull, aResult); } - if (CheckArg("migration")) + ar = CheckArg("migration", PR_TRUE); + if (ar == ARG_BAD) { + PR_fprintf(PR_STDERR, "Error: argument -migration is invalid when argument -osint is specified\n"); + return NS_ERROR_FAILURE; + } else if (ar == ARG_FOUND) { gDoMigration = PR_TRUE; + } - ar = CheckArg("profile", &arg); + ar = CheckArg("profile", PR_TRUE, &arg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument -profile requires a path\n"); return NS_ERROR_FAILURE; @@ -1725,7 +1829,7 @@ SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative, rv = NS_NewToolkitProfileService(getter_AddRefs(profileSvc)); NS_ENSURE_SUCCESS(rv, rv); - ar = CheckArg("createprofile", &arg); + ar = CheckArg("createprofile", PR_TRUE, &arg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument -createprofile requires a profile name\n"); return NS_ERROR_FAILURE; @@ -1782,11 +1886,21 @@ SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative, } } - ar = CheckArg("p", &arg); + ar = CheckArg("p", PR_FALSE, &arg); if (ar == ARG_BAD) { + ar = CheckArg("osint"); + if (ar == ARG_FOUND) { + PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n"); + return NS_ERROR_FAILURE; + } return ShowProfileManager(profileSvc, aNative); } if (ar) { + ar = CheckArg("osint"); + if (ar == ARG_FOUND) { + PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n"); + return NS_ERROR_FAILURE; + } nsCOMPtr profile; rv = profileSvc->GetProfileByName(nsDependentCString(arg), getter_AddRefs(profile)); @@ -1811,7 +1925,11 @@ SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative, return ShowProfileManager(profileSvc, aNative); } - if (CheckArg("profilemanager")) { + ar = CheckArg("profilemanager", PR_TRUE); + if (ar == ARG_BAD) { + PR_fprintf(PR_STDERR, "Error: argument -profilemanager is invalid when argument -osint is specified\n"); + return NS_ERROR_FAILURE; + } else if (ar == ARG_FOUND) { return ShowProfileManager(profileSvc, aNative); } @@ -2086,6 +2204,7 @@ int XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) { nsresult rv; + ArgResult ar; NS_TIMELINE_MARK("enter main"); #ifdef DEBUG @@ -2201,13 +2320,23 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) ScopedFPHandler handler; #endif /* XP_OS2 */ - if (CheckArg("safe-mode")) + ar = CheckArg("safe-mode", PR_TRUE); + if (ar == ARG_BAD) { + PR_fprintf(PR_STDERR, "Error: argument -safe-mode is invalid when argument -osint is specified\n"); + return 1; + } else if (ar == ARG_FOUND) { gSafeMode = PR_TRUE; + } // Handle -no-remote command line argument. Setup the environment to // better accommodate other components and various restart scenarios. - if (CheckArg("no-remote")) + ar = CheckArg("no-remote", PR_TRUE); + if (ar == ARG_BAD) { + PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n"); + return 1; + } else if (ar == ARG_FOUND) { PR_SetEnv("MOZ_NO_REMOTE=1"); + } // Handle -help and -version command line arguments. // They should return quickly, so we deal with them here. @@ -2233,7 +2362,12 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) } // Check for -register, which registers chrome and then exits immediately. - if (CheckArg("register")) { + + ar = CheckArg("register", PR_TRUE); + if (ar == ARG_BAD) { + PR_fprintf(PR_STDERR, "Error: argument -register is invalid when argument -osint is specified\n"); + return 1; + } else if (ar == ARG_FOUND) { ScopedXPCOMStartup xpcom; rv = xpcom.Initialize(); NS_ENSURE_SUCCESS(rv, 1); @@ -2253,6 +2387,9 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) // in nsAppShell::Create, but we need to get in before gtk // has been initialized to make sure everything is running // consistently. +#if defined(MOZ_WIDGET_GTK2) + g_thread_init(NULL); +#endif if (CheckArg("install")) gdk_rgb_set_install(TRUE); @@ -2331,7 +2468,7 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) // handle -remote now that xpcom is fired up const char* xremotearg; - ArgResult ar = CheckArg("remote", &xremotearg); + ar = CheckArg("remote", PR_TRUE, &xremotearg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: -remote requires an argument\n"); return 1; @@ -2342,8 +2479,11 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) if (!PR_GetEnv("MOZ_NO_REMOTE")) { // Try to remote the entire command line. If this fails, start up normally. - if (RemoteCommandLine()) + RemoteResult rr = RemoteCommandLine(); + if (rr == REMOTE_FOUND) return 0; + else if (rr == REMOTE_ARG_BAD) + return 1; } #endif @@ -2367,50 +2507,18 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) } // Check for and process any available updates - nsCOMPtr updRoot = dirProvider.GetAppDir(); - nsCOMPtr updRootl(do_QueryInterface(updRoot)); - -#ifdef XP_WIN - // Use \updates\ if app dir is under Program Files to avoid the - // folder virtualization mess on Windows Vista - char path[MAXPATHLEN]; - rv = GetShellFolderPath(CSIDL_PROGRAM_FILES, path); - - // Fallback to previous behavior since getting CSIDL_PROGRAM_FILES may fail - // on Win9x. - if (NS_SUCCEEDED(rv)) { - nsCOMPtr programFilesDir; - rv = NS_NewNativeLocalFile(nsDependentCString(path), PR_FALSE, - getter_AddRefs(programFilesDir)); - NS_ENSURE_SUCCESS(rv, 1); - - PRBool descendant; - rv = programFilesDir->Contains(updRootl, PR_TRUE, &descendant); - NS_ENSURE_SUCCESS(rv, 1); - if (descendant) { - nsCAutoString relativePath; - rv = updRootl->GetRelativeDescriptor(programFilesDir, relativePath); - NS_ENSURE_SUCCESS(rv, 1); - - nsCOMPtr userLocalDir; - rv = dirProvider.GetUserLocalDataDirectory(getter_AddRefs(userLocalDir)); - NS_ENSURE_SUCCESS(rv, 1); - - rv = NS_NewNativeLocalFile(EmptyCString(), PR_FALSE, - getter_AddRefs(updRootl)); - NS_ENSURE_SUCCESS(rv, 1); - - rv = updRootl->SetRelativeDescriptor(userLocalDir, relativePath); - NS_ENSURE_SUCCESS(rv, 1); - } - } -#endif + nsCOMPtr updRoot; + PRBool persistent; + rv = dirProvider.GetFile(XRE_UPDATE_ROOT_DIR, &persistent, + getter_AddRefs(updRoot)); + // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed + if (NS_FAILED(rv)) + updRoot = dirProvider.GetAppDir(); // Check for and process any available updates ProcessUpdates(greDir, appDir, - updRootl, + updRoot, gRestartArgc, gRestartArgv); #endif @@ -2591,7 +2699,21 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) nsCOMPtr em(do_GetService("@mozilla.org/extensions/manager;1")); NS_ENSURE_TRUE(em, 1); - if (CheckArg("install-global-extension") || CheckArg("install-global-theme")) { + ar = CheckArg("install-global-extension", PR_TRUE); + if (ar == ARG_BAD) { + PR_fprintf(PR_STDERR, "Error: argument -install-global-extension is invalid when argument -osint is specified\n"); + return 1; + } else if (ar == ARG_FOUND) { + // Do the required processing and then shut down. + em->HandleCommandLineArgs(cmdLine); + return 0; + } + + ar = CheckArg("install-global-theme", PR_TRUE); + if (ar == ARG_BAD) { + PR_fprintf(PR_STDERR, "Error: argument -install-global-theme is invalid when argument -osint is specified\n"); + return 1; + } else if (ar == ARG_FOUND) { // Do the required processing and then shut down. em->HandleCommandLineArgs(cmdLine); return 0; diff --git a/toolkit/xre/nsAppRunner.h b/toolkit/xre/nsAppRunner.h index 8dfc650e..13b06acf 100644 --- a/toolkit/xre/nsAppRunner.h +++ b/toolkit/xre/nsAppRunner.h @@ -71,6 +71,16 @@ // such as showing the profile manager uI, this key will not be available. #define NS_APP_PROFILE_LOCAL_DIR_STARTUP "ProfLDS" +/** + * A directory service key which provides the update directory. + * At present this is supported only on Windows. + * Windows: Documents and Settings\\Local Settings\Application Data\ + * \\ + * If appDir is not under the Program Files, directory service will fail. + * Callers should fallback to appDir. + */ +#define XRE_UPDATE_ROOT_DIR "UpdRootD" + class nsACString; struct nsXREAppData; struct nsStaticModuleInfo; diff --git a/toolkit/xre/nsXREDirProvider.cpp b/toolkit/xre/nsXREDirProvider.cpp index 851cac7c..487acad4 100644 --- a/toolkit/xre/nsXREDirProvider.cpp +++ b/toolkit/xre/nsXREDirProvider.cpp @@ -68,6 +68,9 @@ #ifndef CSIDL_LOCAL_APPDATA #define CSIDL_LOCAL_APPDATA 0x001C #endif +#ifndef CSIDL_PROGRAM_FILES +#define CSIDL_PROGRAM_FILES 0x0026 +#endif #endif #ifdef XP_MACOSX #include "nsILocalFileMac.h" @@ -134,13 +137,6 @@ nsXREDirProvider::SetProfile(nsIFile* aDir, nsIFile* aLocalDir) { NS_ASSERTION(aDir && aLocalDir, "We don't support no-profile apps yet!"); -#ifdef DEBUG_bsmedberg - nsCAutoString path, path2; - aDir->GetNativePath(path); - aLocalDir->GetNativePath(path2); - printf("nsXREDirProvider::SetProfile('%s', '%s')\n", path.get(), path2.get()); -#endif - nsresult rv; rv = EnsureDirectoryExists(aDir); @@ -205,6 +201,11 @@ nsXREDirProvider::GetFile(const char* aProperty, PRBool* aPersistent, !strcmp(aProperty, XRE_USER_APP_DATA_DIR)) { rv = GetUserAppDataDirectory((nsILocalFile**)(nsIFile**) getter_AddRefs(file)); } +#ifdef XP_WIN + else if (!strcmp(aProperty, XRE_UPDATE_ROOT_DIR)) { + rv = GetUpdateRootDir(getter_AddRefs(file)); + } +#endif else if (!strcmp(aProperty, NS_APP_APPLICATION_REGISTRY_FILE)) { rv = GetUserAppDataDirectory((nsILocalFile**)(nsIFile**) getter_AddRefs(file)); rv |= file->AppendNative(NS_LITERAL_CSTRING(APP_REGISTRY_NAME)); @@ -725,6 +726,65 @@ GetShellFolderPath(int folder, char result[MAXPATHLEN]) pMalloc->Release(); return rv; } + +nsresult +nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult) +{ + nsCOMPtr appDir = GetAppDir(); + nsCAutoString appPath; + nsresult rv = appDir->GetNativePath(appPath); + NS_ENSURE_SUCCESS(rv, rv); + + // AppDir may be a short path. Convert to long path to make sure + // the consistency of the update folder location + nsCString longPath; + longPath.SetLength(MAXPATHLEN); + char *buf = longPath.BeginWriting(); + + DWORD (WINAPI *pGetLongPathName)(LPCTSTR, LPTSTR, DWORD); + // GetLongPathName() is not present on WinNT 4.0 + *(FARPROC *)&pGetLongPathName = + GetProcAddress(GetModuleHandle("kernel32.dll"), "GetLongPathNameA"); + + if (pGetLongPathName) { + DWORD len = pGetLongPathName(appPath.get(), buf, MAXPATHLEN); + // Failing GetLongPathName() is not fatal. + if (len <= 0 || len >= MAXPATHLEN) + longPath.Assign(appPath); + else + longPath.SetLength(len); + } + else { + longPath.Assign(appPath); + } + + // Use \updates\ if app dir is under Program Files to avoid the + // folder virtualization mess on Windows Vista + char programFiles[MAXPATHLEN]; + rv = GetShellFolderPath(CSIDL_PROGRAM_FILES, programFiles); + NS_ENSURE_SUCCESS(rv, rv); + + PRUint32 programFilesLen = strlen(programFiles); + programFiles[programFilesLen++] = '\\'; + programFiles[programFilesLen] = '\0'; + + if (longPath.Length() < programFilesLen) + return NS_ERROR_FAILURE; + + if (_strnicmp(programFiles, longPath.get(), programFilesLen) != 0) + return NS_ERROR_FAILURE; + + nsCOMPtr updRoot; + rv = GetUserLocalDataDirectory(getter_AddRefs(updRoot)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = updRoot->AppendRelativeNativePath(Substring(longPath, programFilesLen)); + NS_ENSURE_SUCCESS(rv, rv); + + NS_ADDREF(*aResult = updRoot); + return NS_OK; +} #endif nsresult diff --git a/toolkit/xre/nsXREDirProvider.h b/toolkit/xre/nsXREDirProvider.h index 28535480..db9d9524 100644 --- a/toolkit/xre/nsXREDirProvider.h +++ b/toolkit/xre/nsXREDirProvider.h @@ -80,6 +80,13 @@ public: /* make sure you clone it, if you need to do stuff to it */ nsIFile* GetAppDir() { return mAppDir; } + /** + * Get the directory under which update directory is created. + * This method may be called before XPCOM is started. aResult + * is a clone, it may be modified. + */ + nsresult GetUpdateRootDir(nsIFile* *aResult); + protected: static nsresult GetUserDataDirectory(nsILocalFile* *aFile, PRBool aLocal); static nsresult EnsureDirectoryExists(nsIFile* aDirectory); diff --git a/uriloader/base/nsURILoader.cpp b/uriloader/base/nsURILoader.cpp index d87255d5..1f8d957d 100644 --- a/uriloader/base/nsURILoader.cpp +++ b/uriloader/base/nsURILoader.cpp @@ -64,7 +64,7 @@ #include "nsXPIDLString.h" #include "nsString.h" - +#include "nsNetUtil.h" #include "nsIDOMWindowInternal.h" #include "nsReadableUtils.h" #include "nsDOMError.h" @@ -446,6 +446,9 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest *request, nsISupports * if (multipartChannel) { rv = multipartChannel->GetContentDisposition(disposition); + } else { + // Soon-to-be common way to get Disposition: right now only JARChannel + rv = NS_GetContentDisposition(request, disposition); } } diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index 2cc165b7..52d2b331 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -2158,6 +2158,19 @@ nsresult nsExternalAppHandler::ExecuteDesiredAction() if (NS_SUCCEEDED(rv)) rv = OpenWithApplication(); } + else + { + // Cancel the download and report an error. We do not want to end up in + // a state where it appears that we have a normal download that is + // pointing to a file that we did not actually create. + nsAutoString path; + mTempFile->GetPath(path); + SendStatusChange(kWriteError, rv, nsnull, path); + Cancel(rv); + + // We still need to notify if we have a progress listener, so we cannot + // return at this point. + } } else // Various unknown actions go here too { diff --git a/view/src/nsScrollPortView.cpp b/view/src/nsScrollPortView.cpp index b3239b97..6b41cd6b 100644 --- a/view/src/nsScrollPortView.cpp +++ b/view/src/nsScrollPortView.cpp @@ -756,10 +756,13 @@ nsScrollPortView::IncrementalScroll() return; } + nsWeakView thisView = this; if (mSmoothScroll->mFrameIndex < SMOOTH_SCROLL_FRAMES) { ScrollToImpl(mOffsetX + mSmoothScroll->mVelocities[mSmoothScroll->mFrameIndex*2], mOffsetY + mSmoothScroll->mVelocities[mSmoothScroll->mFrameIndex*2 + 1], 0); + if (!thisView.IsAlive()) + return; mSmoothScroll->mFrameIndex++; } else { delete mSmoothScroll; diff --git a/view/src/nsView.cpp b/view/src/nsView.cpp index bee53429..68f03344 100644 --- a/view/src/nsView.cpp +++ b/view/src/nsView.cpp @@ -168,7 +168,8 @@ nsEventStatus PR_CALLBACK HandleEvent(nsGUIEvent *aEvent) if (view) { - view->GetViewManager()->DispatchEvent(aEvent, &result); + nsCOMPtr vm = view->GetViewManager(); + vm->DispatchEvent(aEvent, &result); } return result; diff --git a/view/src/nsViewManager.cpp b/view/src/nsViewManager.cpp index b0d0f85d..fd54731c 100644 --- a/view/src/nsViewManager.cpp +++ b/view/src/nsViewManager.cpp @@ -1637,6 +1637,8 @@ NS_IMETHODIMP nsViewManager::Composite() NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, PRUint32 aUpdateFlags) { + NS_PRECONDITION(nsnull != aView, "null view"); + // Mark the entire view as damaged nsView* view = NS_STATIC_CAST(nsView*, aView); @@ -1998,7 +2000,9 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS vm->mDelayedResize.SizeTo(NSCOORD_NONE, NSCOORD_NONE); // Paint later. - vm->UpdateView(vm->mRootView, NS_VMREFRESH_NO_SYNC); + if (vm->mRootView) { + vm->UpdateView(vm->mRootView, NS_VMREFRESH_NO_SYNC); + } didResize = PR_TRUE; } } diff --git a/xpcom/ds/nsCOMArray.cpp b/xpcom/ds/nsCOMArray.cpp index fa070842..13673de1 100644 --- a/xpcom/ds/nsCOMArray.cpp +++ b/xpcom/ds/nsCOMArray.cpp @@ -55,11 +55,7 @@ nsCOMArray_base::nsCOMArray_base(const nsCOMArray_base& aOther) nsCOMArray_base::~nsCOMArray_base() { - PRInt32 count = Count(), i; - for (i = 0; i < count; ++i) { - nsISupports* obj = ObjectAt(i); - NS_IF_RELEASE(obj); - } + Clear(); } PRInt32 @@ -136,9 +132,10 @@ nsCOMArray_base::RemoveObjectAt(PRInt32 aIndex) { if (PRUint32(aIndex) < PRUint32(Count())) { nsISupports* element = ObjectAt(aIndex); - NS_IF_RELEASE(element); - return mArray.RemoveElementAt(aIndex); + PRBool result = mArray.RemoveElementAt(aIndex); + NS_IF_RELEASE(element); + return result; } return PR_FALSE; @@ -156,7 +153,9 @@ ReleaseObjects(void* aElement, void*) void nsCOMArray_base::Clear() { - mArray.EnumerateForwards(ReleaseObjects, nsnull); - mArray.Clear(); + nsAutoVoidArray objects; + objects = mArray; + mArray.Clear(); + objects.EnumerateForwards(ReleaseObjects, nsnull); } diff --git a/xpcom/ds/nsVoidArray.h b/xpcom/ds/nsVoidArray.h index 90a6260c..12f16efd 100644 --- a/xpcom/ds/nsVoidArray.h +++ b/xpcom/ds/nsVoidArray.h @@ -184,7 +184,13 @@ public: virtual PRBool SizeTo(PRInt32 aMin); virtual void Compact(); - + + nsAutoVoidArray& operator=(const nsVoidArray& other) + { + nsVoidArray::operator=(other); + return *this; + } + protected: // The internal storage enum { kAutoBufSize = 8 }; diff --git a/xpcom/glue/nsCOMPtr.h b/xpcom/glue/nsCOMPtr.h index 5d1c8362..4a8d26b6 100644 --- a/xpcom/glue/nsCOMPtr.h +++ b/xpcom/glue/nsCOMPtr.h @@ -818,6 +818,26 @@ class nsCOMPtr // Other pointer operators + already_AddRefed + forget() + // return the value of mRawPtr and null out mRawPtr. Useful for + // already_AddRefed return values. + { + T* temp = 0; + swap(temp); + return temp; + } + + void + forget( T** rhs ) + // Set the target of rhs to the value of mRawPtr and null out mRawPtr. + // Useful to avoid unnecessary AddRef/Release pairs with "out" + // parameters. + { + NS_ASSERTION(rhs, "Null pointer passed to forget!"); + *rhs = 0; + swap(*rhs); + } nsDerivedSafe* get() const @@ -1125,6 +1145,26 @@ class nsCOMPtr // Other pointer operators + already_AddRefed + forget() + // return the value of mRawPtr and null out mRawPtr. Useful for + // already_AddRefed return values. + { + nsISupports* temp = 0; + swap(temp); + return temp; + } + + void + forget( nsISupports** rhs ) + // Set the target of rhs to the value of mRawPtr and null out mRawPtr. + // Useful to avoid unnecessary AddRef/Release pairs with "out" + // parameters. + { + NS_ASSERTION(rhs, "Null pointer passed to forget!"); + *rhs = 0; + swap(*rhs); + } nsDerivedSafe* get() const diff --git a/xpcom/glue/nsISupportsImpl.h b/xpcom/glue/nsISupportsImpl.h index 9085a148..a20b3c1f 100644 --- a/xpcom/glue/nsISupportsImpl.h +++ b/xpcom/glue/nsISupportsImpl.h @@ -576,6 +576,17 @@ NS_IMETHODIMP_(nsrefcnt) Class::Release(void) \ NS_IMPL_QUERY_BODY(i6) \ NS_IMPL_QUERY_TAIL_INHERITING(Super) \ +#define NS_IMPL_QUERY_INTERFACE_INHERITED7(Class,Super,i1,i2,i3,i4,i5,i6,i7) \ + NS_IMPL_QUERY_HEAD(Class) \ + NS_IMPL_QUERY_BODY(i1) \ + NS_IMPL_QUERY_BODY(i2) \ + NS_IMPL_QUERY_BODY(i3) \ + NS_IMPL_QUERY_BODY(i4) \ + NS_IMPL_QUERY_BODY(i5) \ + NS_IMPL_QUERY_BODY(i6) \ + NS_IMPL_QUERY_BODY(i7) \ + NS_IMPL_QUERY_TAIL_INHERITING(Super) \ + /** * Convenience macros for implementing all nsISupports methods for * a simple class. @@ -684,6 +695,11 @@ NS_IMETHODIMP_(nsrefcnt) Class::Release(void) \ NS_IMPL_ADDREF_INHERITED(Class, Super) \ NS_IMPL_RELEASE_INHERITED(Class, Super) \ +#define NS_IMPL_ISUPPORTS_INHERITED7(Class, Super, i1, i2, i3, i4, i5, i6, i7) \ + NS_IMPL_QUERY_INTERFACE_INHERITED7(Class, Super, i1, i2, i3, i4, i5, i6, i7) \ + NS_IMPL_ADDREF_INHERITED(Class, Super) \ + NS_IMPL_RELEASE_INHERITED(Class, Super) \ + /////////////////////////////////////////////////////////////////////////////// /** * diff --git a/xpcom/io/nsLocalFileUnix.cpp b/xpcom/io/nsLocalFileUnix.cpp index 80100a46..da2b8feb 100644 --- a/xpcom/io/nsLocalFileUnix.cpp +++ b/xpcom/io/nsLocalFileUnix.cpp @@ -1360,6 +1360,45 @@ nsLocalFile::IsExecutable(PRBool *_retval) return NS_OK; } + // Check extension (bug 663899). On certain platforms, the file + // extension may cause the OS to treat it as executable regardless of + // the execute bit, such as .jar on Mac OS X. We borrow the code from + // nsLocalFileWin, slightly modified. + + // Don't be fooled by symlinks. + PRBool symLink; + nsresult rv = IsSymlink(&symLink); + if (NS_FAILED(rv)) + return rv; + + nsAutoString path; + if (symLink) + GetTarget(path); + else + GetPath(path); + + PRInt32 dotIdx = path.RFindChar(PRUnichar('.')); + if (dotIdx != kNotFound) { + // Convert extension to lower case. + PRUnichar *p = path.BeginWriting(); + for(p += dotIdx + 1; *p; p++) + *p += (*p >= L'A' && *p <= L'Z') ? 'a' - 'A' : 0; + + // Search for any of the set of executable extensions. + static const char * const executableExts[] = { + "air", // Adobe AIR installer + "jar"}; // java application bundle + nsDependentSubstring ext = Substring(path, dotIdx + 1); + for (int i = 0; i < NS_ARRAY_LENGTH(executableExts); i++) { + if (ext.EqualsASCII(executableExts[i])) { + // Found a match. Set result and quit. + *_retval = PR_TRUE; + return NS_OK; + } + } + } + + // Failing that, check the execute bit. *_retval = (access(mPath.get(), X_OK) == 0); if (*_retval || errno == EACCES) return NS_OK; diff --git a/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390.cpp b/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390.cpp index 154fbcee..a8c13245 100644 --- a/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390.cpp +++ b/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390.cpp @@ -213,6 +213,7 @@ XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, PRUint32 overflow = invoke_count_words (paramCount, params); PRUint32 result; + register PRUint32 reg_paramCount __asm ("4") = paramCount; __asm__ __volatile__ ( "lr 7,15\n\t" @@ -240,14 +241,15 @@ XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, "la 15,32(7)\n\t" "lr %0,2\n\t" - : "=r" (result) - : "r" (paramCount), - "r" (params), + : "=r" (result), + "=r" (reg_paramCount) + : "r" (params), "r" (overflow), "a" (invoke_copy_to_stack), "a" (that), - "a" (method) - : "2", "3", "4", "5", "6", "7", "14", "cc", "memory", "%f0", "%f2" + "a" (method), + "1" (reg_paramCount) + : "2", "3", "5", "6", "7", "14", "cc", "memory", "%f0", "%f2" ); return result; diff --git a/xpcom/string/src/nsPrintfCString.cpp b/xpcom/string/src/nsPrintfCString.cpp index 8bb06da6..5c743611 100644 --- a/xpcom/string/src/nsPrintfCString.cpp +++ b/xpcom/string/src/nsPrintfCString.cpp @@ -71,7 +71,8 @@ nsPrintfCString::nsPrintfCString( size_type n, const char_type* format, ... ) if ( n > logical_capacity ) { SetCapacity(n); - if (Capacity() < n) + size_type capacity = Capacity(); + if (capacity == size_type(-1) || capacity < n) return; // out of memory !! logical_capacity = n; } diff --git a/xpcom/string/src/nsSubstring.cpp b/xpcom/string/src/nsSubstring.cpp index 8e47a2bb..ad2d5fe6 100644 --- a/xpcom/string/src/nsSubstring.cpp +++ b/xpcom/string/src/nsSubstring.cpp @@ -199,6 +199,9 @@ nsStringBuffer::Alloc(size_t size) STRING_STAT_INCREMENT(Alloc); NS_ASSERTION(size != 0, "zero capacity allocation not allowed"); + NS_ASSERTION(sizeof(nsStringBuffer) + size <= size_t(PRUint32(-1)) && + sizeof(nsStringBuffer) + size > size, + "mStorageSize will truncate"); nsStringBuffer *hdr = (nsStringBuffer *) malloc(sizeof(nsStringBuffer) + size); @@ -216,6 +219,9 @@ nsStringBuffer::Realloc(nsStringBuffer* hdr, size_t size) STRING_STAT_INCREMENT(Realloc); NS_ASSERTION(size != 0, "zero capacity allocation not allowed"); + NS_ASSERTION(sizeof(nsStringBuffer) + size <= size_t(PRUint32(-1)) && + sizeof(nsStringBuffer) + size > size, + "mStorageSize will truncate"); // no point in trying to save ourselves if we hit this assertion NS_ASSERTION(!hdr->IsReadonly(), "|Realloc| attempted on readonly string"); diff --git a/xpcom/string/src/nsTSubstring.cpp b/xpcom/string/src/nsTSubstring.cpp index 1eb89b2d..fcbe0837 100644 --- a/xpcom/string/src/nsTSubstring.cpp +++ b/xpcom/string/src/nsTSubstring.cpp @@ -36,6 +36,7 @@ * * ***** END LICENSE BLOCK ***** */ +#include "nspr.h" /** * helper function for down-casting a nsTSubstring to a nsTFixedString. @@ -63,10 +64,13 @@ nsTSubstring_CharT::MutatePrep( size_type capacity, char_type** oldData, PRUint3 size_type curCapacity = Capacity(); - // If |capacity > size_type(-1)/2|, then our doubling algorithm may not be + // If |capacity > kMaxCapacity|, then our doubling algorithm may not be // able to allocate it. Just bail out in cases like that. We don't want // to be allocating 2GB+ strings anyway. - if (capacity > size_type(-1)/2) { + PR_STATIC_ASSERT((sizeof(nsStringBuffer) & 0x1) == 0); + const size_type kMaxCapacity = + (size_type(-1)/2 - sizeof(nsStringBuffer)) / sizeof(char_type) - 2; + if (capacity > kMaxCapacity) { // Also assert for |capacity| equal to |size_type(-1)|, since we use that value to // flag immutability. NS_ASSERTION(capacity != size_type(-1), "Bogus capacity"); @@ -82,15 +86,15 @@ nsTSubstring_CharT::MutatePrep( size_type capacity, char_type** oldData, PRUint3 if (capacity <= curCapacity) return PR_TRUE; - if (curCapacity > 0) - { - // use doubling algorithm when forced to increase available - // capacity. - PRUint32 temp = curCapacity; - while (temp < capacity) - temp <<= 1; - capacity = temp; - } + if (curCapacity > 0) { + // Use doubling algorithm when forced to increase available capacity. + size_type temp = curCapacity; + while (temp < capacity) + temp <<= 1; + NS_ASSERTION(NS_MIN(temp, kMaxCapacity) >= capacity, + "should have hit the early return at the top"); + capacity = NS_MIN(temp, kMaxCapacity); + } } // @@ -548,7 +552,8 @@ nsTSubstring_CharT::SetLength( size_type length ) // out. We should improve that. For now we just verify that the capacity // changed as expected as a means of error checking. - if (Capacity() >= length) + size_type capacity = Capacity(); + if (capacity != size_type(-1) && capacity >= length) mLength = length; } diff --git a/xpfe/components/autocomplete/public/nsILDAPAutoCompleteSession.idl b/xpfe/components/autocomplete/public/nsILDAPAutoCompleteSession.idl index 9f08e914..b5da212c 100644 --- a/xpfe/components/autocomplete/public/nsILDAPAutoCompleteSession.idl +++ b/xpfe/components/autocomplete/public/nsILDAPAutoCompleteSession.idl @@ -49,6 +49,9 @@ interface nsIMutableArray; /** * Extends nsIAutoCompleteSession to have various LDAP-specific parameters. * and output format. + * + * Note: the formatter attribute should be set prior to starting the LDAP + * lookup via nsIAutoCompleteSession::OnStartLookup. */ [scriptable, uuid(e7f26534-f96c-4c87-803c-30cdf0bc2973)] interface nsILDAPAutoCompleteSession : nsIAutoCompleteSession { @@ -115,7 +118,8 @@ interface nsILDAPAutoCompleteSession : nsIAutoCompleteSession { /** * Callback used to format an individual LDAP message into an - * nsIAutoCompleteItem. + * nsIAutoCompleteItem. This is required to be set before calling + * OnStartLookup. */ attribute nsILDAPAutoCompFormatter formatter; diff --git a/xpfe/components/autocomplete/src/nsLDAPAutoCompleteSession.cpp b/xpfe/components/autocomplete/src/nsLDAPAutoCompleteSession.cpp index 7dd01f5e..f567e8ad 100644 --- a/xpfe/components/autocomplete/src/nsLDAPAutoCompleteSession.cpp +++ b/xpfe/components/autocomplete/src/nsLDAPAutoCompleteSession.cpp @@ -105,6 +105,13 @@ nsLDAPAutoCompleteSession::OnStartLookup(const PRUnichar *searchString, { nsresult rv; // hold return values from XPCOM calls + NS_ENSURE_ARG_POINTER(listener); + if (!mFormatter) + { + NS_WARNING("mFormatter should not be null for nsLDAPAutoCompleteSession::OnStartLookup"); + return NS_ERROR_NOT_INITIALIZED; + } + #ifdef PR_LOGGING // initialize logging, if it hasn't been already // @@ -118,14 +125,8 @@ nsLDAPAutoCompleteSession::OnStartLookup(const PRUnichar *searchString, PR_LOG(sLDAPAutoCompleteLogModule, PR_LOG_DEBUG, ("nsLDAPAutoCompleteSession::OnStartLookup entered\n")); - - if (!listener) { - NS_ERROR("nsLDAPAutoCompleteSession::OnStartLookup(): NULL listener" - "passed in"); - return NS_ERROR_NULL_POINTER; - } else { - mListener = listener; // save it for later callbacks - } + + mListener = listener; // ignore the empty string, strings with @ in them, and strings // that are too short @@ -156,9 +157,6 @@ nsLDAPAutoCompleteSession::OnStartLookup(const PRUnichar *searchString, return NS_ERROR_FAILURE; } - NS_ASSERTION(mFormatter, "nsLDAPAutoCompleteSession::OnStartLookup(): " - "formatter attribute has not been set"); - // see if this is a narrow search that we could potentially do locally // if (previousSearchResult) { diff --git a/xpfe/components/shistory/src/nsSHTransaction.cpp b/xpfe/components/shistory/src/nsSHTransaction.cpp index 7df15527..2050349a 100644 --- a/xpfe/components/shistory/src/nsSHTransaction.cpp +++ b/xpfe/components/shistory/src/nsSHTransaction.cpp @@ -111,10 +111,12 @@ nsSHTransaction::GetNext(nsISHTransaction * * aResult) NS_IMETHODIMP nsSHTransaction::SetNext(nsISHTransaction * aNext) { - NS_ENSURE_SUCCESS(aNext->SetPrev(this), NS_ERROR_FAILURE); + if (aNext) { + NS_ENSURE_SUCCESS(aNext->SetPrev(this), NS_ERROR_FAILURE); + } - mNext = aNext; - return NS_OK; + mNext = aNext; + return NS_OK; } NS_IMETHODIMP diff --git a/xpfe/components/shistory/src/nsSHistory.cpp b/xpfe/components/shistory/src/nsSHistory.cpp index 5bae5bba..a3c56509 100644 --- a/xpfe/components/shistory/src/nsSHistory.cpp +++ b/xpfe/components/shistory/src/nsSHistory.cpp @@ -561,9 +561,14 @@ nsSHistory::PurgeHistory(PRInt32 aEntries) PRInt32 cnt = 0; while (cnt < aEntries) { nsCOMPtr nextTxn; - if (mListRoot) + if (mListRoot) { mListRoot->GetNext(getter_AddRefs(nextTxn)); + mListRoot->SetNext(nsnull); + } mListRoot = nextTxn; + if (mListRoot) { + mListRoot->SetPrev(nsnull); + } cnt++; } mLength -= cnt; diff --git a/xpinstall/wizard/windows/builder/Makefile.in b/xpinstall/wizard/windows/builder/Makefile.in index 96d67e35..860c6907 100644 --- a/xpinstall/wizard/windows/builder/Makefile.in +++ b/xpinstall/wizard/windows/builder/Makefile.in @@ -37,7 +37,7 @@ # # ***** END LICENSE BLOCK ***** -DEPTH = ../../../.. +DEPTH = ../../.. topsrcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ @@ -47,7 +47,7 @@ include $(DEPTH)/config/autoconf.mk MODULE = xpinstall installer: - $(PERL) $(srcdir)/build.pl + $(PERL) build.pl include $(topsrcdir)/config/rules.mk diff --git a/xpinstall/wizard/windows/builder/build.pl b/xpinstall/wizard/windows/builder/build.pl index 29716d6b..5ab33e84 100644 --- a/xpinstall/wizard/windows/builder/build.pl +++ b/xpinstall/wizard/windows/builder/build.pl @@ -56,13 +56,11 @@ use File::Copy; use File::Path; use File::Basename; -$DEPTH = "../../../../../obj-sm95-release/"; -#$topsrcdir = "/c/projects/moz95/mozilla"; +$DEPTH = "../../../.."; $topsrcdir = GetTopSrcDir(); # ensure that Packager.pm is in @INC, since we might not be called from # mozilla/xpinstall/packager -# line below is "/xpinstall/packager" -push(@INC, "/c/projects/moz95/mozilla/xpinstall/packager"); +push(@INC, "$topsrcdir/../mozilla/xpinstall/packager"); require StageUtils; ParseArgv(@ARGV); @@ -74,8 +72,7 @@ $inStagePath = "$topobjdir/stage" if !defined($inStagePath); $inDistPath = "$topobjdir/dist" if !defined($inDistPath); $cwdBuilder = "$topsrcdir/xpinstall/wizard/windows/builder"; $gDistInstallPath = "$inDistPath/install"; -$gPackagerPath = "/c/projects/moz95/mozilla/xpinstall/packager"; - +$gPackagerPath = "$topsrcdir/xpinstall/packager"; if(defined($ENV{DEBUG_INSTALLER_BUILD})) { diff --git a/xulrunner/app/Makefile.in b/xulrunner/app/Makefile.in index 39c3d256..74400b83 100644 --- a/xulrunner/app/Makefile.in +++ b/xulrunner/app/Makefile.in @@ -59,8 +59,13 @@ DEFINES += -DAB_CD=$(AB_CD) ifeq ($(USE_SHORT_LIBNAME), 1) PROGRAM = xulrunner$(BIN_SUFFIX) else +ifeq ($(OS_ARCH), BeOS) +PROGRAM = xulrunner$(BIN_SUFFIX) +else PROGRAM = xulrunner-bin$(BIN_SUFFIX) endif +endif + DEFINES += -DXULRUNNER_PROGNAME=\"xulrunner\" ifdef MOZ_JAVAXPCOM @@ -237,7 +242,7 @@ LDFLAGS += -Zlinker /NOE endif endif -ifneq (,$(filter-out OS2 WINNT Darwin,$(OS_ARCH))) +ifneq (,$(filter-out OS2 WINNT Darwin BeOS,$(OS_ARCH))) xulrunner:: mozilla.in Makefile.in Makefile $(DEPTH)/config/autoconf.mk cat $< | sed -e "s|%MOZAPPDIR%|$(mozappdir)|" \ diff --git a/xulrunner/app/mozilla.in b/xulrunner/app/mozilla.in index f05d4263..66498501 100644 --- a/xulrunner/app/mozilla.in +++ b/xulrunner/app/mozilla.in @@ -36,7 +36,7 @@ # # ***** END LICENSE BLOCK ***** -## $Id: mozilla.in,v 1.2.8.1 2005/09/20 21:13:06 dbaron%dbaron.org Exp $ +## $Id: mozilla.in,v 1.2.8.2 2008/01/11 03:20:02 reed%reedloden.com Exp $ ## ## Usage: ## @@ -112,6 +112,7 @@ else bn=`basename "$progname"` cd `dirname "$progname"` progname=`/bin/ls -l "$bn" | sed -e 's/^.* -> //' ` + progbase=`basename "$progname"` if [ ! -x "$progname" ]; then break fi diff --git a/xulrunner/app/xulrunner.exe.manifest b/xulrunner/app/xulrunner.exe.manifest index 09c28623..ad177236 100644 --- a/xulrunner/app/xulrunner.exe.manifest +++ b/xulrunner/app/xulrunner.exe.manifest @@ -6,7 +6,7 @@ name="Mozilla.XULRunner" type="win32" /> -Mozilla Thunderbird +Mozilla XULRunner + + + + + + + + diff --git a/xulrunner/app/xulrunner.js b/xulrunner/app/xulrunner.js index e89e6bde..d0ffc62a 100644 --- a/xulrunner/app/xulrunner.js +++ b/xulrunner/app/xulrunner.js @@ -54,3 +54,19 @@ pref("intl.charset.detector", "chrome://global/locale/intl.properties"); pref("intl.charset.default", "chrome://global-platform/locale/intl.properties"); pref("intl.menuitems.alwaysappendaccesskeys","chrome://global/locale/intl.properties"); pref("intl.menuitems.insertseparatorbeforeaccesskeys","chrome://global/locale/intl.properties"); +pref("xpinstall.dialog.confirm", "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul"); +pref("xpinstall.dialog.progress.chrome", "chrome://mozapps/content/extensions/extensions.xul"); +pref("xpinstall.dialog.progress.skin", "chrome://mozapps/content/extensions/extensions.xul"); +pref("xpinstall.dialog.progress.type.chrome", "Extension:Manager"); +pref("xpinstall.dialog.progress.type.skin", "Extension:Manager"); +pref("xpinstall.enabled", true); +#ifdef XP_WIN +pref("browser.preferences.instantApply", false); +#else +pref("browser.preferences.instantApply", true); +#endif +#ifdef XP_MACOSX +pref("browser.preferences.animateFadeIn", true); +#else +pref("browser.preferences.animateFadeIn", false); +#endif diff --git a/xulrunner/installer/Makefile.in b/xulrunner/installer/Makefile.in index 07dcfd83..d571b04e 100644 --- a/xulrunner/installer/Makefile.in +++ b/xulrunner/installer/Makefile.in @@ -54,12 +54,53 @@ NO_PKG_FILES = \ xpt_link* \ $(NULL) +# If we're on mac, we want to make the .pkg first, in the mac/ +# directory. Then packager.mk can put it into a DMG + ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) DIRS += mac _APPNAME = $(PKG_BASENAME).pkg PKG_SKIP_STRIP = 1 +MOZ_PKG_SPECIAL = pkg +PKG_DMG_SOURCE = $(STAGEPATH)xulrunner-pkg endif include $(topsrcdir)/config/rules.mk include $(topsrcdir)/toolkit/mozapps/installer/packager.mk + +# +# Package the SDK directory +# + +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +SDK_APPNAME = $(MOZ_APP_NAME) +else +SDK_APPNAME = $(MOZ_PKG_APPNAME) +endif +SDK_BASENAME = $(SDK_APPNAME)-$(MOZ_PKG_VERSION).$(AB_CD).$(MOZ_PKG_PLATFORM) +SDK = $(SDK_BASENAME).sdk$(PKG_SUFFIX) + +ifeq ($(MOZ_PKG_FORMAT),TAR) +MAKE_SDK = $(CREATE_FINAL_TAR) - gecko-sdk > $(SDK) +else +ifeq ($(MOZ_PKG_FORMAT),TGZ) +MAKE_SDK = $(CREATE_FINAL_TAR) - gecko-sdk | gzip -vf9 > $(SDK) +else +ifeq ($(MOZ_PKG_FORMAT),BZ2) +MAKE_SDK = $(CREATE_FINAL_TAR) - gecko-sdk | bzip2 -vf > $(SDK) +else +# default to zip +MAKE_SDK = $(ZIP) -r9D $(SDK_BASENAME).sdk.zip gecko-sdk +endif +endif +endif + +make-sdk: + @echo "Packaging SDK..." + @rm -rf $(DIST)/gecko-sdk + @mkdir $(DIST)/gecko-sdk + @cd $(DIST)/sdk && tar $(TAR_CREATE_FLAGS) - * | (cd ../gecko-sdk; tar -xf -) + cd $(DIST) && $(MAKE_SDK) + +libs:: make-sdk diff --git a/xulrunner/installer/mac/Makefile.in b/xulrunner/installer/mac/Makefile.in index bc84e17f..397b6e42 100644 --- a/xulrunner/installer/mac/Makefile.in +++ b/xulrunner/installer/mac/Makefile.in @@ -58,19 +58,21 @@ NO_PKG_FILES = \ include $(topsrcdir)/config/rules.mk +libs:: stage-package + %.plist: %.plist.in $(PERL) $(topsrcdir)/config/preprocessor.pl $(DEFINES) $(ACDEFINES) $< > $@ PACKAGER_NO_LIBS=1 +_APPNAME = XUL.framework +_BINPATH = /$(_APPNAME)/Versions/Current -# Include this solely for additional NO_PKG_FILES include $(topsrcdir)/toolkit/mozapps/installer/packager.mk BINARY_DIR = $(DIST)/package-stage/XUL.framework/Versions/$(MOZILLA_VERSION) SOFTOKN = $(BINARY_DIR)/$(DLL_PREFIX)softokn3$(DLL_SUFFIX) -FREEBL_HYBRID = $(BINARY_DIR)/$(DLL_PREFIX)freebl_hybrid_3$(DLL_SUFFIX) -FREEBL_PURE = $(BINARY_DIR)/$(DLL_PREFIX)freebl_pure32_3$(DLL_SUFFIX) +FREEBL = $(BINARY_DIR)/$(DLL_PREFIX)freebl3$(DLL_SUFFIX) _ABS_OBJDIR := $(shell pwd) _ABS_DIST := $(shell cd $(DIST) && pwd) @@ -89,45 +91,22 @@ CHOWN_REVERT ?= $(error CHOWN_REVERT must be set to a setuid script.) libs:: Info.plist Description.plist $(RM) -rf resource-stage mkdir resource-stage - $(RM) -rf $(DIST)/package-stage - mkdir $(DIST)/package-stage - rsync --copy-unsafe-links -a $(DIST)/XUL.framework $(DIST)/package-stage - cd $(BINARY_DIR) && $(RM) -rf $(NO_PKG_FILES) - echo "Stripping package directory..." - find $(BINARY_DIR) ! -type d \ - ! -name "*.js" \ - ! -name "*.xpt" \ - ! -name "*.gif" \ - ! -name "*.jpg" \ - ! -name "*.png" \ - ! -name "*.xpm" \ - ! -name "*.txt" \ - ! -name "*.rdf" \ - ! -name "*.sh" \ - ! -name "*.properties" \ - ! -name "*.dtd" \ - ! -name "*.html" \ - ! -name "*.xul" \ - ! -name "*.css" \ - ! -name "*.xml" \ - ! -name "*.jar" \ - ! -name "*.dat" \ - ! -name "*.tbl" \ - ! -name "*.src" \ - ! -name "*.reg" \ - $(PLATFORM_EXCLUDE_LIST) \ - -exec $(STRIP) $(STRIP_FLAGS) {} >/dev/null 2>&1 \; - $(SIGN_NSS) - chmod -R a+rX,u+w,go-w,-s,-t $(DIST)/package-stage + $(RM) -rf $(DIST)/$(STAGEPATH)xulrunner-pkg + mkdir $(DIST)/$(STAGEPATH)xulrunner-pkg + chmod -R a+rX,u+w,go-w,-s,-t $(DIST)/$(STAGEPATH)$(MOZ_PKG_APPNAME) # For some unknown reason, PackageMaker requires absolute paths to everything. unset NEXT_ROOT; \ - $(CHOWN_ROOT) $(DIST)/package-stage && \ - /Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker -build \ - -p $(_ABS_DIST)/$(PKG_BASENAME).pkg \ - -f $(_ABS_DIST)/package-stage \ + $(CHOWN_ROOT) $(DIST)/$(STAGEPATH)$(MOZ_PKG_APPNAME) && \ + /Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker -build -v \ + -p $(_ABS_DIST)/$(STAGEPATH)xulrunner-pkg/$(PKG_BASENAME).pkg \ + -f $(_ABS_DIST)/$(STAGEPATH)$(MOZ_PKG_APPNAME) \ -r $(_ABS_OBJDIR)/resource-stage \ -i $(_ABS_OBJDIR)/Info.plist \ - -d $(_ABS_OBJDIR)/Description.plist; \ + -d $(_ABS_OBJDIR)/Description.plist > packagemaker.log; \ SAVED=$$?; \ - $(CHOWN_REVERT) $(DIST)/package-stage; \ + if [ "$$SAVED" == "1" -a \ + `grep -c 'was completed with the following non-fatal errors' < packagemaker.log` -gt 0 ]; then \ + SAVED=0; \ + fi; \ + $(CHOWN_REVERT) $(DIST)/$(STAGEPATH)$(MOZ_PKG_APPNAME); \ exit $$SAVED diff --git a/xulrunner/setup/nsXULAppInstall.js b/xulrunner/setup/nsXULAppInstall.js index 281f962e..06c505ed 100644 --- a/xulrunner/setup/nsXULAppInstall.js +++ b/xulrunner/setup/nsXULAppInstall.js @@ -247,7 +247,8 @@ const AppInstall = { aDirectory = Components.classes["@mozilla.org/file/local;1"]. createInstance(nsILocalFile); aDirectory.initWithPath("/usr/lib"); - aDirectory.append(vendor.toLowerCase()); + if (vendor) + aDirectory.append(vendor.toLowerCase()); #endif #endif } diff --git a/xulrunner/stub/nsXULStub.cpp b/xulrunner/stub/nsXULStub.cpp index f5d1eb1f..7d63c99c 100644 --- a/xulrunner/stub/nsXULStub.cpp +++ b/xulrunner/stub/nsXULStub.cpp @@ -57,6 +57,12 @@ #define XULRUNNER_BIN "xulrunner-bin" #endif +//Added code to include necessary BEOS header for BEOS specific code +#ifdef XP_BEOS +#include +#include +#endif + #define VERSION_MAXLEN 128 int @@ -66,12 +72,26 @@ main(int argc, char **argv) char *lastSlash; char iniPath[MAXPATHLEN]; + char tmpPath[MAXPATHLEN]; #ifdef XP_WIN if (!::GetModuleFileName(NULL, iniPath, sizeof(iniPath))) return 1; -#else +//Added Beos specific code to get the Path +#elif defined ( XP_BEOS ) + + BEntry e((const char *)argv[0], true); // traverse symlink + BPath p; + status_t err; + err = e.GetPath(&p); + NS_ASSERTION(err == B_OK, "realpath failed"); + + if (err == B_OK) + //p.Path returns a pointer, so use strcpy to store path in iniPath + strcpy(iniPath, p.Path()); + +#else // on unix, there is no official way to get the path of the current binary. // instead of using the MOZILLA_FIVE_HOME hack, which doesn't scale to @@ -96,11 +116,12 @@ main(int argc, char **argv) PRBool found = PR_FALSE; char *token = strtok(pathdup, ":"); while (token) { - sprintf(iniPath, "%s/%s", token, argv[0]); - if (stat(iniPath, &fileStat) == 0) { + sprintf(tmpPath, "%s/%s", token, argv[0]); + if (realpath(tmpPath, iniPath) && stat(iniPath, &fileStat) == 0) { found = PR_TRUE; break; } + token = strtok(NULL, ":"); } free (pathdup); if (!found) @@ -186,8 +207,13 @@ main(int argc, char **argv) "%s" XPCOM_FILE_PATH_SEPARATOR XULRUNNER_BIN, greDir); #ifndef XP_WIN +#ifdef XP_BEOS + putenv(strcat("XPCOM_SEARCH_KEY=", greDir)); +#else setenv(XPCOM_SEARCH_KEY, greDir, 1); #endif +#endif + argv2[0] = xulBin; argv2[1] = iniPath;