org.nuxeo.ecm.platform.web.common.ajax.AjaxProxyServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.nuxeo.ecm.platform.web.common.ajax.AjaxProxyServlet.java

Source

/*
 * (C) Copyright 2006-2009 Nuxeo SA (http://nuxeo.com/) and others.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Contributors:
 *     Nuxeo - initial API and implementation
 *
 * $Id$
 */

package org.nuxeo.ecm.platform.web.common.ajax;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;

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

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuxeo.ecm.platform.ui.web.cache.SimpleCacheFilter;
import org.nuxeo.ecm.platform.web.common.ajax.service.AjaxProxyComponent;
import org.nuxeo.ecm.platform.web.common.ajax.service.AjaxProxyService;
import org.nuxeo.ecm.platform.web.common.ajax.service.ProxyURLConfigEntry;
import org.nuxeo.ecm.platform.web.common.requestcontroller.service.LRUCachingMap;
import org.nuxeo.runtime.api.Framework;

/**
 * Simple proxy servlets.
 * <p>
 * Used for Ajax requests that needs to be proxied to avoid XSiteScripting issues.
 * <p>
 * In order to avoid "open proxiying", only urls configured in the {@link AjaxProxyComponent} via the extension point
 * "proxyableURL" can be proxied.
 *
 * @author tiry
 */
public class AjaxProxyServlet extends HttpServlet {

    public static final String X_METHOD_HEADER = "X-Requested-Method";

    protected static AjaxProxyService service;

    protected static Map<String, String> requestsCache = new LRUCachingMap<String, String>(250);

    protected static final ReentrantReadWriteLock cacheLock = new ReentrantReadWriteLock();

    private static final long serialVersionUID = 1L;

    private static final Log log = LogFactory.getLog(AjaxProxyServlet.class);

    protected static AjaxProxyService getService() {
        if (service == null) {
            service = Framework.getLocalService(AjaxProxyService.class);
        }
        return service;
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        handleProxy(req.getMethod(), req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        handleProxy(req.getHeader(X_METHOD_HEADER), req, resp);
    }

    @Override
    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        handleProxy(req.getMethod(), req, resp);
    }

    protected static void handleProxy(String method, HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        // fetch parameters
        String requestType = req.getParameter("type");
        if (requestType == null) {
            requestType = "text";
        }
        String targetURL = req.getParameter("url");
        if (targetURL == null) {
            return;
        }
        String cache = req.getParameter("cache");

        ProxyURLConfigEntry entry = getService().getConfigForURL(targetURL);
        if (entry == null || !entry.isGranted()) {
            resp.sendError(HttpServletResponse.SC_FORBIDDEN);
            log.warn("client requested proxying for unauthorized url " + targetURL);
            return;
        }

        String body = null;
        String cacheKey = targetURL;

        if (entry.useCache()) {
            if (entry.useCache()) {
                cacheKey += getSessionId(req);
            }
            try {
                cacheLock.readLock().lock();
                body = requestsCache.get(cacheKey);
            } finally {
                cacheLock.readLock().unlock();
            }
        }

        boolean foundInCache = true;
        if (body == null) {
            foundInCache = false;
            body = doRequest(method, targetURL, req);
        }

        if (!foundInCache && entry.useCache()) {
            try {
                cacheLock.writeLock().lock();
                requestsCache.put(cacheKey, body);
            } finally {
                cacheLock.writeLock().unlock();
            }
        }

        if (requestType.equals("text")) {
            resp.setContentType("text/plain");
        } else if (requestType.equals("xml")) {
            resp.setContentType("text/xml");
        }

        if (cache != null) {
            SimpleCacheFilter.addCacheHeader(resp, cache);
        }

        resp.getWriter().write(body);
        resp.setStatus(HttpServletResponse.SC_OK);
    }

    protected static String getSessionId(HttpServletRequest req) {
        String jSessionId = null;
        for (Cookie cookie : req.getCookies()) {
            if ("JSESSIONID".equalsIgnoreCase(cookie.getName())) {
                jSessionId = cookie.getValue();
                break;
            }
        }
        return jSessionId;
    }

    protected static String doRequest(String method, String targetURL, HttpServletRequest req) throws IOException {
        HttpClient client = new HttpClient();
        HttpMethod httpMethod;

        if ("GET".equals(method)) {
            httpMethod = new GetMethod(targetURL);
        } else if ("POST".equals(method)) {
            httpMethod = new PostMethod(targetURL);
            ((PostMethod) httpMethod).setRequestEntity(new InputStreamRequestEntity(req.getInputStream()));
        } else if ("PUT".equals(method)) {
            httpMethod = new PutMethod(targetURL);
            ((PutMethod) httpMethod).setRequestEntity(new InputStreamRequestEntity(req.getInputStream()));
        } else {
            throw new IllegalStateException("Unknown HTTP method: " + method);
        }

        Map<String, String[]> params = req.getParameterMap();
        for (String paramName : params.keySet()) {
            httpMethod.getParams().setParameter(paramName, params.get(paramName));
        }

        client.executeMethod(httpMethod);
        String body = httpMethod.getResponseBodyAsString();
        httpMethod.releaseConnection();
        return body;
    }

}