X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Finternal%2Fkernel%2FNodeHttp.java;h=27083aeaba11812fd219ac60ab7e950ee3c01114;hb=871dd95ada4cf946c8d51d3a2546c817238ad08c;hp=5e1f39acb1f7a57d0651a0976a5c0cc786a781a1;hpb=86db10fcb2299ebf71d5599a80dc54444b26f893;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java index 5e1f39acb..27083aeab 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java @@ -1,11 +1,26 @@ package org.argeo.cms.internal.kernel; +import static javax.jcr.Property.JCR_DESCRIPTION; +import static javax.jcr.Property.JCR_LAST_MODIFIED; +import static javax.jcr.Property.JCR_TITLE; +import static org.argeo.cms.CmsTypes.CMS_IMAGE; + import java.io.IOException; +import java.io.PrintWriter; +import java.security.PrivilegedExceptionAction; import java.security.cert.X509Certificate; +import java.util.Calendar; import java.util.Enumeration; +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.security.auth.Subject; import javax.servlet.FilterChain; import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @@ -13,30 +28,37 @@ import javax.servlet.http.HttpSession; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.cms.CmsException; +import org.argeo.cms.util.CmsUtils; import org.argeo.jcr.ArgeoJcrConstants; +import org.argeo.jcr.JcrUtils; import org.eclipse.equinox.http.servlet.ExtendedHttpService; /** * Intercepts and enriches http access, mainly focusing on security and * transactionality. */ -@Deprecated class NodeHttp implements KernelConstants, ArgeoJcrConstants { private final static Log log = LogFactory.getLog(NodeHttp.class); // Filters - private final RootFilter rootFilter; + // private final RootFilter rootFilter; // private final DoSFilter dosFilter; // private final QoSFilter qosFilter; - NodeHttp(ExtendedHttpService httpService) { - rootFilter = new RootFilter(); + private Repository repository; + + NodeHttp(ExtendedHttpService httpService, NodeRepository node) { + this.repository = node; + // rootFilter = new RootFilter(); // dosFilter = new CustomDosFilter(); // qosFilter = new QoSFilter(); try { - httpService.registerFilter("/", rootFilter, null, null); + httpService.registerServlet("/!", new LinkServlet(repository), + null, null); + httpService.registerServlet("/robots.txt", new RobotServlet(), + null, null); } catch (Exception e) { throw new CmsException("Cannot register filters", e); } @@ -45,6 +67,165 @@ class NodeHttp implements KernelConstants, ArgeoJcrConstants { public void destroy() { } + static class LinkServlet extends HttpServlet { + private static final long serialVersionUID = 3749990143146845708L; + private final Repository repository; + + public LinkServlet(Repository repository) { + this.repository = repository; + } + + @Override + protected void service(HttpServletRequest request, + HttpServletResponse response) throws ServletException, + IOException { + String path = request.getPathInfo(); + String userAgent = request.getHeader("User-Agent").toLowerCase(); + boolean isBot = false; + boolean isCompatibleBrowser = false; + if (userAgent.contains("bot") || userAgent.contains("facebook") + || userAgent.contains("twitter")) { + isBot = true; + } else if (userAgent.contains("webkit") + || userAgent.contains("gecko") + || userAgent.contains("firefox") + || userAgent.contains("msie") + || userAgent.contains("chrome") + || userAgent.contains("chromium") + || userAgent.contains("opera") + || userAgent.contains("browser")) { + isCompatibleBrowser = true; + } + + if (isBot) { + log.warn("# BOT " + request.getHeader("User-Agent")); + canonicalAnswer(request, response, path); + return; + } + + if (isCompatibleBrowser && log.isTraceEnabled()) + log.trace("# BWS " + request.getHeader("User-Agent")); + redirectTo(response, "/#" + path); + } + + private void redirectTo(HttpServletResponse response, String location) { + response.setHeader("Location", location); + response.setStatus(HttpServletResponse.SC_FOUND); + } + + // private boolean canonicalAnswerNeededBy(HttpServletRequest request) { + // String userAgent = request.getHeader("User-Agent").toLowerCase(); + // return userAgent.startsWith("facebookexternalhit/"); + // } + + /** For bots which don't understand RWT. */ + private void canonicalAnswer(HttpServletRequest request, + HttpServletResponse response, String path) { + Session session = null; + try { + PrintWriter writer = response.getWriter(); + session = Subject.doAs(KernelUtils.anonymousLogin(), + new PrivilegedExceptionAction() { + + @Override + public Session run() throws Exception { + return repository.login(); + } + + }); + Node node = session.getNode(path); + String title = node.hasProperty(JCR_TITLE) ? node.getProperty( + JCR_TITLE).getString() : node.getName(); + String desc = node.hasProperty(JCR_DESCRIPTION) ? node + .getProperty(JCR_DESCRIPTION).getString() : null; + Calendar lastUpdate = node.hasProperty(JCR_LAST_MODIFIED) ? node + .getProperty(JCR_LAST_MODIFIED).getDate() : null; + String url = CmsUtils.getCanonicalUrl(node, request); + String imgUrl = null; + loop: for (NodeIterator it = node.getNodes(); it.hasNext();) { + // Takes the first found cms:image + Node child = it.nextNode(); + if (child.isNodeType(CMS_IMAGE)){ + imgUrl = CmsUtils.getDataUrl(child, request); + break loop; + } + } + StringBuilder buf = new StringBuilder(); + buf.append(""); + buf.append(""); + writeMeta(buf, "og:title", title); + writeMeta(buf, "og:type", "website"); + buf.append(""); + buf.append(""); + writeMeta(buf, "og:url", url); + if (desc != null) + writeMeta(buf, "og:description", desc); + if (imgUrl != null) + writeMeta(buf, "og:image", imgUrl); + if (lastUpdate != null) + writeMeta(buf, "og:updated_time", + Long.toString(lastUpdate.getTime().getTime())); + buf.append(""); + buf.append(""); + buf.append( + "

!! This page is meant for indexing robots, not for real people," + + " visit ").append(title) + .append(" instead.

"); + writeCanonical(buf, node); + buf.append(""); + buf.append(""); + writer.print(buf.toString()); + + response.setHeader("Content-Type", "text/html"); + writer.flush(); + } catch (Exception e) { + throw new CmsException("Cannot write canonical answer", e); + } finally { + JcrUtils.logoutQuietly(session); + } + } + + private void writeMeta(StringBuilder buf, String tag, String value) { + buf.append(""); + } + + private void writeCanonical(StringBuilder buf, Node node) + throws RepositoryException { + buf.append("
"); + if (node.hasProperty(JCR_TITLE)) + buf.append("

") + .append(node.getProperty(JCR_TITLE).getString()) + .append("

"); + if (node.hasProperty(JCR_DESCRIPTION)) + buf.append("

") + .append(node.getProperty(JCR_DESCRIPTION).getString()) + .append("

"); + NodeIterator children = node.getNodes(); + while (children.hasNext()) { + writeCanonical(buf, children.nextNode()); + } + buf.append("
"); + } + } + + class RobotServlet extends HttpServlet { + private static final long serialVersionUID = 7935661175336419089L; + + @Override + protected void service(HttpServletRequest request, + HttpServletResponse response) throws ServletException, + IOException { + PrintWriter writer = response.getWriter(); + writer.append("User-agent: *\n"); + writer.append("Disallow:\n"); + response.setHeader("Content-Type", "text/plain"); + writer.flush(); + } + + } + /** Intercepts all requests. Authenticates. */ class RootFilter extends HttpFilter {