/* PHPRPCServer.java
*
* Author: Ma Bingyao <andot@ujn.edu.cn>
* Copyright: CoolCode.CN
* Version: 2.1
* LastModified: 2006-08-05
* This library is free. You can redistribute it and/or modify it.
* http://www.coolcode.cn/?p=204
*/
package PHPRPC;
import java.lang.*;
import java.lang.reflect.*;
import java.io.*;
import java.math.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
class RemoteFunction {
protected String name;
protected Object obj;
protected Class cls;
protected Method[] functions;
protected RemoteFunction(String name, Object obj, Class cls, Method[] functions) {
this.name = name;
this.obj = obj;
this.cls = cls;
this.functions = functions;
}
}
public class PHPRPCServer {
private HttpServletRequest request;
private HttpServletResponse response;
private HttpSession session;
private PrintWriter reswriter;
private ArrayList functions;
private RemoteFunction[] rfs;
private boolean debug;
private String charset;
private boolean encode;
private boolean byref;
private boolean encrypt;
private int encryptmode;
private byte[] key;
private String result;
private String arguments;
private String output;
private String callback;
private Integer errno;
private String errstr;
//private static Regex test = new Regex("[\0-\037\042\047\134]", RegexOptions.Compiled);
public PHPRPCServer(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException {
this.request = request;
this.response = response;
this.reswriter = response.getWriter();
this.session = session;
this.functions = new ArrayList();
this.encode = true;
this.encrypt = false;
this.encryptmode = 0;
this.errno = 0;
this.errstr = "";
this.output = "";
this.callback = "";
this.byref = true;
this.key = null;
}
public void add(String function, Object obj) {
add(new String[] { function }, obj, obj.getClass());
}
public void add(String[] functions, Object obj) {
add(functions, obj, obj.getClass());
}
public void add(String function, Class cls) {
add(new String[] { function }, null, cls);
}
public void add(String[] functions, Class cls) {
add(functions, null, cls);
}
private void add(String[] functions, Object obj, Class cls) {
Method[] ms = cls.getMethods();
for (int i = 0, n = functions.length; i < n; i++) {
ArrayList fs = new ArrayList();
for (int j = 0, m = ms.length; j < m; j++) {
if (functions[i].toLowerCase() == ms[j].getName().toLowerCase() &&
Modifier.isPublic(ms[j].getModifiers())) {
fs.add(ms[j]);
}
}
this.functions.add(new RemoteFunction(functions[i], obj, cls, (Method[])fs.toArray(new Method[0])));
}
}
private String toHexString(int n) {
return ((n < 16) ? "0" : "") + Integer.toHexString(n);
}
private String addJsSlashes(String str) {
char[] s = str.toCharArray();
StringBuffer sb = new StringBuffer();
for (int i =0, n = s.length; i < n; i++) {
if (s[i] <= 31 || s[i] == 34 || s[i] == 39 || s[i] == 92 || s[i] == 127) {
sb.append("\\x");
sb.append(toHexString((int)s[i] & 0xff));
}
else {
sb.append(s[i]);
}
}
return sb.toString();
}
private String addJsSlashes(byte[] s) {
StringBuffer sb = new StringBuffer();
for (int i = 0, n = s.length; i < n; i++) {
if (s[i] <= 31 || s[i] == 34 || s[i] == 39 || s[i] == 92 || s[i] == 127) {
sb.append("\\x");
sb.append(toHexString((int)s[i] & 0xff));
}
else {
sb.append((char)s[i]);
}
}
return sb.toString();
}
private RemoteFunction[] GetFunction(String function) {
ArrayList rf = new ArrayList();
function = function.toLowerCase();
for (int i = 0, n = this.rfs.length; i < n; i++) {
if (function == this.rfs[i].name.toLowerCase()) {
rf.add(this.rfs[i]);
}
}
return (RemoteFunction[])(rf.toArray(new RemoteFunction[0]));
}
private void appendHeader() {
this.response.setContentType("text/plain; charset=" + this.charset);
this.response.addHeader("X-Powered-By", "PHPRPC Server/2.1");
this.response.setDateHeader("Date", (new Date()).getTime());
this.response.setDateHeader("Last-Modified", (new Date()).getTime());
this.response.addHeader("Cache-Control", "no-store, no-cache, must-revalidate");
this.response.addHeader("Cache-Control", "pre-check=0, post-check=0, max-age=0");
this.response.addHeader("Content-Encoding", "none");
}
private void writeError() throws UnsupportedEncodingException {
reswriter.print("phprpc_errno=\"" + this.errno.toString() + "\";\r\n");
if (this.encode) {
reswriter.print("phprpc_errstr=\"" + Base64.encode(this.errstr.getBytes(this.charset)) + "\";\r\n");
}
else {
reswriter.print("phprpc_errstr=\"" + this.addJsSlashes(this.errstr) + "\";\r\n");
}
reswriter.print("phprpc_output=\"" + this.output + "\";\r\n");
reswriter.print(this.callback);
}
private byte[] call(Method function, Object obj, byte[] arguments) throws UnSerializeException, UnsupportedEncodingException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Object[] args = (Object[])PHPSerializer.unserialize(arguments, (new Object[0]).getClass(), this.charset);
if (request.getParameter("phprpc_args") != null)
{
Class[] p = function.getParameterTypes();
for (int i = 0, n = Math.min(p.length, args.length); i < n; i++)
{
if (args[i] != null)
{
args[i] = PHPSerializer.cast(args[i], p[i]);
}
}
}
ByteArrayOutputStream bs = new ByteArrayOutputStream();
PrintStream defaultout = System.out;
PrintStream ps = new PrintStream(bs, true, this.charset);
System.setOut(ps);
byte[] result = PHPSerializer.serialize(function.invoke(obj, args), this.charset);
System.setOut(defaultout);
ps.close();
this.output = new String(bs.toByteArray(), this.charset);
return result;
}
public void start()
{
start(false, "UTF-8");
}
public void start(String charset)
{
start(false, charset);
}
public void start(boolean debug)
{
start(debug, "UTF-8");
}
public void start(boolean debug, String charset)
{
this.debug = debug;
this.charset = charset;
this.rfs = (RemoteFunction[])this.functions.toArray(new RemoteFunction[0]);
/*
response.Clear();
response.Buffer = true;
response.BufferOutput = true;
if (request["phprpc_encode"] != null)
{
this.encode = (request["phprpc_encode"].ToLower() != "false");
}
if (request["phprpc_callback"] != null)
{
this.callback = encoding.GetString(Convert.FromBase64String(request["phprpc_callback"]));
}
if (request["phprpc_ref"] != null)
{
this.byref = (request["phprpc_ref"].ToLower() != "false");
}
if (request["phprpc_encrypt"] != null)
{
string encrypt = request["phprpc_encrypt"].ToLower();
switch (encrypt)
{
case "true": this.encrypt = true; break;
case "false": this.encrypt = false; break;
case "0": this.encryptmode = 0; break;
case "1": this.encryptmode = 1; break;
case "2": this.encryptmode = 2; break;
default: break;
}
}
if (session["phprpc_encrypt"] != null)
{
Hashtable kp = (Hashtable)(session["phprpc_encrypt"]);
if (kp.ContainsKey("k"))
{
this.key = new byte[16];
byte[] key = BigInteger.Parse(kp["k"] as string).GetBytes();
for (int i = 1, n = key.Length; i <= n; i++)
{
this.key[16 - i] = key[n - i];
}
}
}
try
{
if (request["phprpc_func"] != null)
{
RemoteFunction[] rf = GetFunction(request["phprpc_func"]);
object[] args = null;
if (rf.Length > 0)
{
byte[] arguments;
arguments = PHPSerializer.Serialize(new object[] { }, this.encoding);
if (request["phprpc_args"] != null)
{
arguments = Convert.FromBase64String(request["phprpc_args"]);
if (this.encryptmode > 0)
{
if (this.key != null)
{
arguments = XXTEA.Decrypt(arguments, this.key);
}
else
{
this.errno = 1;
this.errstr = "Can't find the key for decryption.";
response.Clear();
this.AppendHeader();
this.WriteError();
return;
}
}
}
byte[] result = null;
for (int i = 0, n = rf.Length; i < n; i++)
{
for (int j = 0, m = rf[i].functions.Length; j < m; j++)
{
try
{
result = Call(rf[i].functions[j], rf[i].obj, arguments, out args);
break;
}
catch (Exception e)
{
if (i == n - 1 && j == m - 1) throw e;
}
}
}
if (this.byref && args != null)
{
arguments = PHPSerializer.Serialize(args, this.encoding);
}
if (this.encryptmode > 0)
{
if (this.key != null)
{
if (this.encryptmode > 1)
{
result = XXTEA.Encrypt(result, this.key);
}
if (this.byref)
{
arguments = XXTEA.Encrypt(arguments, this.key);
}
}
else
{
this.errno = 1;
this.errstr = "Can't find the key for encryption.";
response.Clear();
this.AppendHeader();
this.WriteError();
return;
}
}
if (this.encode)
{
this.result = Convert.ToBase64String(result);
if (this.byref)
{
this.arguments = Convert.ToBase64String(arguments);
}
}
else
{
this.result = this.AddJsSlashes(result);
if (this.byref)
{
this.arguments = this.AddJsSlashes(arguments);
}
}
}
else
{
this.errno = 1;
this.errstr = String.Concat("Can't find this function ", request["phprpc_func"], "().");
}
response.Clear();
this.AppendHeader();
if (this.errno == 0)
{
response.Write(String.Concat("phprpc_result=\"", this.result, "\";\r\n"));
if (this.byref)
{
response.Write(String.Concat("phprpc_args=\"", this.arguments, "\";\r\n"));
}
}
this.WriteError();
}
else
{
byte[] encrypt = null;
if (this.encrypt)
{
Hashtable kp = KeyPairGen.genRandomKeyPair();
BigInteger p = BigInteger.Parse(kp["p"] as string);
BigInteger g = BigInteger.Parse(kp["g"] as string);
BigInteger x = BigInteger.GenerateRandom(127);
BigInteger y = g.ModPow(x, p);
kp["y"] = y.ToString();
encrypt = PHPSerializer.Serialize(kp, this.encoding);
kp["x"] = x.ToString();
session["phprpc_encrypt"] = kp;
}
else if (request["phprpc_encrypt"] != null && request["phprpc_encrypt"].ToLower() != "false")
{
Hashtable kp = session["phprpc_encrypt"] as Hashtable;
kp["y"] = request["phprpc_encrypt"];
BigInteger y = BigInteger.Parse(kp["y"] as string);
BigInteger x = BigInteger.Parse(kp["x"] as string);
BigInteger p = BigInteger.Parse(kp["p"] as string);
BigInteger k = y.ModPow(x, p);
kp["k"] = k.ToString();
session["phprpc_encrypt"] = kp;
encrypt = PHPSerializer.Serialize(true, this.encoding);
}
response.Clear();
this.AppendHeader();
if (encrypt != null)
{
if (this.encode)
{
response.Write(String.Concat("phprpc_encrypt=\"", Convert.ToBase64String(encrypt), "\";\r\n"));
}
else
{
response.Write(String.Concat("phprpc_encrypt=\"", this.AddJsSlashes(encrypt), "\";\r\n"));
}
}
string[] fns = new string[this.rfs.Length];
for (int i = 0, n = fns.Length; i < n; i++)
{
fns[i] = this.rfs[i].name;
}
if (this.encode)
{
response.Write(String.Concat("phprpc_functions=\"", Convert.ToBase64String(PHPSerializer.Serialize(fns, this.encoding)), "\";\r\n"));
}
else
{
response.Write(String.Concat("phprpc_functions=\"", this.AddJsSlashes(PHPSerializer.Serialize(fns, this.encoding)), "\";\r\n"));
}
response.Write(this.callback);
}
}
catch (Exception e)
{
this.errno = 1;
if (this.debug)
{
this.errstr = e.ToString();
}
else
{
this.errstr = e.Message;
}
response.Clear();
this.AppendHeader();
this.WriteError();
}
*/
}
}