tomcat解析(十七)Http11Processor

Http11Processor类的构造方法会做一些初始化的动作,但这些内容不在本文讲解范围内,因此这里先不细讲,有兴趣的同志可自已了解一下哈
 public Http11Processor(int headerBufferSize, JIoEndpoint endpoint) { this.endpoint = endpoint; request = new Request(); inputBuffer = new InternalInputBuffer(request, headerBufferSize); request.setInputBuffer(inputBuffer); response = new Response(); response.setHook(this); outputBuffer = new InternalOutputBuffer(response, headerBufferSize); response.setOutputBuffer(outputBuffer); request.setResponse(response); initializeFilters(); // Cause loading of HexUtils int foo = HexUtils.DEC[0]; }  

    我们主要还是看process方法,
1.一开始会先初始化一些I/O流
    // Setting up the I/O this.socket = socket; inputBuffer.setInputStream(socket.getInputStream()); outputBuffer.setOutputStream(socket.getOutputStream());     
2.解析请求头部
    // Parsing the request header try { if (keptAlive) { if (keepAliveTimeout > 0) { socket.setSoTimeout(keepAliveTimeout); } else if (soTimeout > 0) { socket.setSoTimeout(soTimeout); } } inputBuffer.parseRequestLine(); request.setStartTime(System.currentTimeMillis()); keptAlive = true; if (!disableUploadTimeout) { socket.setSoTimeout(timeout); } inputBuffer.parseHeaders(); } catch (IOException e) { error = true; break; } catch (Throwable t) { if (log.isDebugEnabled()) { log.debug(sm.getString("http11processor.header.parse"), t); } // 400 - Bad Request response.setStatus(400); error = true; } if (!error) { // Setting up filters, and parse some request headers rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE); try { prepareRequest(); } catch (Throwable t) { if (log.isDebugEnabled()) { log.debug(sm.getString("http11processor.request.prepare"), t); } // 400 - Internal Server Error response.setStatus(400); error = true; } }

3.调用处理类对请求进行处理,这里当然指的是具体的处理servlet啦
try { rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); adapter.service(request, response); // Handle when the response was committed before a serious // error occurred. Throwing a ServletException should both // set the status to 500 and set the errorException. // If we fail here, then the response is likely already // committed, so we can't try and set headers. if(keepAlive && !error) { // Avoid checking twice. error = response.getErrorException() != null || statusDropsConnection(response.getStatus()); } } catch (InterruptedIOException e) { error = true; } catch (Throwable t) { log.error(sm.getString("http11processor.request.process"), t); // 500 - Internal Server Error response.setStatus(500); error = true; }  

 这里需要看一下adapter是哪里来的,该类有setAdapter方法,调用的地方为Http11ConnectionHandler(该类为Http11Protocol的内部类)的createProcessor方法,参数为Http11Protocol的adapter变量,该变量是通过调用Http11Protocol的setAdapter方法设置进来的,其调用的地方为Connector.initialize,可看到以下语句:
// Initializa adapter adapter = new CoyoteAdapter(this); protocolHandler.setAdapter(adapter);  

  因此这里其实是将请求转发给CoyoteAdapter进行处理了,再看该类的service方法(是不是跟servlet很像啊:)),但该方法参数并非HttpServletRequest的实例,而是org.apache.coyote.Request实例,在该方法的前半部分,工作便是初始化servlet处理时需要用到的HttpServletRequest及HttpServletResponse实例,当然内容是从参数req而来,具体内容这里不细讲哈.
i.在初始化完HttpServletRequest及HttpServletResponse实例后,将调用postParseRequest做一些请求设置及请求匹配等处理
<1>内容有包括parseSessionId,查看请求中是否有"jsessionid="字段,有则调用request.setRequestedSessionId进行设置;
<2>匹配请求路径,获取用于处理的具体Host,Context,Servlet及对应的方法,这部分的内容也较多,这里先不讲,假设其完成了对路径的匹配
  connector.getMapper().map(serverName, decodedURI,
                            request.getMappingData());
  request.setContext((Context) request.getMappingData().context);
  request.setWrapper((Wrapper) request.getMappingData().wrapper);
<3>若有redirect设置,调用response.sendRedirect(redirectPath);
<4>如果支持Cookie,则从cookie中获取sessionId
 parseSessionCookiesId(req, request);
至此postParseRequest调用结束;
ii.connector.getContainer().getPipeline().getFirst().invoke(request, response);
 这里需要了解connector.getContainer()得到的对象是什么?查看其setContainer方法的调用,可以StandardService的setContainer里看到,而StandardService的setContainer则是在初始化StandardEngine的时候便会调用该方法(具体可看Catalina.createStartDigester),因此这里将会获得一个StandardEngine实例,再继续调用其getPipeline().getFirst().invoke(request, response),我们可在其构造方法中看到最后调用的应该是StandardEngineValve的invoke方法,该方法如下:
 /** * Select the appropriate child Host to process this request, * based on the requested server name. If no matching Host can * be found, return an appropriate HTTP error. * * @param request Request to be processed * @param response Response to be produced * @param valveContext Valve context used to forward to the next Valve * * @exception IOException if an input/output error occurred * @exception ServletException if a servlet error occurred */ public final void invoke(Request request, Response response) throws IOException, ServletException { // Select the Host to be used for this Request Host host = request.getHost(); if (host == null) { response.sendError (HttpServletResponse.SC_BAD_REQUEST, sm.getString("standardEngine.noHost", request.getServerName())); return; } // Ask this Host to process this request host.getPipeline().getFirst().invoke(request, response); }  

    这里将会继续调用StandardHost的相应方法,我们依然可在其构造方法里找到相应的对象为StandardHostValve,再看其invoke方法如下:
    /** * Select the appropriate child Context to process this request, * based on the specified request URI. If no matching Context can * be found, return an appropriate HTTP error. * * @param request Request to be processed * @param response Response to be produced * @param valveContext Valve context used to forward to the next Valve * * @exception IOException if an input/output error occurred * @exception ServletException if a servlet error occurred */ public final void invoke(Request request, Response response) throws IOException, ServletException { // Select the Context to be used for this Request Context context = request.getContext(); //这个Context为前面进行uri匹配的时候得到的 if (context == null) { response.sendError (HttpServletResponse.SC_INTERNAL_SERVER_ERROR, sm.getString("standardHost.noContext")); return; } // Bind the context CL to the current thread if( context.getLoader() != null ) { // Not started - it should check for availability first // This should eventually move to Engine, it's generic. Thread.currentThread().setContextClassLoader (context.getLoader().getClassLoader()); } // Ask this Context to process this request context.getPipeline().getFirst().invoke(request, response); //又调用Context里的相应方法 // Access a session (if present) to update last accessed time, based on a // strict interpretation of the specification if (Globals.STRICT_SERVLET_COMPLIANCE) { request.getSession(false); //获取session,如果没有不进行创建,如果没有session,但参数为true会新建session并 } //生成Cookie // Error page processing response.setSuspended(false); Throwable t = (Throwable) request.getAttribute(Globals.EXCEPTION_ATTR); if (t != null) { throwable(request, response, t); } else { status(request, response); } // Restore the context classloader Thread.currentThread().setContextClassLoader (StandardHostValve.class.getClassLoader()); }  

    在调用StandardContext的getPipeline().getFirst()时与其它的调用有所不同,不再只是简单的调用构造方法里加入的basic vavle,如果当前的Context有设置访问权限(在web.xml里配置),则会相应地在该Context的Pipeline对象里加入授权管理的处理类,具体可看ContextConfig.start-->ContextConfig.authenticatorConfig,在该方法中将与的auth-method对应地产生相应的处理类,如AUTH-METHOD为FORM,则将产生的处理类为org.apache.catalina.authenticator.FormAuthenticator(具体可参考配置文件org/apache/catalina/startup/Authenticators.properties),在实例化处理类后将调用Context的addValve方法加入到其pipeline对象中,可看一下该方法如下(具体类名为StandardPipeline):
    /** *

Add a new Valve to the end of the pipeline associated with this * Container. Prior to adding the Valve, the Valve's * setContainer() method will be called, if it implements * Contained, with the owning Container as an argument. * The method may throw an * IllegalArgumentException if this Valve chooses not to * be associated with this Container, or IllegalStateException * if it is already associated with a different Container.

* * @param valve Valve to be added * * @exception IllegalArgumentException if this Container refused to * accept the specified Valve * @exception IllegalArgumentException if the specifie Valve refuses to be * associated with this Container * @exception IllegalStateException if the specified Valve is already * associated with a different Container */ public void addValve(Valve valve) { // Validate that we can add this Valve if (valve instanceof Contained) ((Contained) valve).setContainer(this.container); // Start the new component if necessary if (started) { if (valve instanceof Lifecycle) { try { ((Lifecycle) valve).start(); } catch (LifecycleException e) { log.error("StandardPipeline.addValve: start: ", e); } } // Register the newly added valve registerValve(valve); } // Add this Valve to the set associated with this Pipeline if (first == null) { first = valve; valve.setNext(basic); } else { Valve current = first; while (current != null) { if (current.getNext() == basic) { current.setNext(valve); valve.setNext(basic); break; } current = current.getNext(); } } }  

    主要内容有i.启动处理类;ii.将该处理类设置为basic处理类(StandardContext的basic处理类为StandardContextValve,可见StandardContext的构造方法)的前一个处理类,如果basic处理类前无处理类,则此处理类为first处理类,因此当有配置访问限制的,将先调用对应的权限控制类的invoke方法,我们以FormAuthenticator(invoke方法在其父类AuthenticatorBase中)为例来看一下是如何进行处理的,由于该部分内容较多,因此将放在下一篇文章独立来讲

你可能感兴趣的:(tomcat)