Fix CORS headers for the API (#494)

diff --git a/example/pubspec.lock b/example/pubspec.lock
index 809bcdc..06aee1b 100644
--- a/example/pubspec.lock
+++ b/example/pubspec.lock
@@ -84,14 +84,14 @@
       name: build_runner
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.8.1"
+    version: "1.9.0"
   build_runner_core:
     dependency: transitive
     description:
       name: build_runner_core
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "5.0.0"
+    version: "5.1.0"
   build_web_compilers:
     dependency: "direct dev"
     description:
@@ -175,7 +175,7 @@
       name: dart_style
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.3.4"
+    version: "1.3.5"
   fixnum:
     dependency: transitive
     description:
@@ -434,7 +434,7 @@
       name: watcher
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.9.7+14"
+    version: "0.9.7+15"
   web_socket_channel:
     dependency: transitive
     description:
diff --git a/example/web/apitest.css b/example/web/apitest.css
deleted file mode 100644
index 3b0729b..0000000
--- a/example/web/apitest.css
+++ /dev/null
@@ -1,59 +0,0 @@
-/* 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. */
-
-body {
-  display: flex;
-  flex-direction: column;
-  margin: 15px;
-  color: #555;
-}
-
-section {
-  margin-top: 20px;
-  padding-top: 6px;
-  border-top: 1px solid #eee;
-  border-width: 2px;
-  padding-left: 16px;
-}
-
-h3 {
-  margin-top: 0;
-  margin-bottom: 8px;
-  margin-left: -16px;
-}
-
-#controls {
-  margin-bottom: 1em;
-}
-
-div.container {
-  display: flex;
-  flex-direction: row;
-}
-
-div.row {
-  margin: 0 0 6px 0;
-}
-
-.editor {
-  flex: 20;
-  display: inline-block;
-  box-shadow: 1px 1px 2px 0px rgba(50, 50, 50, 0.75);
-  margin-right: 16px;
-  height: 300px;
-}
-
-.offset {
-  /*background: #333;*/
-}
-
-.output {
-  flex: 15;
-  display: inline-block;
-  box-shadow: 1px 1px 2px 0px rgba(50, 50, 50, 0.75);
-  height: 300px;
-  white-space: pre-wrap;
-  overflow-y: scroll;
-  font-family: monospace;
-}
diff --git a/example/web/apitest.dart b/example/web/apitest.dart
deleted file mode 100644
index 95e1d3c..0000000
--- a/example/web/apitest.dart
+++ /dev/null
@@ -1,263 +0,0 @@
-// 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 services_server.apitest;
-
-import 'dart:convert';
-import 'dart:html';
-import 'package:codemirror/codemirror.dart';
-import 'services_utils.dart' as utils;
-
-const versions = ['v1', 'v2'];
-
-utils.SanitizingBrowserClient client;
-
-void main() {
-  setupAnalyze();
-  setupAssists();
-  setupCompile();
-  setupCompileDDC();
-  setupComplete();
-  setupDocument();
-  setupFixes();
-  setupVersion();
-}
-
-void _setupClients() {
-  client ??= utils.SanitizingBrowserClient();
-}
-
-void setupAnalyze() {
-  versions.forEach((version) {
-    final editor =
-        createEditor(querySelector('#analyzeSection-$version .editor'));
-    final output = querySelector('#analyzeSection-$version .output');
-    final button =
-        querySelector('#analyzeSection-$version button') as ButtonElement;
-    button.onClick.listen((e) {
-      _setupClients();
-      final source = {'source': editor.getDoc().getValue()};
-      final sw = Stopwatch()..start();
-      client
-          .post(
-            '$_uriBase/dartservices/$version/analyze',
-            encoding: utf8,
-            body: json.encode(source),
-          )
-          .then((response) =>
-              output.text = '${_formatTiming(sw)}${response.body}');
-    });
-  });
-}
-
-void setupAssists() {
-  versions.forEach((version) {
-    final editor =
-        createEditor(querySelector('#assistsSection-$version .editor'));
-    final output = querySelector('#assistsSection-$version .output');
-    final offsetElement = querySelector('#assistsSection-$version .offset');
-    final button =
-        querySelector('#assistsSection-$version button') as ButtonElement;
-    button.onClick.listen((e) {
-      final source = _getSourceRequest(editor);
-      final sw = Stopwatch()..start();
-      client
-          .post(
-            '$_uriBase/dartservices/$version/assists',
-            encoding: utf8,
-            body: json.encode(source),
-          )
-          .then((response) =>
-              output.text = '${_formatTiming(sw)}${response.body}');
-    });
-    offsetElement.text = 'offset ${_getOffset(editor)}';
-    editor.onCursorActivity.listen((_) {
-      offsetElement.text = 'offset ${_getOffset(editor)}';
-    });
-  });
-}
-
-void setupCompile() {
-  versions.forEach((version) {
-    final editor =
-        createEditor(querySelector('#compileSection-$version .editor'));
-    final output = querySelector('#compileSection-$version .output');
-    final button =
-        querySelector('#compileSection-$version button') as ButtonElement;
-    button.onClick.listen((e) {
-      final source = editor.getDoc().getValue();
-
-      _setupClients();
-      final compile = {'source': source};
-      final sw = Stopwatch()..start();
-      client
-          .post(
-            '${_uriBase}/dartservices/$version/compile',
-            encoding: utf8,
-            body: json.encode(compile),
-          )
-          .then((response) =>
-              output.text = '${_formatTiming(sw)}${response.body}');
-    });
-  });
-}
-
-void setupCompileDDC() {
-  versions.forEach((version) {
-    final editor =
-        createEditor(querySelector('#compileDDCSection-$version .editor'));
-    final output = querySelector('#compileDDCSection-$version .output');
-    final button =
-        querySelector('#compileDDCSection-$version button') as ButtonElement;
-    button.onClick.listen((e) {
-      final source = editor.getDoc().getValue();
-
-      _setupClients();
-      final compile = {'source': source};
-      final sw = Stopwatch()..start();
-      client
-          .post(
-            '${_uriBase}/dartservices/$version/compileDDC',
-            encoding: utf8,
-            body: json.encode(compile),
-          )
-          .then((response) =>
-              output.text = '${_formatTiming(sw)}${response.body}');
-    });
-  });
-}
-
-void setupComplete() {
-  versions.forEach((version) {
-    final editor =
-        createEditor(querySelector('#completeSection-$version .editor'));
-    final output = querySelector('#completeSection-$version .output');
-    final offsetElement = querySelector('#completeSection-$version .offset');
-    final button =
-        querySelector('#completeSection-$version button') as ButtonElement;
-    button.onClick.listen((e) {
-      final source = _getSourceRequest(editor);
-      final sw = Stopwatch()..start();
-      client
-          .post(
-            '$_uriBase/dartservices/$version/complete',
-            encoding: utf8,
-            body: json.encode(source),
-          )
-          .then((response) =>
-              output.text = '${_formatTiming(sw)}${response.body}');
-    });
-    offsetElement.text = 'offset ${_getOffset(editor)}';
-    editor.onCursorActivity.listen((_) {
-      offsetElement.text = 'offset ${_getOffset(editor)}';
-    });
-  });
-}
-
-void setupDocument() {
-  versions.forEach((version) {
-    final editor =
-        createEditor(querySelector('#documentSection-$version .editor'));
-    final output = querySelector('#documentSection-$version .output');
-    final offsetElement = querySelector('#documentSection-$version .offset');
-    final button =
-        querySelector('#documentSection-$version button') as ButtonElement;
-    button.onClick.listen((e) {
-      final source = _getSourceRequest(editor);
-      final sw = Stopwatch()..start();
-      client
-          .post(
-            '$_uriBase/dartservices/$version/document',
-            encoding: utf8,
-            body: json.encode(source),
-          )
-          .then((response) =>
-              output.text = '${_formatTiming(sw)}${response.body}');
-    });
-    offsetElement.text = 'offset ${_getOffset(editor)}';
-    editor.onCursorActivity.listen((_) {
-      offsetElement.text = 'offset ${_getOffset(editor)}';
-    });
-  });
-}
-
-void setupFixes() {
-  versions.forEach((version) {
-    final editor =
-        createEditor(querySelector('#fixesSection-$version .editor'));
-    final output = querySelector('#fixesSection-$version .output');
-    final offsetElement = querySelector('#fixesSection-$version .offset');
-    final button =
-        querySelector('#fixesSection-$version button') as ButtonElement;
-    button.onClick.listen((e) {
-      final source = _getSourceRequest(editor);
-      final sw = Stopwatch()..start();
-      client
-          .post(
-            '$_uriBase/dartservices/$version/fixes',
-            encoding: utf8,
-            body: json.encode(source),
-          )
-          .then((response) =>
-              output.text = '${_formatTiming(sw)}${response.body}');
-    });
-    offsetElement.text = 'offset ${_getOffset(editor)}';
-
-    editor.onCursorActivity.listen((_) {
-      offsetElement.text = 'offset ${_getOffset(editor)}';
-    });
-  });
-}
-
-void setupVersion() {
-  versions.forEach((version) {
-    final output = querySelector('#versionSection-$version .output');
-    final button =
-        querySelector('#versionSection-$version button') as ButtonElement;
-    button.onClick.listen((e) {
-      final sw = Stopwatch()..start();
-      client.get('$_uriBase/dartservices/$version/version').then(
-          (response) => output.text = '${_formatTiming(sw)}${response.body}');
-    });
-  });
-}
-
-CodeMirror createEditor(Element element, {String defaultText}) {
-  final options = {
-    'tabSize': 2,
-    'indentUnit': 2,
-    'autoCloseBrackets': true,
-    'matchBrackets': true,
-    'theme': 'zenburn',
-    'mode': 'dart',
-    'value': _text ?? defaultText
-  };
-
-  final editor = CodeMirror.fromElement(element, options: options);
-  editor.refresh();
-  return editor;
-}
-
-String _formatTiming(Stopwatch sw) => '${sw.elapsedMilliseconds}ms\n';
-
-String get _uriBase =>
-    (querySelector('input[type=text]') as InputElement).value;
-
-int _getOffset(CodeMirror editor) {
-  final pos = editor.getDoc().getCursor();
-  return editor.getDoc().indexFromPos(pos);
-}
-
-Map<String, dynamic> _getSourceRequest(CodeMirror editor) => {
-      'source': editor.getDoc().getValue(),
-      'offset': _getOffset(editor),
-    };
-
-final String _text = r'''
-void main() {
-  for (int i = 0; i < 4; i++) {
-    print('hello ${i}');
-  }
-}
-''';
diff --git a/example/web/apitest.html b/example/web/apitest.html
deleted file mode 100644
index d50a911..0000000
--- a/example/web/apitest.html
+++ /dev/null
@@ -1,211 +0,0 @@
-<!DOCTYPE html>
-
-<!-- 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. -->
-
-<html>
-  <head>
-  	<meta charset="utf-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge">
-  	<meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>API Test</title>
-    <link rel="icon" href="favicon.ico">
-    <script defer src="apitest.dart.js"></script>
-    <link href="apitest.css" rel="stylesheet">
-    <link href="packages/codemirror/codemirror.css" rel="stylesheet">
-  </head>
-
-  <body>
-    <script src="packages/codemirror/codemirror.js"></script>
-
-    <h2>Dartpad Server API Tester</h2>
-    <!--<input type="text" value="https://dart-services.appspot.com/">-->
-    <input type="text" value="http://localhost:8082/api">
-
-    <section id="analyzeSection-v1">
-      <h3>api/dartservices/v1/analyze</h3>
-      <div class="row">
-        <button class="post">POST</button>
-      </div>
-      <div class="container">
-        <div class="editor"></div>
-        <div class="output"></div>
-      </div>
-    </section>
-
-    <section id="analyzeSection-v2">
-      <h3>api/dartservices/v2/analyze</h3>
-      <div class="row">
-        <button class="post">POST</button>
-      </div>
-      <div class="container">
-        <div class="editor"></div>
-        <div class="output"></div>
-      </div>
-    </section>
-
-    <section id="assistsSection-v1">
-      <h3>api/dartservices/v1/assists</h3>
-      <div class="row">
-        <button class="post">POST</button>
-        <span class="offset"></span>
-      </div>
-      <div class="container">
-        <div class="editor"></div>
-        <div class="output"></div>
-      </div>
-    </section>
-
-    <section id="assistsSection-v2">
-      <h3>api/dartservices/v2/assists</h3>
-      <div class="row">
-        <button class="post">POST</button>
-        <span class="offset"></span>
-      </div>
-      <div class="container">
-        <div class="editor"></div>
-        <div class="output"></div>
-      </div>
-    </section>
-
-    <section id="compileSection-v1">
-      <h3>api/dartservices/v1/compile</h3>
-      <div class="row">
-        <button class="post">POST</button>
-      </div>
-      <div class="container">
-        <div class="editor"></div>
-        <div class="output"></div>
-      </div>
-    </section>
-
-    <section id="compileSection-v2">
-      <h3>api/dartservices/v2/compile</h3>
-      <div class="row">
-        <button class="post">POST</button>
-      </div>
-      <div class="container">
-        <div class="editor"></div>
-        <div class="output"></div>
-      </div>
-    </section>
-
-    <section id="compileDDCSection-v1">
-      <h3>api/dartservices/v1/compileDDC</h3>
-      <div class="row">
-        <button class="post">POST</button>
-      </div>
-      <div class="container">
-        <div class="editor"></div>
-        <div class="output"></div>
-      </div>
-    </section>
-
-    <section id="compileDDCSection-v2">
-      <h3>api/dartservices/v2/compileDDC</h3>
-      <div class="row">
-        <button class="post">POST</button>
-      </div>
-      <div class="container">
-        <div class="editor"></div>
-        <div class="output"></div>
-      </div>
-    </section>
-
-    <section id="completeSection-v1">
-      <h3>api/dartservices/v1/complete</h3>
-      <div class="row">
-        <button class="post">POST</button>
-        <span class="offset"></span>
-      </div>
-      <div class="container">
-        <div class="editor"></div>
-        <div class="output"></div>
-      </div>
-    </section>
-
-    <section id="completeSection-v2">
-      <h3>api/dartservices/v2/complete</h3>
-      <div class="row">
-        <button class="post">POST</button>
-        <span class="offset"></span>
-      </div>
-      <div class="container">
-        <div class="editor"></div>
-        <div class="output"></div>
-      </div>
-    </section>
-
-    <section id="documentSection-v1">
-      <h3>api/dartservices/v1/document</h3>
-      <div class="row">
-        <button class="post">POST</button>
-        <span class="offset"></span>
-      </div>
-      <div class="container">
-        <div class="editor"></div>
-        <div class="output"></div>
-      </div>
-    </section>
-
-    <section id="documentSection-v2">
-      <h3>api/dartservices/v2/document</h3>
-      <div class="row">
-        <button class="post">POST</button>
-        <span class="offset"></span>
-      </div>
-      <div class="container">
-        <div class="editor"></div>
-        <div class="output"></div>
-      </div>
-    </section>
-
-    <section id="fixesSection-v1">
-      <h3>api/dartservices/v1/fixes</h3>
-      <div class="row">
-        <button class="post">POST</button>
-        <span class="offset"></span>
-      </div>
-      <div class="container">
-        <div class="editor"></div>
-        <div class="output"></div>
-      </div>
-    </section>
-
-    <section id="fixesSection-v2">
-      <h3>api/dartservices/v2/fixes</h3>
-      <div class="row">
-        <button class="post">POST</button>
-        <span class="offset"></span>
-      </div>
-      <div class="container">
-        <div class="editor"></div>
-        <div class="output"></div>
-      </div>
-    </section>
-
-    <section id="versionSection-v1">
-      <h3>api/dartservices/v1/version</h3>
-      <div class="row">
-        <button class="post">GET</button>
-      </div>
-      <div class="container">
-        <div class="editor"></div>
-        <div class="output"></div>
-      </div>
-    </section>
-    
-    <section id="versionSection-v2">
-      <h3>api/dartservices/v2/version</h3>
-      <div class="row">
-        <button class="post">GET</button>
-      </div>
-      <div class="container">
-        <div class="editor"></div>
-        <div class="output"></div>
-      </div>
-    </section>
-    
-  </body>
-</html>
diff --git a/example/web/index.dart b/example/web/index.dart
index 2e39625..b4e0d96 100644
--- a/example/web/index.dart
+++ b/example/web/index.dart
@@ -2,21 +2,252 @@
 // 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 services_server.apitest;
+
 import 'dart:convert';
 import 'dart:html';
+import 'package:codemirror/codemirror.dart';
+import 'package:http/browser_client.dart';
+import 'package:http/http.dart';
+import 'services_utils.dart' as utils;
+
+const versions = ['v2'];
+
+BrowserClient _client;
 
 void main() {
-  querySelector('#sendButton').onClick.listen((MouseEvent e) {
-    final code = querySelector('#code').text;
-    final jsonData = <String, String>{'source': code};
-    final api = (querySelector('#apiEndPoint') as InputElement).value;
+  setupAnalyze();
+  setupAssists();
+  setupCompile();
+  setupCompileDDC();
+  setupComplete();
+  setupDocument();
+  setupFixes();
+  setupVersion();
+}
 
-    final sw = Stopwatch()..start();
-    HttpRequest.request(api, method: 'POST', sendData: json.encode(jsonData))
-        .then((HttpRequest request) {
-      sw.stop();
-      querySelector('#perf').text = '${sw.elapsedMilliseconds}ms';
-      querySelector('#output').text = request.responseText;
+Future<Response> post(String url, {String body}) async {
+  _client ??= utils.SanitizingBrowserClient();
+  return _client.post(
+    url,
+    body: body,
+    encoding: utf8,
+    headers: {'content-type': 'application/json'},
+  );
+}
+
+Future<Response> get(String url) async {
+  _client ??= utils.SanitizingBrowserClient();
+  return _client.get(
+    url,
+    headers: {'content-type': 'application/json'},
+  );
+}
+
+void setupAnalyze() {
+  versions.forEach((version) {
+    final editor =
+        createEditor(querySelector('#analyzeSection-$version .editor'));
+    final output = querySelector('#analyzeSection-$version .output');
+    final button =
+        querySelector('#analyzeSection-$version button') as ButtonElement;
+    button.onClick.listen((e) {
+      final source = {'source': editor.getDoc().getValue()};
+      final sw = Stopwatch()..start();
+      post(
+        '$_uriBase/dartservices/$version/analyze',
+        body: json.encode(source),
+      ).then(
+          (response) => output.text = '${_formatTiming(sw)}${response.body}');
     });
   });
 }
+
+void setupAssists() {
+  versions.forEach((version) {
+    final editor =
+        createEditor(querySelector('#assistsSection-$version .editor'));
+    final output = querySelector('#assistsSection-$version .output');
+    final offsetElement = querySelector('#assistsSection-$version .offset');
+    final button =
+        querySelector('#assistsSection-$version button') as ButtonElement;
+    button.onClick.listen((e) {
+      final source = _getSourceRequest(editor);
+      final sw = Stopwatch()..start();
+      post(
+        '$_uriBase/dartservices/$version/assists',
+        body: json.encode(source),
+      ).then(
+          (response) => output.text = '${_formatTiming(sw)}${response.body}');
+    });
+    offsetElement.text = 'offset ${_getOffset(editor)}';
+    editor.onCursorActivity.listen((_) {
+      offsetElement.text = 'offset ${_getOffset(editor)}';
+    });
+  });
+}
+
+void setupCompile() {
+  versions.forEach((version) {
+    final editor =
+        createEditor(querySelector('#compileSection-$version .editor'));
+    final output = querySelector('#compileSection-$version .output');
+    final button =
+        querySelector('#compileSection-$version button') as ButtonElement;
+    button.onClick.listen((e) {
+      final source = editor.getDoc().getValue();
+      final compile = {'source': source};
+      final sw = Stopwatch()..start();
+      post(
+        '${_uriBase}/dartservices/$version/compile',
+        body: json.encode(compile),
+      ).then(
+          (response) => output.text = '${_formatTiming(sw)}${response.body}');
+    });
+  });
+}
+
+void setupCompileDDC() {
+  versions.forEach((version) {
+    final editor =
+        createEditor(querySelector('#compileDDCSection-$version .editor'));
+    final output = querySelector('#compileDDCSection-$version .output');
+    final button =
+        querySelector('#compileDDCSection-$version button') as ButtonElement;
+    button.onClick.listen((e) {
+      final source = editor.getDoc().getValue();
+      final compile = {'source': source};
+      final sw = Stopwatch()..start();
+      post(
+        '${_uriBase}/dartservices/$version/compileDDC',
+        body: json.encode(compile),
+      ).then(
+          (response) => output.text = '${_formatTiming(sw)}${response.body}');
+    });
+  });
+}
+
+void setupComplete() {
+  versions.forEach((version) {
+    final editor =
+        createEditor(querySelector('#completeSection-$version .editor'));
+    final output = querySelector('#completeSection-$version .output');
+    final offsetElement = querySelector('#completeSection-$version .offset');
+    final button =
+        querySelector('#completeSection-$version button') as ButtonElement;
+    button.onClick.listen((e) {
+      final source = _getSourceRequest(editor);
+      final sw = Stopwatch()..start();
+      post(
+        '$_uriBase/dartservices/$version/complete',
+        body: json.encode(source),
+      ).then(
+          (response) => output.text = '${_formatTiming(sw)}${response.body}');
+    });
+    offsetElement.text = 'offset ${_getOffset(editor)}';
+    editor.onCursorActivity.listen((_) {
+      offsetElement.text = 'offset ${_getOffset(editor)}';
+    });
+  });
+}
+
+void setupDocument() {
+  versions.forEach((version) {
+    final editor =
+        createEditor(querySelector('#documentSection-$version .editor'));
+    final output = querySelector('#documentSection-$version .output');
+    final offsetElement = querySelector('#documentSection-$version .offset');
+    final button =
+        querySelector('#documentSection-$version button') as ButtonElement;
+    button.onClick.listen((e) {
+      final source = _getSourceRequest(editor);
+      final sw = Stopwatch()..start();
+      post(
+        '$_uriBase/dartservices/$version/document',
+        body: json.encode(source),
+      ).then(
+          (response) => output.text = '${_formatTiming(sw)}${response.body}');
+    });
+    offsetElement.text = 'offset ${_getOffset(editor)}';
+    editor.onCursorActivity.listen((_) {
+      offsetElement.text = 'offset ${_getOffset(editor)}';
+    });
+  });
+}
+
+void setupFixes() {
+  versions.forEach((version) {
+    final editor =
+        createEditor(querySelector('#fixesSection-$version .editor'));
+    final output = querySelector('#fixesSection-$version .output');
+    final offsetElement = querySelector('#fixesSection-$version .offset');
+    final button =
+        querySelector('#fixesSection-$version button') as ButtonElement;
+    button.onClick.listen((e) {
+      final source = _getSourceRequest(editor);
+      final sw = Stopwatch()..start();
+      post(
+        '$_uriBase/dartservices/$version/fixes',
+        body: json.encode(source),
+      ).then(
+          (response) => output.text = '${_formatTiming(sw)}${response.body}');
+    });
+    offsetElement.text = 'offset ${_getOffset(editor)}';
+
+    editor.onCursorActivity.listen((_) {
+      offsetElement.text = 'offset ${_getOffset(editor)}';
+    });
+  });
+}
+
+void setupVersion() {
+  versions.forEach((version) {
+    final output = querySelector('#versionSection-$version .output');
+    final button =
+        querySelector('#versionSection-$version button') as ButtonElement;
+    button.onClick.listen((e) {
+      final sw = Stopwatch()..start();
+      get('$_uriBase/dartservices/$version/version').then(
+          (response) => output.text = '${_formatTiming(sw)}${response.body}');
+    });
+  });
+}
+
+CodeMirror createEditor(Element element, {String defaultText}) {
+  final options = {
+    'tabSize': 2,
+    'indentUnit': 2,
+    'autoCloseBrackets': true,
+    'matchBrackets': true,
+    'theme': 'zenburn',
+    'mode': 'dart',
+    'value': _text ?? defaultText
+  };
+
+  final editor = CodeMirror.fromElement(element, options: options);
+  editor.refresh();
+  return editor;
+}
+
+String _formatTiming(Stopwatch sw) => '${sw.elapsedMilliseconds}ms\n';
+
+String get _uriBase =>
+    (querySelector('input[type=text]') as InputElement).value;
+
+int _getOffset(CodeMirror editor) {
+  final pos = editor.getDoc().getCursor();
+  return editor.getDoc().indexFromPos(pos);
+}
+
+Map<String, dynamic> _getSourceRequest(CodeMirror editor) => {
+      'source': editor.getDoc().getValue(),
+      'offset': _getOffset(editor),
+    };
+
+final String _text = r'''
+void main() {
+  for (int i = 0; i < 4; i++) {
+    print('hello ${i}');
+  }
+}
+''';
diff --git a/example/web/index.html b/example/web/index.html
index 800bc5c..63933a0 100644
--- a/example/web/index.html
+++ b/example/web/index.html
@@ -9,51 +9,111 @@
   	<meta charset="utf-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
   	<meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>index</title>
+    <title>API Test</title>
     <link rel="icon" href="favicon.ico">
     <script defer src="index.dart.js"></script>
-    <link href="https://fonts.googleapis.com/css?family=Roboto+Mono&display=swap" rel="stylesheet">
-    <style>
-      #code {
-        font-family: 'Roboto Mono', monospace;
-      }
-    </style>
+    <link href="styles.css" rel="stylesheet">
+    <link href="packages/codemirror/codemirror.css" rel="stylesheet">
   </head>
+
   <body>
-    <h1>API Tester</h1>
-    <br />
+    <script src="packages/codemirror/codemirror.js"></script>
 
-    <table>
-      <tr>
-        <td width = "100px"></td>
-        <td width = "500px">
-          <pre id="code" contentEditable="true">
-main() {
-  print(primesLessThan(15));
-}
+    <h2>Dartpad Server API Tester</h2>
+    <!--<input type="text" value="https://dart-services.appspot.com/">-->
+    <input type="text" value="http://localhost:8082/api">
 
-// Computes primes less than [n] using the Sieve of Eratosthenes.
-primesLessThan(n) {
-  var l = new List.generate(n, (i) =&gt; i);
-  for (int i = 2; i * i &lt; n; i++)
-      if (l[i] != null)
-          for (int j = i * i; j &lt; n; j += i)
-              l[j] = null;
-  return l.skip(2).where((i) => i != null);
-}
-          </pre>
-        </td>
-      </tr>
-    </table>
+    <section id="analyzeSection-v2">
+      <h3>api/dartservices/v2/analyze</h3>
+      <div class="row">
+        <button class="post">POST</button>
+      </div>
+      <div class="container">
+        <div class="editor"></div>
+        <div class="output"></div>
+      </div>
+    </section>
 
-    <input type="text" id="apiEndPoint"
-    value="http://localhost:8082/api/dartservices/v2/analyze"
-    size="64" />
+    <section id="assistsSection-v2">
+      <h3>api/dartservices/v2/assists</h3>
+      <div class="row">
+        <button class="post">POST</button>
+        <span class="offset"></span>
+      </div>
+      <div class="container">
+        <div class="editor"></div>
+        <div class="output"></div>
+      </div>
+    </section>
 
-    <button id="sendButton">Send</button>
-    <hr />
-    <pre id="perf">Perf</pre>
-    <pre id="output">Output</pre>
+    <section id="compileSection-v2">
+      <h3>api/dartservices/v2/compile</h3>
+      <div class="row">
+        <button class="post">POST</button>
+      </div>
+      <div class="container">
+        <div class="editor"></div>
+        <div class="output"></div>
+      </div>
+    </section>
 
+    <section id="compileDDCSection-v2">
+      <h3>api/dartservices/v2/compileDDC</h3>
+      <div class="row">
+        <button class="post">POST</button>
+      </div>
+      <div class="container">
+        <div class="editor"></div>
+        <div class="output"></div>
+      </div>
+    </section>
+
+    <section id="completeSection-v2">
+      <h3>api/dartservices/v2/complete</h3>
+      <div class="row">
+        <button class="post">POST</button>
+        <span class="offset"></span>
+      </div>
+      <div class="container">
+        <div class="editor"></div>
+        <div class="output"></div>
+      </div>
+    </section>
+
+    <section id="documentSection-v2">
+      <h3>api/dartservices/v2/document</h3>
+      <div class="row">
+        <button class="post">POST</button>
+        <span class="offset"></span>
+      </div>
+      <div class="container">
+        <div class="editor"></div>
+        <div class="output"></div>
+      </div>
+    </section>
+
+    <section id="fixesSection-v2">
+      <h3>api/dartservices/v2/fixes</h3>
+      <div class="row">
+        <button class="post">POST</button>
+        <span class="offset"></span>
+      </div>
+      <div class="container">
+        <div class="editor"></div>
+        <div class="output"></div>
+      </div>
+    </section>
+
+    <section id="versionSection-v2">
+      <h3>api/dartservices/v2/version</h3>
+      <div class="row">
+        <button class="post">GET</button>
+      </div>
+      <div class="container">
+        <div class="editor"></div>
+        <div class="output"></div>
+      </div>
+    </section>
+    
   </body>
 </html>
diff --git a/example/web/services_utils.dart b/example/web/services_utils.dart
index d693aa2..9324ad9 100644
--- a/example/web/services_utils.dart
+++ b/example/web/services_utils.dart
@@ -45,11 +45,6 @@
       request.headers.remove(headerKey);
     }
 
-    // Replace 'application/json; charset=utf-8' with text/plain. This will
-    // avoid the browser sending an OPTIONS request before the actual POST (and
-    // introducing an additional round trip between the client and the server).
-    request.headers['Content-Type'] = 'text/plain; charset=utf-8';
-
     return super.send(request);
   }
 }
diff --git a/example/web/styles.css b/example/web/styles.css
index cc035c9..df060a9 100644
--- a/example/web/styles.css
+++ b/example/web/styles.css
@@ -1,14 +1,55 @@
-@import url(https://fonts.googleapis.com/css?family=Roboto);
+/* 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. */
 
-html, body {
-  width: 100%;
-  height: 100%;
-  margin: 0;
-  padding: 0;
-  font-family: 'Roboto', sans-serif;
+body {
+  display: flex;
+  flex-direction: column;
+  margin: 15px;
+  color: #555;
 }
 
-#output {
-  padding: 20px;
-  text-align: center;
+section {
+  margin-top: 20px;
+  padding-top: 6px;
+  border-top: 1px solid #eee;
+  border-width: 2px;
+  padding-left: 16px;
+}
+
+h3 {
+  margin-top: 0;
+  margin-bottom: 8px;
+  margin-left: -16px;
+}
+
+#controls {
+  margin-bottom: 1em;
+}
+
+div.container {
+  display: flex;
+  flex-direction: row;
+}
+
+div.row {
+  margin: 0 0 6px 0;
+}
+
+.editor {
+  flex: 20;
+  display: inline-block;
+  box-shadow: 1px 1px 2px 0px rgba(50, 50, 50, 0.75);
+  margin-right: 16px;
+  height: 300px;
+}
+
+.output {
+  flex: 15;
+  display: inline-block;
+  box-shadow: 1px 1px 2px 0px rgba(50, 50, 50, 0.75);
+  height: 300px;
+  white-space: pre-wrap;
+  overflow-y: scroll;
+  font-family: monospace;
 }
diff --git a/lib/services_dev.dart b/lib/services_dev.dart
index 3a0c77c..a36d272 100644
--- a/lib/services_dev.dart
+++ b/lib/services_dev.dart
@@ -104,7 +104,7 @@
   Middleware _createCustomCorsHeadersMiddleware() {
     return shelf_cors.createCorsHeadersMiddleware(corsHeaders: <String, String>{
       'Access-Control-Allow-Origin': '*',
-      'Access-Control-Allow-Methods': 'POST, OPTIONS',
+      'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
       'Access-Control-Allow-Headers':
           'Origin, X-Requested-With, Content-Type, Accept, x-goog-api-client'
     });
diff --git a/lib/services_gae.dart b/lib/services_gae.dart
index e580b71..cfe4aaa 100644
--- a/lib/services_gae.dart
+++ b/lib/services_gae.dart
@@ -92,9 +92,10 @@
 
   Future<void> requestHandler(io.HttpRequest request) async {
     request.response.headers
-        .add('Access-Control-Allow-Methods', 'POST, OPTIONS');
-    request.response.headers.add('Access-Control-Allow-Headers',
-        'Origin, X-Requested-With, Content-Type, Accept');
+      ..add('Access-Control-Allow-Origin', '*')
+      ..add('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
+      ..add('Access-Control-Allow-Headers',
+          'Origin, X-Requested-With, Content-Type, Accept');
 
     if (request.method == 'OPTIONS') {
       await _processOptionsRequest(request);
@@ -110,14 +111,7 @@
   }
 
   Future<void> _processOptionsRequest(io.HttpRequest request) async {
-    final requestedMethod =
-        request.headers.value('access-control-request-method');
-    int statusCode;
-    if (requestedMethod != null && requestedMethod.toUpperCase() == 'POST') {
-      statusCode = io.HttpStatus.ok;
-    } else {
-      statusCode = io.HttpStatus.badRequest;
-    }
+    final statusCode = io.HttpStatus.ok;
     request.response.statusCode = statusCode;
     await request.response.close();
   }
diff --git a/pubspec.lock b/pubspec.lock
index 56968a1..e352cae 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -370,8 +370,8 @@
     description:
       path: "."
       ref: HEAD
-      resolved-ref: "7a21837c234f9328df8de0e0cf74893d4a82df93"
-      url: "https://github.com/domesticmouse/mock_request.git"
+      resolved-ref: "5a6336d6a7ba9309b6fa31a6185b619f329dc5d7"
+      url: "https://github.com/thosakwe/mock_request.git"
     source: git
     version: "1.0.7"
   multi_server_socket: