Merge pull request #2272 from ahankinson/new-fixed-with-credentials-cpurl

Rework of withCredentials, CPURLRequest, and CPURLConnection
This commit is contained in:
Antoine Mercadal
2015-01-14 11:51:14 -08:00
16 changed files with 2599 additions and 93 deletions
+7 -33
View File
@@ -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);
+27 -54
View File
@@ -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
+4 -1
View File
@@ -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;
};
+34 -3
View File
@@ -1,3 +1,4 @@
@import <OJUnit/OJTestCase.j>
@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
+30
View File
@@ -0,0 +1,30 @@
@import <OJUnit/OJTestCase.j>
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
@@ -0,0 +1,78 @@
/*
* AppController.j
* CrossOriginTest
*
* Created by You on December 5, 2014.
* Copyright 2014, Your Company All rights reserved.
*/
@import <Foundation/Foundation.j>
@import <AppKit/AppKit.j>
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
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Main cib file base name</key>
<string>MainMenu.cib</string>
<key>CPBundleName</key>
<string>CrossOriginTest</string>
<key>CPBundleVersion</key>
<string>1.0</string>
<key>CPHumanReadableCopyright</key>
<string>Copyright © 2014, Your Company All rights reserved.</string>
</dict>
</plist>
+184
View File
@@ -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();
}
}
+45
View File
@@ -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<sup>**</sup>
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.
<sup>*</sup> What, you expected IE to actually work like the rest of the world?
File diff suppressed because it is too large Load Diff
@@ -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()
@@ -0,0 +1,191 @@
<!DOCTYPE html>
<html lang="en">
<!--
index-debug.html
CrossOriginTest
Created by You on December 5, 2014.
Copyright 2014, Your Company All rights reserved.
-->
<head>
<meta charset="utf-8">
<!--[if lte IE 8]>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7, chrome=1">
<![endif]-->
<!--[if gte IE 9]>
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<![endif]-->
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="apple-touch-icon" href="Resources/icon.png">
<link rel="apple-touch-startup-image" href="Resources/default.png">
<title>TestIEWithCredentials</title>
<!-- Custom javascript goes here -->
<!-- End custom javascript -->
<script type="text/javascript">
OBJJ_MAIN_FILE = "main.j";
OBJJ_INCLUDE_PATHS = ["Frameworks/Debug", "Frameworks"];
var progressBar = null;
OBJJ_PROGRESS_CALLBACK = function(percent, appSize, path)
{
percent = percent * 100;
if (!progressBar)
progressBar = document.getElementById("progress-bar");
if (progressBar)
progressBar.style.width = Math.min(percent, 100) + "%";
}
var loadingHTML =
'<div id="loading">' +
' <div id="loading-text">Loading...</div>' +
' <div id="progress-indicator">' +
' <span id="progress-bar" style="width:0%"></span>' +
' </div>' +
'</div>';
</script>
<script type="text/javascript" src="Frameworks/Debug/Objective-J/Objective-J.js" charset="UTF-8"></script>
<script type="text/javascript">
objj_msgSend_reset();
// DEBUG OPTIONS:
// Uncomment to enable printing of backtraces on exceptions:
//objj_msgSend_decorate(objj_backtrace_decorator);
// Uncomment to supress exceptions that take place inside a message
//objj_msgSend_decorate(objj_supress_exceptions_decorator)
// Uncomment to enable runtime type checking:
//objj_msgSend_decorate(objj_typecheck_decorator);
// Uncomment (along with both above) to print backtraces on type check errors:
//objj_typecheck_prints_backtrace = true;
// Uncomment to disable the default logger (CPLogConsole if window.console exists, CPLogPopup otherwise):
//CPLogUnregister(CPLogDefault);
// Uncomment to enable a specific logger:
//CPLogRegister(CPLogConsole);
//CPLogRegister(CPLogPopup);
// Tag view DOM elements with a "data-cappuccino-view" attribute that contains
// the class name of the view that created them. Comment this or set to false to disable.
appkit_tag_dom_elements = true;
</script>
<style type="text/css">
html, body, h1, p {
margin: 0;
padding: 0;
}
/* We need a body wrapper because Cappuccino is unhappy if we change the body element */
#cappuccino-body {
/* Position it absolutely so it will fill the height without content */
position: absolute;
top: 0;
bottom: 0;
width: 100%;
/* Put it at the bottom of the stack so it doesn't interfere with UI */
z-index: -1000;
}
#cappuccino-body .container {
display: table;
margin: 0 auto;
height: 100%;
}
#cappuccino-body .content {
display: table-cell;
height: 100%;
vertical-align: top;
}
#loading {
position: relative;
top: 35%;
}
#loading-text {
height: 1.5em;
color: #555;
font: normal bold 36px/36px Arial, sans-serif;
}
#progress-indicator {
padding: 0px;
height: 16px;
border: 5px solid #555;
border-radius: 18px;
background-color: white;
}
#progress-bar {
position: relative;
top: -1px;
left: -1px;
display: block;
height: 18px;
/* Compensate for moving the bar left 1px to overlap the indicator border */
border-right: 1px solid #555;
background-color: #555;
}
#noscript {
position: relative;
top: 35%;
padding: 1em 1.5em;
border: 5px solid #555;
border-radius: 16px;
background-color: white;
color: #555;
text-align: center;
font: bold 24px Arial, sans-serif;
}
#noscript a {
color: #98c0ff;
text-decoration: none;
}
</style>
</head>
<body>
<div id="cappuccino-body">
<div class="container">
<div class="content">
<script type="text/javascript">
document.write(loadingHTML);
</script>
</div>
</div>
<noscript style="position:absolute; top:0; left:0; width:100%; height:100%">
<div class="container">
<div class="content">
<div id="noscript">
<p style="font-size:120%; margin-bottom:.75em">JavaScript is required for this site.</p>
<p><a href="http://www.enable-javascript.com" target="_blank">Enable JavaScript</a></p>
</div>
</div>
</div>
</noscript>
</div>
</body>
</html>
+161
View File
@@ -0,0 +1,161 @@
<!DOCTYPE html>
<html lang="en">
<!--
index.html
CrossOriginTest
Created by You on December 5, 2014.
Copyright 2014, Your Company All rights reserved.
-->
<head>
<meta charset="utf-8">
<!--[if lte IE 8]>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7, chrome=1">
<![endif]-->
<!--[if gte IE 9]>
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<![endif]-->
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="apple-touch-icon" href="Resources/icon.png">
<link rel="apple-touch-startup-image" href="Resources/default.png">
<title>CrossOriginTest</title>
<!-- Custom javascript goes here -->
<!-- End custom javascript -->
<script type="text/javascript">
OBJJ_MAIN_FILE = "main.j";
var progressBar = null;
OBJJ_PROGRESS_CALLBACK = function(percent, appSize, path)
{
percent = percent * 100;
if (!progressBar)
progressBar = document.getElementById("progress-bar");
if (progressBar)
progressBar.style.width = Math.min(percent, 100) + "%";
}
var loadingHTML =
'<div id="loading">' +
' <div id="loading-text">Loading...</div>' +
' <div id="progress-indicator">' +
' <span id="progress-bar" style="width:0%"></span>' +
' </div>' +
'</div>';
</script>
<script type="text/javascript" src="Frameworks/Objective-J/Objective-J.js" charset="UTF-8"></script>
<style type="text/css">
html, body, h1, p {
margin: 0;
padding: 0;
}
/* We need a body wrapper because Cappuccino is unhappy if we change the body element */
#cappuccino-body {
/* Position it absolutely so it will fill the height without content */
position: absolute;
top: 0;
bottom: 0;
width: 100%;
/* Put it at the bottom of the stack so it doesn't interfere with UI */
z-index: -1000;
}
#cappuccino-body .container {
display: table;
margin: 0 auto;
height: 100%;
}
#cappuccino-body .content {
display: table-cell;
height: 100%;
vertical-align: top;
}
#loading {
position: relative;
top: 35%;
}
#loading-text {
height: 1.5em;
color: #555;
font: normal bold 36px/36px Arial, sans-serif;
}
#progress-indicator {
padding: 0px;
height: 16px;
border: 5px solid #555;
border-radius: 18px;
background-color: white;
}
#progress-bar {
position: relative;
top: -1px;
left: -1px;
display: block;
height: 18px;
/* Compensate for moving the bar left 1px to overlap the indicator border */
border-right: 1px solid #555;
background-color: #555;
}
#noscript {
position: relative;
top: 35%;
padding: 1em 1.5em;
border: 5px solid #555;
border-radius: 16px;
background-color: white;
color: #555;
text-align: center;
font: bold 24px Arial, sans-serif;
}
#noscript a {
color: #98c0ff;
text-decoration: none;
}
</style>
</head>
<body>
<div id="cappuccino-body">
<div class="container">
<div class="content">
<script type="text/javascript">
document.write(loadingHTML);
</script>
</div>
</div>
<noscript style="position:absolute; top:0; left:0; width:100%; height:100%">
<div class="container">
<div class="content">
<div id="noscript">
<p style="font-size:120%; margin-bottom:.75em">JavaScript is required for this site.</p>
<p><a href="http://www.enable-javascript.com" target="_blank">Enable JavaScript</a></p>
</div>
</div>
</div>
</noscript>
</div>
</body>
</html>
+18
View File
@@ -0,0 +1,18 @@
/*
* AppController.j
* CrossOriginTest
*
* Created by You on December 9, 2014.
* Copyright 2014, Your Company All rights reserved.
*/
@import <Foundation/Foundation.j>
@import <AppKit/AppKit.j>
@import "AppController.j"
function main(args, namedArgs)
{
CPApplicationMain(args, namedArgs);
}
+1
View File
@@ -0,0 +1 @@
{"response": "ok"}
+2 -2
View File
@@ -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