All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.almende.eve.transport.http.EveServlet Maven / Gradle / Ivy

There is a newer version: 3.1.1
Show newest version
/*
 * Copyright: Almende B.V. (2014), Rotterdam, The Netherlands
 * License: The Apache Software License, Version 2.0
 */
package com.almende.eve.transport.http;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;

import com.almende.util.ApacheHttpClient;
import com.almende.util.StringUtil;
import com.almende.util.jackson.JOM;
import com.fasterxml.jackson.databind.node.ObjectNode;

/**
 * The Class EveServlet.
 */
public class EveServlet extends HttpServlet {
	private static final long	serialVersionUID	= -4635490705591217600L;

	private static final Logger	LOG					= Logger.getLogger(EveServlet.class
															.getSimpleName());
	protected URI				myUrl				= null;

	/**
	 * Instantiates a new eve servlet.
	 */
	public EveServlet() {}

	/**
	 * Instantiates a new eve servlet.
	 * 
	 * @param servletUrl
	 *            the servlet url
	 */
	public EveServlet(final URI servletUrl) {
		if (servletUrl != null) {
			myUrl = servletUrl;
		}
	}

	/*
	 * (non-Javadoc)
	 * @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig)
	 */
	@Override
	public void init(final ServletConfig config) throws ServletException {
		if (myUrl == null) {
			final String servletUrl = config.getInitParameter("ServletUrl");
			if (servletUrl != null) {
				try {
					myUrl = new URI(servletUrl);
				} catch (final URISyntaxException e) {
					LOG.log(Level.WARNING,
							"Couldn't init servlet, url invalid. ('ServletUrl' init param)",
							e);
				}
			} else {
				LOG.warning("Servlet init parameter 'ServletUrl' is required!");
			}
		}
		super.init(config);
	}

	/**
	 * The Enum Handshake.
	 */
	enum Handshake {

		/** The ok. */
		OK,
		/** The nak. */
		NAK,
		/** The invalid. */
		INVALID
	}

	/**
	 * Handle hand shake.
	 * 
	 * @param req
	 *            the req
	 * @param res
	 *            the res
	 * @return true, if successful
	 * @throws IOException
	 *             Signals that an I/O exception has occurred.
	 */
	protected boolean handleHandShake(final HttpServletRequest req,
			final HttpServletResponse res) throws IOException {

		final String time = req.getHeader("X-Eve-requestToken");
		if (time == null) {
			return false;
		}
		final String url = req.getRequestURI();
		final String id = getId(url);
		final HttpTransport transport = HttpService.get(myUrl, id);
		if (transport != null) {
			final String token = transport.getTokenstore().get(time);
			if (token == null) {
				res.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
			} else {
				res.setHeader("X-Eve-replyToken", token);
				res.setStatus(HttpServletResponse.SC_OK);
				res.flushBuffer();
			}
		} else {
			res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
					"Can't find the correct transport:'" + myUrl + "' for:'"
							+ id + "'");
		}
		return true;
	}

	/**
	 * Do hand shake.
	 * 
	 * @param req
	 *            the req
	 * @return the handshake
	 */
	protected Handshake doHandShake(final HttpServletRequest req) {
		final String tokenTupple = req.getHeader("X-Eve-Token");
		if (tokenTupple == null) {
			// This is a webpage, no HandShake available.
			return Handshake.NAK;
		}

		try {
			final String senderUrl = req.getHeader("X-Eve-SenderUrl");
			if (senderUrl != null && !senderUrl.equals("")) {
				final ObjectNode tokenObj = (ObjectNode) JOM.getInstance()
						.readTree(tokenTupple);
				final HttpGet httpGet = new HttpGet(senderUrl);
				httpGet.setHeader("X-Eve-requestToken", tokenObj.get("time")
						.textValue());
				final HttpResponse response = ApacheHttpClient.get().execute(
						httpGet);
				if (response != null
						&& response.getStatusLine().getStatusCode() == HttpServletResponse.SC_OK) {
					Header replyToken = response
							.getLastHeader("X-Eve-replyToken");
					if (replyToken == null) {
						LOG.log(Level.WARNING,
								"Failed to receive valid handshake, replyToken missing!:"
										+ response);
						return Handshake.INVALID;
					}
					if (tokenObj.get("token").textValue()
							.equals(replyToken.getValue())) {
						return Handshake.OK;
					}
				} else {
					LOG.log(Level.WARNING, "Failed to receive valid handshake:"
							+ response);
				}
			}
		} catch (final Exception e) {
			LOG.log(Level.WARNING, "", e);
		}

		return Handshake.INVALID;
	}

	/**
	 * Handle session.
	 * 
	 * @param req
	 *            the req
	 * @param res
	 *            the res
	 * @return true, if successful
	 * @throws IOException
	 *             Signals that an I/O exception has occurred.
	 */
	protected boolean handleSession(final HttpServletRequest req,
			final HttpServletResponse res) throws IOException {
		try {

			if (req.getSession(false) != null) {
				return true;
			}

			final boolean doAuthentication = HttpService
					.doAuthentication(myUrl);
			if (doAuthentication) {
				final Handshake hs = doHandShake(req);
				if (hs.equals(Handshake.INVALID)) {
					return false;
				}

				if (hs.equals(Handshake.NAK)) {
					if (!req.authenticate(res)) {
						return false;
					}
				}
			}

			// generate new session:
			req.getSession(true);
		} catch (final Exception e) {
			res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
					"Exception running HandleSession:" + e.getMessage());
			LOG.log(Level.WARNING, "", e);
			return false;
		}
		return true;
	}

	protected String getId(final String url) {
		String id = "";
		if (myUrl != null) {
			id = url.replace(myUrl.getRawPath(), "");
		} else {
			// TODO: this doesn't work with resources behind agentId
			id = url.replaceAll(".*/[^/]+", "");
		}
		return id.indexOf('/') > 0 ? id.substring(0, id.indexOf('/')) : id;
	}

	/*
	 * (non-Javadoc)
	 * @see
	 * javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest
	 * , javax.servlet.http.HttpServletResponse)
	 */
	@Override
	public void doPost(final HttpServletRequest req,
			final HttpServletResponse resp) throws IOException,
			ServletException {

		if (!handleSession(req, resp)) {
			if (!resp.isCommitted()) {
				resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
			}
			resp.flushBuffer();
			return;
		}

		// retrieve the url and the request body
		final String body = StringUtil.streamToString(req.getInputStream());
		final String url = req.getRequestURI();
		final String id = getId(url);
		if (id == null || id.equals("") || id.equals(myUrl.toASCIIString())) {
			resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
					"Couldn't parse URL, missing 'id'");
			resp.flushBuffer();
			return;
		}

		String sender = req.getHeader("X-Eve-SenderUrl");
		if (sender == null || sender.equals("")) {
			sender = "web://" + req.getRemoteUser() + "@" + req.getRemoteAddr();
		}
		URI senderUrl = null;
		try {
			senderUrl = new URI(sender);
		} catch (final URISyntaxException e) {
			LOG.log(Level.WARNING, "Couldn't parse senderUrl:" + sender, e);
		}
		final HttpTransport transport = HttpService.get(myUrl, id);
		if (transport != null) {
			try {
				final String response = transport.receive(body, senderUrl);
				// TODO: It doesn't need to be json, should we handle mime-types
				// better?
				resp.addHeader("Content-Type", "application/json");
				resp.getWriter().println(response);
				resp.getWriter().close();
			} catch (final IOException e) {
				resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
						"Receiver raised exception:" + e.getMessage());
			}
		} else {
			resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
					"Couldn't load transport");
		}
		resp.flushBuffer();
	}

	@Override
	protected void doGet(final HttpServletRequest req,
			final HttpServletResponse resp) throws ServletException,
			IOException {

		// If this is a handshake request, handle it.
		if (handleHandShake(req, resp)) {
			return;
		}

		final String url = req.getRequestURI();
		final String id = getId(url);
		if (id == null || id.equals("") || id.equals(myUrl.toASCIIString())) {
			resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
					"Couldn't parse URL, missing 'id'");
			resp.flushBuffer();
			return;
		}
		final HttpTransport transport = HttpService.get(myUrl, id);

		resp.setContentType("text/plain");
		resp.getWriter().println(
				"You've found the servlet for agent:" + id + " ("
						+ (transport == null ? "not " : "") + " configured)");
		resp.getWriter().close();
		resp.flushBuffer();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy