diff --git a/Foundation/CPURLConnection.j b/Foundation/CPURLConnection.j index 88a1afbf8..5a4f09f26 100644 --- a/Foundation/CPURLConnection.j +++ b/Foundation/CPURLConnection.j @@ -76,13 +76,12 @@ var CPURLConnectionDelegate = nil; */ @implementation CPURLConnection : CPObject { - CPURLRequest _request; + CPURLRequest _originalRequest @accessors(readonly, getter=originalRequest); + CPURLRequest _request @accessors(readonly, getter=currentRequest); id _delegate; BOOL _isCanceled; BOOL _isLocalFileConnection; - BOOL _withCredentials @accessors(property=withCredentials); - HTTPRequest _HTTPRequest; } @@ -99,25 +98,12 @@ var CPURLConnectionDelegate = nil; @return the data at the URL or \c nil if there was an error */ + (CPData)sendSynchronousRequest:(CPURLRequest)aRequest returningResponse:(/*{*/CPURLResponse/*}*/)aURLResponse -{ - var cfHTTPRequest = new CFHTTPRequest(); - - return [CPURLConnection _sendSynchronousRequest:aRequest returningResponse:aURLResponse withCFHTTPRequest:cfHTTPRequest]; -} - -+ (CPData)sendSynchronousRequest:(CPURLRequest)aRequest returningResponse:(/*{*/CPURLResponse/*}*/)aURLResponse withCredentials:(BOOL)withCredentials -{ - var cfHTTPRequest = new CFHTTPRequest(); - - cfHTTPRequest.setWithCredentials(withCredentials); - - return [CPURLConnection _sendSynchronousRequest:aRequest returningResponse:aURLResponse withCFHTTPRequest:cfHTTPRequest]; -} - -+ (CPData)_sendSynchronousRequest:(CPURLRequest)aRequest returningResponse:(/*{*/CPURLResponse/*}*/)aURLResponse withCFHTTPRequest:(CFHTTPRequest)aCFHTTPRequest { try { + var aCFHTTPRequest = new CFHTTPRequest(); + aCFHTTPRequest.setWithCredentials([aRequest withCredentials]); + aCFHTTPRequest.open([aRequest HTTPMethod], [[aRequest URL] absoluteString], NO); var fields = [aRequest allHTTPHeaderFields], @@ -152,17 +138,6 @@ var CPURLConnectionDelegate = nil; return [[self alloc] initWithRequest:aRequest delegate:aDelegate]; } -//overloaded method that allows user to set _withCredentials -+ (CPURLConnection)connectionWithRequest:(CPURLRequest)aRequest delegate:(id)aDelegate withCredentials:(BOOL)withCredentials -{ - var connection = [[self alloc] initWithRequest:aRequest delegate:aDelegate startImmediately:NO]; - - [connection setWithCredentials:withCredentials]; - [connection start]; - - return connection; -} - /* Default class initializer. Use one of the class methods instead. @param aRequest contains the URL to contact @@ -177,9 +152,9 @@ var CPURLConnectionDelegate = nil; if (self) { _request = aRequest; + _originalRequest = [aRequest copy]; _delegate = aDelegate; _isCanceled = NO; - _withCredentials = NO; var URL = [_request URL], scheme = [URL scheme]; @@ -191,6 +166,7 @@ var CPURLConnectionDelegate = nil; (window.location.protocol === "file:" || window.location.protocol === "app:")); _HTTPRequest = new CFHTTPRequest(); + _HTTPRequest.setWithCredentials([aRequest withCredentials]); if (shouldStartImmediately) [self start]; @@ -219,8 +195,6 @@ var CPURLConnectionDelegate = nil; { _isCanceled = NO; - _HTTPRequest.setWithCredentials(_withCredentials); - try { _HTTPRequest.open([_request HTTPMethod], [[_request URL] absoluteString], YES); diff --git a/Foundation/CPURLRequest.j b/Foundation/CPURLRequest.j index 703c81bcc..8d6a39e3b 100644 --- a/Foundation/CPURLRequest.j +++ b/Foundation/CPURLRequest.j @@ -35,12 +35,14 @@ */ @implementation CPURLRequest : CPObject { - CPURL _URL; + CPURL _URL @accessors(property=URL); // FIXME: this should be CPData - CPString _HTTPBody; - CPString _HTTPMethod; - CPDictionary _HTTPHeaderFields; + CPString _HTTPBody @accessors(property=HTTPBody); + CPString _HTTPMethod @accessors(property=HTTPMethod); + BOOL _withCredentials @accessors(property=withCredentials); + + CPDictionary _HTTPHeaderFields @accessors(readonly, getter=allHTTPHeaderFields); } /*! @@ -78,6 +80,7 @@ _HTTPBody = @""; _HTTPMethod = @"GET"; _HTTPHeaderFields = @{}; + _withCredentials = NO; [self setValue:"Thu, 01 Jan 1970 00:00:00 GMT" forHTTPHeaderField:"If-Modified-Since"]; [self setValue:"no-cache" forHTTPHeaderField:"Cache-Control"]; @@ -87,14 +90,6 @@ return self; } -/*! - Returns the request URL -*/ -- (CPURL)URL -{ - return _URL; -} - /*! Sets the URL for this request. @param aURL the new URL @@ -105,48 +100,6 @@ _URL = new CFURL(aURL); } -/*! - Sets the HTTP body for this request - @param anHTTPBody the new HTTP body -*/ -- (void)setHTTPBody:(CPString)anHTTPBody -{ - _HTTPBody = anHTTPBody; -} - -/*! - Returns the request's http body. -*/ -- (CPString)HTTPBody -{ - return _HTTPBody; -} - -/*! - Sets the request's http method. - @param anHTPPMethod the new http method -*/ -- (void)setHTTPMethod:(CPString)anHTTPMethod -{ - _HTTPMethod = anHTTPMethod; -} - -/*! - Returns the request's http method -*/ -- (CPString)HTTPMethod -{ - return _HTTPMethod; -} - -/*! - Returns a dictionary of the http header fields -*/ -- (CPDictionary)allHTTPHeaderFields -{ - return _HTTPHeaderFields; -} - /*! Returns the value for the specified header field. @param aField the header field to obtain a value for @@ -167,3 +120,23 @@ } @end + +/* + Implements the CPCopying Protocol for a CPURLRequest to provide deep copying for CPURLRequests +*/ +@implementation CPURLRequest (CPCopying) +{ +} + +- (id)copy +{ + var request = [[CPURLRequest alloc] initWithURL:[self URL]]; + [request setHTTPBody:[self HTTPBody]]; + [request setHTTPMethod:[self HTTPMethod]]; + [request setWithCredentials:[self withCredentials]]; + request._HTTPHeaderFields = [self allHTTPHeaderFields]; + + return request; +} + +@end diff --git a/Objective-J/CFHTTPRequest.js b/Objective-J/CFHTTPRequest.js index 6186dc80f..37bdf61e8 100644 --- a/Objective-J/CFHTTPRequest.js +++ b/Objective-J/CFHTTPRequest.js @@ -103,6 +103,9 @@ GLOBAL(CFHTTPRequest) = function() this._eventDispatcher = new EventDispatcher(this); this._nativeRequest = new NativeRequest(); + // by default, all requests will assume that credentials should not be sent. + this._nativeRequest.withCredentials = false; + var self = this; this._stateChangeHandler = function() { @@ -279,7 +282,7 @@ CFHTTPRequest.prototype.setWithCredentials = function(/*Boolean*/ willSendWithCr this._nativeRequest.withCredentials = willSendWithCredentials; }; -CFHTTPRequest.prototype.getWithCredentials = function() +CFHTTPRequest.prototype.withCredentials = function() { return this._nativeRequest.withCredentials; }; diff --git a/Tests/Foundation/CPURLConnectionTest.j b/Tests/Foundation/CPURLConnectionTest.j index 91df094d3..8d176c9e7 100644 --- a/Tests/Foundation/CPURLConnectionTest.j +++ b/Tests/Foundation/CPURLConnectionTest.j @@ -1,3 +1,4 @@ +@import @implementation CPURLConnectionTest : OJTestCase { @@ -36,10 +37,40 @@ [self assertNull:data]; } -- (void)testRequestWithCredentials +- (void)testClassMethodConnectionWithCredentials { - var connection = [CPURLConnection connectionWithRequest:[CPURLRequest requestWithURL:@"Tests/Foundation/CPURLConnectionTest.j"] delegate:self withCredentials:YES]; - [self assertTrue:[connection withCredentials]]; + var req = [CPURLRequest requestWithURL:[CPURL URLWithString:@"Tests/Foundation/CPURLConnectionTest.j"]]; + [req setWithCredentials:YES]; + var data = [CPURLConnection sendSynchronousRequest:req returningResponse:nil]; + + [self assertNotNull:data]; +} + +- (void)testInstanceMethodConnectionWithCredentials +{ + var req = [CPURLRequest requestWithURL:[CPURL URLWithString:@"Tests/Foundation/CPURLConnectionTest.j"]]; + [req setWithCredentials:YES]; + + var conn = [[CPURLConnection alloc] initWithRequest:req delegate:nil startImmediately:NO]; + + [self assertTrue:conn._HTTPRequest.withCredentials]; + + [req setWithCredentials:NO]; + [self assertTrue:conn._HTTPRequest.withCredentials]; +} + +- (void)testRequestGetters +{ + var req = [CPURLRequest requestWithURL:[CPURL URLWithString:@"Tests/Foundation/CPURLConnectionTest.j"]], + conn = [[CPURLConnection alloc] initWithRequest:req delegate:nil startImmediately:NO]; + + var originalRequest = [conn originalRequest], + currentRequest = [conn currentRequest]; + + [self assert:originalRequest._UID notEqual:currentRequest._UID]; + + [[conn currentRequest] setWithCredentials:YES]; + [self assert:[originalRequest withCredentials] notEqual:[currentRequest withCredentials]]; } @end diff --git a/Tests/Foundation/CPURLRequestTest.j b/Tests/Foundation/CPURLRequestTest.j new file mode 100644 index 000000000..2c9cbdb72 --- /dev/null +++ b/Tests/Foundation/CPURLRequestTest.j @@ -0,0 +1,30 @@ +@import + + +var exampleURL = "http://www.cappuccino-project.org"; + +@implementation CPURLRequestTest : OJTestCase +{ +} + +- (void)testClassMethods +{ + var url = [CPURL URLWithString:exampleURL], + req = [CPURLRequest requestWithURL:url]; + + [self assert:[req HTTPMethod] equals:@"GET"]; + [self assert:[req URL] equals:url]; +} + +- (void)testWithCredentials +{ + var url = [CPURL URLWithString:exampleURL], + req = [CPURLRequest requestWithURL:url]; + + [self assertFalse:[req withCredentials]]; + + [req setWithCredentials:YES]; + [self assertTrue:[req withCredentials]]; +} + +@end \ No newline at end of file diff --git a/Tests/Manual/CrossOriginTest/AppController.j b/Tests/Manual/CrossOriginTest/AppController.j new file mode 100644 index 000000000..2d3781175 --- /dev/null +++ b/Tests/Manual/CrossOriginTest/AppController.j @@ -0,0 +1,78 @@ +/* + * AppController.j + * CrossOriginTest + * + * Created by You on December 5, 2014. + * Copyright 2014, Your Company All rights reserved. + */ + +@import +@import + +var corsServer = "http://localhost:8001"; + +@implementation AppController : CPObject +{ + @outlet CPWindow theWindow; + @outlet CPButton theButton; + @outlet CPButton setsWithCredentials; +} + +- (void)applicationDidFinishLaunching:(CPNotification)aNotification +{ +} + +- (void)awakeFromCib +{ + // This is called when the cib is done loading. + // You can implement this method on any object instantiated from a Cib. + // It's a useful hook for setting up current UI values, and other things. + + // In this case, we want the window from Cib to become our full browser window + [theWindow setFullPlatformWindow:YES]; +} + +-(void)connection:(CPURLConnection)connection didReceiveResponse:(CPHTTPURLResponse)response +{ + console.log("Response received"); +} + +-(void)connection:(CPURLConnection)connection didReceiveData:(CPString)data +{ + var wc = ([[connection originalRequest] withCredentials]) ? "YES" : "NO" + console.log("CPURLConnection was sent with credentials? " + wc + " Response: " + data); +} + +- (@action)stateOfWithCredentials:(id)aSender +{ + console.log([setsWithCredentials state]); +} + +- (@action)testCappuccinoRequest:(id)aSender +{ + var req = [CPURLRequest requestWithURL:[CPURL URLWithString:corsServer + @"/resp.json"]]; + [req setValue:@"no-cache" forHTTPHeaderField:@"Pragma"]; + [req setValue:@"no-store, no-cache, must-revalidate, post-check=0, pre-check=0" forHTTPHeaderField:@"Cache-Control"]; + [req setWithCredentials:[setsWithCredentials state]]; + [[CPURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES]; +} + +- (@action)testNativeRequest:(id)aSender +{ + var wc = ([setsWithCredentials state]) ? true : false; + var req = new XMLHttpRequest(); + function reqListener () + { + console.log("Native XHR was sent with credentials? " + wc + " Response: " + this.responseText); + } + + req.onload = reqListener; + req.withCredentials = wc; + req.open("GET", corsServer + "/resp.json", true); + req.setRequestHeader("Pragma", "no-cache"); + req.setRequestHeader("Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); + + req.send(); +} + +@end diff --git a/Tests/Manual/CrossOriginTest/Info.plist b/Tests/Manual/CrossOriginTest/Info.plist new file mode 100644 index 000000000..2074fa146 --- /dev/null +++ b/Tests/Manual/CrossOriginTest/Info.plist @@ -0,0 +1,14 @@ + + + + + Main cib file base name + MainMenu.cib + CPBundleName + CrossOriginTest + CPBundleVersion + 1.0 + CPHumanReadableCopyright + Copyright © 2014, Your Company All rights reserved. + + diff --git a/Tests/Manual/CrossOriginTest/Jakefile b/Tests/Manual/CrossOriginTest/Jakefile new file mode 100644 index 000000000..6a448e9b0 --- /dev/null +++ b/Tests/Manual/CrossOriginTest/Jakefile @@ -0,0 +1,184 @@ +/* + * Jakefile + * CrossOriginTest + * + * Created by You on December 9, 2014. + * Copyright 2014, Your Company All rights reserved. + */ + +var ENV = require("system").env, + FILE = require("file"), + JAKE = require("jake"), + task = JAKE.task, + FileList = JAKE.FileList, + app = require("cappuccino/jake").app, + configuration = ENV["CONFIG"] || ENV["CONFIGURATION"] || ENV["c"] || "Debug", + OS = require("os"), + projectName = "CrossOriginTest"; + +app (projectName, function(task) +{ + ENV["OBJJ_INCLUDE_PATHS"] = "Frameworks"; + + if (configuration === "Debug") + ENV["OBJJ_INCLUDE_PATHS"] = FILE.join(ENV["OBJJ_INCLUDE_PATHS"], configuration); + + task.setBuildIntermediatesPath(FILE.join("Build", "CrossOriginTest.build", configuration)); + task.setBuildPath(FILE.join("Build", configuration)); + + task.setProductName("CrossOriginTest"); + task.setIdentifier("com.yourcompany.CrossOriginTest"); + task.setVersion("1.0"); + task.setAuthor("Your Company"); + task.setEmail("feedback @nospam@ yourcompany.com"); + task.setSummary("CrossOriginTest"); + task.setSources(new FileList("**/*.j").exclude(FILE.join("Build", "**")).exclude(FILE.join("Frameworks", "Source", "**"))); + task.setResources(new FileList("Resources/**")); + task.setIndexFilePath("index.html"); + task.setInfoPlistPath("Info.plist"); + + if (configuration === "Debug") + task.setCompilerFlags("-DDEBUG -g"); + else + task.setCompilerFlags("-O"); +}); + +task ("default", [projectName], function() +{ + printResults(configuration); +}); + +task ("build", ["default"], function() +{ + updateApplicationSize(); +}); + +task ("debug", function() +{ + configuration = ENV["CONFIGURATION"] = "Debug"; + JAKE.subjake(["."], "build", ENV); +}); + +task ("release", function() +{ + configuration = ENV["CONFIGURATION"] = "Release"; + JAKE.subjake(["."], "build", ENV); +}); + +task ("run", ["debug"], function() +{ + OS.system(["open", FILE.join("Build", "Debug", projectName, "index.html")]); +}); + +task ("run-release", ["release"], function() +{ + OS.system(["open", FILE.join("Build", "Release", projectName, "index.html")]); +}); + +task ("deploy", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Deployment", projectName)); + OS.system(["press", "-f", FILE.join("Build", "Release", projectName), FILE.join("Build", "Deployment", projectName)]); + printResults("Deployment") +}); + +task ("desktop", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Desktop", projectName)); + require("cappuccino/nativehost").buildNativeHost(FILE.join("Build", "Release", projectName), FILE.join("Build", "Desktop", projectName, "CrossOriginTest.app")); + printResults("Desktop") +}); + +task ("run-desktop", ["desktop"], function() +{ + OS.system([FILE.join("Build", "Desktop", projectName, "CrossOriginTest.app", "Contents", "MacOS", "NativeHost"), "-i"]); +}); + +function printResults(configuration) +{ + print("----------------------------"); + print(configuration+" app built at path: "+FILE.join("Build", configuration, projectName)); + print("----------------------------"); +} + +function updateApplicationSize() +{ + print("Calculating application file sizes..."); + + var contents = FILE.read(FILE.join("Build", configuration, projectName, "Info.plist"), { charset:"UTF-8" }), + format = CFPropertyList.sniffedFormatOfString(contents), + plist = CFPropertyList.propertyListFromString(contents), + totalBytes = {executable:0, data:0, mhtml:0}; + + // Get the size of all framework executables and sprite data + var frameworksDir = "Frameworks"; + + if (configuration === "Debug") + frameworksDir = FILE.join(frameworksDir, "Debug"); + + var frameworks = FILE.list(frameworksDir); + + frameworks.forEach(function(framework) + { + if (framework !== "Source") + addBundleFileSizes(FILE.join(frameworksDir, framework), totalBytes); + }); + + // Read in the default theme name, and attempt to get its size + var themeName = plist.valueForKey("CPDefaultTheme") || "Aristo2", + themePath = nil; + + if (themeName === "Aristo" || themeName === "Aristo2") + themePath = FILE.join(frameworksDir, "AppKit", "Resources", themeName + ".blend"); + else + themePath = FILE.join("Frameworks", "Resources", themeName + ".blend"); + + if (FILE.isDirectory(themePath)) + addBundleFileSizes(themePath, totalBytes); + + // Add sizes for the app + addBundleFileSizes(FILE.join("Build", configuration, projectName), totalBytes); + + print("Executables: " + totalBytes.executable + ", sprite data: " + totalBytes.data + ", total: " + (totalBytes.executable + totalBytes.data)); + + var dict = new CFMutableDictionary(); + + dict.setValueForKey("executable", totalBytes.executable); + dict.setValueForKey("data", totalBytes.data); + dict.setValueForKey("mhtml", totalBytes.mhtml); + + plist.setValueForKey("CPApplicationSize", dict); + + FILE.write(FILE.join("Build", configuration, projectName, "Info.plist"), CFPropertyList.stringFromPropertyList(plist, format), { charset:"UTF-8" }); +} + +function addBundleFileSizes(bundlePath, totalBytes) +{ + var bundleName = FILE.basename(bundlePath), + environment = bundleName === "Foundation" ? "Objj" : "Browser", + bundlePath = FILE.join(bundlePath, environment + ".environment"); + + if (FILE.isDirectory(bundlePath)) + { + var filename = bundleName + ".sj", + filePath = new FILE.Path(FILE.join(bundlePath, filename)); + + if (filePath.exists()) + totalBytes.executable += filePath.size(); + + filePath = new FILE.Path(FILE.join(bundlePath, "dataURLs.txt")); + + if (filePath.exists()) + totalBytes.data += filePath.size(); + + filePath = new FILE.Path(FILE.join(bundlePath, "MHTMLData.txt")); + + if (filePath.exists()) + totalBytes.mhtml += filePath.size(); + + filePath = new FILE.Path(FILE.join(bundlePath, "MHTMLPaths.txt")); + + if (filePath.exists()) + totalBytes.mhtml += filePath.size(); + } +} diff --git a/Tests/Manual/CrossOriginTest/README.md b/Tests/Manual/CrossOriginTest/README.md new file mode 100644 index 000000000..6c50ecada --- /dev/null +++ b/Tests/Manual/CrossOriginTest/README.md @@ -0,0 +1,45 @@ +This test checks the withCredentials CORS functionality with Cappuccino. + +Running the test: + +You will need to start two HTTP Servers; one on localhost:8000, and one on localhost:8001. + +The first: + +`$> python -m SimpleHTTPServer` // starts it on 8000 + +In another terminal window: + +`$> python cors-server.py` // starts another on 8001 + +Visit http://localhost:8000 in your web browser. There are two buttons and a checkbox. + +One button will issue a native XMLHTTPRequest. The other will issue a CPURLConnection request. The checkbox will control whether the withCredentials option is set on both types of requests. + +With the checkbox checked, you should press either of the buttons. In the terminal with the 'cors-server.py' script running you will see output that should match the following: + +``` +INFO:root:CORS: With Credentials +127.0.0.1 - - [05/Dec/2014 18:44:48] "GET /resp.json HTTP/1.1" 200 - +``` + +If you uncheck the checkbox, you should see the following: + +``` +INFO:root:CORS: No Credentials +127.0.0.1 - - [05/Dec/2014 18:44:56] "GET /resp.json HTTP/1.1" 200 - +``` + +This error message is controlled by the presence of the 'Cookies' header. + +NOTE: The cors-server.py will set a cookie for you (mycookie=cappuccino!), but only after the first request. If you don't have a cookie set for localhost, the server message will show 'No Credentials' on the first request since the Cookie header is not set. Subsequent requests will behave correctly. + +The browser console will also provide some status information about the request and response. + +# A note about IE** + +As best I can tell, IE behaves differently than all other browsers. I have tested this in Chrome and Firefox on Mac & Windows, Safari on Mac, IE11 on Windows. In this test, unchecking the 'With Credentials' will tell the browser to not send a cookie to the server if the server and client are not on the same host. However, in IE, it will pass the cookie along if the server and host are on the same top domain, but not necessarily the same host. The corollary of this is that if the two servers are on different domains, the `withCredentials` setting in IE does absolutely nothing. + +To get it to work, you must instruct your users to adjust their cookie privacy settings and allow third-party cookies. This seemed to work for me, but dynamically adjusting the `withCredentials` parameter did nothing with this on -- IE always sent the cookies if it was configured to do so. + +* What, you expected IE to actually work like the rest of the world? \ No newline at end of file diff --git a/Tests/Manual/CrossOriginTest/Resources/MainMenu.xib b/Tests/Manual/CrossOriginTest/Resources/MainMenu.xib new file mode 100644 index 000000000..a9914bcd6 --- /dev/null +++ b/Tests/Manual/CrossOriginTest/Resources/MainMenu.xib @@ -0,0 +1,1759 @@ + + + + 1050 + 14B25 + 6250 + 1343.16 + 755.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 6250 + + + NSButton + NSButtonCell + NSCustomObject + NSMenu + NSMenuItem + NSView + NSWindowTemplate + + + com.apple.InterfaceBuilder.CocoaPlugin + + + PluginDependencyRecalculationVersion + + + + + NSApplication + + + FirstResponder + + + NSApplication + + + AMainMenu + + + + NewApplication + + 1048576 + 2147483647 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + submenuAction: + + + NewApplication + + + + About NewApplication + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Preferences… + , + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Quit NewApplication + q + 1048576 + 2147483647 + + + + + _NSAppleMenu + + + + + File + + 1048576 + 2147483647 + + + submenuAction: + + + File + + + + New + n + 1048576 + 2147483647 + + + + + + Open… + o + 1048576 + 2147483647 + + + + + + Open Recent + + 1048576 + 2147483647 + + + submenuAction: + + + Open Recent + + + + Clear Menu + + 1048576 + 2147483647 + + + + + _NSRecentDocumentsMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Close + w + 1048576 + 2147483647 + + + + + + Save + s + 1048576 + 2147483647 + + + + + + Save As… + S + 1179648 + 2147483647 + + + + + + Revert to Saved + + 2147483647 + + + + + + + + + Edit + + 1048576 + 2147483647 + + + submenuAction: + + + Edit + + + + Undo + z + 1048576 + 2147483647 + + + + + + Redo + Z + 1179648 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Cut + x + 1048576 + 2147483647 + + + + + + Copy + c + 1048576 + 2147483647 + + + + + + Paste + v + 1048576 + 2147483647 + + + + + + Delete + + 1048576 + 2147483647 + + + + + + Select All + a + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Find + + 1048576 + 2147483647 + + + submenuAction: + + + Find + + + + Find… + f + 1048576 + 2147483647 + + + 1 + + + + Find Next + g + 1048576 + 2147483647 + + + 2 + + + + Find Previous + G + 1179648 + 2147483647 + + + 3 + + + + Use Selection for Find + e + 1048576 + 2147483647 + + + 7 + + + + Jump to Selection + j + 1048576 + 2147483647 + + + + + + + + + Spelling and Grammar + + 1048576 + 2147483647 + + + submenuAction: + + + Spelling and Grammar + + + + Show Spelling… + : + 1048576 + 2147483647 + + + + + + Check Spelling + ; + 1048576 + 2147483647 + + + + + + Check Spelling While Typing + + 1048576 + 2147483647 + + + + + + Check Grammar With Spelling + + 1048576 + 2147483647 + + + + + + + + + Substitutions + + 1048576 + 2147483647 + + + submenuAction: + + + Substitutions + + + + Smart Copy/Paste + f + 1048576 + 2147483647 + + + 1 + + + + Smart Quotes + g + 1048576 + 2147483647 + + + 2 + + + + Smart Links + G + 1179648 + 2147483647 + + + 3 + + + + + + + Speech + + 1048576 + 2147483647 + + + submenuAction: + + + Speech + + + + Start Speaking + + 1048576 + 2147483647 + + + + + + Stop Speaking + + 1048576 + 2147483647 + + + + + + + + + + + + View + + 1048576 + 2147483647 + + + submenuAction: + + + View + + + + Show Toolbar + t + 1572864 + 2147483647 + + + + + + Customize Toolbar… + + 1048576 + 2147483647 + + + + + + + + + Window + + 1048576 + 2147483647 + + + submenuAction: + + + Window + + + + Minimize + m + 1048576 + 2147483647 + + + + + + Zoom + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Bring All to Front + + 1048576 + 2147483647 + + + + + _NSWindowsMenu + + + + + Help + + 1048576 + 2147483647 + + + submenuAction: + + + Help + + + + NewApplication Help + ? + 1048576 + 2147483647 + + + + + + + + _NSMainMenu + + + 7 + 2 + {{335, 390}, {480, 360}} + 1946157056 + Window + NSWindow + + + + + 256 + + + + 268 + {{142, 196}, {197, 32}} + + + + _NS:9 + YES + + 67108864 + 134217728 + Native XMLHTTPRequest + + YES + 13 + 1044 + + _NS:9 + + -2038284288 + 129 + + + 200 + 25 + + NO + + + + 268 + {{133, 163}, {215, 32}} + + + _NS:9 + YES + + 67108864 + 134217728 + Cappuccino CPURLRequest + + _NS:9 + + -2038284288 + 129 + + + 200 + 25 + + NO + + + + 268 + {{178, 272}, {124, 18}} + + + + _NS:9 + YES + + -2080374784 + 268435456 + With Credentials + + _NS:9 + + 1211912448 + 2 + + NSImage + NSSwitch + + + NSSwitch + + + + 200 + 25 + + NO + + + {480, 360} + + + + + {{0, 0}, {1920, 1177}} + {10000000000000, 10000000000000} + YES + + + AppController + + + + + + + terminate: + + + + 449 + + + + orderFrontStandardAboutPanel: + + + + 142 + + + + delegate + + + + 451 + + + + performMiniaturize: + + + + 37 + + + + arrangeInFront: + + + + 39 + + + + clearRecentDocuments: + + + + 127 + + + + performClose: + + + + 193 + + + + toggleContinuousSpellChecking: + + + + 222 + + + + undo: + + + + 223 + + + + copy: + + + + 224 + + + + checkSpelling: + + + + 225 + + + + paste: + + + + 226 + + + + stopSpeaking: + + + + 227 + + + + cut: + + + + 228 + + + + showGuessPanel: + + + + 230 + + + + redo: + + + + 231 + + + + selectAll: + + + + 232 + + + + startSpeaking: + + + + 233 + + + + delete: + + + + 235 + + + + performZoom: + + + + 240 + + + + performFindPanelAction: + + + + 241 + + + + centerSelectionInVisibleArea: + + + + 245 + + + + toggleGrammarChecking: + + + + 347 + + + + toggleSmartInsertDelete: + + + + 355 + + + + toggleAutomaticQuoteSubstitution: + + + + 356 + + + + toggleAutomaticLinkDetection: + + + + 357 + + + + showHelp: + + + + 360 + + + + saveDocument: + + + + 362 + + + + saveDocumentAs: + + + + 363 + + + + revertDocumentToSaved: + + + + 364 + + + + runToolbarCustomizationPalette: + + + + 365 + + + + toggleToolbarShown: + + + + 366 + + + + newDocument: + + + + 373 + + + + openDocument: + + + + 374 + + + + theButton + + + + 462 + + + + theWindow + + + + 463 + + + + setsWithCredentials + + + + 471 + + + + stateOfWithCredentials: + + + + 472 + + + + testNativeRequest: + + + + 473 + + + + testCappuccinoRequest: + + + + 474 + + + + + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 29 + + + + + + + + + + + MainMenu + + + 19 + + + + + + + + 56 + + + + + + + + 103 + + + + + + + + 217 + + + + + + + + 83 + + + + + + + + 81 + + + + + + + + + + + + + + + 75 + + + + + 80 + + + + + 72 + + + + + 82 + + + + + 124 + + + + + + + + 73 + + + + + 79 + + + + + 112 + + + + + 125 + + + + + + + + 126 + + + + + 205 + + + + + + + + + + + + + + + + + + + + 202 + + + + + 198 + + + + + 207 + + + + + 214 + + + + + 199 + + + + + 203 + + + + + 197 + + + + + 206 + + + + + 215 + + + + + 218 + + + + + + + + 216 + + + + + + + + 200 + + + + + + + + + + + 219 + + + + + 201 + + + + + 204 + + + + + 220 + + + + + + + + + + + + 213 + + + + + 210 + + + + + 221 + + + + + 208 + + + + + 209 + + + + + 106 + + + + + + + + 111 + + + + + 57 + + + + + + + + + + + + 58 + + + + + 136 + + + + + 129 + + + + + 143 + + + + + 236 + + + + + 24 + + + + + + + + + + + 92 + + + + + 5 + + + + + 239 + + + + + 23 + + + + + 295 + + + + + + + + 296 + + + + + + + + + 297 + + + + + 298 + + + + + 211 + + + + + + + + 212 + + + + + + + + + 195 + + + + + 196 + + + + + 346 + + + + + 348 + + + + + + + + 349 + + + + + + + + + + 350 + + + + + 351 + + + + + 354 + + + + + 371 + + + + + + + + 372 + + + + + + + + + + 450 + + + + + 460 + + + + + + + + 461 + + + + + 465 + + + + + + + + 466 + + + + + 468 + + + + + + + + 469 + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{303, 221}, {480, 360}} + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + 474 + + + + + AppController + NSObject + + id + id + id + + + + stateOfWithCredentials: + id + + + testCappuccinoRequest: + id + + + testNativeRequest: + id + + + + NSButton + NSButton + NSWindow + + + + setsWithCredentials + NSButton + + + theButton + NSButton + + + theWindow + NSWindow + + + + IBProjectSource + ../.XcodeSupport/AppController.h + + + + + 0 + IBCocoaFramework + NO + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + + YES + 3 + + {12, 12} + {10, 2} + {15, 15} + + + diff --git a/Tests/Manual/CrossOriginTest/cors-server.py b/Tests/Manual/CrossOriginTest/cors-server.py new file mode 100644 index 000000000..937f2188a --- /dev/null +++ b/Tests/Manual/CrossOriginTest/cors-server.py @@ -0,0 +1,44 @@ +import SimpleHTTPServer +import SocketServer +import logging +import cgi + +logging.basicConfig(level=logging.INFO) +PORT = 8001 + +class ServerHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): + + def end_headers (self): + self.send_header('Set-Cookie', 'mycookie=cappuccino!') + self.send_header('Access-Control-Allow-Origin', 'http://142.157.142.237:8000') + self.send_header('Access-Control-Allow-Methods', 'GET, OPTIONS') + self.send_header("Access-Control-Allow-Headers", "X-Requested-With, If-Modified-Since, Cache-Control, Pragma") + self.send_header('Access-Control-Allow-Credentials', 'true') + SimpleHTTPServer.SimpleHTTPRequestHandler.end_headers(self) + + def do_OPTIONS(self): + logging.info("OPTIONS Request") + self.send_response(204, "No Content") + self.send_header('Access-Control-Allow-Origin', 'http://142.157.142.237:8000') + self.send_header('Access-Control-Allow-Methods', 'GET, OPTIONS') + self.send_header("Access-Control-Allow-Headers", "X-Requested-With, If-Modified-Since, Cache-Control, Pragma") + self.send_header('Access-Control-Allow-Credentials', 'true') + self.send_header("Access-Control-Max-Age", 10) + self.send_header("content-length", 0) + + def do_GET(self): + try: + self.headers['Cookie'] + logging.info("CORS: With Credentials") + logging.info(self.headers['Cookie']) + except KeyError, e: + logging.info("CORS: No Credentials") + SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) + +Handler = ServerHandler + +SocketServer.TCPServer.allow_reuse_address = True +httpd = SocketServer.TCPServer(("0.0.0.0", PORT), Handler) + +print "serving at port", PORT +httpd.serve_forever() \ No newline at end of file diff --git a/Tests/Manual/CrossOriginTest/index-debug.html b/Tests/Manual/CrossOriginTest/index-debug.html new file mode 100644 index 000000000..59a519b3d --- /dev/null +++ b/Tests/Manual/CrossOriginTest/index-debug.html @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + + + TestIEWithCredentials + + + + + + + + + + + + + + +
+
+
+ +
+
+ +
+ + diff --git a/Tests/Manual/CrossOriginTest/index.html b/Tests/Manual/CrossOriginTest/index.html new file mode 100644 index 000000000..b38196c63 --- /dev/null +++ b/Tests/Manual/CrossOriginTest/index.html @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + + CrossOriginTest + + + + + + + + + + + + +
+
+
+ +
+
+ +
+ + diff --git a/Tests/Manual/CrossOriginTest/main.j b/Tests/Manual/CrossOriginTest/main.j new file mode 100644 index 000000000..fb705f3f3 --- /dev/null +++ b/Tests/Manual/CrossOriginTest/main.j @@ -0,0 +1,18 @@ +/* + * AppController.j + * CrossOriginTest + * + * Created by You on December 9, 2014. + * Copyright 2014, Your Company All rights reserved. + */ + +@import +@import + +@import "AppController.j" + + +function main(args, namedArgs) +{ + CPApplicationMain(args, namedArgs); +} diff --git a/Tests/Manual/CrossOriginTest/resp.json b/Tests/Manual/CrossOriginTest/resp.json new file mode 100644 index 000000000..5d76ff1e6 --- /dev/null +++ b/Tests/Manual/CrossOriginTest/resp.json @@ -0,0 +1 @@ +{"response": "ok"} \ No newline at end of file diff --git a/Tests/Objective-J/CFHTTPRequestTest.j b/Tests/Objective-J/CFHTTPRequestTest.j index f6afe5a58..c10edba85 100644 --- a/Tests/Objective-J/CFHTTPRequestTest.j +++ b/Tests/Objective-J/CFHTTPRequestTest.j @@ -7,10 +7,10 @@ - (void)testSetWithCredentials { var cfHTTPRequest = new CFHTTPRequest(); - [self assertFalse:cfHTTPRequest.getWithCredentials()]; + [self assertFalse:cfHTTPRequest.withCredentials()]; cfHTTPRequest.setWithCredentials(YES); - [self assertTrue:cfHTTPRequest.getWithCredentials()]; + [self assertTrue:cfHTTPRequest.withCredentials()]; } @end