Works
This commit is contained in:
parent
074c2f8511
commit
a2dfb17586
15 changed files with 313 additions and 1 deletions
44
.gitignore
vendored
44
.gitignore
vendored
|
@ -25,3 +25,47 @@ doc/api/
|
|||
# Don't commit pubspec lock file
|
||||
# (Library packages only! Remove pattern if developing an application package)
|
||||
pubspec.lock
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff:
|
||||
.idea/workspace.xml
|
||||
.idea/tasks.xml
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
.idea/dataSources/
|
||||
.idea/dataSources.ids
|
||||
.idea/dataSources.xml
|
||||
.idea/dataSources.local.xml
|
||||
.idea/sqlDataSources.xml
|
||||
.idea/dynamic.xml
|
||||
.idea/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
.idea/gradle.xml
|
||||
.idea/libraries
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
.idea/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
|
|
17
.idea/angel_proxy.iml
Normal file
17
.idea/angel_proxy.iml
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/packages" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Dart SDK" level="application" />
|
||||
<orderEntry type="library" name="Dart Packages" level="project" />
|
||||
</component>
|
||||
</module>
|
7
.idea/jsLibraryMappings.xml
Normal file
7
.idea/jsLibraryMappings.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptLibraryMappings">
|
||||
<includedPredefinedLibrary name="ECMAScript 6" />
|
||||
<includedPredefinedLibrary name="Node.js Core" />
|
||||
</component>
|
||||
</project>
|
28
.idea/misc.xml
Normal file
28
.idea/misc.xml
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptSettings">
|
||||
<option name="languageLevel" value="ES6" />
|
||||
</component>
|
||||
<component name="ProjectInspectionProfilesVisibleTreeState">
|
||||
<entry key="Project Default">
|
||||
<profile-state>
|
||||
<expanded-state>
|
||||
<State>
|
||||
<id />
|
||||
</State>
|
||||
<State>
|
||||
<id>General</id>
|
||||
</State>
|
||||
<State>
|
||||
<id>XPath</id>
|
||||
</State>
|
||||
</expanded-state>
|
||||
<selected-state>
|
||||
<State>
|
||||
<id>AngularJS</id>
|
||||
</State>
|
||||
</selected-state>
|
||||
</profile-state>
|
||||
</entry>
|
||||
</component>
|
||||
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/angel_proxy.iml" filepath="$PROJECT_DIR$/.idea/angel_proxy.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
.idea/runConfigurations/Basic_Tests.xml
Normal file
6
.idea/runConfigurations/Basic_Tests.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Basic Tests" type="DartTestRunConfigurationType" factoryName="Dart Test" singleton="true">
|
||||
<option name="filePath" value="$PROJECT_DIR$/test/basic_test.dart" />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
1
.travis.yml
Normal file
1
.travis.yml
Normal file
|
@ -0,0 +1 @@
|
|||
language: dart
|
24
README.md
24
README.md
|
@ -1,2 +1,24 @@
|
|||
# angel_proxy
|
||||
Middleware to forward requests to another server (i.e. pub serve)
|
||||
|
||||
![version 1.0.0-dev](https://img.shields.io/badge/version-1.0.0--dev-red.svg)
|
||||
![build status](https://travis-ci.org/angel-dart/proxy.svg?branch=master)
|
||||
|
||||
Angel middleware to forward requests to another server (i.e. pub serve).
|
||||
Based on [this repo](https://github.com/agilord/http_request_proxy).
|
||||
|
||||
```dart
|
||||
import 'package:angel_proxy/angel_proxy.dart';
|
||||
|
||||
main() async {
|
||||
// ...
|
||||
|
||||
// Forward requests instead of serving statically
|
||||
await app.configure(new ProxyLayer('localhost', 3000));
|
||||
|
||||
// Or, use one for pub serve.
|
||||
//
|
||||
// This automatically deactivates itself if the app is
|
||||
// in production.
|
||||
await app.configure(new PubServeLayer());
|
||||
}
|
||||
```
|
4
lib/angel_proxy.dart
Normal file
4
lib/angel_proxy.dart
Normal file
|
@ -0,0 +1,4 @@
|
|||
library angel_proxy;
|
||||
|
||||
export 'src/proxy_layer.dart';
|
||||
export 'src/pub_serve_layer.dart';
|
83
lib/src/proxy_layer.dart
Normal file
83
lib/src/proxy_layer.dart
Normal file
|
@ -0,0 +1,83 @@
|
|||
import 'dart:io';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
|
||||
final RegExp _param = new RegExp(r':([A-Za-z0-9_]+)(\((.+)\))?');
|
||||
final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)');
|
||||
|
||||
String _pathify(String path) {
|
||||
var p = path.replaceAll(_straySlashes, '');
|
||||
|
||||
Map<String, String> replace = {};
|
||||
|
||||
for (Match match in _param.allMatches(p)) {
|
||||
if (match[3] != null) replace[match[0]] = ':${match[1]}';
|
||||
}
|
||||
|
||||
replace.forEach((k, v) {
|
||||
p = p.replaceAll(k, v);
|
||||
});
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
class ProxyLayer {
|
||||
HttpClient _client;
|
||||
String _prefix;
|
||||
final bool debug;
|
||||
final String host, mapTo, publicPath;
|
||||
final int port;
|
||||
|
||||
ProxyLayer(this.host, this.port,
|
||||
{this.debug: false,
|
||||
this.mapTo: '/',
|
||||
this.publicPath: '/',
|
||||
SecurityContext securityContext}) {
|
||||
_client = new HttpClient(context: securityContext);
|
||||
_prefix = publicPath.replaceAll(_straySlashes, '');
|
||||
}
|
||||
|
||||
call(AngelBase app) async => serve(app);
|
||||
|
||||
_printDebug(msg) {
|
||||
if (debug == true) print(msg);
|
||||
}
|
||||
|
||||
void close() => _client.close(force: true);
|
||||
|
||||
void serve(Router router) {
|
||||
_printDebug('Public path prefix: "$_prefix"');
|
||||
|
||||
handler(RequestContext req, ResponseContext res) async {
|
||||
var path = req.path.replaceAll(_straySlashes, '');
|
||||
|
||||
return serveFile(path, req, res);
|
||||
}
|
||||
|
||||
router.get('$publicPath/*', handler);
|
||||
router.get(publicPath, (req, res) => serveFile('', req, res));
|
||||
}
|
||||
|
||||
serveFile(String path, RequestContext req, ResponseContext res) async {
|
||||
var _path = path;
|
||||
|
||||
if (_prefix.isNotEmpty) {
|
||||
_path = path.replaceAll(new RegExp('^' + _pathify(_prefix)), '');
|
||||
}
|
||||
|
||||
res
|
||||
..willCloseItself = true
|
||||
..end();
|
||||
|
||||
// Create mapping
|
||||
final mapping = '$mapTo/$_path'.replaceAll(_straySlashes, '');
|
||||
final rq = await _client.open(req.method, host, port, mapping);
|
||||
await rq.addStream(req.io);
|
||||
final HttpClientResponse rs = await rq.close();
|
||||
final HttpResponse r = res.io;
|
||||
r.statusCode = rs.statusCode;
|
||||
r.headers.contentType = rs.headers.contentType;
|
||||
await r.addStream(rs);
|
||||
await r.flush();
|
||||
await r.close();
|
||||
}
|
||||
}
|
21
lib/src/pub_serve_layer.dart
Normal file
21
lib/src/pub_serve_layer.dart
Normal file
|
@ -0,0 +1,21 @@
|
|||
import 'dart:io';
|
||||
import 'package:angel_route/angel_route.dart';
|
||||
import 'proxy_layer.dart';
|
||||
|
||||
class PubServeLayer extends ProxyLayer {
|
||||
PubServeLayer(
|
||||
{bool debug: false,
|
||||
String host: 'localhost',
|
||||
String mapTo: '/',
|
||||
int port: 8888,
|
||||
String publicPath: '/'})
|
||||
: super(host, port, debug: debug, mapTo: mapTo, publicPath: publicPath);
|
||||
|
||||
@override
|
||||
void serve(Router router) {
|
||||
if (Platform.environment['ANGEL_ENV'] == 'production') {
|
||||
// Auto-deactivate in production ;)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
12
pubspec.yaml
Normal file
12
pubspec.yaml
Normal file
|
@ -0,0 +1,12 @@
|
|||
name: angel_proxy
|
||||
description: Angel middleware to forward requests to another server (i.e. pub serve).
|
||||
version: 1.0.0-dev
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/proxy
|
||||
environment:
|
||||
sdk: ">=1.18.0"
|
||||
dependencies:
|
||||
angel_framework: ^1.0.0-dev
|
||||
dev_dependencies:
|
||||
http: ^0.11.3
|
||||
test: ^0.12.15
|
43
test/basic_test.dart
Normal file
43
test/basic_test.dart
Normal file
|
@ -0,0 +1,43 @@
|
|||
import 'dart:io';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_proxy/angel_proxy.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:test/test.dart';
|
||||
import 'common.dart';
|
||||
|
||||
main() {
|
||||
Angel app;
|
||||
http.Client client = new http.Client();
|
||||
HttpServer server, testServer;
|
||||
String url;
|
||||
|
||||
setUp(() async {
|
||||
app = new Angel();
|
||||
|
||||
testServer = await testApp().startServer();
|
||||
await app.configure(new ProxyLayer(testServer.address.address, testServer.port, publicPath: '/proxy'));
|
||||
await app.configure(new ProxyLayer(testServer.address.address, testServer.port, mapTo: '/foo'));
|
||||
|
||||
server = await app.startServer();
|
||||
url = 'http://${server.address.address}:${server.port}';
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
await testServer.close(force: true);
|
||||
await server.close(force: true);
|
||||
app = null;
|
||||
url = null;
|
||||
});
|
||||
|
||||
test('publicPath', () async {
|
||||
final response = await client.get('$url/proxy/hello');
|
||||
print('Response: ${response.body}');
|
||||
expect(response.body, equals('"world"'));
|
||||
});
|
||||
|
||||
test('mapTo', () async {
|
||||
final response = await client.get('$url/bar');
|
||||
print('Response: ${response.body}');
|
||||
expect(response.body, equals('"baz"'));
|
||||
});
|
||||
}
|
10
test/common.dart
Normal file
10
test/common.dart
Normal file
|
@ -0,0 +1,10 @@
|
|||
import 'package:angel_framework/angel_framework.dart';
|
||||
|
||||
Angel testApp() {
|
||||
final app = new Angel();
|
||||
|
||||
app.get('/hello', 'world');
|
||||
app.get('/foo/bar', 'baz');
|
||||
|
||||
return app;
|
||||
}
|
Loading…
Reference in a new issue