[tomcat] branch master updated: Add extended ErrorReportValve that returns response as JSON instead of HTML

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

[tomcat] branch master updated: Add extended ErrorReportValve that returns response as JSON instead of HTML

kfujino
This is an automated email from the ASF dual-hosted git repository.

kfujino pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/master by this push:
     new 42a0841  Add extended ErrorReportValve that returns response as JSON instead of HTML
42a0841 is described below

commit 42a0841d289a35117da842201622454a9f387cd7
Author: KeiichiFujino <[hidden email]>
AuthorDate: Wed Oct 14 23:54:22 2020 +0900

    Add extended ErrorReportValve that returns response as JSON instead of HTML
---
 .../catalina/valves/JsonErrorReportValve.java      | 111 +++++++++++++++++++++
 webapps/docs/changelog.xml                         |   8 +-
 2 files changed, 117 insertions(+), 2 deletions(-)

diff --git a/java/org/apache/catalina/valves/JsonErrorReportValve.java b/java/org/apache/catalina/valves/JsonErrorReportValve.java
new file mode 100644
index 0000000..a438e77
--- /dev/null
+++ b/java/org/apache/catalina/valves/JsonErrorReportValve.java
@@ -0,0 +1,111 @@
+/*
+ * 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.valves;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.tribes.util.ExceptionUtils;
+import org.apache.coyote.ActionCode;
+import org.apache.tomcat.util.res.StringManager;
+
+/**
+ * <p>Implementation of a Valve that outputs error jsons.</p>
+ *
+ * <p>This Valve should be attached at the Host level, although it will work
+ * if attached to a Context.</p>
+ *
+ */
+public class JsonErrorReportValve extends ErrorReportValve {
+
+    public JsonErrorReportValve() {
+        super();
+    }
+
+    @Override
+    protected void report(Request request, Response response, Throwable throwable) {
+
+        int statusCode = response.getStatus();
+
+        // Do nothing on a 1xx, 2xx and 3xx status
+        // Do nothing if anything has been written already
+        // Do nothing if the response hasn't been explicitly marked as in error
+        //    and that error has not been reported.
+        if (statusCode < 400 || response.getContentWritten() > 0 || !response.setErrorReported()) {
+            return;
+        }
+
+        // If an error has occurred that prevents further I/O, don't waste time
+        // producing an error report that will never be read
+        AtomicBoolean result = new AtomicBoolean(false);
+        response.getCoyoteResponse().action(ActionCode.IS_IO_ALLOWED, result);
+        if (!result.get()) {
+            return;
+        }
+
+        StringManager smClient = StringManager.getManager(Constants.Package, request.getLocales());
+        response.setLocale(smClient.getLocale());
+        String type = null;
+        if (throwable != null) {
+            type = smClient.getString("errorReportValve.exceptionReport");
+        } else {
+            type = smClient.getString("errorReportValve.statusReport");
+        }
+        String message = response.getMessage();
+        if (message == null && throwable != null) {
+            message = throwable.getMessage();
+        }
+        String description = null;
+        description = smClient.getString("http." + statusCode + ".desc");
+        if (description == null) {
+            if (message.isEmpty()) {
+                return;
+            } else {
+                description = smClient.getString("errorReportValve.noDescription");
+            }
+        }
+        String jsonReport = "{\n" +
+                            "  \"type\": \"" + type + "\",\n" +
+                            "  \"message\": \"" + message + "\"\n" +
+                            "  \"description\": \"" + description + "\"\n" +
+                            "}";
+        try {
+            try {
+                response.setContentType("application/json");
+                response.setCharacterEncoding("utf-8");
+            } catch (Throwable t) {
+                ExceptionUtils.handleThrowable(t);
+                if (container.getLogger().isDebugEnabled()) {
+                    container.getLogger().debug("status.setContentType", t);
+                }
+            }
+            Writer writer = response.getReporter();
+            if (writer != null) {
+                writer.write(jsonReport);
+                response.finishResponse();
+                return;
+            }
+        } catch (IOException e) {
+            // Ignore
+        } catch (IllegalStateException e) {
+            // Ignore
+        }
+    }
+}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 97cf512..1abb0ee 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -63,9 +63,13 @@
         retries are made on a new connection, just like with the single
         connection scenario. (remm)
       </fix>
+      <add>
+        Add extended <code>ErrorReportValve</code> that returns response as
+        JSON instead of HTML. (kfujino)
+      </add>
     </changelog>
   </subsection>
-  <subseciton name="Coyote">
+  <subsection name="Coyote">
     <changelog>
       <fix>
         Refactor the HTTP/2 window update handling for padding in data frames to
@@ -83,7 +87,7 @@
         request statistics for HTTP/2 requests. (markt)
       </fix>
     </changelog>
-  </subseciton>
+  </subsection>
   <subsection name="Jasper">
     <changelog>
       <fix>


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: [tomcat] branch master updated: Add extended ErrorReportValve that returns response as JSON instead of HTML

Michael Osipov
Am 2020-10-14 um 16:55 schrieb [hidden email]:

> This is an automated email from the ASF dual-hosted git repository.
>
> kfujino pushed a commit to branch master
> in repository https://gitbox.apache.org/repos/asf/tomcat.git
>
>
> The following commit(s) were added to refs/heads/master by this push:
>       new 42a0841  Add extended ErrorReportValve that returns response as JSON instead of HTML
> 42a0841 is described below
>
> commit 42a0841d289a35117da842201622454a9f387cd7
> Author: KeiichiFujino <[hidden email]>
> AuthorDate: Wed Oct 14 23:54:22 2020 +0900
>
>      Add extended ErrorReportValve that returns response as JSON instead of HTML

Why not properly negotiate the content type? It does not seems that you
aren't returning the same content the HTML version does. Moreover, why
don't you use the print writer from the response?

Michael

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: [tomcat] branch master updated: Add extended ErrorReportValve that returns response as JSON instead of HTML

Martin Grigorov
In reply to this post by kfujino
On Wed, Oct 14, 2020 at 5:55 PM <[hidden email]> wrote:

> This is an automated email from the ASF dual-hosted git repository.
>
> kfujino pushed a commit to branch master
> in repository https://gitbox.apache.org/repos/asf/tomcat.git
>
>
> The following commit(s) were added to refs/heads/master by this push:
>      new 42a0841  Add extended ErrorReportValve that returns response as
> JSON instead of HTML
> 42a0841 is described below
>
> commit 42a0841d289a35117da842201622454a9f387cd7
> Author: KeiichiFujino <[hidden email]>
> AuthorDate: Wed Oct 14 23:54:22 2020 +0900
>
>     Add extended ErrorReportValve that returns response as JSON instead of
> HTML
> ---
>  .../catalina/valves/JsonErrorReportValve.java      | 111
> +++++++++++++++++++++
>  webapps/docs/changelog.xml                         |   8 +-
>  2 files changed, 117 insertions(+), 2 deletions(-)
>
> diff --git a/java/org/apache/catalina/valves/JsonErrorReportValve.java
> b/java/org/apache/catalina/valves/JsonErrorReportValve.java
> new file mode 100644
> index 0000000..a438e77
> --- /dev/null
> +++ b/java/org/apache/catalina/valves/JsonErrorReportValve.java
> @@ -0,0 +1,111 @@
> +/*
> + * 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.valves;
> +
> +import java.io.IOException;
> +import java.io.Writer;
> +import java.util.concurrent.atomic.AtomicBoolean;
> +
> +import org.apache.catalina.connector.Request;
> +import org.apache.catalina.connector.Response;
> +import org.apache.catalina.tribes.util.ExceptionUtils;
> +import org.apache.coyote.ActionCode;
> +import org.apache.tomcat.util.res.StringManager;
> +
> +/**
> + * <p>Implementation of a Valve that outputs error jsons.</p>
> + *
> + * <p>This Valve should be attached at the Host level, although it will
> work
> + * if attached to a Context.</p>
> + *
> + */
> +public class JsonErrorReportValve extends ErrorReportValve {
> +
> +    public JsonErrorReportValve() {
> +        super();
> +    }
> +
> +    @Override
> +    protected void report(Request request, Response response, Throwable
> throwable) {
> +
> +        int statusCode = response.getStatus();
> +
> +        // Do nothing on a 1xx, 2xx and 3xx status
> +        // Do nothing if anything has been written already
> +        // Do nothing if the response hasn't been explicitly marked as in
> error
> +        //    and that error has not been reported.
> +        if (statusCode < 400 || response.getContentWritten() > 0 ||
> !response.setErrorReported()) {
> +            return;
> +        }
> +
> +        // If an error has occurred that prevents further I/O, don't
> waste time
> +        // producing an error report that will never be read
> +        AtomicBoolean result = new AtomicBoolean(false);
> +        response.getCoyoteResponse().action(ActionCode.IS_IO_ALLOWED,
> result);
> +        if (!result.get()) {
> +            return;
> +        }
> +
> +        StringManager smClient =
> StringManager.getManager(Constants.Package, request.getLocales());
> +        response.setLocale(smClient.getLocale());
> +        String type = null;
> +        if (throwable != null) {
> +            type = smClient.getString("errorReportValve.exceptionReport");
> +        } else {
> +            type = smClient.getString("errorReportValve.statusReport");
> +        }
> +        String message = response.getMessage();
> +        if (message == null && throwable != null) {
> +            message = throwable.getMessage();
> +        }
> +        String description = null;
> +        description = smClient.getString("http." + statusCode + ".desc");
> +        if (description == null) {
> +            if (message.isEmpty()) {
> +                return;
> +            } else {
> +                description =
> smClient.getString("errorReportValve.noDescription");
> +            }
> +        }
> +        String jsonReport = "{\n" +
> +                            "  \"type\": \"" + type + "\",\n" +
> +                            "  \"message\": \"" + message + "\"\n" +
> +                            "  \"description\": \"" + description +
> "\"\n" +
> +                            "}";
> +        try {
> +            try {
> +                response.setContentType("application/json");
> +                response.setCharacterEncoding("utf-8");
> +            } catch (Throwable t) {
> +                ExceptionUtils.handleThrowable(t);
> +                if (container.getLogger().isDebugEnabled()) {
> +                    container.getLogger().debug("status.setContentType",
> t);
> +                }
> +            }
> +            Writer writer = response.getReporter();
> +            if (writer != null) {
> +                writer.write(jsonReport);
> +                response.finishResponse();
> +                return;
> +            }
> +        } catch (IOException e) {
> +            // Ignore
> +        } catch (IllegalStateException e) {
> +            // Ignore
> +        }
> +    }
> +}
> diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
> index 97cf512..1abb0ee 100644
> --- a/webapps/docs/changelog.xml
> +++ b/webapps/docs/changelog.xml
> @@ -63,9 +63,13 @@
>          retries are made on a new connection, just like with the single
>          connection scenario. (remm)
>        </fix>
> +      <add>
> +        Add extended <code>ErrorReportValve</code> that returns response
> as
> +        JSON instead of HTML. (kfujino)
>

From the changelog entry it is not clear what is the name of the new class.
And since the docs are not updated the users will have to check the commit
diff to figure out.


> +      </add>
>      </changelog>
>    </subsection>
> -  <subseciton name="Coyote">
> +  <subsection name="Coyote">
>      <changelog>
>        <fix>
>          Refactor the HTTP/2 window update handling for padding in data
> frames to
> @@ -83,7 +87,7 @@
>          request statistics for HTTP/2 requests. (markt)
>        </fix>
>      </changelog>
> -  </subseciton>
> +  </subsection>
>    <subsection name="Jasper">
>      <changelog>
>        <fix>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>
>
Reply | Threaded
Open this post in threaded view
|

Re: [tomcat] branch master updated: Add extended ErrorReportValve that returns response as JSON instead of HTML

kfujino
2020年10月16日(金) 22:08 Martin Grigorov <[hidden email]>:

> On Wed, Oct 14, 2020 at 5:55 PM <[hidden email]> wrote:
>
> > This is an automated email from the ASF dual-hosted git repository.
> >
> > kfujino pushed a commit to branch master
> > in repository https://gitbox.apache.org/repos/asf/tomcat.git
> >
> >
> > The following commit(s) were added to refs/heads/master by this push:
> >      new 42a0841  Add extended ErrorReportValve that returns response as
> > JSON instead of HTML
> > 42a0841 is described below
> >
> > commit 42a0841d289a35117da842201622454a9f387cd7
> > Author: KeiichiFujino <[hidden email]>
> > AuthorDate: Wed Oct 14 23:54:22 2020 +0900
> >
> >     Add extended ErrorReportValve that returns response as JSON instead
> of
> > HTML
> > ---
> >  .../catalina/valves/JsonErrorReportValve.java      | 111
> > +++++++++++++++++++++
> >  webapps/docs/changelog.xml                         |   8 +-
> >  2 files changed, 117 insertions(+), 2 deletions(-)
> >
> > diff --git a/java/org/apache/catalina/valves/JsonErrorReportValve.java
> > b/java/org/apache/catalina/valves/JsonErrorReportValve.java
> > new file mode 100644
> > index 0000000..a438e77
> > --- /dev/null
> > +++ b/java/org/apache/catalina/valves/JsonErrorReportValve.java
> > @@ -0,0 +1,111 @@
> > +/*
> > + * 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.valves;
> > +
> > +import java.io.IOException;
> > +import java.io.Writer;
> > +import java.util.concurrent.atomic.AtomicBoolean;
> > +
> > +import org.apache.catalina.connector.Request;
> > +import org.apache.catalina.connector.Response;
> > +import org.apache.catalina.tribes.util.ExceptionUtils;
> > +import org.apache.coyote.ActionCode;
> > +import org.apache.tomcat.util.res.StringManager;
> > +
> > +/**
> > + * <p>Implementation of a Valve that outputs error jsons.</p>
> > + *
> > + * <p>This Valve should be attached at the Host level, although it will
> > work
> > + * if attached to a Context.</p>
> > + *
> > + */
> > +public class JsonErrorReportValve extends ErrorReportValve {
> > +
> > +    public JsonErrorReportValve() {
> > +        super();
> > +    }
> > +
> > +    @Override
> > +    protected void report(Request request, Response response, Throwable
> > throwable) {
> > +
> > +        int statusCode = response.getStatus();
> > +
> > +        // Do nothing on a 1xx, 2xx and 3xx status
> > +        // Do nothing if anything has been written already
> > +        // Do nothing if the response hasn't been explicitly marked as
> in
> > error
> > +        //    and that error has not been reported.
> > +        if (statusCode < 400 || response.getContentWritten() > 0 ||
> > !response.setErrorReported()) {
> > +            return;
> > +        }
> > +
> > +        // If an error has occurred that prevents further I/O, don't
> > waste time
> > +        // producing an error report that will never be read
> > +        AtomicBoolean result = new AtomicBoolean(false);
> > +        response.getCoyoteResponse().action(ActionCode.IS_IO_ALLOWED,
> > result);
> > +        if (!result.get()) {
> > +            return;
> > +        }
> > +
> > +        StringManager smClient =
> > StringManager.getManager(Constants.Package, request.getLocales());
> > +        response.setLocale(smClient.getLocale());
> > +        String type = null;
> > +        if (throwable != null) {
> > +            type =
> smClient.getString("errorReportValve.exceptionReport");
> > +        } else {
> > +            type = smClient.getString("errorReportValve.statusReport");
> > +        }
> > +        String message = response.getMessage();
> > +        if (message == null && throwable != null) {
> > +            message = throwable.getMessage();
> > +        }
> > +        String description = null;
> > +        description = smClient.getString("http." + statusCode +
> ".desc");
> > +        if (description == null) {
> > +            if (message.isEmpty()) {
> > +                return;
> > +            } else {
> > +                description =
> > smClient.getString("errorReportValve.noDescription");
> > +            }
> > +        }
> > +        String jsonReport = "{\n" +
> > +                            "  \"type\": \"" + type + "\",\n" +
> > +                            "  \"message\": \"" + message + "\"\n" +
> > +                            "  \"description\": \"" + description +
> > "\"\n" +
> > +                            "}";
> > +        try {
> > +            try {
> > +                response.setContentType("application/json");
> > +                response.setCharacterEncoding("utf-8");
> > +            } catch (Throwable t) {
> > +                ExceptionUtils.handleThrowable(t);
> > +                if (container.getLogger().isDebugEnabled()) {
> > +                    container.getLogger().debug("status.setContentType",
> > t);
> > +                }
> > +            }
> > +            Writer writer = response.getReporter();
> > +            if (writer != null) {
> > +                writer.write(jsonReport);
> > +                response.finishResponse();
> > +                return;
> > +            }
> > +        } catch (IOException e) {
> > +            // Ignore
> > +        } catch (IllegalStateException e) {
> > +            // Ignore
> > +        }
> > +    }
> > +}
> > diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
> > index 97cf512..1abb0ee 100644
> > --- a/webapps/docs/changelog.xml
> > +++ b/webapps/docs/changelog.xml
> > @@ -63,9 +63,13 @@
> >          retries are made on a new connection, just like with the single
> >          connection scenario. (remm)
> >        </fix>
> > +      <add>
> > +        Add extended <code>ErrorReportValve</code> that returns response
> > as
> > +        JSON instead of HTML. (kfujino)
> >
>
> From the changelog entry it is not clear what is the name of the new class.
> And since the docs are not updated the users will have to check the commit
> diff to figure out.
>
>
I'm sorry to reply late.
Thanks for your comment.
Fixed changelog entry and added documentation.



>
> > +      </add>
> >      </changelog>
> >    </subsection>
> > -  <subseciton name="Coyote">
> > +  <subsection name="Coyote">
> >      <changelog>
> >        <fix>
> >          Refactor the HTTP/2 window update handling for padding in data
> > frames to
> > @@ -83,7 +87,7 @@
> >          request statistics for HTTP/2 requests. (markt)
> >        </fix>
> >      </changelog>
> > -  </subseciton>
> > +  </subsection>
> >    <subsection name="Jasper">
> >      <changelog>
> >        <fix>
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: [hidden email]
> > For additional commands, e-mail: [hidden email]
> >
> >
>


--
Keiichi.Fujino