NS_IMETHODIMP EventSource::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext, nsresult aStatusCode) { mWaitingForOnStopRequest = false; if (mReadyState == CLOSED) { return NS_ERROR_ABORT; } // "Network errors that prevents the connection from being established in the // first place (e.g. DNS errors), must cause the user agent to asynchronously // reestablish the connection. // // (...) the cancelation of the fetch algorithm by the user agent (e.g. in // response to window.stop() or the user canceling the network connection // manually) must cause the user agent to fail the connection. if (NS_FAILED(aStatusCode) && aStatusCode != NS_ERROR_CONNECTION_REFUSED && aStatusCode != NS_ERROR_NET_TIMEOUT && aStatusCode != NS_ERROR_NET_RESET && aStatusCode != NS_ERROR_NET_INTERRUPT && aStatusCode != NS_ERROR_PROXY_CONNECTION_REFUSED && aStatusCode != NS_ERROR_DNS_LOOKUP_QUEUE_FULL) { DispatchFailConnection(); return NS_ERROR_ABORT; } nsresult rv = CheckHealthOfRequestCallback(aRequest); NS_ENSURE_SUCCESS(rv, rv); ClearFields(); nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &EventSource::ReestablishConnection); NS_ENSURE_STATE(event); rv = NS_DispatchToMainThread(event); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
NS_IMETHODIMP EventSource::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt) { nsresult rv = CheckHealthOfRequestCallback(aRequest); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest, &rv); NS_ENSURE_SUCCESS(rv, rv); bool requestSucceeded; rv = httpChannel->GetRequestSucceeded(&requestSucceeded); NS_ENSURE_SUCCESS(rv, rv); nsAutoCString contentType; rv = httpChannel->GetContentType(contentType); NS_ENSURE_SUCCESS(rv, rv); if (!requestSucceeded || !contentType.EqualsLiteral(TEXT_EVENT_STREAM)) { DispatchFailConnection(); return NS_ERROR_NOT_AVAILABLE; } nsCOMPtr<nsIPrincipal> principal = mPrincipal; if (nsContentUtils::IsSystemPrincipal(principal)) { // Don't give this channel the system principal. principal = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv); NS_ENSURE_SUCCESS(rv, rv); } rv = httpChannel->SetOwner(principal); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &EventSource::AnnounceConnection); NS_ENSURE_STATE(event); rv = NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); NS_ENSURE_SUCCESS(rv, rv); mStatus = PARSE_STATE_BEGIN_OF_STREAM; return NS_OK; }
NS_IMETHODIMP EventSource::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext, nsresult aStatusCode) { mWaitingForOnStopRequest = false; if (mReadyState == CLOSED) { return NS_ERROR_ABORT; } if (NS_FAILED(aStatusCode)) { DispatchFailConnection(); return aStatusCode; } nsresult rv; nsresult healthOfRequestResult = CheckHealthOfRequestCallback(aRequest); if (NS_SUCCEEDED(healthOfRequestResult) && mLastConvertionResult == NS_PARTIAL_MORE_INPUT) { // we had an incomplete UTF8 char at the end of the stream rv = ParseCharacter(REPLACEMENT_CHAR); NS_ENSURE_SUCCESS(rv, rv); } ClearFields(); nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &EventSource::ReestablishConnection); NS_ENSURE_STATE(event); rv = NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); NS_ENSURE_SUCCESS(rv, rv); return healthOfRequestResult; }
nsresult EventSource::InitChannelAndRequestEventSource() { if (mReadyState == CLOSED) { return NS_ERROR_ABORT; } bool isValidScheme = (NS_SUCCEEDED(mSrc->SchemeIs("http", &isValidScheme)) && isValidScheme) || (NS_SUCCEEDED(mSrc->SchemeIs("https", &isValidScheme)) && isValidScheme); nsresult rv = CheckInnerWindowCorrectness(); if (NS_FAILED(rv) || !isValidScheme) { DispatchFailConnection(); return NS_ERROR_DOM_SECURITY_ERR; } nsLoadFlags loadFlags; loadFlags = nsIRequest::LOAD_BACKGROUND | nsIRequest::LOAD_BYPASS_CACHE; nsIScriptContext* sc = GetContextForEventHandlers(&rv); nsCOMPtr<nsIDocument> doc = nsContentUtils::GetDocumentFromScriptContext(sc); nsSecurityFlags securityFlags = nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS; if (mWithCredentials) { securityFlags |= nsILoadInfo::SEC_REQUIRE_CORS_WITH_CREDENTIALS; } nsCOMPtr<nsIChannel> channel; // If we have the document, use it if (doc) { rv = NS_NewChannel(getter_AddRefs(channel), mSrc, doc, securityFlags, nsIContentPolicy::TYPE_INTERNAL_EVENTSOURCE, mLoadGroup, // loadGroup nullptr, // aCallbacks loadFlags); // aLoadFlags } else { // otherwise use the principal rv = NS_NewChannel(getter_AddRefs(channel), mSrc, mPrincipal, securityFlags, nsIContentPolicy::TYPE_INTERNAL_EVENTSOURCE, mLoadGroup, // loadGroup nullptr, // aCallbacks loadFlags); // aLoadFlags } NS_ENSURE_SUCCESS(rv, rv); mHttpChannel = do_QueryInterface(channel); NS_ENSURE_TRUE(mHttpChannel, NS_ERROR_NO_INTERFACE); rv = SetupHttpChannel(); NS_ENSURE_SUCCESS(rv, rv); #ifdef DEBUG { nsCOMPtr<nsIInterfaceRequestor> notificationCallbacks; mHttpChannel->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks)); MOZ_ASSERT(!notificationCallbacks); } #endif mHttpChannel->SetNotificationCallbacks(this); // Start reading from the channel rv = mHttpChannel->AsyncOpen2(this); if (NS_FAILED(rv)) { DispatchFailConnection(); return rv; } mWaitingForOnStopRequest = true; return rv; }