手写tomcat系列3-长叶-第一个Servlet容器优化

系列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。
划重点:本次优化是思路二的实现。
UML图,比系列2多两个Facade类实现,具体功能看代码。
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完全相同,不再重复列出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值