diff --git a/src/applications/diffusion/controller/DiffusionServeController.php b/src/applications/diffusion/controller/DiffusionServeController.php
--- a/src/applications/diffusion/controller/DiffusionServeController.php
+++ b/src/applications/diffusion/controller/DiffusionServeController.php
@@ -888,10 +888,31 @@
       }
       $args_raw[] = $_SERVER[$header];
     }
-    $args_raw = implode('', $args_raw);
 
-    return id(new PhutilQueryStringParser())
-      ->parseQueryString($args_raw);
+    if (nonempty($args_raw)) {
+      $args_raw = implode('', $args_raw);
+      return id(new PhutilQueryStringParser())
+        ->parseQueryString($args_raw);
+    }
+
+    // Sometimes arguments come in via the query string.
+    $args_raw = array();
+    foreach ($_GET as $key => $value) {
+      // Filter out private/internal keys as well as the command itself.
+      if (strncmp($key, '__', 2) && $key != 'cmd') {
+        $args_raw[] = "{$key}={$value}";
+      }
+    }
+
+    if (nonempty($args_raw)) {
+      $args_raw = implode('&', $args_raw);
+      return id(new PhutilQueryStringParser())
+        ->parseQueryString($args_raw);
+    }
+
+    // TODO: Arguments can also come in via request body for POST requests. The
+    // body would be all arguments, url-encoded.
+    return array();
   }
 
   private function formatMercurialArguments($command, array $arguments) {