Implement chrome.experimental.downloads.onChanged

ExtensionDownloadsEventRouter now also observes all DownloadItems and dispatches onChanged events.

Download.OnChanged records the percentage of OnDownloadUpdated() calls that are propagated as onChanged events instead of being suppressed.

BUG=12133

Review URL: http://codereview.chromium.org/8203005

git-svn-id: http://src.chromium.org/svn/trunk/src/net/tools/testserver@121912 4ff67af0-8c30-449e-8e8b-ad334ec8d88c
diff --git a/testserver.py b/testserver.py
index 12882b5..f280333 100755
--- a/testserver.py
+++ b/testserver.py
@@ -909,9 +909,6 @@
     prefix = self.server.file_root_url
     if not self.path.startswith(prefix):
       return False
-    # Consume a request body if present.
-    if self.command == 'POST' or self.command == 'PUT' :
-      self.ReadRequestBody()
     return self._FileHandlerHelper(prefix)
 
   def PostOnlyFileHandler(self):
@@ -919,12 +916,33 @@
     prefix = urlparse.urljoin(self.server.file_root_url, 'post/')
     if not self.path.startswith(prefix):
       return False
-    self.ReadRequestBody()
     return self._FileHandlerHelper(prefix)
 
   def _FileHandlerHelper(self, prefix):
-    old_protocol_version = self.protocol_version
+    request_body = ''
+    if self.command == 'POST' or self.command == 'PUT':
+      # Consume a request body if present.
+      request_body = self.ReadRequestBody()
+
     _, _, url_path, _, query, _ = urlparse.urlparse(self.path)
+    query_dict = cgi.parse_qs(query)
+
+    expected_body = query_dict.get('expected_body', [])
+    if expected_body and request_body not in expected_body:
+      self.send_response(404)
+      self.end_headers()
+      self.wfile.write('')
+      return True
+
+    expected_headers = query_dict.get('expected_headers', [])
+    for expected_header in expected_headers:
+      header_name, expected_value = expected_header.split(':')
+      if self.headers.getheader(header_name) != expected_value:
+        self.send_response(404)
+        self.end_headers()
+        self.wfile.write('')
+        return True
+
     sub_path = url_path[len(prefix):]
     entries = sub_path.split('/')
     file_path = os.path.join(self.server.data_dir, *entries)
@@ -942,6 +960,8 @@
 
     data = self._ReplaceFileData(data, query)
 
+    old_protocol_version = self.protocol_version
+
     # If file.mock-http-headers exists, it contains the headers we
     # should send.  Read them in and parse them.
     headers_path = file_path + '.mock-http-headers'