blob: 8ba4acbc3f1a5cfdf188983c9ffff6b3aad52439 [file] [log] [blame]
/*
* 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.coyote.ActionCode;
import org.apache.tomcat.util.ExceptionUtils;
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 == null || 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 | IllegalStateException e) {
// Ignore
}
}
}