use of jakarta.servlet.http.HttpServletResponse in project tomcat by apache.
the class CorsFilter method doFilter.
@Override
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
if (!(servletRequest instanceof HttpServletRequest) || !(servletResponse instanceof HttpServletResponse)) {
throw new ServletException(sm.getString("corsFilter.onlyHttp"));
}
// Safe to downcast at this point.
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// Determines the CORS request type.
CorsFilter.CORSRequestType requestType = checkRequestType(request);
// Adds CORS specific attributes to request.
if (isDecorateRequest()) {
CorsFilter.decorateCORSProperties(request, requestType);
}
switch(requestType) {
case SIMPLE:
// Handles a Simple CORS request.
case ACTUAL:
// Handles an Actual CORS request.
this.handleSimpleCORS(request, response, filterChain);
break;
case PRE_FLIGHT:
// Handles a Pre-flight CORS request.
this.handlePreflightCORS(request, response, filterChain);
break;
case NOT_CORS:
// Handles a Normal request that is not a cross-origin request.
this.handleNonCORS(request, response, filterChain);
break;
default:
// Handles a CORS request that violates specification.
this.handleInvalidCORS(request, response, filterChain);
break;
}
}
use of jakarta.servlet.http.HttpServletResponse in project tomcat by apache.
the class CsrfPreventionFilter method doFilter.
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ServletResponse wResponse = null;
if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
boolean skipNonceCheck = false;
if (Constants.METHOD_GET.equals(req.getMethod()) && entryPoints.contains(getRequestedPath(req))) {
if (log.isTraceEnabled()) {
log.trace("Skipping CSRF nonce-check for GET request to entry point " + getRequestedPath(req));
}
skipNonceCheck = true;
}
HttpSession session = req.getSession(false);
@SuppressWarnings("unchecked") LruCache<String> nonceCache = (session == null) ? null : (LruCache<String>) session.getAttribute(Constants.CSRF_NONCE_SESSION_ATTR_NAME);
if (!skipNonceCheck) {
String previousNonce = req.getParameter(nonceRequestParameterName);
if (previousNonce == null) {
if (log.isDebugEnabled()) {
log.debug("Rejecting request for " + getRequestedPath(req) + ", session " + (null == session ? "(none)" : session.getId()) + " with no CSRF nonce found in request");
}
res.sendError(getDenyStatus());
return;
} else if (nonceCache == null) {
if (log.isDebugEnabled()) {
log.debug("Rejecting request for " + getRequestedPath(req) + ", session " + (null == session ? "(none)" : session.getId()) + " due to empty / missing nonce cache");
}
res.sendError(getDenyStatus());
return;
} else if (!nonceCache.contains(previousNonce)) {
if (log.isDebugEnabled()) {
log.debug("Rejecting request for " + getRequestedPath(req) + ", session " + (null == session ? "(none)" : session.getId()) + " due to invalid nonce " + previousNonce);
}
res.sendError(getDenyStatus());
return;
}
if (log.isTraceEnabled()) {
log.trace("Allowing request to " + getRequestedPath(req) + " with valid CSRF nonce " + previousNonce);
}
}
if (nonceCache == null) {
if (log.isDebugEnabled()) {
log.debug("Creating new CSRF nonce cache with size=" + nonceCacheSize + " for session " + (null == session ? "(will create)" : session.getId()));
}
nonceCache = new LruCache<>(nonceCacheSize);
if (session == null) {
if (log.isDebugEnabled()) {
log.debug("Creating new session to store CSRF nonce cache");
}
session = req.getSession(true);
}
session.setAttribute(Constants.CSRF_NONCE_SESSION_ATTR_NAME, nonceCache);
}
String newNonce = generateNonce();
nonceCache.add(newNonce);
// Take this request's nonce and put it into the request
// attributes so pages can make direct use of it, rather than
// requiring the use of response.encodeURL.
request.setAttribute(Constants.CSRF_NONCE_REQUEST_ATTR_NAME, newNonce);
wResponse = new CsrfResponseWrapper(res, nonceRequestParameterName, newNonce);
} else {
wResponse = response;
}
chain.doFilter(request, wResponse);
}
use of jakarta.servlet.http.HttpServletResponse in project tomcat by apache.
the class FailedRequestFilter method doFilter.
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (!isGoodRequest(request)) {
FailReason reason = (FailReason) request.getAttribute(Globals.PARAMETER_PARSE_FAILED_REASON_ATTR);
int status;
switch(reason) {
case IO_ERROR:
// Not the client's fault
status = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
break;
case POST_TOO_LARGE:
status = HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE;
break;
case TOO_MANY_PARAMETERS:
// Assume the client is at fault
case UNKNOWN:
// a specific status code so use the default.
case INVALID_CONTENT_TYPE:
case MULTIPART_CONFIG_INVALID:
case NO_NAME:
case REQUEST_BODY_INCOMPLETE:
case URL_DECODING:
case CLIENT_DISCONNECT:
// for the access logs. The default is fine.
default:
// 400
status = HttpServletResponse.SC_BAD_REQUEST;
break;
}
((HttpServletResponse) response).sendError(status);
return;
}
chain.doFilter(request, response);
}
use of jakarta.servlet.http.HttpServletResponse in project tomcat by apache.
the class DefaultServlet method serveResource.
/**
* Serve the specified resource, optionally including the data content.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
* @param content Should the content be included?
* @param inputEncoding The encoding to use if it is necessary to access the
* source as characters rather than as bytes
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet-specified error occurs
*/
protected void serveResource(HttpServletRequest request, HttpServletResponse response, boolean content, String inputEncoding) throws IOException, ServletException {
boolean serveContent = content;
// Identify the requested resource path
String path = getRelativePath(request, true);
if (debug > 0) {
if (serveContent) {
log("DefaultServlet.serveResource: Serving resource '" + path + "' headers and data");
} else {
log("DefaultServlet.serveResource: Serving resource '" + path + "' headers only");
}
}
if (path.length() == 0) {
// Context root redirect
doDirectoryRedirect(request, response);
return;
}
WebResource resource = resources.getResource(path);
boolean isError = DispatcherType.ERROR == request.getDispatcherType();
if (!resource.exists()) {
// Check if we're included so we can return the appropriate
// missing resource name in the error
String requestUri = (String) request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI);
if (requestUri == null) {
requestUri = request.getRequestURI();
} else {
// SRV.9.3 says we must throw a FNFE
throw new FileNotFoundException(sm.getString("defaultServlet.missingResource", requestUri));
}
if (isError) {
response.sendError(((Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)).intValue());
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND, sm.getString("defaultServlet.missingResource", requestUri));
}
return;
}
if (!resource.canRead()) {
// Check if we're included so we can return the appropriate
// missing resource name in the error
String requestUri = (String) request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI);
if (requestUri == null) {
requestUri = request.getRequestURI();
} else {
// reasonable
throw new FileNotFoundException(sm.getString("defaultServlet.missingResource", requestUri));
}
if (isError) {
response.sendError(((Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)).intValue());
} else {
response.sendError(HttpServletResponse.SC_FORBIDDEN, requestUri);
}
return;
}
boolean included = false;
// satisfied.
if (resource.isFile()) {
// Checking If headers
included = (request.getAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH) != null);
if (!included && !isError && !checkIfHeaders(request, response, resource)) {
return;
}
}
// Find content type.
String contentType = resource.getMimeType();
if (contentType == null) {
contentType = getServletContext().getMimeType(resource.getName());
resource.setMimeType(contentType);
}
// These need to reflect the original resource, not the potentially
// precompressed version of the resource so get them now if they are going to
// be needed later
String eTag = null;
String lastModifiedHttp = null;
if (resource.isFile() && !isError) {
eTag = generateETag(resource);
lastModifiedHttp = resource.getLastModifiedHttp();
}
// Serve a precompressed version of the file if present
boolean usingPrecompressedVersion = false;
if (compressionFormats.length > 0 && !included && resource.isFile() && !pathEndsWithCompressedExtension(path)) {
List<PrecompressedResource> precompressedResources = getAvailablePrecompressedResources(path);
if (!precompressedResources.isEmpty()) {
ResponseUtil.addVaryFieldName(response, "accept-encoding");
PrecompressedResource bestResource = getBestPrecompressedResource(request, precompressedResources);
if (bestResource != null) {
response.addHeader("Content-Encoding", bestResource.format.encoding);
resource = bestResource.resource;
usingPrecompressedVersion = true;
}
}
}
Ranges ranges = FULL;
long contentLength = -1L;
if (resource.isDirectory()) {
if (!path.endsWith("/")) {
doDirectoryRedirect(request, response);
return;
}
// suppress them
if (!listings) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, sm.getString("defaultServlet.missingResource", request.getRequestURI()));
return;
}
contentType = "text/html;charset=UTF-8";
} else {
if (!isError) {
if (useAcceptRanges) {
// Accept ranges header
response.setHeader("Accept-Ranges", "bytes");
}
// Parse range specifier
ranges = parseRange(request, response, resource);
if (ranges == null) {
return;
}
// ETag header
response.setHeader("ETag", eTag);
// Last-Modified header
response.setHeader("Last-Modified", lastModifiedHttp);
}
// Get content length
contentLength = resource.getContentLength();
// (silent) ISE when setting the output buffer size
if (contentLength == 0L) {
serveContent = false;
}
}
ServletOutputStream ostream = null;
PrintWriter writer = null;
if (serveContent) {
// Trying to retrieve the servlet output stream
try {
ostream = response.getOutputStream();
} catch (IllegalStateException e) {
// trying to serve a text file
if (!usingPrecompressedVersion && isText(contentType)) {
writer = response.getWriter();
// Cannot reliably serve partial content with a Writer
ranges = FULL;
} else {
throw e;
}
}
}
// Check to see if a Filter, Valve or wrapper has written some content.
// If it has, disable range requests and setting of a content length
// since neither can be done reliably.
ServletResponse r = response;
long contentWritten = 0;
while (r instanceof ServletResponseWrapper) {
r = ((ServletResponseWrapper) r).getResponse();
}
if (r instanceof ResponseFacade) {
contentWritten = ((ResponseFacade) r).getContentWritten();
}
if (contentWritten > 0) {
ranges = FULL;
}
String outputEncoding = response.getCharacterEncoding();
Charset charset = B2CConverter.getCharset(outputEncoding);
boolean conversionRequired;
/*
* The test below deliberately uses != to compare two Strings. This is
* because the code is looking to see if the default character encoding
* has been returned because no explicit character encoding has been
* defined. There is no clean way of doing this via the Servlet API. It
* would be possible to add a Tomcat specific API but that would require
* quite a bit of code to get to the Tomcat specific request object that
* may have been wrapped. The != test is a (slightly hacky) quick way of
* doing this.
*/
boolean outputEncodingSpecified = outputEncoding != org.apache.coyote.Constants.DEFAULT_BODY_CHARSET.name() && outputEncoding != resources.getContext().getResponseCharacterEncoding();
if (!usingPrecompressedVersion && isText(contentType) && outputEncodingSpecified && !charset.equals(fileEncodingCharset)) {
conversionRequired = true;
// Conversion often results fewer/more/different bytes.
// That does not play nicely with range requests.
ranges = FULL;
} else {
conversionRequired = false;
}
if (resource.isDirectory() || isError || ranges == FULL) {
// Set the appropriate output headers
if (contentType != null) {
if (debug > 0) {
log("DefaultServlet.serveFile: contentType='" + contentType + "'");
}
// Don't override a previously set content type
if (response.getContentType() == null) {
response.setContentType(contentType);
}
}
if (resource.isFile() && contentLength >= 0 && (!serveContent || ostream != null)) {
if (debug > 0) {
log("DefaultServlet.serveFile: contentLength=" + contentLength);
}
// written to the response or if conversion will be taking place
if (contentWritten == 0 && !conversionRequired) {
response.setContentLengthLong(contentLength);
}
}
if (serveContent) {
try {
response.setBufferSize(output);
} catch (IllegalStateException e) {
// Silent catch
}
InputStream renderResult = null;
if (ostream == null) {
// content directly.
if (resource.isDirectory()) {
renderResult = render(request, getPathPrefix(request), resource, inputEncoding);
} else {
renderResult = resource.getInputStream();
if (included) {
// Need to make sure any BOM is removed
if (!renderResult.markSupported()) {
renderResult = new BufferedInputStream(renderResult);
}
Charset bomCharset = processBom(renderResult, useBomIfPresent.stripBom);
if (bomCharset != null && useBomIfPresent.useBomEncoding) {
inputEncoding = bomCharset.name();
}
}
}
copy(renderResult, writer, inputEncoding);
} else {
// Output is via an OutputStream
if (resource.isDirectory()) {
renderResult = render(request, getPathPrefix(request), resource, inputEncoding);
} else {
// Check to see if conversion is required
if (conversionRequired || included) {
// When including a file, we need to check for a BOM
// to determine if a conversion is required, so we
// might as well always convert
InputStream source = resource.getInputStream();
if (!source.markSupported()) {
source = new BufferedInputStream(source);
}
Charset bomCharset = processBom(source, useBomIfPresent.stripBom);
if (bomCharset != null && useBomIfPresent.useBomEncoding) {
inputEncoding = bomCharset.name();
}
// specified
if (outputEncodingSpecified) {
OutputStreamWriter osw = new OutputStreamWriter(ostream, charset);
PrintWriter pw = new PrintWriter(osw);
copy(source, pw, inputEncoding);
pw.flush();
} else {
// Just included but no conversion
renderResult = source;
}
} else {
if (!checkSendfile(request, response, resource, contentLength, null)) {
// sendfile not possible so check if resource
// content is available directly via
// CachedResource. Do not want to call
// getContent() on other resource
// implementations as that could trigger loading
// the contents of a very large file into memory
byte[] resourceBody = null;
if (resource instanceof CachedResource) {
resourceBody = resource.getContent();
}
if (resourceBody == null) {
// Resource content not directly available,
// use InputStream
renderResult = resource.getInputStream();
} else {
// Use the resource content directly
ostream.write(resourceBody);
}
}
}
}
// the output (this method closes the stream)
if (renderResult != null) {
copy(renderResult, ostream);
}
}
}
} else {
if ((ranges == null) || (ranges.getEntries().isEmpty())) {
return;
}
// Partial content response.
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
if (ranges.getEntries().size() == 1) {
Ranges.Entry range = ranges.getEntries().get(0);
long start = getStart(range, contentLength);
long end = getEnd(range, contentLength);
response.addHeader("Content-Range", "bytes " + start + "-" + end + "/" + contentLength);
long length = end - start + 1;
response.setContentLengthLong(length);
if (contentType != null) {
if (debug > 0) {
log("DefaultServlet.serveFile: contentType='" + contentType + "'");
}
response.setContentType(contentType);
}
if (serveContent) {
try {
response.setBufferSize(output);
} catch (IllegalStateException e) {
// Silent catch
}
if (ostream != null) {
if (!checkSendfile(request, response, resource, contentLength, range)) {
copy(resource, contentLength, ostream, range);
}
} else {
// we should not get here
throw new IllegalStateException();
}
}
} else {
response.setContentType("multipart/byteranges; boundary=" + mimeSeparation);
if (serveContent) {
try {
response.setBufferSize(output);
} catch (IllegalStateException e) {
// Silent catch
}
if (ostream != null) {
copy(resource, contentLength, ostream, ranges, contentType);
} else {
// we should not get here
throw new IllegalStateException();
}
}
}
}
}
use of jakarta.servlet.http.HttpServletResponse in project tomcat by apache.
the class TestExpiresFilter method testExcludedResponseStatusCode.
@Test
public void testExcludedResponseStatusCode() throws Exception {
HttpServlet servlet = new HttpServlet() {
private static final long serialVersionUID = 1L;
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
response.addHeader("ETag", "W/\"1934-1269208821000\"");
response.addDateHeader("Date", System.currentTimeMillis());
}
};
validate(servlet, null, HttpServletResponse.SC_NOT_MODIFIED);
}
Aggregations