diff options
author | Artur Signell <artur@vaadin.com> | 2013-03-27 14:57:50 +0200 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2013-04-03 13:01:43 +0000 |
commit | 3c479dd00b24acad23e7c97e7283e31299d771d1 (patch) | |
tree | 436156b439ae7952829bec24a247e486ac8ac107 | |
parent | ad290f8c65057bdef33ec73cb49a8c6d10b9e356 (diff) | |
download | vaadin-framework-3c479dd00b24acad23e7c97e7283e31299d771d1.tar.gz vaadin-framework-3c479dd00b24acad23e7c97e7283e31299d771d1.zip |
Refactored how all requests are handled by VaadinServlet and VaadinPortlet (#11192)
* Handling is now based on a list of RequestHandlers in VaadinService
* Request handling logic has been moved to VaadinService
* Users can customize the list by adding own (service level) request handlers
* For users specific request handlers you can still use the request handlers in VaadinSession
* Deprecated RequestType - all handlers are given the opportunity to handle a request until one of them chooses to handle it. RequestType makes no sense as it does not tell which handler will handle the request.
* Removed serveStaticResource which has never been used
Change-Id: Ia7d088535e46430ca8adf631d3f1dd944b9d51e2
18 files changed, 658 insertions, 570 deletions
diff --git a/server/src/com/vaadin/server/BootstrapHandler.java b/server/src/com/vaadin/server/BootstrapHandler.java index 9c603ae7ed..80cadb02c1 100644 --- a/server/src/com/vaadin/server/BootstrapHandler.java +++ b/server/src/com/vaadin/server/BootstrapHandler.java @@ -115,6 +115,12 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { @Override public boolean synchronizedHandleRequest(VaadinSession session, VaadinRequest request, VaadinResponse response) throws IOException { + String pathInfo = request.getPathInfo(); + if (pathInfo.startsWith("/" + ApplicationConstants.APP_PATH + "/")) { + // We do not want to handle /APP requests here, instead let it fall + // through and produce a 404 + return false; + } try { List<UIProvider> uiProviders = session.getUIProviders(); diff --git a/server/src/com/vaadin/server/ConnectorResourceHandler.java b/server/src/com/vaadin/server/ConnectorResourceHandler.java index 12c6df6ffa..00d82988d3 100644 --- a/server/src/com/vaadin/server/ConnectorResourceHandler.java +++ b/server/src/com/vaadin/server/ConnectorResourceHandler.java @@ -48,60 +48,50 @@ public class ConnectorResourceHandler implements RequestHandler { return false; } Matcher matcher = CONNECTOR_RESOURCE_PATTERN.matcher(requestPath); - if (matcher.matches()) { - String uiId = matcher.group(1); - String cid = matcher.group(2); - String key = matcher.group(3); - - session.lock(); - UI ui; - ClientConnector connector; - try { - ui = session.getUIById(Integer.parseInt(uiId)); - if (ui == null) { - return error(request, response, - "Ignoring connector request for no-existent root " - + uiId); - } - - connector = ui.getConnectorTracker().getConnector(cid); - if (connector == null) { - return error(request, response, - "Ignoring connector request for no-existent connector " - + cid + " in root " + uiId); - } + if (!matcher.matches()) { + return false; + } + String uiId = matcher.group(1); + String cid = matcher.group(2); + String key = matcher.group(3); - } finally { - session.unlock(); + session.lock(); + UI ui; + ClientConnector connector; + try { + ui = session.getUIById(Integer.parseInt(uiId)); + if (ui == null) { + return error(request, response, + "Ignoring connector request for no-existent root " + + uiId); } - Map<Class<?>, CurrentInstance> oldThreadLocals = CurrentInstance - .setThreadLocals(ui); - try { - if (!connector.handleConnectorRequest(request, response, key)) { - return error(request, response, - connector.getClass().getSimpleName() + " (" - + connector.getConnectorId() - + ") did not handle connector request for " - + key); - } - } finally { - CurrentInstance.restoreThreadLocals(oldThreadLocals); + connector = ui.getConnectorTracker().getConnector(cid); + if (connector == null) { + return error(request, response, + "Ignoring connector request for no-existent connector " + + cid + " in root " + uiId); } - return true; - } else if (requestPath.matches('/' + ApplicationConstants.APP_PATH - + "(/.*)?")) { - /* - * This should be the last request handler before we get to - * bootstrap logic. Prevent /APP requests from reaching bootstrap - * handlers to help protect the /APP name space for framework usage. - */ - return error(request, response, - "Returning 404 for /APP request not yet handled."); - } else { - return false; + } finally { + session.unlock(); } + + Map<Class<?>, CurrentInstance> oldThreadLocals = CurrentInstance + .setThreadLocals(ui); + try { + if (!connector.handleConnectorRequest(request, response, key)) { + return error(request, response, connector.getClass() + .getSimpleName() + + " (" + + connector.getConnectorId() + + ") did not handle connector request for " + key); + } + } finally { + CurrentInstance.restoreThreadLocals(oldThreadLocals); + } + + return true; } private static boolean error(VaadinRequest request, diff --git a/server/src/com/vaadin/server/GAEVaadinServlet.java b/server/src/com/vaadin/server/GAEVaadinServlet.java index 0d2063d446..b4a83603b0 100644 --- a/server/src/com/vaadin/server/GAEVaadinServlet.java +++ b/server/src/com/vaadin/server/GAEVaadinServlet.java @@ -184,16 +184,14 @@ public class GAEVaadinServlet extends VaadinServlet { return; } - RequestType requestType = getRequestType(request); - - if (requestType == RequestType.STATIC_FILE) { + if (isStaticResourceRequest(request)) { // no locking needed, let superclass handle super.service(request, response); cleanSession(request); return; } - if (requestType == RequestType.APP) { + if (ServletPortletHelper.isAppRequest(request)) { // no locking needed, let superclass handle getApplicationContext(request, MemcacheServiceFactory.getMemcacheService()); @@ -205,7 +203,11 @@ public class GAEVaadinServlet extends VaadinServlet { final HttpSession session = request.getSession(getService() .requestCanCreateSession(request)); if (session == null) { - handleServiceSessionExpired(request, response); + try { + getService().handleSessionExpired(request, response); + } catch (ServiceException e) { + throw new ServletException(e); + } cleanSession(request); return; } @@ -218,19 +220,21 @@ public class GAEVaadinServlet extends VaadinServlet { // try to get lock long started = new Date().getTime(); // non-UIDL requests will try indefinitely - while (requestType != RequestType.UIDL - || new Date().getTime() - started < MAX_UIDL_WAIT_MILLISECONDS) { - locked = memcache.put(mutex, 1, Expiration.byDeltaSeconds(40), - MemcacheService.SetPolicy.ADD_ONLY_IF_NOT_PRESENT); - if (locked) { - break; - } - try { - Thread.sleep(RETRY_AFTER_MILLISECONDS); - } catch (InterruptedException e) { - getLogger().finer( - "Thread.sleep() interrupted while waiting for lock. Trying again. " - + e); + if (!ServletPortletHelper.isUIDLRequest(request)) { + while (new Date().getTime() - started < MAX_UIDL_WAIT_MILLISECONDS) { + locked = memcache.put(mutex, 1, + Expiration.byDeltaSeconds(40), + MemcacheService.SetPolicy.ADD_ONLY_IF_NOT_PRESENT); + if (locked) { + break; + } + try { + Thread.sleep(RETRY_AFTER_MILLISECONDS); + } catch (InterruptedException e) { + getLogger().finer( + "Thread.sleep() interrupted while waiting for lock. Trying again. " + + e); + } } } diff --git a/server/src/com/vaadin/server/LegacyCommunicationManager.java b/server/src/com/vaadin/server/LegacyCommunicationManager.java index b956b806bd..2f559e4b26 100644 --- a/server/src/com/vaadin/server/LegacyCommunicationManager.java +++ b/server/src/com/vaadin/server/LegacyCommunicationManager.java @@ -65,10 +65,6 @@ public class LegacyCommunicationManager implements Serializable { // TODO PUSH move public static final String WRITE_SECURITY_TOKEN_FLAG = "writeSecurityToken"; - private static final RequestHandler UNSUPPORTED_BROWSER_HANDLER = new UnsupportedBrowserHandler(); - - private static final RequestHandler CONNECTOR_RESOURCE_HANDLER = new ConnectorResourceHandler(); - /** * TODO Document me! * @@ -112,10 +108,6 @@ public class LegacyCommunicationManager implements Serializable { */ public LegacyCommunicationManager(VaadinSession session) { this.session = session; - session.addRequestHandler(session.getService().createBootstrapHandler( - session)); - session.addRequestHandler(UNSUPPORTED_BROWSER_HANDLER); - session.addRequestHandler(CONNECTOR_RESOURCE_HANDLER); requireLocale(session.getLocale().toString()); } diff --git a/server/src/com/vaadin/server/VaadinPortlet.java b/server/src/com/vaadin/server/VaadinPortlet.java index 9dd8a4c94b..6aa7546b16 100644 --- a/server/src/com/vaadin/server/VaadinPortlet.java +++ b/server/src/com/vaadin/server/VaadinPortlet.java @@ -17,17 +17,14 @@ package com.vaadin.server; import java.io.BufferedWriter; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.Serializable; import java.lang.reflect.Method; -import java.net.MalformedURLException; import java.util.Enumeration; import java.util.Map; import java.util.Properties; -import java.util.logging.Level; import java.util.logging.Logger; import javax.portlet.ActionRequest; @@ -46,18 +43,11 @@ import javax.portlet.ResourceRequest; import javax.portlet.ResourceResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; -import javax.servlet.http.HttpServletResponse; import com.liferay.portal.kernel.util.PortalClassInvoker; import com.liferay.portal.kernel.util.PropsUtil; -import com.vaadin.server.LegacyCommunicationManager.Callback; -import com.vaadin.server.communication.FileUploadHandler; -import com.vaadin.server.communication.HeartbeatHandler; -import com.vaadin.server.communication.PortletListenerNotifier; -import com.vaadin.server.communication.PublishedFileHandler; -import com.vaadin.server.communication.SessionRequestHandler; -import com.vaadin.server.communication.UIInitHandler; -import com.vaadin.server.communication.UidlRequestHandler; +import com.vaadin.server.communication.PortletDummyRequestHandler; +import com.vaadin.server.communication.PortletUIInitHandler; import com.vaadin.util.CurrentInstance; /** @@ -207,24 +197,6 @@ public class VaadinPortlet extends GenericPortlet implements Constants, } - public static class AbstractApplicationPortletWrapper implements Callback { - - private final VaadinPortlet portlet; - - public AbstractApplicationPortletWrapper(VaadinPortlet portlet) { - this.portlet = portlet; - } - - @Override - public void criticalNotification(VaadinRequest request, - VaadinResponse response, String cap, String msg, - String details, String outOfSyncURL) throws IOException { - portlet.criticalNotification((VaadinPortletRequest) request, - (VaadinPortletResponse) response, cap, msg, details, - outOfSyncURL); - } - } - /** * This portlet parameter is used to add styles to the main element. E.g * "height:500px" generates a style="height:500px" to the main element. @@ -287,6 +259,7 @@ public class VaadinPortlet extends GenericPortlet implements Constants, vaadinService.setCurrentInstances(null, null); portletInitialized(); + CurrentInstance.clearAll(); } @@ -307,8 +280,10 @@ public class VaadinPortlet extends GenericPortlet implements Constants, /** * @author Vaadin Ltd * - * @deprecated As of 7.0. Will likely change or be removed in a future - * version + * @deprecated As of 7.0. This is no longer used and only provided for + * backwards compatibility. Each {@link RequestHandler} can + * individually decide whether it wants to handle a request or + * not. */ @Deprecated protected enum RequestType { @@ -319,8 +294,10 @@ public class VaadinPortlet extends GenericPortlet implements Constants, * @param vaadinRequest * @return * - * @deprecated As of 7.0. Will likely change or be removed in a future - * version + * @deprecated As of 7.0. This is no longer used and only provided for + * backwards compatibility. Each {@link RequestHandler} can + * individually decide whether it wants to handle a request or + * not. */ @Deprecated protected RequestType getRequestType(VaadinPortletRequest vaadinRequest) { @@ -331,7 +308,7 @@ public class VaadinPortlet extends GenericPortlet implements Constants, ResourceRequest resourceRequest = (ResourceRequest) request; if (ServletPortletHelper.isUIDLRequest(vaadinRequest)) { return RequestType.UIDL; - } else if (isBrowserDetailsRequest(resourceRequest)) { + } else if (PortletUIInitHandler.isUIInitRequest(vaadinRequest)) { return RequestType.BROWSER_DETAILS; } else if (ServletPortletHelper.isFileUploadRequest(vaadinRequest)) { return RequestType.FILE_UPLOAD; @@ -342,7 +319,7 @@ public class VaadinPortlet extends GenericPortlet implements Constants, return RequestType.APP; } else if (ServletPortletHelper.isHeartbeatRequest(vaadinRequest)) { return RequestType.HEARTBEAT; - } else if (isDummyRequest(resourceRequest)) { + } else if (PortletDummyRequestHandler.isDummyRequest(vaadinRequest)) { return RequestType.DUMMY; } else { return RequestType.STATIC_FILE; @@ -355,16 +332,6 @@ public class VaadinPortlet extends GenericPortlet implements Constants, return RequestType.UNKNOWN; } - private boolean isBrowserDetailsRequest(ResourceRequest request) { - return request.getResourceID() != null - && request.getResourceID().equals("v-browserDetails"); - } - - private boolean isDummyRequest(ResourceRequest request) { - return request.getResourceID() != null - && request.getResourceID().equals("DUMMY"); - } - /** * @param request * @param response @@ -380,93 +347,11 @@ public class VaadinPortlet extends GenericPortlet implements Constants, CurrentInstance.clearAll(); setCurrent(this); - handleRequest(createVaadinRequest(request), - createVaadinResponse(response)); - } - - protected void handleRequest(VaadinPortletRequest request, - VaadinPortletResponse response) throws PortletException, - IOException { - getService().requestStart(request, response); - - VaadinPortletSession vaadinSession = null; try { - AbstractApplicationPortletWrapper portletWrapper = new AbstractApplicationPortletWrapper( - this); - - RequestType requestType = getRequestType(request); - - if (requestType == RequestType.UNKNOWN) { - handleUnknownRequest(request, response); - } else if (requestType == RequestType.DUMMY) { - /* - * This dummy page is used by action responses to redirect to, - * in order to prevent the boot strap code from being rendered - * into strange places such as iframes. - */ - ((ResourceResponse) response).setContentType("text/html"); - final OutputStream out = ((ResourceResponse) response) - .getPortletOutputStream(); - final PrintWriter outWriter = new PrintWriter( - new BufferedWriter(new OutputStreamWriter(out, "UTF-8"))); - outWriter.print("<html><body>dummy page</body></html>"); - outWriter.close(); - } else if (requestType == RequestType.STATIC_FILE) { - serveStaticResources((ResourceRequest) request, - (ResourceResponse) response); - } else { - try { - vaadinSession = (VaadinPortletSession) getService() - .findVaadinSession(request); - if (vaadinSession == null) { - return; - } - - if (requestType == RequestType.PUBLISHED_FILE) { - new PublishedFileHandler().handleRequest(vaadinSession, - request, response); - return; - } else if (requestType == RequestType.HEARTBEAT) { - new HeartbeatHandler().handleRequest(vaadinSession, - request, response); - return; - } - - // Notify listeners - new PortletListenerNotifier().handleRequest(vaadinSession, - request, response); - - /* Handle the request */ - if (requestType == RequestType.FILE_UPLOAD) { - new FileUploadHandler().handleRequest(vaadinSession, - request, response); - return; - } else if (requestType == RequestType.BROWSER_DETAILS) { - new UIInitHandler().handleRequest(vaadinSession, - request, response); - return; - } else if (requestType == RequestType.UIDL) { - // Handles AJAX UIDL requests - new UidlRequestHandler(portletWrapper).handleRequest( - vaadinSession, request, response); - - return; - } else { - handleOtherRequest(request, response, requestType, - vaadinSession, - vaadinSession.getCommunicationManager()); - } - } catch (final SessionExpiredException e) { - // TODO Figure out a better way to deal with - // SessionExpiredExceptions - getLogger().finest("A user session has expired"); - } catch (final Throwable e) { - handleServiceException(request, response, vaadinSession, e); - - } - } - } finally { - getService().requestEnd(request, response, vaadinSession); + getService().handleRequest(createVaadinRequest(request), + createVaadinResponse(response)); + } catch (ServiceException e) { + throw new PortletException(e); } } @@ -498,80 +383,12 @@ public class VaadinPortlet extends GenericPortlet implements Constants, return vaadinService; } - private void handleUnknownRequest(VaadinPortletRequest request, - VaadinPortletResponse response) { - getLogger().warning("Unknown request type"); - } - - /** - * Handle a portlet request that is not for static files, UIDL or upload. - * Also render requests are handled here. - * - * This method is called after starting the application and calling portlet - * and transaction listeners. - * - * @param request - * @param response - * @param requestType - * @param vaadinSession - * @param vaadinSession - * @param communicationManager - * @throws PortletException - * @throws IOException - * @throws MalformedURLException - */ - private void handleOtherRequest(VaadinPortletRequest request, - VaadinResponse response, RequestType requestType, - VaadinSession vaadinSession, - LegacyCommunicationManager communicationManager) - throws PortletException, IOException, MalformedURLException { - if (requestType == RequestType.APP || requestType == RequestType.RENDER) { - if (!new SessionRequestHandler().handleRequest(vaadinSession, - request, response)) { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - "Not found"); - } - } else if (requestType == RequestType.EVENT) { - // nothing to do, listeners do all the work - } else if (requestType == RequestType.ACTION) { - // nothing to do, listeners do all the work - } else { - throw new IllegalStateException( - "handleRequest() without anything to do - should never happen!"); - } - } - @Override public void processEvent(EventRequest request, EventResponse response) throws PortletException, IOException { handleRequest(request, response); } - private void serveStaticResources(ResourceRequest request, - ResourceResponse response) throws IOException, PortletException { - final String resourceID = request.getResourceID(); - final PortletContext pc = getPortletContext(); - - InputStream is = pc.getResourceAsStream(resourceID); - if (is != null) { - final String mimetype = pc.getMimeType(resourceID); - if (mimetype != null) { - response.setContentType(mimetype); - } - final OutputStream os = response.getPortletOutputStream(); - final byte buffer[] = new byte[DEFAULT_BUFFER_SIZE]; - int bytes; - while ((bytes = is.read(buffer)) >= 0) { - os.write(buffer, 0, bytes); - } - } else { - getLogger().log(Level.INFO, - "Requested resource [{0}] could not be found", resourceID); - response.setProperty(ResourceResponse.HTTP_STATUS_CODE, - Integer.toString(HttpServletResponse.SC_NOT_FOUND)); - } - } - @Override public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException { @@ -606,44 +423,6 @@ public class VaadinPortlet extends GenericPortlet implements Constants, handleRequest(request, response); } - private void handleServiceException(VaadinPortletRequest request, - VaadinPortletResponse response, VaadinSession vaadinSession, - Throwable e) throws IOException, PortletException { - // TODO Check that this error handler is working when running inside a - // portlet - if (vaadinSession != null) { - vaadinSession.lock(); - } - try { - // if this was an UIDL request, response UIDL back to client - ErrorHandler errorHandler = ErrorEvent - .findErrorHandler(vaadinSession); - if (getRequestType(request) == RequestType.UIDL) { - SystemMessages ci = getService().getSystemMessages( - ServletPortletHelper.findLocale(null, vaadinSession, - request), request); - criticalNotification(request, response, - ci.getInternalErrorCaption(), - ci.getInternalErrorMessage(), null, - ci.getInternalErrorURL()); - if (errorHandler != null) { - errorHandler.error(new ErrorEvent(e)); - } - } else { - if (errorHandler != null) { - errorHandler.error(new ErrorEvent(e)); - } else { - // Re-throw other exceptions - throw new PortletException(e); - } - } - } finally { - if (vaadinSession != null) { - vaadinSession.unlock(); - } - } - } - /** * Send notification to client's application. Used to notify client of * critical errors and session expiration due to long inactivity. Server has diff --git a/server/src/com/vaadin/server/VaadinPortletService.java b/server/src/com/vaadin/server/VaadinPortletService.java index 6023f6448b..b9dcfa5768 100644 --- a/server/src/com/vaadin/server/VaadinPortletService.java +++ b/server/src/com/vaadin/server/VaadinPortletService.java @@ -17,17 +17,23 @@ package com.vaadin.server; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import javax.portlet.EventRequest; import javax.portlet.PortletContext; import javax.portlet.PortletRequest; - +import javax.portlet.RenderRequest; import com.vaadin.server.VaadinPortlet.RequestType; import com.vaadin.server.communication.PortletBootstrapHandler; +import com.vaadin.server.communication.PortletDummyRequestHandler; +import com.vaadin.server.communication.PortletListenerNotifier; +import com.vaadin.server.communication.PortletUIInitHandler; import com.vaadin.ui.UI; public class VaadinPortletService extends VaadinService { @@ -49,6 +55,35 @@ public class VaadinPortletService extends VaadinService { } } + /* + * (non-Javadoc) + * + * @see + * com.vaadin.server.LegacyCommunicationManager.Callback#criticalNotification + * (com.vaadin.server.VaadinRequest, com.vaadin.server.VaadinResponse, + * java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + @Deprecated + @Override + public void criticalNotification(VaadinRequest request, + VaadinResponse response, String cap, String msg, String details, + String url) throws IOException { + getPortlet().criticalNotification((VaadinPortletRequest) request, + (VaadinPortletResponse) response, cap, msg, details, url); + } + + @Override + protected List<RequestHandler> createRequestHandlers() { + List<RequestHandler> handlers = super.createRequestHandlers(); + + handlers.add(new PortletUIInitHandler()); + handlers.add(new PortletListenerNotifier()); + handlers.add(0, new PortletDummyRequestHandler()); + handlers.add(0, new PortletBootstrapHandler()); + + return handlers; + } + /** * Retrieves a reference to the portlet associated with this service. * @@ -163,13 +198,19 @@ public class VaadinPortletService extends VaadinService { @Override protected boolean requestCanCreateSession(VaadinRequest request) { - RequestType requestType = getRequestType(request); - if (requestType == RequestType.RENDER) { + if (!(request instanceof VaadinPortletRequest)) { + throw new IllegalArgumentException( + "Request is not a VaadinPortletRequest"); + } + + PortletRequest portletRequest = ((VaadinPortletRequest) request) + .getPortletRequest(); + if (portletRequest instanceof RenderRequest) { // In most cases the first request is a render request that // renders the HTML fragment. This should create a Vaadin // session unless there is already one. return true; - } else if (requestType == RequestType.EVENT) { + } else if (portletRequest instanceof EventRequest) { // A portlet can also be sent an event even though it has not // been rendered, e.g. portlet on one page sends an event to a // portlet on another page and then moves the user to that page. @@ -254,8 +295,19 @@ public class VaadinPortletService extends VaadinService { return "v-" + portletRequest.getWindowID(); } + /* + * (non-Javadoc) + * + * @see + * com.vaadin.server.VaadinService#handleSessionExpired(com.vaadin.server + * .VaadinRequest, com.vaadin.server.VaadinResponse) + */ @Override - protected BootstrapHandler createBootstrapHandler(VaadinSession session) { - return new PortletBootstrapHandler(); + protected void handleSessionExpired(VaadinRequest request, + VaadinResponse response) { + // TODO Figure out a better way to deal with + // SessionExpiredExceptions + getLogger().finest("A user session has expired"); } + } diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java index e4970d4104..3b088294e3 100644 --- a/server/src/com/vaadin/server/VaadinService.java +++ b/server/src/com/vaadin/server/VaadinService.java @@ -17,6 +17,7 @@ package com.vaadin.server; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.lang.reflect.Constructor; @@ -24,7 +25,9 @@ import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -33,9 +36,16 @@ import java.util.logging.Logger; import javax.portlet.PortletContext; import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletResponse; import com.vaadin.annotations.PreserveOnRefresh; import com.vaadin.event.EventRouter; +import com.vaadin.server.LegacyCommunicationManager.Callback; +import com.vaadin.server.communication.FileUploadHandler; +import com.vaadin.server.communication.HeartbeatHandler; +import com.vaadin.server.communication.PublishedFileHandler; +import com.vaadin.server.communication.SessionRequestHandler; +import com.vaadin.server.communication.UidlRequestHandler; import com.vaadin.shared.ui.ui.UIConstants; import com.vaadin.ui.UI; import com.vaadin.util.CurrentInstance; @@ -49,7 +59,7 @@ import com.vaadin.util.ReflectTools; * * @since 7.0 */ -public abstract class VaadinService implements Serializable { +public abstract class VaadinService implements Serializable, Callback { static final String REINITIALIZING_SESSION_MARKER = VaadinService.class .getName() + ".reinitializing"; @@ -83,6 +93,8 @@ public abstract class VaadinService implements Serializable { private ClassLoader classLoader; + private final Iterable<RequestHandler> requestHandlers; + /** * Creates a new vaadin service based on a deployment configuration * @@ -108,6 +120,33 @@ public abstract class VaadinService implements Serializable { + classLoaderName, e); } } + + List<RequestHandler> handlers = createRequestHandlers(); + Collections.reverse(handlers); + requestHandlers = Collections.unmodifiableCollection(handlers); + + } + + /** + * Called during initialization to add the request handlers for the service. + * Note that the returned list will be reversed so the last handler will be + * called first. This enables overriding this method and using add on the + * returned list to add a custom request handler which overrides any + * predefined handler. + * + * @return The list of request handlers used by this service. + */ + protected List<RequestHandler> createRequestHandlers() { + ArrayList<RequestHandler> handlers = new ArrayList<RequestHandler>(); + handlers.add(new SessionRequestHandler()); + handlers.add(new PublishedFileHandler()); + handlers.add(new HeartbeatHandler()); + handlers.add(new FileUploadHandler()); + handlers.add(new UidlRequestHandler(this)); + handlers.add(new UnsupportedBrowserHandler()); + handlers.add(new ConnectorResourceHandler()); + + return handlers; } /** @@ -286,13 +325,6 @@ public abstract class VaadinService implements Serializable { public abstract File getBaseDirectory(); /** - * Creates the bootstrap handler that should be used to generate the initial - * HTML bootstrapping a new {@link UI} in the given session. - */ - protected abstract BootstrapHandler createBootstrapHandler( - VaadinSession session); - - /** * Adds a listener that gets notified when a new Vaadin service session is * initialized for this service. * <p> @@ -1203,4 +1235,125 @@ public abstract class VaadinService implements Serializable { } CurrentInstance.clearAll(); } + + /** + * Returns the request handlers that are registered with this service. The + * iteration order of the returned collection is the same as the order in + * which the request handlers will be invoked when a request is handled. + * + * @return a collection of request handlers in the order they are invoked + * + * @see #createRequestHandlers() + * + * @since 7.1 + */ + public Iterable<RequestHandler> getRequestHandlers() { + return requestHandlers; + } + + /** + * Handles the incoming request and writes the response into the response + * object. Uses {@link #getRequestHandlers()} for handling the request. + * + * @param request + * The incoming request + * @param response + * The outgoing response + * @throws ServiceException + * Any exception that occurs during response handling will be + * wrapped in a ServiceException + */ + public void handleRequest(VaadinRequest request, VaadinResponse response) + throws ServiceException { + requestStart(request, response); + + VaadinSession vaadinSession = null; + try { + // Find out the service session this request is related to + vaadinSession = findVaadinSession(request); + if (vaadinSession == null) { + return; + } + + for (RequestHandler handler : getRequestHandlers()) { + if (handler.handleRequest(vaadinSession, request, response)) { + return; + } + } + + // Request not handled by any RequestHandler + response.sendError(HttpServletResponse.SC_NOT_FOUND, + "Request was not handled by any registered handler."); + + } catch (final SessionExpiredException e) { + handleSessionExpired(request, response); + } catch (final Throwable e) { + handleExceptionDuringRequest(request, response, vaadinSession, e); + } finally { + requestEnd(request, response, vaadinSession); + } + } + + private void handleExceptionDuringRequest(VaadinRequest request, + VaadinResponse response, VaadinSession vaadinSession, Throwable t) + throws ServiceException { + if (vaadinSession != null) { + vaadinSession.lock(); + } + try { + ErrorHandler errorHandler = ErrorEvent + .findErrorHandler(vaadinSession); + + // if this was an UIDL request, response UIDL back to client + if (ServletPortletHelper.isUIDLRequest(request)) { + SystemMessages ci = getSystemMessages( + ServletPortletHelper.findLocale(null, vaadinSession, + request), request); + try { + criticalNotification(request, response, + ci.getInternalErrorCaption(), + ci.getInternalErrorMessage(), null, + ci.getInternalErrorURL()); + } catch (IOException e) { + // An exception occured while writing the response. Log + // it and continue handling only the original error. + getLogger() + .log(Level.WARNING, + "Failed to write critical notification response to the client", + e); + } + if (errorHandler != null) { + errorHandler.error(new ErrorEvent(t)); + } + } else { + if (errorHandler != null) { + errorHandler.error(new ErrorEvent(t)); + } + + // Re-throw other exceptions + throw new ServiceException(t); + } + } finally { + if (vaadinSession != null) { + vaadinSession.unlock(); + } + } + + } + + /** + * Called when the session has expired and the request handling is therefore + * aborted. + * + * @param request + * The request + * @param response + * The response + * @throws ServiceException + * Thrown if there was any problem handling the expiration of + * the session + */ + protected abstract void handleSessionExpired(VaadinRequest request, + VaadinResponse response) throws ServiceException; + } diff --git a/server/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java index 5780b2bbc9..2c274957d9 100644 --- a/server/src/com/vaadin/server/VaadinServlet.java +++ b/server/src/com/vaadin/server/VaadinServlet.java @@ -39,41 +39,12 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.vaadin.sass.internal.ScssStylesheet; -import com.vaadin.server.LegacyCommunicationManager.Callback; -import com.vaadin.server.communication.FileUploadHandler; -import com.vaadin.server.communication.HeartbeatHandler; -import com.vaadin.server.communication.PublishedFileHandler; -import com.vaadin.server.communication.SessionRequestHandler; -import com.vaadin.server.communication.UIInitHandler; -import com.vaadin.server.communication.UidlRequestHandler; +import com.vaadin.server.communication.ServletUIInitHandler; import com.vaadin.util.CurrentInstance; @SuppressWarnings("serial") public class VaadinServlet extends HttpServlet implements Constants { - private static class AbstractApplicationServletWrapper implements Callback { - - private final VaadinServlet servlet; - - public AbstractApplicationServletWrapper(VaadinServlet servlet) { - this.servlet = servlet; - } - - @Override - public void criticalNotification(VaadinRequest request, - VaadinResponse response, String cap, String msg, - String details, String outOfSyncURL) throws IOException { - servlet.criticalNotification((VaadinServletRequest) request, - ((VaadinServletResponse) response), cap, msg, details, - outOfSyncURL); - } - } - - // TODO Move some (all?) of the constants to a separate interface (shared - // with portlet) - - private final String resourcePath = null; - private VaadinServletService servletService; /** @@ -200,7 +171,23 @@ public class VaadinServlet extends HttpServlet implements Constants { } CurrentInstance.clearAll(); setCurrent(this); - service(createVaadinRequest(request), createVaadinResponse(response)); + + VaadinServletRequest vaadinRequest = createVaadinRequest(request); + VaadinServletResponse vaadinResponse = createVaadinResponse(response); + if (!ensureCookiesEnabled(vaadinRequest, vaadinResponse)) { + return; + } + + if (isStaticResourceRequest(request)) { + serveStaticResources(request, response); + return; + } + try { + getService().handleRequest(vaadinRequest, vaadinResponse); + } catch (ServiceException e) { + throw new ServletException(e); + } + } /** @@ -239,73 +226,6 @@ public class VaadinServlet extends HttpServlet implements Constants { } } - private void service(VaadinServletRequest request, - VaadinServletResponse response) throws ServletException, - IOException { - getService().requestStart(request, response); - VaadinSession vaadinSession = null; - - try { - AbstractApplicationServletWrapper servletWrapper = new AbstractApplicationServletWrapper( - this); - - RequestType requestType = getRequestType(request); - if (!ensureCookiesEnabled(requestType, request, response)) { - return; - } - - if (requestType == RequestType.STATIC_FILE) { - serveStaticResources(request, response); - return; - } - - try { - // Find out the service session this request is related to - vaadinSession = getService().findVaadinSession(request); - if (vaadinSession == null) { - return; - } - - if (requestType == RequestType.PUBLISHED_FILE) { - new PublishedFileHandler().handleRequest(vaadinSession, - request, response); - return; - } else if (requestType == RequestType.HEARTBEAT) { - new HeartbeatHandler().handleRequest(vaadinSession, - request, response); - return; - } else if (requestType == RequestType.FILE_UPLOAD) { - new FileUploadHandler().handleRequest(vaadinSession, - request, response); - return; - } else if (requestType == RequestType.UIDL) { - new UidlRequestHandler(servletWrapper).handleRequest( - vaadinSession, request, response); - return; - } else if (requestType == RequestType.BROWSER_DETAILS) { - // Browser details - not related to a specific UI - new UIInitHandler().handleRequest(vaadinSession, request, - response); - return; - } else if (new SessionRequestHandler().handleRequest( - vaadinSession, request, response)) { - return; - } - - // Request not handled by any RequestHandler -> 404 - response.sendError(HttpServletResponse.SC_NOT_FOUND); - - } catch (final SessionExpiredException e) { - // Session has expired, notify user - handleServiceSessionExpired(request, response); - } catch (final Throwable e) { - handleServiceException(request, response, vaadinSession, e); - } - } finally { - getService().requestEnd(request, response, vaadinSession); - } - } - private VaadinServletResponse createVaadinResponse( HttpServletResponse response) { return new VaadinServletResponse(response, getService()); @@ -347,10 +267,9 @@ public class VaadinServlet extends HttpServlet implements Constants { * @return false if cookies are disabled, true otherwise * @throws IOException */ - private boolean ensureCookiesEnabled(RequestType requestType, - VaadinServletRequest request, VaadinServletResponse response) - throws IOException { - if (requestType == RequestType.UIDL) { + private boolean ensureCookiesEnabled(VaadinServletRequest request, + VaadinServletResponse response) throws IOException { + if (ServletPortletHelper.isUIDLRequest(request)) { // In all other but the first UIDL request a cookie should be // returned by the browser. // This can be removed if cookieless mode (#3228) is supported @@ -509,44 +428,6 @@ public class VaadinServlet extends HttpServlet implements Constants { return resultPath; } - private void handleServiceException(VaadinServletRequest request, - VaadinServletResponse response, VaadinSession vaadinSession, - Throwable e) throws IOException, ServletException { - if (vaadinSession != null) { - vaadinSession.lock(); - } - try { - ErrorHandler errorHandler = ErrorEvent - .findErrorHandler(vaadinSession); - - // if this was an UIDL request, response UIDL back to client - if (getRequestType(request) == RequestType.UIDL) { - SystemMessages ci = getService().getSystemMessages( - ServletPortletHelper.findLocale(null, vaadinSession, - request), request); - criticalNotification(request, response, - ci.getInternalErrorCaption(), - ci.getInternalErrorMessage(), null, - ci.getInternalErrorURL()); - if (errorHandler != null) { - errorHandler.error(new ErrorEvent(e)); - } - } else { - if (errorHandler != null) { - errorHandler.error(new ErrorEvent(e)); - } - - // Re-throw other exceptions - throw new ServletException(e); - } - } finally { - if (vaadinSession != null) { - vaadinSession.unlock(); - } - } - - } - /** * A helper method to strip away characters that might somehow be used for * XSS attacs. Leaves at least alphanumeric characters intact. Also removes @@ -591,68 +472,6 @@ public class VaadinServlet extends HttpServlet implements Constants { return DEFAULT_THEME_NAME; } - /** - * @param request - * @param response - * @throws IOException - * @throws ServletException - * - * @deprecated As of 7.0. Will likely change or be removed in a future - * version - */ - @Deprecated - void handleServiceSessionExpired(VaadinServletRequest request, - VaadinServletResponse response) throws IOException, - ServletException { - - try { - SystemMessages ci = getService().getSystemMessages( - ServletPortletHelper.findLocale(null, null, request), - request); - RequestType requestType = getRequestType(request); - if (requestType == RequestType.UIDL) { - /* - * Invalidate session (weird to have session if we're saying - * that it's expired, and worse: portal integration will fail - * since the session is not created by the portal. - * - * Session must be invalidated before criticalNotification as it - * commits the response. - */ - request.getSession().invalidate(); - - // send uidl redirect - criticalNotification(request, response, - ci.getSessionExpiredCaption(), - ci.getSessionExpiredMessage(), null, - ci.getSessionExpiredURL()); - - } else if (requestType == RequestType.HEARTBEAT) { - response.sendError(HttpServletResponse.SC_GONE, - "Session expired"); - } else { - // 'plain' http req - e.g. browser reload; - // just go ahead redirect the browser - String sessionExpiredURL = ci.getSessionExpiredURL(); - if (sessionExpiredURL != null) { - response.sendRedirect(sessionExpiredURL); - } else { - /* - * Session expired as a result of a standard http request - * and we have nowhere to redirect. Reloading would likely - * cause an endless loop. This can at least happen if - * refreshing a resource when the session has expired. - */ - response.sendError(HttpServletResponse.SC_GONE, - "Session expired"); - } - } - } catch (SystemMessageException ee) { - throw new ServletException(ee); - } - - } - private void handleServiceSecurityException(VaadinServletRequest request, VaadinServletResponse response) throws IOException, ServletException { @@ -664,14 +483,13 @@ public class VaadinServlet extends HttpServlet implements Constants { */ SystemMessages ci = getService().getSystemMessages( request.getLocale(), request); - RequestType requestType = getRequestType(request); - if (requestType == RequestType.UIDL) { + if (ServletPortletHelper.isUIDLRequest(request)) { // send uidl redirect criticalNotification(request, response, ci.getCommunicationErrorCaption(), ci.getCommunicationErrorMessage(), INVALID_SECURITY_KEY_MSG, ci.getCommunicationErrorURL()); - } else if (requestType == RequestType.HEARTBEAT) { + } else if (ServletPortletHelper.isHeartbeatRequest(request)) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "Forbidden"); } else { @@ -1056,10 +874,12 @@ public class VaadinServlet extends HttpServlet implements Constants { /** * * @author Vaadin Ltd - * @since 7.0.0 + * @since 7.0 * - * @deprecated As of 7.0. Will likely change or be removed in a future - * version + * @deprecated As of 7.0. This is no longer used and only provided for + * backwards compatibility. Each {@link RequestHandler} can + * individually decide whether it wants to handle a request or + * not. */ @Deprecated protected enum RequestType { @@ -1070,8 +890,10 @@ public class VaadinServlet extends HttpServlet implements Constants { * @param request * @return * - * @deprecated As of 7.0. Will likely change or be removed in a future - * version + * @deprecated As of 7.0. This is no longer used and only provided for + * backwards compatibility. Each {@link RequestHandler} can + * individually decide whether it wants to handle a request or + * not. */ @Deprecated protected RequestType getRequestType(VaadinServletRequest request) { @@ -1079,7 +901,7 @@ public class VaadinServlet extends HttpServlet implements Constants { return RequestType.FILE_UPLOAD; } else if (ServletPortletHelper.isPublishedFileRequest(request)) { return RequestType.PUBLISHED_FILE; - } else if (isBrowserDetailsRequest(request)) { + } else if (ServletUIInitHandler.isUIInitRequest(request)) { return RequestType.BROWSER_DETAILS; } else if (ServletPortletHelper.isUIDLRequest(request)) { return RequestType.UIDL; @@ -1094,12 +916,7 @@ public class VaadinServlet extends HttpServlet implements Constants { } - private static boolean isBrowserDetailsRequest(HttpServletRequest request) { - return "POST".equals(request.getMethod()) - && request.getParameter("v-browserDetails") != null; - } - - private boolean isStaticResourceRequest(HttpServletRequest request) { + protected boolean isStaticResourceRequest(HttpServletRequest request) { String pathInfo = request.getPathInfo(); if (pathInfo == null || pathInfo.length() <= 10) { return false; @@ -1235,4 +1052,5 @@ public class VaadinServlet extends HttpServlet implements Constants { private static final Logger getLogger() { return Logger.getLogger(VaadinServlet.class.getName()); } + } diff --git a/server/src/com/vaadin/server/VaadinServletService.java b/server/src/com/vaadin/server/VaadinServletService.java index f453a6b140..a12e2b47e2 100644 --- a/server/src/com/vaadin/server/VaadinServletService.java +++ b/server/src/com/vaadin/server/VaadinServletService.java @@ -17,15 +17,19 @@ package com.vaadin.server; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; +import java.util.List; +import java.util.logging.Logger; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; -import com.vaadin.server.VaadinServlet.RequestType; import com.vaadin.server.communication.ServletBootstrapHandler; +import com.vaadin.server.communication.ServletUIInitHandler; import com.vaadin.ui.UI; public class VaadinServletService extends VaadinService { @@ -47,6 +51,31 @@ public class VaadinServletService extends VaadinService { } } + /* + * (non-Javadoc) + * + * @see + * com.vaadin.server.LegacyCommunicationManager.Callback#criticalNotification + * (com.vaadin.server.VaadinRequest, com.vaadin.server.VaadinResponse, + * java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + @Deprecated + @Override + public void criticalNotification(VaadinRequest request, + VaadinResponse response, String cap, String msg, String details, + String url) throws IOException { + getServlet().criticalNotification((VaadinServletRequest) request, + (VaadinServletResponse) response, cap, msg, details, url); + } + + @Override + protected List<RequestHandler> createRequestHandlers() { + List<RequestHandler> handlers = super.createRequestHandlers(); + handlers.add(0, new ServletBootstrapHandler()); + handlers.add(new ServletUIInitHandler()); + return handlers; + } + /** * Retrieves a reference to the servlet associated with this service. * @@ -135,12 +164,11 @@ public class VaadinServletService extends VaadinService { @Override protected boolean requestCanCreateSession(VaadinRequest request) { - RequestType requestType = getRequestType(request); - if (requestType == RequestType.BROWSER_DETAILS) { + if (ServletUIInitHandler.isUIInitRequest(request)) { // This is the first request if you are embedding by writing the // embedding code yourself return true; - } else if (requestType == RequestType.OTHER) { + } else if (isOtherRequest(request)) { /* * I.e URIs that are not RPC calls or static (theme) files. */ @@ -150,25 +178,15 @@ public class VaadinServletService extends VaadinService { return false; } - /** - * Gets the request type for the request. - * - * @param request - * the request to get a request type for - * @return the request type - * - * @deprecated As of 7.0. Will likely change or be removed in a future - * version - */ - @Deprecated - protected RequestType getRequestType(VaadinRequest request) { - RequestType type = (RequestType) request.getAttribute(RequestType.class - .getName()); - if (type == null) { - type = getServlet().getRequestType((VaadinServletRequest) request); - request.setAttribute(RequestType.class.getName(), type); - } - return type; + private boolean isOtherRequest(VaadinRequest request) { + // TODO This should be refactored in some way. It should not be + // necessary to check all these types. + return (!ServletPortletHelper.isAppRequest(request) + && !ServletUIInitHandler.isUIInitRequest(request) + && !ServletPortletHelper.isFileUploadRequest(request) + && !ServletPortletHelper.isHeartbeatRequest(request) + && !ServletPortletHelper.isPublishedFileRequest(request) && !ServletPortletHelper + .isUIDLRequest(request)); } @Override @@ -235,8 +253,73 @@ public class VaadinServletService extends VaadinService { return appId; } + /* + * (non-Javadoc) + * + * @see + * com.vaadin.server.VaadinService#handleSessionExpired(com.vaadin.server + * .VaadinRequest, com.vaadin.server.VaadinResponse) + */ @Override - protected BootstrapHandler createBootstrapHandler(VaadinSession session) { - return new ServletBootstrapHandler(); + protected void handleSessionExpired(VaadinRequest request, + VaadinResponse response) throws ServiceException { + if (!(request instanceof VaadinServletRequest)) { + throw new ServiceException(new IllegalArgumentException( + "handleSessionExpired called with a non-VaadinServletRequest: " + + request.getClass().getName())); + } + + VaadinServletRequest servletRequest = (VaadinServletRequest) request; + VaadinServletResponse servletResponse = (VaadinServletResponse) response; + + try { + SystemMessages ci = getSystemMessages( + ServletPortletHelper.findLocale(null, null, request), + request); + if (ServletPortletHelper.isUIDLRequest(request)) { + /* + * Invalidate session (weird to have session if we're saying + * that it's expired) + * + * Session must be invalidated before criticalNotification as it + * commits the response. + */ + servletRequest.getSession().invalidate(); + + // send uidl redirect + criticalNotification(request, response, + ci.getSessionExpiredCaption(), + ci.getSessionExpiredMessage(), null, + ci.getSessionExpiredURL()); + + } else if (ServletPortletHelper.isHeartbeatRequest(request)) { + response.sendError(HttpServletResponse.SC_GONE, + "Session expired"); + } else { + // 'plain' http req - e.g. browser reload; + // just go ahead redirect the browser + String sessionExpiredURL = ci.getSessionExpiredURL(); + if (sessionExpiredURL != null) { + servletResponse.sendRedirect(sessionExpiredURL); + } else { + /* + * Session expired as a result of a standard http request + * and we have nowhere to redirect. Reloading would likely + * cause an endless loop. This can at least happen if + * refreshing a resource when the session has expired. + */ + response.sendError(HttpServletResponse.SC_GONE, + "Session expired"); + } + } + } catch (IOException e) { + throw new ServiceException(e); + } + } + + private static final Logger getLogger() { + return Logger.getLogger(VaadinServletService.class.getName()); + } + } diff --git a/server/src/com/vaadin/server/communication/FileUploadHandler.java b/server/src/com/vaadin/server/communication/FileUploadHandler.java index fc3c4b65f8..1f5011a42e 100644 --- a/server/src/com/vaadin/server/communication/FileUploadHandler.java +++ b/server/src/com/vaadin/server/communication/FileUploadHandler.java @@ -217,6 +217,9 @@ public class FileUploadHandler implements RequestHandler { @Override public boolean handleRequest(VaadinSession session, VaadinRequest request, VaadinResponse response) throws IOException { + if (!ServletPortletHelper.isFileUploadRequest(request)) { + return false; + } /* * URI pattern: APP/UPLOAD/[UIID]/[PID]/[NAME]/[SECKEY] See diff --git a/server/src/com/vaadin/server/communication/HeartbeatHandler.java b/server/src/com/vaadin/server/communication/HeartbeatHandler.java index a696ad3919..a547d32b30 100644 --- a/server/src/com/vaadin/server/communication/HeartbeatHandler.java +++ b/server/src/com/vaadin/server/communication/HeartbeatHandler.java @@ -20,10 +20,12 @@ import java.io.IOException; import javax.servlet.http.HttpServletResponse; +import com.vaadin.server.ServletPortletHelper; import com.vaadin.server.SynchronizedRequestHandler; import com.vaadin.server.VaadinRequest; import com.vaadin.server.VaadinResponse; import com.vaadin.server.VaadinSession; +import com.vaadin.shared.ui.ui.UIConstants; import com.vaadin.ui.UI; /** @@ -49,6 +51,10 @@ public class HeartbeatHandler extends SynchronizedRequestHandler { @Override public boolean synchronizedHandleRequest(VaadinSession session, VaadinRequest request, VaadinResponse response) throws IOException { + if (!ServletPortletHelper.isHeartbeatRequest(request)) { + return false; + } + UI ui = session.getService().findUI(request); if (ui != null) { ui.setLastHeartbeatTimestamp(System.currentTimeMillis()); diff --git a/server/src/com/vaadin/server/communication/PortletDummyRequestHandler.java b/server/src/com/vaadin/server/communication/PortletDummyRequestHandler.java new file mode 100644 index 0000000000..8383cf607b --- /dev/null +++ b/server/src/com/vaadin/server/communication/PortletDummyRequestHandler.java @@ -0,0 +1,82 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.server.communication; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; + +import javax.portlet.PortletResponse; +import javax.portlet.ResourceRequest; +import javax.portlet.ResourceResponse; + +import com.vaadin.server.RequestHandler; +import com.vaadin.server.VaadinPortletResponse; +import com.vaadin.server.VaadinRequest; +import com.vaadin.server.VaadinResponse; +import com.vaadin.server.VaadinSession; + +/** + * Request handler which provides a dummy HTML response to any resource request + * with the resource id DUMMY. + * + * @author Vaadin Ltd + * @since 7.1 + */ +public class PortletDummyRequestHandler implements RequestHandler { + + @Override + public boolean handleRequest(VaadinSession session, VaadinRequest request, + VaadinResponse response) throws IOException { + if (!isDummyRequest(request)) { + return false; + } + + /* + * This dummy page is used by action responses to redirect to, in order + * to prevent the boot strap code from being rendered into strange + * places such as iframes. + */ + PortletResponse portletResponse = ((VaadinPortletResponse) response) + .getPortletResponse(); + if (portletResponse instanceof ResourceResponse) { + ((ResourceResponse) portletResponse).setContentType("text/html"); + } + + final OutputStream out = ((ResourceResponse) response) + .getPortletOutputStream(); + final PrintWriter outWriter = new PrintWriter(new BufferedWriter( + new OutputStreamWriter(out, "UTF-8"))); + outWriter.print("<html><body>dummy page</body></html>"); + outWriter.close(); + + return true; + } + + public static boolean isDummyRequest(VaadinRequest request) { + ResourceRequest resourceRequest = PortletUIInitHandler + .getResourceRequest(request); + if (resourceRequest == null) { + return false; + } + + return resourceRequest.getResourceID() != null + && resourceRequest.getResourceID().equals("DUMMY"); + } + +} diff --git a/server/src/com/vaadin/server/communication/PortletUIInitHandler.java b/server/src/com/vaadin/server/communication/PortletUIInitHandler.java new file mode 100644 index 0000000000..d5d1e6b98d --- /dev/null +++ b/server/src/com/vaadin/server/communication/PortletUIInitHandler.java @@ -0,0 +1,63 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.server.communication; + +import javax.portlet.PortletRequest; +import javax.portlet.ResourceRequest; + +import com.vaadin.server.VaadinPortletRequest; +import com.vaadin.server.VaadinRequest; + +public class PortletUIInitHandler extends UIInitHandler { + + @Override + protected boolean isInitRequest(VaadinRequest request) { + return isUIInitRequest(request); + } + + public static boolean isUIInitRequest(VaadinRequest request) { + ResourceRequest resourceRequest = getResourceRequest(request); + if (resourceRequest == null) { + return false; + } + + return UIInitHandler.BROWSER_DETAILS_PARAMETER.equals(resourceRequest + .getResourceID()); + } + + /** + * Returns the {@link ResourceRequest} for the given request or null if none + * could be found. + * + * @param request + * The original request, must be a {@link VaadinPortletRequest} + * @return The resource request from the request parameter or null + */ + static ResourceRequest getResourceRequest(VaadinRequest request) { + if (!(request instanceof VaadinPortletRequest)) { + throw new IllegalArgumentException( + "Request must a VaadinPortletRequest"); + } + PortletRequest portletRequest = ((VaadinPortletRequest) request) + .getPortletRequest(); + if (!(portletRequest instanceof ResourceRequest)) { + return null; + } + + return (ResourceRequest) portletRequest; + + } +} diff --git a/server/src/com/vaadin/server/communication/PublishedFileHandler.java b/server/src/com/vaadin/server/communication/PublishedFileHandler.java index 1cd70bb173..8fe0f7085f 100644 --- a/server/src/com/vaadin/server/communication/PublishedFileHandler.java +++ b/server/src/com/vaadin/server/communication/PublishedFileHandler.java @@ -28,6 +28,7 @@ import com.vaadin.annotations.StyleSheet; import com.vaadin.server.Constants; import com.vaadin.server.LegacyCommunicationManager; import com.vaadin.server.RequestHandler; +import com.vaadin.server.ServletPortletHelper; import com.vaadin.server.VaadinRequest; import com.vaadin.server.VaadinResponse; import com.vaadin.server.VaadinSession; @@ -55,6 +56,9 @@ public class PublishedFileHandler implements RequestHandler { @Override public boolean handleRequest(VaadinSession session, VaadinRequest request, VaadinResponse response) throws IOException { + if (!ServletPortletHelper.isPublishedFileRequest(request)) { + return false; + } String pathInfo = request.getPathInfo(); // + 2 to also remove beginning and ending slashes diff --git a/server/src/com/vaadin/server/communication/ServletUIInitHandler.java b/server/src/com/vaadin/server/communication/ServletUIInitHandler.java new file mode 100644 index 0000000000..6286c161f2 --- /dev/null +++ b/server/src/com/vaadin/server/communication/ServletUIInitHandler.java @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.server.communication; + +import com.vaadin.server.VaadinRequest; + +public class ServletUIInitHandler extends UIInitHandler { + + @Override + protected boolean isInitRequest(VaadinRequest request) { + return isUIInitRequest(request); + } + + public static boolean isUIInitRequest(VaadinRequest request) { + return "POST".equals(request.getMethod()) + && request + .getParameter(UIInitHandler.BROWSER_DETAILS_PARAMETER) != null; + } + +} diff --git a/server/src/com/vaadin/server/communication/SessionRequestHandler.java b/server/src/com/vaadin/server/communication/SessionRequestHandler.java index 244cb0121d..14c940acf5 100644 --- a/server/src/com/vaadin/server/communication/SessionRequestHandler.java +++ b/server/src/com/vaadin/server/communication/SessionRequestHandler.java @@ -22,6 +22,7 @@ import com.vaadin.server.RequestHandler; import com.vaadin.server.VaadinRequest; import com.vaadin.server.VaadinResponse; import com.vaadin.server.VaadinSession; +import com.vaadin.shared.ApplicationConstants; /** * Handles a request by passing it to each registered {@link RequestHandler} in @@ -50,6 +51,13 @@ public class SessionRequestHandler implements RequestHandler { @Override public boolean handleRequest(VaadinSession session, VaadinRequest request, VaadinResponse response) throws IOException { + String pathInfo = request.getPathInfo(); + if (pathInfo.startsWith("/" + ApplicationConstants.APP_PATH + "/")) { + // /<APP_PATH>/ is reserved for Vaadin internal use and these + // requests should not be passed to session request handlers + return false; + } + // Use a copy to avoid ConcurrentModificationException session.lock(); ArrayList<RequestHandler> requestHandlers; diff --git a/server/src/com/vaadin/server/communication/UIInitHandler.java b/server/src/com/vaadin/server/communication/UIInitHandler.java index e4790e95e5..0e18209986 100644 --- a/server/src/com/vaadin/server/communication/UIInitHandler.java +++ b/server/src/com/vaadin/server/communication/UIInitHandler.java @@ -49,11 +49,18 @@ import com.vaadin.ui.UI; * @author Vaadin Ltd * @since 7.1 */ -public class UIInitHandler extends SynchronizedRequestHandler { +public abstract class UIInitHandler extends SynchronizedRequestHandler { + + public static final String BROWSER_DETAILS_PARAMETER = "v-browserDetails"; + + protected abstract boolean isInitRequest(VaadinRequest request); @Override public boolean synchronizedHandleRequest(VaadinSession session, VaadinRequest request, VaadinResponse response) throws IOException { + if (!isInitRequest(request)) { + return false; + } // NOTE! GateIn requires, for some weird reason, getOutputStream // to be used instead of getWriter() (it seems to interpret diff --git a/server/src/com/vaadin/server/communication/UidlRequestHandler.java b/server/src/com/vaadin/server/communication/UidlRequestHandler.java index e55f39246e..e626bbe58d 100644 --- a/server/src/com/vaadin/server/communication/UidlRequestHandler.java +++ b/server/src/com/vaadin/server/communication/UidlRequestHandler.java @@ -32,6 +32,7 @@ import com.vaadin.server.Constants; import com.vaadin.server.LegacyCommunicationManager; import com.vaadin.server.LegacyCommunicationManager.Callback; import com.vaadin.server.LegacyCommunicationManager.InvalidUIDLSecurityKeyException; +import com.vaadin.server.ServletPortletHelper; import com.vaadin.server.SynchronizedRequestHandler; import com.vaadin.server.VaadinRequest; import com.vaadin.server.VaadinResponse; @@ -53,6 +54,8 @@ import com.vaadin.ui.UI; */ public class UidlRequestHandler extends SynchronizedRequestHandler { + public static final String UIDL_PATH = "UIDL/"; + private Callback criticalNotifier; private ServerRpcHandler rpcHandler = new ServerRpcHandler(); @@ -64,7 +67,9 @@ public class UidlRequestHandler extends SynchronizedRequestHandler { @Override public boolean synchronizedHandleRequest(VaadinSession session, VaadinRequest request, VaadinResponse response) throws IOException { - + if (!ServletPortletHelper.isUIDLRequest(request)) { + return false; + } UI uI = session.getService().findUI(request); checkWidgetsetVersion(request); |