public function __construct($method, array $params, $strictly_typed = true)
 {
     $this->method = $method;
     $this->handler = $this->buildMethodHandler($method);
     $param_types = $this->handler->getParamTypes();
     foreach ($param_types as $key => $spec) {
         if (ConduitAPIMethod::getParameterMetadataKey($key) !== null) {
             throw new ConduitException(pht('API Method "%s" defines a disallowed parameter, "%s". This ' . 'parameter name is reserved.', $method, $key));
         }
     }
     $invalid_params = array_diff_key($params, $param_types);
     if ($invalid_params) {
         throw new ConduitException(pht('API Method "%s" does not define these parameters: %s.', $method, "'" . implode("', '", array_keys($invalid_params)) . "'"));
     }
     $this->request = new ConduitAPIRequest($params, $strictly_typed);
 }
 private function decodeConduitParams(AphrontRequest $request, $method)
 {
     // Look for parameters from the Conduit API Console, which are encoded
     // as HTTP POST parameters in an array, e.g.:
     //
     //   params[name]=value&params[name2]=value2
     //
     // The fields are individually JSON encoded, since we require users to
     // enter JSON so that we avoid type ambiguity.
     $params = $request->getArr('params', null);
     if ($params !== null) {
         foreach ($params as $key => $value) {
             if ($value == '') {
                 // Interpret empty string null (e.g., the user didn't type anything
                 // into the box).
                 $value = 'null';
             }
             $decoded_value = json_decode($value, true);
             if ($decoded_value === null && strtolower($value) != 'null') {
                 // When json_decode() fails, it returns null. This almost certainly
                 // indicates that a user was using the web UI and didn't put quotes
                 // around a string value. We can either do what we think they meant
                 // (treat it as a string) or fail. For now, err on the side of
                 // caution and fail. In the future, if we make the Conduit API
                 // actually do type checking, it might be reasonable to treat it as
                 // a string if the parameter type is string.
                 throw new Exception(pht("The value for parameter '%s' is not valid JSON. All " . "parameters must be encoded as JSON values, including strings " . "(which means you need to surround them in double quotes). " . "Check your syntax. Value was: %s.", $key, $value));
             }
             $params[$key] = $decoded_value;
         }
         $metadata = idx($params, '__conduit__', array());
         unset($params['__conduit__']);
         return array($metadata, $params);
     }
     // Otherwise, look for a single parameter called 'params' which has the
     // entire param dictionary JSON encoded.
     $params_json = $request->getStr('params');
     if (strlen($params_json)) {
         $params = null;
         try {
             $params = phutil_json_decode($params_json);
         } catch (PhutilJSONParserException $ex) {
             throw new PhutilProxyException(pht("Invalid parameter information was passed to method '%s'.", $method), $ex);
         }
         $metadata = idx($params, '__conduit__', array());
         unset($params['__conduit__']);
         return array($metadata, $params);
     }
     // If we do not have `params`, assume this is a simple HTTP request with
     // HTTP key-value pairs.
     $params = array();
     $metadata = array();
     foreach ($request->getPassthroughRequestData() as $key => $value) {
         $meta_key = ConduitAPIMethod::getParameterMetadataKey($key);
         if ($meta_key !== null) {
             $metadata[$meta_key] = $value;
         } else {
             $params[$key] = $value;
         }
     }
     return array($metadata, $params);
 }