Search in sources :

Example 6 with RenderContext

use of org.structr.web.common.RenderContext in project structr by structr.

the class HtmlServlet method doGet.

@Override
protected void doGet(final HttpServletRequest request, final HttpServletResponse response) {
    final Authenticator auth = getConfig().getAuthenticator();
    List<Page> pages = null;
    boolean requestUriContainsUuids = false;
    SecurityContext securityContext;
    final App app;
    try {
        assertInitialized();
        final String path = request.getPathInfo() != null ? request.getPathInfo() : "/";
        // check for registration (has its own tx because of write access
        if (checkRegistration(auth, request, response, path)) {
            return;
        }
        // check for registration (has its own tx because of write access
        if (checkResetPassword(auth, request, response, path)) {
            return;
        }
        // isolate request authentication in a transaction
        try (final Tx tx = StructrApp.getInstance().tx()) {
            securityContext = auth.initializeAndExamineRequest(request, response);
            tx.success();
        } catch (AuthenticationException aex) {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            return;
        }
        app = StructrApp.getInstance(securityContext);
        try (final Tx tx = app.tx()) {
            // Ensure access mode is frontend
            securityContext.setAccessMode(AccessMode.Frontend);
            request.setCharacterEncoding("UTF-8");
            // Important: Set character encoding before calling response.getWriter() !!, see Servlet Spec 5.4
            response.setCharacterEncoding("UTF-8");
            boolean dontCache = false;
            logger.debug("Path info {}", path);
            // don't continue on redirects
            if (response.getStatus() == 302) {
                tx.success();
                return;
            }
            final Principal user = securityContext.getUser(false);
            if (user != null) {
                // Don't cache if a user is logged in
                dontCache = true;
            }
            final RenderContext renderContext = RenderContext.getInstance(securityContext, request, response);
            renderContext.setResourceProvider(config.getResourceProvider());
            final EditMode edit = renderContext.getEditMode(user);
            DOMNode rootElement = null;
            AbstractNode dataNode = null;
            final String[] uriParts = PathHelper.getParts(path);
            if ((uriParts == null) || (uriParts.length == 0)) {
                // find a visible page
                rootElement = findIndexPage(securityContext, pages, edit);
                logger.debug("No path supplied, trying to find index page");
            } else {
                if (rootElement == null) {
                    rootElement = findPage(securityContext, pages, path, edit);
                } else {
                    dontCache = true;
                }
            }
            if (rootElement == null) {
                // No page found
                // In case of a file, try to find a file with the query string in the filename
                final String queryString = request.getQueryString();
                // Look for a file, first include the query string
                File file = findFile(securityContext, request, path + (queryString != null ? "?" + queryString : ""));
                // If no file with query string in the file name found, try without query string
                if (file == null) {
                    file = findFile(securityContext, request, path);
                }
                if (file != null) {
                    streamFile(securityContext, file, request, response, edit);
                    tx.success();
                    return;
                }
                if (uriParts != null) {
                    // store remaining path parts in request
                    final Matcher matcher = threadLocalUUIDMatcher.get();
                    for (int i = 0; i < uriParts.length; i++) {
                        request.setAttribute(uriParts[i], i);
                        matcher.reset(uriParts[i]);
                        // set to "true" if part matches UUID pattern
                        requestUriContainsUuids |= matcher.matches();
                    }
                }
                if (!requestUriContainsUuids) {
                    // Try to find a data node by name
                    dataNode = findFirstNodeByName(securityContext, request, path);
                } else {
                    dataNode = findNodeByUuid(securityContext, PathHelper.getName(path));
                }
                // if (dataNode != null && !(dataNode instanceof Linkable)) {
                if (dataNode != null) {
                    // Last path part matches a data node
                    // Remove last path part and try again searching for a page
                    // clear possible entry points
                    request.removeAttribute(POSSIBLE_ENTRY_POINTS_KEY);
                    rootElement = findPage(securityContext, pages, StringUtils.substringBeforeLast(path, PathHelper.PATH_SEP), edit);
                    renderContext.setDetailsDataObject(dataNode);
                    // Start rendering on data node
                    if (rootElement == null && dataNode instanceof DOMNode) {
                        // check visibleForSite here as well
                        if (!(dataNode instanceof Page) || isVisibleForSite(request, (Page) dataNode)) {
                            rootElement = ((DOMNode) dataNode);
                        }
                    }
                }
            }
            // look for pages with HTTP Basic Authentication (must be done as superuser)
            if (rootElement == null) {
                final HttpBasicAuthResult authResult = checkHttpBasicAuth(request, response, path);
                switch(authResult.authState()) {
                    // Element with Basic Auth found and authentication succeeded
                    case Authenticated:
                        final Linkable result = authResult.getRootElement();
                        if (result instanceof Page) {
                            rootElement = (DOMNode) result;
                            securityContext = authResult.getSecurityContext();
                            renderContext.pushSecurityContext(securityContext);
                        } else if (result instanceof File) {
                            streamFile(authResult.getSecurityContext(), (File) result, request, response, EditMode.NONE);
                            tx.success();
                            return;
                        }
                        break;
                    // Page with Basic Auth found but not yet authenticated
                    case MustAuthenticate:
                        final Page errorPage = StructrApp.getInstance().nodeQuery(Page.class).and(StructrApp.key(Page.class, "showOnErrorCodes"), "401", false).getFirst();
                        if (errorPage != null && isVisibleForSite(request, errorPage)) {
                            // set error page
                            rootElement = errorPage;
                            // don't cache the error page
                            dontCache = true;
                        } else {
                            // send error
                            response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
                            tx.success();
                            return;
                        }
                        break;
                    // no Basic Auth for given path, go on
                    case NoBasicAuth:
                        break;
                }
            }
            // Still nothing found, do error handling
            if (rootElement == null) {
                rootElement = notFound(response, securityContext);
            }
            if (rootElement == null) {
                tx.success();
                return;
            }
            // check dont cache flag on page (if root element is a page)
            // but don't modify true to false
            dontCache |= rootElement.dontCache();
            if (EditMode.WIDGET.equals(edit) || dontCache) {
                setNoCacheHeaders(response);
            }
            if (!securityContext.isVisible(rootElement)) {
                rootElement = notFound(response, securityContext);
                if (rootElement == null) {
                    tx.success();
                    return;
                }
            } else {
                if (!EditMode.WIDGET.equals(edit) && !dontCache && notModifiedSince(request, response, rootElement, dontCache)) {
                    ServletOutputStream out = response.getOutputStream();
                    out.flush();
                    // response.flushBuffer();
                    out.close();
                } else {
                    // prepare response
                    response.setCharacterEncoding("UTF-8");
                    String contentType = rootElement.getProperty(StructrApp.key(Page.class, "contentType"));
                    if (contentType == null) {
                        // Default
                        contentType = "text/html;charset=UTF-8";
                    }
                    if (contentType.equals("text/html")) {
                        contentType = contentType.concat(";charset=UTF-8");
                    }
                    response.setContentType(contentType);
                    setCustomResponseHeaders(response);
                    final boolean createsRawData = rootElement.getProperty(StructrApp.key(Page.class, "pageCreatesRawData"));
                    // async or not?
                    if (isAsync && !createsRawData) {
                        final AsyncContext async = request.startAsync();
                        final ServletOutputStream out = async.getResponse().getOutputStream();
                        final AtomicBoolean finished = new AtomicBoolean(false);
                        final DOMNode rootNode = rootElement;
                        threadPool.submit(new Runnable() {

                            @Override
                            public void run() {
                                try (final Tx tx = app.tx()) {
                                    // render
                                    rootNode.render(renderContext, 0);
                                    finished.set(true);
                                    tx.success();
                                } catch (Throwable t) {
                                    t.printStackTrace();
                                    logger.warn("Error while rendering page {}: {}", rootNode.getName(), t.getMessage());
                                    try {
                                        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                                        finished.set(true);
                                    } catch (IOException ex) {
                                        logger.warn("", ex);
                                    }
                                }
                            }
                        });
                        // start output write listener
                        out.setWriteListener(new WriteListener() {

                            @Override
                            public void onWritePossible() throws IOException {
                                try {
                                    final Queue<String> queue = renderContext.getBuffer().getQueue();
                                    while (out.isReady()) {
                                        String buffer = null;
                                        synchronized (queue) {
                                            buffer = queue.poll();
                                        }
                                        if (buffer != null) {
                                            out.print(buffer);
                                        } else {
                                            if (finished.get()) {
                                                async.complete();
                                                // prevent this block from being called again
                                                break;
                                            }
                                            Thread.sleep(1);
                                        }
                                    }
                                } catch (Throwable t) {
                                    logger.warn("", t);
                                }
                            }

                            @Override
                            public void onError(Throwable t) {
                                logger.warn("", t);
                            }
                        });
                    } else {
                        final StringRenderBuffer buffer = new StringRenderBuffer();
                        renderContext.setBuffer(buffer);
                        // render
                        rootElement.render(renderContext, 0);
                        try {
                            response.getOutputStream().write(buffer.getBuffer().toString().getBytes("utf-8"));
                            response.getOutputStream().flush();
                            response.getOutputStream().close();
                        } catch (IOException ioex) {
                            logger.warn("", ioex);
                        }
                    }
                }
            }
            tx.success();
        } catch (FrameworkException fex) {
            logger.error("Exception while processing request: {}", fex.getMessage());
        }
    } catch (FrameworkException fex) {
        logger.error("Exception while processing request: {}", fex.getMessage());
        UiAuthenticator.writeFrameworkException(response, fex);
    } catch (IOException ioex) {
        logger.error("Exception while processing request: {}", ioex.getMessage());
        UiAuthenticator.writeInternalServerError(response);
    }
}
Also used : App(org.structr.core.app.App) StructrApp(org.structr.core.app.StructrApp) StringRenderBuffer(org.structr.web.common.StringRenderBuffer) AuthenticationException(org.structr.core.auth.exception.AuthenticationException) AbstractNode(org.structr.core.entity.AbstractNode) Matcher(java.util.regex.Matcher) ThreadLocalMatcher(org.structr.common.ThreadLocalMatcher) ServletOutputStream(javax.servlet.ServletOutputStream) Page(org.structr.web.entity.dom.Page) AsyncContext(javax.servlet.AsyncContext) DOMNode(org.structr.web.entity.dom.DOMNode) WriteListener(javax.servlet.WriteListener) Queue(java.util.Queue) UiAuthenticator(org.structr.web.auth.UiAuthenticator) Authenticator(org.structr.core.auth.Authenticator) RenderContext(org.structr.web.common.RenderContext) Tx(org.structr.core.graph.Tx) FrameworkException(org.structr.common.error.FrameworkException) IOException(java.io.IOException) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) SecurityContext(org.structr.common.SecurityContext) EditMode(org.structr.web.common.RenderContext.EditMode) Linkable(org.structr.web.entity.Linkable) AbstractFile(org.structr.web.entity.AbstractFile) File(org.structr.web.entity.File) Principal(org.structr.core.entity.Principal)

Example 7 with RenderContext

use of org.structr.web.common.RenderContext in project structr by structr.

the class Page method getContent.

static String getContent(final Page page, final RenderContext.EditMode editMode) throws FrameworkException {
    final RenderContext ctx = new RenderContext(page.getSecurityContext(), null, null, editMode);
    final StringRenderBuffer buffer = new StringRenderBuffer();
    ctx.setBuffer(buffer);
    page.render(ctx, 0);
    // extract source
    return buffer.getBuffer().toString();
}
Also used : RenderContext(org.structr.web.common.RenderContext) StringRenderBuffer(org.structr.web.common.StringRenderBuffer)

Example 8 with RenderContext

use of org.structr.web.common.RenderContext in project structr by structr.

the class IncludeFunction method apply.

@Override
public Object apply(final ActionContext ctx, final Object caller, final Object[] sources) throws FrameworkException {
    try {
        if (!(arrayHasMinLengthAndAllElementsNotNull(sources, 1) && sources[0] instanceof String)) {
            return null;
        }
        final PropertyKey<DOMNode> sharedCompKey = StructrApp.key(DOMNode.class, "sharedComponent");
        final SecurityContext securityContext = ctx.getSecurityContext();
        final App app = StructrApp.getInstance(securityContext);
        final RenderContext innerCtx = new RenderContext((RenderContext) ctx);
        final List<DOMNode> nodeList = app.nodeQuery(DOMNode.class).andName((String) sources[0]).getAsList();
        DOMNode node = null;
        /**
         * Nodes can be included via their name property These nodes MUST: 1. be unique in name 2. NOT be in the trash => have an ownerDocument AND a parent (public
         * users are not allowed to see the __ShadowDocument__ ==> this check must either be made in a superuser-context OR the __ShadowDocument could be made public?)
         *
         * These nodes can be: 1. somewhere in the pages tree 2. in the shared components 3. both ==> causes a problem because we now have multiple nodes with the same
         * name (one shared component and multiple linking instances of that component)
         *
         * INFOS:
         *
         * - If a DOMNode has "syncedNodes" it MUST BE a shared component - If a DOMNodes "sharedComponent" is set it MUST BE AN INSTANCE of a shared component => Can
         * we safely ignore these? I THINK SO!
         */
        for (final DOMNode n : nodeList) {
            if (n.inTrash()) {
                continue;
            }
            // IGNORE everything that REFERENCES a shared component!
            if (n.getProperty(sharedCompKey) == null) {
                // the DOMNode is either a shared component OR a named node in the pages tree
                if (node == null) {
                    node = n;
                } else {
                    // TODO: Do we need to remove the nodes from the nodeList which can be ignored? (references to a shared component)
                    return "Ambiguous node name \"" + ((String) sources[0]) + "\" (nodes found: " + StringUtils.join(nodeList, ", ") + ")";
                }
            }
        }
        if (node != null) {
            if (sources.length == 3 && sources[1] instanceof Iterable && sources[2] instanceof String) {
                final Iterable<GraphObject> iterable = FunctionDataSource.map((Iterable) sources[1]);
                final String dataKey = (String) sources[2];
                innerCtx.setListSource(iterable);
                node.renderNodeList(securityContext, innerCtx, 0, dataKey);
            } else {
                node.render(innerCtx, 0);
            }
            if (innerCtx.appLibRendered()) {
                ((RenderContext) ctx).setAppLibRendered(true);
            }
        } else {
            final File file = app.nodeQuery(File.class).andName((String) sources[0]).getFirst();
            if (file != null) {
                final String name = file.getProperty(NodeInterface.name);
                final String contentType = file.getContentType();
                final String charset = StringUtils.substringAfterLast(contentType, "charset=");
                final String extension = StringUtils.substringAfterLast(name, ".");
                if (contentType == null || StringUtils.isBlank(extension)) {
                    logger.warn("No valid file type detected. Please make sure {} has a valid content type set or file extension. Parameters: {}", new Object[] { name, getParametersAsString(sources) });
                    return "No valid file type detected. Please make sure " + name + " has a valid content type set or file extension.";
                }
                if (contentType.startsWith("text/css")) {
                    return "<link href=\"" + file.getPath() + "\" rel=\"stylesheet\">";
                } else if (contentType.contains("/javascript")) {
                    return "<script src=\"" + file.getPath() + "\"></script>";
                } else if (contentType.startsWith("image/svg")) {
                    try (final InputStream is = file.getInputStream()) {
                        final byte[] buffer = new byte[file.getSize().intValue()];
                        IOUtils.read(is, buffer);
                        return StringUtils.toEncodedString(buffer, Charset.forName(charset));
                    } catch (IOException ex) {
                        logger.warn("Exception for parameters: {}", getParametersAsString(sources));
                        logger.error("", ex);
                    }
                    return "<img alt=\"" + name + "\" src=\"" + file.getPath() + "\">";
                } else if (contentType.startsWith("image/")) {
                    return "<img alt=\"" + name + "\" src=\"" + file.getPath() + "\">";
                } else {
                    logger.warn("Don't know how to render content type or extension of {}. Parameters: {}", new Object[] { name, getParametersAsString(sources) });
                    return "Don't know how to render content type or extension of  " + name + ".";
                }
            }
        }
        return StringUtils.join(innerCtx.getBuffer().getQueue(), "");
    } catch (final IllegalArgumentException e) {
        logParameterError(caller, sources, ctx.isJavaScriptContext());
        return usage(ctx.isJavaScriptContext());
    }
}
Also used : StructrApp(org.structr.core.app.StructrApp) App(org.structr.core.app.App) RenderContext(org.structr.web.common.RenderContext) InputStream(java.io.InputStream) IOException(java.io.IOException) GraphObject(org.structr.core.GraphObject) SecurityContext(org.structr.common.SecurityContext) GraphObject(org.structr.core.GraphObject) DOMNode(org.structr.web.entity.dom.DOMNode) File(org.structr.web.entity.File)

Example 9 with RenderContext

use of org.structr.web.common.RenderContext in project structr by structr.

the class UiScriptingTest method testScripting.

@Test
public void testScripting() {
    NodeInterface detailsDataObject = null;
    Page page = null;
    DOMNode html = null;
    DOMNode head = null;
    DOMNode body = null;
    DOMNode title = null;
    DOMNode div = null;
    DOMNode p = null;
    DOMNode text = null;
    try (final Tx tx = app.tx()) {
        detailsDataObject = app.create(TestOne.class, "TestOne");
        page = Page.createNewPage(securityContext, "testpage");
        page.setProperties(page.getSecurityContext(), new PropertyMap(Page.visibleToPublicUsers, true));
        assertTrue(page != null);
        assertTrue(page instanceof Page);
        html = (DOMNode) page.createElement("html");
        head = (DOMNode) page.createElement("head");
        body = (DOMNode) page.createElement("body");
        title = (DOMNode) page.createElement("title");
        div = (DOMNode) page.createElement("div");
        p = (DOMNode) page.createElement("p");
        text = (DOMNode) page.createTextNode("x");
        // add HTML element to page
        page.appendChild(html);
        // add HEAD and BODY elements to HTML
        html.appendChild(head);
        html.appendChild(body);
        // add TITLE element to HEAD
        head.appendChild(title);
        body.appendChild(div);
        div.appendChild(p);
        final PropertyMap changedProperties = new PropertyMap();
        changedProperties.put(StructrApp.key(DOMElement.class, "restQuery"), "/divs");
        changedProperties.put(StructrApp.key(DOMElement.class, "dataKey"), "div");
        p.setProperties(p.getSecurityContext(), changedProperties);
        p.appendChild(text);
        tx.success();
    } catch (FrameworkException fex) {
        fail("Unexpected exception");
    }
    try (final Tx tx = app.tx()) {
        final RenderContext ctx = new RenderContext(securityContext, new RequestMockUp(), new ResponseMockUp(), RenderContext.EditMode.NONE);
        ctx.setDetailsDataObject(detailsDataObject);
        ctx.setPage(page);
        test(p, text, "${{ return Structr.get('div').id}}", "<p>" + div.getUuid() + "</p>", ctx);
        test(p, text, "${{ return Structr.get('page').id}}", "<p>" + page.getUuid() + "</p>", ctx);
        test(p, text, "${{ return Structr.get('parent').id}}", "<p>" + p.getUuid() + "</p>", ctx);
        tx.success();
    } catch (FrameworkException fex) {
        logger.warn("", fex);
        fail("Unexpected exception.");
    }
}
Also used : RenderContext(org.structr.web.common.RenderContext) PropertyMap(org.structr.core.property.PropertyMap) Tx(org.structr.core.graph.Tx) FrameworkException(org.structr.common.error.FrameworkException) Page(org.structr.web.entity.dom.Page) TestOne(org.structr.web.entity.TestOne) DOMNode(org.structr.web.entity.dom.DOMNode) DOMElement(org.structr.web.entity.dom.DOMElement) NodeInterface(org.structr.core.graph.NodeInterface) Test(org.junit.Test) StructrUiTest(org.structr.web.StructrUiTest)

Example 10 with RenderContext

use of org.structr.web.common.RenderContext in project structr by structr.

the class UiScriptingTest method testDoPrivileged.

@Test
public void testDoPrivileged() {
    User tester = null;
    try (final Tx tx = app.tx()) {
        // create admin user
        createTestNode(User.class, new NodeAttribute<>(StructrApp.key(User.class, "name"), "admin"), new NodeAttribute<>(StructrApp.key(User.class, "password"), "admin"), new NodeAttribute<>(StructrApp.key(User.class, "isAdmin"), true));
        // create test user
        tester = createTestNode(User.class, new NodeAttribute<>(StructrApp.key(User.class, "name"), "tester"), new NodeAttribute<>(StructrApp.key(User.class, "password"), "test"));
        tx.success();
    } catch (FrameworkException fex) {
        fex.printStackTrace();
        fail("Unexpected exception.");
    }
    final String script1 = "${{ return Structr.find('User', 'name', 'admin'); }}\n";
    final String script2 = "${{ return Structr.doPrivileged(function() { return Structr.find('User', 'name', 'admin'); }); }}\n";
    final SecurityContext userContext = SecurityContext.getInstance(tester, AccessMode.Backend);
    final App app = StructrApp.getInstance(userContext);
    final RenderContext renderContext = new RenderContext(userContext, new RequestMockUp(), new ResponseMockUp(), RenderContext.EditMode.NONE);
    try (final Tx tx = app.tx()) {
        // unprivileged call
        final Object result = Scripting.evaluate(renderContext, null, script1, "test");
        assertEquals("Result is of invalid type", ArrayList.class, result.getClass());
        assertEquals("Script in user context should not see admin", 0, ((List) result).size());
        tx.success();
    } catch (FrameworkException fex) {
        fex.printStackTrace();
        fail("Unexpected exception.");
    }
    try (final Tx tx = app.tx()) {
        // doPrivileged call
        final Object result = Scripting.evaluate(renderContext, null, script2, "test");
        assertEquals("Result is of invalid type", ArrayList.class, result.getClass());
        assertEquals("Privileged script should not see admin", 1, ((List) result).size());
        tx.success();
    } catch (FrameworkException fex) {
        fex.printStackTrace();
        fail("Unexpected exception.");
    }
}
Also used : App(org.structr.core.app.App) StructrApp(org.structr.core.app.StructrApp) NodeAttribute(org.structr.core.graph.NodeAttribute) RenderContext(org.structr.web.common.RenderContext) User(org.structr.web.entity.User) Tx(org.structr.core.graph.Tx) FrameworkException(org.structr.common.error.FrameworkException) SecurityContext(org.structr.common.SecurityContext) Test(org.junit.Test) StructrUiTest(org.structr.web.StructrUiTest)

Aggregations

RenderContext (org.structr.web.common.RenderContext)15 FrameworkException (org.structr.common.error.FrameworkException)12 Tx (org.structr.core.graph.Tx)11 Test (org.junit.Test)9 StructrUiTest (org.structr.web.StructrUiTest)9 SecurityContext (org.structr.common.SecurityContext)5 NodeAttribute (org.structr.core.graph.NodeAttribute)5 NodeInterface (org.structr.core.graph.NodeInterface)5 DOMNode (org.structr.web.entity.dom.DOMNode)5 Page (org.structr.web.entity.dom.Page)5 App (org.structr.core.app.App)4 StructrApp (org.structr.core.app.StructrApp)4 LinkedList (java.util.LinkedList)3 AbstractNode (org.structr.core.entity.AbstractNode)3 Principal (org.structr.core.entity.Principal)3 PropertyKey (org.structr.core.property.PropertyKey)3 PropertyMap (org.structr.core.property.PropertyMap)3 StringProperty (org.structr.core.property.StringProperty)3 StringRenderBuffer (org.structr.web.common.StringRenderBuffer)3 File (org.structr.web.entity.File)3