/** * Copyright (c) 2011, Thilo Planz. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package v7db.files.milton; import static com.bradmcevoy.http.StandardFilter.INTERNAL_SERVER_ERROR_HTML; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.bradmcevoy.http.Filter; import com.bradmcevoy.http.FilterChain; import com.bradmcevoy.http.GetableResource; import com.bradmcevoy.http.HandlerHelper; import com.bradmcevoy.http.HttpManager; import com.bradmcevoy.http.Request; import com.bradmcevoy.http.Resource; import com.bradmcevoy.http.Response; import com.bradmcevoy.http.ServletRequest; import com.bradmcevoy.http.exceptions.BadRequestException; import com.bradmcevoy.http.exceptions.ConflictException; import com.bradmcevoy.http.exceptions.NotAuthorizedException; import com.bradmcevoy.http.exceptions.NotFoundException; import com.bradmcevoy.http.http11.Http11ResponseHandler; /** * Support for conditional gets (If-None-Match). See * http://jira.ettrema.com:8080/browse/MIL-11 * */ class GetHandler extends com.bradmcevoy.http.http11.GetHandler implements Filter { private static final Logger log = LoggerFactory.getLogger(GetHandler.class); private final Http11ResponseHandler responseHandler; GetHandler(Http11ResponseHandler responseHandler, HandlerHelper handlerHelper) { super(responseHandler, handlerHelper); this.responseHandler = responseHandler; } @Override public void processExistingResource(HttpManager manager, Request request, Response response, Resource resource) throws NotAuthorizedException, BadRequestException, ConflictException, NotFoundException { if (log.isTraceEnabled()) { log.trace("process: " + request.getAbsolutePath()); } GetableResource r = (GetableResource) resource; if (checkIfNoneMatch(r, request)) { if (log.isTraceEnabled()) { log.trace("respond not modified with: " + responseHandler.getClass().getCanonicalName()); } responseHandler.respondNotModified(r, response, request); return; } super.processExistingResource(manager, request, response, resource); } private boolean checkIfNoneMatch(GetableResource resource, Request requestInfo) { String header = getIfNoneMatchHeader(); if (StringUtils.isBlank(header)) return false; String etag = responseHandler.generateEtag(resource); if (StringUtils.isBlank(etag)) return false; if (!StringUtils.contains(header, etag)) return false; // TODO: proper parsing of multiple tags in the header return true; } private static final String getIfNoneMatchHeader() { HttpServletRequest request = ServletRequest.getRequest(); return request.getHeader("If-None-Match"); } public void process(FilterChain chain, Request request, Response response) { Request.Method method = request.getMethod(); HttpManager manager = chain.getHttpManager(); if (Request.Method.GET == method && StringUtils.isNotBlank(getIfNoneMatchHeader())) { try { process(manager, request, response); } catch (BadRequestException ex) { log.warn("BadRequestException: " + ex.getReason()); manager.getResponseHandler().respondBadRequest( ex.getResource(), response, request); } catch (ConflictException ex) { log.warn("conflictException: " + ex.getMessage()); manager.getResponseHandler().respondConflict(ex.getResource(), response, request, INTERNAL_SERVER_ERROR_HTML); } catch (NotAuthorizedException ex) { log.warn("NotAuthorizedException"); manager.getResponseHandler().respondUnauthorised( ex.getResource(), response, request); } catch (Throwable e) { log.error("process", e); try { manager.getResponseHandler().respondServerError(request, response, INTERNAL_SERVER_ERROR_HTML); } catch (Throwable ex) { log .error( "Exception generating server error response, setting response status to 500", ex); response .setStatus(Response.Status.SC_INTERNAL_SERVER_ERROR); } } finally { response.close(); } } else { chain.process(request, response); } } }