kinda working
diff --git a/lib/shelf_proxy.dart b/lib/shelf_proxy.dart
index 3c7f8bf..6adc1a1 100644
--- a/lib/shelf_proxy.dart
+++ b/lib/shelf_proxy.dart
@@ -1 +1,48 @@
 library shelf_proxy;
+
+import 'dart:io';
+
+import 'package:shelf/shelf.dart';
+
+///
+///
+/// Imagine that rootUri is specified as `http://example.com/files`
+///
+/// A request for `/test/sample.html` would result is a request for
+/// `http://example.com/files/test/sample.html`.
+Handler createProxyHandler(Uri rootUri) {
+  assert(rootUri.scheme == 'http' || rootUri.scheme == 'https');
+  assert(rootUri.query == '');
+  assert(rootUri.isAbsolute);
+
+  return (Request request) {
+    // TODO: really need to tear down the client when this is done...
+    var client = new HttpClient();
+
+    var url = _getProxyUrl(rootUri, request.url);
+
+    return client.openUrl(request.method, url).then((ioRequest) {
+      return ioRequest.close();
+    }).then((ioResponse) {
+
+      return new Response(ioResponse.statusCode, body: ioResponse);
+    });
+  };
+}
+
+Uri _getProxyUrl(Uri proxyRoot, Uri requestUrl) {
+  assert(proxyRoot.scheme == 'http' || proxyRoot.scheme == 'https');
+  assert(proxyRoot.query == '');
+  assert(proxyRoot.isAbsolute);
+  assert(!requestUrl.isAbsolute);
+
+  var updatedPath = proxyRoot.pathSegments.toList()
+      ..addAll(requestUrl.pathSegments);
+
+  return new Uri(scheme: proxyRoot.scheme,
+      userInfo: proxyRoot.userInfo,
+      host: proxyRoot.host,
+      port: proxyRoot.port,
+      pathSegments: updatedPath,
+      query: requestUrl.query);
+}
diff --git a/lib/src/util.dart b/lib/src/util.dart
new file mode 100644
index 0000000..6085013
--- /dev/null
+++ b/lib/src/util.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2014, 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.
+
+library shelf_proxy.util;
+
+import 'dart:async';
+
+import 'package:stack_trace/stack_trace.dart';
+
+/// Like [Future.sync], but wraps the Future in [Chain.track] as well.
+Future syncFuture(callback()) => Chain.track(new Future.sync(callback));
diff --git a/pubspec.yaml b/pubspec.yaml
index 8e6eb12..58f62fa 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -13,3 +13,4 @@
   hop_unittest: '>=0.1.0 <0.2.0'
   path: '>=1.1.0 <2.0.0'
   scheduled_test: '>=0.11.0 <0.12.0'
+  shelf_static: any
diff --git a/test/harness_console.dart b/test/harness_console.dart
index d04e002..bb1c3c3 100644
--- a/test/harness_console.dart
+++ b/test/harness_console.dart
@@ -2,6 +2,12 @@
 
 import 'package:scheduled_test/scheduled_test.dart';
 
+import 'proxy_test.dart' as proxy;
+import 'static_file_test.dart' as static_file;
+
 void main() {
   groupSep = ' - ';
+
+  proxy.main();
+  static_file.main();
 }
diff --git a/test/proxy_test.dart b/test/proxy_test.dart
new file mode 100644
index 0000000..1ad5baf
--- /dev/null
+++ b/test/proxy_test.dart
@@ -0,0 +1,93 @@
+library shelf_proxy.proxy_test;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:scheduled_test/scheduled_test.dart';
+import 'package:shelf/shelf.dart';
+import 'package:shelf/shelf_io.dart' as shelf_io;
+import 'package:shelf_proxy/shelf_proxy.dart';
+
+import 'test_util.dart';
+
+void main() {
+  test('root', () {
+    _scheduleServer(_handler);
+
+    schedule(() {
+      var url = new Uri.http('localhost:$_serverPort', '');
+      var handler = createProxyHandler(url);
+
+      return makeRequest(handler, '/').then((response) {
+        expect(response.statusCode, HttpStatus.OK);
+        expect(response.readAsString(), completion('root with slash'));
+      });
+    });
+  });
+
+  test('bar', () {
+    _scheduleServer(_handler);
+
+    schedule(() {
+      var url = new Uri.http('localhost:$_serverPort', '');
+      var handler = createProxyHandler(url);
+
+      return makeRequest(handler, '/bar').then((response) {
+        expect(response.statusCode, HttpStatus.OK);
+        expect(response.readAsString(), completion('bar'));
+      });
+    });
+  });
+
+  test('bar/', () {
+    _scheduleServer(_handler);
+
+    schedule(() {
+      var url = new Uri.http('localhost:$_serverPort', '');
+      var handler = createProxyHandler(url);
+
+      return makeRequest(handler, '/bar/').then((response) {
+        expect(response.statusCode, HttpStatus.OK);
+        expect(response.readAsString(), completion('bar with slash'));
+      });
+    });
+  });
+}
+
+Response _handler(Request request) {
+  if (request.method != 'GET') {
+    return new Response.forbidden("I don't like method ${request.method}.");
+  }
+
+  String content;
+  switch (request.url.path) {
+    case '':
+      content = 'root';
+      break;
+    case '/':
+      content = 'root with slash';
+      break;
+    case '/bar':
+      content = 'bar';
+      break;
+    case '/bar/':
+      content = 'bar with slash';
+      break;
+    default:
+      return new Response.notFound("I don't like '${request.url.path}'.");
+  }
+  return new Response.ok(content);
+}
+
+int _serverPort;
+
+Future _scheduleServer(Handler handler) {
+  return schedule(() => shelf_io.serve(handler, 'localhost', 0).then((server) {
+    currentSchedule.onComplete.schedule(() {
+      _serverPort = null;
+      return server.close(force: true);
+    });
+
+    _serverPort = server.port;
+  }));
+}
diff --git a/test/static_file_test.dart b/test/static_file_test.dart
new file mode 100644
index 0000000..2705f23
--- /dev/null
+++ b/test/static_file_test.dart
@@ -0,0 +1,46 @@
+library shelf_proxy.static_file_test;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:scheduled_test/scheduled_test.dart';
+import 'package:shelf/shelf.dart';
+import 'package:shelf/shelf_io.dart' as shelf_io;
+import 'package:shelf_static/shelf_static.dart' as shelf_static;
+import 'package:shelf_proxy/shelf_proxy.dart';
+
+import 'test_util.dart';
+
+void main() {
+  test('foo', () {
+    _scheduleServer(_handler);
+
+    schedule(() {
+      var url = new Uri.http('localhost:$_serverPort', '');
+      var handler = createProxyHandler(url);
+
+      return makeRequest(handler, '/').then((response) {
+        expect(response.statusCode, HttpStatus.OK);
+        expect(response.readAsString(),
+            completion(contains('<title>shelf_static</title>')));
+        expect(response.contentLength, isNotNull);
+      });
+    });
+  });
+}
+
+final _handler = shelf_static.createStaticHandler('test/test_files',
+    defaultDocument: 'index.html');
+
+int _serverPort;
+
+Future _scheduleServer(Handler handler) {
+  return schedule(() => shelf_io.serve(handler, 'localhost', 0).then((server) {
+    currentSchedule.onComplete.schedule(() {
+      _serverPort = null;
+      return server.close(force: true);
+    });
+
+    _serverPort = server.port;
+  }));
+}
diff --git a/test/test_files/dart.png b/test/test_files/dart.png
new file mode 100644
index 0000000..fd6de2a
--- /dev/null
+++ b/test/test_files/dart.png
Binary files differ
diff --git a/test/test_files/favicon.ico b/test/test_files/favicon.ico
new file mode 100644
index 0000000..e605972
--- /dev/null
+++ b/test/test_files/favicon.ico
Binary files differ
diff --git a/test/test_files/index.html b/test/test_files/index.html
new file mode 100644
index 0000000..7bf28d1
--- /dev/null
+++ b/test/test_files/index.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+
+<html>
+  <head>
+  	<meta charset="utf-8">
+    <title>shelf_static</title>
+  </head>
+  <body>
+    <h1>Hello, shelf_static!</h1>
+    <img src='dart.png' alt='Dart logo' width='150' height='151'>
+  </body>
+</html>
diff --git a/test/test_util.dart b/test/test_util.dart
new file mode 100644
index 0000000..eedd672
--- /dev/null
+++ b/test/test_util.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2014, 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.
+
+library shelf_proxy.test_util;
+
+import 'dart:async';
+
+import 'package:path/path.dart' as p;
+import 'package:shelf/shelf.dart';
+import 'package:shelf_proxy/src/util.dart';
+
+final p.Context _ctx = p.url;
+
+/// Makes a simple GET request to [handler] and returns the result.
+Future<Response> makeRequest(Handler handler, String path,
+    {String scriptName, Map<String, String> headers}) {
+  var rootedHandler = _rootHandler(scriptName, handler);
+  return syncFuture(() => rootedHandler(_fromPath(path, headers)));
+}
+
+Request _fromPath(String path, Map<String, String> headers) =>
+    new Request('GET', Uri.parse('http://localhost' + path), headers: headers);
+
+Handler _rootHandler(String scriptName, Handler handler) {
+  if (scriptName == null || scriptName.isEmpty) {
+    return handler;
+  }
+
+  if (!scriptName.startsWith('/')) {
+    throw new ArgumentError('scriptName must start with "/" or be empty');
+  }
+
+  return (Request request) {
+    if (!_ctx.isWithin(scriptName, request.requestedUri.path)) {
+      return new Response.notFound('not found');
+    }
+    assert(request.scriptName.isEmpty);
+
+    var relativeRequest = request.change(scriptName: scriptName);
+
+    return handler(relativeRequest);
+  };
+}