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

de.mklinger.qetcher.liferay.client.impl.htmlinliner.ResourceLoaderImpl Maven / Gradle / Ivy

The newest version!
package de.mklinger.qetcher.liferay.client.impl.htmlinliner;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.util.Base64;
import java.util.Optional;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.WriterOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.mklinger.qetcher.client.QetcherClientException;
import de.mklinger.qetcher.client.model.v1.MediaType;
import de.mklinger.qetcher.liferay.client.impl.abstraction.liferay71.LiferayAbstractionFactory;

/**
 * @author Marc Klinger - mklinger[at]mklinger[dot]de
 */
public class ResourceLoaderImpl implements ResourceLoader {
	private static final Logger LOG = LoggerFactory.getLogger(ResourceLoaderImpl.class);

	private static final Charset UTF_8 = Charset.forName("UTF-8");

	@Override
	public Optional getContents(final URI url, final URI referrer) {
		LOG.info("Fetching {} for inline contents", url);
		try {
			final URLConnection connection = get(url, referrer);

			final Charset charset = getCharset(connection);
			final StringWriter sw = new StringWriter();
			final WriterOutputStream wout = new WriterOutputStream(sw, charset);
			try (InputStream in = connection.getInputStream()) {
				IOUtils.copy(in, wout);
			}
			wout.flush();
			final String contents = sw.toString();
			return Optional.of(contents);
		} catch (final Exception e) {
			// no stack trace here.
			LOG.info("Error getting contents for inlining: {}", url);
			LOG.debug("Error getting contents for inlining had exception:", e);
			return Optional.empty();
		}
	}

	@Override
	public Optional getExternalInlineImgSrc(final URI url, final URI referrer) {
		LOG.info("Fetching {} for inline image", url);
		try {
			final URLConnection connection = get(url, referrer);
			final String contentType = getImageContentType(connection);
			try (InputStream in = connection.getInputStream()) {
				return Optional.of(getInlineImgSrc(contentType, in));
			}
		} catch (final Exception e) {
			// no stack trace here.
			LOG.info("Error getting contents for inlining: {}", url);
			LOG.debug("Error getting contents for inlining had exception:", e);
			return Optional.empty();
		}
	}

	@Override
	public String getInlineImgSrc(final String contentType, final InputStream in) throws IOException {
		final byte[] data = IOUtils.toByteArray(in);
		final String base64Data = Base64.getEncoder().encodeToString(data);

		final StringBuilder sb = new StringBuilder(base64Data.length() + "data:".length() + contentType.length() + ";base64,".length());
		sb.append("data:");
		sb.append(contentType);
		sb.append(";base64,");
		sb.append(base64Data);

		return sb.toString();
	}

	private URLConnection get(final URI uri, final URI referrer) throws IOException {
		final URLConnection connection = uri.toURL().openConnection();
		if (isSameHost(uri, referrer)) {
			LOG.debug("Using cookies for url {}", uri);
			setCookies(connection);
		}

		connection.connect();

		if (connection instanceof HttpURLConnection) {
			final int statusCode = ((HttpURLConnection)connection).getResponseCode();
			if (statusCode != 200) {
				throw new QetcherClientException("Non 200 status code (" + statusCode + ") for content: " + uri);
			}
		}
		return connection;
	}

	private boolean isSameHost(final URI uri1, final URI uri2) {
		return
				uri1.getScheme() != null && uri1.getScheme().equals(uri2.getScheme()) &&
				uri1.getHost() != null && uri1.getHost().equals(uri2.getHost()) &&
				uri1.getPort() == uri2.getPort();
	}

	private void setCookies(final URLConnection connection) {
		final HttpServletRequest request = LiferayAbstractionFactory.getInstance().getPortalTool().getHttpServletRequest();
		if (request == null) {
			LOG.debug("No request available");
			return;
		}
		final Cookie[] cookies = request.getCookies();
		if (cookies == null || cookies.length == 0) {
			LOG.debug("No cookies");
			return;
		}
		for (final Cookie cookie : cookies) {
			// XXX escape cookie name/value ??
			// Cookie names and values seem not to be escapable. Only certain
			// characters are allowed for name and for value.
			// For value see https://tools.ietf.org/html/rfc6265.html.
			// Should we validate here and ignore invalid cookies?
			connection.addRequestProperty("Cookie", cookie.getName() + "=" + cookie.getValue());
		}
	}

	private Charset getCharset(final URLConnection connection) {
		final String contentType = connection.getContentType();
		if (contentType != null && !contentType.isEmpty()) {
			final MediaType mediaType = MediaType.valueOf(contentType);
			final Optional responseCharset = mediaType.getParameter("charset");
			if (responseCharset.isPresent()) {
				try {
					final Charset charset = Charset.forName(responseCharset.get());
					LOG.debug("Using response charset: {}", charset);
					return charset;
				} catch (final Exception e) {
					// ignore
				}
			}
		}
		return UTF_8;
	}

	private String getImageContentType(final URLConnection connection) {
		final String contentType = connection.getContentType();
		if (contentType == null) {
			throw new QetcherClientException("No content type available for inline image");
		}
		final MediaType mediaType = MediaType.valueOf(contentType);
		if (!"image".equals(mediaType.getType())) {
			throw new QetcherClientException("Unsupported content type for inline image: '" + contentType + "'");
		}
		return mediaType.getFullType();
	}

	@Override
	public void close() {
		// Do nothing
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy