org/apache/tomcat/embed/tomcat-embed-core/8.0.33/tomcat-embed-core-8.0.33-sources.jar!/org/apache/catalina/core/ApplicationDispatcher.javajava
private void doDispatch(ServletRequest request, ServletResponse response) throws ServletException, IOException private void doForward(ServletRequest request, ServletResponse response) throws ServletException, IOException private void doInclude(ServletRequest request, ServletResponse response) throws ServletException, IOException
這裏看doDispatchapache
private void doDispatch(ServletRequest request, ServletResponse response) throws ServletException, IOException { // Set up to handle the specified request and response State state = new State(request, response, false); // Create a wrapped response to use for this request wrapResponse(state); ApplicationHttpRequest wrequest = (ApplicationHttpRequest) wrapRequest(state); if (queryString != null) { wrequest.setQueryParams(queryString); } wrequest.setAttribute(Globals.DISPATCHER_TYPE_ATTR, DispatcherType.ASYNC); wrequest.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, getCombinedPath()); wrequest.setContextPath(context.getPath()); wrequest.setRequestURI(requestURI); wrequest.setServletPath(servletPath); wrequest.setPathInfo(pathInfo); if (queryString != null) { wrequest.setQueryString(queryString); wrequest.setQueryParams(queryString); } invoke(state.outerRequest, state.outerResponse, state); }
ApplicationDispatcher.doDispatch-->ApplicationHttpRequest.setQueryString -->ApplicationHttpRequest.parseParameters -->mergeParameterstomcat
private void mergeParameters() { if ((queryParamString == null) || (queryParamString.length() < 1)) return; // Parse the query string from the dispatch target Parameters paramParser = new Parameters(); MessageBytes queryMB = MessageBytes.newInstance(); queryMB.setString(queryParamString); String encoding = getCharacterEncoding(); // No need to process null value, as ISO-8859-1 is the default encoding // in MessageBytes.toBytes(). if (encoding != null) { try { queryMB.setCharset(B2CConverter.getCharset(encoding)); } catch (UnsupportedEncodingException ignored) { // Fall-back to ISO-8859-1 } } paramParser.setQuery(queryMB); paramParser.setQueryStringEncoding(encoding); paramParser.handleQueryParameters(); // Insert the additional parameters from the dispatch target Enumeration<String> dispParamNames = paramParser.getParameterNames(); while (dispParamNames.hasMoreElements()) { String dispParamName = dispParamNames.nextElement(); String[] dispParamValues = paramParser.getParameterValues(dispParamName); String[] originalValues = parameters.get(dispParamName); if (originalValues == null) { parameters.put(dispParamName, dispParamValues); continue; } parameters.put(dispParamName, mergeValues(dispParamValues, originalValues)); } }
org/apache/tomcat/embed/tomcat-embed-core/8.0.33/tomcat-embed-core-8.0.33-sources.jar!/org/apache/catalina/connector/Request.java多線程
/** * Parse request parameters. */ protected void parseParameters() { parametersParsed = true; Parameters parameters = coyoteRequest.getParameters(); boolean success = false; try { // Set this every time in case limit has been changed via JMX parameters.setLimit(getConnector().getMaxParameterCount()); // getCharacterEncoding() may have been overridden to search for // hidden form field containing request encoding String enc = getCharacterEncoding(); boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI(); if (enc != null) { parameters.setEncoding(enc); if (useBodyEncodingForURI) { parameters.setQueryStringEncoding(enc); } } else { parameters.setEncoding (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING); if (useBodyEncodingForURI) { parameters.setQueryStringEncoding (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING); } } parameters.handleQueryParameters(); if (usingInputStream || usingReader) { success = true; return; } if( !getConnector().isParseBodyMethod(getMethod()) ) { success = true; return; } String contentType = getContentType(); if (contentType == null) { contentType = ""; } int semicolon = contentType.indexOf(';'); if (semicolon >= 0) { contentType = contentType.substring(0, semicolon).trim(); } else { contentType = contentType.trim(); } if ("multipart/form-data".equals(contentType)) { parseParts(false); success = true; return; } if (!("application/x-www-form-urlencoded".equals(contentType))) { success = true; return; } int len = getContentLength(); if (len > 0) { int maxPostSize = connector.getMaxPostSize(); if ((maxPostSize >= 0) && (len > maxPostSize)) { Context context = getContext(); if (context != null && context.getLogger().isDebugEnabled()) { context.getLogger().debug( sm.getString("coyoteRequest.postTooLarge")); } checkSwallowInput(); parameters.setParseFailedReason(FailReason.POST_TOO_LARGE); return; } byte[] formData = null; if (len < CACHED_POST_LEN) { if (postData == null) { postData = new byte[CACHED_POST_LEN]; } formData = postData; } else { formData = new byte[len]; } try { if (readPostBody(formData, len) != len) { parameters.setParseFailedReason(FailReason.REQUEST_BODY_INCOMPLETE); return; } } catch (IOException e) { // Client disconnect Context context = getContext(); if (context != null && context.getLogger().isDebugEnabled()) { context.getLogger().debug( sm.getString("coyoteRequest.parseParameters"), e); } parameters.setParseFailedReason(FailReason.CLIENT_DISCONNECT); return; } parameters.processParameters(formData, 0, len); } else if ("chunked".equalsIgnoreCase( coyoteRequest.getHeader("transfer-encoding"))) { byte[] formData = null; try { formData = readChunkedPostBody(); } catch (IllegalStateException ise) { // chunkedPostTooLarge error parameters.setParseFailedReason(FailReason.POST_TOO_LARGE); Context context = getContext(); if (context != null && context.getLogger().isDebugEnabled()) { context.getLogger().debug( sm.getString("coyoteRequest.parseParameters"), ise); } return; } catch (IOException e) { // Client disconnect parameters.setParseFailedReason(FailReason.CLIENT_DISCONNECT); Context context = getContext(); if (context != null && context.getLogger().isDebugEnabled()) { context.getLogger().debug( sm.getString("coyoteRequest.parseParameters"), e); } return; } if (formData != null) { parameters.processParameters(formData, 0, formData.length); } } success = true; } finally { if (!success) { parameters.setParseFailedReason(FailReason.UNKNOWN); } } }
/** * Read post body in an array. */ protected int readPostBody(byte body[], int len) throws IOException { int offset = 0; do { int inputLen = getStream().read(body, offset, len - offset); if (inputLen <= 0) { return offset; } offset += inputLen; } while ((len - offset) > 0); return len; }
/** * Read chunked post body. */ protected byte[] readChunkedPostBody() throws IOException { ByteChunk body = new ByteChunk(); byte[] buffer = new byte[CACHED_POST_LEN]; int len = 0; while (len > -1) { len = getStream().read(buffer, 0, CACHED_POST_LEN); if (connector.getMaxPostSize() >= 0 && (body.getLength() + len) > connector.getMaxPostSize()) { // Too much data checkSwallowInput(); throw new IllegalStateException( sm.getString("coyoteRequest.chunkedPostTooLarge")); } if (len > 0) { body.append(buffer, 0, len); } } if (body.getLength() == 0) { return null; } if (body.getLength() < body.getBuffer().length) { int length = body.getLength(); byte[] result = new byte[length]; System.arraycopy(body.getBuffer(), 0, result, 0, length); return result; } return body.getBuffer(); }
-->addParameterapp
public void addParameter( String key, String value ) throws IllegalStateException { if( key==null ) { return; } parameterCount ++; if (limit > -1 && parameterCount > limit) { // Processing this parameter will push us over the limit. ISE is // what Request.parseParts() uses for requests that are too big setParseFailedReason(FailReason.TOO_MANY_PARAMETERS); throw new IllegalStateException(sm.getString( "parameters.maxCountFail", Integer.valueOf(limit))); } ArrayList<String> values = paramHashValues.get(key); if (values == null) { values = new ArrayList<>(1); paramHashValues.put(key, values); } values.add(value); }
而後再這裏調用ide
public Enumeration<String> getParameterNames() { handleQueryParameters(); return Collections.enumeration(paramHashValues.keySet()); }
而Request的getParameterNames則委託Parameters的getParameterNamespost
public Enumeration<String> getParameterNames() { if (!parametersParsed) { parseParameters(); } return coyoteRequest.getParameters().getParameterNames(); }
最後,有個統一的merge過程,見上頭的mergeParameters。this
@Override public BufferedReader getReader() throws IOException { if (usingInputStream) { throw new IllegalStateException (sm.getString("coyoteRequest.getReader.ise")); } usingReader = true; inputBuffer.checkConverter(); if (reader == null) { reader = new CoyoteReader(inputBuffer); } return reader; }
@Override public ServletInputStream getInputStream() throws IOException { if (usingReader) { throw new IllegalStateException (sm.getString("coyoteRequest.getInputStream.ise")); } usingInputStream = true; if (inputStream == null) { inputStream = new CoyoteInputStream(inputBuffer); } return inputStream; }
Servlet Request的 getInputStream() getReader() getParameter(),在讀取post方法的參數時,使用了任意一個,再調用其餘兩個方法是讀取不到參數的。getParameter單線程上可重複使用,多線程的話可能會有異常,由於該方法依賴parametersParsed,這個boolean的參數不是原子的。url