WebCore:
authormjs <mjs@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 11 Dec 2003 04:55:47 +0000 (04:55 +0000)
committermjs <mjs@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 11 Dec 2003 04:55:47 +0000 (04:55 +0000)
        Reviewed by Richard.

<rdar://problem/3487160>: Implement synchronous loading for XMLHttpRequest

* khtml/ecma/xmlhttprequest.cpp:
        (KJS::XMLHttpRequest::XMLHttpRequest):
        (KJS::XMLHttpRequest::send):
        (KJS::XMLHttpRequest::abort):
        (KJS::XMLHttpRequest::processSyncLoadResults):
        (KJS::XMLHttpRequest::slotRedirection):
        (KJS::XMLHttpRequest::slotData):
        * khtml/ecma/xmlhttprequest.h:
        * kwq/KWQLoader.h:
        * kwq/KWQLoader.mm:
        (KWQHeaderStringFromDictionary):
        (KWQServeSynchronousRequest):
        (KWQResponseHeaderString):
        * kwq/WebCoreBridge.h:

WebKit:

        Reviewed by Richard.

WebKit part of fix for:

<rdar://problem/3487160>: Implement synchronous loading for XMLHttpRequest

        * WebCoreSupport.subproj/WebBridge.m:
        (-[WebBridge syncLoadResourceWithURL:customHeaders:postData:finalURL:responseHeaders:statusCode:]):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@5754 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog-2005-08-23
WebCore/khtml/ecma/xmlhttprequest.cpp
WebCore/khtml/ecma/xmlhttprequest.h
WebCore/kwq/KWQLoader.h
WebCore/kwq/KWQLoader.mm
WebCore/kwq/WebCoreBridge.h
WebKit/ChangeLog
WebKit/WebCoreSupport.subproj/WebBridge.m

index 025d5fe..8aba3cd 100644 (file)
@@ -1,3 +1,24 @@
+2003-12-10  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Richard.
+
+       <rdar://problem/3487160>: Implement synchronous loading for XMLHttpRequest
+        
+       * khtml/ecma/xmlhttprequest.cpp:
+        (KJS::XMLHttpRequest::XMLHttpRequest):
+        (KJS::XMLHttpRequest::send):
+        (KJS::XMLHttpRequest::abort):
+        (KJS::XMLHttpRequest::processSyncLoadResults):
+        (KJS::XMLHttpRequest::slotRedirection):
+        (KJS::XMLHttpRequest::slotData):
+        * khtml/ecma/xmlhttprequest.h:
+        * kwq/KWQLoader.h:
+        * kwq/KWQLoader.mm:
+        (KWQHeaderStringFromDictionary):
+        (KWQServeSynchronousRequest):
+        (KWQResponseHeaderString):
+        * kwq/WebCoreBridge.h:
+
 2003-12-10  Darin Adler  <darin@apple.com>
 
         Reviewed by Maciej.
index 2349369..1e119c5 100644 (file)
@@ -211,7 +211,8 @@ XMLHttpRequest::XMLHttpRequest(ExecState *exec, const DOM::Document &d)
     onReadyStateChangeListener(0),
     onLoadListener(0),
     decoder(0),
-    createdDocument(false)
+    createdDocument(false),
+    aborted(false)
 {
 }
 
@@ -275,6 +276,14 @@ void XMLHttpRequest::open(const QString& _method, const KURL& _url, bool _async)
 
 void XMLHttpRequest::send(const QString& _body)
 {
+  aborted = false;
+
+#if !APPLE_CHANGES
+  if (!async) {
+    return;
+  }
+#endif
+
   if (method.lower() == "post" && (url.protocol().lower() == "http" || url.protocol().lower() == "https") ) {
       // FIXME: determine post encoding correctly by looking in headers for charset
       job = KIO::http_post( url, QCString(_body.utf8()), false );
@@ -287,6 +296,19 @@ void XMLHttpRequest::send(const QString& _body)
     job->addMetaData("customHTTPHeader", requestHeaders);
   }
 
+#if APPLE_CHANGES
+  if (!async) {
+    QByteArray data;
+    KURL finalURL;
+    QString headers;
+
+    data = KWQServeSynchronousRequest(khtml::Cache::loader(), doc->docLoader(), job, finalURL, headers);
+    job = 0;
+    processSyncLoadResults(data, finalURL, headers);
+    return;
+  }
+#endif
+
   qObject->connect( job, SIGNAL( result( KIO::Job* ) ),
                    SLOT( slotFinished( KIO::Job* ) ) );
 #if APPLE_CHANGES
@@ -312,6 +334,7 @@ void XMLHttpRequest::abort()
     job->kill();
     job = 0;
   }
+  aborted = true;
 }
 
 void XMLHttpRequest::setRequestHeader(const QString& name, const QString &value)
@@ -404,7 +427,34 @@ Value XMLHttpRequest::getStatusText() const
   
   return String(firstLine);
 }
-   
+
+#if APPLE_CHANGES   
+void XMLHttpRequest::processSyncLoadResults(const QByteArray &data, const KURL &finalURL, const QString &headers)
+{
+  if (!urlMatchesDocumentDomain(finalURL)) {
+    abort();
+    return;
+  }
+  
+  responseHeaders = headers;
+  changeState(Loaded);
+  if (aborted) {
+    return;
+  }
+  
+  const char *bytes = (const char *)data.data();
+  int len = (int)data.size();
+
+  slotData(0, bytes, len);
+
+  if (aborted) {
+    return;
+  }
+
+  slotFinished(0);
+}
+#endif
+
 void XMLHttpRequest::slotFinished(KIO::Job *)
 {
   if (decoder) {
@@ -423,8 +473,7 @@ void XMLHttpRequest::slotFinished(KIO::Job *)
 void XMLHttpRequest::slotRedirection(KIO::Job*, const KURL& url)
 {
   if (!urlMatchesDocumentDomain(url)) {
-    job->kill();
-    job = 0;
+    abort();
   }
 }
 
@@ -462,7 +511,7 @@ void XMLHttpRequest::slotData(KIO::Job*, const QByteArray &_data)
 
   response += decoded;
 
-  if (job != 0) {
+  if (!aborted) {
     changeState(Interactive);
   }
 }
index 6351699..cab43d3 100644 (file)
@@ -80,6 +80,10 @@ namespace KJS {
     void slotFinished( KIO::Job* );
     void slotRedirection( KIO::Job*, const KURL& );
 
+#if APPLE_CHANGES
+    void processSyncLoadResults(const QByteArray &data, const KURL &finalURL, const QString &headers);
+#endif
+
     void open(const QString& _method, const KURL& _url, bool _async);
     void send(const QString& _body);
     void abort();
@@ -109,6 +113,8 @@ namespace KJS {
     QString response;
     mutable bool createdDocument;
     mutable DOM::Document responseXML;
+
+    bool aborted;
   };
 
 
index b0aabf8..0653d8b 100644 (file)
@@ -24,6 +24,7 @@
  */
 
 #include "KWQSignal.h"
+#include "QCString.h"
 
 namespace khtml {
     class CachedObject;
@@ -38,6 +39,9 @@ namespace KIO {
 
 bool KWQServeRequest(khtml::Loader *, khtml::Request *, KIO::TransferJob *);
 bool KWQServeRequest(khtml::Loader *, khtml::DocLoader *, KIO::TransferJob *);
+
+QByteArray KWQServeSynchronousRequest(khtml::Loader *, khtml::DocLoader *, KIO::TransferJob *, KURL &finalURL, QString &headers);
+
 void KWQCheckCacheObjectStatus(khtml::DocLoader *, khtml::CachedObject *);
 bool KWQCheckIfReloading(khtml::DocLoader *loader);
 void KWQRetainResponse(void *response);
index 49361bd..07fa3d8 100644 (file)
@@ -137,6 +137,74 @@ bool KWQServeRequest(Loader *loader, DocLoader *docLoader, TransferJob *job)
     return true;
 }
 
+static NSString *KWQHeaderStringFromDictionary(NSDictionary *headers, int statusCode)
+{
+    NSMutableString *headerString = [[NSMutableString alloc] init];
+    [headerString appendString:[NSString stringWithFormat:@"HTTP/1.0 %d OK\n", statusCode]];
+    
+    NSEnumerator *e = [headers keyEnumerator];
+    NSString *key;
+    
+    bool first = true;
+    
+    while ((key = [e nextObject]) != nil) {
+       if (first) {
+           first = false;
+       } else {
+           [headerString appendString:@"\n"];
+       }
+       [headerString appendString:key];
+       [headerString appendString:@": "];
+       [headerString appendString:[headers objectForKey:key]];
+    }
+       
+    return headerString;
+}
+
+QByteArray KWQServeSynchronousRequest(Loader *loader, DocLoader *docLoader, TransferJob *job, KURL &finalURL, QString &responseHeaders)
+{
+    KWQKHTMLPart *part = static_cast<KWQKHTMLPart *>(docLoader->part());
+    WebCoreBridge *bridge = part->bridge();
+
+    part->didTellBridgeAboutLoad(job->url().url());
+
+    KWQ_BLOCK_EXCEPTIONS;
+
+    NSDictionary *headerDict = nil;
+    QString headerString = job->queryMetaData("customHTTPHeader");
+
+    if (!headerString.isEmpty()) {
+       headerDict = [[NSDictionary alloc] _webcore_initWithHeaderString:headerString.getNSString()];
+    }
+
+    NSData *postData = nil;
+    
+
+    if (job->method() == "POST") {
+       postData = [NSData dataWithBytesNoCopy:job->postData().data() length:job->postData().size() freeWhenDone:NO];
+    }
+
+    NSURL *finalNSURL = nil;
+    NSDictionary *responseHeaderDict = nil;
+    int statusCode = 0;
+    NSData *resultData = [bridge syncLoadResourceWithURL:job->url().getNSURL() customHeaders:headerDict postData:postData finalURL:&finalNSURL responseHeaders:&responseHeaderDict statusCode:&statusCode];
+    
+    job->kill();
+
+    finalURL = finalNSURL;
+    responseHeaders = QString::fromNSString(KWQHeaderStringFromDictionary(responseHeaderDict, statusCode));
+
+    QByteArray results([resultData length]);
+
+    memcpy( results.data(), [resultData bytes], [resultData length] );
+
+    return results;
+
+    KWQ_UNBLOCK_EXCEPTIONS;
+
+    return QByteArray();
+}
+
 int KWQNumberOfPendingOrLoadingRequests(khtml::DocLoader *dl)
 {
     return Cache::loader()->numRequests(dl);
@@ -218,27 +286,9 @@ void *KWQResponseHeaderString(void *response)
     NSURLResponse *nsResponse = (NSURLResponse *)response;
     if ([nsResponse isKindOfClass:[NSHTTPURLResponse class]]) {
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)nsResponse;
-       NSMutableString *headerString = [[NSMutableString alloc] init];
-       [headerString appendString:[NSString stringWithFormat:@"HTTP/1.0 %d OK\n", [httpResponse statusCode]]];
        NSDictionary *headers = [httpResponse allHeaderFields];
 
-       NSEnumerator *e = [headers keyEnumerator];
-       NSString *key;
-       
-       bool first = true;
-       
-       while ((key = [e nextObject]) != nil) {
-           if (first) {
-               first = false;
-           } else {
-               [headerString appendString:@"\n"];
-           }
-           [headerString appendString:key];
-           [headerString appendString:@": "];
-           [headerString appendString:[headers objectForKey:key]];
-       }
-       
-       return headerString;
+       return KWQHeaderStringFromDictionary(headers, [httpResponse statusCode]);
     }
 
     KWQ_UNBLOCK_EXCEPTIONS;
index 10836d5..76b948c 100644 (file)
@@ -299,6 +299,9 @@ typedef enum {
 - (id <WebCoreResourceHandle>)startLoadingResource:(id <WebCoreResourceLoader>)loader withURL:(NSURL *)URL customHeaders:(NSDictionary *)customHeaders;
 - (id <WebCoreResourceHandle>)startLoadingResource:(id <WebCoreResourceLoader>)loader withURL:(NSURL *)URL customHeaders:(NSDictionary *)customHeaders postData:(NSData *)data;
 - (void)objectLoadedFromCacheWithURL:(NSURL *)URL response:(id)response size:(unsigned)bytes;
+
+- (NSData *)syncLoadResourceWithURL:(NSURL *)URL customHeaders:(NSDictionary *)requestHeaders postData:(NSData *)postData finalURL:(NSURL **)finalNSURL responseHeaders:(NSDictionary **)responseHeaderDict statusCode:(int *)statusCode;
+
 - (BOOL)isReloading;
 
 - (void)reportClientRedirectToURL:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction;
index 4124405..fb5feb0 100644 (file)
@@ -1,3 +1,14 @@
+2003-12-10  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Richard.
+
+       WebKit part of fix for:
+
+       <rdar://problem/3487160>: Implement synchronous loading for XMLHttpRequest
+
+        * WebCoreSupport.subproj/WebBridge.m:
+        (-[WebBridge syncLoadResourceWithURL:customHeaders:postData:finalURL:responseHeaders:statusCode:]):
+
 2003-12-10  Richard Williamson   <rjw@apple.com>
 
        Added method to get to the bridge from a view.  This is
index da4cfa8..036fba2 100644 (file)
     [request release];
 }
 
+- (NSData *)syncLoadResourceWithURL:(NSURL *)URL customHeaders:(NSDictionary *)requestHeaders postData:(NSData *)postData finalURL:(NSURL **)finalURL responseHeaders:(NSDictionary **)responseHeaderDict statusCode:(int *)statusCode
+{
+    NSMutableURLRequest *newRequest = [[NSMutableURLRequest alloc] initWithURL:URL];
+
+    if (postData) {
+       [newRequest setHTTPMethod:@"POST"];
+       [newRequest setHTTPBody:postData];
+    }
+
+    NSEnumerator *e = [requestHeaders keyEnumerator];
+    NSString *key;
+    while ((key = (NSString *)[e nextObject]) != nil) {
+       [newRequest addValue:[requestHeaders objectForKey:key] forHTTPHeaderField:key];
+    }
+
+    [newRequest setCachePolicy:[[[self dataSource] request] cachePolicy]];
+    [newRequest setHTTPReferrer:[self referrer]];
+    
+    WebView *webView = [_frame webView];
+    [newRequest setMainDocumentURL:[[[[webView mainFrame] dataSource] request] URL]];
+    [newRequest setHTTPUserAgent:[webView userAgentForURL:[newRequest URL]]];
+
+    NSURLResponse *response = nil;
+    NSError *error = nil;
+    NSData *result = [NSURLConnection sendSynchronousRequest:newRequest returningResponse:&response error:&error];
+
+    if (error == nil) {
+       *finalURL = [response URL];
+       if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
+           NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; 
+           *responseHeaderDict = [httpResponse allHeaderFields];
+           *statusCode = [httpResponse statusCode];
+       } else {
+           *responseHeaderDict = [NSDictionary dictionary];
+           *statusCode = 200;
+       }
+    } else {
+       *finalURL = URL;
+       *responseHeaderDict = [NSDictionary dictionary];
+       *statusCode = 404;
+    }
+
+    // notify the delegates
+    [self objectLoadedFromCacheWithURL:URL response:response size:[result length]];
+
+    return result;
+}
+
 - (BOOL)isReloading
 {
     return [[[self dataSource] request] cachePolicy] == NSURLRequestReloadIgnoringCacheData;