Search code examples
javahibernatemappingxhtmltomcat9

how to redirect the 400 error in tomcat 9 version with custom error page


i tried to redirect the 400 error with my custom error page but its not working. 400 only not redirect, 404 and 500 its working fine

1:

 <error-page>
        <error-code>400</error-code>
        <location>/faces/errors.xhtml</location>
    </error-page>
    
    <error-page>
        <error-code>404</error-code>
        <location>/faces/notfound.xhtml</location>
    </error-page>
    <error-page>
        <error-code>500</error-code>
        <location>/faces/error.xhtml</location>
    </error-page>

2: changed in server level --sever.xml file its also not working

 <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

                     <Valve className="org.apache.catalina.valves.ErrorReportValve"
       errorCode.400="/faces/errors.xhtml"
       showReport="false"
       showServerInfo="false" />

3 created the servelet class to redirect the error its also not working

package tneb.ccms.consumer;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/error400")
public class Error400Servlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // Set response content type
        
        //System.out.println( request.getRequestURI());
         response.setContentType("text/html");

        System.out.println("error page");
        // Set response status to 400 Bad Request
        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
       
        response.sendRedirect(request.getContextPath()+"/faces/errors.xhtml");
       
    }
}
package tneb.ccms.consumer;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class BadRequestFilter implements Filter {

     private FilterConfig filterConfig;

        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            this.filterConfig = filterConfig;
        }

        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            HttpServletResponse httpResponse = (HttpServletResponse) response;

            try {
                chain.doFilter(request, response);
            } catch (Exception e) {
                if (httpResponse.getStatus() == HttpServletResponse.SC_BAD_REQUEST) {
                    httpRequest.getRequestDispatcher("/faces/errors.xhtml").forward(request, response);
                } else {
                    throw e;
                }
            }
        }

        @Override
        public void destroy() {
            // Cleanup code if needed
        }
}

i tried everything i can and refer the documentation still i cant resolve this issue

if i encounter the 400 error in url it should not return the custom error page it shows normal tomcat page

http://localhost:11779/tangedco-public/%
404: http://localhost:11779/tangedco-public/~ --its encounter the 404 error its working fine and shows the custom error page output: 404 -The page you are trying to access is not found. ZZZZZ - The requested resource could not be found on this server.

I tried everything i know,created the standalone project and set the custom error and upgrade and downgraded the tomcatversion still i cant resolve the error!


Solution

  • Project Tree

    hello-tomcat9-web
    ├── pom.xml
    └── src
        └── main
            ├── java
            │   └── com
            │       └── example
            │           └── HelloStatusServlet.java
            └── webapp
                ├── 400.html
                ├── 404.html
                ├── 500.html
                ├── index.jsp
                └── WEB-INF
                    └── web.xml
    

    pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.example</groupId>
        <artifactId>helloweb</artifactId>
        <packaging>war</packaging>
        <version>0.0.1-SNAPSHOT</version>
        <name>helloweb</name>
        <properties>
            <maven.compiler.target>1.8</maven.compiler.target>
            <maven.compiler.source>1.8</maven.compiler.source>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
                <scope>provided</scope>
            </dependency>
    
            <dependency>
                <groupId>javax.servlet.jsp</groupId>
                <artifactId>javax.servlet.jsp-api</artifactId>
                <version>2.3.3</version>
                <scope>provided</scope>
            </dependency>
        </dependencies>
    
        <build>
            <finalName>helloworld</finalName>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>3.4.0</version>
                    <configuration>
                        <failOnMissingWebXml>false</failOnMissingWebXml>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    

    web.xml

    Just set the corresponding web pages in web.xml - status code 400, 404, 500.

    Please confirm the version of web.xml.

    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
    ...
    http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    version="3.1">
    
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
                                 http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
             version="3.1">
      <display-name>hello-tomcat9-web</display-name>
    
        <error-page>
            <error-code>400</error-code>
            <location>/400.html</location>
        </error-page>
    
        <error-page>
            <error-code>404</error-code>
            <location>/404.html</location>
        </error-page>
        
        <error-page>
            <error-code>500</error-code>
            <location>/500.html</location>
        </error-page>
               
      <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.jsp</welcome-file>
        <welcome-file>default.htm</welcome-file>
      </welcome-file-list>  
    </web-app>
    

    HelloStatusServlet.java

    HelloStatusServlet can be used to simulate generating and returning 400 and 500 status codes.

    package com.example;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    @WebServlet("/helloStatus")
    public class HelloStatusServlet extends HttpServlet {
    
        private static final long serialVersionUID = 1L;
    
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            String errorType = request.getParameter("error");
    
            if ("400".equals(errorType)) {
                response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Simulated 400 Error");
                return;
            } else if ("500".equals(errorType)) {
                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Simulated 500 Error");
                return;
            }
    
            response.setContentType("text/html");
            PrintWriter out = response.getWriter();
            out.println("<html><body>");
            out.println("<h1>Hello, World!</h1><p/>");
            out.println("<h1>Status TEST!</h1><p/>");
            out.println("</body></html>");
        }
    }
    

    index.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Hello Page</title>
    </head>
    <body>
        <h1>Hello</h1>
        <p>Current Date and Time: <%= new java.util.Date() %></p>
    </body>
    </html>
    

    400.html

    <!DOCTYPE html>
    <html>
    <head>
        <title>Bad Request</title>
    </head>
    <body>
    <h1>400 - Bad Request</h1>
    <p>ZZZZZ - The request could not be understood by the server due to malformed syntax.</p>
    </body>
    </html>
    

    404.html

    <!DOCTYPE html>
    <html>
    <head>
        <title>Page Not Found</title>
    </head>
    <body>
    <h1>404 - Page Not Found</h1>
    <p>ZZZZZ - The requested resource could not be found on this server.</p>
    </body>
    </html>
    

    500.html

    <!DOCTYPE html>
    <html>
    <head>
        <title>Internal Server Error</title>
    </head>
    <body>
    <h1>500 - Internal Server Error</h1>
    <p>ZZZZZ - Sorry, something went wrong on our end. Please try again later.</p>
    </body>
    </html>
    

    Package

    mvn clean package
    

    put war to tomcat

    put helloworld.war to Tomcat/webapps/

    Start Tomcat

    Test

    • http://localhost:8080/helloworld/

    return index.jsp

    001.png

    • http://localhost:8080/helloworld/helloStatus

    return helloStatus servlet.

    002.png

    • http://localhost:8080/helloworld/helloStatus?error=400

    Simulates a status code of 400.

    003.png

    • http://localhost:8080/helloworld/helloStatus?error=500

    Simulates a status code of 500.

    004.png

    • http://localhost:8080/helloworld/12324344

    return 404

    005.png

    Debug More

    • http://localhost:8080/tangedco-public/% show tomcat HTTP Status 400 – Bad Request , not my 400 error page. FAIL.
    • http://localhost:8080/tangedco-public/~ show my 404 error page.

    Check log

    logs/catalina.out

    12-Jul-2024 18:03:20.057 INFO [http-nio-8080-exec-8] org.apache.tomcat.util.http.Parameters.processParameters Character decoding failed. Parameter [%] with value [] has been ignored. Note that the name and value quoted here may be corrupted due to the failed decoding. Use debug level logging to see the original, non-corrupted values.
     Note: further occurrences of Parameter errors will be logged at DEBUG level.
    

    change server.xml

    add URIEncoding="UTF-8"

    <!--
        <Connector port="8080" protocol="HTTP/1.1"
                   connectionTimeout="20000"
                   redirectPort="8443"
                   maxParameterCount="1000"
                   />
    -->
        <Connector port="8080" protocol="HTTP/1.1"
                   connectionTimeout="20000"
                   redirectPort="8443"
                   maxParameterCount="1000"
                   URIEncoding="UTF-8"
                   />    
    

    same problem. not solve URI invalid character problem.

    add config file

    conf/logging.properties

    org.apache.coyote.http11.Http11Processor.level = FINE
    org.apache.tomcat.util.http.Parameters.level = FINE
    

    shutdown tomcat

    start tomcat

    test again

    • http://localhost:8080/tangedco-public/% show tomcat HTTP Status 400 – Bad Request , not my 400 error page. FAIL.
    • http://localhost:8080/tangedco-public/~ show my 404 error page.

    Check log again

    logs/catalina.out

    12-Jul-2024 18:23:59.711 XXXX [http-nio-8080-exec-8] org.apache.tomcat.util.http.Parameters.processParameters Character decoding failed. Parameter [%] with value [null] has been ignored.
        org.apache.tomcat.util.buf.UDecoder$DecodeException: End of file (EOF)
    12-Jul-2024 18:24:30.096 XXXX [http-nio-8080-exec-1] org.apache.coyote.http11.Http11Processor.service Error parsing HTTP request header
        java.io.EOFException
            at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1343)
            at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoint.java:1231)
            at org.apache.coyote.http11.Http11InputBuffer.fill(Http11InputBuffer.java:789)
            at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:348)
            at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:261)
            at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
            at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:936)
            at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1791)
            at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
            at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
            at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
            at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
            at java.base/java.lang.Thread.run(Thread.java:840)
    12-Jul-2024 18:24:30.098 XXXX [http-nio-8080-exec-1] org.apache.coyote.AbstractProcessor.setErrorState Error state [CLOSE_CONNECTION_NOW] reported while processing request
        java.io.EOFException
            at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1343)
            at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoint.java:1231)
            at org.apache.coyote.http11.Http11InputBuffer.fill(Http11InputBuffer.java:789)
            at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:348)
            at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:261)
            at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
            at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:936)
            at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1791)
            at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
            at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
            at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
            at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
            at java.base/java.lang.Thread.run(Thread.java:840)
    

    My inference is that when the request comes in, it will be processed first in org.apache.coyote.http11.Http11Processor.service, but when illegal characters are found, it will cause it to generate an org.apache.coyote.AbstractProcessor.setErrorState Error state [CLOSE_CONNECTION_NOW] reported while processing request, leading to early termination and not sending the request to the scope of our own webapp level. In other words, our webapp has not received the request at all and has been sent to the tomcat server level in advance. Disposed of.

    As for how to deal with this problem, this is a problem of how Tomcat handles illegal characters in URIs, so we need to seek answers to how Tomcat handles illegal characters.