TextureClientPool*
ClientLayerManager::GetTexturePool(SurfaceFormat aFormat, TextureFlags aFlags)
{
  MOZ_DIAGNOSTIC_ASSERT(!mDestroyed);

  for (size_t i = 0; i < mTexturePools.Length(); i++) {
    if (mTexturePools[i]->GetFormat() == aFormat &&
        mTexturePools[i]->GetFlags() == aFlags) {
      return mTexturePools[i];
    }
  }

  mTexturePools.AppendElement(
      new TextureClientPool(aFormat, aFlags,
                            IntSize(gfxPlatform::GetPlatform()->GetTileWidth(),
                                    gfxPlatform::GetPlatform()->GetTileHeight()),
                            gfxPrefs::LayersTileMaxPoolSize(),
                            gfxPrefs::LayersTileShrinkPoolTimeout(),
                            mForwarder));

  return mTexturePools.LastElement();
}
Exemple #2
0
void
ProxyAccessible::Shutdown()
{
  MOZ_DIAGNOSTIC_ASSERT(!IsDoc());
  NS_ASSERTION(!mOuterDoc, "Why do we still have a child doc?");

  // XXX Ideally  this wouldn't be necessary, but it seems OuterDoc accessibles
  // can be destroyed before the doc they own.
  if (!mOuterDoc) {
    uint32_t childCount = mChildren.Length();
    for (uint32_t idx = 0; idx < childCount; idx++)
      mChildren[idx]->Shutdown();
  } else {
    if (mChildren.Length() != 1)
      MOZ_CRASH("outer doc doesn't own adoc!");

    mChildren[0]->AsDoc()->Unbind();
  }

  mChildren.Clear();
  ProxyDestroyed(this);
  mDoc->RemoveAccessible(this);
}
Exemple #3
0
/* static */ void
FetchStream::WriteIntoReadRequestCallback(JSContext* aCx,
                                          JS::HandleObject aStream,
                                          void* aUnderlyingSource,
                                          uint8_t aFlags, void* aBuffer,
                                          size_t aLength, size_t* aByteWritten)
{
  MOZ_DIAGNOSTIC_ASSERT(aUnderlyingSource);
  MOZ_DIAGNOSTIC_ASSERT(aFlags == FETCH_STREAM_FLAG);
  MOZ_DIAGNOSTIC_ASSERT(aBuffer);
  MOZ_DIAGNOSTIC_ASSERT(aByteWritten);

  RefPtr<FetchStream> stream = static_cast<FetchStream*>(aUnderlyingSource);
  stream->AssertIsOnOwningThread();

  MutexAutoLock lock(stream->mMutex);

  MOZ_DIAGNOSTIC_ASSERT(stream->mInputStream);
  MOZ_DIAGNOSTIC_ASSERT(stream->mState == eWriting);
  stream->mState = eChecking;

  uint32_t written;
  nsresult rv =
    stream->mInputStream->Read(static_cast<char*>(aBuffer), aLength, &written);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    stream->ErrorPropagation(aCx, lock, aStream, rv);
    return;
  }

  *aByteWritten = written;

  if (written == 0) {
    stream->CloseAndReleaseObjects(aCx, lock, aStream);
    return;
  }

  rv = stream->mInputStream->AsyncWait(stream, 0, 0,
                                       stream->mOwningEventTarget);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    stream->ErrorPropagation(aCx, lock, aStream, rv);
    return;
  }

  // All good.
}
void
ChannelMediaDecoder::DownloadProgressed()
{
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());

  GetOwner()->DownloadProgressed();

  using StatsPromise = MozPromise<MediaStatistics, bool, true>;
  InvokeAsync(GetStateMachine()->OwnerThread(),
              __func__,
              [
                playbackStats = mPlaybackStatistics,
                res = RefPtr<BaseMediaResource>(mResource),
                duration = mDuration,
                pos = mPlaybackPosition
              ]() {
                auto rate = ComputePlaybackRate(playbackStats, res, duration);
                UpdatePlaybackRate(rate, res);
                MediaStatistics stats = GetStatistics(rate, res, pos);
                return StatsPromise::CreateAndResolve(stats, __func__);
              })
    ->Then(
      mAbstractMainThread,
      __func__,
      [ =, self = RefPtr<ChannelMediaDecoder>(this) ](MediaStatistics aStats) {
        if (IsShutdown()) {
          return;
        }
        mCanPlayThrough = aStats.CanPlayThrough();
        GetStateMachine()->DispatchCanPlayThrough(mCanPlayThrough);
        mResource->ThrottleReadahead(ShouldThrottleDownload(aStats));
        // Update readyState since mCanPlayThrough might have changed.
        GetOwner()->UpdateReadyState();
      },
      []() { MOZ_ASSERT_UNREACHABLE("Promise not resolved"); });
}
Exemple #5
0
  NS_IMETHOD
  Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) override
  {
    MOZ_ASSERT(NS_IsMainThread());
    MOZ_DIAGNOSTIC_ASSERT(strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC) == 0);

    if (!mStream) {
      return NS_OK;
    }

    nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mGlobal);
    if (!SameCOMIdentity(aSubject, window)) {
      return NS_OK;
    }

    // mStream->Close() will call JSStreamConsumer::OnInputStreamReady which may
    // then destory itself, dropping the last reference to 'this'.
    RefPtr<WindowStreamOwner> keepAlive(this);

    mStream->Close();
    mStream = nullptr;
    mGlobal = nullptr;
    return NS_OK;
  }
Exemple #6
0
/* static */
already_AddRefed<Promise> FileCreatorHelper::CreateFile(
    nsIGlobalObject* aGlobalObject, nsIFile* aFile,
    const ChromeFilePropertyBag& aBag, bool aIsFromNsIFile, ErrorResult& aRv) {
  MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());

  RefPtr<Promise> promise = Promise::Create(aGlobalObject, aRv);
  if (NS_WARN_IF(aRv.Failed())) {
    return nullptr;
  }

  nsAutoString path;
  aRv = aFile->GetPath(path);
  if (NS_WARN_IF(aRv.Failed())) {
    return nullptr;
  }

  // Register this component to PBackground.
  mozilla::ipc::PBackgroundChild* actorChild =
      mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
  if (NS_WARN_IF(!actorChild)) {
    aRv.Throw(NS_ERROR_FAILURE);
    return nullptr;
  }

  Maybe<int64_t> lastModified;
  if (aBag.mLastModified.WasPassed()) {
    lastModified.emplace(aBag.mLastModified.Value());
  }

  PFileCreatorChild* actor = actorChild->SendPFileCreatorConstructor(
      path, aBag.mType, aBag.mName, lastModified, aBag.mExistenceCheck,
      aIsFromNsIFile);

  static_cast<FileCreatorChild*>(actor)->SetPromise(promise);
  return promise.forget();
}
Exemple #7
0
nsresult
FetchDriver::FinishOnStopRequest(AlternativeDataStreamListener* aAltDataListener)
{
  AssertIsOnMainThread();
  // OnStopRequest is not called from channel, that means the main data loading
  // does not finish yet. Reaching here since alternative data loading finishes.
  if (!mOnStopRequestCalled) {
    return NS_OK;
  }

  MOZ_DIAGNOSTIC_ASSERT(!mAltDataListener);
  // Wait for alternative data loading finish if we needed it.
  if (aAltDataListener &&
      aAltDataListener->Status() == AlternativeDataStreamListener::LOADING) {
    // For LOADING case, channel holds the reference of altDataListener, no need
    // to restore it to mAltDataListener.
    return NS_OK;
  }

  if (mObserver) {
    // From "Main Fetch" step 19.1, 19.2: Process response.
    if (ShouldCheckSRI(mRequest, mResponse)) {
      MOZ_ASSERT(mResponse);
      mObserver->OnResponseAvailable(mResponse);
      #ifdef DEBUG
        mResponseAvailableCalled = true;
      #endif
    }

    mObserver->OnResponseEnd(FetchDriverObserver::eByNetworking);
    mObserver = nullptr;
  }

  mChannel = nullptr;
  return NS_OK;
}
Exemple #8
0
NS_IMETHODIMP
FetchDriver::OnStopRequest(nsIRequest* aRequest,
                           nsISupports* aContext,
                           nsresult aStatusCode)
{
  AssertIsOnMainThread();

  MOZ_DIAGNOSTIC_ASSERT(!mOnStopRequestCalled);
  mOnStopRequestCalled = true;

  // main data loading is going to finish, breaking the reference cycle.
  RefPtr<AlternativeDataStreamListener> altDataListener = mAltDataListener.forget();

  // We need to check mObserver, which is nulled by FailWithNetworkError(),
  // because in the case of "error" redirect mode, aStatusCode may be NS_OK but
  // mResponse will definitely be null so we must not take the else branch.
  if (NS_FAILED(aStatusCode) || !mObserver) {
    nsCOMPtr<nsIAsyncOutputStream> outputStream = do_QueryInterface(mPipeOutputStream);
    if (outputStream) {
      outputStream->CloseWithStatus(NS_BINDING_FAILED);
    }
    if (altDataListener) {
      altDataListener->Cancel();
    }

    // We proceed as usual here, since we've already created a successful response
    // from OnStartRequest.
  } else {
    MOZ_ASSERT(mResponse);
    MOZ_ASSERT(!mResponse->IsError());

    // From "Main Fetch" step 19: SRI-part3.
    if (ShouldCheckSRI(mRequest, mResponse)) {
      MOZ_ASSERT(mSRIDataVerifier);

      nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);

      nsIConsoleReportCollector* reporter = nullptr;
      if (mObserver) {
        reporter = mObserver->GetReporter();
      }

      nsAutoCString sourceUri;
      if (mDocument && mDocument->GetDocumentURI()) {
        mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
      } else if (!mWorkerScript.IsEmpty()) {
        sourceUri.Assign(mWorkerScript);
      }
      nsresult rv = mSRIDataVerifier->Verify(mSRIMetadata, channel, sourceUri,
                                             reporter);
      if (NS_FAILED(rv)) {
        if (altDataListener) {
          altDataListener->Cancel();
        }
        FailWithNetworkError(rv);
        // Cancel request.
        return rv;
      }
    }

    if (mPipeOutputStream) {
      mPipeOutputStream->Close();
    }
  }

  return FinishOnStopRequest(altDataListener);
}
Exemple #9
0
/* static */
already_AddRefed<File> File::CreateFromFile(nsISupports* aParent,
                                            nsIFile* aFile) {
  MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
  RefPtr<File> file = new File(aParent, new FileBlobImpl(aFile));
  return file.forget();
}
Exemple #10
0
MP4Metadata::ResultAndTrackCount MP4Metadata::GetNumberTracks(
    mozilla::TrackInfo::TrackType aType) const {
  uint32_t tracks;
  auto rv = mp4parse_get_track_count(mParser.get(), &tracks);
  if (rv != MP4PARSE_STATUS_OK) {
    MOZ_LOG(gMP4MetadataLog, LogLevel::Warning,
            ("rust parser error %d counting tracks", rv));
    return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
                        RESULT_DETAIL("Rust parser error %d", rv)),
            MP4Metadata::NumberTracksError()};
  }

  uint32_t total = 0;
  for (uint32_t i = 0; i < tracks; ++i) {
    Mp4parseTrackInfo track_info;
    rv = mp4parse_get_track_info(mParser.get(), i, &track_info);
    if (rv != MP4PARSE_STATUS_OK) {
      continue;
    }

    if (track_info.track_type == MP4PARSE_TRACK_TYPE_AUDIO) {
      Mp4parseTrackAudioInfo audio;
      auto rv = mp4parse_get_track_audio_info(mParser.get(), i, &audio);
      if (rv != MP4PARSE_STATUS_OK) {
        MOZ_LOG(gMP4MetadataLog, LogLevel::Warning,
                ("mp4parse_get_track_audio_info returned error %d", rv));
        continue;
      }
      MOZ_DIAGNOSTIC_ASSERT(audio.sample_info_count > 0,
                            "Must have at least one audio sample info");
      if (audio.sample_info_count == 0) {
        return {
            MediaResult(
                NS_ERROR_DOM_MEDIA_METADATA_ERR,
                RESULT_DETAIL(
                    "Got 0 audio sample info while checking number tracks")),
            MP4Metadata::NumberTracksError()};
      }
      // We assume the codec of the first sample info is representative of the
      // whole track and skip it if we don't recognize the codec.
      if (audio.sample_info[0].codec_type == MP4PARSE_CODEC_UNKNOWN) {
        continue;
      }
    } else if (track_info.track_type == MP4PARSE_TRACK_TYPE_VIDEO) {
      Mp4parseTrackVideoInfo video;
      auto rv = mp4parse_get_track_video_info(mParser.get(), i, &video);
      if (rv != MP4PARSE_STATUS_OK) {
        MOZ_LOG(gMP4MetadataLog, LogLevel::Warning,
                ("mp4parse_get_track_video_info returned error %d", rv));
        continue;
      }
      MOZ_DIAGNOSTIC_ASSERT(video.sample_info_count > 0,
                            "Must have at least one video sample info");
      if (video.sample_info_count == 0) {
        return {
            MediaResult(
                NS_ERROR_DOM_MEDIA_METADATA_ERR,
                RESULT_DETAIL(
                    "Got 0 video sample info while checking number tracks")),
            MP4Metadata::NumberTracksError()};
      }
      // We assume the codec of the first sample info is representative of the
      // whole track and skip it if we don't recognize the codec.
      if (video.sample_info[0].codec_type == MP4PARSE_CODEC_UNKNOWN) {
        continue;
      }
    } else {
      // Only audio and video are supported
      continue;
    }
    if (TrackTypeEqual(aType, track_info.track_type)) {
      total += 1;
    }
  }

  MOZ_LOG(gMP4MetadataLog, LogLevel::Info,
          ("%s tracks found: %u", TrackTypeToString(aType), total));

  return {NS_OK, total};
}
ServiceWorkerCloneData::ServiceWorkerCloneData()
    : mEventTarget(GetCurrentThreadSerialEventTarget()) {
  MOZ_DIAGNOSTIC_ASSERT(mEventTarget);
}
void ResizeObserverNotificationHelper::WillRefresh(TimeStamp aTime) {
  MOZ_DIAGNOSTIC_ASSERT(mOwner, "Should've de-registered on-time!");
  mOwner->Notify();
  // Note that mOwner may be null / dead here.
}
NS_IMETHODIMP
PostMessageEvent::Run()
{
  MOZ_ASSERT(mTargetWindow->IsOuterWindow(),
             "should have been passed an outer window!");
  MOZ_ASSERT(!mSource || mSource->IsOuterWindow(),
             "should have been passed an outer window!");

  // Note: We don't init this AutoJSAPI with targetWindow, because we do not
  // want exceptions during message deserialization to trigger error events on
  // targetWindow.
  AutoJSAPI jsapi;
  jsapi.Init();
  JSContext* cx = jsapi.cx();

  // The document is just used for the principal mismatch error message below.
  // Use a stack variable so mSourceDocument is not held onto after this method
  // finishes, regardless of the method outcome.
  nsCOMPtr<nsIDocument> sourceDocument;
  sourceDocument.swap(mSourceDocument);

  // If we bailed before this point we're going to leak mMessage, but
  // that's probably better than crashing.

  RefPtr<nsGlobalWindow> targetWindow;
  if (mTargetWindow->IsClosedOrClosing() ||
      !(targetWindow = mTargetWindow->GetCurrentInnerWindowInternal()) ||
      targetWindow->IsClosedOrClosing())
    return NS_OK;

  MOZ_ASSERT(targetWindow->IsInnerWindow(),
             "we ordered an inner window!");
  JSAutoCompartment ac(cx, targetWindow->GetWrapper());

  // Ensure that any origin which might have been provided is the origin of this
  // window's document.  Note that we do this *now* instead of when postMessage
  // is called because the target window might have been navigated to a
  // different location between then and now.  If this check happened when
  // postMessage was called, it would be fairly easy for a malicious webpage to
  // intercept messages intended for another site by carefully timing navigation
  // of the target window so it changed location after postMessage but before
  // now.
  if (mProvidedPrincipal) {
    // Get the target's origin either from its principal or, in the case the
    // principal doesn't carry a URI (e.g. the system principal), the target's
    // document.
    nsIPrincipal* targetPrin = targetWindow->GetPrincipal();
    if (NS_WARN_IF(!targetPrin))
      return NS_OK;

    // Note: This is contrary to the spec with respect to file: URLs, which
    //       the spec groups into a single origin, but given we intentionally
    //       don't do that in other places it seems better to hold the line for
    //       now.  Long-term, we want HTML5 to address this so that we can
    //       be compliant while being safer.
    if (!BasePrincipal::Cast(targetPrin)->EqualsIgnoringAddonId(mProvidedPrincipal)) {
      nsAutoString providedOrigin, targetOrigin;
      nsresult rv = nsContentUtils::GetUTFOrigin(targetPrin, targetOrigin);
      NS_ENSURE_SUCCESS(rv, rv);
      rv = nsContentUtils::GetUTFOrigin(mProvidedPrincipal, providedOrigin);
      NS_ENSURE_SUCCESS(rv, rv);

      MOZ_DIAGNOSTIC_ASSERT(providedOrigin != targetOrigin ||
                            (BasePrincipal::Cast(mProvidedPrincipal)->OriginAttributesRef() ==
                              BasePrincipal::Cast(targetPrin)->OriginAttributesRef()),
                            "Unexpected postMessage call to a window with mismatched "
                            "origin attributes");

      const char16_t* params[] = { providedOrigin.get(), targetOrigin.get() };

      nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
        NS_LITERAL_CSTRING("DOM Window"), sourceDocument,
        nsContentUtils::eDOM_PROPERTIES,
        "TargetPrincipalDoesNotMatch",
        params, ArrayLength(params));

      return NS_OK;
    }
  }

  ErrorResult rv;
  JS::Rooted<JS::Value> messageData(cx);
  nsCOMPtr<nsPIDOMWindowInner> window = targetWindow->AsInner();

  Read(window, cx, &messageData, rv);
  if (NS_WARN_IF(rv.Failed())) {
    return rv.StealNSResult();
  }

  // Create the event
  nsCOMPtr<mozilla::dom::EventTarget> eventTarget = do_QueryObject(targetWindow);
  RefPtr<MessageEvent> event =
    new MessageEvent(eventTarget, nullptr, nullptr);


  Nullable<WindowProxyOrMessagePort> source;
  source.SetValue().SetAsWindowProxy() = mSource ? mSource->AsOuter() : nullptr;

  Sequence<OwningNonNull<MessagePort>> ports;
  if (!TakeTransferredPortsAsSequence(ports)) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  event->InitMessageEvent(nullptr, NS_LITERAL_STRING("message"),
                          false /*non-bubbling */, false /*cancelable */,
                          messageData, mCallerOrigin,
                          EmptyString(), source, ports);

  // We can't simply call dispatchEvent on the window because doing so ends
  // up flipping the trusted bit on the event, and we don't want that to
  // happen because then untrusted content can call postMessage on a chrome
  // window if it can get a reference to it.

  nsIPresShell *shell = targetWindow->GetExtantDoc()->GetShell();
  RefPtr<nsPresContext> presContext;
  if (shell)
    presContext = shell->GetPresContext();

  event->SetTrusted(mTrustedCaller);
  WidgetEvent* internalEvent = event->WidgetEventPtr();

  nsEventStatus status = nsEventStatus_eIgnore;
  EventDispatcher::Dispatch(window,
                            presContext,
                            internalEvent,
                            static_cast<dom::Event*>(event.get()),
                            &status);
  return NS_OK;
}
Exemple #14
0
size_t
AudioConverter::DownmixAudio(void* aOut, const void* aIn, size_t aFrames) const
{
    MOZ_ASSERT(mIn.Format() == AudioConfig::FORMAT_S16 ||
               mIn.Format() == AudioConfig::FORMAT_FLT);
    MOZ_ASSERT(mIn.Channels() >= mOut.Channels());
    MOZ_ASSERT(mIn.Layout() == AudioConfig::ChannelLayout(mIn.Channels()),
               "Can only downmix input data in SMPTE layout");
    MOZ_ASSERT(mOut.Layout() == AudioConfig::ChannelLayout(2) ||
               mOut.Layout() == AudioConfig::ChannelLayout(1));

    uint32_t channels = mIn.Channels();

    if (channels == 1 && mOut.Channels() == 1) {
        if (aOut != aIn) {
            memmove(aOut, aIn, FramesOutToBytes(aFrames));
        }
        return aFrames;
    }

    if (channels > 2) {
        if (mIn.Format() == AudioConfig::FORMAT_FLT) {
            // Downmix matrix. Per-row normalization 1 for rows 3,4 and 2 for rows 5-8.
            static const float dmatrix[6][8][2]= {
                /*3*/{{0.5858f,0},{0,0.5858f},{0.4142f,0.4142f}},
                /*4*/{{0.4226f,0},{0,0.4226f},{0.366f, 0.2114f},{0.2114f,0.366f}},
                /*5*/{{0.6510f,0},{0,0.6510f},{0.4600f,0.4600f},{0.5636f,0.3254f},{0.3254f,0.5636f}},
                /*6*/{{0.5290f,0},{0,0.5290f},{0.3741f,0.3741f},{0.3741f,0.3741f},{0.4582f,0.2645f},{0.2645f,0.4582f}},
                /*7*/{{0.4553f,0},{0,0.4553f},{0.3220f,0.3220f},{0.3220f,0.3220f},{0.2788f,0.2788f},{0.3943f,0.2277f},{0.2277f,0.3943f}},
                /*8*/{{0.3886f,0},{0,0.3886f},{0.2748f,0.2748f},{0.2748f,0.2748f},{0.3366f,0.1943f},{0.1943f,0.3366f},{0.3366f,0.1943f},{0.1943f,0.3366f}},
            };
            // Re-write the buffer with downmixed data
            const float* in = static_cast<const float*>(aIn);
            float* out = static_cast<float*>(aOut);
            for (uint32_t i = 0; i < aFrames; i++) {
                float sampL = 0.0;
                float sampR = 0.0;
                for (uint32_t j = 0; j < channels; j++) {
                    sampL += in[i*mIn.Channels()+j]*dmatrix[mIn.Channels()-3][j][0];
                    sampR += in[i*mIn.Channels()+j]*dmatrix[mIn.Channels()-3][j][1];
                }
                *out++ = sampL;
                *out++ = sampR;
            }
        } else if (mIn.Format() == AudioConfig::FORMAT_S16) {
            // Downmix matrix. Per-row normalization 1 for rows 3,4 and 2 for rows 5-8.
            // Coefficients in Q14.
            static const int16_t dmatrix[6][8][2]= {
                /*3*/{{9598, 0},{0,   9598},{6786,6786}},
                /*4*/{{6925, 0},{0,   6925},{5997,3462},{3462,5997}},
                /*5*/{{10663,0},{0,  10663},{7540,7540},{9234,5331},{5331,9234}},
                /*6*/{{8668, 0},{0,   8668},{6129,6129},{6129,6129},{7507,4335},{4335,7507}},
                /*7*/{{7459, 0},{0,   7459},{5275,5275},{5275,5275},{4568,4568},{6460,3731},{3731,6460}},
                /*8*/{{6368, 0},{0,   6368},{4502,4502},{4502,4502},{5514,3184},{3184,5514},{5514,3184},{3184,5514}}
            };
            // Re-write the buffer with downmixed data
            const int16_t* in = static_cast<const int16_t*>(aIn);
            int16_t* out = static_cast<int16_t*>(aOut);
            for (uint32_t i = 0; i < aFrames; i++) {
                int32_t sampL = 0;
                int32_t sampR = 0;
                for (uint32_t j = 0; j < channels; j++) {
                    sampL+=in[i*channels+j]*dmatrix[channels-3][j][0];
                    sampR+=in[i*channels+j]*dmatrix[channels-3][j][1];
                }
                *out++ = clipTo15((sampL + 8192)>>14);
                *out++ = clipTo15((sampR + 8192)>>14);
            }
        } else {
            MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type");
        }

        // If we are to continue downmixing to mono, start working on the output
        // buffer.
        aIn = aOut;
        channels = 2;
    }
bool
DocAccessibleParent::RecvShowEvent(const ShowEventData& aData,
                                   const bool& aFromUser)
{
  if (mShutdown)
    return true;

  MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());

  if (aData.NewTree().IsEmpty()) {
    NS_ERROR("no children being added");
    return false;
  }

  ProxyAccessible* parent = GetAccessible(aData.ID());

  // XXX This should really never happen, but sometimes we fail to fire the
  // required show events.
  if (!parent) {
    NS_ERROR("adding child to unknown accessible");
    return true;
  }

  uint32_t newChildIdx = aData.Idx();
  if (newChildIdx > parent->ChildrenCount()) {
    NS_ERROR("invalid index to add child at");
    return true;
  }

  uint32_t consumed = AddSubtree(parent, aData.NewTree(), 0, newChildIdx);
  MOZ_ASSERT(consumed == aData.NewTree().Length());

  // XXX This shouldn't happen, but if we failed to add children then the below
  // is pointless and can crash.
  if (!consumed) {
    return true;
  }

#ifdef DEBUG
  for (uint32_t i = 0; i < consumed; i++) {
    uint64_t id = aData.NewTree()[i].ID();
    MOZ_ASSERT(mAccessibles.GetEntry(id));
  }
#endif

  MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());

  ProxyAccessible* target = parent->ChildAt(newChildIdx);
  ProxyShowHideEvent(target, parent, true, aFromUser);

  if (!nsCoreUtils::AccEventObserversExist()) {
    return true;
  }

  uint32_t type = nsIAccessibleEvent::EVENT_SHOW;
  xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(target);
  xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
  nsIDOMNode* node = nullptr;
  RefPtr<xpcAccEvent> event = new xpcAccEvent(type, xpcAcc, doc, node,
                                              aFromUser);
  nsCoreUtils::DispatchAccEvent(Move(event));

  return true;
}
Exemple #16
0
ProxyStream::ProxyStream(REFIID aIID, IUnknown* aObject, Environment* aEnv,
                         ProxyStreamFlags aFlags)
  : mGlobalLockedBuf(nullptr)
  , mHGlobal(nullptr)
  , mBufSize(0)
  , mPreserveStream(aFlags & ProxyStreamFlags::ePreservable)
{
  if (!aObject) {
    return;
  }

  RefPtr<IStream> stream;
  HGLOBAL hglobal = NULL;
  int streamSize = 0;
  DWORD mshlFlags = mPreserveStream ? MSHLFLAGS_TABLESTRONG : MSHLFLAGS_NORMAL;

  HRESULT createStreamResult = S_OK;
  HRESULT marshalResult = S_OK;
  HRESULT statResult = S_OK;
  HRESULT getHGlobalResult = S_OK;

  nsAutoString manifestPath;

  auto marshalFn = [this, &aIID, aObject, mshlFlags, &stream, &streamSize,
                    &hglobal, &createStreamResult, &marshalResult, &statResult,
                    &getHGlobalResult, aEnv, &manifestPath]() -> void
  {
    if (aEnv) {
      bool pushOk = aEnv->Push();
      MOZ_DIAGNOSTIC_ASSERT(pushOk);
      if (!pushOk) {
        return;
      }
    }

    auto popEnv = MakeScopeExit([aEnv]() -> void {
      if (!aEnv) {
        return;
      }

      bool popOk = aEnv->Pop();
      MOZ_DIAGNOSTIC_ASSERT(popOk);
    });

    createStreamResult = ::CreateStreamOnHGlobal(nullptr, TRUE,
                                                 getter_AddRefs(stream));
    if (FAILED(createStreamResult)) {
      return;
    }

#if defined(ACCESSIBILITY)
    ActivationContext::GetCurrentManifestPath(manifestPath);
#endif // defined(ACCESSIBILITY)

    marshalResult = ::CoMarshalInterface(stream, aIID, aObject, MSHCTX_LOCAL,
                                         nullptr, mshlFlags);
#if !defined(MOZ_DEV_EDITION)
    MOZ_DIAGNOSTIC_ASSERT(marshalResult != E_INVALIDARG);
#endif // !defined(MOZ_DEV_EDITION)
    if (FAILED(marshalResult)) {
      return;
    }

    STATSTG statstg;
    statResult = stream->Stat(&statstg, STATFLAG_NONAME);
    if (SUCCEEDED(statResult)) {
      streamSize = static_cast<int>(statstg.cbSize.LowPart);
    } else {
      return;
    }

    getHGlobalResult = ::GetHGlobalFromStream(stream, &hglobal);
    MOZ_ASSERT(SUCCEEDED(getHGlobalResult));
  };

  if (XRE_IsParentProcess()) {
    // We'll marshal this stuff directly using the current thread, therefore its
    // stub will reside in the same apartment as the current thread.
    marshalFn();
  } else {
    // When marshaling in child processes, we want to force the MTA.
    EnsureMTA mta(marshalFn);
  }

  if (FAILED(createStreamResult)) {
    nsPrintfCString hrAsStr("0x%08X", createStreamResult);
    CrashReporter::AnnotateCrashReport(
        NS_LITERAL_CSTRING("CreateStreamOnHGlobalFailure"),
        hrAsStr);
  }

  if (FAILED(marshalResult)) {
    AnnotateInterfaceRegistration(aIID);
    nsPrintfCString hrAsStr("0x%08X", marshalResult);
    CrashReporter::AnnotateCrashReport(
        NS_LITERAL_CSTRING("CoMarshalInterfaceFailure"), hrAsStr);
    CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("MarshalActCtxManifestPath"),
                                       NS_ConvertUTF16toUTF8(manifestPath));
  }

  if (FAILED(statResult)) {
    nsPrintfCString hrAsStr("0x%08X", statResult);
    CrashReporter::AnnotateCrashReport(
        NS_LITERAL_CSTRING("StatFailure"),
        hrAsStr);
  }

  if (FAILED(getHGlobalResult)) {
    nsPrintfCString hrAsStr("0x%08X", getHGlobalResult);
    CrashReporter::AnnotateCrashReport(
        NS_LITERAL_CSTRING("GetHGlobalFromStreamFailure"),
        hrAsStr);
  }

  mStream = mozilla::Move(stream);

  if (streamSize) {
    CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProxyStreamSizeFrom"),
                                       NS_LITERAL_CSTRING("IStream::Stat"));
    mBufSize = streamSize;
  }

  if (!hglobal) {
    return;
  }

  mGlobalLockedBuf = reinterpret_cast<BYTE*>(::GlobalLock(hglobal));
  mHGlobal = hglobal;

  // If we couldn't get the stream size directly from mStream, we may use
  // the size of the memory block allocated by the HGLOBAL, though it might
  // be larger than the actual stream size.
  if (!streamSize) {
    CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProxyStreamSizeFrom"),
                                       NS_LITERAL_CSTRING("GlobalSize"));
    mBufSize = static_cast<int>(::GlobalSize(hglobal));
  }

  nsAutoCString strBufSize;
  strBufSize.AppendInt(mBufSize);

  CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProxyStreamSize"),
                                     strBufSize);
}
void
DocAccessibleParent::Destroy()
{
  // If we are already shutdown that is because our containing tab parent is
  // shutting down in which case we don't need to do anything.
  if (mShutdown) {
    return;
  }

  mShutdown = true;

  MOZ_DIAGNOSTIC_ASSERT(LiveDocs().Contains(mActorID));
  uint32_t childDocCount = mChildDocs.Length();
  for (uint32_t i = 0; i < childDocCount; i++) {
    for (uint32_t j = i + 1; j < childDocCount; j++) {
      MOZ_DIAGNOSTIC_ASSERT(mChildDocs[i] != mChildDocs[j]);
    }
  }

  // XXX This indirection through the hash map of live documents shouldn't be
  // needed, but be paranoid for now.
  int32_t actorID = mActorID;
  for (uint32_t i = childDocCount - 1; i < childDocCount; i--) {
    DocAccessibleParent* thisDoc = LiveDocs().Get(actorID);
    MOZ_ASSERT(thisDoc);
    if (!thisDoc) {
      return;
    }

    thisDoc->ChildDocAt(i)->Destroy();
  }

  for (auto iter = mAccessibles.Iter(); !iter.Done(); iter.Next()) {
    MOZ_ASSERT(iter.Get()->mProxy != this);
    ProxyDestroyed(iter.Get()->mProxy);
    iter.Remove();
  }

  DocAccessibleParent* thisDoc = LiveDocs().Get(actorID);
  MOZ_ASSERT(thisDoc);
  if (!thisDoc) {
    return;
  }

  // The code above should have already completely cleared these, but to be
  // extra safe make sure they are cleared here.
  thisDoc->mAccessibles.Clear();
  thisDoc->mChildDocs.Clear();

  DocManager::NotifyOfRemoteDocShutdown(thisDoc);
  thisDoc = LiveDocs().Get(actorID);
  MOZ_ASSERT(thisDoc);
  if (!thisDoc) {
    return;
  }

  ProxyDestroyed(thisDoc);
  thisDoc = LiveDocs().Get(actorID);
  MOZ_ASSERT(thisDoc);
  if (!thisDoc) {
    return;
  }

  if (DocAccessibleParent* parentDoc = thisDoc->ParentDoc())
    parentDoc->RemoveChildDoc(thisDoc);
  else if (IsTopLevel())
    GetAccService()->RemoteDocShutdown(this);
}
Exemple #18
0
const TimeDuration& Timeout::TimeRemaining() const {
  MOZ_DIAGNOSTIC_ASSERT(mWhen.IsNull());
  // Note, mWindow->IsFrozen() can be false here.  The Thaw() method calls
  // TimeRemaining() to calculate the new When() value.
  return mTimeRemaining;
}
Exemple #19
0
void
AbortSignal::RemoveFollower(AbortFollower* aFollower)
{
  MOZ_DIAGNOSTIC_ASSERT(aFollower);
  mFollowers.RemoveElement(aFollower);
}
Exemple #20
0
nsresult
FileReader::DoReadData(uint64_t aCount)
{
  MOZ_ASSERT(mAsyncStream);

  uint32_t bytesRead = 0;

  if (mDataFormat == FILE_AS_BINARY) {
    //Continuously update our binary string as data comes in
    CheckedInt<uint64_t> size = mResult.Length();
    size += aCount;

    if (!size.isValid() ||
        size.value() > UINT32_MAX ||
        size.value() > mTotal) {
      return NS_ERROR_OUT_OF_MEMORY;
    }

    uint32_t oldLen = mResult.Length();
    MOZ_ASSERT(oldLen == mDataLen, "unexpected mResult length");

    char16_t* dest = nullptr;
    mResult.GetMutableData(&dest, size.value(), fallible);
    NS_ENSURE_TRUE(dest, NS_ERROR_OUT_OF_MEMORY);

    dest += oldLen;

    if (NS_InputStreamIsBuffered(mAsyncStream)) {
      nsresult rv = mAsyncStream->ReadSegments(ReadFuncBinaryString, dest,
                                               aCount, &bytesRead);
      NS_ENSURE_SUCCESS(rv, rv);
    } else {
      while (aCount > 0) {
        char tmpBuffer[4096];
        uint32_t minCount =
          XPCOM_MIN(aCount, static_cast<uint64_t>(sizeof(tmpBuffer)));
        uint32_t read;

        nsresult rv = mAsyncStream->Read(tmpBuffer, minCount, &read);
        if (rv == NS_BASE_STREAM_CLOSED) {
          rv = NS_OK;
        }

        NS_ENSURE_SUCCESS(rv, rv);

        if (read == 0) {
          // The stream finished too early.
          return NS_ERROR_OUT_OF_MEMORY;
        }

        PopulateBufferForBinaryString(dest, tmpBuffer, read);

        dest += read;
        aCount -= read;
        bytesRead += read;
      }
    }

    MOZ_ASSERT(size.value() == oldLen + bytesRead);
    mResult.Truncate(size.value());
  }
  else {
    CheckedInt<uint64_t> size = mDataLen;
    size += aCount;

    //Update memory buffer to reflect the contents of the file
    if (!size.isValid() ||
        // PR_Realloc doesn't support over 4GB memory size even if 64-bit OS
        // XXX: it's likely that this check is unnecessary and the comment is
        // wrong because we no longer use PR_Realloc outside of NSPR and NSS.
        size.value() > UINT32_MAX ||
        size.value() > mTotal) {
      return NS_ERROR_OUT_OF_MEMORY;
    }

    MOZ_DIAGNOSTIC_ASSERT(mFileData);
    MOZ_RELEASE_ASSERT((mDataLen + aCount) <= mTotal);

    nsresult rv = mAsyncStream->Read(mFileData + mDataLen, aCount, &bytesRead);
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return rv;
    }
  }

  mDataLen += bytesRead;
  return NS_OK;
}
Exemple #21
0
StreamControl::~StreamControl() {
  // owning thread only, but can't call virtual AssertOwningThread in destructor
  MOZ_DIAGNOSTIC_ASSERT(mReadStreamList.IsEmpty());
}
Exemple #22
0
void StreamControl::AddReadStream(ReadStream::Controllable* aReadStream) {
  AssertOwningThread();
  MOZ_DIAGNOSTIC_ASSERT(aReadStream);
  MOZ_ASSERT(!mReadStreamList.Contains(aReadStream));
  mReadStreamList.AppendElement(aReadStream);
}
Exemple #23
0
NS_IMETHODIMP
FetchDriver::OnStartRequest(nsIRequest* aRequest,
                            nsISupports* aContext)
{
  AssertIsOnMainThread();

  // Note, this can be called multiple times if we are doing an opaqueredirect.
  // In that case we will get a simulated OnStartRequest() and then the real
  // channel will call in with an errored OnStartRequest().

  if (!mChannel) {
    MOZ_ASSERT(!mObserver);
    return NS_BINDING_ABORTED;
  }

  nsresult rv;
  aRequest->GetStatus(&rv);
  if (NS_FAILED(rv)) {
    FailWithNetworkError(rv);
    return rv;
  }

  // We should only get to the following code once.
  MOZ_ASSERT(!mPipeOutputStream);
  MOZ_ASSERT(mObserver);

  mNeedToObserveOnDataAvailable = mObserver->NeedOnDataAvailable();

  RefPtr<InternalResponse> response;
  nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);

  // On a successful redirect we perform the following substeps of HTTP Fetch,
  // step 5, "redirect status", step 11.

  bool foundOpaqueRedirect = false;

  int64_t contentLength = InternalResponse::UNKNOWN_BODY_SIZE;
  rv = channel->GetContentLength(&contentLength);
  MOZ_ASSERT_IF(NS_FAILED(rv), contentLength == InternalResponse::UNKNOWN_BODY_SIZE);

  if (httpChannel) {
    uint32_t responseStatus;
    rv = httpChannel->GetResponseStatus(&responseStatus);
    MOZ_ASSERT(NS_SUCCEEDED(rv));

    if (mozilla::net::nsHttpChannel::IsRedirectStatus(responseStatus)) {
      if (mRequest->GetRedirectMode() == RequestRedirect::Error) {
        FailWithNetworkError(NS_BINDING_ABORTED);
        return NS_BINDING_FAILED;
      }
      if (mRequest->GetRedirectMode() == RequestRedirect::Manual) {
        foundOpaqueRedirect = true;
      }
    }

    nsAutoCString statusText;
    rv = httpChannel->GetResponseStatusText(statusText);
    MOZ_ASSERT(NS_SUCCEEDED(rv));

    response = new InternalResponse(responseStatus, statusText);

    response->Headers()->FillResponseHeaders(httpChannel);

    // If Content-Encoding or Transfer-Encoding headers are set, then the actual
    // Content-Length (which refer to the decoded data) is obscured behind the encodings.
    ErrorResult result;
    if (response->Headers()->Has(NS_LITERAL_CSTRING("content-encoding"), result) ||
        response->Headers()->Has(NS_LITERAL_CSTRING("transfer-encoding"), result)) {
      // We cannot trust the content-length when content-encoding or
      // transfer-encoding are set.  There are many servers which just
      // get this wrong.
      contentLength = InternalResponse::UNKNOWN_BODY_SIZE;
    }
    MOZ_ASSERT(!result.Failed());
  } else {
    response = new InternalResponse(200, NS_LITERAL_CSTRING("OK"));

    ErrorResult result;
    nsAutoCString contentType;
    rv = channel->GetContentType(contentType);
    if (NS_SUCCEEDED(rv) && !contentType.IsEmpty()) {
      nsAutoCString contentCharset;
      channel->GetContentCharset(contentCharset);
      if (NS_SUCCEEDED(rv) && !contentCharset.IsEmpty()) {
        contentType += NS_LITERAL_CSTRING(";charset=") + contentCharset;
      }

      response->Headers()->Append(NS_LITERAL_CSTRING("Content-Type"),
                                  contentType,
                                  result);
      MOZ_ASSERT(!result.Failed());
    }

    if (contentLength > 0) {
      nsAutoCString contentLenStr;
      contentLenStr.AppendInt(contentLength);
      response->Headers()->Append(NS_LITERAL_CSTRING("Content-Length"),
                                  contentLenStr,
                                  result);
      MOZ_ASSERT(!result.Failed());
    }
  }

  nsCOMPtr<nsICacheInfoChannel> cic = do_QueryInterface(aRequest);
  if (cic && mAltDataListener) {
    // Skip the case that mAltDataListener->Status() equals to FALLBACK, that means
    // the opened channel for alternative data loading is reused for loading the
    // main data.
    if (mAltDataListener->Status() != AlternativeDataStreamListener::FALLBACK) {
      // Verify the cache ID is the same with from alternative data cache.
      // If the cache ID is different, droping the alternative data loading,
      // otherwise setup the response's alternative body and cacheInfoChannel.
      uint64_t cacheEntryId = 0;
      if (NS_SUCCEEDED(cic->GetCacheEntryId(&cacheEntryId)) &&
          cacheEntryId != mAltDataListener->GetAlternativeDataCacheEntryId()) {
        mAltDataListener->Cancel();
      } else {
        // AlternativeDataStreamListener::OnStartRequest had already been called,
        // the alternative data input stream and cacheInfo channel must be created.
        nsCOMPtr<nsICacheInfoChannel> cacheInfo = mAltDataListener->GetCacheInfoChannel();
        nsCOMPtr<nsIInputStream> altInputStream = mAltDataListener->GetAlternativeInputStream();
        MOZ_ASSERT(altInputStream && cacheInfo);
        response->SetAlternativeBody(altInputStream);
        nsMainThreadPtrHandle<nsICacheInfoChannel> handle(
          new nsMainThreadPtrHolder<nsICacheInfoChannel>("nsICacheInfoChannel",
                                                         cacheInfo,
                                                         false));
        response->SetCacheInfoChannel(handle);
      }
    } else if (!mAltDataListener->GetAlternativeDataType().IsEmpty()) {
      // If the status is FALLBACK and the mAltDataListener::mAlternativeDataType
      // is not empty, that means the data need to be saved into cache, setup the
      // response's nsICacheInfoChannel for caching the data after loading.
      nsMainThreadPtrHandle<nsICacheInfoChannel> handle(
        new nsMainThreadPtrHolder<nsICacheInfoChannel>("nsICacheInfoChannel",
                                                       cic,
                                                       false));
      response->SetCacheInfoChannel(handle);
    }
  }

  // We open a pipe so that we can immediately set the pipe's read end as the
  // response's body. Setting the segment size to UINT32_MAX means that the
  // pipe has infinite space. The nsIChannel will continue to buffer data in
  // xpcom events even if we block on a fixed size pipe.  It might be possible
  // to suspend the channel and then resume when there is space available, but
  // for now use an infinite pipe to avoid blocking.
  nsCOMPtr<nsIInputStream> pipeInputStream;
  rv = NS_NewPipe(getter_AddRefs(pipeInputStream),
                  getter_AddRefs(mPipeOutputStream),
                  0, /* default segment size */
                  UINT32_MAX /* infinite pipe */,
                  true /* non-blocking input, otherwise you deadlock */,
                  false /* blocking output, since the pipe is 'in'finite */ );
  if (NS_WARN_IF(NS_FAILED(rv))) {
    FailWithNetworkError(rv);
    // Cancel request.
    return rv;
  }
  response->SetBody(pipeInputStream, contentLength);

  response->InitChannelInfo(channel);

  nsCOMPtr<nsIURI> channelURI;
  rv = channel->GetURI(getter_AddRefs(channelURI));
  if (NS_WARN_IF(NS_FAILED(rv))) {
    FailWithNetworkError(rv);
    // Cancel request.
    return rv;
  }

  nsCOMPtr<nsILoadInfo> loadInfo;
  rv = channel->GetLoadInfo(getter_AddRefs(loadInfo));
  if (NS_WARN_IF(NS_FAILED(rv))) {
    FailWithNetworkError(rv);
    return rv;
  }

  // Propagate any tainting from the channel back to our response here.  This
  // step is not reflected in the spec because the spec is written such that
  // FetchEvent.respondWith() just passes the already-tainted Response back to
  // the outer fetch().  In gecko, however, we serialize the Response through
  // the channel and must regenerate the tainting from the channel in the
  // interception case.
  mRequest->MaybeIncreaseResponseTainting(loadInfo->GetTainting());

  // Resolves fetch() promise which may trigger code running in a worker.  Make
  // sure the Response is fully initialized before calling this.
  mResponse = BeginAndGetFilteredResponse(response, foundOpaqueRedirect);
  if (NS_WARN_IF(!mResponse)) {
    // Fail to generate a paddingInfo for opaque response.
    MOZ_DIAGNOSTIC_ASSERT(mResponse->Type() == ResponseType::Opaque);
    FailWithNetworkError(NS_ERROR_UNEXPECTED);
    return rv;
  }

  // From "Main Fetch" step 19: SRI-part1.
  if (ShouldCheckSRI(mRequest, mResponse) && mSRIMetadata.IsEmpty()) {
    nsIConsoleReportCollector* reporter = nullptr;
    if (mObserver) {
      reporter = mObserver->GetReporter();
    }

    nsAutoCString sourceUri;
    if (mDocument && mDocument->GetDocumentURI()) {
      mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
    } else if (!mWorkerScript.IsEmpty()) {
      sourceUri.Assign(mWorkerScript);
    }
    SRICheck::IntegrityMetadata(mRequest->GetIntegrity(), sourceUri,
                                reporter, &mSRIMetadata);
    mSRIDataVerifier = new SRICheckDataVerifier(mSRIMetadata, sourceUri,
                                                reporter);

    // Do not retarget off main thread when using SRI API.
    return NS_OK;
  }

  nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    FailWithNetworkError(rv);
    // Cancel request.
    return rv;
  }

  // Try to retarget off main thread.
  if (nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(aRequest)) {
    Unused << NS_WARN_IF(NS_FAILED(rr->RetargetDeliveryTo(sts)));
  }
  return NS_OK;
}
ServiceWorkerImpl::ServiceWorkerImpl(ServiceWorkerInfo* aInfo)
  : mInfo(aInfo)
  , mOuter(nullptr)
{
  MOZ_DIAGNOSTIC_ASSERT(mInfo);
}
Exemple #25
0
already_AddRefed<IDBOpenDBRequest>
IDBFactory::OpenInternal(JSContext* aCx,
                         nsIPrincipal* aPrincipal,
                         const nsAString& aName,
                         const Optional<uint64_t>& aVersion,
                         const Optional<StorageType>& aStorageType,
                         bool aDeleting,
                         CallerType aCallerType,
                         ErrorResult& aRv)
{
  MOZ_ASSERT(mWindow || mOwningObject);
  MOZ_ASSERT_IF(!mWindow, !mPrivateBrowsingMode);

  CommonFactoryRequestParams commonParams;

  PrincipalInfo& principalInfo = commonParams.principalInfo();

  if (aPrincipal) {
    if (!NS_IsMainThread()) {
      MOZ_CRASH("Figure out security checks for workers!  What's this "
                "aPrincipal we have on a worker thread?");
    }
    MOZ_ASSERT(aCallerType == CallerType::System);
    MOZ_DIAGNOSTIC_ASSERT(mPrivateBrowsingMode == (aPrincipal->GetPrivateBrowsingId() > 0));

    if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(aPrincipal,
                                                      &principalInfo)))) {
      IDB_REPORT_INTERNAL_ERR();
      aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
      return nullptr;
    }

    if (principalInfo.type() != PrincipalInfo::TContentPrincipalInfo &&
        principalInfo.type() != PrincipalInfo::TSystemPrincipalInfo) {
      IDB_REPORT_INTERNAL_ERR();
      aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
      return nullptr;
    }
  } else {
    principalInfo = *mPrincipalInfo;
  }

  uint64_t version = 0;
  if (!aDeleting && aVersion.WasPassed()) {
    if (aVersion.Value() < 1) {
      aRv.ThrowTypeError<MSG_INVALID_VERSION>();
      return nullptr;
    }
    version = aVersion.Value();
  }

  // Nothing can be done here if we have previously failed to create a
  // background actor.
  if (mBackgroundActorFailed) {
    IDB_REPORT_INTERNAL_ERR();
    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    return nullptr;
  }

  PersistenceType persistenceType;

  bool isInternal = principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo;
  if (!isInternal && principalInfo.type() == PrincipalInfo::TContentPrincipalInfo) {
    nsCString origin = principalInfo.get_ContentPrincipalInfo().originNoSuffix();
    isInternal = QuotaManager::IsOriginInternal(origin);
  }

  // Allow storage attributes for add-ons independent of the pref.
  // This works in the main thread only, workers don't have the principal.
  bool isAddon = false;
  if (NS_IsMainThread()) {
    // aPrincipal is passed inconsistently, so even when we are already on
    // the main thread, we may have been passed a null aPrincipal.
    nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(principalInfo);
    if (principal) {
      nsAutoString addonId;
      Unused << NS_WARN_IF(NS_FAILED(principal->GetAddonId(addonId)));
      isAddon = !addonId.IsEmpty();
    }
  }

  if (isInternal) {
    // Chrome privilege and internal origins always get persistent storage.
    persistenceType = PERSISTENCE_TYPE_PERSISTENT;
  } else if (isAddon || DOMPrefs::IndexedDBStorageOptionsEnabled()) {
    persistenceType = PersistenceTypeFromStorage(aStorageType);
  } else {
    persistenceType = PERSISTENCE_TYPE_DEFAULT;
  }

  DatabaseMetadata& metadata = commonParams.metadata();
  metadata.name() = aName;
  metadata.persistenceType() = persistenceType;

  FactoryRequestParams params;
  if (aDeleting) {
    metadata.version() = 0;
    params = DeleteDatabaseRequestParams(commonParams);
  } else {
    metadata.version() = version;
    params = OpenDatabaseRequestParams(commonParams);
  }

  if (!mBackgroundActor) {
    BackgroundChildImpl::ThreadLocal* threadLocal =
      BackgroundChildImpl::GetThreadLocalForCurrentThread();

    nsAutoPtr<ThreadLocal> newIDBThreadLocal;
    ThreadLocal* idbThreadLocal;

    if (threadLocal && threadLocal->mIndexedDBThreadLocal) {
      idbThreadLocal = threadLocal->mIndexedDBThreadLocal;
    } else {
      nsCOMPtr<nsIUUIDGenerator> uuidGen =
        do_GetService("@mozilla.org/uuid-generator;1");
      MOZ_ASSERT(uuidGen);

      nsID id;
      MOZ_ALWAYS_SUCCEEDS(uuidGen->GenerateUUIDInPlace(&id));

      newIDBThreadLocal = idbThreadLocal = new ThreadLocal(id);
    }

    PBackgroundChild* backgroundActor =
      BackgroundChild::GetOrCreateForCurrentThread();
    if (NS_WARN_IF(!backgroundActor)) {
      IDB_REPORT_INTERNAL_ERR();
      aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
      return nullptr;
    }

    {
      BackgroundFactoryChild* actor = new BackgroundFactoryChild(this);

      // Set EventTarget for the top-level actor.
      // All child actors created later inherit the same event target.
      backgroundActor->SetEventTargetForActor(actor, EventTarget());
      MOZ_ASSERT(actor->GetActorEventTarget());
      mBackgroundActor =
        static_cast<BackgroundFactoryChild*>(
          backgroundActor->SendPBackgroundIDBFactoryConstructor(actor,
                                                                idbThreadLocal->GetLoggingInfo()));

      if (NS_WARN_IF(!mBackgroundActor)) {
        mBackgroundActorFailed = true;
        IDB_REPORT_INTERNAL_ERR();
        aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
        return nullptr;
      }
    }

    if (newIDBThreadLocal) {
      if (!threadLocal) {
        threadLocal = BackgroundChildImpl::GetThreadLocalForCurrentThread();
      }
      MOZ_ASSERT(threadLocal);
      MOZ_ASSERT(!threadLocal->mIndexedDBThreadLocal);

      threadLocal->mIndexedDBThreadLocal = newIDBThreadLocal.forget();
    }
  }

  RefPtr<IDBOpenDBRequest> request;

  if (mWindow) {
    JS::Rooted<JSObject*> scriptOwner(aCx,
                                      nsGlobalWindowInner::Cast(mWindow.get())->FastGetGlobalJSObject());
    MOZ_ASSERT(scriptOwner);

    request = IDBOpenDBRequest::CreateForWindow(aCx, this, mWindow, scriptOwner);
  } else {
    JS::Rooted<JSObject*> scriptOwner(aCx, mOwningObject);

    request = IDBOpenDBRequest::CreateForJS(aCx, this, scriptOwner);
    if (!request) {
      MOZ_ASSERT(!NS_IsMainThread());
      aRv.ThrowUncatchableException();
      return nullptr;
    }
  }

  MOZ_ASSERT(request);

  if (aDeleting) {
    IDB_LOG_MARK("IndexedDB %s: Child  Request[%llu]: "
                   "indexedDB.deleteDatabase(\"%s\")",
                 "IndexedDB %s: C R[%llu]: IDBFactory.deleteDatabase()",
                 IDB_LOG_ID_STRING(),
                 request->LoggingSerialNumber(),
                 NS_ConvertUTF16toUTF8(aName).get());
  } else {
    IDB_LOG_MARK("IndexedDB %s: Child  Request[%llu]: "
                   "indexedDB.open(\"%s\", %s)",
                 "IndexedDB %s: C R[%llu]: IDBFactory.open()",
                 IDB_LOG_ID_STRING(),
                 request->LoggingSerialNumber(),
                 NS_ConvertUTF16toUTF8(aName).get(),
                 IDB_LOG_STRINGIFY(aVersion));
  }

  nsresult rv = InitiateRequest(request, params);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    IDB_REPORT_INTERNAL_ERR();
    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    return nullptr;
  }

  return request.forget();
}
Exemple #26
0
nsCommandManager::nsCommandManager(mozIDOMWindowProxy* aWindow)
    : mWindow(aWindow) {
  MOZ_DIAGNOSTIC_ASSERT(mWindow);
}
 void FireTailDispatcher()
 {
   MOZ_DIAGNOSTIC_ASSERT(mTailDispatcher.isSome());
   mTailDispatcher.ref().DrainDirectTasks();
   mTailDispatcher.reset();
 }
ServiceWorkerImpl::~ServiceWorkerImpl()
{
  MOZ_DIAGNOSTIC_ASSERT(!mOuter);
  mInfo->RemoveListener(this);
}