Skip to content
This repository was archived by the owner on Feb 22, 2018. It is now read-only.

feat(Http): Http service can make cross-site requests (get, post, put, e... #1026

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 35 additions & 25 deletions lib/core_dom/http.dart
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@ class Http {
* - headers: Map of strings or functions which return strings representing
* HTTP headers to send to the server. If the return value of a function
* is null, the header will not be sent.
* - withCredentials: True if cross-site requests should use credentials such as cookies or
* authorization headers; false otherwise. If not specified, defaults to false.
* - xsrfHeaderName: TBI
* - xsrfCookieName: TBI
* - interceptors: Either a [HttpInterceptor] or a [HttpInterceptors]
Expand All @@ -422,6 +424,7 @@ class Http {
data,
Map<String, dynamic> params,
Map<String, dynamic> headers,
bool withCredentials: false,
xsrfHeaderName,
xsrfCookieName,
interceptors,
Expand Down Expand Up @@ -481,7 +484,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 +539,16 @@ class Http {
String data,
Map<String, dynamic> params,
Map<String, String> headers,
bool 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 +558,16 @@ class Http {
String data,
Map<String, dynamic> params,
Map<String, String> headers,
bool 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 +577,16 @@ class Http {
String data,
Map<String, dynamic> params,
Map<String, String> headers,
bool 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 +595,16 @@ class Http {
async.Future<HttpResponse> put(String url, String data, {
Map<String, dynamic> params,
Map<String, String> headers,
bool 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 +613,16 @@ class Http {
async.Future<HttpResponse> post(String url, String data, {
Map<String, dynamic> params,
Map<String, String> headers,
bool 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 +632,16 @@ class Http {
String data,
Map<String, dynamic> params,
Map<String, String> headers,
bool 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
52 changes: 34 additions & 18 deletions lib/mock/http_backend.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,20 +64,23 @@ class _MockXhr {
* An internal class used by [MockHttpBackend].
*/
class MockHttpExpectation {
final method;
final url;
final String method;
final String url;
final data;
final headers;
final bool withCredentials;

var response;

MockHttpExpectation(this.method, this.url, [this.data, this.headers]);
MockHttpExpectation(this.method, this.url, [this.data, this.headers, withCredentials]) :
this.withCredentials = withCredentials == true;

bool match(method, url, [data, headers]) {
bool match(method, url, [data, headers, withCredentials]) {
if (method != method) return false;
if (!matchUrl(url)) return false;
if (data != null && !matchData(data)) return false;
if (headers != null && !matchHeaders(headers)) return false;
if (withCredentials != null && !matchWithCredentials(withCredentials)) return false;
return true;
}

Expand All @@ -102,6 +105,8 @@ class MockHttpExpectation {
return JSON.encode(data) == JSON.encode(d);
}

bool matchWithCredentials(withCredentials) => this.withCredentials == withCredentials;

String toString() => "$method $url";
}

Expand All @@ -124,7 +129,7 @@ class MockHttpBackend implements HttpBackend {
* This function is called from [Http] and designed to mimic the Dart APIs.
*/
dart_async.Future request(String url,
{String method, bool withCredentials, String responseType,
{String method, bool withCredentials: false, String responseType,
String mimeType, Map<String, String> requestHeaders, sendData,
void onProgress(ProgressEvent e)}) {
dart_async.Completer c = new dart_async.Completer();
Expand All @@ -136,7 +141,7 @@ class MockHttpBackend implements HttpBackend {
new MockHttpRequest(status, data, headers)));
}
};
call(method == null ? 'GET' : method, url, sendData, callback,
call(method == null ? 'GET' : method, url, sendData, withCredentials, callback,
requestHeaders);
return c.future;
}
Expand All @@ -163,7 +168,7 @@ class MockHttpBackend implements HttpBackend {
* A callback oriented API. This function takes a callback with
* will be called with (status, data, headers)
*/
void call(method, [url, data, callback, headers, timeout]) {
void call(method, [url, data, withCredentials, callback, headers, timeout]) {
var xhr = new _MockXhr(),
expectation = expectations.isEmpty ? null : expectations[0],
wasExpected = false;
Expand Down Expand Up @@ -206,6 +211,11 @@ class MockHttpBackend implements HttpBackend {
'EXPECTED: ${prettyPrint(expectation.headers)}\n'
'GOT: ${prettyPrint(headers)}'];

if (!expectation.matchWithCredentials(withCredentials))
throw ['Expected $expectation with different withCredentials\n'
'EXPECTED: ${prettyPrint(expectation.withCredentials)}\n'
'GOT: ${prettyPrint(withCredentials)}'];

expectations.removeAt(0);

if (expectation.response != null) {
Expand All @@ -216,7 +226,7 @@ class MockHttpBackend implements HttpBackend {
}

for (var definition in definitions) {
if (definition.match(method, url, data, headers != null ? headers : {})) {
if (definition.match(method, url, data, headers != null ? headers : {}, withCredentials)) {
if (definition.response != null) {
// if $browser specified, we do auto flush all requests
responses.add(wrapResponse(definition));
Expand Down Expand Up @@ -248,8 +258,8 @@ class MockHttpBackend implements HttpBackend {
* an array containing response status (number), response data (string) and response headers
* (Object).
*/
_Chain when(method, [url, data, headers]) {
var definition = new MockHttpExpectation(method, url, data, headers),
_Chain when(method, [url, data, headers, withCredentials = false]) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can remove the false default value if you implement my suggestion in the MockHttpExpectation ctor

var definition = new MockHttpExpectation(method, url, data, headers, withCredentials),
chain = new _Chain(respond: (status, data, headers) {
definition.response = _createResponse(status, data, headers);
});
Expand Down Expand Up @@ -364,8 +374,8 @@ class MockHttpBackend implements HttpBackend {
* an array containing response status (number), response data (string) and response headers
* (Object).
*/
_Chain expect(method, [url, data, headers]) {
var expectation = new MockHttpExpectation(method, url, data, headers);
_Chain expect(method, [url, data, headers, withCredentials = false]) {
var expectation = new MockHttpExpectation(method, url, data, headers, withCredentials);
expectations.add(expectation);
return new _Chain(respond: (status, data, headers) {
expectation.response = _createResponse(status, data, headers);
Expand All @@ -385,7 +395,8 @@ class MockHttpBackend implements HttpBackend {
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
* request is handled. See #expect for more info.
*/
_Chain expectGET(url, [headers]) => expect('GET', url, null, headers);
_Chain expectGET(url, [headers, withCredentials = false]) => expect('GET', url, null, headers,
withCredentials);

/**
* @ngdoc method
Expand All @@ -399,7 +410,8 @@ class MockHttpBackend implements HttpBackend {
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
* request is handled.
*/
_Chain expectDELETE(url, [headers]) => expect('DELETE', url, null, headers);
_Chain expectDELETE(url, [headers, withCredentials = false]) => expect('DELETE', url, null,
headers, withCredentials);

/**
* @ngdoc method
Expand All @@ -412,7 +424,8 @@ class MockHttpBackend implements HttpBackend {
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
* request is handled.
*/
_Chain expectJSONP(url, [headers]) => expect('JSONP', url, null, headers);
_Chain expectJSONP(url, [headers, withCredentials = false]) => expect('JSONP', url, null, headers,
withCredentials);

/**
* @ngdoc method
Expand All @@ -427,7 +440,8 @@ class MockHttpBackend implements HttpBackend {
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
* request is handled.
*/
_Chain expectPUT(url, [data, headers]) => expect('PUT', url, data, headers);
_Chain expectPUT(url, [data, headers, withCredentials = false]) => expect('PUT', url, data,
headers, withCredentials);

/**
* @ngdoc method
Expand All @@ -442,7 +456,8 @@ class MockHttpBackend implements HttpBackend {
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
* request is handled.
*/
_Chain expectPOST(url, [data, headers]) => expect('POST', url, data, headers);
_Chain expectPOST(url, [data, headers, withCredentials = false]) => expect('POST', url, data,
headers, withCredentials);

/**
* @ngdoc method
Expand All @@ -457,7 +472,8 @@ class MockHttpBackend implements HttpBackend {
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
* request is handled.
*/
_Chain expectPATCH(url, [data, headers]) => expect('PATCH', url, data, headers);
_Chain expectPATCH(url, [data, headers, withCredentials = false]) => expect('PATCH', url, data,
headers, withCredentials);

/**
* @ngdoc method
Expand Down
9 changes: 9 additions & 0 deletions test/core_dom/http_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,15 @@ void main() {
flush();
}));

describe('backend', () {
it('should pass on withCredentials to backend and use GET as default method',
async(() {
backend.expect('GET', '/url', null, null, true).respond('');
http(url: '/url', method: 'GET', withCredentials: true);
flush();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Identation pb

}));
});


describe('params', () {
it('should do basic request with params and encode', async(() {
Expand Down
Loading