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:
Edwin Kempin
2013-07-08 16:34:36 +02:00
parent 872cd35978
commit fe228a7258
4 changed files with 38 additions and 21 deletions

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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);
}