diff --git a/lib/src/pipeline.dart b/lib/src/pipeline.dart new file mode 100644 index 0000000000..d7fe1e4d70 --- /dev/null +++ b/lib/src/pipeline.dart @@ -0,0 +1,50 @@ +k// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'client.dart'; +import 'handler.dart'; +import 'middleware.dart'; + +/// A helper that makes it easy to compose a set of [Middleware] and a +/// [Client]. +/// +/// var client = const Pipeline() +/// .addMiddleware(loggingMiddleware) +/// .addMiddleware(basicAuthMiddleware) +/// .addClient(new Client()); +class Pipeline { + /// The outer pipeline. + final Pipeline _parent; + + /// The [Middleware] that is invoked at this stage. + final Middleware _middleware; + + const Pipeline() + : _parent = null, + _middleware = null; + + Pipeline._(this._parent, this._middleware); + + /// Returns a new [Pipeline] with [middleware] added to the existing set of + /// [Middleware]. + /// + /// [middleware] will be the last [Middleware] to process a request and + /// the first to process a response. + Pipeline addMiddleware(Middleware middleware) => + new Pipeline._(this, middleware); + + /// Returns a new [Client] with [client] as the final processor of a + /// [Request] if all of the middleware in the pipeline have passed the request + /// through. + Client addClient(Client client) => + _middleware == null ? client : _parent.addClient(_middleware(client)); + + /// Returns a new [Client] with [handler] as the final processor of a + /// [Request] if all of the middleware in the pipeline have passed the request + /// through. + Client addHandler(Handler handler) => addClient(new Client.handler(handler)); + + /// Exposes this pipeline of [Middleware] as a single middleware instance. + Middleware get middleware => addClient; +} diff --git a/test/pipeline_test.dart b/test/pipeline_test.dart new file mode 100644 index 0000000000..cbde3a62e3 --- /dev/null +++ b/test/pipeline_test.dart @@ -0,0 +1,112 @@ +// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:test/test.dart'; + +import 'package:http/http.dart'; + +void main() { + test('compose middleware with Pipeline', () async { + var accessLocation = 0; + + var middlewareA = createMiddleware(requestHandler: (request) async { + expect(accessLocation, 0); + accessLocation = 1; + return request; + }, responseHandler: (response) async { + expect(accessLocation, 4); + accessLocation = 5; + return response; + }); + + var middlewareB = createMiddleware(requestHandler: (request) async { + expect(accessLocation, 1); + accessLocation = 2; + return request; + }, responseHandler: (response) async { + expect(accessLocation, 3); + accessLocation = 4; + return response; + }); + + var client = const Pipeline() + .addMiddleware(middlewareA) + .addMiddleware(middlewareB) + .addClient(new Client.handler((request) async { + expect(accessLocation, 2); + accessLocation = 3; + return new Response(Uri.parse('dart:http'), 200); + })); + + var response = await client.get(Uri.parse('dart:http')); + + expect(response, isNotNull); + expect(accessLocation, 5); + }); + + test('Pipeline can be used as middleware', () async { + int accessLocation = 0; + + var middlewareA = createMiddleware(requestHandler: (request) async { + expect(accessLocation, 0); + accessLocation = 1; + return request; + }, responseHandler: (response) async { + expect(accessLocation, 4); + accessLocation = 5; + return response; + }); + + var middlewareB = createMiddleware(requestHandler: (request) async { + expect(accessLocation, 1); + accessLocation = 2; + return request; + }, responseHandler: (response) async { + expect(accessLocation, 3); + accessLocation = 4; + return response; + }); + + var innerPipeline = + const Pipeline().addMiddleware(middlewareA).addMiddleware(middlewareB); + + var client = const Pipeline() + .addMiddleware(innerPipeline.middleware) + .addClient(new Client.handler((request) async { + expect(accessLocation, 2); + accessLocation = 3; + return new Response(Uri.parse('dart:http'), 200); + })); + + var response = await client.get(Uri.parse('dart:http')); + + expect(response, isNotNull); + expect(accessLocation, 5); + }); + + test('Pipeline calls close on all middleware', () { + int accessLocation = 0; + + var middlewareA = createMiddleware(onClose: () { + expect(accessLocation, 0); + accessLocation = 1; + }); + + var middlewareB = createMiddleware(onClose: () { + expect(accessLocation, 1); + accessLocation = 2; + }); + + var client = const Pipeline() + .addMiddleware(middlewareA) + .addMiddleware(middlewareB) + .addClient(new Client.handler((request) async => null, onClose: () { + expect(accessLocation, 2); + accessLocation = 3; + })); + + client.close(); + expect(accessLocation, 3); + }); +}