Bug 822367 - Since document.open() creates a new channel, set nsDocShell:mMixedContentChannel to the newly created channel if the user has decided to allow mixed content on the page. r=smaug
authorTanvi Vyas <tvyas@mozilla.com>
Wed, 30 Jan 2013 00:04:34 -0800
changeset 120345 a704f2af8bf37e9f7172829f4c9de974ca46b0fa
parent 120344 4068ef6c54a6355d23893c56afa69b8de4d4b320
child 120346 0ec7dd6fc51672fb1d946acd574457bd706ae149
push id24247
push userryanvm@gmail.com
push dateWed, 30 Jan 2013 15:20:29 +0000
treeherdermozilla-central@2cc710018b14 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs822367
milestone21.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 822367 - Since document.open() creates a new channel, set nsDocShell:mMixedContentChannel to the newly created channel if the user has decided to allow mixed content on the page. r=smaug
accessible/src/base/DocManager.cpp
accessible/src/base/Logging.cpp
content/base/src/nsMixedContentBlocker.cpp
content/html/document/src/nsHTMLDocument.cpp
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
docshell/base/nsDocShellLoadTypes.h
docshell/base/nsIDocShell.idl
--- a/accessible/src/base/DocManager.cpp
+++ b/accessible/src/base/DocManager.cpp
@@ -190,17 +190,18 @@ DocManager::OnStateChange(nsIWebProgress
   NS_ENSURE_STATE(docShell);
 
   bool isReloading = false;
   uint32_t loadType;
   docShell->GetLoadType(&loadType);
   if (loadType == LOAD_RELOAD_NORMAL ||
       loadType == LOAD_RELOAD_BYPASS_CACHE ||
       loadType == LOAD_RELOAD_BYPASS_PROXY ||
-      loadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE) {
+      loadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE ||
+      loadType == LOAD_RELOAD_ALLOW_MIXED_CONTENT) {
     isReloading = true;
   }
 
   docAcc->NotifyOfLoading(isReloading);
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/accessible/src/base/Logging.cpp
+++ b/accessible/src/base/Logging.cpp
@@ -268,16 +268,19 @@ LogShellLoadType(nsIDocShell* aDocShell)
       printf("reload bypass cache; ");
       break;
     case LOAD_RELOAD_BYPASS_PROXY:
       printf("reload bypass proxy; ");
       break;
     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
       printf("reload bypass proxy and cache; ");
       break;
+    case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
+      printf("reload allow mixed content; ");
+      break;
     case LOAD_LINK:
       printf("link; ");
       break;
     case LOAD_REFRESH:
       printf("refresh; ");
       break;
     case LOAD_RELOAD_CHARSET_CHANGE:
       printf("reload charset change; ");
--- a/content/base/src/nsMixedContentBlocker.cpp
+++ b/content/base/src/nsMixedContentBlocker.cpp
@@ -328,17 +328,18 @@ nsMixedContentBlocker::ShouldLoad(uint32
 
   // If we are here we have mixed content.
 
   // Determine if the rootDoc is https and if the user decided to allow Mixed Content
   nsCOMPtr<nsIDocShell> docShell = NS_CP_GetDocShellFromContext(aRequestingContext);
   NS_ENSURE_TRUE(docShell, NS_OK);
   bool rootHasSecureConnection = false;
   bool allowMixedContent = false;
-  rv = docShell->GetAllowMixedContentAndConnectionData(&rootHasSecureConnection, &allowMixedContent);
+  bool isRootDocShell = false;
+  rv = docShell->GetAllowMixedContentAndConnectionData(&rootHasSecureConnection, &allowMixedContent, &isRootDocShell);
   if (NS_FAILED(rv)) {
      return rv;
   }
 
   // Get the root document from the docshell
   nsCOMPtr<nsIDocShellTreeItem> currentDocShellTreeItem(do_QueryInterface(docShell));
   NS_ASSERTION(currentDocShellTreeItem, "No DocShellTreeItem from docshell");  
   nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -1615,16 +1615,26 @@ nsHTMLDocument::Open(JSContext* cx,
     }
 
     loadFlags |= callerLoadFlags & nsIRequest::INHIBIT_PERSISTENT_CACHING;
 
     rv = channel->SetLoadFlags(loadFlags);
     if (rv.Failed()) {
       return nullptr;
     }
+
+    // If the user has allowed mixed content on the rootDoc, then we should propogate it
+    // down to the new document channel.
+    bool rootHasSecureConnection = false;
+    bool allowMixedContent = false;
+    bool isDocShellRoot = false;
+    nsresult rvalue = shell->GetAllowMixedContentAndConnectionData(&rootHasSecureConnection, &allowMixedContent, &isDocShellRoot);
+    if (NS_SUCCEEDED(rvalue) && allowMixedContent && isDocShellRoot) {
+       shell->SetMixedContentChannel(channel);
+    }
   }
 
   // Before we reset the doc notify the globalwindow of the change,
   // but only if we still have a window (i.e. our window object the
   // current inner window in our outer window).
 
   // Hold onto ourselves on the offchance that we're down to one ref
   nsCOMPtr<nsIDocument> kungFuDeathGrip = this;
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -658,16 +658,17 @@ ConvertLoadTypeToNavigationType(uint32_t
     case LOAD_HISTORY:
         result = dom::PerformanceNavigation::TYPE_BACK_FORWARD;
         break;
     case LOAD_RELOAD_NORMAL:
     case LOAD_RELOAD_CHARSET_CHANGE:
     case LOAD_RELOAD_BYPASS_CACHE:
     case LOAD_RELOAD_BYPASS_PROXY:
     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
+    case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
         result = dom::PerformanceNavigation::TYPE_RELOAD;
         break;
     case LOAD_STOP_CONTENT_AND_REPLACE:
     case LOAD_REFRESH:
     case LOAD_BYPASS_HISTORY:
     case LOAD_ERROR_PAGE:
     case LOAD_PUSHSTATE:
         result = dom::PerformanceNavigation::TYPE_RESERVED;
@@ -1143,17 +1144,17 @@ ConvertDocShellLoadInfoToLoadType(nsDocS
         break;
     case nsIDocShellLoadInfo::loadPushState:
         loadType = LOAD_PUSHSTATE;
         break;
     case nsIDocShellLoadInfo::loadReplaceBypassCache:
         loadType = LOAD_REPLACE_BYPASS_CACHE;
         break;
     case nsIDocShellLoadInfo::loadMixedContent:
-        loadType = LOAD_MIXED_CONTENT;
+        loadType = LOAD_RELOAD_ALLOW_MIXED_CONTENT;
         break;
     default:
         NS_NOTREACHED("Unexpected nsDocShellInfoLoadType value");
     }
 
     return loadType;
 }
 
@@ -1216,17 +1217,17 @@ nsDocShell::ConvertLoadTypeToDocShellLoa
         docShellLoadType = nsIDocShellLoadInfo::loadStopContentAndReplace;
         break;
     case LOAD_PUSHSTATE:
         docShellLoadType = nsIDocShellLoadInfo::loadPushState;
         break;
     case LOAD_REPLACE_BYPASS_CACHE:
         docShellLoadType = nsIDocShellLoadInfo::loadReplaceBypassCache;
         break;
-    case LOAD_MIXED_CONTENT:
+    case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
         docShellLoadType = nsIDocShellLoadInfo::loadMixedContent;
         break;
     default:
         NS_NOTREACHED("Unexpected load type value");
     }
 
     return docShellLoadType;
 }                                                                               
@@ -5325,62 +5326,67 @@ nsDocShell::GetSandboxFlags(uint32_t  *a
     *aSandboxFlags = mSandboxFlags;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::SetMixedContentChannel(nsIChannel* aMixedContentChannel)
 {
 #ifdef DEBUG
-     // Get the root docshell.
-     nsCOMPtr<nsIDocShellTreeItem> root;
-     GetSameTypeRootTreeItem(getter_AddRefs(root));
-     NS_WARN_IF_FALSE(
-       root.get() == static_cast<nsIDocShellTreeItem *>(this), 
-       "Setting mMixedContentChannel on a docshell that is not the root docshell"
-     );
+     // if the channel is non-null
+     if (aMixedContentChannel) {
+       // Get the root docshell.
+       nsCOMPtr<nsIDocShellTreeItem> root;
+       GetSameTypeRootTreeItem(getter_AddRefs(root));
+       NS_WARN_IF_FALSE(
+         root.get() == static_cast<nsIDocShellTreeItem *>(this), 
+         "Setting mMixedContentChannel on a docshell that is not the root docshell"
+       );
+    }
 #endif
      mMixedContentChannel = aMixedContentChannel;
      return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetMixedContentChannel(nsIChannel **aMixedContentChannel)
 {
     NS_ENSURE_ARG_POINTER(aMixedContentChannel);
     NS_IF_ADDREF(*aMixedContentChannel = mMixedContentChannel);
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDocShell::GetAllowMixedContentAndConnectionData(bool* aRootHasSecureConnection, bool* aAllowMixedContent)
+nsDocShell::GetAllowMixedContentAndConnectionData(bool* aRootHasSecureConnection, bool* aAllowMixedContent, bool* aIsRootDocShell)
 {
   *aRootHasSecureConnection = false;
   *aAllowMixedContent = false;
-
-  nsCOMPtr<nsIDocShellTreeItem> currentDocShellTreeItem = static_cast<nsIDocShellTreeItem *>(this);
-  NS_ASSERTION(currentDocShellTreeItem, "No DocShellTreeItem from docshell");
+  *aIsRootDocShell = false;
 
   nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
-  currentDocShellTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
+  GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
   NS_ASSERTION(sameTypeRoot, "No document shell root tree item from document shell tree item!");
+  *aIsRootDocShell = sameTypeRoot.get() == static_cast<nsIDocShellTreeItem *>(this);
 
   // now get the document from sameTypeRoot
   nsCOMPtr<nsIDocument> rootDoc = do_GetInterface(sameTypeRoot);
   NS_ASSERTION(rootDoc, "No root document from document shell root tree item.");
 
-//  nsCOMPtr<nsIScriptObjectPrincipal> prin = do_QueryInterface(rootDoc);
-//  nsCOMPtr<nsIPrincipal> rootPrincipal = prin->GetPrincipal();
   nsCOMPtr<nsIPrincipal> rootPrincipal = rootDoc->NodePrincipal();
   NS_ASSERTION(rootPrincipal, "No root principal from root document");
-  nsCOMPtr<nsIURI> rootUri;
-  rootPrincipal->GetURI(getter_AddRefs(rootUri));
-  NS_ASSERTION(rootUri, "No root uri from root principal");
-  nsresult rv = rootUri->SchemeIs("https", aRootHasSecureConnection);
-  NS_ENSURE_SUCCESS(rv, rv);
+
+  // For things with system principal (e.g. scratchpad) there is no uri
+  // aRootHasSecureConnection should remain false.
+  if (!nsContentUtils::IsSystemPrincipal(rootPrincipal)) {
+     nsCOMPtr<nsIURI> rootUri;
+     rootPrincipal->GetURI(getter_AddRefs(rootUri));
+     NS_ASSERTION(rootUri, "No root uri from root principal");
+     nsresult rv = rootUri->SchemeIs("https", aRootHasSecureConnection);
+     NS_ENSURE_SUCCESS(rv, rv);
+  }
 
   // Check the root doc's channel against the root docShell's mMixedContentChannel to see
   // if they are the same.  If they are the same, the user has overriden
   // the block.
   nsCOMPtr<nsIDocShell> rootDocShell = do_GetInterface(sameTypeRoot);
   nsCOMPtr<nsIChannel> mixedChannel;
   rootDocShell->GetMixedContentChannel(getter_AddRefs(mixedChannel));
   *aAllowMixedContent = mixedChannel && (mixedChannel == rootDoc->GetChannel());
@@ -9401,17 +9407,17 @@ nsDocShell::DoURILoad(nsIURI * aURI,
         rv = channel->SetContentDisposition(nsIChannel::DISPOSITION_ATTACHMENT);
         NS_ENSURE_SUCCESS(rv, rv);
         if (!aFileName.IsEmpty()) {
             rv = channel->SetContentDispositionFilename(aFileName);
             NS_ENSURE_SUCCESS(rv, rv);
         }
     }
 
-    if (mLoadType == LOAD_MIXED_CONTENT) {
+    if (mLoadType == LOAD_RELOAD_ALLOW_MIXED_CONTENT) {
           rv = SetMixedContentChannel(channel);
           NS_ENSURE_SUCCESS(rv, rv);
     } else {
           rv = SetMixedContentChannel(nullptr);
           NS_ENSURE_SUCCESS(rv, rv);
     }
 
     //hack
@@ -9676,16 +9682,17 @@ nsresult nsDocShell::DoChannelLoad(nsICh
         break;
 
     case LOAD_NORMAL_BYPASS_CACHE:
     case LOAD_NORMAL_BYPASS_PROXY:
     case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
     case LOAD_RELOAD_BYPASS_CACHE:
     case LOAD_RELOAD_BYPASS_PROXY:
     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
+    case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
     case LOAD_REPLACE_BYPASS_CACHE:
         loadFlags |= nsIRequest::LOAD_BYPASS_CACHE |
                      nsIRequest::LOAD_FRESH_CONNECTION;
         break;
 
     case LOAD_NORMAL:
     case LOAD_LINK:
         // Set cache checking flags
@@ -9973,17 +9980,18 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIC
 
     /* If the user pressed shift-reload, cache will create a new cache key
      * for the page. Save the new cacheKey in Session History. 
      * see bug 90098
      */
     if (aChannel &&
         (aLoadType == LOAD_RELOAD_BYPASS_CACHE ||
          aLoadType == LOAD_RELOAD_BYPASS_PROXY ||
-         aLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE)) {
+         aLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE ||
+         aLoadType == LOAD_RELOAD_ALLOW_MIXED_CONTENT)) {
         NS_ASSERTION(!updateSHistory,
                      "We shouldn't be updating session history for forced"
                      " reloads!");
         
         nsCOMPtr<nsICachingChannel> cacheChannel(do_QueryInterface(aChannel));
         nsCOMPtr<nsISupports>  cacheKey;
         // Get the Cache Key and store it in SH.
         if (cacheChannel)
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -740,17 +740,17 @@ protected:
 
     // Set in LoadErrorPage from the method argument and used later
     // in CreateContentViewer. We have to delay an shistory entry creation
     // for which these objects are needed.
     nsCOMPtr<nsIURI>           mFailedURI;
     nsCOMPtr<nsIChannel>       mFailedChannel;
     uint32_t                   mFailedLoadType;
 
-    // Set in DoURILoad when the LOAD_MIXED_CONTENT flag is set.
+    // Set in DoURILoad when the LOAD_RELOAD_ALLOW_MIXED_CONTENT flag is set.
     // Checked in nsMixedContentBlocker, to see if the channels match.
     nsCOMPtr<nsIChannel>       mMixedContentChannel;
 
     // WEAK REFERENCES BELOW HERE.
     // Note these are intentionally not addrefd.  Doing so will create a cycle.
     // For that reasons don't use nsCOMPtr.
 
     nsIDocShellTreeOwner *     mTreeOwner; // Weak Reference
--- a/docshell/base/nsDocShellLoadTypes.h
+++ b/docshell/base/nsDocShellLoadTypes.h
@@ -46,26 +46,26 @@ enum LoadType {
     LOAD_NORMAL_EXTERNAL = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_FROM_EXTERNAL),
     LOAD_HISTORY = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_HISTORY, nsIWebNavigation::LOAD_FLAGS_NONE),
     LOAD_NORMAL_BYPASS_CACHE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE),
     LOAD_NORMAL_BYPASS_PROXY = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY),
     LOAD_NORMAL_BYPASS_PROXY_AND_CACHE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE | nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY),
     LOAD_RELOAD_NORMAL = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_RELOAD, nsIWebNavigation::LOAD_FLAGS_NONE),
     LOAD_RELOAD_BYPASS_CACHE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_RELOAD, nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE),
     LOAD_RELOAD_BYPASS_PROXY = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_RELOAD, nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY),
+    LOAD_RELOAD_ALLOW_MIXED_CONTENT = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_RELOAD, nsIWebNavigation::LOAD_FLAGS_ALLOW_MIXED_CONTENT | nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE),
     LOAD_RELOAD_BYPASS_PROXY_AND_CACHE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_RELOAD, nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE | nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY),
     LOAD_LINK = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_IS_LINK),
     LOAD_REFRESH = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_IS_REFRESH),
     LOAD_RELOAD_CHARSET_CHANGE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_RELOAD, nsIWebNavigation::LOAD_FLAGS_CHARSET_CHANGE),
     LOAD_BYPASS_HISTORY = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_BYPASS_HISTORY),
     LOAD_STOP_CONTENT = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_STOP_CONTENT),
     LOAD_STOP_CONTENT_AND_REPLACE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_STOP_CONTENT | nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY),
     LOAD_PUSHSTATE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_PUSHSTATE, nsIWebNavigation::LOAD_FLAGS_NONE),
     LOAD_REPLACE_BYPASS_CACHE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY | nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE),
-    LOAD_MIXED_CONTENT = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_ALLOW_MIXED_CONTENT),
     /**
      * Load type for an error page. These loads are never triggered by users of
      * Docshell. Instead, Docshell triggers the load itself when a
      * consumer-triggered load failed.
      */
     LOAD_ERROR_PAGE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, LOAD_FLAGS_ERROR_PAGE)
 
     // NOTE: Adding a new value? Remember to update IsValidLoadType!
@@ -80,25 +80,25 @@ static inline bool IsValidLoadType(uint3
     case LOAD_NORMAL_BYPASS_CACHE:
     case LOAD_NORMAL_BYPASS_PROXY:
     case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
     case LOAD_HISTORY:
     case LOAD_RELOAD_NORMAL:
     case LOAD_RELOAD_BYPASS_CACHE:
     case LOAD_RELOAD_BYPASS_PROXY:
     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
+    case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
     case LOAD_LINK:
     case LOAD_REFRESH:
     case LOAD_RELOAD_CHARSET_CHANGE:
     case LOAD_BYPASS_HISTORY:
     case LOAD_STOP_CONTENT:
     case LOAD_STOP_CONTENT_AND_REPLACE:
     case LOAD_PUSHSTATE:
     case LOAD_REPLACE_BYPASS_CACHE:
-    case LOAD_MIXED_CONTENT:
     case LOAD_ERROR_PAGE:
         return true;
     }
     return false;
 }
 
 #endif // MOZILLA_INTERNAL_API
 #endif 
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -733,19 +733,20 @@ interface nsIDocShell : nsISupports
    * been disabled and hence mMixedContentChannel will never be set.
    */
   attribute nsIChannel mixedContentChannel;
 
   /**
    * Checks whether the channel associated with the root docShell is equal to
    * mMixedContentChannel. If they are the same, allowMixedContent is set to true.
    * Checks if the root document has a secure connection. If it is, sets 
-   * rootHasSecureConnection to true.
+   * rootHasSecureConnection to true. If the docShell is the root doc shell, 
+   * isRootDocShell is set to true. 
    */
-  void GetAllowMixedContentAndConnectionData(out boolean rootHasSecureConnection, out boolean allowMixedContent);
+  void GetAllowMixedContentAndConnectionData(out boolean rootHasSecureConnection, out boolean allowMixedContent, out boolean isRootDocShell);
 
 
   /**
    * Are plugins allowed in the current document loaded in this docshell ?
    * (if there is one). This depends on whether plugins are allowed by this
    * docshell itself or if the document is sandboxed and hence plugins should
    * not be allowed.
    */