Author: bhofmann
Date: Mon Feb 14 15:52:17 2011
New Revision: 1070532

URL: http://svn.apache.org/viewvc?rev=1070532&view=rev
Log:
SHINDIG-1506: fixed incorrect dispatching of parameters in RPC GET requests

Added:
    shindig/trunk/php/test/social/JsonRpcServletTest.php
Modified:
    shindig/trunk/php/src/social/servlet/JsonRpcServlet.php

Modified: shindig/trunk/php/src/social/servlet/JsonRpcServlet.php
URL: 
http://svn.apache.org/viewvc/shindig/trunk/php/src/social/servlet/JsonRpcServlet.php?rev=1070532&r1=1070531&r2=1070532&view=diff
==============================================================================
--- shindig/trunk/php/src/social/servlet/JsonRpcServlet.php (original)
+++ shindig/trunk/php/src/social/servlet/JsonRpcServlet.php Mon Feb 14 15:52:17 
2011
@@ -27,7 +27,7 @@ class JsonRpcServlet extends ApiServlet 
 
   /**
    * Single request through GET
-   * 
http://api.example.org/rpc?method=people.get&id=myself&userid=@me&groupid=@self
+   * 
http://api.example.org/rpc?method=people.get&id=myself&params.userId=@me&params.groupId=@self
    */
   public function doGet() {
     $token = $this->getSecurityToken();
@@ -35,12 +35,89 @@ class JsonRpcServlet extends ApiServlet 
       $this->sendSecurityError();
       return;
     }
-    // Request object == GET params
-    $request = $_GET;
+
+    $request = $this->parseGetRequest($_SERVER['QUERY_STRING']);
+
     $this->dispatch($request, $token);
   }
 
   /**
+   * parses all $_GET parameters according to rpc spec
+   * @see 
http://opensocial-resources.googlecode.com/svn/spec/1.1/Core-API-Server.xml#urlAddressing
+   *
+   * @param string $parameters should be $_GET on production
+   * @return array
+   */
+  public function parseGetRequest($parameterString)
+  {
+    // we have to parse the query parameters by hand because parse_str or the 
built in
+    // $_GET replace '.' with '_' in parameter keys
+    $parameters = array();
+    $pairs = explode('&', $parameterString);
+    foreach ($pairs as $pair) {
+      if (strpos($pair, '=') !== false) {
+        list($key, $value) = explode('=', $pair);
+        $parameters[$key] = urldecode($value);
+      }
+    }
+    $request = array();
+    foreach($parameters as $key => $value) {
+      // parse value lists like field=1,2,3,4,5
+      if (strpos($value, ',') !== false) {
+        $parsedValue = explode(',', $value);
+      } else {
+        $parsedValue = $value;
+      }
+      // handle multidimensional nested keys like field.nested=value
+      if (strpos($key, '.') > 0) {
+        $keyParts = explode('.', $key);
+        $request = $this->getMultiDimensionalArray($request, $keyParts, 
$parsedValue);
+      } else {
+        $request = $this->getMultiDimensionalArray($request, array($key), 
$parsedValue);
+      }
+    }
+    return $request;
+  }
+
+  /**
+   * parses a multidimensional parameter
+   * e.g. params.foo=bar to 'params' => array('foo' => 'bar')
+   *
+   * @param array $request
+   * @param array $keyParts
+   * @param mixed $value
+   * @return array
+   */
+  private function getMultiDimensionalArray($request, $keyParts, $value)
+  {
+    if (! $keyParts) {
+      return $value;
+    }
+    $key = array_shift($keyParts);
+
+    $matches = array();
+
+    // handle something like field(0).nested1=value1&field(1).nested2=value2
+    if (preg_match('/^([a-zA-Z0-9]*)\(([0-9]*)\)$/', $key, $matches)) {
+      $key = $matches[1];
+      array_unshift($keyParts, $matches[2]);
+    }
+
+    if (! isset($request[$key])) {
+      $request[$key] = array();
+    }
+    $value = $this->getMultiDimensionalArray($request[$key], $keyParts, 
$value);
+
+    if (is_array($value)) {
+      $request[$key] = $value + $request[$key];
+    } else {
+      $request[$key] = $value;
+    }
+
+    return $request;
+  }
+
+  /**
    * RPC Post request
    */
   public function doPost() {
@@ -107,7 +184,8 @@ class JsonRpcServlet extends ApiServlet 
     $requestItem = new RpcRequestItem($request, $token);
     // Resolve each Future into a response.
     // TODO: should use shared deadline across each request
-    $response = $this->getResponseItem($this->handleRequestItem($requestItem));
+    $a = $this->handleRequestItem($requestItem);
+    $response = $this->getResponseItem($a);
     $result = $this->getJSONResponse($key, $response);
     $this->encodeAndSendResponse($result);
   }
@@ -160,7 +238,7 @@ class JsonRpcServlet extends ApiServlet 
   /**
    * encodes data to json, adds jsonp callback if requested and sends response
    * to client
-   * 
+   *
    * @param array $data
    * @return string
    */

Added: shindig/trunk/php/test/social/JsonRpcServletTest.php
URL: 
http://svn.apache.org/viewvc/shindig/trunk/php/test/social/JsonRpcServletTest.php?rev=1070532&view=auto
==============================================================================
--- shindig/trunk/php/test/social/JsonRpcServletTest.php (added)
+++ shindig/trunk/php/test/social/JsonRpcServletTest.php Mon Feb 14 15:52:17 
2011
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+class JsonRpcServletTest extends PHPUnit_Framework_TestCase {
+
+    public function testParseRPCGetParameters()
+    {
+        $servlet = new JsonRpcServlet();
+
+        $parameters = 
'oauth_token=abcdef&method=people.get&id=req&params.userId=@me&params.groupId=@self&field=1,2,3&fieldtwo(0).nested1=value1&fieldtwo(1).nested2.blub(0)=value2&fieldtwo(1).nested3=value3&f.a.c=foo&f.a.d=bar';
+
+        $result = $servlet->parseGetRequest($parameters);
+
+        $expected = array(
+            'method' => 'people.get',
+            'id' => 'req',
+            'params' => array(
+                'userId' => '@me',
+                'groupId' => '@self',
+            ),
+            'field' => array(1,2,3),
+            'fieldtwo' => array(
+                0 => array(
+                    'nested1' => 'value1',
+                ),
+                1 => array(
+                    'nested2' => array(
+                        'blub' => array(
+                            0 => 'value2',
+                        ),
+                    ),
+                    'nested3' => 'value3',
+                ),
+            ),
+            'f' => array(
+                'a' => array(
+                    'c' => 'foo',
+                    'd' => 'bar',
+                )
+            ),
+            'oauth_token' => 'abcdef',
+        );
+
+        $this->assertEquals($expected, $result);
+    }
+
+
+    public function testParseRPCGetWithEmptyParameters()
+    {
+        $servlet = new JsonRpcServlet();
+
+        $result = $servlet->parseGetRequest('');
+
+        $this->assertEquals(array(), $result);
+    }
+}


Reply via email to