PageRenderTime 50ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/src/com/didactilab/gwt/phprpc/phprpc/phprpc/rpc/RPC.php

http://gwtphp-derpc.googlecode.com/
PHP | 519 lines | 424 code | 68 blank | 27 comment | 50 complexity | abf1d71b961554ba4f7a5f1f2bc7370e MD5 | raw file
  1. <?php
  2. require_once PHPRPC_ROOT . 'classes.php';
  3. require_once PHPRPC_ROOT . 'primitives.php';
  4. require_once PHPRPC_ROOT . 'primitives_serializers.php';
  5. require_once PHPRPC_ROOT . 'collections.php';
  6. require_once PHPRPC_ROOT . 'collections_serializers.php';
  7. require_once PHPRPC_ROOT . 'datetime.php';
  8. require_once PHPRPC_ROOT . 'datetime_serializers.php';
  9. require_once PHPRPC_ROOT . 'serialization.php';
  10. require_once PHPRPC_ROOT . 'rpc/SerializationPolicy.php';
  11. require_once PHPRPC_ROOT . 'rpc/ServerSerializationStreamReader.php';
  12. require_once PHPRPC_ROOT . 'rpc/ServerSerializationStreamWriter.php';
  13. require_once PHPRPC_ROOT . 'rpc/RpcToken.php';
  14. require_once PHPRPC_ROOT . 'rpc/RPCServletUtils.php';
  15. require_once PHPRPC_ROOT . 'rpc/javaclasses.php';
  16. class RPC {
  17. private static $PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS;
  18. private static $serviceToImplementedInterfacesMap;
  19. private static $TYPE_NAMES = array();
  20. public static function init() {
  21. self::$PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS = new HashMap();
  22. self::$PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS->put(Boolean::clazz(), Boolean::typeClass());
  23. self::$PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS->put(Byte::clazz(), Byte::typeClass());
  24. self::$PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS->put(Character::clazz(), Character::typeClass());
  25. self::$PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS->put(Float::clazz(), Float::typeClass());
  26. self::$PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS->put(Integer::clazz(), Integer::typeClass());
  27. self::$PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS->put(Long::clazz(), Long::typeClass());
  28. self::$PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS->put(Short::clazz(), Short::typeClass());
  29. self::$TYPE_NAMES['Z'] = Boolean::typeClass();
  30. self::$TYPE_NAMES['B'] = Byte::typeClass();
  31. self::$TYPE_NAMES['C'] = Character::typeClass();
  32. self::$TYPE_NAMES['D'] = Double::typeClass();
  33. self::$TYPE_NAMES['F'] = Float::typeClass();
  34. self::$TYPE_NAMES['I'] = Integer::typeClass();
  35. self::$TYPE_NAMES['J'] = Long::typeClass();
  36. self::$TYPE_NAMES['S'] = Short::typeClass();
  37. self::$serviceToImplementedInterfacesMap = new HashMap();
  38. }
  39. public static function decodeRequest($encodedRequest, Clazz $type = null,
  40. SerializationPolicyProvider $serializationPolicyPolicyProvider = null) {
  41. if (is_null($encodedRequest)) {
  42. throw new NullPointerException('encodedRequest cannot be null');
  43. }
  44. if (empty($encodedRequest)) {
  45. throw new IllegalArgumentException('encodedRequest cannot be empty');
  46. }
  47. try {
  48. $streamReader = new ServerSerializationStreamReader($serializationPolicyPolicyProvider);
  49. $streamReader->prepareToRead($encodedRequest);
  50. $rpcToken = null;
  51. if ($streamReader->hasFlags(AbstractSerializationStream::FLAG_RPC_TOKEN_INCLUDED)) {
  52. // Read the RPC token
  53. $rpcToken = $streamReader->deserializeValue(Classes::classOf(RpcToken));
  54. }
  55. // Read the name of the RemoteService interface
  56. $serviceIntfName = self::maybeDeobfuscate($streamReader, $streamReader->readString());
  57. //TODO: implements model or is class
  58. /*if (!is_null($type)) {
  59. if (!self::implementsInterface($type, $serviceIntfName)) {
  60. $printedType = self::printTypeName($type);
  61. throw new IncompatibleRemoteServiceException(
  62. "Blocked attempt to access interface '$serviceIntfName', " .
  63. "which is not implemented by '$printedType'; " .
  64. "this is either misconfiguration or a hack attempt"
  65. );
  66. }
  67. }*/
  68. $serializationPolicy = $streamReader->getSerializationPolicy();
  69. try {
  70. $serviceIntf = self::getClassFromSerializedName($serviceIntfName);
  71. if (!Classes::classOf(RemoteService)->isAssignableFrom($serviceIntf)) {
  72. // The requested interface is not a RemoteService interface
  73. $printedType = $this->printTypeName($serviceIntf);
  74. throw new IncompatibleRemoteServiceException(
  75. "Blocked attempt to access interface '$printedType', " .
  76. "which doesn't extend RemoteService; this is either misconfiguration or a hack attempt"
  77. );
  78. }
  79. }
  80. catch (ClassNotFoundException $e) {
  81. throw new IncompatibleRemoteServiceException(
  82. "Could not locate requested interface '$serviceIntfName' : $e"
  83. );
  84. }
  85. $serviceMethodName = $streamReader->readString();
  86. $paramCount =$streamReader->readInt();
  87. if ($paramCount > $streamReader->getNumberOfTokens()) {
  88. throw new IncompatibleRemoteServiceException('Invalid number of parameters');
  89. }
  90. $parameterTypes = array();
  91. for ($i=0; $i<$paramCount; $i++) {
  92. $paramClassName = self::maybeDeobfuscate($streamReader, $streamReader->readString());
  93. try {
  94. $parameterTypes[] = self::getClassFromSerializedName($paramClassName);
  95. }
  96. catch (ClassNotFoundException $e) {
  97. throw new IncompatibleRemoteServiceException("Paramter $i is unknown type '$paramClassName' : $e");
  98. }
  99. }
  100. try {
  101. $method = $serviceIntf->getMethod($serviceMethodName);
  102. $parameterValues = array();
  103. for ($i=0; $i<$paramCount; $i++) {
  104. $parameterValues[] = $streamReader->deserializeValue($parameterTypes[$i]);
  105. }
  106. return new RPCRequest($method, $parameterValues, $serializationPolicy,
  107. $streamReader->getFlags(), $rpcToken);
  108. }
  109. catch (NoSuchMethodException $e) {
  110. throw new IncompatibleRemoteServiceException(
  111. self::formatMethodNotFoundErrorMessage($serviceIntf, $serviceMethodName, $parameterTypes)
  112. );
  113. }
  114. }
  115. catch (SerizalizationException $ex) {
  116. throw new IncompatibleRemoteServiceException($ex->getMessage() . ' : ' . $ex);
  117. }
  118. }
  119. public static function encodeResponseForFailure(Method $serviceMethod, Throwable $cause,
  120. SerializationPolicy $serializationPolicy = null,
  121. $flags = AbstractSerializationStream::DEFAULT_FLAGS) {
  122. if (is_null($cause)) {
  123. throw new NullPointerException('cause cannot be null');
  124. }
  125. if (is_null($serializationPolicy)) {
  126. //throw new NullPointerException('serializationPolicy cannot be null');
  127. $serializationPolicy = self::getDefaultSerializationPolicy();
  128. }
  129. if (!is_null($serviceMethod) && !RPCServletUtils::isExpectedException($serviceMethod, $cause)) {
  130. $cause = (string) $cause;
  131. $source = self::getSourceRepresentation($serviceMethod);
  132. throw new UnexpectedException("Service method '$source' threw an unexpected excetion: $cause");
  133. }
  134. return self::encodeResponse($cause->getClass(), $cause, true, $flags, $serializationPolicy);
  135. }
  136. public static function encodeResponseForSuccess(Method $serviceMethod, $object,
  137. SerializationPolicy $serializationPolicy = null,
  138. $flags = AbstractSerializationStream::DEFAULT_FLAGS) {
  139. if (is_null($serviceMethod)) {
  140. throw new NullPointerException('serviceMethod cannot be null');
  141. }
  142. if (is_null($serializationPolicy)) {
  143. $serializationPolicy = self::getDefaultSerializationPolicy();
  144. throw new NullPointerException('serializationPolicy cannot be null');
  145. }
  146. $methodReturnTypeName = $serviceMethod->getReturnType();
  147. //TODO see if must be an object
  148. if (empty($methodReturnTypeName)) {
  149. $methodReturnType = Void::typeClass();
  150. }
  151. else {
  152. $methodReturnType = Classes::classOf($methodReturnTypeName);
  153. }
  154. if ($methodReturnType !== Void::typeClass() && !is_null($object)) {
  155. // TODO : Verify
  156. /*if ($methodReturnType->isPrimitive()) {
  157. $actualReturnType = self::getPrimitiveClassFromWrapper(Classes::classOf($object));
  158. }
  159. else {
  160. $actualReturnType = Classes::classOf($object);
  161. }*/
  162. $actualReturnType = Classes::classOfValue($object);
  163. //var_dump($methodReturnType);
  164. // TODO : Enum manage
  165. if ($methodReturnType->isEnum() && $actualReturnType === Integer::typeClass()) {
  166. return self::encodeResponse($methodReturnType, $object, false, $flags, $serializationPolicy);
  167. }
  168. if (is_null($actualReturnType) || !$methodReturnType->isAssignableFrom($actualReturnType)) {
  169. $printedType = self::printTypeName(Classes::classOfValue($object));
  170. $source = self::getSourceRepresentation($serviceMethod);
  171. throw new IllegalArgumentException(
  172. "Type '$printedType' does not match the return type in the method's signature : '$source'"
  173. );
  174. }
  175. }
  176. return self::encodeResponse($methodReturnType, $object, false, $flags, $serializationPolicy);
  177. }
  178. public static function getDefaultSerializationPolicy() {
  179. return LegacySerializationPolicy::getInstance();
  180. }
  181. public static function invokeAndEncodeResponse($target, Method $serviceMethod, $args,
  182. SerializationPolicy $serializationPolicy = null,
  183. $flags = AbstractSerializationStream::DEFAULT_FLAGS) {
  184. if (is_null($serviceMethod)) {
  185. throw new NullPointerException('serviceMethod cannot be null');
  186. }
  187. if (is_null($serializationPolicy)) {
  188. $serializationPolicy = self::getDefaultSerializationPolicy();
  189. throw new NullPointerException('serializationPolicy cannot be null');
  190. }
  191. try {
  192. $result = $serviceMethod->invokeArgs($target, $args);
  193. $responsePayload = self::encodeResponseForSuccess($serviceMethod, $result, $serializationPolicy, $flags);
  194. }
  195. //cannot be happen in Php
  196. catch (IllegalAccessException $e) {
  197. $securityException = new SecurityException(self::formatIllegalAccessErrorMessage($target, $serviceMethod), $e);
  198. throw $securityException;
  199. }
  200. //cannot be happen in Php
  201. catch (IllegalArgumentException $e) {
  202. $securityException = new SecurityException(self::formatIllegalArgumentErrorMessage($target, $serviceMethod, $args), $e);
  203. throw $securityException;
  204. }
  205. catch (Exception $e) {
  206. $cause = new Throwable($e, $e->getMessage());
  207. $responsePayload = self::encodeResponseForFailure($serviceMethod, $cause, $serializationPolicy, $flags);
  208. }
  209. return $responsePayload;
  210. }
  211. private static function encodeResponse(Clazz $responseClass, $object, $wasThrown, $flags, $serializationPolicy) {
  212. $stream = new ServerSerializationStreamWriter($serializationPolicy);
  213. $stream->setFlags($flags);
  214. $stream->prepareToWrite();
  215. if ($responseClass !== Void::typeClass()) {
  216. $stream->serializeValue($object, $responseClass);
  217. }
  218. $bufferStr = ($wasThrown ? '//EX' : '//OK') . (string) $stream;
  219. return $bufferStr;
  220. }
  221. private static function formatIllegalAccessErrorMessage($target, Method $serviceMethod) {
  222. $source = self::getSourceRepresentation($serviceMethod);
  223. $sb = "Blocked attempt to access inaccessible method '$source'";
  224. if (!is_null($target)) {
  225. $printedType = self::printTypeName(Classes::classOf($target));
  226. $sb .= " on target '$printedType'";
  227. }
  228. $sb .= '; this is either misconfiguration or a hack attempt';
  229. return $sb;
  230. }
  231. private static function formatIllegalArgumentErrorMessage($target, Method $serviceMethod, $args) {
  232. $source = self::getSourceRepresentation($serviceMethod);
  233. $sb = "Blocked attempt to invoke method '$source'";
  234. if (!is_null($target)) {
  235. $printedType = self::printTypeName(Classes::classOf($target));
  236. $sb .= " on target '$printedType'";
  237. }
  238. $sb .= ' with invalid arguments';
  239. if (!is_null($args) && !empty($args)) {
  240. $sb .= Arrays::asList($args);
  241. }
  242. return $sb;
  243. }
  244. private static function formatMethodNotFoundErrorMessage(Clazz $serviceIntf, $serviceMethodName, $parameterTypes) {
  245. $sb = "Could not locate requested method '$serviceMethodName(";
  246. for ($i=0; $i<count($parameterTypes); $i++) {
  247. if ($i > 0) {
  248. $sb .= ', ';
  249. }
  250. $sb .= self::printTypeName($parameterTypes[$i]);
  251. }
  252. $sb .= ")'";
  253. $printedType = self::printTypeName($serviceIntf);
  254. $sb .= " in interface '$printedType'";
  255. return $sb;
  256. }
  257. private static function getClassFromSerializedName($serializedName) {
  258. if (isset(self::$TYPE_NAMES[$serializedName])) {
  259. return self::$TYPE_NAMES[$serializedName];
  260. }
  261. return Classes::classOf($serializedName);
  262. }
  263. private static function getPrimitiveClassFromWrapper(Clazz $wrapperClass) {
  264. return self::$PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS->get($wrapperClass);
  265. }
  266. private static function getSourceRepresentation(Method $method) {
  267. return str_replace('$', '.', (string) $method);
  268. }
  269. private static function implementsInterface(Clazz $service, $intfName) {
  270. $interfaceSet = self::$serviceToImplementedInterfacesMap->get($service);
  271. if (!is_null($interfaceSet)) {
  272. if ($interfaceSet->contains($intfName)) {
  273. return true;
  274. }
  275. }
  276. else {
  277. $interfaceSet = new HashSet();
  278. self::$serviceToImplementedInterfacesMap->put($service, $interfaceSet);
  279. }
  280. if (!$service->isInterface()) {
  281. while ((!is_null($service)) && Classes::classOf('RemoteServiceServlet') !== $service) {
  282. $intfs = $service->getInterfaces();
  283. foreach ($intfs as $intf) {
  284. if (self::implementsInterfaceRecursive($intf, $intfName)) {
  285. $interfaceSet->add($intfName);
  286. return true;
  287. }
  288. }
  289. // did not find the interface in this class so we look in the
  290. // superclass
  291. //
  292. $service = $service->getSuperClass();
  293. }
  294. }
  295. else {
  296. if (self::implementsInterfaceRecursive($service, $intfName)) {
  297. $interfaceSet->add($intfName);
  298. return true;
  299. }
  300. }
  301. return false;
  302. }
  303. private static function implementsInterfaceRecursive(Clazz $clazz, $intfName) {
  304. assert($clazz->isInterface());
  305. if ($clazz->getName() === $intfName) {
  306. return true;
  307. }
  308. $intfs = $clazz->getInterfaces();
  309. foreach ($intfs as $intf) {
  310. if (self::implementsInterfaceRecursive($intf, $intfName)) {
  311. return true;
  312. }
  313. }
  314. return false;
  315. }
  316. private static function maybeDeobfuscate(ServerSerializationStreamReader $streamReader, $name) {
  317. if ($streamReader->hasFlags(AbstractSerializationStream::FLAG_ELIDE_TYPE_NAMES)) {
  318. $serializationPolicy = $streamReader->getSerializationPolicy();
  319. if (!(serializationPolicy instanceof TypeNameObfuscator)) {
  320. throw new IncompatibleRemoteServiceException(
  321. 'RPC request was encoded with obfuscated type names, ' .
  322. 'but the SerializationPolicy in use does not implement ' .
  323. Classes::classOf(TypeNameObfuscator)->getName()
  324. );
  325. }
  326. $maybe = $serializationPolicy->getClassNameForTypeId($name);
  327. if (!is_null($maybe)) {
  328. return $maybe;
  329. }
  330. }
  331. else if (($index = mb_strpos($name, '/')) !== false) {
  332. return mb_substr($name, 0, $index);
  333. }
  334. return $name;
  335. }
  336. private static function printTypeName(Clazz $type) {
  337. // Primitives
  338. //
  339. if ($type === Integer::typeClass()) {
  340. return 'int';
  341. }
  342. else if ($type === Long::typeClass()) {
  343. return 'long';
  344. }
  345. else if ($type === Short::typeClass()) {
  346. return 'short';
  347. }
  348. else if ($type === Byte::typeClass()) {
  349. return 'byte';
  350. }
  351. else if ($type === Character::typeClass()) {
  352. return 'char';
  353. }
  354. else if ($type === Boolean::typeClass()) {
  355. return 'boolean';
  356. }
  357. else if ($type === Float::typeClass()) {
  358. return 'float';
  359. }
  360. else if ($type === Double::typeClass()) {
  361. return 'double';
  362. }
  363. // Arrays
  364. //
  365. if ($type->isArray()) {
  366. $componentType = $type->getComponentType();
  367. return self::printTypeName($componentType) . '[]';
  368. }
  369. // Everything else
  370. //
  371. return str_replace('$', '.', $type->getName());
  372. }
  373. }
  374. RPC::init();
  375. class RPCRequest {
  376. private $flags;
  377. private $method;
  378. private $parameters;
  379. private $rpcToken;
  380. private $serializationPolicy;
  381. public function __construct(Method $method, $parameters, SerializationPolicy $serializationPolicy, $flags, RpcToken $rpcToken = null) {
  382. $this->method = $method;
  383. $this->parameters = $parameters;
  384. $this->rpcToken = $rpcToken;
  385. $this->serializationPolicy = $serializationPolicy;
  386. $this->flags = $flags;
  387. }
  388. public function getMethod() {
  389. return $this->method;
  390. }
  391. public function getParameters() {
  392. return $this->parameters;
  393. }
  394. public function getRpcToken() {
  395. return $this->rpcToken;
  396. }
  397. public function getSerializationPolicy() {
  398. return $this->serializationPolicy;
  399. }
  400. public function getFlags() {
  401. return $this->flags;
  402. }
  403. public function __toString() {
  404. $sb = $this->method->getDeclaringClass()->getName();
  405. $sb .= '.';
  406. $sb .= $this->method->getName();
  407. $sb .= '(';
  408. for ($i=0, $c=count($this->parameters); $i<$c; $i++) {
  409. $param = $this->parameters[$i];
  410. if ($i < $c - 1) {
  411. $sb .= ', ';
  412. }
  413. if (is_string($param)) {
  414. $escaped = str_replace('\\\"', '\\\\\"', $param);
  415. $sb .= "\"$escaped\"";
  416. }
  417. else if (is_null($param)) {
  418. $sb .= 'null';
  419. }
  420. else {
  421. $sb .= (string) $param;
  422. }
  423. }
  424. $sb .= ')';
  425. return $sb;
  426. }
  427. }
  428. /** @gwtname com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException */
  429. class IncompatibleRemoteServiceException extends Exception {
  430. }
  431. /** @gwtname com.google.gwt.user.client.rpc.RpcTokenException */
  432. class RpcTokenException extends Exception {
  433. }