手写tomcat系列3-长叶-第一个Servlet容器优化
2019-04-17 20:55
399 查看
系列2遗留问题
本文接系列2,首先抛出一个问题,系列2实现的第一个Servlet容器有一个安全问题:在 ServletProcessor1 类的 process 方法中执行servlet 的 service 方 法时,request对象向上转型为 javax.servlet.ServletRequest对象,response向上转型为
javax.servlet.ServletResponse对象。
try { servlet = (Servlet) myClass.newInstance(); servlet.service((ServletRequest) request,(ServletResponse) response); }
这种玩法存在安全漏洞,具体问题为:知道这个servlet 容器的内部运作的程序员可以分别把ServletRequest 和 ServletResponse 实例向下转型本容器的Request 和Response对象,并调用Request 和Response对象的公共方法。如可以调用Request的parse方法或调用Response的sendStaticResource 方法。同时不能将 parse 和 sendStaticResource 方法定义为private,因为其他的类需要调用上述两个方法。
解决思路一:让 Request 和Response 类拥有默认访问修饰(包访问权限),不允许在包外部被调用。
解决思路二:更优雅的解决办法,门面模式,使用 facade 类隐藏Request 和Response。
划重点:本次优化是思路二的实现。
RequestFacade类代码实现:
/** *** 门面模式应用,区别于代理模式,这里应用的目的是隐藏真request对象,而不是代理一个request对象接受用户请求。 * 使用此模式用户保护response和request对象中方法不被劫持利用。** */ public class RequestFacade implements ServletRequest { **// 持有私有化的ServletRequest对象,通过构造函数初始化,通过此方式隐藏真request对象** private ServletRequest request = null; public RequestFacade(Request request) { this.request = request; } /* implementation of the ServletRequest*/ public Object getAttribute(String attribute) { return request.getAttribute(attribute); } public Enumeration<?> getAttributeNames() { return request.getAttributeNames(); } @SuppressWarnings("deprecation") public String getRealPath(String path) { return request.getRealPath(path); } public RequestDispatcher getRequestDispatcher(String path) { return request.getRequestDispatcher(path); } public boolean isSecure() { return request.isSecure(); } public String getCharacterEncoding() { return request.getCharacterEncoding(); } public int getContentLength() { return request.getContentLength(); } public String getContentType() { return request.getContentType(); } public ServletInputStream getInputStream() throws IOException { return request.getInputStream(); } public Locale getLocale() { return request.getLocale(); } public Enumeration getLocales() { return request.getLocales(); } public String getParameter(String name) { return request.getParameter(name); } public Map getParameterMap() { return request.getParameterMap(); } public Enumeration getParameterNames() { return request.getParameterNames(); } public String[] getParameterValues(String parameter) { return request.getParameterValues(parameter); } public String getProtocol() { return request.getProtocol(); } public BufferedReader getReader() throws IOException { return request.getReader(); } public String getRemoteAddr() { return request.getRemoteAddr(); } public String getRemoteHost() { return request.getRemoteHost(); } public String getScheme() { return request.getScheme(); } public String getServerName() { return request.getServerName(); } public int getServerPort() { return request.getServerPort(); } public void removeAttribute(String attribute) { request.removeAttribute(attribute); } public void setAttribute(String key, Object value) { request.setAttribute(key, value); } public void setCharacterEncoding(String encoding) throws UnsupportedEncodingException { request.setCharacterEncoding(encoding); } }
ResponseFacade类代码实现:
/** * 门面模式应用,区别于代理模式,这里应用的目的是隐藏真request对象,而不是代理一个request对象接受用户请求。 * 使用此模式用户保护response和request对象中方法不被劫持利用。 */ public class ResponseFacade implements ServletResponse { private ServletResponse response; public ResponseFacade(Response response) { this.response = response; } public void flushBuffer() throws IOException { response.flushBuffer(); } public int getBufferSize() { return response.getBufferSize(); } public String getCharacterEncoding() { return response.getCharacterEncoding(); } public Locale getLocale() { return response.getLocale(); } public ServletOutputStream getOutputStream() throws IOException { return response.getOutputStream(); } public PrintWriter getWriter() throws IOException { return response.getWriter(); } public boolean isCommitted() { return response.isCommitted(); } public void reset() { response.reset(); } public void resetBuffer() { response.resetBuffer(); } public void setBufferSize(int size) { response.setBufferSize(size); } public void setContentLength(int length) { response.setContentLength(length); } public void setContentType(String type) { response.setContentType(type); } public void setLocale(Locale locale) { response.setLocale(locale); } }
ServletProcessor2.0实现(ServletProcessor1升级版)
public class ServletProcessor2 { public void process(Request request, Response response) { String uri = request.getUri(); String servletName = uri.substring(uri.lastIndexOf("/") + 1); URLClassLoader loader = null; try { // create a URLClassLoader URL[] urls = new URL[1]; URLStreamHandler streamHandler = null; File classPath = new File(Constants.WEB_ROOT); // the forming of repository is taken from the createClassLoader method in // org.apache.catalina.startup.ClassLoaderFactory String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString() ; // the code for forming the URL is taken from the addRepository method in // org.apache.catalina.loader.StandardClassLoader class. urls[0] = new URL(null, repository, streamHandler); loader = new URLClassLoader(urls); } catch (IOException e) { System.out.println(e.toString() ); } Class myClass = null; try { myClass = loader.loadClass(servletName); }catch (ClassNotFoundException e) { System.out.println(e.toString()); } Servlet servlet = null; /** * 门面模式应用,区别于代理模式,这里应用的目的是隐藏真request对象,而不是代理一个request对象接受用户请求。 */ **RequestFacade requestFacade = new RequestFacade(request); ResponseFacade responseFacade = new ResponseFacade(response);** try { servlet = (Servlet) myClass.newInstance(); **servlet.service((ServletRequest) requestFacade, (ServletResponse) responseFacade);** } catch (Exception e) { System.out.println(e.toString()); } catch (Throwable e) { System.out.println(e.toString()); } } }
其他类和系列2完全相同,不再重复列出。
相关文章推荐
- springboot框架servlet容器tomcat、Jetty、undertow压测报告
- Tomcat学习2.2(简单的Servlet容器)
- Web服务器(Apache)与Servlet容器(Tomcat)
- Servlet容器原型(三)——Tomcat 4默认连接器浅谈
- Apache CXF实现Web Service(3)——Tomcat容器和不借助Spring的普通Servlet实现JAX-RS(RESTful) web service
- tomcat之servlet容器
- [深入剖析Tomcat]一个简单的servlet容器实现
- JSP学习 —— 开篇:JSP,servlet容器,Tomcat,servlet容器之间的关系
- JSP学习 —— 开篇:JSP,servlet容器,Tomcat,servlet容器之间的关系
- 深入理解Tomcat系列之五:Context容器和Wrapper容器
- Servlet容器Tomcat中web.xml中url-pattern的配置详解[附带源码分析]
- JavaWeb学习之servlet快速入门(形象生动理解容器、Servlet、Tomcat、session之间的关系)
- Servlet容器:Jetty和tomcat的比较
- Tomcat学习2.1(简单的Servlet容器)
- tomcat(5)servlet容器
- 以Tomcat为例介绍Servlet容器启动过程
- Servlet+Tomcat制作出第一个运行在Tomcat上的Java应用程序
- 深入剖析Tomcat 第五章 Servlet容器
- Spring Boot 定制与优化内置的Tomcat容器实例详解
- Java应用容器介绍以及tomcat优化实战