Skip to content

Commit

Permalink
feat(Http): Http service can make cross-site requests (get, post, put…
Browse files Browse the repository at this point in the history
…, etc.) which use credentials (such as cookies or authorization headers).

Closes dart-archive#945
  • Loading branch information
mvuksano committed May 9, 2014
1 parent 6bbd7f6 commit 34e66bb
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 25 deletions.
58 changes: 33 additions & 25 deletions lib/core_dom/http.dart
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ class Http {
data,
Map<String, dynamic> params,
Map<String, dynamic> headers,
withCredentials: false,
xsrfHeaderName,
xsrfCookieName,
interceptors,
Expand Down Expand Up @@ -481,7 +482,8 @@ class Http {
var result = _backend.request(url,
method: method,
requestHeaders: config.headers,
sendData: config.data).then((dom.HttpRequest value) {
sendData: config.data,
withCredentials: withCredentials).then((dom.HttpRequest value) {
// TODO: Uncomment after apps migrate off of this class.
// assert(value.status >= 200 && value.status < 300);

Expand Down Expand Up @@ -535,15 +537,16 @@ class Http {
String data,
Map<String, dynamic> params,
Map<String, String> headers,
withCredentials: false,
xsrfHeaderName,
xsrfCookieName,
interceptors,
cache,
timeout
}) => call(method: 'GET', url: url, data: data, params: params,
headers: headers, xsrfHeaderName: xsrfHeaderName,
xsrfCookieName: xsrfCookieName, interceptors: interceptors,
cache: cache, timeout: timeout);
}) => call(method: 'GET', url: url, data: data, params: params, headers: headers,
withCredentials: withCredentials, xsrfHeaderName: xsrfHeaderName,
xsrfCookieName: xsrfCookieName, interceptors: interceptors, cache: cache,
timeout: timeout);

/**
* Shortcut method for DELETE requests. See [call] for a complete description
Expand All @@ -553,15 +556,16 @@ class Http {
String data,
Map<String, dynamic> params,
Map<String, String> headers,
withCredentials: false,
xsrfHeaderName,
xsrfCookieName,
interceptors,
cache,
timeout
}) => call(method: 'DELETE', url: url, data: data, params: params,
headers: headers, xsrfHeaderName: xsrfHeaderName,
xsrfCookieName: xsrfCookieName, interceptors: interceptors,
cache: cache, timeout: timeout);
}) => call(method: 'DELETE', url: url, data: data, params: params, headers: headers,
withCredentials: withCredentials, xsrfHeaderName: xsrfHeaderName,
xsrfCookieName: xsrfCookieName, interceptors: interceptors, cache: cache,
timeout: timeout);

/**
* Shortcut method for HEAD requests. See [call] for a complete description
Expand All @@ -571,15 +575,16 @@ class Http {
String data,
Map<String, dynamic> params,
Map<String, String> headers,
withCredentials: false,
xsrfHeaderName,
xsrfCookieName,
interceptors,
cache,
timeout
}) => call(method: 'HEAD', url: url, data: data, params: params,
headers: headers, xsrfHeaderName: xsrfHeaderName,
xsrfCookieName: xsrfCookieName, interceptors: interceptors,
cache: cache, timeout: timeout);
}) => call(method: 'HEAD', url: url, data: data, params: params, headers: headers,
withCredentials: withCredentials, xsrfHeaderName: xsrfHeaderName,
xsrfCookieName: xsrfCookieName, interceptors: interceptors, cache: cache,
timeout: timeout);

/**
* Shortcut method for PUT requests. See [call] for a complete description
Expand All @@ -588,15 +593,16 @@ class Http {
async.Future<HttpResponse> put(String url, String data, {
Map<String, dynamic> params,
Map<String, String> headers,
withCredentials: false,
xsrfHeaderName,
xsrfCookieName,
interceptors,
cache,
timeout
}) => call(method: 'PUT', url: url, data: data, params: params,
headers: headers, xsrfHeaderName: xsrfHeaderName,
xsrfCookieName: xsrfCookieName, interceptors: interceptors,
cache: cache, timeout: timeout);
}) => call(method: 'PUT', url: url, data: data, params: params, headers: headers,
withCredentials: withCredentials, xsrfHeaderName: xsrfHeaderName,
xsrfCookieName: xsrfCookieName, interceptors: interceptors, cache: cache,
timeout: timeout);

/**
* Shortcut method for POST requests. See [call] for a complete description
Expand All @@ -605,15 +611,16 @@ class Http {
async.Future<HttpResponse> post(String url, String data, {
Map<String, dynamic> params,
Map<String, String> headers,
withCredentials: false,
xsrfHeaderName,
xsrfCookieName,
interceptors,
cache,
timeout
}) => call(method: 'POST', url: url, data: data, params: params,
headers: headers, xsrfHeaderName: xsrfHeaderName,
xsrfCookieName: xsrfCookieName, interceptors: interceptors,
cache: cache, timeout: timeout);
}) => call(method: 'POST', url: url, data: data, params: params, headers: headers,
withCredentials: withCredentials, xsrfHeaderName: xsrfHeaderName,
xsrfCookieName: xsrfCookieName, interceptors: interceptors, cache: cache,
timeout: timeout);

/**
* Shortcut method for JSONP requests. See [call] for a complete description
Expand All @@ -623,15 +630,16 @@ class Http {
String data,
Map<String, dynamic> params,
Map<String, String> headers,
withCredentials: false,
xsrfHeaderName,
xsrfCookieName,
interceptors,
cache,
timeout
}) => call(method: 'JSONP', url: url, data: data, params: params,
headers: headers, xsrfHeaderName: xsrfHeaderName,
xsrfCookieName: xsrfCookieName, interceptors: interceptors,
cache: cache, timeout: timeout);
}) => call(method: 'JSONP', url: url, data: data, params: params, headers: headers,
withCredentials: withCredentials, xsrfHeaderName: xsrfHeaderName,
xsrfCookieName: xsrfCookieName, interceptors: interceptors, cache: cache,
timeout: timeout);

/**
* Parse raw headers into key-value object
Expand Down
100 changes: 100 additions & 0 deletions test/core_dom/http_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,69 @@ void main() {
flush();
}));

describe('backend', () {
beforeEachModule((Module module) {
FakeBackend fakeBackend = new FakeBackend();
module.bind(HttpBackend, toFactory: (i) => fakeBackend);
module.bind(FakeBackend, toFactory: (i) => i.get(HttpBackend));
});

it('should pass on withCredentials to backend and use GET as default method',
async((FakeBackend backend) {
http(url: '/url', method: 'GET', withCredentials: true);
microLeap();
expect(backend.url).toEqual('/url');
expect(backend.method).toEqual('GET');
expect(backend.withCredentials).toBeTruthy();
}));

it('get should pass on withCredentials to backend', async((FakeBackend backend) {
http.get('/url', withCredentials: true);
microLeap();
expect(backend.method).toEqual('GET');
expect(backend.withCredentials).toBeTruthy();
}));

it('delete should pass on withCredentials to backend', async((FakeBackend backend) {
http.delete('/url', withCredentials: true);
microLeap();
expect(backend.method).toEqual('DELETE');
expect(backend.withCredentials).toBeTruthy();
}));

it('head should pass on withCredentials to backend', async((FakeBackend backend) {
http.head('/url', withCredentials: true);
microLeap();
expect(backend.method).toEqual('HEAD');
expect(backend.withCredentials).toBeTruthy();
}));

it('put should pass on data and withCredentials to backend', async((FakeBackend backend) {
var mockData = "mockData";
http.put('/url', mockData, withCredentials: true);
microLeap();
expect(backend.sendData).toEqual(mockData);
expect(backend.method).toEqual('PUT');
expect(backend.withCredentials).toBeTruthy();
}));

it('post should pass on data and withCredentials to backend', async((FakeBackend backend) {
var mockData = "mockData";
http.post('/url', mockData, withCredentials: true);
microLeap();
expect(backend.sendData).toEqual(mockData);
expect(backend.method).toEqual('POST');
expect(backend.withCredentials).toBeTruthy();
}));

it('jsonp should pass withCredentials to backend', async((FakeBackend backend) {
http.jsonp('/url', withCredentials: true);
microLeap();
expect(backend.method).toEqual('JSONP');
expect(backend.withCredentials).toBeTruthy();
}));
});


describe('params', () {
it('should do basic request with params and encode', async(() {
Expand Down Expand Up @@ -1356,3 +1419,40 @@ class FakeFile implements File {
Blob slice([int start, int end, String contentType]) => null;
int get lastModified => new DateTime.now().millisecondsSinceEpoch;
}

class FakeBackend extends Mock implements HttpBackend {

String url;
String method;
bool withCredentials;
String responseType;
String mimeType;
Map<String, String> requestHeaders;
dynamic sendData;

Future<HttpRequest> request(String url, {
String method,
bool withCredentials,
String responseType,
String mimeType,
Map<String, String> requestHeaders,
sendData,
void onProgress(ProgressEvent e)}) {
this.url = url;
this.method = method;
this.withCredentials = withCredentials;
this.responseType = responseType;
this.mimeType = mimeType;
this.requestHeaders = requestHeaders;
this.sendData = sendData;
HttpRequest request = new HttpRequest();
return new Future.value(new HttpRequest());
}
}

class FakeHttpRequest extends Mock implements HttpRequest {
FakeHttpRequest() {
when(callsTo('get status')).thenReturn(200);
when(callsTo('get responseText')).thenReturn('Fake Request');
}
}

0 comments on commit 34e66bb

Please sign in to comment.