This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit d28d6836b80d0709c56a3ab24d515788498c760e Author: Mark Thomas <ma...@apache.org> AuthorDate: Mon Oct 2 11:56:41 2023 +0100 Remove support for HTTP/2 server push --- java/org/apache/catalina/connector/Request.java | 19 - .../apache/catalina/connector/RequestFacade.java | 14 - .../catalina/core/ApplicationHttpRequest.java | 18 - .../catalina/core/ApplicationPushBuilder.java | 427 --------------------- .../apache/catalina/core/LocalStrings.properties | 5 - .../catalina/core/LocalStrings_fr.properties | 5 - .../catalina/core/LocalStrings_ja.properties | 5 - .../catalina/core/LocalStrings_ko.properties | 5 - .../catalina/core/LocalStrings_zh_CN.properties | 5 - .../apache/catalina/filters/RemoteIpFilter.java | 16 - .../catalina/core/TestApplicationPushBuilder.java | 72 ---- .../catalina/filters/TesterHttpServletRequest.java | 6 - .../apache/coyote/http2/TestHttp2Section_6_6.java | 127 ------ webapps/docs/changelog.xml | 5 + .../WEB-INF/classes/http2/SimpleImagePush.java | 59 --- webapps/examples/WEB-INF/web.xml | 10 - webapps/examples/servlets/index.html | 11 - 17 files changed, 5 insertions(+), 804 deletions(-) diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java index 8e800464be..cc9a515f96 100644 --- a/java/org/apache/catalina/connector/Request.java +++ b/java/org/apache/catalina/connector/Request.java @@ -65,7 +65,6 @@ import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; import jakarta.servlet.http.HttpUpgradeHandler; import jakarta.servlet.http.Part; -import jakarta.servlet.http.PushBuilder; import org.apache.catalina.Container; import org.apache.catalina.Context; @@ -79,7 +78,6 @@ import org.apache.catalina.Wrapper; import org.apache.catalina.core.ApplicationFilterChain; import org.apache.catalina.core.ApplicationMapping; import org.apache.catalina.core.ApplicationPart; -import org.apache.catalina.core.ApplicationPushBuilder; import org.apache.catalina.core.ApplicationSessionCookieConfig; import org.apache.catalina.core.AsyncContextImpl; import org.apache.catalina.mapper.MappingData; @@ -1866,23 +1864,6 @@ public class Request implements HttpServletRequest { } - @Override - public PushBuilder newPushBuilder() { - return newPushBuilder(this); - } - - - public PushBuilder newPushBuilder(HttpServletRequest request) { - AtomicBoolean result = new AtomicBoolean(); - coyoteRequest.action(ActionCode.IS_PUSH_SUPPORTED, result); - if (result.get()) { - return new ApplicationPushBuilder(this, request); - } else { - return null; - } - } - - @SuppressWarnings("unchecked") @Override public <T extends HttpUpgradeHandler> T upgrade(Class<T> httpUpgradeHandlerClass) diff --git a/java/org/apache/catalina/connector/RequestFacade.java b/java/org/apache/catalina/connector/RequestFacade.java index 956790888f..1a2f335076 100644 --- a/java/org/apache/catalina/connector/RequestFacade.java +++ b/java/org/apache/catalina/connector/RequestFacade.java @@ -40,7 +40,6 @@ import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; import jakarta.servlet.http.HttpUpgradeHandler; import jakarta.servlet.http.Part; -import jakarta.servlet.http.PushBuilder; import org.apache.tomcat.util.res.StringManager; @@ -573,19 +572,6 @@ public class RequestFacade implements HttpServletRequest { } - @Override - public PushBuilder newPushBuilder() { - checkFacade(); - return request.newPushBuilder(); - } - - - public PushBuilder newPushBuilder(HttpServletRequest request) { - checkFacade(); - return this.request.newPushBuilder(request); - } - - @Override public boolean isTrailerFieldsReady() { checkFacade(); diff --git a/java/org/apache/catalina/core/ApplicationHttpRequest.java b/java/org/apache/catalina/core/ApplicationHttpRequest.java index 1b93479d32..14f0855b9e 100644 --- a/java/org/apache/catalina/core/ApplicationHttpRequest.java +++ b/java/org/apache/catalina/core/ApplicationHttpRequest.java @@ -32,19 +32,15 @@ import java.util.NoSuchElementException; import jakarta.servlet.DispatcherType; import jakarta.servlet.RequestDispatcher; import jakarta.servlet.ServletContext; -import jakarta.servlet.ServletRequest; -import jakarta.servlet.ServletRequestWrapper; import jakarta.servlet.http.HttpServletMapping; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequestWrapper; import jakarta.servlet.http.HttpSession; -import jakarta.servlet.http.PushBuilder; import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.Manager; import org.apache.catalina.Session; -import org.apache.catalina.connector.RequestFacade; import org.apache.catalina.util.ParameterMap; import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.URLEncoder; @@ -597,20 +593,6 @@ class ApplicationHttpRequest extends HttpServletRequestWrapper { } - @Override - public PushBuilder newPushBuilder() { - ServletRequest current = getRequest(); - while (current instanceof ServletRequestWrapper) { - current = ((ServletRequestWrapper) current).getRequest(); - } - if (current instanceof RequestFacade) { - return ((RequestFacade) current).newPushBuilder(this); - } else { - return null; - } - } - - // -------------------------------------------------------- Package Methods /** diff --git a/java/org/apache/catalina/core/ApplicationPushBuilder.java b/java/org/apache/catalina/core/ApplicationPushBuilder.java deleted file mode 100644 index 90250326ac..0000000000 --- a/java/org/apache/catalina/core/ApplicationPushBuilder.java +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.catalina.core; - -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; - -import jakarta.servlet.SessionTrackingMode; -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpSession; -import jakarta.servlet.http.PushBuilder; - -import org.apache.catalina.Context; -import org.apache.catalina.authenticator.AuthenticatorBase; -import org.apache.catalina.connector.Request; -import org.apache.catalina.util.SessionConfig; -import org.apache.coyote.ActionCode; -import org.apache.tomcat.util.buf.HexUtils; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.collections.CaseInsensitiveKeyMap; -import org.apache.tomcat.util.http.CookieProcessor; -import org.apache.tomcat.util.http.parser.HttpParser; -import org.apache.tomcat.util.res.StringManager; - -public class ApplicationPushBuilder implements PushBuilder { - - private static final StringManager sm = StringManager.getManager(ApplicationPushBuilder.class); - private static final Set<String> DISALLOWED_METHODS = new HashSet<>(); - - static { - DISALLOWED_METHODS.add("POST"); - DISALLOWED_METHODS.add("PUT"); - DISALLOWED_METHODS.add("DELETE"); - DISALLOWED_METHODS.add("CONNECT"); - DISALLOWED_METHODS.add("OPTIONS"); - DISALLOWED_METHODS.add("TRACE"); - } - - private final HttpServletRequest baseRequest; - private final Request catalinaRequest; - private final org.apache.coyote.Request coyoteRequest; - private final String sessionCookieName; - private final String sessionPathParameterName; - private final boolean addSessionCookie; - private final boolean addSessionPathParameter; - - private final Map<String,List<String>> headers = new CaseInsensitiveKeyMap<>(); - private final List<Cookie> cookies = new ArrayList<>(); - private String method = "GET"; - private String path; - private String queryString; - private String sessionId; - private String userName; - - - public ApplicationPushBuilder(Request catalinaRequest, HttpServletRequest request) { - - baseRequest = request; - this.catalinaRequest = catalinaRequest; - coyoteRequest = catalinaRequest.getCoyoteRequest(); - - // Populate the initial list of HTTP headers - Enumeration<String> headerNames = request.getHeaderNames(); - while (headerNames.hasMoreElements()) { - String headerName = headerNames.nextElement(); - List<String> values = new ArrayList<>(); - headers.put(headerName, values); - Enumeration<String> headerValues = request.getHeaders(headerName); - while (headerValues.hasMoreElements()) { - values.add(headerValues.nextElement()); - } - } - - // Remove the headers - headers.remove("if-match"); - headers.remove("if-none-match"); - headers.remove("if-modified-since"); - headers.remove("if-unmodified-since"); - headers.remove("if-range"); - headers.remove("range"); - headers.remove("expect"); - headers.remove("authorization"); - headers.remove("referer"); - // Also remove the cookie header since it will be regenerated - headers.remove("cookie"); - - // set the referer header - StringBuffer referer = request.getRequestURL(); - if (request.getQueryString() != null) { - referer.append('?'); - referer.append(request.getQueryString()); - } - addHeader("referer", referer.toString()); - - // Session - Context context = catalinaRequest.getContext(); - sessionCookieName = SessionConfig.getSessionCookieName(context); - sessionPathParameterName = SessionConfig.getSessionUriParamName(context); - - HttpSession session = request.getSession(false); - if (session != null) { - sessionId = session.getId(); - } - if (sessionId == null) { - sessionId = request.getRequestedSessionId(); - } - if (!request.isRequestedSessionIdFromCookie() && !request.isRequestedSessionIdFromURL() && sessionId != null) { - Set<SessionTrackingMode> sessionTrackingModes = - request.getServletContext().getEffectiveSessionTrackingModes(); - addSessionCookie = sessionTrackingModes.contains(SessionTrackingMode.COOKIE); - addSessionPathParameter = sessionTrackingModes.contains(SessionTrackingMode.URL); - } else { - addSessionCookie = request.isRequestedSessionIdFromCookie(); - addSessionPathParameter = request.isRequestedSessionIdFromURL(); - } - - // Cookies - if (request.getCookies() != null) { - cookies.addAll(Arrays.asList(request.getCookies())); - } - for (Cookie responseCookie : catalinaRequest.getResponse().getCookies()) { - if (responseCookie.getMaxAge() < 0) { - // Path information not available so can only remove based on - // name. - cookies.removeIf(cookie -> cookie.getName().equals(responseCookie.getName())); - } else { - cookies.add(new Cookie(responseCookie.getName(), responseCookie.getValue())); - } - } - if (cookies.size() > 0) { - List<String> cookieValues = new ArrayList<>(1); - cookieValues.add(generateCookieHeader(cookies, catalinaRequest.getContext().getCookieProcessor())); - headers.put("cookie", cookieValues); - } - - // Authentication - if (catalinaRequest.getPrincipal() != null) { - if ((session == null) || catalinaRequest.getSessionInternal(false).getPrincipal() == null || - !(context.getAuthenticator() instanceof AuthenticatorBase) || - !((AuthenticatorBase) context.getAuthenticator()).getCache()) { - // Set a username only if there is no session cache for the principal - userName = catalinaRequest.getPrincipal().getName(); - } - setHeader("authorization", "x-push"); - } - } - - @Override - public PushBuilder path(String path) { - if (path.startsWith("/")) { - this.path = path; - } else { - String contextPath = baseRequest.getContextPath(); - int len = contextPath.length() + path.length() + 1; - StringBuilder sb = new StringBuilder(len); - sb.append(contextPath); - sb.append('/'); - sb.append(path); - this.path = sb.toString(); - } - return this; - } - - - @Override - public String getPath() { - return path; - } - - - @Override - public PushBuilder method(String method) { - String upperMethod = method.trim().toUpperCase(Locale.ENGLISH); - if (DISALLOWED_METHODS.contains(upperMethod) || upperMethod.length() == 0) { - throw new IllegalArgumentException(sm.getString("applicationPushBuilder.methodInvalid", upperMethod)); - } - // Check a token was supplied - if (!HttpParser.isToken(upperMethod)) { - throw new IllegalArgumentException(sm.getString("applicationPushBuilder.methodNotToken", upperMethod)); - } - this.method = method; - return this; - } - - - @Override - public String getMethod() { - return method; - } - - - @Override - public PushBuilder queryString(String queryString) { - this.queryString = queryString; - return this; - } - - - @Override - public String getQueryString() { - return queryString; - } - - - @Override - public PushBuilder sessionId(String sessionId) { - this.sessionId = sessionId; - return this; - } - - - @Override - public String getSessionId() { - return sessionId; - } - - - @Override - public PushBuilder addHeader(String name, String value) { - headers.computeIfAbsent(name, k -> new ArrayList<>()).add(value); - return this; - } - - - @Override - public PushBuilder setHeader(String name, String value) { - List<String> values = headers.get(name); - if (values == null) { - values = new ArrayList<>(); - headers.put(name, values); - } else { - values.clear(); - } - values.add(value); - - return this; - } - - - @Override - public PushBuilder removeHeader(String name) { - headers.remove(name); - - return this; - } - - - @Override - public Set<String> getHeaderNames() { - return Collections.unmodifiableSet(headers.keySet()); - } - - - @Override - public String getHeader(String name) { - List<String> values = headers.get(name); - if (values == null) { - return null; - } else { - return values.get(0); - } - } - - - @Override - public void push() { - if (path == null) { - throw new IllegalStateException(sm.getString("pushBuilder.noPath")); - } - - org.apache.coyote.Request pushTarget = new org.apache.coyote.Request(); - - pushTarget.method().setString(method); - // The next three are implied by the Javadoc getPath() - pushTarget.serverName().setString(baseRequest.getServerName()); - pushTarget.setServerPort(baseRequest.getServerPort()); - pushTarget.scheme().setString(baseRequest.getScheme()); - - // Copy headers - for (Map.Entry<String,List<String>> header : headers.entrySet()) { - for (String value : header.getValue()) { - pushTarget.getMimeHeaders().addValue(header.getKey()).setString(value); - } - } - - // Path and query string - int queryIndex = path.indexOf('?'); - String pushPath; - String pushQueryString = null; - if (queryIndex > -1) { - pushPath = path.substring(0, queryIndex); - if (queryIndex + 1 < path.length()) { - pushQueryString = path.substring(queryIndex + 1); - } - } else { - pushPath = path; - } - - // Session ID (do this before setting the path since it may change it) - if (sessionId != null) { - if (addSessionPathParameter) { - pushPath = pushPath + ";" + sessionPathParameterName + "=" + sessionId; - pushTarget.addPathParameter(sessionPathParameterName, sessionId); - } - if (addSessionCookie) { - String sessionCookieHeader = sessionCookieName + "=" + sessionId; - MessageBytes mb = pushTarget.getMimeHeaders().getValue("cookie"); - if (mb == null) { - mb = pushTarget.getMimeHeaders().addValue("cookie"); - mb.setString(sessionCookieHeader); - } else { - mb.setString(mb.getString() + ";" + sessionCookieHeader); - } - } - } - - // Undecoded path - just %nn encoded - pushTarget.requestURI().setString(pushPath); - pushTarget.decodedURI().setString(decode(pushPath, catalinaRequest.getConnector().getURICharset())); - - // Query string - if (pushQueryString == null && queryString != null) { - pushTarget.queryString().setString(queryString); - } else if (pushQueryString != null && queryString == null) { - pushTarget.queryString().setString(pushQueryString); - } else if (pushQueryString != null && queryString != null) { - pushTarget.queryString().setString(pushQueryString + "&" + queryString); - } - - // Authorization - if (userName != null) { - pushTarget.getRemoteUser().setString(userName); - pushTarget.setRemoteUserNeedsAuthorization(true); - } - - coyoteRequest.action(ActionCode.PUSH_REQUEST, pushTarget); - - // Reset for next call to this method - path = null; - headers.remove("if-none-match"); - headers.remove("if-modified-since"); - } - - - // Package private so it can be tested. charsetName must be in lower case. - static String decode(String input, Charset charset) { - int start = input.indexOf('%'); - int end = 0; - - // Shortcut - if (start == -1) { - return input; - } - - StringBuilder result = new StringBuilder(input.length()); - while (start != -1) { - // Found the start of a %nn sequence. Copy everything from the last - // end to this start to the output. - result.append(input.substring(end, start)); - // Advance the end 3 characters: %nn - end = start + 3; - while (end < input.length() && input.charAt(end) == '%') { - end += 3; - } - result.append(decodePercentSequence(input.substring(start, end), charset)); - start = input.indexOf('%', end); - } - // Append the remaining text - result.append(input.substring(end)); - - return result.toString(); - } - - - private static String decodePercentSequence(String sequence, Charset charset) { - byte[] bytes = new byte[sequence.length() / 3]; - for (int i = 0; i < bytes.length; i += 3) { - bytes[i] = (byte) ((HexUtils.getDec(sequence.charAt(1 + 3 * i)) << 4) + - HexUtils.getDec(sequence.charAt(2 + 3 * i))); - } - - return new String(bytes, charset); - } - - - private static String generateCookieHeader(List<Cookie> cookies, CookieProcessor cookieProcessor) { - StringBuilder result = new StringBuilder(); - boolean first = true; - for (Cookie cookie : cookies) { - if (first) { - first = false; - } else { - result.append(';'); - } - // The cookie header value generated by the CookieProcessor was - // originally intended for the Set-Cookie header on the response. - // However, if passed a Cookie with just a name and value set it - // will generate an appropriate header for the Cookie header on the - // pushed request. - result.append(cookieProcessor.generateHeader(cookie, null)); - } - return result.toString(); - } -} diff --git a/java/org/apache/catalina/core/LocalStrings.properties b/java/org/apache/catalina/core/LocalStrings.properties index fd59aa65dc..d3d47814d0 100644 --- a/java/org/apache/catalina/core/LocalStrings.properties +++ b/java/org/apache/catalina/core/LocalStrings.properties @@ -60,9 +60,6 @@ applicationFilterRegistration.nullInitParams=Unable to set initialisation parame applicationHttpRequest.fragmentInDispatchPath=The fragment in dispatch path [{0}] has been removed -applicationPushBuilder.methodInvalid=The HTTP method for a push request must be both cacheable and safe but [{0}] is not -applicationPushBuilder.methodNotToken=HTTP methods must be tokens but [{0}] contains a non-token character - applicationServletRegistration.setServletSecurity.iae=Null constraint specified for servlet [{0}] deployed to context with name [{1}] applicationServletRegistration.setServletSecurity.ise=Security constraints can''t be added to servlet [{0}] deployed to context with name [{1}] as the context has already been initialised @@ -162,8 +159,6 @@ naming.wsdlFailed=Failed to find wsdl file: [{0}] noPluggabilityServletContext.notAllowed=Section 4.4 of the Servlet 3.0 specification does not permit this method to be called from a ServletContextListener that was not defined in web.xml, a web-fragment.xml file nor annotated with @WebListener -pushBuilder.noPath=It is illegal to call push() before setting a path - propertiesRoleMappingListener.roleMappingFileNull=Role mapping file cannot be null propertiesRoleMappingListener.roleMappingFileEmpty=Role mapping file cannot be empty propertiesRoleMappingListener.roleMappingFileFail=Failed to load role mapping file [{0}] diff --git a/java/org/apache/catalina/core/LocalStrings_fr.properties b/java/org/apache/catalina/core/LocalStrings_fr.properties index f77785045b..cd627970f9 100644 --- a/java/org/apache/catalina/core/LocalStrings_fr.properties +++ b/java/org/apache/catalina/core/LocalStrings_fr.properties @@ -60,9 +60,6 @@ applicationFilterRegistration.nullInitParams=Impossible de fixer les paramètres applicationHttpRequest.fragmentInDispatchPath=Le fragment dans le chemin de dispatch [{0}] a été enlevé -applicationPushBuilder.methodInvalid=La méthode HTTP pour une requête push doit être à la fois être sans danger et pouvoir être mise en cache, mais [{0}] ne correspond pas -applicationPushBuilder.methodNotToken=Les méthodes HTTP doivent être des "token", mais [{0}] contient un caractère invalide dans un token. - applicationServletRegistration.setServletSecurity.iae=Contrainte nulle spécifiée pour le Servlet [{0}] déployé dans le contexte avec le nom [{1}] applicationServletRegistration.setServletSecurity.ise=Les contraintes de sécurité ne peuvent pas être ajoutées au Servlet [{0}] déployé dans le contexte [{1}] car le contexte a déjà été initialisé @@ -168,8 +165,6 @@ propertiesRoleMappingListener.roleMappingFileEmpty=Le fichier d'association de r propertiesRoleMappingListener.roleMappingFileFail=Erreur de chargement du fichier d''association de rôles [{0}] propertiesRoleMappingListener.roleMappingFileNull=Le fichier d'association de rôles ne peut être null -pushBuilder.noPath=Il est interdit d'appeler push() avant de fixer un chemin - standardContext.applicationListener=Erreur lors de la configuration de la classe d''écoute de l''application (application listener) [{0}] standardContext.applicationSkipped=L'installation des écouteurs (listeners) de l'application a été sautée suite aux erreurs précédentes standardContext.backgroundProcess.instanceManager=Exception lors du traitement d''arrière plan du gestionnaire d''instances [{0}] diff --git a/java/org/apache/catalina/core/LocalStrings_ja.properties b/java/org/apache/catalina/core/LocalStrings_ja.properties index 40006c8836..7faf8abedc 100644 --- a/java/org/apache/catalina/core/LocalStrings_ja.properties +++ b/java/org/apache/catalina/core/LocalStrings_ja.properties @@ -60,9 +60,6 @@ applicationFilterRegistration.nullInitParams=キー [{0}] または値 [{1}] の applicationHttpRequest.fragmentInDispatchPath=ディスパッチパス [{0}] 中のフラグメントは除去されました -applicationPushBuilder.methodInvalid=プッシュリクエストの HTTP メソッドはキャッシュ可能、かつ、安全でなければなりません。[{0}] は指定できません。 -applicationPushBuilder.methodNotToken=HTTP メソッド [{0}] にトークンとして利用できない文字が含まれています。 - applicationServletRegistration.setServletSecurity.iae=サーブレット [{0}] に指定されたNULL制約が、名前 [{1}] のコンテキストに配備されました applicationServletRegistration.setServletSecurity.ise=コンテキストが既に初期化されているため、名前 [{1}] のコンテキストに配備されたサーブレット [{0}] にセキュリティ制約を追加できません @@ -168,8 +165,6 @@ propertiesRoleMappingListener.roleMappingFileEmpty=ロール マッピング フ propertiesRoleMappingListener.roleMappingFileFail=ロール マッピング ファイル [{0}] のロードに失敗しました propertiesRoleMappingListener.roleMappingFileNull=ロール マッピング ファイルを null にすることはできません -pushBuilder.noPath=path を設定する前に push() を呼び出すことはできません。 - standardContext.applicationListener=クラス [{0}] のアプリケーションリスナの設定中にエラーが発生しました standardContext.applicationSkipped=前のエラーのためにアプリケーションリスナのインストールをスキップします standardContext.backgroundProcess.instanceManager=インスタンスマネージャ [{0}] のバックグラウンドプロセス処理中の例外 diff --git a/java/org/apache/catalina/core/LocalStrings_ko.properties b/java/org/apache/catalina/core/LocalStrings_ko.properties index 6d735f15cb..6ed9a1005d 100644 --- a/java/org/apache/catalina/core/LocalStrings_ko.properties +++ b/java/org/apache/catalina/core/LocalStrings_ko.properties @@ -60,9 +60,6 @@ applicationFilterRegistration.nullInitParams=널인 이름 또는 값 때문에, applicationHttpRequest.fragmentInDispatchPath=디스패치 경로 [{0}](으)로부터 URI fragment를 제거했습니다. -applicationPushBuilder.methodInvalid=PUSH 요청을 위한 HTTP 메소드는 반드시 캐시 가능하고 안전해야 하는데, [{0}]은(는) 그렇지 않습니다. -applicationPushBuilder.methodNotToken=HTTP 메소드들은 토큰들이어야 하지만, [{0}]은(는) 토큰이 아닌 문자를 포함하고 있습니다. - applicationServletRegistration.setServletSecurity.iae=[{1}](이)라는 이름의 컨텍스트에 배치된 서블릿 [{0}]을(를) 위해, 널 constraint가 지정되었습니다. applicationServletRegistration.setServletSecurity.ise=컨텍스트가 이미 초기화되었기에, [{1}](이)라는 이름의 컨텍스트에 배치된 서블릿 [{0}]에 security constraint들이 추가될 수 없습니다. @@ -159,8 +156,6 @@ naming.wsdlFailed=wsdl 파일을 찾지 못했습니다: [{0}] noPluggabilityServletContext.notAllowed=Servlet 3.0 스펙의 4.4 장에 따르면, web.xml 또는 web-fragment.xml 파일에 정의되지 않거나 @WebListener로 annotate되지 않은, ServletContextListener에서 이 메소드를 호출하는 것은 허용되지 않습니다. -pushBuilder.noPath=경로를 설정하기 전에 push()를 호출하는 것은 불허됩니다. - standardContext.applicationListener=클래스 [{0}]의 애플리케이션 리스너를 설정하는 중 오류 발생 standardContext.applicationSkipped=이전 오류(들)로 인하여, 애플리케이션 리스너들을 설치하는 것을 건너뛰었습니다. standardContext.backgroundProcess.instanceManager=인스턴스 매니저 [{0}]을(를) 백그라운드 프로세스에서 처리 중 예외 발생 diff --git a/java/org/apache/catalina/core/LocalStrings_zh_CN.properties b/java/org/apache/catalina/core/LocalStrings_zh_CN.properties index 1ce8fc779b..534134732a 100644 --- a/java/org/apache/catalina/core/LocalStrings_zh_CN.properties +++ b/java/org/apache/catalina/core/LocalStrings_zh_CN.properties @@ -61,9 +61,6 @@ applicationFilterRegistration.nullInitParams=由于name和(或)value为null, applicationHttpRequest.fragmentInDispatchPath=调度路径[{0}]中的片段已被删除 -applicationPushBuilder.methodInvalid=推送请求的HTTP方法必须既可缓存又安全,但是[{0}]不是 -applicationPushBuilder.methodNotToken=HTTP方法必须是令牌(token),但 [{0}] 包含非令牌字符 - applicationServletRegistration.setServletSecurity.iae=为部署到名为[{1}]的上下文的Servlet[{0}]指定的空约束 applicationServletRegistration.setServletSecurity.ise=无法将安全性约束添加到已部署到名称为[{1}]的上下文的servlet [{0}]中,因为上下文已被初始化 @@ -164,8 +161,6 @@ propertiesRoleMappingListener.roleMappingFileEmpty=角色映射文件不能为 propertiesRoleMappingListener.roleMappingFileFail=加载角色映射文件[{0}]失败 propertiesRoleMappingListener.roleMappingFileNull=角色映射文件不能为NULL -pushBuilder.noPath=在设置路径之前调用push()是非法的 - standardContext.applicationListener=配置应用程序监听器[{0}]错误 standardContext.applicationSkipped=由于以前的错误,已跳过安装应用程序侦听器 standardContext.backgroundProcess.instanceManager=异常处理实例管理器[{0}]后台进程 diff --git a/java/org/apache/catalina/filters/RemoteIpFilter.java b/java/org/apache/catalina/filters/RemoteIpFilter.java index 13a0eb7bf9..038f4a95b7 100644 --- a/java/org/apache/catalina/filters/RemoteIpFilter.java +++ b/java/org/apache/catalina/filters/RemoteIpFilter.java @@ -34,16 +34,13 @@ import jakarta.servlet.FilterChain; import jakarta.servlet.GenericFilter; import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; -import jakarta.servlet.ServletRequestWrapper; import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequestWrapper; import jakarta.servlet.http.HttpServletResponse; -import jakarta.servlet.http.PushBuilder; import org.apache.catalina.AccessLog; import org.apache.catalina.Globals; -import org.apache.catalina.connector.RequestFacade; import org.apache.catalina.util.RequestUtil; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; @@ -640,19 +637,6 @@ public class RemoteIpFilter extends GenericFilter { public StringBuffer getRequestURL() { return RequestUtil.getRequestURL(this); } - - @Override - public PushBuilder newPushBuilder() { - ServletRequest current = getRequest(); - while (current instanceof ServletRequestWrapper) { - current = ((ServletRequestWrapper) current).getRequest(); - } - if (current instanceof RequestFacade) { - return ((RequestFacade) current).newPushBuilder(this); - } else { - return null; - } - } } diff --git a/test/org/apache/catalina/core/TestApplicationPushBuilder.java b/test/org/apache/catalina/core/TestApplicationPushBuilder.java deleted file mode 100644 index e939084b64..0000000000 --- a/test/org/apache/catalina/core/TestApplicationPushBuilder.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.catalina.core; - -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - -import org.junit.Assert; -import org.junit.Test; - -public class TestApplicationPushBuilder { - - @Test - public void test01() { - doTest("foo", StandardCharsets.UTF_8, "foo"); - } - - @Test - public void test02() { - doTest("/foo", StandardCharsets.UTF_8, "/foo"); - } - - @Test - public void test03() { - doTest("%20foo", StandardCharsets.UTF_8, " foo"); - } - - @Test - public void test04() { - doTest("fo%20o", StandardCharsets.UTF_8, "fo o"); - } - - @Test - public void test05() { - doTest("foo%20", StandardCharsets.UTF_8, "foo "); - } - - @Test - public void test06() { - doTest("%21foo", StandardCharsets.UTF_8, "!foo"); - } - - @Test - public void test07() { - doTest("fo%21o", StandardCharsets.UTF_8, "fo!o"); - } - - @Test - public void test08() { - doTest("foo%21", StandardCharsets.UTF_8, "foo!"); - } - - - private void doTest(String input, Charset charset, String expected) { - String result = ApplicationPushBuilder.decode(input, charset); - Assert.assertEquals(expected, result); - } -} diff --git a/test/org/apache/catalina/filters/TesterHttpServletRequest.java b/test/org/apache/catalina/filters/TesterHttpServletRequest.java index 449963e6ec..e03737b83a 100644 --- a/test/org/apache/catalina/filters/TesterHttpServletRequest.java +++ b/test/org/apache/catalina/filters/TesterHttpServletRequest.java @@ -45,7 +45,6 @@ import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; import jakarta.servlet.http.HttpUpgradeHandler; import jakarta.servlet.http.Part; -import jakarta.servlet.http.PushBuilder; public class TesterHttpServletRequest implements HttpServletRequest { @@ -431,11 +430,6 @@ public class TesterHttpServletRequest implements HttpServletRequest { throw new RuntimeException("Not implemented"); } - @Override - public PushBuilder newPushBuilder() { - throw new RuntimeException("Not implemented"); - } - @Override public boolean isTrailerFieldsReady() { throw new RuntimeException("Not implemented"); diff --git a/test/org/apache/coyote/http2/TestHttp2Section_6_6.java b/test/org/apache/coyote/http2/TestHttp2Section_6_6.java deleted file mode 100644 index ae61fd31f1..0000000000 --- a/test/org/apache/coyote/http2/TestHttp2Section_6_6.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.coyote.http2; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; - -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.servlet.http.PushBuilder; - -import org.junit.Assert; -import org.junit.Test; - -import org.apache.catalina.Context; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.startup.Tomcat; - -/** - * Unit tests for Section 6.5 of <a href="https://tools.ietf.org/html/rfc7540">RFC 7540</a>. - */ -public class TestHttp2Section_6_6 extends Http2TestBase { - - - @Test - public void testPushPromise() throws Exception { - http2Connect(); - - // Build the push request - byte[] frameHeader = new byte[9]; - ByteBuffer headersPayload = ByteBuffer.allocate(128); - - List<Header> headers = new ArrayList<>(4); - headers.add(new Header(":method", "GET")); - headers.add(new Header(":scheme", "http")); - headers.add(new Header(":path", "/push")); - headers.add(new Header(":authority", "localhost:" + getPort())); - - buildGetRequest(frameHeader, headersPayload, null, headers, 3); - - // Send the request - writeFrame(frameHeader, headersPayload); - - // Read the response - // push promise - parser.readFrame(); - // stream 3 response headers - parser.readFrame(); - // stream 3 response body - parser.readFrame(); - // stream 2 response headers - parser.readFrame(); - // stream 2 response body - parser.readFrame(); - - String trace = output.getTrace(); - - Assert.assertTrue(trace, trace.contains("3-PushPromise-2")); - Assert.assertTrue(trace, trace.contains("2-Header-[:status]-[200]")); - Assert.assertTrue(trace, trace.contains("2-Body-8192")); - Assert.assertTrue(trace, trace.contains("3-Header-[:status]-[200]")); - Assert.assertTrue(trace, trace.contains("3-Body-1024")); - } - - - @Override - protected void configureAndStartWebApplication() throws LifecycleException { - Tomcat tomcat = getTomcatInstance(); - - Context ctxt = tomcat.addContext("", null); - - Tomcat.addServlet(ctxt, "simple", new SimpleServlet()); - ctxt.addServletMappingDecoded("/simple", "simple"); - - Tomcat.addServlet(ctxt, "push", new PushServlet()); - ctxt.addServletMappingDecoded("/push", "push"); - - tomcat.start(); - } - - - private static class PushServlet extends HttpServlet { - - private static final long serialVersionUID = 1L; - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - PushBuilder pb = req.newPushBuilder(); - pb.path("/simple").push(); - - // Generate content with a simple known format. - resp.setContentType("application/octet-stream"); - - int count = 512; - - // Two bytes per entry (1k data) - resp.setContentLengthLong(count * 2); - - OutputStream os = resp.getOutputStream(); - byte[] data = new byte[2]; - for (int i = 0; i < count; i++) { - data[0] = (byte) (i & 0xFF); - data[1] = (byte) ((i >> 8) & 0xFF); - os.write(data); - } - } - } -} diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 0addab5e1f..9b1c426bfd 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -165,6 +165,11 @@ for the Servlet 6.1 specification. It will be replaced in a future Tomcat 11 milestone with support for 103 early hints. (markt) </update> + <update> + Remove support for HTTP/2 server push. Calls to + <code>newPushBuilder()</code> will always return <code>null</code>. + (markt) + </update> </changelog> </subsection> <subsection name="Jasper"> diff --git a/webapps/examples/WEB-INF/classes/http2/SimpleImagePush.java b/webapps/examples/WEB-INF/classes/http2/SimpleImagePush.java deleted file mode 100644 index 3da6895904..0000000000 --- a/webapps/examples/WEB-INF/classes/http2/SimpleImagePush.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package http2; - -import java.io.IOException; -import java.io.PrintWriter; - -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.servlet.http.PushBuilder; - -public class SimpleImagePush extends HttpServlet { - - private static final long serialVersionUID = 1L; - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - resp.setCharacterEncoding("UTF-8"); - resp.setContentType("text/html"); - PrintWriter pw = resp.getWriter(); - - PushBuilder pb = req.newPushBuilder(); - if (pb != null) { - pb.path("servlets/images/code.gif"); - pb.push(); - pw.println("<html>"); - pw.println("<body>"); - pw.println("<p>The following image was provided via a push request.</p>"); - pw.println("<img src=\"" + getServletContext().getContextPath() + "/servlets/images/code.gif\"/>"); - pw.println("</body>"); - pw.println("</html>"); - pw.flush(); - } else { - pw.println("<html>"); - pw.println("<body>"); - pw.println("<p>Server push requests are not supported by this protocol.</p>"); - pw.println("</body>"); - pw.println("</html>"); - } - } -} diff --git a/webapps/examples/WEB-INF/web.xml b/webapps/examples/WEB-INF/web.xml index 12d865ef2d..442aa032e8 100644 --- a/webapps/examples/WEB-INF/web.xml +++ b/webapps/examples/WEB-INF/web.xml @@ -383,16 +383,6 @@ <url-pattern>/servlets/nonblocking/numberwriter</url-pattern> </servlet-mapping> - <!-- Server Push examples --> - <servlet> - <servlet-name>simpleimagepush</servlet-name> - <servlet-class>http2.SimpleImagePush</servlet-class> - </servlet> - <servlet-mapping> - <servlet-name>simpleimagepush</servlet-name> - <url-pattern>/servlets/serverpush/simpleimage</url-pattern> - </servlet-mapping> - <!-- Trailer examples --> <servlet> <servlet-name>responsetrailer</servlet-name> diff --git a/webapps/examples/servlets/index.html b/webapps/examples/servlets/index.html index d07a277e9c..5a36096d17 100644 --- a/webapps/examples/servlets/index.html +++ b/webapps/examples/servlets/index.html @@ -165,17 +165,6 @@ for clarity.</p> <td style="width: 30%;"></td> </tr> -<tr> - <th colspan="3">Servlet 4.0 Server Push examples</th> -</tr> -<tr> - <td>Simple image push</td> - <td style="width: 30%;"> - <a href="serverpush/simpleimage"><img src="images/execute.gif" alt=""> Execute</a> - </td> - <td style="width: 30%;"></td> -</tr> - <tr> <th colspan="3">Servlet 4.0 Trailer Field examples</th> </tr> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org