mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-03-06 12:20:56 +01:00
re implement ProxyServlet
This commit is contained in:
@@ -41,7 +41,9 @@ import java.net.URL;
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 1.8
|
||||
* @deprecated use {@link ProxyConfigurationProvider} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class BasicProxyURLProvider implements ProxyURLProvider
|
||||
{
|
||||
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer. 2. Redistributions in
|
||||
* binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
|
||||
* nor the names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package sonia.scm.web.proxy;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlElementWrapper;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 1.25
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement(name = "proxy-configuration")
|
||||
public class ProxyConfiguration
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*/
|
||||
public ProxyConfiguration() {}
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param url
|
||||
* @param requestHeaderExcludes
|
||||
* @param responseHeaderExcludes
|
||||
* @param cacheEnabled
|
||||
*/
|
||||
public ProxyConfiguration(URL url, Set<String> requestHeaderExcludes,
|
||||
Set<String> responseHeaderExcludes, boolean cacheEnabled)
|
||||
{
|
||||
this.url = url;
|
||||
this.requestHeaderExcludes = requestHeaderExcludes;
|
||||
this.responseHeaderExcludes = responseHeaderExcludes;
|
||||
this.cacheEnabled = cacheEnabled;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param obj
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getClass() != obj.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
final ProxyConfiguration other = (ProxyConfiguration) obj;
|
||||
|
||||
return Objects.equal(url, other.url)
|
||||
&& Objects.equal(requestHeaderExcludes, other.requestHeaderExcludes)
|
||||
&& Objects.equal(responseHeaderExcludes, other.responseHeaderExcludes)
|
||||
&& Objects.equal(cacheEnabled, other.cacheEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hashCode(url, requestHeaderExcludes, responseHeaderExcludes,
|
||||
cacheEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
//J-
|
||||
return Objects.toStringHelper(this)
|
||||
.add("url", url)
|
||||
.add("requestHeaderExcludes", requestHeaderExcludes)
|
||||
.add("responseHeaderExcludes", responseHeaderExcludes)
|
||||
.add("cacheEnabled", cacheEnabled)
|
||||
.toString();
|
||||
//J+
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Set<String> getRequestHeaderExcludes()
|
||||
{
|
||||
if (requestHeaderExcludes == null)
|
||||
{
|
||||
requestHeaderExcludes = Collections.EMPTY_SET;
|
||||
}
|
||||
|
||||
return requestHeaderExcludes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Set<String> getResponseHeaderExcludes()
|
||||
{
|
||||
if (responseHeaderExcludes == null)
|
||||
{
|
||||
responseHeaderExcludes = Collections.EMPTY_SET;
|
||||
}
|
||||
|
||||
return responseHeaderExcludes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public URL getUrl()
|
||||
{
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isCacheEnabled()
|
||||
{
|
||||
return cacheEnabled;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
@XmlElement(name = "cache-enabled")
|
||||
private boolean cacheEnabled = true;
|
||||
|
||||
/** Field description */
|
||||
@XmlElement(name = "exclude")
|
||||
@XmlElementWrapper(name = "request-header-excludes")
|
||||
private Set<String> requestHeaderExcludes;
|
||||
|
||||
/** Field description */
|
||||
@XmlElement(name = "exclude")
|
||||
@XmlElementWrapper(name = "response-header-excludes")
|
||||
private Set<String> responseHeaderExcludes;
|
||||
|
||||
/** Field description */
|
||||
private URL url;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer. 2. Redistributions in
|
||||
* binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
|
||||
* nor the names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package sonia.scm.web.proxy;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 1.25
|
||||
*/
|
||||
public interface ProxyConfigurationProvider
|
||||
{
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ProxyConfiguration getConfiguration(HttpServletRequest request);
|
||||
}
|
||||
@@ -65,8 +65,10 @@ import javax.servlet.http.HttpServletResponse;
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 1.8
|
||||
* @deprecated use {@link ProxyServlet} instead
|
||||
*/
|
||||
@Singleton
|
||||
@Deprecated
|
||||
public class ProxyServet extends HttpServlet
|
||||
{
|
||||
|
||||
|
||||
293
scm-core/src/main/java/sonia/scm/web/proxy/ProxyServlet.java
Normal file
293
scm-core/src/main/java/sonia/scm/web/proxy/ProxyServlet.java
Normal file
@@ -0,0 +1,293 @@
|
||||
/**
|
||||
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer. 2. Redistributions in
|
||||
* binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
|
||||
* nor the names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package sonia.scm.web.proxy;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.google.common.io.Closeables;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 1.25
|
||||
*/
|
||||
@Singleton
|
||||
public class ProxyServlet extends HttpServlet
|
||||
{
|
||||
|
||||
/**
|
||||
* the logger for ProxyServlet
|
||||
*/
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(ProxyServlet.class);
|
||||
|
||||
/** Field description */
|
||||
private static final long serialVersionUID = 5589963595604482849L;
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param configurationProvider
|
||||
*/
|
||||
@Inject
|
||||
public ProxyServlet(ProxyConfigurationProvider configurationProvider)
|
||||
{
|
||||
this.configurationProvider = configurationProvider;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
*/
|
||||
@Override
|
||||
public void service(HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
|
||||
HttpURLConnection con;
|
||||
|
||||
try
|
||||
{
|
||||
ProxyConfiguration configuration =
|
||||
configurationProvider.getConfiguration(request);
|
||||
|
||||
Preconditions.checkNotNull(configuration);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("proxy request for {}", configuration);
|
||||
}
|
||||
|
||||
con = createConnection(configuration, request);
|
||||
|
||||
copyRequestHeaders(configuration, request, con);
|
||||
con.connect();
|
||||
|
||||
int responseCode = con.getResponseCode();
|
||||
|
||||
logger.trace("resonse returned status code {}", responseCode);
|
||||
response.setStatus(responseCode);
|
||||
|
||||
copyResponseHeaders(configuration, con, response);
|
||||
|
||||
copyContent(con, response);
|
||||
|
||||
con.disconnect();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.error("could not proxy request", ex);
|
||||
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param con
|
||||
* @param response
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private void copyContent(HttpURLConnection con, HttpServletResponse response)
|
||||
throws IOException
|
||||
{
|
||||
BufferedInputStream webToProxyBuf = null;
|
||||
BufferedOutputStream proxyToClientBuf = null;
|
||||
|
||||
try
|
||||
{
|
||||
webToProxyBuf = new BufferedInputStream(con.getInputStream());
|
||||
proxyToClientBuf = new BufferedOutputStream(response.getOutputStream());
|
||||
|
||||
long bytes = ByteStreams.copy(webToProxyBuf, proxyToClientBuf);
|
||||
|
||||
logger.trace("copied {} bytes for proxy", bytes);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Closeables.closeQuietly(webToProxyBuf);
|
||||
Closeables.closeQuietly(proxyToClientBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param configuration
|
||||
* @param request
|
||||
* @param con
|
||||
*/
|
||||
private void copyRequestHeaders(ProxyConfiguration configuration,
|
||||
HttpServletRequest request, HttpURLConnection con)
|
||||
{
|
||||
Enumeration<String> names = request.getHeaderNames();
|
||||
Enumeration<String> values;
|
||||
String headerName;
|
||||
String value;
|
||||
|
||||
while (names.hasMoreElements())
|
||||
{
|
||||
headerName = names.nextElement();
|
||||
|
||||
if (!configuration.getRequestHeaderExcludes().contains(headerName))
|
||||
{
|
||||
|
||||
values = request.getHeaders(headerName);
|
||||
|
||||
while (values.hasMoreElements())
|
||||
{
|
||||
value = values.nextElement();
|
||||
logger.trace("set request header {}={}", headerName, value);
|
||||
con.setRequestProperty(headerName, value);
|
||||
}
|
||||
}
|
||||
else if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.trace(
|
||||
"skip request header {}, because it is in the exclude list",
|
||||
headerName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param configuration
|
||||
* @param con
|
||||
* @param response
|
||||
*/
|
||||
private void copyResponseHeaders(ProxyConfiguration configuration,
|
||||
HttpURLConnection con, HttpServletResponse response)
|
||||
{
|
||||
Map<String, List<String>> headers = con.getHeaderFields();
|
||||
String key;
|
||||
|
||||
for (Entry<String, List<String>> e : headers.entrySet())
|
||||
{
|
||||
key = e.getKey();
|
||||
|
||||
if (key != null)
|
||||
{
|
||||
|
||||
if (!configuration.getResponseHeaderExcludes().contains(key))
|
||||
{
|
||||
for (String v : e.getValue())
|
||||
{
|
||||
logger.trace("add response header {}={}", key, v);
|
||||
response.addHeader(key, v);
|
||||
}
|
||||
|
||||
}
|
||||
else if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.trace(
|
||||
"skip request header {}, because it is in the exclude list", key);
|
||||
}
|
||||
|
||||
}
|
||||
else if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.trace("response header key is null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param configuration
|
||||
* @param request
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private HttpURLConnection createConnection(ProxyConfiguration configuration,
|
||||
HttpServletRequest request)
|
||||
throws IOException
|
||||
{
|
||||
HttpURLConnection con =
|
||||
(HttpURLConnection) configuration.getUrl().openConnection();
|
||||
|
||||
con.setRequestMethod(request.getMethod());
|
||||
con.setDoOutput(true);
|
||||
con.setDoInput(true);
|
||||
con.setUseCaches(configuration.isCacheEnabled());
|
||||
|
||||
return con;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private ProxyConfigurationProvider configurationProvider;
|
||||
}
|
||||
@@ -41,7 +41,9 @@ import java.net.URL;
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 1.8
|
||||
* @deprecated use {@link ProxyConfigurationProvider} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface ProxyURLProvider
|
||||
{
|
||||
|
||||
|
||||
Reference in New Issue
Block a user