// Copyright 2014 The Flutter Authors. 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:shelf/shelf.dart' as shelf; import 'package:shelf_proxy/shelf_proxy.dart'; import '../base/logger.dart'; import '../web/devfs_proxy.dart'; const _kLogEntryPrefix = '[proxyMiddleware]'; /// Creates a new [shelf.Request] by proxying an [originalRequest] to a [finalTargetUrl]. /// /// The new request will have the same method, headers, body, and context as the /// [originalRequest], but its URL will be set to [finalTargetUrl]. shelf.Request proxyRequest(shelf.Request originalRequest, Uri finalTargetUrl) { return shelf.Request( originalRequest.method, finalTargetUrl, headers: originalRequest.headers, body: originalRequest.read(), context: originalRequest.context, ); } /// Iterates through the provided [effectiveProxy] rules for each incoming [shelf.Request]. /// /// If a rule's pattern matches the request's path, the request is /// rewritten and forwarded to the target URI defined in the matching [ProxyRule]. /// Otherwise, the request is passed to the next handler in the Shelf stack. Future _applyProxyRules( shelf.Request request, List effectiveProxy, shelf.Handler innerHandler, Logger logger, ) async { final String requestPath = request.requestedUri.path; for (final rule in effectiveProxy) { if (!rule.matches(requestPath)) { continue; } final shelf.Handler handler = proxyHandler(rule.targetUri, proxyName: 'flutter_tools'); final Uri finalTargetUrl = rule.finalTargetUri(request.requestedUri); try { final shelf.Request proxyBackendRequest = proxyRequest(request, finalTargetUrl); final shelf.Response proxyResponse = await handler(proxyBackendRequest); logger.printStatus('$_kLogEntryPrefix Matched "$requestPath". Requesting "$finalTargetUrl"'); logger.printTrace('$_kLogEntryPrefix Matched with proxy rule: $rule'); return proxyResponse; } on Exception catch (e) { logger.printError('$_kLogEntryPrefix Error for $finalTargetUrl: $e. Allowing fall-through.'); return innerHandler(request); } } return innerHandler(request); } /// Creates a [shelf.Middleware] that proxies requests based on a list of [ProxyRule]s. shelf.Middleware proxyMiddleware(List effectiveProxy, Logger logger) { return (shelf.Handler innerHandler) { return (shelf.Request request) async { return _applyProxyRules(request, effectiveProxy, innerHandler, logger); }; }; }