public static void handleThemeResourceRequest(final HttpServletRequest req,
			final HttpServletResponse resp)
			throws ServletException, IOException {

		if (req.getHeader("If-Modified-Since") != null) {
			resp.reset();
			resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
			return;
		}

		String fileName = req.getParameter("f");

		String path = req.getPathInfo();
		if (fileName == null && !Util.empty(path)) {
			int offset = path.startsWith(THEME_RESOURCE_PATH_PARAM) ? THEME_RESOURCE_PATH_PARAM.
					length() : 1;
			fileName = path.substring(offset);
		}

		if (fileName == null || !checkThemeFile(fileName)) {
			resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
			return;
		}

		InputStream resourceStream = null;

		try {
			URL url = null;

			// Check for project translation file
			if (fileName.startsWith(THEME_TRANSLATION_RESOURCE_PREFIX)) {
				String resourceFileName = fileName.substring(THEME_TRANSLATION_RESOURCE_PREFIX.length());
				url = ServletUtil.class.getResource(THEME_PROJECT_TRANSLATION_RESOURCE_PATH + resourceFileName);
			}

			// Load from the theme path
			if (url == null) {
				String resourceName = ThemeUtil.getThemeBase() + fileName;
				url = ServletUtil.class.getResource(resourceName);
			}

			if (url == null) {
				resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
			} else {
				URLConnection connection = url.openConnection();
				resourceStream = connection.getInputStream();
				int size = resourceStream.available();
				if (size > 0) {
					resp.setContentLength(size);
				}

				/*
				I have commented out the setting of the Content-Disposition on static theme resources because, well why is it there?
				If this needs to be reinstated please provide a thorough justification comment here so the reasons are clear.

				Note that setting this header breaks Polymer 1.0 when it is present on HTML imports.

				String encodedName = WebUtilities.encodeForContentDispositionHeader(fileName.
						substring(fileName
								.lastIndexOf('/') + 1));
				resp.setHeader("Content-Disposition", "filename=" + encodedName);  // "filename=" to comply with https://tools.ietf.org/html/rfc6266
				 */
				resp.setContentType(WebUtilities.getContentType(fileName));
				resp.setHeader("Cache-Control", CacheType.THEME_CACHE.getSettings());

				resp.setHeader("Expires", "31536000");
				resp.setHeader("ETag", "\"" + WebUtilities.getProjectVersion() + "\"");
				// resp.setHeader("Last-Modified", "Mon, 02 Jan 2015 01:00:00 GMT");
				long modified = connection.getLastModified();
				resp.setDateHeader("Last-Modified", modified);
				StreamUtil.copy(resourceStream, resp.getOutputStream());
			}
		} finally {
			StreamUtil.safeClose(resourceStream);
		}
	}
public static void handleThemeResourceRequest ( final HttpServletRequest req , final HttpServletResponse resp ) throws ServletException , IOException { if ( req . getHeader ( "If-Modified-Since" ) != null ) { resp . reset ( ) ; resp . setStatus ( HttpServletResponse . SC_NOT_MODIFIED ) ; return ; } String fileName = req . getParameter ( "f" ) ; String path = req . getPathInfo ( ) ; if ( fileName == null && ! Util . empty ( path ) ) { int offset = path . startsWith ( THEME_RESOURCE_PATH_PARAM ) ? THEME_RESOURCE_PATH_PARAM . length ( ) : 1 ; fileName = path . substring ( offset ) ; } if ( fileName == null || ! checkThemeFile ( fileName ) ) { resp . setStatus ( HttpServletResponse . SC_NOT_FOUND ) ; return ; } InputStream resourceStream = null ; try { URL url = null ; if ( fileName . startsWith ( THEME_TRANSLATION_RESOURCE_PREFIX ) ) { String resourceFileName = fileName . substring ( THEME_TRANSLATION_RESOURCE_PREFIX . length ( ) ) ; url = ServletUtil . class . getResource ( THEME_PROJECT_TRANSLATION_RESOURCE_PATH + resourceFileName ) ; } if ( url == null ) { String resourceName = ThemeUtil . getThemeBase ( ) + fileName ; url = ServletUtil . class . getResource ( resourceName ) ; } if ( url == null ) { resp . setStatus ( HttpServletResponse . SC_NOT_FOUND ) ; } else { URLConnection connection = url . openConnection ( ) ; resourceStream = connection . getInputStream ( ) ; int size = resourceStream . available ( ) ; if ( size > 0 ) { resp . setContentLength ( size ) ; } resp . setContentType ( WebUtilities . getContentType ( fileName ) ) ; resp . setHeader ( "Cache-Control" , CacheType . THEME_CACHE . getSettings ( ) ) ; resp . setHeader ( "Expires" , "31536000" ) ; resp . setHeader ( "ETag" , "\"" + WebUtilities . getProjectVersion ( ) + "\"" ) ; long modified = connection . getLastModified ( ) ; resp . setDateHeader ( "Last-Modified" , modified ) ; StreamUtil . copy ( resourceStream , resp . getOutputStream ( ) ) ; } } finally { StreamUtil . safeClose ( resourceStream ) ; } }
Serves up a file from the theme. In practice it is generally a bad idea to use this servlet to serve up static
resources. Instead it would make more sense to move CSS, JS, HTML resources to a CDN or similar.


@param req the request with the file name in parameter "f", or following the servlet path.
@param resp the response to write to.
@throws ServletException on error.
@throws IOException if there is an error reading the file / writing the response.