Skip to content

Commit 34e66bb

Browse files
committed
feat(Http): Http service can make cross-site requests (get, post, put, etc.) which use credentials (such as cookies or authorization headers).
Closes dart-archive#945
1 parent 6bbd7f6 commit 34e66bb

File tree

2 files changed

+133
-25
lines changed

2 files changed

+133
-25
lines changed

lib/core_dom/http.dart

+33-25
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ class Http {
422422
data,
423423
Map<String, dynamic> params,
424424
Map<String, dynamic> headers,
425+
withCredentials: false,
425426
xsrfHeaderName,
426427
xsrfCookieName,
427428
interceptors,
@@ -481,7 +482,8 @@ class Http {
481482
var result = _backend.request(url,
482483
method: method,
483484
requestHeaders: config.headers,
484-
sendData: config.data).then((dom.HttpRequest value) {
485+
sendData: config.data,
486+
withCredentials: withCredentials).then((dom.HttpRequest value) {
485487
// TODO: Uncomment after apps migrate off of this class.
486488
// assert(value.status >= 200 && value.status < 300);
487489

@@ -535,15 +537,16 @@ class Http {
535537
String data,
536538
Map<String, dynamic> params,
537539
Map<String, String> headers,
540+
withCredentials: false,
538541
xsrfHeaderName,
539542
xsrfCookieName,
540543
interceptors,
541544
cache,
542545
timeout
543-
}) => call(method: 'GET', url: url, data: data, params: params,
544-
headers: headers, xsrfHeaderName: xsrfHeaderName,
545-
xsrfCookieName: xsrfCookieName, interceptors: interceptors,
546-
cache: cache, timeout: timeout);
546+
}) => call(method: 'GET', url: url, data: data, params: params, headers: headers,
547+
withCredentials: withCredentials, xsrfHeaderName: xsrfHeaderName,
548+
xsrfCookieName: xsrfCookieName, interceptors: interceptors, cache: cache,
549+
timeout: timeout);
547550

548551
/**
549552
* Shortcut method for DELETE requests. See [call] for a complete description
@@ -553,15 +556,16 @@ class Http {
553556
String data,
554557
Map<String, dynamic> params,
555558
Map<String, String> headers,
559+
withCredentials: false,
556560
xsrfHeaderName,
557561
xsrfCookieName,
558562
interceptors,
559563
cache,
560564
timeout
561-
}) => call(method: 'DELETE', url: url, data: data, params: params,
562-
headers: headers, xsrfHeaderName: xsrfHeaderName,
563-
xsrfCookieName: xsrfCookieName, interceptors: interceptors,
564-
cache: cache, timeout: timeout);
565+
}) => call(method: 'DELETE', url: url, data: data, params: params, headers: headers,
566+
withCredentials: withCredentials, xsrfHeaderName: xsrfHeaderName,
567+
xsrfCookieName: xsrfCookieName, interceptors: interceptors, cache: cache,
568+
timeout: timeout);
565569

566570
/**
567571
* Shortcut method for HEAD requests. See [call] for a complete description
@@ -571,15 +575,16 @@ class Http {
571575
String data,
572576
Map<String, dynamic> params,
573577
Map<String, String> headers,
578+
withCredentials: false,
574579
xsrfHeaderName,
575580
xsrfCookieName,
576581
interceptors,
577582
cache,
578583
timeout
579-
}) => call(method: 'HEAD', url: url, data: data, params: params,
580-
headers: headers, xsrfHeaderName: xsrfHeaderName,
581-
xsrfCookieName: xsrfCookieName, interceptors: interceptors,
582-
cache: cache, timeout: timeout);
584+
}) => call(method: 'HEAD', url: url, data: data, params: params, headers: headers,
585+
withCredentials: withCredentials, xsrfHeaderName: xsrfHeaderName,
586+
xsrfCookieName: xsrfCookieName, interceptors: interceptors, cache: cache,
587+
timeout: timeout);
583588

584589
/**
585590
* Shortcut method for PUT requests. See [call] for a complete description
@@ -588,15 +593,16 @@ class Http {
588593
async.Future<HttpResponse> put(String url, String data, {
589594
Map<String, dynamic> params,
590595
Map<String, String> headers,
596+
withCredentials: false,
591597
xsrfHeaderName,
592598
xsrfCookieName,
593599
interceptors,
594600
cache,
595601
timeout
596-
}) => call(method: 'PUT', url: url, data: data, params: params,
597-
headers: headers, xsrfHeaderName: xsrfHeaderName,
598-
xsrfCookieName: xsrfCookieName, interceptors: interceptors,
599-
cache: cache, timeout: timeout);
602+
}) => call(method: 'PUT', url: url, data: data, params: params, headers: headers,
603+
withCredentials: withCredentials, xsrfHeaderName: xsrfHeaderName,
604+
xsrfCookieName: xsrfCookieName, interceptors: interceptors, cache: cache,
605+
timeout: timeout);
600606

601607
/**
602608
* Shortcut method for POST requests. See [call] for a complete description
@@ -605,15 +611,16 @@ class Http {
605611
async.Future<HttpResponse> post(String url, String data, {
606612
Map<String, dynamic> params,
607613
Map<String, String> headers,
614+
withCredentials: false,
608615
xsrfHeaderName,
609616
xsrfCookieName,
610617
interceptors,
611618
cache,
612619
timeout
613-
}) => call(method: 'POST', url: url, data: data, params: params,
614-
headers: headers, xsrfHeaderName: xsrfHeaderName,
615-
xsrfCookieName: xsrfCookieName, interceptors: interceptors,
616-
cache: cache, timeout: timeout);
620+
}) => call(method: 'POST', url: url, data: data, params: params, headers: headers,
621+
withCredentials: withCredentials, xsrfHeaderName: xsrfHeaderName,
622+
xsrfCookieName: xsrfCookieName, interceptors: interceptors, cache: cache,
623+
timeout: timeout);
617624

618625
/**
619626
* Shortcut method for JSONP requests. See [call] for a complete description
@@ -623,15 +630,16 @@ class Http {
623630
String data,
624631
Map<String, dynamic> params,
625632
Map<String, String> headers,
633+
withCredentials: false,
626634
xsrfHeaderName,
627635
xsrfCookieName,
628636
interceptors,
629637
cache,
630638
timeout
631-
}) => call(method: 'JSONP', url: url, data: data, params: params,
632-
headers: headers, xsrfHeaderName: xsrfHeaderName,
633-
xsrfCookieName: xsrfCookieName, interceptors: interceptors,
634-
cache: cache, timeout: timeout);
639+
}) => call(method: 'JSONP', url: url, data: data, params: params, headers: headers,
640+
withCredentials: withCredentials, xsrfHeaderName: xsrfHeaderName,
641+
xsrfCookieName: xsrfCookieName, interceptors: interceptors, cache: cache,
642+
timeout: timeout);
635643

636644
/**
637645
* Parse raw headers into key-value object

test/core_dom/http_spec.dart

+100
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,69 @@ void main() {
9898
flush();
9999
}));
100100

101+
describe('backend', () {
102+
beforeEachModule((Module module) {
103+
FakeBackend fakeBackend = new FakeBackend();
104+
module.bind(HttpBackend, toFactory: (i) => fakeBackend);
105+
module.bind(FakeBackend, toFactory: (i) => i.get(HttpBackend));
106+
});
107+
108+
it('should pass on withCredentials to backend and use GET as default method',
109+
async((FakeBackend backend) {
110+
http(url: '/url', method: 'GET', withCredentials: true);
111+
microLeap();
112+
expect(backend.url).toEqual('/url');
113+
expect(backend.method).toEqual('GET');
114+
expect(backend.withCredentials).toBeTruthy();
115+
}));
116+
117+
it('get should pass on withCredentials to backend', async((FakeBackend backend) {
118+
http.get('/url', withCredentials: true);
119+
microLeap();
120+
expect(backend.method).toEqual('GET');
121+
expect(backend.withCredentials).toBeTruthy();
122+
}));
123+
124+
it('delete should pass on withCredentials to backend', async((FakeBackend backend) {
125+
http.delete('/url', withCredentials: true);
126+
microLeap();
127+
expect(backend.method).toEqual('DELETE');
128+
expect(backend.withCredentials).toBeTruthy();
129+
}));
130+
131+
it('head should pass on withCredentials to backend', async((FakeBackend backend) {
132+
http.head('/url', withCredentials: true);
133+
microLeap();
134+
expect(backend.method).toEqual('HEAD');
135+
expect(backend.withCredentials).toBeTruthy();
136+
}));
137+
138+
it('put should pass on data and withCredentials to backend', async((FakeBackend backend) {
139+
var mockData = "mockData";
140+
http.put('/url', mockData, withCredentials: true);
141+
microLeap();
142+
expect(backend.sendData).toEqual(mockData);
143+
expect(backend.method).toEqual('PUT');
144+
expect(backend.withCredentials).toBeTruthy();
145+
}));
146+
147+
it('post should pass on data and withCredentials to backend', async((FakeBackend backend) {
148+
var mockData = "mockData";
149+
http.post('/url', mockData, withCredentials: true);
150+
microLeap();
151+
expect(backend.sendData).toEqual(mockData);
152+
expect(backend.method).toEqual('POST');
153+
expect(backend.withCredentials).toBeTruthy();
154+
}));
155+
156+
it('jsonp should pass withCredentials to backend', async((FakeBackend backend) {
157+
http.jsonp('/url', withCredentials: true);
158+
microLeap();
159+
expect(backend.method).toEqual('JSONP');
160+
expect(backend.withCredentials).toBeTruthy();
161+
}));
162+
});
163+
101164

102165
describe('params', () {
103166
it('should do basic request with params and encode', async(() {
@@ -1356,3 +1419,40 @@ class FakeFile implements File {
13561419
Blob slice([int start, int end, String contentType]) => null;
13571420
int get lastModified => new DateTime.now().millisecondsSinceEpoch;
13581421
}
1422+
1423+
class FakeBackend extends Mock implements HttpBackend {
1424+
1425+
String url;
1426+
String method;
1427+
bool withCredentials;
1428+
String responseType;
1429+
String mimeType;
1430+
Map<String, String> requestHeaders;
1431+
dynamic sendData;
1432+
1433+
Future<HttpRequest> request(String url, {
1434+
String method,
1435+
bool withCredentials,
1436+
String responseType,
1437+
String mimeType,
1438+
Map<String, String> requestHeaders,
1439+
sendData,
1440+
void onProgress(ProgressEvent e)}) {
1441+
this.url = url;
1442+
this.method = method;
1443+
this.withCredentials = withCredentials;
1444+
this.responseType = responseType;
1445+
this.mimeType = mimeType;
1446+
this.requestHeaders = requestHeaders;
1447+
this.sendData = sendData;
1448+
HttpRequest request = new HttpRequest();
1449+
return new Future.value(new HttpRequest());
1450+
}
1451+
}
1452+
1453+
class FakeHttpRequest extends Mock implements HttpRequest {
1454+
FakeHttpRequest() {
1455+
when(callsTo('get status')).thenReturn(200);
1456+
when(callsTo('get responseText')).thenReturn('Fake Request');
1457+
}
1458+
}

0 commit comments

Comments
 (0)