- 浏览: 930113 次
- 性别:
- 来自: 北京
-
文章分类
- 全部博客 (498)
- J2EE (52)
- 数据库 (17)
- java基础 (43)
- web技术 (19)
- 程序设计 (6)
- 操作系统 (18)
- IT资讯 (7)
- 我的IT生活 (12)
- 学习笔记 (9)
- Jquery (25)
- JavaScript (18)
- spring (40)
- Hibernate (12)
- Struts (10)
- YUI (2)
- Extjs (22)
- .net (0)
- Eclipse (10)
- 社会主义 (2)
- 服务器 (9)
- CSS (8)
- 网络安全 (16)
- 版本控制 (9)
- PHP (2)
- Oracle (42)
- SQL server (1)
- Mysql (11)
- 项目管理 (3)
- 开发工具使用 (10)
- SQL语句 (7)
- Perl (0)
- Shell (6)
- 漏洞 (4)
- ibatis (5)
- hacker (2)
- SQL注入 (6)
- Hacker工具 (2)
- 入侵和渗透 (7)
- 插件/组件 (2)
- 最爱开源 (5)
- 常用软件 (2)
- DOS (1)
- HTML (2)
- Android (9)
- CMS (1)
- portal (8)
- Linux (7)
- OSGI (1)
- Mina (5)
- maven (2)
- hadoop (7)
- twitter storm (2)
- sap hana (0)
- OAuth (0)
- RESTful (1)
- Nginx (4)
- flex (1)
- Dubbo (1)
- redis (1)
- springMVC (1)
- node.js (1)
- solr (2)
- Flume (1)
- MongoDB (2)
- ElasticSearch (1)
最新评论
-
M_drm:
请问要怎么设置浏览器才不报没权限呢?
用JS在页面调用本地可执行文件的方法(ACTIVEX) -
Alexniver:
官方文档。When importing data into I ...
mysql导入数据过慢 解决方法 -
camelwoo:
我记得 Criteria 可以做连接查询与子查询,也可以做分页 ...
Hibernate总结篇二 -
zhenglongfei:
楼主如果SubKeyName 这个节点不存在,怎么办??怎么用 ...
Java操作注册表 -
yxx676229549:
用log4j 2 了
logback
项目选定Hessian作为web service的实现方式,确实很轻量级,速度就跟直接用socket差不多,全是二进制传送节约了不少开销。但是在使用过程中有业务需要是必须获得远程端的ip地址,主机名等信息的。翻便Hessian的文档和google了n次未果,迫不得已到caucho和spring论坛去问,都没有得到答复。今天心一横把hessian的源代码加入到项目中单步跟踪,总算有点小收获。献丑分享出来,一方面给需要的朋友,主要还是希望各位找找是否存在bug,以及是否有更好的改良。
一:先撇开Spring不谈,来看看纯Hessian的调用
按照hessian文档里边介绍的demo,在web.xml里边如下配置
由此可知Hessian调用的入口是HessianServlet这个Servlet,进去看看
先看init()函数,功能还是一样,初始话一些东西,读入init-param的内容,并且load这些init-param的class
主要的还是service()函数
在service函数里边会获得request和response对象的输入和输出流,用来构造Hessian2Input和Hessian2Output,Hessian就是解析这两个东西来执行函数调用的。当然,在service里边还有一个重要的语句
Java代码
ServiceContext.begin(req, serviceId, objectId);
ServiceContext.begin(req, serviceId, objectId);
这个函数有点奇怪,我每次到这里serviceId和objectId都是空,不知道是不是历史遗留问题还存在这两个参数。
进去这个类看看
原来ServiceContext 是用来保存当前调用线程的上下文的,比如request对象等(不知道这个解释对不对)。有了这个东西就太好了,因为里边有request,就有了调用端的一切信息,呵呵。
继续回来看那个Servlet,到了真正调用的时候了,也就是这段代码
跟踪invoke方法看看真面目
就是在这个方法里边,hessian把包装过的输入输出流当作参数传入并进行解析的,看看这个函数的第一句,正是取得ServiceContext的地方,此时应该就是把刚才Servlet里边保存的上下文取出来使用。
这个时候出现了第一个hack的地方 Java代码
String ip = context.getContextRequest().getRemoteAddr();
String ip = context.getContextRequest().getRemoteAddr();在此处我取得远程的ip地址保存起来。然后在第二个hack的地方
第三个hack的地方就是 in.readObject(args[i], ip); 这个方法。 这个方法是我自己加的,原本只有
in.readObject(args[i]); 这个方法。 这个方法就是hessian读取参数值的地方
进去看看
剩下的步骤就原封不动的是hessian来处理了,没有需要干涉的地方,你也就能在你的服务端service函数里边获得这个你想要的信息了。
这就是Hessian的一个普通流程,不知道分析和Hack的对不对,我在这里是调试成功了,但是还没彻底测试有没有其它bug。 至于跟Spring的结合,待会儿跟帖来说。
一:先撇开Spring不谈,来看看纯Hessian的调用
按照hessian文档里边介绍的demo,在web.xml里边如下配置
<servlet> <servlet-name>hello</servlet-name> <servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class> <init-param> <param-name>home-class</param-name> <param-value>example.BasicService</param-value> </init-param> <init-param> <param-name>home-api</param-name> <param-value>example.Basic</param-value> </init-param> </servlet> <servlet-mapping> <url-pattern>/hello</url-pattern> <servlet-name>hello</servlet-name> </servlet-mapping> <servlet> <servlet-name>hello</servlet-name> <servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class> <init-param> <param-name>home-class</param-name> <param-value>example.BasicService</param-value> </init-param> <init-param> <param-name>home-api</param-name> <param-value>example.Basic</param-value> </init-param> </servlet> <servlet-mapping> <url-pattern>/hello</url-pattern> <servlet-name>hello</servlet-name> </servlet-mapping>
由此可知Hessian调用的入口是HessianServlet这个Servlet,进去看看
/** * Servlet for serving Hessian services. */ public class HessianServlet extends GenericServlet { private Class _homeAPI; private Object _homeImpl; private Class _objectAPI; private Object _objectImpl; private HessianSkeleton _homeSkeleton; private HessianSkeleton _objectSkeleton; private SerializerFactory _serializerFactory; public String getServletInfo() { return "Hessian Servlet"; } /** * Sets the home api. */ public void setHomeAPI(Class api) { _homeAPI = api; } /** * Sets the home implementation */ public void setHome(Object home) { _homeImpl = home; } /** * Sets the object api. */ public void setObjectAPI(Class api) { _objectAPI = api; } /** * Sets the object implementation */ public void setObject(Object object) { _objectImpl = object; } /** * Sets the service class. */ public void setService(Object service) { setHome(service); } /** * Sets the api-class. */ public void setAPIClass(Class api) { setHomeAPI(api); } /** * Gets the api-class. */ public Class getAPIClass() { return _homeAPI; } /** * Sets the serializer factory. */ public void setSerializerFactory(SerializerFactory factory) { _serializerFactory = factory; } /** * Gets the serializer factory. */ public SerializerFactory getSerializerFactory() { if (_serializerFactory == null) _serializerFactory = new SerializerFactory(); return _serializerFactory; } /** * Sets the serializer send collection java type. */ public void setSendCollectionType(boolean sendType) { getSerializerFactory().setSendCollectionType(sendType); } /** * Initialize the service, including the service object. */ public void init(ServletConfig config) throws ServletException { super.init(config); try { if (_homeImpl != null) { } else if (getInitParameter("home-class") != null) { String className = getInitParameter("home-class"); Class homeClass = loadClass(className); _homeImpl = homeClass.newInstance(); init(_homeImpl); } else if (getInitParameter("service-class") != null) { String className = getInitParameter("service-class"); Class homeClass = loadClass(className); _homeImpl = homeClass.newInstance(); init(_homeImpl); } else { if (getClass().equals(HessianServlet.class)) throw new ServletException("server must extend HessianServlet"); _homeImpl = this; } if (_homeAPI != null) { } else if (getInitParameter("home-api") != null) { String className = getInitParameter("home-api"); _homeAPI = loadClass(className); } else if (getInitParameter("api-class") != null) { String className = getInitParameter("api-class"); _homeAPI = loadClass(className); } else if (_homeImpl != null) { _homeAPI = findRemoteAPI(_homeImpl.getClass()); if (_homeAPI == null) _homeAPI = _homeImpl.getClass(); } if (_objectImpl != null) { } else if (getInitParameter("object-class") != null) { String className = getInitParameter("object-class"); Class objectClass = loadClass(className); _objectImpl = objectClass.newInstance(); init(_objectImpl); } if (_objectAPI != null) { } else if (getInitParameter("object-api") != null) { String className = getInitParameter("object-api"); _objectAPI = loadClass(className); } else if (_objectImpl != null) _objectAPI = _objectImpl.getClass(); _homeSkeleton = new HessianSkeleton(_homeImpl, _homeAPI); if (_objectAPI != null) _homeSkeleton.setObjectClass(_objectAPI); if (_objectImpl != null) { _objectSkeleton = new HessianSkeleton(_objectImpl, _objectAPI); _objectSkeleton.setHomeClass(_homeAPI); } else _objectSkeleton = _homeSkeleton; } catch (ServletException e) { throw e; } catch (Exception e) { throw new ServletException(e); } } private Class findRemoteAPI(Class implClass) { if (implClass == null || implClass.equals(GenericService.class)) return null; Class []interfaces = implClass.getInterfaces(); if (interfaces.length == 1) return interfaces[0]; return findRemoteAPI(implClass.getSuperclass()); } private Class loadClass(String className) throws ClassNotFoundException { ClassLoader loader = Thread.currentThread().getContextClassLoader(); if (loader != null) return Class.forName(className, false, loader); else return Class.forName(className); } private void init(Object service) throws ServletException { if (service instanceof Service) ((Service) service).init(getServletConfig()); else if (service instanceof Servlet) ((Servlet) service).init(getServletConfig()); } /** * Execute a request. The path-info of the request selects the bean. * Once the bean's selected, it will be applied. */ public void service(ServletRequest request, ServletResponse response) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; if (! req.getMethod().equals("POST")) { res.setStatus(500, "Hessian Requires POST"); PrintWriter out = res.getWriter(); res.setContentType("text/html"); out.println("<h1>Hessian Requires POST</h1>"); return; } String serviceId = req.getPathInfo(); String objectId = req.getParameter("id"); if (objectId == null) objectId = req.getParameter("ejbid"); ServiceContext.begin(req, serviceId, objectId); try { InputStream is = request.getInputStream(); OutputStream os = response.getOutputStream(); Hessian2Input in = new Hessian2Input(is); AbstractHessianOutput out; SerializerFactory serializerFactory = getSerializerFactory(); in.setSerializerFactory(serializerFactory); int code = in.read(); if (code != 'c') { // XXX: deflate throw new IOException("expected 'c' in hessian input at " + code); } int major = in.read(); int minor = in.read(); if (major >= 2) out = new Hessian2Output(os); else out = new HessianOutput(os); out.setSerializerFactory(serializerFactory); if (objectId != null) _objectSkeleton.invoke(in, out); else _homeSkeleton.invoke(in, out); out.close(); } catch (RuntimeException e) { throw e; } catch (ServletException e) { throw e; } catch (Throwable e) { throw new ServletException(e); } finally { ServiceContext.end(); } } } /** * Servlet for serving Hessian services. */ public class HessianServlet extends GenericServlet { private Class _homeAPI; private Object _homeImpl; private Class _objectAPI; private Object _objectImpl; private HessianSkeleton _homeSkeleton; private HessianSkeleton _objectSkeleton; private SerializerFactory _serializerFactory; public String getServletInfo() { return "Hessian Servlet"; } /** * Sets the home api. */ public void setHomeAPI(Class api) { _homeAPI = api; } /** * Sets the home implementation */ public void setHome(Object home) { _homeImpl = home; } /** * Sets the object api. */ public void setObjectAPI(Class api) { _objectAPI = api; } /** * Sets the object implementation */ public void setObject(Object object) { _objectImpl = object; } /** * Sets the service class. */ public void setService(Object service) { setHome(service); } /** * Sets the api-class. */ public void setAPIClass(Class api) { setHomeAPI(api); } /** * Gets the api-class. */ public Class getAPIClass() { return _homeAPI; } /** * Sets the serializer factory. */ public void setSerializerFactory(SerializerFactory factory) { _serializerFactory = factory; } /** * Gets the serializer factory. */ public SerializerFactory getSerializerFactory() { if (_serializerFactory == null) _serializerFactory = new SerializerFactory(); return _serializerFactory; } /** * Sets the serializer send collection java type. */ public void setSendCollectionType(boolean sendType) { getSerializerFactory().setSendCollectionType(sendType); } /** * Initialize the service, including the service object. */ public void init(ServletConfig config) throws ServletException { super.init(config); try { if (_homeImpl != null) { } else if (getInitParameter("home-class") != null) { String className = getInitParameter("home-class"); Class homeClass = loadClass(className); _homeImpl = homeClass.newInstance(); init(_homeImpl); } else if (getInitParameter("service-class") != null) { String className = getInitParameter("service-class"); Class homeClass = loadClass(className); _homeImpl = homeClass.newInstance(); init(_homeImpl); } else { if (getClass().equals(HessianServlet.class)) throw new ServletException("server must extend HessianServlet"); _homeImpl = this; } if (_homeAPI != null) { } else if (getInitParameter("home-api") != null) { String className = getInitParameter("home-api"); _homeAPI = loadClass(className); } else if (getInitParameter("api-class") != null) { String className = getInitParameter("api-class"); _homeAPI = loadClass(className); } else if (_homeImpl != null) { _homeAPI = findRemoteAPI(_homeImpl.getClass()); if (_homeAPI == null) _homeAPI = _homeImpl.getClass(); } if (_objectImpl != null) { } else if (getInitParameter("object-class") != null) { String className = getInitParameter("object-class"); Class objectClass = loadClass(className); _objectImpl = objectClass.newInstance(); init(_objectImpl); } if (_objectAPI != null) { } else if (getInitParameter("object-api") != null) { String className = getInitParameter("object-api"); _objectAPI = loadClass(className); } else if (_objectImpl != null) _objectAPI = _objectImpl.getClass(); _homeSkeleton = new HessianSkeleton(_homeImpl, _homeAPI); if (_objectAPI != null) _homeSkeleton.setObjectClass(_objectAPI); if (_objectImpl != null) { _objectSkeleton = new HessianSkeleton(_objectImpl, _objectAPI); _objectSkeleton.setHomeClass(_homeAPI); } else _objectSkeleton = _homeSkeleton; } catch (ServletException e) { throw e; } catch (Exception e) { throw new ServletException(e); } } private Class findRemoteAPI(Class implClass) { if (implClass == null || implClass.equals(GenericService.class)) return null; Class []interfaces = implClass.getInterfaces(); if (interfaces.length == 1) return interfaces[0]; return findRemoteAPI(implClass.getSuperclass()); } private Class loadClass(String className) throws ClassNotFoundException { ClassLoader loader = Thread.currentThread().getContextClassLoader(); if (loader != null) return Class.forName(className, false, loader); else return Class.forName(className); } private void init(Object service) throws ServletException { if (service instanceof Service) ((Service) service).init(getServletConfig()); else if (service instanceof Servlet) ((Servlet) service).init(getServletConfig()); } /** * Execute a request. The path-info of the request selects the bean. * Once the bean's selected, it will be applied. */ public void service(ServletRequest request, ServletResponse response) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; if (! req.getMethod().equals("POST")) { res.setStatus(500, "Hessian Requires POST"); PrintWriter out = res.getWriter(); res.setContentType("text/html"); out.println("<h1>Hessian Requires POST</h1>"); return; } String serviceId = req.getPathInfo(); String objectId = req.getParameter("id"); if (objectId == null) objectId = req.getParameter("ejbid"); ServiceContext.begin(req, serviceId, objectId); try { InputStream is = request.getInputStream(); OutputStream os = response.getOutputStream(); Hessian2Input in = new Hessian2Input(is); AbstractHessianOutput out; SerializerFactory serializerFactory = getSerializerFactory(); in.setSerializerFactory(serializerFactory); int code = in.read(); if (code != 'c') { // XXX: deflate throw new IOException("expected 'c' in hessian input at " + code); } int major = in.read(); int minor = in.read(); if (major >= 2) out = new Hessian2Output(os); else out = new HessianOutput(os); out.setSerializerFactory(serializerFactory); if (objectId != null) _objectSkeleton.invoke(in, out); else _homeSkeleton.invoke(in, out); out.close(); } catch (RuntimeException e) { throw e; } catch (ServletException e) { throw e; } catch (Throwable e) { throw new ServletException(e); } finally { ServiceContext.end(); } } }
先看init()函数,功能还是一样,初始话一些东西,读入init-param的内容,并且load这些init-param的class
主要的还是service()函数
在service函数里边会获得request和response对象的输入和输出流,用来构造Hessian2Input和Hessian2Output,Hessian就是解析这两个东西来执行函数调用的。当然,在service里边还有一个重要的语句
Java代码
ServiceContext.begin(req, serviceId, objectId);
ServiceContext.begin(req, serviceId, objectId);
这个函数有点奇怪,我每次到这里serviceId和objectId都是空,不知道是不是历史遗留问题还存在这两个参数。
进去这个类看看
public class ServiceContext { private static final ThreadLocal _localContext = new ThreadLocal(); private ServletRequest _request; private String _serviceName; private String _objectId; private int _count; private HashMap _headers = new HashMap(); private ServiceContext() { } /** * Sets the request object prior to calling the service's method. * * @param request the calling servlet request * @param serviceId the service identifier * @param objectId the object identifier */ public static void begin(ServletRequest request, String serviceName, String objectId) throws ServletException { ServiceContext context = (ServiceContext) _localContext.get(); if (context == null) { context = new ServiceContext(); _localContext.set(context); } context._request = request; context._serviceName = serviceName; context._objectId = objectId; context._count++; } /** * Returns the service request. */ public static ServiceContext getContext() { return (ServiceContext) _localContext.get(); } /** * Adds a header. */ public void addHeader(String header, Object value) { _headers.put(header, value); } /** * Gets a header. */ public Object getHeader(String header) { return _headers.get(header); } /** * Gets a header from the context. */ public static Object getContextHeader(String header) { ServiceContext context = (ServiceContext) _localContext.get(); if (context != null) return context.getHeader(header); else return null; } /** * Returns the service request. */ public static ServletRequest getContextRequest() { ServiceContext context = (ServiceContext) _localContext.get(); if (context != null) return context._request; else return null; } /** * Returns the service id, corresponding to the pathInfo of the URL. */ public static String getContextServiceName() { ServiceContext context = (ServiceContext) _localContext.get(); if (context != null) return context._serviceName; else return null; } /** * Returns the object id, corresponding to the ?id= of the URL. */ public static String getContextObjectId() { ServiceContext context = (ServiceContext) _localContext.get(); if (context != null) return context._objectId; else return null; } /** * Cleanup at the end of a request. */ public static void end() { ServiceContext context = (ServiceContext) _localContext.get(); if (context != null && --context._count == 0) { context._request = null; context._headers.clear(); } } /** * Returns the service request. * * @deprecated */ public static ServletRequest getRequest() { ServiceContext context = (ServiceContext) _localContext.get(); if (context != null) return context._request; else return null; } /** * Returns the service id, corresponding to the pathInfo of the URL. * * @deprecated */ public static String getServiceName() { ServiceContext context = (ServiceContext) _localContext.get(); if (context != null) return context._serviceName; else return null; } /** * Returns the object id, corresponding to the ?id= of the URL. * * @deprecated */ public static String getObjectId() { ServiceContext context = (ServiceContext) _localContext.get(); if (context != null) return context._objectId; else return null; } } public class ServiceContext { private static final ThreadLocal _localContext = new ThreadLocal(); private ServletRequest _request; private String _serviceName; private String _objectId; private int _count; private HashMap _headers = new HashMap(); private ServiceContext() { } /** * Sets the request object prior to calling the service's method. * * @param request the calling servlet request * @param serviceId the service identifier * @param objectId the object identifier */ public static void begin(ServletRequest request, String serviceName, String objectId) throws ServletException { ServiceContext context = (ServiceContext) _localContext.get(); if (context == null) { context = new ServiceContext(); _localContext.set(context); } context._request = request; context._serviceName = serviceName; context._objectId = objectId; context._count++; } /** * Returns the service request. */ public static ServiceContext getContext() { return (ServiceContext) _localContext.get(); } /** * Adds a header. */ public void addHeader(String header, Object value) { _headers.put(header, value); } /** * Gets a header. */ public Object getHeader(String header) { return _headers.get(header); } /** * Gets a header from the context. */ public static Object getContextHeader(String header) { ServiceContext context = (ServiceContext) _localContext.get(); if (context != null) return context.getHeader(header); else return null; } /** * Returns the service request. */ public static ServletRequest getContextRequest() { ServiceContext context = (ServiceContext) _localContext.get(); if (context != null) return context._request; else return null; } /** * Returns the service id, corresponding to the pathInfo of the URL. */ public static String getContextServiceName() { ServiceContext context = (ServiceContext) _localContext.get(); if (context != null) return context._serviceName; else return null; } /** * Returns the object id, corresponding to the ?id= of the URL. */ public static String getContextObjectId() { ServiceContext context = (ServiceContext) _localContext.get(); if (context != null) return context._objectId; else return null; } /** * Cleanup at the end of a request. */ public static void end() { ServiceContext context = (ServiceContext) _localContext.get(); if (context != null && --context._count == 0) { context._request = null; context._headers.clear(); } } /** * Returns the service request. * * @deprecated */ public static ServletRequest getRequest() { ServiceContext context = (ServiceContext) _localContext.get(); if (context != null) return context._request; else return null; } /** * Returns the service id, corresponding to the pathInfo of the URL. * * @deprecated */ public static String getServiceName() { ServiceContext context = (ServiceContext) _localContext.get(); if (context != null) return context._serviceName; else return null; } /** * Returns the object id, corresponding to the ?id= of the URL. * * @deprecated */ public static String getObjectId() { ServiceContext context = (ServiceContext) _localContext.get(); if (context != null) return context._objectId; else return null; } }
原来ServiceContext 是用来保存当前调用线程的上下文的,比如request对象等(不知道这个解释对不对)。有了这个东西就太好了,因为里边有request,就有了调用端的一切信息,呵呵。
继续回来看那个Servlet,到了真正调用的时候了,也就是这段代码
if (objectId != null) ctSkeleton.invoke(in, out); else Skeleton.invoke(in, out); if (objectId != null) _objectSkeleton.invoke(in, out); else _homeSkeleton.invoke(in, out);
跟踪invoke方法看看真面目
public void invoke(AbstractHessianInput in, AbstractHessianOutput out) throws Throwable { ServiceContext context = ServiceContext.getContext(); String header; while ((header = in.readHeader()) != null) { Object value = in.readObject(); context.addHeader(header, value); } String ip = context.getContextRequest().getRemoteAddr(); String methodName = in.readMethod(); Method method = getMethod(methodName); if (method != null) { } else if ("_hessian_getAttribute".equals(methodName)) { String attrName = in.readString(); in.completeCall(); String value = null; if ("java.api.class".equals(attrName)) alue = getAPIClassName(); else if ("java.home.class".equals(attrName)) alue = getHomeClassName(); else if ("java.object.class".equals(attrName)) alue = getObjectClassName(); out.startReply(); out.writeObject(value); out.completeReply(); return; } else if (method == null) { out.startReply(); out.writeFault("NoSuchMethodException", "The service has no method named: " + in.getMethod(), null); out.completeReply(); return; } Class []args = method.getParameterTypes(); Object []values = new Object[args.length]; //args[0] for (int i = 0; i < args.length; i++){ if(i == args.length-1){ values[i] = in.readObject(args[i], ip); }else{ values[i] = in.readObject(args[i]); } } in.completeCall(); Object result = null; try { result = method.invoke(_service, values); } catch (Throwable e) { if (e instanceof InvocationTargetException) e = ((InvocationTargetException) e).getTargetException(); log.log(Level.WARNING, e.toString(), e); out.startReply(); out.writeFault("ServiceException", e.getMessage(), e); out.completeReply(); return; } out.startReply(); out.writeObject(result); out.completeReply(); } public void invoke(AbstractHessianInput in, AbstractHessianOutput out) throws Throwable { ServiceContext context = ServiceContext.getContext(); String header; while ((header = in.readHeader()) != null) { Object value = in.readObject(); context.addHeader(header, value); } String ip = context.getContextRequest().getRemoteAddr(); String methodName = in.readMethod(); Method method = getMethod(methodName); if (method != null) { } else if ("_hessian_getAttribute".equals(methodName)) { String attrName = in.readString(); in.completeCall(); String value = null; if ("java.api.class".equals(attrName)) value = getAPIClassName(); else if ("java.home.class".equals(attrName)) value = getHomeClassName(); else if ("java.object.class".equals(attrName)) value = getObjectClassName(); out.startReply(); out.writeObject(value); out.completeReply(); return; } else if (method == null) { out.startReply(); out.writeFault("NoSuchMethodException", "The service has no method named: " + in.getMethod(), null); out.completeReply(); return; } Class []args = method.getParameterTypes(); Object []values = new Object[args.length]; //args[0] for (int i = 0; i < args.length; i++){ if(i == args.length-1){ values[i] = in.readObject(args[i], ip); }else{ values[i] = in.readObject(args[i]); } } in.completeCall(); Object result = null; try { result = method.invoke(_service, values); } catch (Throwable e) { if (e instanceof InvocationTargetException) e = ((InvocationTargetException) e).getTargetException(); log.log(Level.WARNING, e.toString(), e); out.startReply(); out.writeFault("ServiceException", e.getMessage(), e); out.completeReply(); return; } out.startReply(); out.writeObject(result); out.completeReply(); }
就是在这个方法里边,hessian把包装过的输入输出流当作参数传入并进行解析的,看看这个函数的第一句,正是取得ServiceContext的地方,此时应该就是把刚才Servlet里边保存的上下文取出来使用。
这个时候出现了第一个hack的地方 Java代码
String ip = context.getContextRequest().getRemoteAddr();
String ip = context.getContextRequest().getRemoteAddr();在此处我取得远程的ip地址保存起来。然后在第二个hack的地方
Class []args = method.getParameterTypes(); Object []values = new Object[args.length]; //args[0] for (int i = 0; i < args.length; i++){ if(i == args.length-1){ values[i] = in.readObject(args[i], ip); }else{ values[i] = in.readObject(args[i]); } } Class []args = method.getParameterTypes(); Object []values = new Object[args.length]; //args[0] for (int i = 0; i < args.length; i++){ if(i == args.length-1){ values[i] = in.readObject(args[i], ip); }else{ values[i] = in.readObject(args[i]); } }我用这个ip地址取代最后一个参数(web服务函数的参数,即远程端调用的函数的参数)。
第三个hack的地方就是 in.readObject(args[i], ip); 这个方法。 这个方法是我自己加的,原本只有
in.readObject(args[i]); 这个方法。 这个方法就是hessian读取参数值的地方
进去看看
/** * Reads an object from the input stream with an expected type. */ public Object readObject(Class cl, String ip) throws IOException { if (cl == null || cl == Object.class) return readObject(); int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read(); switch (tag) { case 'N': return null; case 'M': { String type = readType(); Deserializer reader; reader = findSerializerFactory().getObjectDeserializer(type); if (cl != reader.getType() && cl.isAssignableFrom(reader.getType())) return reader.readMap(this); reader = findSerializerFactory().getDeserializer(cl); return reader.readMap(this); } case 'O': { return readObjectDefinition(cl); } case 'o': { int ref = readInt(); ObjectDefinition def = (ObjectDefinition) _classDefs.get(ref - 1); return readObjectInstance(cl, def); } case 'V': { String type = readType(); int length = readLength(); Deserializer reader; reader = findSerializerFactory().getObjectDeserializer(type); if (cl != reader.getType() && cl.isAssignableFrom(reader.getType())) return reader.readList(this, length); reader = findSerializerFactory().getDeserializer(cl); Object v = reader.readList(this, length); return v; } case 'v': { int ref = readInt(); String type = (String) _types.get(ref); int length = readInt(); Deserializer reader; reader = findSerializerFactory().getObjectDeserializer(type); if (cl != reader.getType() && cl.isAssignableFrom(reader.getType())) return reader.readLengthList(this, length); reader = findSerializerFactory().getDeserializer(cl); Object v = reader.readLengthList(this, length); return v; } case 'R': { int ref = parseInt(); return _refs.get(ref); } case 'r': { String type = readType(); String url = readString(); return resolveRemote(type, url); } } if (tag >= 0) _offset--; Object value = findSerializerFactory().getDeserializer(cl).readObject(this); if(value instanceof String){ value = ip; } return value; } /** * Reads an object from the input stream with an expected type. */ public Object readObject(Class cl, String ip) throws IOException { if (cl == null || cl == Object.class) return readObject(); int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read(); switch (tag) { case 'N': return null; case 'M': { String type = readType(); Deserializer reader; reader = findSerializerFactory().getObjectDeserializer(type); if (cl != reader.getType() && cl.isAssignableFrom(reader.getType())) return reader.readMap(this); reader = findSerializerFactory().getDeserializer(cl); return reader.readMap(this); } case 'O': { return readObjectDefinition(cl); } case 'o': { int ref = readInt(); ObjectDefinition def = (ObjectDefinition) _classDefs.get(ref - 1); return readObjectInstance(cl, def); } case 'V': { String type = readType(); int length = readLength(); Deserializer reader; reader = findSerializerFactory().getObjectDeserializer(type); if (cl != reader.getType() && cl.isAssignableFrom(reader.getType())) return reader.readList(this, length); reader = findSerializerFactory().getDeserializer(cl); Object v = reader.readList(this, length); return v; } case 'v': { int ref = readInt(); String type = (String) _types.get(ref); int length = readInt(); Deserializer reader; reader = findSerializerFactory().getObjectDeserializer(type); if (cl != reader.getType() && cl.isAssignableFrom(reader.getType())) return reader.readLengthList(this, length); reader = findSerializerFactory().getDeserializer(cl); Object v = reader.readLengthList(this, length); return v; } case 'R': { int ref = parseInt(); return _refs.get(ref); } case 'r': { String type = readType(); String url = readString(); return resolveRemote(type, url); } } if (tag >= 0) _offset--; Object value = findSerializerFactory().getDeserializer(cl).readObject(this); if(value instanceof String){ value = ip; } return value; }我重载了这个方法,加入了一个String类型的参数,用来把ip地址传进去,并且最后返回这个值。到了这里,hack的原理大家应该知道了--就是强行修改远程调用端的调用函数里边的最后一个参数的值(规定为String类型),把这个值设为我想要的信息,那么服务端的服务函数就会获得这个值,并且进行后续处理。
剩下的步骤就原封不动的是hessian来处理了,没有需要干涉的地方,你也就能在你的服务端service函数里边获得这个你想要的信息了。
这就是Hessian的一个普通流程,不知道分析和Hack的对不对,我在这里是调试成功了,但是还没彻底测试有没有其它bug。 至于跟Spring的结合,待会儿跟帖来说。
发表评论
-
使用EhCache和Spring AOP实现计算结果缓存
2012-08-07 10:47 1085原文:http://kim-miao.iteye.com/bl ... -
wsdl axis2 spring
2012-08-02 17:06 980http://renxiangzyq.iteye.com/ ... -
spring 监听器 IntrospectorCleanupListener简介
2012-08-02 17:00 1096"在服务器运行过程中,Spring不停的运行的计划任 ... -
Quartz的cron时间表达式
2012-04-11 17:33 1352一个cron表达式有至少6个(也可能7个)有空格分隔的时间元素 ... -
Spring 框架的设计理念与设计模式分析
2012-03-06 13:49 1016Spring 框架的设计理念与设计模式分析 http://ww ... -
Spring事务配置的五种方式
2012-03-04 10:40 1431前段时间对Spring的事务配置做了比较深入的研究,在此之间对 ... -
Spring技术内幕:深入解析Spring架构与设计原理(转)
2011-07-01 16:58 1192http://jiwenke.iteye.com/blo ... -
AOP 的利器:ASM 3.0 介绍
2011-06-29 13:48 1496AOP 的利器:ASM 3.0 介绍 http://www ... -
在非web环境中使用spring
2011-06-29 13:34 4256Spring再强大,也要面对降临的问题--因为Spr ... -
Spring LDAP 1.3.1 发布
2010-12-05 21:17 1237http://www.iteye.com/news/18834 ... -
Spring MVC 3.x annotated controller的几点心得体会
2010-12-01 09:53 2518最近拿Spring MVC 3.x做项目,用了最新的系列相关A ... -
Spring开始关注移动应用开发,发布Spring Mobile,Spring Android
2010-11-29 11:01 3393近日,Roy Clarkson发布了S ... -
SSH全注解-annotation详细配置
2010-11-21 18:50 2493如果有点SSH框架的经验,这个很好理解.配置不难. 配置an ... -
spring安全框架应用
2010-10-11 22:09 3278第一步 将spring-security-core-2.0. ... -
spring3.0.4 新增加的注解(mvc:resources)
2010-08-23 22:19 8975从spring3.0.3发布以后一直等待spring3.0.4 ... -
spring2.0与spring2.5的差别
2010-08-22 00:14 1683资料:http://ajava.org/online/spri ... -
利用Spring框架封装的JavaMail现实同步或异步邮件发送
2010-08-21 23:25 5585利用Spring框架封装的JavaMail现实同步或异步邮件发 ... -
领略Spring 3.x 时代的Spring MVC
2010-08-21 23:20 1462鼎鼎大名的Spring框架3.0版在12月5日由其作者之一—— ... -
使用 Spring 2.5 基于注解驱动的 Spring MVC
2010-08-21 23:16 1058概述 继 Spring 2.0 对 Spring MVC ... -
Spring2.0压缩包目录说明
2010-08-21 22:44 6031、 Spring2.0压缩包目录说明 aspectj目录 ...
相关推荐
com.alibaba:hessian-lite:jar:3.2.1-fixed-2 hessian-lite hessian-lite-3.2.1-fixed-2.jar
《Hessian源码分析与Hack:携带远程调用端信息》 Hessian作为一种轻量级的RPC(远程过程调用)框架,因其高效、简洁的二进制协议,被广泛应用于构建Web服务。然而,在实际应用中,有时我们需要获取到远程调用端的IP...
赠送Maven依赖信息文件:hessian-4.0.63.pom; 包含翻译后的API文档:hessian-4.0.63-javadoc-API文档-中文(简体)版.zip; Maven坐标:com.caucho:hessian:4.0.63; 标签:hessian、caucho、jar包、java、中文文档;...
赠送Maven依赖信息文件:hessian-4.0.63.pom; 包含翻译后的API文档:hessian-4.0.63-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven坐标:com.caucho:hessian:4.0.63; 标签:hessian、caucho、jar包、java、...
在解压的"**hessian-4.0.51-src**"源码包中,主要包含两个关键文件:"**pom.xml**"和"**src**"。 1. **pom.xml**:这是Maven项目的配置文件,定义了项目依赖、构建过程等信息。通过这个文件,我们可以看到Hessian ...
赠送jar包:hessian-3.3.6.jar 赠送原API文档:hessian-3.3.6-javadoc.jar 赠送源代码:hessian-3.3.6-sources.jar 包含翻译后的API文档:hessian-3.3.6-javadoc-API文档-中文(简体)-英语-对照版.zip 对应Maven...
在IT行业中,远程调用是一种常见的技术,使得客户端可以跨网络调用远程服务器上的方法,就像调用本地方法一样方便。Hessian是Apache项目下的一个轻量级的RPC(Remote Procedure Call,远程过程调用)框架,它提供了...
赠送Maven依赖信息文件:hessian-3.3.6.pom; 包含翻译后的API文档:hessian-3.3.6-javadoc-API文档-中文(简体)版.zip; Maven坐标:com.alipay.sofa:hessian:3.3.6; 标签:sofa、hessian、alipay、jar包、java、...
hessian是一个轻量级的Java Remoting方案
Hessian是由Caucho Technology开发的一种二进制Web服务协议,它提供了对Java对象序列化和反序列化的支持,使得远程调用如同本地调用一样快速和简单。与传统的XML-RPC或SOAP相比,Hessian的序列化格式更为紧凑,因此...
Hessian是一种轻量级的二进制Web服务协议,它由Caucho Technology开发,用于提高远程调用的效率和速度。Hessian 4.0.7是该协议的一个版本,提供了一个Java库,允许开发者在Java应用之间进行高效的数据交换。这个版本...
Hessian是一种高效的二进制序列化协议,常用于远程过程调用(RPC)和服务之间的通信。这个压缩包包含了Hessian的多个版本,分别是Hessian3.1.6、Hessian3.2.1以及Hessian4.0.7。每个版本都有其特定的功能改进和优化...
java运行依赖jar包
在服务器端,通过HessianServlet来暴露这个服务,客户端则通过HessianProxyFactory来创建服务代理,从而能够调用远程服务的方法。这种简单设置可以让开发者快速理解Hessian的基本工作原理。 二、Hessian与Spring...
在这个专题中,我们将以hessian-4.0.33.jar为例,详细探讨Hessian框架的核心特性和使用方法。 一、Hessian协议简介 Hessian协议基于HTTP协议,但其数据传输采用二进制格式,这使得它在数据传输效率上远超基于文本...
1. **远程调用**:在Dubbo框架中,Hessian-lite用于实现服务调用的二进制序列化和反序列化,使得远程方法调用(RMI)更加高效。它将Java对象转换为二进制流,通过网络发送,然后在服务端反序列化回原来的对象,降低了...
【标题】"dubbo-hessian-lite" 是一个与阿里巴巴的著名开源远程调用框架 Dubbo 相关的组件。Dubbo 提供了多种序列化方式,其中之一就是 Hessian 序列化,而 hessian-lite 是 Dubbo 在编译时依赖的一个轻量级 Hessian...
Spring会自动创建代理对象,使得客户端可以通过这个代理对象调用远程服务的方法,就像调用本地对象一样。 3. **使用源码分析**: Hessian库提供了`HessianProxyFactoryBean`和`HessianServiceExporter`这两个关键...
Hessian二进制Web服务协议(Hessian Binary Web Service Protocol)是一种高效的、轻量级的远程过程调用(RPC)协议,它主要用于提高Web服务之间的通信效率。Hessian由Caucho Technology公司开发,旨在解决XML-RPC在...