view src/nabble/view/web/template/NamlServlet.java @ 0:7ecd1a4ef557

add content
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 21 Mar 2019 19:15:52 -0600
parents
children
line wrap: on
line source

package nabble.view.web.template;

import fschmidt.util.servlet.AuthorizingServlet;
import fschmidt.util.servlet.CanonicalUrl;
import fschmidt.util.servlet.JtpContext;
import fschmidt.util.servlet.ServletUtils;
import nabble.model.Site;
import nabble.model.User;
import nabble.modules.ModuleManager;
import nabble.naml.compiler.Command;
import nabble.naml.compiler.CompileException;
import nabble.naml.compiler.IPrintWriter;
import nabble.naml.compiler.Interpreter;
import nabble.naml.compiler.Namespace;
import nabble.naml.compiler.Template;
import nabble.naml.compiler.TemplateRuntimeException;
import nabble.naml.namespaces.BasicNamespace;
import nabble.view.lib.Jtp;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;


public final class NamlServlet extends HttpServlet implements CanonicalUrl, AuthorizingServlet {

	private static String runTemplate(HttpServletRequest request,String templateName)
		throws ServletException
	{
		Site site = Jtp.getSite(request);
		if( site == null )
			return null;
		Template template = site.getTemplate( templateName ,
			BasicNamespace.class, NabbleNamespace.class, RequestNamespace.class
		);
		if( template == null )
			return null;
		StringWriter sw = new StringWriter();
		try {
			ModuleManager.run( template, sw, Collections.<String,Object>emptyMap(),
				new BasicNamespace(template), new NabbleNamespace(site), new RequestNamespace(request)
			);
		} catch(IOException e) {
			throw new RuntimeException(e);
		} catch(TemplateRuntimeException e) {
			checkTweaked(request,site,e);
			throw e;
		}
		return sw.toString();
	}

	public String getCanonicalUrl(HttpServletRequest request) {
		if( request.getParameterMap().isEmpty() )
			return Jtp.homePage();
		try {
			String macroName = request.getParameter("macro");
			String path = runTemplate(request,macroName+" canonical path");
			if( path == null )
				return null;
			path = path.trim();
			if( path.length() > 0 )
				return Jtp.getBaseUrl(request)+path;
		} catch(ServletException e) {
			return null;
		}
/* why bother? - fschmidt
		Site site = Jtp.getSite(request);
		StringBuilder url = new StringBuilder();
		url.append( site.getBaseUrl() ).append( request.getServletPath() );
		String pathInfo = request.getPathInfo();
		if( pathInfo != null )
			url.append( pathInfo );
		String query = request.getQueryString();
		if( query != null )
			url.append( '?' ).append( query );
		return url.toString();
*/
		return null;
	}

	public String getAuthorizationKey(HttpServletRequest request) throws ServletException {
		String s = runTemplate(request,"get read authorization key");
		if( s == null )
			return null;
		s = s.trim();
		return s.length() > 0 ? s : null;
	}

	@Namespace (
		name = "read_authorization",
		global = true
	)
	public static final class ReadAuthorization {
		private final String key;

		private ReadAuthorization(String key) {
			this.key = key;
		}

		@Command public void authorization_key(IPrintWriter out,Interpreter interp) {
			out.print(key);
		}
	}

	public boolean authorize(String key,HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
		Site site = Jtp.getSiteNotNull(request);
		Template template = site.getTemplate( "authorize for read" ,
			BasicNamespace.class, NabbleNamespace.class, ServletNamespace.class, ReadAuthorization.class
		);
		StringWriter sw = new StringWriter();
		ModuleManager.run( template, sw, Collections.<String,Object>emptyMap(),
			new BasicNamespace(template), new NabbleNamespace(site), new ServletNamespace(request,response), new ReadAuthorization(key)
		);
		String s = sw.toString();
		return s.trim().equals("true");
	}

	protected void service(HttpServletRequest request,HttpServletResponse response)
		throws ServletException, IOException
	{
		Site site = Jtp.getSite(request);
		if( site == null ) {
			response.sendError(HttpServletResponse.SC_NOT_FOUND, "Site Not Found");
			return;
		}
		try {
			service(site,request,response);
		} catch(TemplateRuntimeException e) {
			Throwable cause = e.getCause();
			if( cause instanceof CompileException ) {
				CompileException ce = (CompileException)cause;
				if( site.setTweakException(ce) ) {
					service(site,request,response);
					return;
				}
			}
			checkTweaked(request,site,e);
			throw e;
		}
	}

	private void service(Site site,HttpServletRequest request,HttpServletResponse response)
		throws ServletException, IOException
	{
		String macroName = request.getParameter("macro");
		if( macroName == null )
			throw Jtp.servletException(request,"macroName is null");
		Template template = site.getTemplate(macroName,
			BasicNamespace.class, NabbleNamespace.class, ServletNamespace.class
		);
		if( template == null )
			throw Jtp.servletException(request,"macro not found: "+macroName);
		response.setHeader("X-XSS-Protection","0");
		BasicNamespace basicNs = new BasicNamespace(template);
		NabbleNamespace nabbleNs = new NabbleNamespace(site);
		ServletNamespace servletNs = new ServletNamespace(request, response);
		StringWriter sw = new StringWriter();
		PrintWriter out = new PrintWriter(sw);
		ModuleManager.run( template, out, Collections.<String,Object>emptyMap(),
			basicNs, nabbleNs, servletNs
		);
		out.flush();
		if( servletNs.cacheEvents != null ) {
			JtpContext jtpContext = (JtpContext)getServletContext().getAttribute(JtpContext.attrName);
			jtpContext.setEtag(request,response, servletNs.cacheEvents.toArray(new String[servletNs.cacheEvents.size()]) );
		}
		response.getWriter().print(sw.toString());
	}

	private static void checkTweaked(HttpServletRequest request,Site site,TemplateRuntimeException e)
		throws ServletException
	{
		if( !site.getCustomTweaks().isEmpty() ) {
			NamlLogger logger = NamlLogger.getLogger(site);
			DateFormat dateFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			logger.log( dateFmt.format(new Date()) + "  " + ServletUtils.getCurrentURL(request) + "  referer=" + request.getHeader("referer"));
			logger.log("IP = "+Jtp.getClientIpAddr(request));
			User user = Jtp.getUser(request);
			if( user != null )
				logger.log("user = "+user.getId());
			logger.log(e.toString());
			logger.log("");
			throw new ServletException("NAML exception in customized site: "+e.getMessage(),e);
		}
	}

}