void SocketStreamHandle::addCONNECTCredentials(CFHTTPMessageRef proxyResponse) { RetainPtr<CFHTTPAuthenticationRef> authentication(AdoptCF, CFHTTPAuthenticationCreateFromResponse(0, proxyResponse)); if (!CFHTTPAuthenticationRequiresUserNameAndPassword(authentication.get())) { // That's all we can offer... m_client->didFail(this, SocketStreamError()); // FIXME: Provide a sensible error. return; } int port = 0; CFNumberGetValue(m_proxyPort.get(), kCFNumberIntType, &port); RetainPtr<CFStringRef> methodCF(AdoptCF, CFHTTPAuthenticationCopyMethod(authentication.get())); RetainPtr<CFStringRef> realmCF(AdoptCF, CFHTTPAuthenticationCopyRealm(authentication.get())); ProtectionSpace protectionSpace(String(m_proxyHost.get()), port, ProtectionSpaceProxyHTTPS, String(realmCF.get()), authenticationSchemeFromAuthenticationMethod(methodCF.get())); String login; String password; if (!m_sentStoredCredentials && getStoredCONNECTProxyCredentials(protectionSpace, login, password)) { // Try to apply stored credentials, if we haven't tried those already. RetainPtr<CFStringRef> loginCF(AdoptCF, login.createCFString()); RetainPtr<CFStringRef> passwordCF(AdoptCF, password.createCFString()); // Creating a temporary request to make CFNetwork apply credentials to it. Unfortunately, this cannot work with NTLM authentication. RetainPtr<CFHTTPMessageRef> dummyRequest(AdoptCF, CFHTTPMessageCreateRequest(0, CFSTR("GET"), m_httpsURL.get(), kCFHTTPVersion1_1)); Boolean appliedCredentials = CFHTTPMessageApplyCredentials(dummyRequest.get(), authentication.get(), loginCF.get(), passwordCF.get(), 0); ASSERT_UNUSED(appliedCredentials, appliedCredentials); RetainPtr<CFStringRef> proxyAuthorizationString(AdoptCF, CFHTTPMessageCopyHeaderFieldValue(dummyRequest.get(), CFSTR("Proxy-Authorization"))); if (!proxyAuthorizationString) { // Fails e.g. for NTLM auth. m_client->didFail(this, SocketStreamError()); // FIXME: Provide a sensible error. return; } // Setting the authorization results in a new connection attempt. wkSetCONNECTProxyAuthorizationForStream(m_readStream.get(), proxyAuthorizationString.get()); m_sentStoredCredentials = true; return; } // FIXME: Ask the client if credentials could not be found. m_client->didFail(this, SocketStreamError()); // FIXME: Provide a sensible error. }
bool RChannelReaderImpl::FetchNextItemArray(UInt32 maxArraySize, RChannelItemArrayRef* pItemArray, DrTimeInterval csTimeOut) { ChannelProcessRequestList requestList; ChannelUnitList returnUnitList; DryadHandleListEntry* event = NULL; bool timedOut = false; bool mustBlock = false; bool startSupplier = false; { AutoCriticalSection acs(&m_baseDR); if (m_state != RS_Running) { LogAssert(m_state != RS_Closed); /* return an empty array */ pItemArray->Attach(new RChannelItemArray()); return true; } if (!m_unitList.IsEmpty()) { LogAssert(m_startedSupplier == true); LogAssert(m_handlerList.IsEmpty()); RChannelReaderSyncWaiter dummyHandler(NULL, INVALID_HANDLE_VALUE, NULL); dummyHandler.SetMaximumArraySize(maxArraySize); RChannelProcessRequest dummyRequest(NULL, &dummyHandler, NULL); m_handlerList.InsertAsTail(m_handlerList.CastIn(&dummyRequest)); TransferWaitingItems("FetchNextItemArray", &requestList, &returnUnitList); RChannelProcessRequest* dummyReturn = requestList.CastOut(requestList.RemoveHead()); LogAssert(dummyReturn == &dummyRequest); pItemArray->Set(dummyRequest.GetItemArray()); LogAssert((*pItemArray)->GetNumberOfItems() > 0); } else if (m_writerTerminationItem != NULL || m_readerTerminationItem != NULL) { /* we have already sent a termination item for processing so there aren't going to be any more arriving on the queue and we can return an empty list immediately */ pItemArray->Attach(new RChannelItemArray()); } else if (csTimeOut > DrTimeInterval_Zero) { if (m_startedSupplier == false) { /* when we exit the lock, we will start the supplier since this is the first read we have received. After the supplier has been started we'll set m_startedSupplierEvent to prevent a race condition in Interrupt */ startSupplier = true; BOOL bRet = ::ResetEvent(m_startedSupplierEvent); LogAssert(bRet != 0); m_startedSupplier = true; } /* we are going to block */ mustBlock = true; event = m_eventCache.GetEvent(true); } else { /* there's no item available and a zero timeout --- return an empty list immediately */ pItemArray->Attach(new RChannelItemArray()); LogAssert(csTimeOut == DrTimeInterval_Zero); timedOut = true; } m_unitLatch.AcceptList(&returnUnitList); FOO(&requestList); m_sendLatch.AcceptList(&requestList); } if (startSupplier) { // DrLogI( "Starting Supplier"); m_supplier->StartSupplier(m_prefetchCookie); // DrLogI( "Started Supplier"); BOOL bRet = ::SetEvent(m_startedSupplierEvent); LogAssert(bRet != 0); } DispatchRequests("FetchNextItemArray", &requestList, &returnUnitList); if (mustBlock == false) { LogAssert(event == NULL); } else { LogAssert(event != NULL); *pItemArray = NULL; RChannelReaderSyncWaiter* waiter = new RChannelReaderSyncWaiter(this, event->GetHandle(), pItemArray); this->SupplyHandler(waiter, waiter); DWORD timeOut = DrGetTimerMsFromInterval(csTimeOut); DWORD dRet = ::WaitForSingleObject(event->GetHandle(), timeOut); if (dRet == WAIT_TIMEOUT) { /* when cancel returns it's guaranteed the handler has been called */ this->Cancel(waiter); } else { LogAssert(dRet == WAIT_OBJECT_0); } LogAssert(*pItemArray != NULL); delete waiter; { AutoCriticalSection acs(&m_baseDR); /* save this event in case we need one again in the future */ m_eventCache.ReturnEvent(event); /* even if we actually timed out the wait, the handler may have supplied an item immediately afterwards or during the cancel. We only return a timed out value if there's no item ready but we haven't processed a termination item, so it's worth waiting for another one. */ timedOut = ((*pItemArray)->GetNumberOfItems() == 0 && m_writerTerminationItem == NULL && m_readerTerminationItem == NULL); } } return (!timedOut); }