diff options
Diffstat (limited to 'WebCore/platform/network')
19 files changed, 501 insertions, 207 deletions
diff --git a/WebCore/platform/network/FormDataBuilder.h b/WebCore/platform/network/FormDataBuilder.h index 666f0c1..286f59f 100644 --- a/WebCore/platform/network/FormDataBuilder.h +++ b/WebCore/platform/network/FormDataBuilder.h @@ -30,7 +30,7 @@ class CString; class Document; class TextEncoding; -class FormDataBuilder : Noncopyable { +class FormDataBuilder : public Noncopyable { public: FormDataBuilder(); ~FormDataBuilder(); diff --git a/WebCore/platform/network/HTTPParsers.cpp b/WebCore/platform/network/HTTPParsers.cpp index e57401e..9202660 100644 --- a/WebCore/platform/network/HTTPParsers.cpp +++ b/WebCore/platform/network/HTTPParsers.cpp @@ -100,6 +100,13 @@ bool parseHTTPRefresh(const String& refresh, bool fromHttpEquivMeta, double& del if (refresh[urlEndPos] == quotationMark) break; } + + // https://bugs.webkit.org/show_bug.cgi?id=27868 + // Sometimes there is no closing quote for the end of the URL even though there was an opening quote. + // If we looped over the entire alleged URL string back to the opening quote, just go ahead and use everything + // after the opening quote instead. + if (urlEndPos == urlStartPos) + urlEndPos = len; } url = refresh.substring(urlStartPos, urlEndPos - urlStartPos).stripWhiteSpace(); diff --git a/WebCore/platform/network/ResourceHandle.h b/WebCore/platform/network/ResourceHandle.h index 3b27b00..e82e13b 100644 --- a/WebCore/platform/network/ResourceHandle.h +++ b/WebCore/platform/network/ResourceHandle.h @@ -105,7 +105,7 @@ public: static PassRefPtr<ResourceHandle> create(const ResourceRequest&, ResourceHandleClient*, Frame*, bool defersLoading, bool shouldContentSniff, bool mightDownloadFromHandle = false); static void loadResourceSynchronously(const ResourceRequest&, StoredCredentials, ResourceError&, ResourceResponse&, Vector<char>& data, Frame* frame); - static bool willLoadFromCache(ResourceRequest&); + static bool willLoadFromCache(ResourceRequest&, Frame*); #if PLATFORM(MAC) static bool didSendBodyDataDelegateExists(); #endif @@ -191,12 +191,6 @@ public: void fireFailure(Timer<ResourceHandle>*); private: -#if USE(SOUP) - bool startData(String urlString); - bool startHttp(String urlString); - bool startGio(KURL url); -#endif - void scheduleFailure(FailureType); bool start(Frame*); diff --git a/WebCore/platform/network/ResourceHandleInternal.h b/WebCore/platform/network/ResourceHandleInternal.h index b10c658..7951109 100644 --- a/WebCore/platform/network/ResourceHandleInternal.h +++ b/WebCore/platform/network/ResourceHandleInternal.h @@ -35,7 +35,7 @@ #include <CFNetwork/CFURLConnectionPriv.h> #endif -#if USE(WININET) +#if USE(WININET) || (USE(CURL) && PLATFORM(WIN)) #include <winsock2.h> #include <windows.h> #endif @@ -81,7 +81,7 @@ namespace android { namespace WebCore { class ResourceHandleClient; - class ResourceHandleInternal : Noncopyable { + class ResourceHandleInternal : public Noncopyable { public: ResourceHandleInternal(ResourceHandle* loader, const ResourceRequest& request, ResourceHandleClient* c, bool defersLoading, bool shouldContentSniff, bool mightDownloadFromHandle) : m_client(c) @@ -117,7 +117,6 @@ namespace WebCore { #if USE(SOUP) , m_msg(0) , m_cancelled(false) - , m_reportedHeaders(false) , m_gfile(0) , m_inputStream(0) , m_cancellable(0) @@ -203,7 +202,6 @@ namespace WebCore { SoupMessage* m_msg; ResourceResponse m_response; bool m_cancelled; - bool m_reportedHeaders; GFile* m_gfile; GInputStream* m_inputStream; GCancellable* m_cancellable; diff --git a/WebCore/platform/network/ResourceResponseBase.cpp b/WebCore/platform/network/ResourceResponseBase.cpp index 965759e..7f8a4e2 100644 --- a/WebCore/platform/network/ResourceResponseBase.cpp +++ b/WebCore/platform/network/ResourceResponseBase.cpp @@ -42,12 +42,21 @@ static void parseCacheHeader(const String& header, Vector<pair<String, String> > ResourceResponseBase::ResourceResponseBase() : m_expectedContentLength(0) , m_httpStatusCode(0) + , m_lastModifiedDate(0) , m_isNull(true) , m_haveParsedCacheControlHeader(false) , m_haveParsedAgeHeader(false) , m_haveParsedDateHeader(false) , m_haveParsedExpiresHeader(false) , m_haveParsedLastModifiedHeader(false) + , m_cacheControlContainsNoCache(false) + , m_cacheControlContainsNoStore(false) + , m_cacheControlContainsMustRevalidate(false) + , m_cacheControlMaxAge(0.0) + , m_age(0.0) + , m_date(0.0) + , m_expires(0.0) + , m_lastModified(0.0) { } @@ -58,12 +67,21 @@ ResourceResponseBase::ResourceResponseBase(const KURL& url, const String& mimeTy , m_textEncodingName(textEncodingName) , m_suggestedFilename(filename) , m_httpStatusCode(0) + , m_lastModifiedDate(0) , m_isNull(false) , m_haveParsedCacheControlHeader(false) , m_haveParsedAgeHeader(false) , m_haveParsedDateHeader(false) , m_haveParsedExpiresHeader(false) , m_haveParsedLastModifiedHeader(false) + , m_cacheControlContainsNoCache(false) + , m_cacheControlContainsNoStore(false) + , m_cacheControlContainsMustRevalidate(false) + , m_cacheControlMaxAge(0.0) + , m_age(0.0) + , m_date(0.0) + , m_expires(0.0) + , m_lastModified(0.0) { } @@ -266,6 +284,7 @@ void ResourceResponseBase::parseCacheControlDirectives() const DEFINE_STATIC_LOCAL(const AtomicString, cacheControlString, ("cache-control")); DEFINE_STATIC_LOCAL(const AtomicString, noCacheDirective, ("no-cache")); + DEFINE_STATIC_LOCAL(const AtomicString, noStoreDirective, ("no-store")); DEFINE_STATIC_LOCAL(const AtomicString, mustRevalidateDirective, ("must-revalidate")); DEFINE_STATIC_LOCAL(const AtomicString, maxAgeDirective, ("max-age")); @@ -280,6 +299,8 @@ void ResourceResponseBase::parseCacheControlDirectives() const // It should be ignored by a browser level cache. if (equalIgnoringCase(directives[i].first, noCacheDirective) && directives[i].second.isEmpty()) m_cacheControlContainsNoCache = true; + else if (equalIgnoringCase(directives[i].first, noStoreDirective)) + m_cacheControlContainsNoStore = true; else if (equalIgnoringCase(directives[i].first, mustRevalidateDirective)) m_cacheControlContainsMustRevalidate = true; else if (equalIgnoringCase(directives[i].first, maxAgeDirective)) { @@ -308,6 +329,13 @@ bool ResourceResponseBase::cacheControlContainsNoCache() const return m_cacheControlContainsNoCache; } +bool ResourceResponseBase::cacheControlContainsNoStore() const +{ + if (!m_haveParsedCacheControlHeader) + parseCacheControlDirectives(); + return m_cacheControlContainsNoStore; +} + bool ResourceResponseBase::cacheControlContainsMustRevalidate() const { if (!m_haveParsedCacheControlHeader) diff --git a/WebCore/platform/network/ResourceResponseBase.h b/WebCore/platform/network/ResourceResponseBase.h index 7138908..7594c09 100644 --- a/WebCore/platform/network/ResourceResponseBase.h +++ b/WebCore/platform/network/ResourceResponseBase.h @@ -86,6 +86,7 @@ public: // These functions return parsed values of the corresponding response headers. // NaN means that the header was not present or had invalid value. bool cacheControlContainsNoCache() const; + bool cacheControlContainsNoStore() const; bool cacheControlContainsMustRevalidate() const; double cacheControlMaxAge() const; double date() const; @@ -136,6 +137,7 @@ private: mutable bool m_haveParsedLastModifiedHeader : 1; mutable bool m_cacheControlContainsNoCache : 1; + mutable bool m_cacheControlContainsNoStore : 1; mutable bool m_cacheControlContainsMustRevalidate : 1; mutable double m_cacheControlMaxAge; diff --git a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp index 1d5bf9f..e348f83 100644 --- a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp +++ b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp @@ -116,9 +116,27 @@ CFURLRequestRef willSendRequest(CFURLConnectionRef conn, CFURLRequestRef cfReque LOG(Network, "CFNet - willSendRequest(conn=%p, handle=%p) (%s)", conn, handle, handle->request().url().string().utf8().data()); - ResourceRequest request(cfRequest); + ResourceRequest request; + if (cfRedirectResponse) { + CFHTTPMessageRef httpMessage = CFURLResponseGetHTTPResponse(cfRedirectResponse); + if (httpMessage && CFHTTPMessageGetResponseStatusCode(httpMessage) == 307) { + RetainPtr<CFStringRef> originalMethod(AdoptCF, handle->request().httpMethod().createCFString()); + RetainPtr<CFStringRef> newMethod(AdoptCF, CFURLRequestCopyHTTPRequestMethod(cfRequest)); + if (CFStringCompareWithOptions(originalMethod.get(), newMethod.get(), CFRangeMake(0, CFStringGetLength(originalMethod.get())), kCFCompareCaseInsensitive)) { + RetainPtr<CFMutableURLRequestRef> mutableRequest(AdoptCF, CFURLRequestCreateMutableCopy(0, cfRequest)); + CFURLRequestSetHTTPRequestMethod(mutableRequest.get(), originalMethod.get()); + request = mutableRequest.get(); + } + } + } + if (request.isNull()) + request = cfRequest; + handle->willSendRequest(request, cfRedirectResponse); + if (request.isNull()) + return 0; + cfRequest = request.cfURLRequest(); CFRetain(cfRequest); @@ -554,7 +572,7 @@ bool ResourceHandle::loadsBlocked() return false; } -bool ResourceHandle::willLoadFromCache(ResourceRequest& request) +bool ResourceHandle::willLoadFromCache(ResourceRequest& request, Frame* frame) { request.setCachePolicy(ReturnCacheDataDontLoad); diff --git a/WebCore/platform/network/curl/ResourceHandleCurl.cpp b/WebCore/platform/network/curl/ResourceHandleCurl.cpp index a2e692c..a6f5dca 100644 --- a/WebCore/platform/network/curl/ResourceHandleCurl.cpp +++ b/WebCore/platform/network/curl/ResourceHandleCurl.cpp @@ -179,7 +179,7 @@ void ResourceHandle::setDefersLoading(bool defers) #endif } -bool ResourceHandle::willLoadFromCache(ResourceRequest&) +bool ResourceHandle::willLoadFromCache(ResourceRequest&, Frame*) { notImplemented(); return false; diff --git a/WebCore/platform/network/curl/ResourceHandleManager.cpp b/WebCore/platform/network/curl/ResourceHandleManager.cpp index c61ad4f..2aa286a 100644 --- a/WebCore/platform/network/curl/ResourceHandleManager.cpp +++ b/WebCore/platform/network/curl/ResourceHandleManager.cpp @@ -582,7 +582,7 @@ void ResourceHandleManager::initializeHandle(ResourceHandle* job) KURL kurl = job->request().url(); // Remove any fragment part, otherwise curl will send it as part of the request. - kurl.removeRef(); + kurl.removeFragmentIdentifier(); ResourceHandleInternal* d = job->getInternal(); String url = kurl.string(); diff --git a/WebCore/platform/network/curl/ResourceHandleManager.h b/WebCore/platform/network/curl/ResourceHandleManager.h index f3ad234..d38e577 100644 --- a/WebCore/platform/network/curl/ResourceHandleManager.h +++ b/WebCore/platform/network/curl/ResourceHandleManager.h @@ -32,6 +32,11 @@ #include "Timer.h" #include "ResourceHandleClient.h" +#if PLATFORM(WIN) +#include <winsock2.h> +#include <windows.h> +#endif + #include <curl/curl.h> #include <wtf/Vector.h> diff --git a/WebCore/platform/network/mac/FormDataStreamMac.mm b/WebCore/platform/network/mac/FormDataStreamMac.mm index 94fdb25..a8d6887 100644 --- a/WebCore/platform/network/mac/FormDataStreamMac.mm +++ b/WebCore/platform/network/mac/FormDataStreamMac.mm @@ -32,6 +32,7 @@ #import "FormDataStreamMac.h" #import "CString.h" +#import "FileSystem.h" #import "FormData.h" #import "ResourceHandle.h" #import "ResourceHandleClient.h" @@ -360,11 +361,9 @@ void setHTTPBody(NSMutableURLRequest *request, PassRefPtr<FormData> formData) if (element.m_type == FormDataElement::data) length += element.m_data.size(); else { - const String& filename = element.m_shouldGenerateFile ? element.m_generatedFilename : element.m_filename; - struct stat sb; - int statResult = stat(filename.utf8().data(), &sb); - if (statResult == 0 && (sb.st_mode & S_IFMT) == S_IFREG) - length += sb.st_size; + long long fileSize; + if (getFileSize(element.m_shouldGenerateFile ? element.m_generatedFilename : element.m_filename, fileSize)) + length += fileSize; } } diff --git a/WebCore/platform/network/mac/ResourceHandleMac.mm b/WebCore/platform/network/mac/ResourceHandleMac.mm index 3af1b97..db76d1a 100644 --- a/WebCore/platform/network/mac/ResourceHandleMac.mm +++ b/WebCore/platform/network/mac/ResourceHandleMac.mm @@ -46,10 +46,6 @@ #import "WebCoreURLResponse.h" #import <wtf/UnusedParam.h> -#ifndef BUILDING_ON_TIGER -#import <objc/objc-class.h> -#endif - #ifdef BUILDING_ON_TIGER typedef int NSInteger; #endif @@ -93,9 +89,6 @@ using namespace WebCore; static NSString *WebCoreSynchronousLoaderRunLoopMode = @"WebCoreSynchronousLoaderRunLoopMode"; -static IMP oldNSURLResponseMIMETypeIMP = 0; -static NSString *webNSURLResponseMIMEType(id, SEL); - #endif namespace WebCore { @@ -182,11 +175,18 @@ bool ResourceHandle::start(Frame* frame) if (!ResourceHandle::didSendBodyDataDelegateExists()) associateStreamWithResourceHandle([d->m_request.nsURLRequest() HTTPBodyStream], this); +#ifdef BUILDING_ON_TIGER + // A conditional request sent by WebCore (e.g. to update appcache) can be for a resource that is not cacheable by NSURLConnection, + // which can get confused and fail to load it in this case. + if (d->m_request.isConditional()) + d->m_request.setCachePolicy(ReloadIgnoringCacheData); +#endif + d->m_needsSiteSpecificQuirks = frame->settings() && frame->settings()->needsSiteSpecificQuirks(); NSURLConnection *connection; - if (d->m_shouldContentSniff) + if (d->m_shouldContentSniff || frame->settings()->localFileContentSniffingEnabled()) #ifdef BUILDING_ON_TIGER connection = [[NSURLConnection alloc] initWithRequest:d->m_request.nsURLRequest() delegate:delegate]; #else @@ -348,7 +348,7 @@ bool ResourceHandle::loadsBlocked() #endif } -bool ResourceHandle::willLoadFromCache(ResourceRequest& request) +bool ResourceHandle::willLoadFromCache(ResourceRequest& request, Frame*) { #ifndef BUILDING_ON_TIGER request.setCachePolicy(ReturnCacheDataDontLoad); @@ -567,6 +567,15 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen LOG(Network, "Handle %p delegate connection:%p willSendRequest:%@ redirectResponse:%p", m_handle, connection, [newRequest description], redirectResponse); + if (redirectResponse && [redirectResponse isKindOfClass:[NSHTTPURLResponse class]] && [(NSHTTPURLResponse *)redirectResponse statusCode] == 307) { + String originalMethod = m_handle->request().httpMethod(); + if (!equalIgnoringCase(originalMethod, String([newRequest HTTPMethod]))) { + NSMutableURLRequest *mutableRequest = [newRequest mutableCopy]; + [mutableRequest setHTTPMethod:originalMethod]; + newRequest = [mutableRequest autorelease]; + } + } + CallbackGuard guard; ResourceRequest request = newRequest; m_handle->willSendRequest(request, redirectResponse); @@ -626,19 +635,13 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen { UNUSED_PARAM(connection); - LOG(Network, "Handle %p delegate connection:%p didReceiveResponse:%p (HTTP status %d)", m_handle, connection, r, [r respondsToSelector:@selector(statusCode)] ? [(id)r statusCode] : 0); + LOG(Network, "Handle %p delegate connection:%p didReceiveResponse:%p (HTTP status %d, MIMEType '%s', reported MIMEType '%s')", m_handle, connection, r, [r respondsToSelector:@selector(statusCode)] ? [(id)r statusCode] : 0, [[r MIMEType] UTF8String], [[r _webcore_reportedMIMEType] UTF8String]); if (!m_handle || !m_handle->client()) return; CallbackGuard guard; -#ifndef BUILDING_ON_TIGER - if (!oldNSURLResponseMIMETypeIMP) { - Method nsURLResponseMIMETypeMethod = class_getInstanceMethod(objc_getClass("NSURLResponse"), @selector(MIMEType)); - ASSERT(nsURLResponseMIMETypeMethod); - oldNSURLResponseMIMETypeIMP = method_setImplementation(nsURLResponseMIMETypeMethod, (IMP)webNSURLResponseMIMEType); - } -#endif + swizzleMIMETypeMethodIfNecessary(); if ([m_handle->request().nsURLRequest() _propertyForKey:@"ForceHTMLMIMEType"]) [r _setMIMEType:@"text/html"]; @@ -653,7 +656,7 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen DEFINE_STATIC_LOCAL(const String, wmlExt, (".wml")); if (path.endsWith(wmlExt, false)) { static NSString* defaultMIMETypeString = [(NSString*) defaultMIMEType() retain]; - if ([[r _webcore_MIMEType] isEqualToString:defaultMIMETypeString]) + if ([[r MIMEType] isEqualToString:defaultMIMETypeString]) [r _setMIMEType:@"text/vnd.wap.wml"]; } } @@ -1008,14 +1011,4 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen @end -static NSString *webNSURLResponseMIMEType(id self, SEL _cmd) -{ - ASSERT(oldNSURLResponseMIMETypeIMP); - if (NSString *result = oldNSURLResponseMIMETypeIMP(self, _cmd)) - return result; - - static NSString *defaultMIMETypeString = [(NSString *)defaultMIMEType() retain]; - return defaultMIMETypeString; -} - #endif diff --git a/WebCore/platform/network/mac/ResourceResponseMac.mm b/WebCore/platform/network/mac/ResourceResponseMac.mm index 60a4dc6..9b507e6 100644 --- a/WebCore/platform/network/mac/ResourceResponseMac.mm +++ b/WebCore/platform/network/mac/ResourceResponseMac.mm @@ -69,7 +69,7 @@ void ResourceResponse::platformLazyInit() } m_url = [m_nsResponse.get() URL]; - m_mimeType = [m_nsResponse.get() _webcore_MIMEType]; + m_mimeType = [m_nsResponse.get() MIMEType]; m_expectedContentLength = [m_nsResponse.get() expectedContentLength]; m_textEncodingName = [m_nsResponse.get() textEncodingName]; m_suggestedFilename = [m_nsResponse.get() suggestedFilename]; @@ -86,20 +86,8 @@ void ResourceResponse::platformLazyInit() NSEnumerator *e = [headers keyEnumerator]; while (NSString *name = [e nextObject]) m_httpHeaderFields.set(name, [headers objectForKey:name]); - } else { + } else m_httpStatusCode = 0; - -#ifndef BUILDING_ON_TIGER - // FIXME: This is a work around for <rdar://problem/5230154> (-[NSURLConnection initWithRequest:delegate:] - // is returning incorrect MIME type for local .xhtml files) which is only required in Leopard. - if (m_url.isLocalFile() && m_mimeType == "text/html") { - const String& path = m_url.path(); - DEFINE_STATIC_LOCAL(const String, xhtmlExt, (".xhtml")); - if (path.endsWith(xhtmlExt, false)) - m_mimeType = "application/xhtml+xml"; - } -#endif - } } bool ResourceResponse::platformCompare(const ResourceResponse& a, const ResourceResponse& b) diff --git a/WebCore/platform/network/mac/WebCoreURLResponse.h b/WebCore/platform/network/mac/WebCoreURLResponse.h index a06ab70..0a9a7c4 100644 --- a/WebCore/platform/network/mac/WebCoreURLResponse.h +++ b/WebCore/platform/network/mac/WebCoreURLResponse.h @@ -26,9 +26,8 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// FIXME: This is a workaround for <rdar://problem/5321972> REGRESSION: Plain text document from HTTP server detected -// as application/octet-stream - @interface NSURLResponse (WebCoreURLResponse) -- (NSString *)_webcore_MIMEType; +-(NSString *)_webcore_reportedMIMEType; @end + +void swizzleMIMETypeMethodIfNecessary(); diff --git a/WebCore/platform/network/mac/WebCoreURLResponse.mm b/WebCore/platform/network/mac/WebCoreURLResponse.mm index b8843af..f025769 100644 --- a/WebCore/platform/network/mac/WebCoreURLResponse.mm +++ b/WebCore/platform/network/mac/WebCoreURLResponse.mm @@ -27,10 +27,20 @@ */ #import "config.h" - #import "WebCoreURLResponse.h" +#import "FoundationExtras.h" +#import "MIMETypeRegistry.h" +#import <objc/objc-class.h> +#import <wtf/Assertions.h> +#import <wtf/RetainPtr.h> + #ifndef BUILDING_ON_TIGER +// <rdar://problem/5321972> Plain text document from HTTP server detected as application/octet-stream +// When we sniff a resource as application/octet-stream but the http response headers had "text/plain", +// we have a hard decision to make about which of the two generic MIME types to go with. +// When the URL's extension is a known binary type, we'll go with application/octet-stream. +// Otherwise, we'll trust the server. static NSSet *createBinaryExtensionsSet() { return [[NSSet alloc] initWithObjects: @@ -88,6 +98,7 @@ static NSSet *createBinaryExtensionsSet() @"jpgv", @"jpm", @"kar", + @"kmz", @"lha", @"lrm", @"lzh", @@ -189,33 +200,247 @@ static NSSet *createBinaryExtensionsSet() } #endif -@implementation NSURLResponse (WebCoreURLResponse) +// <rdar://problem/7007389> CoreTypes UTI map is missing 100+ file extensions that GateKeeper knew about +// When we disabled content sniffing for file URLs we caused problems with these 100+ extensions that CoreTypes +// doesn't know about. +// If CoreTypes is ever brought up to speed we can remove this table and associated code. +static NSDictionary *createExtensionToMIMETypeMap() +{ + return [[NSDictionary alloc] initWithObjectsAndKeys: + @"application/postscript", @"ai", + @"text/plain", @"asc", + @"application/x-bcpio", @"bcpio", + @"image/bmp", @"bmp", + @"application/x-netcdf", @"cdf", + @"application/octet-stream", @"class", + @"application/x-gzip", @"cpgz", + @"application/x-cpio", @"cpio", + @"application/mac-compactpro", @"cpt", + @"application/x-csh", @"csh", + @"text/css", @"css", + @"application/x-director", @"dcr", + @"application/x-director", @"dir", + @"application/x-diskcopy", @"dmg", + @"application/octet-stream", @"dms", + @"application/x-dvi", @"dvi", + @"application/x-director", @"dxr", + @"application/postscript", @"eps", + @"text/x-setext", @"etx", + @"application/andrew-inset", @"ez", + @"application/vnd.fdf", @"fdf", + @"application/octet-stream", @"fla", + @"application/x-filemaker", @"fp", + @"application/x-filemaker", @"fp2", + @"application/x-filemaker", @"fp3", + @"application/x-filemaker", @"fp4", + @"application/x-filemaker", @"fp5", + @"application/x-filemaker", @"fp6", + @"application/x-hdf", @"hdf", + @"x-conference/x-cooltalk", @"ice", + @"image/x-icon", @"ico", + @"text/calendar", @"ics", + @"image/ief", @"ief", + @"model/iges", @"iges", + @"model/iges", @"igs", + @"application/octet-stream", @"iso", + @"text/html", @"jhtml", + @"application/x-latex", @"latex", + @"application/octet-stream", @"lha", + @"application/octet-stream", @"lzh", + @"audio/x-mpegurl", @"m3u", + @"audio/x-m4p", @"m4p", + @"image/x-macpaint", @"mac", + @"application/x-troff-man", @"man", + @"application/x-troff-me", @"me", + @"model/mesh", @"mesh", + @"application/vnd.mif", @"mif", + @"video/x-sgi-movie", @"movie", + @"audio/mpeg", @"mp2", + @"audio/mpeg", @"mpga", + @"application/x-troff-ms", @"ms", + @"model/mesh", @"msh", + @"video/vnd.mpegurl", @"mxu", + @"application/x-netcdf", @"nc", + @"application/oda", @"oda", + @"image/x-portable-bitmap", @"pbm", + @"image/x-pcx", @"pcx", + @"chemical/x-pdb", @"pdb", + @"image/x-portable-graymap", @"pgm", + @"application/x-chess-pgn", @"pgn", + @"audio/scpls", @"pls", + @"image/x-portable-anymap", @"pnm", + @"image/x-macpaint", @"pnt", + @"image/x-macpaint", @"pntg", + @"image/x-portable-pixmap", @"ppm", + @"image/x-cmu-raster", @"ras", + @"image/x-rgb", @"rgb", + @"application/x-troff", @"roff", + @"audio/x-pn-realaudio-plugin", @"rpm", + @"text/richtext", @"rtx", + @"text/sgml", @"sgm", + @"text/sgml", @"sgml", + @"application/x-sh", @"sh", + @"application/x-shar", @"shar", + @"model/mesh", @"silo", + @"application/x-koan", @"skd", + @"application/x-koan", @"skm", + @"application/x-koan", @"skp", + @"application/x-koan", @"skt", + @"application/x-diskcopy", @"smi", + @"application/octet-stream", @"so", + @"application/x-futuresplash", @"spl", + @"application/x-wais-source", @"src", + @"application/x-sv4cpio", @"sv4cpio", + @"application/x-sv4crc", @"sv4crc", + @"application/x-shockwave-flash", @"swf", + @"application/x-troff", @"t", + @"image/x-targa", @"targa", + @"application/x-tcl", @"tcl", + @"application/x-tex", @"tex", + @"application/x-texinfo", @"texi", + @"application/x-texinfo", @"texinfo", + @"application/x-gzip", @"tgz", + @"application/x-bittorrent", @"torrent", + @"application/x-troff", @"tr", + @"text/tab-separated-values", @"tsv", + @"application/x-ustar", @"ustar", + @"application/x-cdlink", @"vcd", + @"model/vrml", @"vrml", + @"image/vnd.wap.wbmp", @"wbmp", + @"application/vnd.wap.wbxml", @"wbxml", + @"application/x-webarchive", @"webarchive", + @"application/x-ms-wmd", @"wmd", + @"text/vnd.wap.wml", @"wml", + @"application/vnd.wap.wmlc", @"wmlc", + @"text/vnd.wap.wmlscript", @"wmls", + @"application/vnd.wap.wmlscriptc", @"wmlsc", + @"model/vrml", @"wrl", + @"application/vnd.adobe.xdp+xml", @"xdp", + @"application/vnd.adobe.xfd+xml", @"xfd", + @"application/vnd.adobe.xfdf", @"xfdf", + @"image/x-xpixmap", @"xpm", + @"text/xml", @"xsl", + @"image/x-xwindowdump", @"xwd", + @"chemical/x-xyz", @"xyz", + @"application/x-compress", @"z", + nil + ]; +} -- (NSString *)_webcore_MIMEType +static IMP oldNSURLResponseMIMETypeIMP = 0; +static NSString *webNSURLResponseMIMEType(id, SEL); + +void swizzleMIMETypeMethodIfNecessary() { - NSString *MIMEType = [self MIMEType]; -#ifdef BUILDING_ON_LEOPARD - // Workaround for <rdar://problem/5539824> - if ([MIMEType isEqualToString:@"text/xml"]) - return @"application/xml"; + if (!oldNSURLResponseMIMETypeIMP) { + Method nsURLResponseMIMETypeMethod = class_getInstanceMethod([NSURLResponse class], @selector(MIMEType)); + ASSERT(nsURLResponseMIMETypeMethod); +#ifdef BUILDING_ON_TIGER + oldNSURLResponseMIMETypeIMP = nsURLResponseMIMETypeMethod->method_imp; + nsURLResponseMIMETypeMethod->method_imp = (IMP)webNSURLResponseMIMEType; +#else + oldNSURLResponseMIMETypeIMP = method_setImplementation(nsURLResponseMIMETypeMethod, (IMP)webNSURLResponseMIMEType); #endif - return MIMEType; + } } -@end +static NSString *mimeTypeFromUTITree(CFStringRef uti) +{ + // Check if this UTI has a MIME type. + RetainPtr<CFStringRef> mimeType(AdoptCF, UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)); + if (mimeType) + return (NSString *)HardAutorelease(mimeType.releaseRef()); + + // If not, walk the ancestory of this UTI via its "ConformsTo" tags and return the first MIME type we find. + RetainPtr<CFDictionaryRef> decl(AdoptCF, UTTypeCopyDeclaration(uti)); + if (!decl) + return nil; + CFTypeRef value = CFDictionaryGetValue(decl.get(), kUTTypeConformsToKey); + if (!value) + return nil; + CFTypeID typeID = CFGetTypeID(value); + + if (typeID == CFStringGetTypeID()) + return mimeTypeFromUTITree((CFStringRef)value); -@implementation NSHTTPURLResponse (WebCoreURLResponse) + if (typeID == CFArrayGetTypeID()) { + CFArrayRef newTypes = (CFArrayRef)value; + CFIndex count = CFArrayGetCount(newTypes); + for (CFIndex i = 0; i < count; ++i) { + CFTypeRef object = CFArrayGetValueAtIndex(newTypes, i); + if (CFGetTypeID(object) != CFStringGetTypeID()) + continue; -- (NSString *)_webcore_MIMEType + if (NSString *mimeType = mimeTypeFromUTITree((CFStringRef)object)) + return mimeType; + } + } + + return nil; +} + +static NSString *webNSURLResponseMIMEType(id self, SEL _cmd) { - NSString *MIMEType = [self MIMEType]; + ASSERT(oldNSURLResponseMIMETypeIMP); + NSString *result = oldNSURLResponseMIMETypeIMP(self, _cmd); + +#ifdef BUILDING_ON_TIGER + // When content sniffing is disabled, Tiger's CFNetwork automatically returns application/octet-stream for certain + // extensions even when scouring the UTI maps would end up with a better result, so we'll give a chance for that to happen. + if ([[self URL] isFileURL] && [result caseInsensitiveCompare:@"application/octet-stream"] == NSOrderedSame) + result = nil; +#endif + + if (!result) { + NSURL *url = [self URL]; + if ([url isFileURL]) { + if (NSString *extension = [[url path] pathExtension]) { + // <rdar://problem/7007389> CoreTypes UTI map is missing 100+ file extensions that GateKeeper knew about + // When this radar is resolved, we can remove this file:// url specific code. + static NSDictionary *extensionMap = createExtensionToMIMETypeMap(); + result = [extensionMap objectForKey:[extension lowercaseString]]; + + if (!result) { + // If the Gatekeeper-based map doesn't have a MIME type, we'll try to figure out what it should be by + // looking up the file extension in the UTI maps. + RetainPtr<CFStringRef> uti(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)extension, 0)); + result = mimeTypeFromUTITree(uti.get()); + } + } + } + } + + if (!result) { + static NSString *defaultMIMETypeString = [(NSString *)WebCore::defaultMIMEType() retain]; + result = defaultMIMETypeString; + } + #ifndef BUILDING_ON_TIGER - if ([MIMEType isEqualToString:@"application/octet-stream"] && [[[self allHeaderFields] objectForKey:@"Content-Type"] hasPrefix:@"text/plain"]) { + // <rdar://problem/5321972> Plain text document from HTTP server detected as application/octet-stream + // Make the best guess when deciding between "generic binary" and "generic text" using a table of known binary MIME types. + if ([result isEqualToString:@"application/octet-stream"] && [self respondsToSelector:@selector(allHeaderFields)] && [[[self allHeaderFields] objectForKey:@"Content-Type"] hasPrefix:@"text/plain"]) { static NSSet *binaryExtensions = createBinaryExtensionsSet(); - return [binaryExtensions containsObject:[[[self suggestedFilename] pathExtension] lowercaseString]] ? MIMEType : @"text/plain"; + if (![binaryExtensions containsObject:[[[self suggestedFilename] pathExtension] lowercaseString]]) + result = @"text/plain"; } + +#endif + +#ifdef BUILDING_ON_LEOPARD + // Workaround for <rdar://problem/5539824> + if ([result isEqualToString:@"text/xml"]) + result = @"application/xml"; #endif - return MIMEType; + + return result; +} + +@implementation NSURLResponse (WebCoreURLResponse) + +-(NSString *)_webcore_reportedMIMEType +{ + swizzleMIMETypeMethodIfNecessary(); + return oldNSURLResponseMIMETypeIMP(self, @selector(_webcore_realMIMEType)); } @end diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp index 06b60bf..898e5f4 100644 --- a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp +++ b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp @@ -162,9 +162,21 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode load void QNetworkReplyHandler::setLoadMode(LoadMode mode) { - m_loadMode = mode; - if (m_loadMode == LoadNormal) - sendQueuedItems(); + // https://bugs.webkit.org/show_bug.cgi?id=26556 + // We cannot call sendQueuedItems() from here, because the signal that + // caused us to get into deferred mode, might not be processed yet. + switch (mode) { + case LoadNormal: + m_loadMode = LoadResuming; + emit processQueuedItems(); + break; + case LoadDeferred: + m_loadMode = LoadDeferred; + break; + case LoadResuming: + Q_ASSERT(0); // should never happen + break; + }; } void QNetworkReplyHandler::abort() @@ -194,8 +206,8 @@ QNetworkReply* QNetworkReplyHandler::release() void QNetworkReplyHandler::finish() { - m_shouldFinish = (m_loadMode == LoadDeferred); - if (m_loadMode == LoadDeferred) + m_shouldFinish = (m_loadMode != LoadNormal); + if (m_shouldFinish) return; sendResponseIfNeeded(); @@ -213,9 +225,11 @@ void QNetworkReplyHandler::finish() resetState(); start(); } else if (m_reply->error() != QNetworkReply::NoError - // a web page that returns 403/404 can still have content + // a web page that returns 401/403/404 can still have content && m_reply->error() != QNetworkReply::ContentOperationNotPermittedError - && m_reply->error() != QNetworkReply::ContentNotFoundError) { + && m_reply->error() != QNetworkReply::ContentNotFoundError + && m_reply->error() != QNetworkReply::AuthenticationRequiredError + && m_reply->error() != QNetworkReply::ProxyAuthenticationRequiredError) { QUrl url = m_reply->url(); ResourceError error(url.host(), m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), url.toString(), m_reply->errorString()); @@ -230,8 +244,8 @@ void QNetworkReplyHandler::finish() void QNetworkReplyHandler::sendResponseIfNeeded() { - m_shouldSendResponse = (m_loadMode == LoadDeferred); - if (m_loadMode == LoadDeferred) + m_shouldSendResponse = (m_loadMode != LoadNormal); + if (m_shouldSendResponse) return; if (m_responseSent || !m_resourceHandle) @@ -314,8 +328,8 @@ void QNetworkReplyHandler::sendResponseIfNeeded() void QNetworkReplyHandler::forwardData() { - m_shouldForwardData = (m_loadMode == LoadDeferred); - if (m_loadMode == LoadDeferred) + m_shouldForwardData = (m_loadMode != LoadNormal); + if (m_shouldForwardData) return; sendResponseIfNeeded(); @@ -399,6 +413,8 @@ void QNetworkReplyHandler::start() connect(m_reply, SIGNAL(readyRead()), this, SLOT(forwardData()), Qt::QueuedConnection); + connect(this, SIGNAL(processQueuedItems()), + this, SLOT(sendQueuedItems()), Qt::QueuedConnection); } void QNetworkReplyHandler::resetState() @@ -413,7 +429,9 @@ void QNetworkReplyHandler::resetState() void QNetworkReplyHandler::sendQueuedItems() { - Q_ASSERT(m_loadMode == LoadNormal); + if (m_loadMode != LoadResuming) + return; + m_loadMode = LoadNormal; if (m_shouldStart) start(); diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.h b/WebCore/platform/network/qt/QNetworkReplyHandler.h index 3de6d88..f88ce8a 100644 --- a/WebCore/platform/network/qt/QNetworkReplyHandler.h +++ b/WebCore/platform/network/qt/QNetworkReplyHandler.h @@ -43,7 +43,8 @@ class QNetworkReplyHandler : public QObject public: enum LoadMode { LoadNormal, - LoadDeferred + LoadDeferred, + LoadResuming }; QNetworkReplyHandler(ResourceHandle *handle, LoadMode); @@ -55,15 +56,18 @@ public: QNetworkReply* release(); +signals: + void processQueuedItems(); + private slots: void finish(); void sendResponseIfNeeded(); void forwardData(); + void sendQueuedItems(); private: void start(); void resetState(); - void sendQueuedItems(); QNetworkReply* m_reply; ResourceHandle* m_resourceHandle; diff --git a/WebCore/platform/network/qt/ResourceHandleQt.cpp b/WebCore/platform/network/qt/ResourceHandleQt.cpp index c5816a4..f4c30c9 100644 --- a/WebCore/platform/network/qt/ResourceHandleQt.cpp +++ b/WebCore/platform/network/qt/ResourceHandleQt.cpp @@ -35,6 +35,7 @@ #include "ResourceHandleClient.h" #include "ResourceHandleInternal.h" #include "qwebpage_p.h" +#include "qwebframe_p.h" #include "ChromeClientQt.h" #include "FrameLoaderClientQt.h" #include "Page.h" @@ -42,6 +43,9 @@ #include "NotImplemented.h" +#if QT_VERSION >= 0x040500 +#include <QAbstractNetworkCache> +#endif #include <QCoreApplication> #include <QUrl> #if QT_VERSION >= 0x040400 @@ -73,11 +77,10 @@ private: ResourceResponse m_response; ResourceError m_error; Vector<char> m_data; - bool m_finished; + QEventLoop m_eventLoop; }; WebCoreSynchronousLoader::WebCoreSynchronousLoader() - : m_finished(false) { } @@ -93,19 +96,18 @@ void WebCoreSynchronousLoader::didReceiveData(ResourceHandle*, const char* data, void WebCoreSynchronousLoader::didFinishLoading(ResourceHandle*) { - m_finished = true; + m_eventLoop.exit(); } void WebCoreSynchronousLoader::didFail(ResourceHandle*, const ResourceError& error) { m_error = error; - m_finished = true; + m_eventLoop.exit(); } void WebCoreSynchronousLoader::waitForCompletion() { - while (!m_finished) - QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents); } ResourceHandleInternal::~ResourceHandleInternal() @@ -154,10 +156,28 @@ bool ResourceHandle::loadsBlocked() return false; } -bool ResourceHandle::willLoadFromCache(ResourceRequest& request) +bool ResourceHandle::willLoadFromCache(ResourceRequest& request, Frame* frame) { - notImplemented(); + if (!frame) + return false; + +#if QT_VERSION >= 0x040500 + QNetworkAccessManager* manager = QWebFramePrivate::kit(frame)->page()->networkAccessManager(); + QAbstractNetworkCache* cache = manager->cache(); + + if (!cache) + return false; + + QNetworkCacheMetaData data = cache->metaData(request.url()); + if (data.isValid()) { + request.setCachePolicy(ReturnCacheDataDontLoad); + return true; + } + return false; +#else + return false; +#endif } bool ResourceHandle::supportsBufferedData() diff --git a/WebCore/platform/network/soup/ResourceHandleSoup.cpp b/WebCore/platform/network/soup/ResourceHandleSoup.cpp index 6be13e2..4a22d8a 100644 --- a/WebCore/platform/network/soup/ResourceHandleSoup.cpp +++ b/WebCore/platform/network/soup/ResourceHandleSoup.cpp @@ -6,6 +6,7 @@ * Copyright (C) 2009 Gustavo Noronha Silva <gns@gnome.org> * Copyright (C) 2009 Christian Dywan <christian@imendio.com> * Copyright (C) 2009 Igalia S.L. + * Copyright (C) 2009 John Kjellberg <john.kjellberg@power.alstom.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -55,7 +56,7 @@ namespace WebCore { -class WebCoreSynchronousLoader : public ResourceHandleClient, Noncopyable { +class WebCoreSynchronousLoader : public ResourceHandleClient, public Noncopyable { public: WebCoreSynchronousLoader(ResourceError&, ResourceResponse &, Vector<char>&); ~WebCoreSynchronousLoader(); @@ -118,6 +119,8 @@ void WebCoreSynchronousLoader::run() } static void cleanupGioOperation(ResourceHandleInternal* handle); +static bool startData(ResourceHandle* handle, String urlString); +static bool startGio(ResourceHandle* handle, KURL url); ResourceHandleInternal::~ResourceHandleInternal() { @@ -150,39 +153,7 @@ static void fillResponseFromMessage(SoupMessage* msg, ResourceResponse* response while (soup_message_headers_iter_next(&iter, &name, &value)) response->setHTTPHeaderField(name, value); - GHashTable* contentTypeParameters = 0; - String contentType = soup_message_headers_get_content_type(msg->response_headers, &contentTypeParameters); - - // When the server sends multiple Content-Type headers, soup will - // give us their values concatenated with commas as a separator; - // we need to handle this and use only one value. We use the first - // value, and add all the parameters, afterwards, if any. - Vector<String> contentTypes; - contentType.split(',', true, contentTypes); - contentType = contentTypes[0]; - - if (contentTypeParameters) { - GString* parametersString = g_string_new(0); - GHashTableIter hashTableIter; - const char* hashKey; - const char* hashValue; - - g_hash_table_iter_init(&hashTableIter, contentTypeParameters); - while (g_hash_table_iter_next(&hashTableIter, reinterpret_cast<void**>(const_cast<char**>(&hashKey)), reinterpret_cast<void**>(const_cast<char**>(&hashValue)))) { - // Work-around bug in soup which causes a crash; - // See http://bugzilla.gnome.org/show_bug.cgi?id=577728 - if (!hashValue) - hashValue = ""; - - g_string_append(parametersString, "; "); - soup_header_g_string_append_param(parametersString, hashKey, hashValue); - } - contentType += String(parametersString->str); - - g_string_free(parametersString, true); - g_hash_table_destroy(contentTypeParameters); - } - + String contentType = soup_message_headers_get_one(msg->response_headers, "Content-Type"); response->setMimeType(extractMIMETypeFromMediaType(contentType)); char* uri = soup_uri_to_string(soup_message_get_uri(msg), false); @@ -211,15 +182,6 @@ static void restartedCallback(SoupMessage* msg, gpointer data) g_free(uri); KURL newURL = KURL(handle->request().url(), location); - // FIXME: This is needed because some servers use broken URIs in - // their Location header, when redirecting, such as URIs with - // white spaces instead of %20; this should be fixed in soup, in - // the future, and this work-around removed. - // See http://bugzilla.gnome.org/show_bug.cgi?id=575378. - SoupURI* soup_uri = soup_uri_new(newURL.string().utf8().data()); - soup_message_set_uri(msg, soup_uri); - soup_uri_free(soup_uri); - ResourceRequest request = handle->request(); ResourceResponse response; request.setURL(newURL); @@ -242,21 +204,38 @@ static void gotHeadersCallback(SoupMessage* msg, gpointer data) // we got, when we finish downloading. soup_message_body_set_accumulate(msg->response_body, FALSE); + if (msg->status_code == SOUP_STATUS_NOT_MODIFIED) { + RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data); + if (!handle) + return; + ResourceHandleInternal* d = handle->getInternal(); + if (d->m_cancelled) + return; + ResourceHandleClient* client = handle->client(); + if (!client) + return; + + fillResponseFromMessage(msg, &d->m_response); + client->didReceiveResponse(handle.get(), d->m_response); + } +} + +static void contentSniffedCallback(SoupMessage* msg, const char* sniffedType, GHashTable *params, gpointer data) +{ + if (sniffedType) { + const char* officialType = soup_message_headers_get_one(msg->response_headers, "Content-Type"); + + if (!officialType || strcmp(officialType, sniffedType)) + soup_message_headers_set_content_type(msg->response_headers, sniffedType, params); + } + // The 304 status code (SOUP_STATUS_NOT_MODIFIED) needs to be fed // into WebCore, as opposed to other kinds of redirections, which // are handled by soup directly, so we special-case it here and in // gotChunk. if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code) - || (SOUP_STATUS_IS_REDIRECTION(msg->status_code) && (msg->status_code != SOUP_STATUS_NOT_MODIFIED))) - return; - - // We still don't know anything about Content-Type, so we will try - // sniffing the contents of the file, and then report that we got - // headers; we will not do content sniffing for 304 responses, - // though, since they do not have a body. - const char* contentType = soup_message_headers_get_content_type(msg->response_headers, NULL); - if ((msg->status_code != SOUP_STATUS_NOT_MODIFIED) - && (!contentType || !g_ascii_strcasecmp(contentType, "text/plain"))) + || (SOUP_STATUS_IS_REDIRECTION(msg->status_code) && (msg->status_code != SOUP_STATUS_NOT_MODIFIED)) + || (msg->status_code == SOUP_STATUS_UNAUTHORIZED)) return; RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data); @@ -270,7 +249,6 @@ static void gotHeadersCallback(SoupMessage* msg, gpointer data) return; fillResponseFromMessage(msg, &d->m_response); - d->m_reportedHeaders = true; client->didReceiveResponse(handle.get(), d->m_response); } @@ -291,21 +269,6 @@ static void gotChunkCallback(SoupMessage* msg, SoupBuffer* chunk, gpointer data) if (!client) return; - if (!d->m_reportedHeaders) { - gboolean uncertain; - char* contentType = g_content_type_guess(d->m_request.url().lastPathComponent().utf8().data(), reinterpret_cast<const guchar*>(chunk->data), chunk->length, &uncertain); - soup_message_headers_set_content_type(msg->response_headers, contentType, NULL); - g_free(contentType); - - fillResponseFromMessage(msg, &d->m_response); - client->didReceiveResponse(handle.get(), d->m_response); - d->m_reportedHeaders = true; - - // the didReceiveResponse call above may have cancelled the request - if (d->m_cancelled) - return; - } - client->didReceiveData(handle.get(), chunk->data, chunk->length, false); } @@ -328,10 +291,12 @@ static void finishedCallback(SoupSession *session, SoupMessage* msg, gpointer da return; if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code)) { + char* uri = soup_uri_to_string(soup_message_get_uri(msg), false); ResourceError error(g_quark_to_string(SOUP_HTTP_ERROR), msg->status_code, - soup_uri_to_string(soup_message_get_uri(msg), false), + uri, String::fromUTF8(msg->reason_phrase)); + g_free(uri); client->didFail(handle.get(), error); return; } @@ -428,13 +393,15 @@ static gboolean parseDataUrl(gpointer callback_data) return false; } -bool ResourceHandle::startData(String urlString) +static bool startData(ResourceHandle* handle, String urlString) { - ResourceHandleInternal* d = this->getInternal(); + ASSERT(handle); + + ResourceHandleInternal* d = handle->getInternal(); // If parseDataUrl is called synchronously the job is not yet effectively started // and webkit won't never know that the data has been parsed even didFinishLoading is called. - d->m_idleHandler = g_idle_add(parseDataUrl, this); + d->m_idleHandler = g_idle_add(parseDataUrl, handle); return true; } @@ -463,17 +430,31 @@ static void ensureSessionIsInitialized(SoupSession* session) g_object_set_data(G_OBJECT(session), "webkit-init", reinterpret_cast<void*>(0xdeadbeef)); } -bool ResourceHandle::startHttp(String urlString) +static bool startHttp(ResourceHandle* handle, String urlString) { - SoupSession* session = defaultSession(); + ASSERT(handle); + + SoupSession* session = handle->defaultSession(); ensureSessionIsInitialized(session); - d->m_msg = request().toSoupMessage(); - g_signal_connect(d->m_msg, "restarted", G_CALLBACK(restartedCallback), this); - g_signal_connect(d->m_msg, "got-headers", G_CALLBACK(gotHeadersCallback), this); - g_signal_connect(d->m_msg, "got-chunk", G_CALLBACK(gotChunkCallback), this); + ResourceHandleInternal* d = handle->getInternal(); + + d->m_msg = handle->request().toSoupMessage(); + if (!d->m_msg) { + ResourceError resourceError(g_quark_to_string(SOUP_HTTP_ERROR), + SOUP_STATUS_MALFORMED, + urlString, + handle->request().httpMethod()); + d->client()->didFail(handle, resourceError); + return false; + } + + g_signal_connect(d->m_msg, "restarted", G_CALLBACK(restartedCallback), handle); + g_signal_connect(d->m_msg, "got-headers", G_CALLBACK(gotHeadersCallback), handle); + g_signal_connect(d->m_msg, "content-sniffed", G_CALLBACK(contentSniffedCallback), handle); + g_signal_connect(d->m_msg, "got-chunk", G_CALLBACK(gotChunkCallback), handle); - g_object_set_data(G_OBJECT(d->m_msg), "resourceHandle", reinterpret_cast<void*>(this)); + g_object_set_data(G_OBJECT(d->m_msg), "resourceHandle", reinterpret_cast<void*>(handle)); FormData* httpBody = d->m_request.httpBody(); if (httpBody && !httpBody->isEmpty()) { @@ -516,10 +497,10 @@ bool ResourceHandle::startHttp(String urlString) String::fromUTF8(error->message)); g_error_free(error); - d->client()->didFail(this, resourceError); + d->client()->didFail(handle, resourceError); g_signal_handlers_disconnect_matched(d->m_msg, G_SIGNAL_MATCH_DATA, - 0, 0, 0, 0, this); + 0, 0, 0, 0, handle); g_object_unref(d->m_msg); d->m_msg = 0; @@ -528,7 +509,12 @@ bool ResourceHandle::startHttp(String urlString) SoupBuffer* soupBuffer = soup_buffer_new_with_owner(g_mapped_file_get_contents(fileMapping), g_mapped_file_get_length(fileMapping), - fileMapping, reinterpret_cast<GDestroyNotify>(g_mapped_file_free)); + fileMapping, +#if GLIB_CHECK_VERSION(2, 21, 3) + reinterpret_cast<GDestroyNotify>(g_mapped_file_unref)); +#else + reinterpret_cast<GDestroyNotify>(g_mapped_file_free)); +#endif soup_message_body_append_buffer(d->m_msg->request_body, soupBuffer); soup_buffer_free(soupBuffer); } @@ -537,7 +523,7 @@ bool ResourceHandle::startHttp(String urlString) } // balanced by a deref() in finishedCallback, which should always run - ref(); + handle->ref(); // FIXME: For now, we cannot accept content encoded in anything // other than identity, so force servers to do it our way. When @@ -549,7 +535,7 @@ bool ResourceHandle::startHttp(String urlString) // keep our own ref, because after queueing the message, the // session owns the initial reference. g_object_ref(d->m_msg); - soup_session_queue_message(session, d->m_msg, finishedCallback, this); + soup_session_queue_message(session, d->m_msg, finishedCallback, handle); return true; } @@ -574,14 +560,14 @@ bool ResourceHandle::start(Frame* frame) d->m_frame = frame; if (equalIgnoringCase(protocol, "data")) - return startData(urlString); + return startData(this, urlString); - if ((equalIgnoringCase(protocol, "http") || equalIgnoringCase(protocol, "https")) && SOUP_URI_VALID_FOR_HTTP(soup_uri_new(urlString.utf8().data()))) - return startHttp(urlString); + if (equalIgnoringCase(protocol, "http") || equalIgnoringCase(protocol, "https")) + return startHttp(this, urlString); if (equalIgnoringCase(protocol, "file") || equalIgnoringCase(protocol, "ftp") || equalIgnoringCase(protocol, "ftps")) // FIXME: should we be doing any other protocols here? - return startGio(url); + return startGio(this, url); // Error must not be reported immediately this->scheduleFailure(InvalidURLFailure); @@ -620,7 +606,7 @@ bool ResourceHandle::loadsBlocked() return false; } -bool ResourceHandle::willLoadFromCache(ResourceRequest&) +bool ResourceHandle::willLoadFromCache(ResourceRequest&, Frame*) { // Not having this function means that we'll ask the user about re-posting a form // even when we go back to a page that's still in the cache. @@ -697,10 +683,12 @@ static void readCallback(GObject* source, GAsyncResult* res, gpointer) gssize bytesRead = g_input_stream_read_finish(d->m_inputStream, res, &error); if (error) { + char* uri = g_file_get_uri(d->m_gfile); ResourceError resourceError(g_quark_to_string(G_IO_ERROR), error->code, - g_file_get_uri(d->m_gfile), + uri, error ? String::fromUTF8(error->message) : String()); + g_free(uri); g_error_free(error); cleanupGioOperation(d); client->didFail(handle.get(), resourceError); @@ -743,11 +731,12 @@ static void openCallback(GObject* source, GAsyncResult* res, gpointer) GError *error = 0; GFileInputStream* in = g_file_read_finish(G_FILE(source), res, &error); if (error) { + char* uri = g_file_get_uri(d->m_gfile); ResourceError resourceError(g_quark_to_string(G_IO_ERROR), error->code, - g_file_get_uri(d->m_gfile), + uri, error ? String::fromUTF8(error->message) : String()); - + g_free(uri); g_error_free(error); cleanupGioOperation(d); client->didFail(handle, resourceError); @@ -794,10 +783,12 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer) // server (and then keep track of the fact that we mounted it, // and set a timeout to unmount it later after it's been idle // for a while). + char* uri = g_file_get_uri(d->m_gfile); ResourceError resourceError(g_quark_to_string(G_IO_ERROR), error->code, - g_file_get_uri(d->m_gfile), + uri, error ? String::fromUTF8(error->message) : String()); + g_free(uri); g_error_free(error); cleanupGioOperation(d); client->didFail(handle, resourceError); @@ -807,10 +798,12 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer) if (g_file_info_get_file_type(info) != G_FILE_TYPE_REGULAR) { // FIXME: what if the URI points to a directory? Should we // generate a listing? How? What do other backends do here? + char* uri = g_file_get_uri(d->m_gfile); ResourceError resourceError(g_quark_to_string(G_IO_ERROR), G_IO_ERROR_FAILED, - g_file_get_uri(d->m_gfile), + uri, String()); + g_free(uri); cleanupGioOperation(d); client->didFail(handle, resourceError); return; @@ -828,21 +821,24 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer) g_file_read_async(d->m_gfile, G_PRIORITY_DEFAULT, d->m_cancellable, openCallback, 0); } - -bool ResourceHandle::startGio(KURL url) +static bool startGio(ResourceHandle* handle, KURL url) { - if (request().httpMethod() != "GET" && request().httpMethod() != "POST") { + ASSERT(handle); + + ResourceHandleInternal* d = handle->getInternal(); + + if (handle->request().httpMethod() != "GET" && handle->request().httpMethod() != "POST") { ResourceError error(g_quark_to_string(SOUP_HTTP_ERROR), SOUP_STATUS_METHOD_NOT_ALLOWED, - url.string(), request().httpMethod()); - d->client()->didFail(this, error); + url.string(), handle->request().httpMethod()); + d->client()->didFail(handle, error); return false; } // GIO doesn't know how to handle refs and queries, so remove them // TODO: use KURL.fileSystemPath after KURLGtk and FileSystemGtk are // using GIO internally, and providing URIs instead of file paths - url.removeRef(); + url.removeFragmentIdentifier(); url.setQuery(String()); url.setPort(0); @@ -855,7 +851,7 @@ bool ResourceHandle::startGio(KURL url) else #endif d->m_gfile = g_file_new_for_uri(url.string().utf8().data()); - g_object_set_data(G_OBJECT(d->m_gfile), "webkit-resource", this); + g_object_set_data(G_OBJECT(d->m_gfile), "webkit-resource", handle); d->m_cancellable = g_cancellable_new(); g_file_query_info_async(d->m_gfile, G_FILE_ATTRIBUTE_STANDARD_TYPE "," |