Allow error responses from REST API to be cached
Change-Id: I45986c287f244a1a4b53ea623258255e29dbacb5 Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
@@ -17,6 +17,7 @@ package com.google.gerrit.extensions.restapi;
|
||||
/** Root exception type for JSON API failures. */
|
||||
public abstract class RestApiException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private CacheControl caching = CacheControl.NONE;
|
||||
|
||||
public RestApiException() {
|
||||
}
|
||||
@@ -28,4 +29,14 @@ public abstract class RestApiException extends Exception {
|
||||
public RestApiException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
public CacheControl caching() {
|
||||
return caching;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends RestApiException> T caching(CacheControl c) {
|
||||
caching = c;
|
||||
return (T) this;
|
||||
}
|
||||
}
|
||||
|
@@ -77,7 +77,7 @@ class RunAsFilter implements Filter {
|
||||
String runas = req.getHeader(RUN_AS);
|
||||
if (runas != null) {
|
||||
if (!enabled) {
|
||||
RestApiServlet.replyError(res,
|
||||
RestApiServlet.replyError(req, res,
|
||||
SC_FORBIDDEN,
|
||||
RUN_AS + " disabled by auth.enableRunAs = false");
|
||||
return;
|
||||
@@ -85,7 +85,7 @@ class RunAsFilter implements Filter {
|
||||
|
||||
CurrentUser self = session.get().getCurrentUser();
|
||||
if (!self.getCapabilities().canRunAs()) {
|
||||
RestApiServlet.replyError(res,
|
||||
RestApiServlet.replyError(req, res,
|
||||
SC_FORBIDDEN,
|
||||
"not permitted to use " + RUN_AS);
|
||||
return;
|
||||
@@ -96,13 +96,13 @@ class RunAsFilter implements Filter {
|
||||
target = accountResolver.find(runas);
|
||||
} catch (OrmException e) {
|
||||
log.warn("cannot resolve account for " + RUN_AS, e);
|
||||
RestApiServlet.replyError(res,
|
||||
RestApiServlet.replyError(req, res,
|
||||
SC_INTERNAL_SERVER_ERROR,
|
||||
"cannot resolve " + RUN_AS);
|
||||
return;
|
||||
}
|
||||
if (target == null) {
|
||||
RestApiServlet.replyError(res,
|
||||
RestApiServlet.replyError(req, res,
|
||||
SC_FORBIDDEN,
|
||||
"no account matches " + RUN_AS);
|
||||
return;
|
||||
|
@@ -68,7 +68,7 @@ class ParameterParser {
|
||||
clp.parseOptionMap(in);
|
||||
} catch (CmdLineException e) {
|
||||
if (!clp.wasHelpRequestedByOption()) {
|
||||
replyError(res, SC_BAD_REQUEST, e.getMessage());
|
||||
replyError(req, res, SC_BAD_REQUEST, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -321,27 +321,27 @@ public class RestApiServlet extends HttpServlet {
|
||||
}
|
||||
}
|
||||
} catch (AuthException e) {
|
||||
replyError(res, status = SC_FORBIDDEN, e.getMessage());
|
||||
replyError(req, res, status = SC_FORBIDDEN, e.getMessage(), e.caching());
|
||||
} catch (BadRequestException e) {
|
||||
replyError(res, status = SC_BAD_REQUEST, e.getMessage());
|
||||
replyError(req, res, status = SC_BAD_REQUEST, e.getMessage(), e.caching());
|
||||
} catch (MethodNotAllowedException e) {
|
||||
replyError(res, status = SC_METHOD_NOT_ALLOWED, "Method not allowed");
|
||||
replyError(req, res, status = SC_METHOD_NOT_ALLOWED, "Method not allowed", e.caching());
|
||||
} catch (ResourceConflictException e) {
|
||||
replyError(res, status = SC_CONFLICT, e.getMessage());
|
||||
replyError(req, res, status = SC_CONFLICT, e.getMessage(), e.caching());
|
||||
} catch (PreconditionFailedException e) {
|
||||
replyError(res, status = SC_PRECONDITION_FAILED,
|
||||
Objects.firstNonNull(e.getMessage(), "Precondition failed"));
|
||||
replyError(req, res, status = SC_PRECONDITION_FAILED,
|
||||
Objects.firstNonNull(e.getMessage(), "Precondition failed"), e.caching());
|
||||
} catch (ResourceNotFoundException e) {
|
||||
replyError(res, status = SC_NOT_FOUND, "Not found");
|
||||
replyError(req, res, status = SC_NOT_FOUND, "Not found", e.caching());
|
||||
} catch (UnprocessableEntityException e) {
|
||||
replyError(res, status = 422,
|
||||
Objects.firstNonNull(e.getMessage(), "Unprocessable Entity"));
|
||||
replyError(req, res, status = 422,
|
||||
Objects.firstNonNull(e.getMessage(), "Unprocessable Entity"), e.caching());
|
||||
} catch (AmbiguousViewException e) {
|
||||
replyError(res, status = SC_NOT_FOUND, e.getMessage());
|
||||
replyError(req, res, status = SC_NOT_FOUND, e.getMessage());
|
||||
} catch (MalformedJsonException e) {
|
||||
replyError(res, status = SC_BAD_REQUEST, "Invalid " + JSON_TYPE + " in request");
|
||||
replyError(req, res, status = SC_BAD_REQUEST, "Invalid " + JSON_TYPE + " in request");
|
||||
} catch (JsonParseException e) {
|
||||
replyError(res, status = SC_BAD_REQUEST, "Invalid " + JSON_TYPE + " in request");
|
||||
replyError(req, res, status = SC_BAD_REQUEST, "Invalid " + JSON_TYPE + " in request");
|
||||
} catch (Exception e) {
|
||||
status = SC_INTERNAL_SERVER_ERROR;
|
||||
handleException(e, req, res);
|
||||
@@ -837,14 +837,20 @@ public class RestApiServlet extends HttpServlet {
|
||||
|
||||
if (!res.isCommitted()) {
|
||||
res.reset();
|
||||
replyError(res, SC_INTERNAL_SERVER_ERROR, "Internal server error");
|
||||
replyError(req, res, SC_INTERNAL_SERVER_ERROR, "Internal server error");
|
||||
}
|
||||
}
|
||||
|
||||
public static void replyError(HttpServletResponse res, int statusCode,
|
||||
String msg) throws IOException {
|
||||
public static void replyError(HttpServletRequest req,
|
||||
HttpServletResponse res, int statusCode, String msg) throws IOException {
|
||||
replyError(req, res, statusCode, msg, CacheControl.NONE);
|
||||
}
|
||||
|
||||
public static void replyError(HttpServletRequest req,
|
||||
HttpServletResponse res, int statusCode, String msg,
|
||||
CacheControl c) throws IOException {
|
||||
res.setStatus(statusCode);
|
||||
CacheHeaders.setNotCacheable(res);
|
||||
configureCaching(req, res, c);
|
||||
replyText(null, res, msg);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user