2 * Copyright (C) 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2009 Google Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include "SocketStreamHandle.h"
35 #include "Credential.h"
36 #include "CredentialStorage.h"
38 #include "ProtectionSpace.h"
39 #include "SocketStreamError.h"
40 #include "SocketStreamHandleClient.h"
41 #include <wtf/MainThread.h>
42 #include <wtf/text/WTFString.h>
44 #ifdef BUILDING_ON_LEOPARD
45 #include <SystemConfiguration/SystemConfiguration.h>
49 #include "LoaderRunLoopCF.h"
50 #include <CFNetwork/CFNetwork.h>
51 #include <WebKitSystemInterface/WebKitSystemInterface.h>
53 #include "WebCoreSystemInterface.h"
59 SocketStreamHandle::SocketStreamHandle(const KURL& url, SocketStreamHandleClient* client)
60 : SocketStreamHandleBase(url, client)
61 , m_connectingSubstate(New)
62 , m_connectionType(Unknown)
63 , m_sentStoredCredentials(false)
65 LOG(Network, "SocketStreamHandle %p new client %p", this, m_client);
67 ASSERT(url.protocolIs("ws") || url.protocolIs("wss"));
69 KURL httpsURL(KURL(), "https://" + m_url.host());
70 m_httpsURL.adoptCF(httpsURL.createCFURL());
73 ASSERT(!m_readStream == !m_writeStream);
74 if (!m_readStream) // Doing asynchronous PAC file processing, streams will be created later.
80 void SocketStreamHandle::scheduleStreams()
83 ASSERT(m_writeStream);
85 CFStreamClientContext clientContext = { 0, this, retainSocketStreamHandle, releaseSocketStreamHandle, copyCFStreamDescription };
86 // FIXME: Pass specific events we're interested in instead of -1.
87 CFReadStreamSetClient(m_readStream.get(), static_cast<CFOptionFlags>(-1), readStreamCallback, &clientContext);
88 CFWriteStreamSetClient(m_writeStream.get(), static_cast<CFOptionFlags>(-1), writeStreamCallback, &clientContext);
91 CFReadStreamScheduleWithRunLoop(m_readStream.get(), loaderRunLoop(), kCFRunLoopDefaultMode);
92 CFWriteStreamScheduleWithRunLoop(m_writeStream.get(), loaderRunLoop(), kCFRunLoopDefaultMode);
94 CFReadStreamScheduleWithRunLoop(m_readStream.get(), CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
95 CFWriteStreamScheduleWithRunLoop(m_writeStream.get(), CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
98 CFReadStreamOpen(m_readStream.get());
99 CFWriteStreamOpen(m_writeStream.get());
101 if (m_pacRunLoopSource)
102 removePACRunLoopSource();
104 m_connectingSubstate = WaitingForConnect;
107 void* SocketStreamHandle::retainSocketStreamHandle(void* info)
109 SocketStreamHandle* handle = static_cast<SocketStreamHandle*>(info);
114 void SocketStreamHandle::releaseSocketStreamHandle(void* info)
116 SocketStreamHandle* handle = static_cast<SocketStreamHandle*>(info);
120 CFStringRef SocketStreamHandle::copyPACExecutionDescription(void*)
122 return CFSTR("WebSocket proxy PAC file execution");
125 struct MainThreadPACCallbackInfo {
126 MainThreadPACCallbackInfo(SocketStreamHandle* handle, CFArrayRef proxyList) : handle(handle), proxyList(proxyList) { }
127 RefPtr<SocketStreamHandle> handle;
128 CFArrayRef proxyList;
131 void SocketStreamHandle::pacExecutionCallback(void* client, CFArrayRef proxyList, CFErrorRef)
133 SocketStreamHandle* handle = static_cast<SocketStreamHandle*>(client);
134 MainThreadPACCallbackInfo info(handle, proxyList);
135 // If we're already on main thread (e.g. on Mac), callOnMainThreadAndWait() will be just a function call.
136 callOnMainThreadAndWait(pacExecutionCallbackMainThread, &info);
139 void SocketStreamHandle::pacExecutionCallbackMainThread(void* invocation)
141 MainThreadPACCallbackInfo* info = static_cast<MainThreadPACCallbackInfo*>(invocation);
142 ASSERT(info->handle->m_connectingSubstate == ExecutingPACFile);
143 // This time, the array won't have PAC as a first entry.
144 if (info->handle->m_state != Connecting)
146 info->handle->chooseProxyFromArray(info->proxyList);
147 info->handle->createStreams();
148 info->handle->scheduleStreams();
151 void SocketStreamHandle::executePACFileURL(CFURLRef pacFileURL)
153 // CFNetwork returns an empty proxy array for WebScoket schemes, so use m_httpsURL.
154 CFStreamClientContext clientContext = { 0, this, retainSocketStreamHandle, releaseSocketStreamHandle, copyPACExecutionDescription };
155 m_pacRunLoopSource.adoptCF(CFNetworkExecuteProxyAutoConfigurationURL(pacFileURL, m_httpsURL.get(), pacExecutionCallback, &clientContext));
157 CFRunLoopAddSource(loaderRunLoop(), m_pacRunLoopSource.get(), kCFRunLoopDefaultMode);
159 CFRunLoopAddSource(CFRunLoopGetCurrent(), m_pacRunLoopSource.get(), kCFRunLoopCommonModes);
161 m_connectingSubstate = ExecutingPACFile;
164 void SocketStreamHandle::removePACRunLoopSource()
166 ASSERT(m_pacRunLoopSource);
168 CFRunLoopSourceInvalidate(m_pacRunLoopSource.get());
170 CFRunLoopRemoveSource(loaderRunLoop(), m_pacRunLoopSource.get(), kCFRunLoopDefaultMode);
172 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m_pacRunLoopSource.get(), kCFRunLoopCommonModes);
174 m_pacRunLoopSource = 0;
177 void SocketStreamHandle::chooseProxy()
179 #ifndef BUILDING_ON_LEOPARD
180 RetainPtr<CFDictionaryRef> proxyDictionary(AdoptCF, CFNetworkCopySystemProxySettings());
182 // We don't need proxy information often, so there is no need to set up a permanent dynamic store session.
183 RetainPtr<CFDictionaryRef> proxyDictionary(AdoptCF, SCDynamicStoreCopyProxies(0));
186 // SOCKS or HTTPS (AKA CONNECT) proxies are supported.
187 // WebSocket protocol relies on handshake being transferred unchanged, so we need a proxy that will not modify headers.
188 // Since HTTP proxies must add Via headers, they are highly unlikely to work.
189 // Many CONNECT proxies limit connectivity to port 443, so we prefer SOCKS, if configured.
191 if (!proxyDictionary) {
192 m_connectionType = Direct;
196 // CFNetworkCopyProxiesForURL doesn't know about WebSocket schemes, so pretend to use http.
197 // Always use "https" to get HTTPS proxies in result - we'll try to use those for ws:// even though many are configured to reject connections to ports other than 443.
198 RetainPtr<CFArrayRef> proxyArray(AdoptCF, CFNetworkCopyProxiesForURL(m_httpsURL.get(), proxyDictionary.get()));
200 chooseProxyFromArray(proxyArray.get());
203 void SocketStreamHandle::chooseProxyFromArray(CFArrayRef proxyArray)
206 m_connectionType = Direct;
210 CFIndex proxyArrayCount = CFArrayGetCount(proxyArray);
212 // PAC is always the first entry, if present.
213 if (proxyArrayCount) {
214 CFDictionaryRef proxyInfo = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(proxyArray, 0));
215 CFTypeRef proxyType = CFDictionaryGetValue(proxyInfo, kCFProxyTypeKey);
216 if (proxyType && CFGetTypeID(proxyType) == CFStringGetTypeID()) {
217 if (CFEqual(proxyType, kCFProxyTypeAutoConfigurationURL)) {
218 CFTypeRef pacFileURL = CFDictionaryGetValue(proxyInfo, kCFProxyAutoConfigurationURLKey);
219 if (pacFileURL && CFGetTypeID(pacFileURL) == CFURLGetTypeID()) {
220 executePACFileURL(static_cast<CFURLRef>(pacFileURL));
227 CFDictionaryRef chosenProxy = 0;
228 for (CFIndex i = 0; i < proxyArrayCount; ++i) {
229 CFDictionaryRef proxyInfo = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(proxyArray, i));
230 CFTypeRef proxyType = CFDictionaryGetValue(proxyInfo, kCFProxyTypeKey);
231 if (proxyType && CFGetTypeID(proxyType) == CFStringGetTypeID()) {
232 if (CFEqual(proxyType, kCFProxyTypeSOCKS)) {
233 m_connectionType = SOCKSProxy;
234 chosenProxy = proxyInfo;
237 if (CFEqual(proxyType, kCFProxyTypeHTTPS)) {
238 m_connectionType = CONNECTProxy;
239 chosenProxy = proxyInfo;
240 // Keep looking for proxies, as a SOCKS one is preferable.
246 ASSERT(m_connectionType != Unknown);
247 ASSERT(m_connectionType != Direct);
249 CFTypeRef proxyHost = CFDictionaryGetValue(chosenProxy, kCFProxyHostNameKey);
250 CFTypeRef proxyPort = CFDictionaryGetValue(chosenProxy, kCFProxyPortNumberKey);
252 if (proxyHost && CFGetTypeID(proxyHost) == CFStringGetTypeID() && proxyPort && CFGetTypeID(proxyPort) == CFNumberGetTypeID()) {
253 m_proxyHost = static_cast<CFStringRef>(proxyHost);
254 m_proxyPort = static_cast<CFNumberRef>(proxyPort);
259 m_connectionType = Direct;
263 void SocketStreamHandle::createStreams()
265 if (m_connectionType == Unknown)
268 // If it's still unknown, then we're resolving a PAC file asynchronously.
269 if (m_connectionType == Unknown)
272 RetainPtr<CFStringRef> host(AdoptCF, m_url.host().createCFString());
274 // Creating streams to final destination, not to proxy.
275 CFReadStreamRef readStream = 0;
276 CFWriteStreamRef writeStream = 0;
277 CFStreamCreatePairWithSocketToHost(0, host.get(), port(), &readStream, &writeStream);
279 m_readStream.adoptCF(readStream);
280 m_writeStream.adoptCF(writeStream);
282 switch (m_connectionType) {
284 ASSERT_NOT_REACHED();
289 // FIXME: SOCKS5 doesn't do challenge-response, should we try to apply credentials from Keychain right away?
290 // But SOCKS5 credentials don't work at the time of this writing anyway, see <rdar://6776698>.
291 const void* proxyKeys[] = { kCFStreamPropertySOCKSProxyHost, kCFStreamPropertySOCKSProxyPort };
292 const void* proxyValues[] = { m_proxyHost.get(), m_proxyPort.get() };
293 RetainPtr<CFDictionaryRef> connectDictionary(AdoptCF, CFDictionaryCreate(0, proxyKeys, proxyValues, WTF_ARRAY_LENGTH(proxyKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
294 CFReadStreamSetProperty(m_readStream.get(), kCFStreamPropertySOCKSProxy, connectDictionary.get());
298 wkSetCONNECTProxyForStream(m_readStream.get(), m_proxyHost.get(), m_proxyPort.get());
302 if (shouldUseSSL()) {
303 const void* keys[] = { kCFStreamSSLPeerName, kCFStreamSSLLevel };
304 const void* values[] = { host.get(), kCFStreamSocketSecurityLevelNegotiatedSSL };
305 RetainPtr<CFDictionaryRef> settings(AdoptCF, CFDictionaryCreate(0, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
306 CFReadStreamSetProperty(m_readStream.get(), kCFStreamPropertySSLSettings, settings.get());
307 CFWriteStreamSetProperty(m_writeStream.get(), kCFStreamPropertySSLSettings, settings.get());
311 static bool getStoredCONNECTProxyCredentials(const ProtectionSpace& protectionSpace, String& login, String& password)
313 // Try system credential storage first, matching HTTP behavior (CFNetwork only asks the client for password if it couldn't find it in Keychain).
314 Credential storedCredential = CredentialStorage::getFromPersistentStorage(protectionSpace);
315 if (storedCredential.isEmpty())
316 storedCredential = CredentialStorage::get(protectionSpace);
318 if (storedCredential.isEmpty())
321 login = storedCredential.user();
322 password = storedCredential.password();
327 static ProtectionSpaceAuthenticationScheme authenticationSchemeFromAuthenticationMethod(CFStringRef method)
329 if (CFEqual(method, kCFHTTPAuthenticationSchemeBasic))
330 return ProtectionSpaceAuthenticationSchemeHTTPBasic;
331 if (CFEqual(method, kCFHTTPAuthenticationSchemeDigest))
332 return ProtectionSpaceAuthenticationSchemeHTTPDigest;
333 if (CFEqual(method, kCFHTTPAuthenticationSchemeNTLM))
334 return ProtectionSpaceAuthenticationSchemeNTLM;
335 if (CFEqual(method, kCFHTTPAuthenticationSchemeNegotiate))
336 return ProtectionSpaceAuthenticationSchemeNegotiate;
337 ASSERT_NOT_REACHED();
338 return ProtectionSpaceAuthenticationSchemeUnknown;
341 void SocketStreamHandle::addCONNECTCredentials(CFHTTPMessageRef proxyResponse)
343 RetainPtr<CFHTTPAuthenticationRef> authentication(AdoptCF, CFHTTPAuthenticationCreateFromResponse(0, proxyResponse));
345 if (!CFHTTPAuthenticationRequiresUserNameAndPassword(authentication.get())) {
346 // That's all we can offer...
347 m_client->didFailSocketStream(this, SocketStreamError()); // FIXME: Provide a sensible error.
352 CFNumberGetValue(m_proxyPort.get(), kCFNumberIntType, &port);
353 RetainPtr<CFStringRef> methodCF(AdoptCF, CFHTTPAuthenticationCopyMethod(authentication.get()));
354 RetainPtr<CFStringRef> realmCF(AdoptCF, CFHTTPAuthenticationCopyRealm(authentication.get()));
355 ProtectionSpace protectionSpace(String(m_proxyHost.get()), port, ProtectionSpaceProxyHTTPS, String(realmCF.get()), authenticationSchemeFromAuthenticationMethod(methodCF.get()));
358 if (!m_sentStoredCredentials && getStoredCONNECTProxyCredentials(protectionSpace, login, password)) {
359 // Try to apply stored credentials, if we haven't tried those already.
360 RetainPtr<CFStringRef> loginCF(AdoptCF, login.createCFString());
361 RetainPtr<CFStringRef> passwordCF(AdoptCF, password.createCFString());
362 // Creating a temporary request to make CFNetwork apply credentials to it. Unfortunately, this cannot work with NTLM authentication.
363 RetainPtr<CFHTTPMessageRef> dummyRequest(AdoptCF, CFHTTPMessageCreateRequest(0, CFSTR("GET"), m_httpsURL.get(), kCFHTTPVersion1_1));
365 Boolean appliedCredentials = CFHTTPMessageApplyCredentials(dummyRequest.get(), authentication.get(), loginCF.get(), passwordCF.get(), 0);
366 ASSERT_UNUSED(appliedCredentials, appliedCredentials);
368 RetainPtr<CFStringRef> proxyAuthorizationString(AdoptCF, CFHTTPMessageCopyHeaderFieldValue(dummyRequest.get(), CFSTR("Proxy-Authorization")));
370 if (!proxyAuthorizationString) {
371 // Fails e.g. for NTLM auth.
372 m_client->didFailSocketStream(this, SocketStreamError()); // FIXME: Provide a sensible error.
376 // Setting the authorization results in a new connection attempt.
377 wkSetCONNECTProxyAuthorizationForStream(m_readStream.get(), proxyAuthorizationString.get());
378 m_sentStoredCredentials = true;
382 // FIXME: Ask the client if credentials could not be found.
384 m_client->didFailSocketStream(this, SocketStreamError()); // FIXME: Provide a sensible error.
387 CFStringRef SocketStreamHandle::copyCFStreamDescription(void* info)
389 SocketStreamHandle* handle = static_cast<SocketStreamHandle*>(info);
390 return String("WebKit socket stream, " + handle->m_url.string()).createCFString();
393 struct MainThreadEventCallbackInfo {
394 MainThreadEventCallbackInfo(CFStreamEventType type, SocketStreamHandle* handle) : type(type), handle(handle) { }
395 CFStreamEventType type;
396 RefPtr<SocketStreamHandle> handle;
399 void SocketStreamHandle::readStreamCallback(CFReadStreamRef stream, CFStreamEventType type, void* clientCallBackInfo)
401 SocketStreamHandle* handle = static_cast<SocketStreamHandle*>(clientCallBackInfo);
402 ASSERT_UNUSED(stream, stream == handle->m_readStream.get());
404 MainThreadEventCallbackInfo info(type, handle);
405 callOnMainThreadAndWait(readStreamCallbackMainThread, &info);
407 ASSERT(isMainThread());
408 handle->readStreamCallback(type);
412 void SocketStreamHandle::writeStreamCallback(CFWriteStreamRef stream, CFStreamEventType type, void* clientCallBackInfo)
414 SocketStreamHandle* handle = static_cast<SocketStreamHandle*>(clientCallBackInfo);
415 ASSERT_UNUSED(stream, stream == handle->m_writeStream.get());
417 MainThreadEventCallbackInfo info(type, handle);
418 callOnMainThreadAndWait(writeStreamCallbackMainThread, &info);
420 ASSERT(isMainThread());
421 handle->writeStreamCallback(type);
426 void SocketStreamHandle::readStreamCallbackMainThread(void* invocation)
428 MainThreadEventCallbackInfo* info = static_cast<MainThreadEventCallbackInfo*>(invocation);
429 info->handle->readStreamCallback(info->type);
432 void SocketStreamHandle::writeStreamCallbackMainThread(void* invocation)
434 MainThreadEventCallbackInfo* info = static_cast<MainThreadEventCallbackInfo*>(invocation);
435 info->handle->writeStreamCallback(info->type);
437 #endif // PLATFORM(WIN)
439 void SocketStreamHandle::readStreamCallback(CFStreamEventType type)
442 case kCFStreamEventNone:
444 case kCFStreamEventOpenCompleted:
446 case kCFStreamEventHasBytesAvailable: {
447 if (m_connectingSubstate == WaitingForConnect) {
448 if (m_connectionType == CONNECTProxy) {
449 RetainPtr<CFHTTPMessageRef> proxyResponse(AdoptCF, wkCopyCONNECTProxyResponse(m_readStream.get(), m_httpsURL.get()));
450 if (proxyResponse && (407 == CFHTTPMessageGetResponseStatusCode(proxyResponse.get()))) {
451 addCONNECTCredentials(proxyResponse.get());
455 } else if (m_connectingSubstate == WaitingForCredentials)
458 if (m_connectingSubstate == WaitingForConnect) {
459 m_connectingSubstate = Connected;
461 m_client->didOpenSocketStream(this);
462 if (m_state == Closed)
465 } else if (m_state == Closed)
468 ASSERT(m_state == Open);
469 ASSERT(m_connectingSubstate == Connected);
472 UInt8 localBuffer[1024]; // Used if CFReadStreamGetBuffer couldn't return anything.
473 const UInt8* ptr = CFReadStreamGetBuffer(m_readStream.get(), 0, &length);
475 length = CFReadStreamRead(m_readStream.get(), localBuffer, sizeof(localBuffer));
479 m_client->didReceiveSocketStreamData(this, reinterpret_cast<const char*>(ptr), length);
483 case kCFStreamEventCanAcceptBytes:
484 ASSERT_NOT_REACHED();
486 case kCFStreamEventErrorOccurred: {
487 RetainPtr<CFErrorRef> error(AdoptCF, CFReadStreamCopyError(m_readStream.get()));
488 reportErrorToClient(error.get());
491 case kCFStreamEventEndEncountered:
497 void SocketStreamHandle::writeStreamCallback(CFStreamEventType type)
500 case kCFStreamEventNone:
502 case kCFStreamEventOpenCompleted:
504 case kCFStreamEventHasBytesAvailable:
505 ASSERT_NOT_REACHED();
507 case kCFStreamEventCanAcceptBytes: {
508 // Possibly, a spurious event from CONNECT handshake.
509 if (!CFWriteStreamCanAcceptBytes(m_writeStream.get()))
512 if (m_connectingSubstate == WaitingForCredentials)
515 if (m_connectingSubstate == WaitingForConnect) {
516 m_connectingSubstate = Connected;
518 m_client->didOpenSocketStream(this);
522 ASSERT(m_state == Open);
523 ASSERT(m_connectingSubstate == Connected);
528 case kCFStreamEventErrorOccurred: {
529 RetainPtr<CFErrorRef> error(AdoptCF, CFWriteStreamCopyError(m_writeStream.get()));
530 reportErrorToClient(error.get());
533 case kCFStreamEventEndEncountered:
534 // FIXME: Currently, we handle closing in read callback, but these can come independently (e.g. a server can stop listening, but keep sending data).
539 void SocketStreamHandle::reportErrorToClient(CFErrorRef error)
541 CFIndex errorCode = CFErrorGetCode(error);
547 #pragma clang diagnostic push
548 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
551 if (CFEqual(CFErrorGetDomain(error), kCFErrorDomainOSStatus)) {
552 const char* descriptionOSStatus = GetMacOSStatusCommentString(static_cast<OSStatus>(errorCode));
553 if (descriptionOSStatus && descriptionOSStatus[0] != '\0')
554 description = "OSStatus Error " + String::number(errorCode) + ": " + descriptionOSStatus;
558 #pragma clang diagnostic pop
563 if (description.isNull()) {
564 RetainPtr<CFStringRef> descriptionCF(AdoptCF, CFErrorCopyDescription(error));
565 description = String(descriptionCF.get());
568 m_client->didFailSocketStream(this, SocketStreamError(static_cast<int>(errorCode), m_url.string(), description));
571 SocketStreamHandle::~SocketStreamHandle()
573 LOG(Network, "SocketStreamHandle %p dtor", this);
575 ASSERT(!m_pacRunLoopSource);
578 int SocketStreamHandle::platformSend(const char* data, int length)
580 if (!CFWriteStreamCanAcceptBytes(m_writeStream.get()))
583 return CFWriteStreamWrite(m_writeStream.get(), reinterpret_cast<const UInt8*>(data), length);
586 void SocketStreamHandle::platformClose()
588 LOG(Network, "SocketStreamHandle %p platformClose", this);
590 if (m_pacRunLoopSource)
591 removePACRunLoopSource();
593 ASSERT(!m_readStream == !m_writeStream);
595 if (m_connectingSubstate == New || m_connectingSubstate == ExecutingPACFile)
596 m_client->didCloseSocketStream(this);
601 CFReadStreamUnscheduleFromRunLoop(m_readStream.get(), loaderRunLoop(), kCFRunLoopDefaultMode);
602 CFWriteStreamUnscheduleFromRunLoop(m_writeStream.get(), loaderRunLoop(), kCFRunLoopDefaultMode);
604 CFReadStreamUnscheduleFromRunLoop(m_readStream.get(), CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
605 CFWriteStreamUnscheduleFromRunLoop(m_writeStream.get(), CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
608 CFReadStreamClose(m_readStream.get());
609 CFWriteStreamClose(m_writeStream.get());
614 m_client->didCloseSocketStream(this);
617 void SocketStreamHandle::receivedCredential(const AuthenticationChallenge&, const Credential&)
621 void SocketStreamHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&)
625 void SocketStreamHandle::receivedCancellation(const AuthenticationChallenge&)
629 unsigned short SocketStreamHandle::port() const
631 if (unsigned short urlPort = m_url.port())
638 } // namespace WebCore