Giter VIP home page Giter VIP logo

http-proxy-servlet's Introduction

Smiley's HTTP Proxy Servlet

This is an HTTP Proxy (aka gateway) in the form of a Java servlet. An HTTP proxy is useful for AJAX applications to communicate with web accessible services on hosts other than where the web application is hosted. It's a reverse proxy, and not really a forwarding proxy albeit the template form of the servlet may blur that line.

This is hardly the first proxy, so why did I write it and thus why might you use it?

  • It's simple -- a single source file implementation
  • It's tested -- have confidence it works Build Status
  • It's securable -- via Java EE web.xml or via a servlet filter such as Spring-Security
  • It's extendable -- via simple class extension
  • It's embeddable -- into your Java web application making testing your app easier

I have seen many quick'n'dirty proxies posted in source form on the web such as in a blog. I've found such proxies to support a limited HTTP subset, such as only a GET request, or to suffer other implementation problems such as performance issues or URL escaping bugs. Disappointed at the situation, I set out to create a simple one that works well and that is well tested so I know it works. I suggest you use a well tested proxy instead of something non-tested that is perhaps better described as a proof-of-concept.

If you need something more sophisticated than there are some alternatives listed at the bottom of this page.

This proxy depends on Apache HttpClient, which offers another point of extension for this proxy. At some point I may write an alternative that uses the JDK and thus doesn't have any dependencies, which is desirable. In the meantime, you'll have to add the jar files for this and its dependencies:

 +- org.apache.httpcomponents:httpclient:jar:4.5.13:compile
    +- org.apache.httpcomponents:httpcore:jar:4.4.13:compile
    |  +- commons-logging:commons-logging:jar:1.2:compile
    |  \- commons-codec:commons-codec:jar:1.11:compile

This proxy supports HttpClient 4.5, and newer version too. If you need to support older HttpClient versions:

  • use 1.8 version of this proxy for HttpClient versions 4.1 and 4.2
  • use 1.12 version of this proxy for HttpClient versions 4.3 and 4.4

As of version 2.0 of the proxy, the proxy switched to the jakarta servlet-api, while nonetheless retaining support for the javax servlet-api version for those that need it. To use that, specify the javax classifier on the dependency declaration as follows:

<dependency>
    <groupId>org.mitre.dsmiley.httpproxy</groupId>
    <artifactId>smiley-http-proxy-servlet</artifactId>
    <version>${smiley-http-proxy-servlet.version}</version>
    <classifier>javax</classifier>
</dependency>

As of version 1.5 of the proxy, there is the ability to parameterize your proxy URL, allowing you to use the same web.xml servlet specification for multiple target servers. It follows the URI Template RFC, Level 1. Special query parameters (see the examples below) sent from the client to the ProxyServlet will map to the matching URL template, replacing arguments in the proxy's targetUri as specified in the web.xml. To use this, you must use a subclass of the base servlet. IMPORTANT! The template substitutions must be placed in the query string, even when using HTTP POST. Other application parameters can be in your POSTed url-encoded-form string; just not proxyArgs.

See CHANGES.md for a history of changes.

Build & Installation

Simply build the jar using "mvn package" at the command line. The jar is built to "target/smiley-http-proxy-servlet-VERSION.jar". You don't have to build the jar if you aren't modifying the code, since released versions are deployed to maven-central. If you are using maven then you can add this to your dependencies in your pom like so: (Note: the version below is not necessarily the latest.)

<dependency>
    <groupId>org.mitre.dsmiley.httpproxy</groupId>
    <artifactId>smiley-http-proxy-servlet</artifactId>
    <version>1.12.1</version>
</dependency>

Ivy and other dependency managers can be used as well.

Configuration

Parameters

The following is a list of parameters that can be configured

  • log: A boolean parameter name to enable logging of input and target URLs to the servlet log.
  • forwardip: A boolean parameter name to enable forwarding of the client IP
  • preserveHost: A boolean parameter name to keep HOST parameter as-is
  • preserveCookies: A boolean parameter name to keep COOKIES as-is
  • preserveCookiePath: A boolean parameter name to keep cookie path unchanged in Set-Cookie server response header
  • http.protocol.handle-redirects: A boolean parameter name to have auto-handle redirects
  • http.socket.timeout: A integer parameter name to set the socket connection timeout (millis)
  • http.read.timeout: A integer parameter name to set the socket read timeout (millis)
  • http.connectionrequest.timeout: A integer parameter name to set the connection request timeout (millis)
  • http.maxConnections: A integer parameter name to set max connection number
  • useSystemProperties: A boolean parameter whether to use JVM-defined system properties to configure various networking aspects.
  • targetUri: The parameter name for the target (destination) URI to proxy to.

Servlet

Here's an example excerpt of a web.xml file to communicate to a Solr server:

<servlet>
  <servlet-name>solr</servlet-name>
  <servlet-class>org.mitre.dsmiley.httpproxy.ProxyServlet</servlet-class>
  <init-param>
    <param-name>targetUri</param-name>
    <param-value>http://solrserver:8983/solr</param-value>
  </init-param>
  <init-param>
    <param-name>log</param-name>
    <param-value>true</param-value>
  </init-param>
</servlet>
<servlet-mapping>
  <servlet-name>solr</servlet-name>
  <url-pattern>/solr/*</url-pattern>
</servlet-mapping>

Here's an example with a parameterized proxy URL matching query parameters _subHost, _port, and _path such as "http://mywebapp/cluster/subpath?_subHost=namenode&_port=8080&_path=monitor". Note the different proxy servlet class. The leading underscore is not mandatory but it's good to differentiate them from the normal query parameters in case of a conflict.:

<servlet>
  <servlet-name>clusterProxy</servlet-name>
  <servlet-class>org.mitre.dsmiley.httpproxy.URITemplateProxyServlet</servlet-class>
  <init-param>
    <param-name>targetUri</param-name>
    <param-value>http://{_subHost}.behindfirewall.mycompany.com:{_port}/{_path}</param-value>
  </init-param>
  <init-param>
    <param-name>log</param-name>
    <param-value>true</param-value>
  </init-param>
</servlet>

<servlet-mapping>
  <servlet-name>clusterProxy</servlet-name>
  <url-pattern>/mywebapp/cluster/*</url-pattern>
</servlet-mapping>

SpringMVC

If you are using SpringMVC, then an alternative is to use its ServletWrappingController so that you can configure this servlet via Spring, which is supremely flexible, instead of having to modify your web.xml. However, note that some customization may be needed to divide the URL at the proxied portion; see Issue #15.

Spring Boot

If you are using Spring Boot, then consider this basic configuration:

@Configuration
public class SolrProxyServletConfiguration implements EnvironmentAware {

  @Bean
  public ServletRegistrationBean servletRegistrationBean() {
    ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new ProxyServlet(), propertyResolver.getProperty("servlet_url"));
    servletRegistrationBean.addInitParameter(ProxyServlet.P_TARGET_URI, propertyResolver.getProperty("target_url"));
    servletRegistrationBean.addInitParameter(ProxyServlet.P_LOG, propertyResolver.getProperty("logging_enabled", "false"));
    return servletRegistrationBean;
  }

  private RelaxedPropertyResolver propertyResolver;

  @Override
  public void setEnvironment(Environment environment) {
    this.propertyResolver = new RelaxedPropertyResolver(environment, "proxy.solr.");
  }
}

if you use Spring Boot 2.x,you can try this:

@Configuration
public class SolrProxyServletConfiguration implements EnvironmentAware {

    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
        Properties properties= (Properties) bindResult.get();
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new ProxyServlet(), properties.getProperty("servlet_url"));
        servletRegistrationBean.addInitParameter(ProxyServlet.P_TARGET_URI, properties.getProperty("target_url"));
        servletRegistrationBean.addInitParameter(ProxyServlet.P_LOG, properties.getProperty("logging_enabled", "false"));
        return servletRegistrationBean;
    }

    private BindResult bindResult;

    @Override
    public void setEnvironment(Environment environment) {
        Iterable sources = ConfigurationPropertySources.get(environment);
        Binder binder = new Binder(sources);
        BindResult bindResult = binder.bind("proxy.solr", Properties.class);
        this.bindResult = bindResult;
    }
}

and properties in application.yml:

proxy:
    solr:
        servlet_url: /solr/*
        target_url: http://solrserver:8983/solr

It may be the case that Spring Boot (or Spring MVC) is consuming the servlet input stream before the servlet gets it, which is a problem.
See Issue #83 RE disabling FilterRegistrationBean.

Dropwizard

Addition of Smiley's proxy to Dropwizard is very straightforward.

Add a new property in the Dropwizard app .yml file

targetUri: http://foo.com/api  

Create a new configuration property

    @NotEmpty
    private String targetUri = "";

    @JsonProperty("targetUri")
    public String getTargetUri() {
        return targetUri;
    }  

Then register Smiley's proxy servlet with Jetty through the Dropwizard service's App run() method.

@Override
    public void run(final ShepherdServiceConfiguration configuration,
        final Environment environment) {

        environment.getApplicationContext()
            .addServlet("org.mitre.dsmiley.httpproxy.ProxyServlet", "foo/*")
            .setInitParameter("targetUri", configuration.getTargetUri());  

Alternatives

This servlet is intentionally simple and limited in scope. As such it may not meet your needs, so consider looking at these alternatives:

http-proxy-servlet's People

Contributors

5im-0n avatar aldas avatar asashour avatar asteffens avatar chw-1 avatar dependabot[bot] avatar dsmiley avatar dweebo avatar gillarramendi avatar hw626 avatar klopfdreh avatar l-dobrev avatar lorandlorincz avatar lxhcaicai avatar matthiasblaesing avatar meir017 avatar mikehearn avatar mirkojahn avatar mmichaelis avatar phuongnq avatar pjunlin avatar reda-alaoui avatar richkadel avatar royling avatar rweng avatar stephan972 avatar tracer021 avatar twwwt avatar vsevolod-volkov avatar weeniearms avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

http-proxy-servlet's Issues

Exception handling truncated response

Hi,

I am using the ProxyServlet to provide security to solr service. Following is an exception I encountered. What is strange the servlet stops responding on future requests ?

See the error stack trace below. Appreciate your inputs.

Thanks,
Pratik

Jun 27, 2013 3:50:20 PM org.apache.catalina.core.ApplicationContext log
SEVERE: ProxyServlet: null
ClientAbortException: java.io.IOException
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:358)
at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:432)
at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:309)
at org.apache.catalina.connector.OutputBuffer.close(OutputBuffer.java:273)
at org.apache.catalina.connector.CoyoteOutputStream.close(CoyoteOutputStream.java:104)
at org.mitre.dsmiley.httpproxy.ProxyServlet.closeQuietly(ProxyServlet.java:227)
at org.mitre.dsmiley.httpproxy.ProxyServlet.copyResponseEntity(ProxyServlet.java:299)
at org.mitre.dsmiley.httpproxy.ProxyServlet.service(ProxyServlet.java:177)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at gc.solr.proxy.SolrHttpRequestFilter.doFilter(SolrHttpRequestFilter.java:66)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:864)
at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:579)
at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1665)
at java.lang.Thread.run(Unknown Source)
Caused by: java.io.IOException
at org.apache.coyote.http11.InternalAprOutputBuffer.flushBuffer(InternalAprOutputBuffer.java:716)
at org.apache.coyote.http11.InternalAprOutputBuffer$SocketOutputBuffer.doWrite(InternalAprOutputBuffer.java:746)
at org.apache.coyote.http11.filters.ChunkedOutputFilter.doWrite(ChunkedOutputFilter.java:124)
at org.apache.coyote.http11.InternalAprOutputBuffer.doWrite(InternalAprOutputBuffer.java:552)
at org.apache.coyote.Response.doWrite(Response.java:560)
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:353)
... 23 more
Jun 27, 2013 3:50:20 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet ProxyServlet threw exception
org.apache.http.TruncatedChunkException: Truncated chunk ( expected size: 8192; actual size: 1672)
at org.apache.http.impl.io.ChunkedInputStream.read(ChunkedInputStream.java:182)
at org.apache.http.impl.io.ChunkedInputStream.read(ChunkedInputStream.java:196)
at org.apache.http.impl.io.ChunkedInputStream.close(ChunkedInputStream.java:292)
at org.apache.http.entity.BasicHttpEntity.writeTo(BasicHttpEntity.java:117)
at org.apache.http.entity.HttpEntityWrapper.writeTo(HttpEntityWrapper.java:96)
at org.apache.http.conn.BasicManagedEntity.writeTo(BasicManagedEntity.java:114)
at org.mitre.dsmiley.httpproxy.ProxyServlet.copyResponseEntity(ProxyServlet.java:297)
at org.mitre.dsmiley.httpproxy.ProxyServlet.service(ProxyServlet.java:177)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at gc.solr.proxy.SolrHttpRequestFilter.doFilter(SolrHttpRequestFilter.java:66)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:864)
at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:579)
at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1665)
at java.lang.Thread.run(Unknown Source)

Servlet kills web container

I'm sorry, that I haven't steps to reproduce the situation, but

after some houres of using the proxy servlet with apache tomcat 7.0.42 it (tomcat or servlet) stops responding.

Also I had the similar situation with WebSphere 7. After couple of days of using the proxy servlet the app with it stopped responding.

ClassNotFoundException org.apache.http.conn.ClientConnectionManager

when i use tomcat 6 run the serverlet, it throw this error

why?

Servlet /gdds threw load() exception
java.lang.ClassNotFoundException: org.apache.http.conn.ClientConnectionManager
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1516)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1361)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2389)
at java.lang.Class.getConstructor0(Class.java:2699)
at java.lang.Class.newInstance0(Class.java:326)
at java.lang.Class.newInstance(Class.java:308)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1116)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:993)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4187)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4496)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:546)
at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1041)
at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:964)
at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:502)
at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1277)
at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:321)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:785)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
at org.apache.catalina.core.StandardService.start(StandardService.java:519)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
at org.apache.catalina.startup.Catalina.start(Catalina.java:581)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)

my web.xml:

solr
org.mitre.dsmiley.httpproxy.ProxyServlet

targetUri
http://solrserver:8983/solr


log
true

1


solr
/solr/*

Migrate from HttpUnit to Jetty's ServletTester

HttpUnit sometimes seems to not quite emulate a browser as well as I'd like. Off-hand I forgot the issues. I found Jetty's ServletTester recently and it looks like a better alternative to try.

<dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-servlet</artifactId>
    <version>9.0.7.v20131107</version>
    <scope>test</scope>
</dependency>

Possible query param parse bug with colon

(From Thomas Kramer)

The query is interpreted and considered to be syntactically wrong:
INFO: INFO 12 Mai 2012 16:18:47,605
org.mitre.dsmiley.httpproxy.ProxyServlet.service (ProxyServlet.java:189)

INFO: INFO 12 Mai 2012 16:18:47,605
org.mitre.dsmiley.httpproxy.ProxyServlet.service (ProxyServlet.java:190)

  • HTTP/1.1 400 invalid boolean value: note:Leitbild

(I added some log lines to your class locally)

Connection reset exception

Hello,

I have been testing this servlet for a requirement we have and it has been fairly stable except for the following one issue.

This happens intermittently and when we see this error, the servlet hangs (it continues to receive requests but does not send a response back to the client). I am using this servlet to forward requests that come over a HTTPS pipe to tomcat to various end points over HTTP after some pre-processing (client --> https --> tomcat proxy servlet --> http --> endpoints).

Environment - Tomcat 6.0.33/Scientific Linux 5.9

Exception -
ClientAbortException: javax.net.ssl.SSLException: Connection has been shutdown.: javax.net.ssl.SSLException:java.net.SocketException:Connection reset.

at org.apache.catalina.connector.OutputBuffer.realWriteBytes()
at org.apache.tomcat.util.buf.ByteChunk.flushBuffer()
at org.apache.catalina.connector.OutputBuffer.doFlush()
at org.apache.catalina.connector.OutputBuffer.close()
at org.apache.catalina.connector.CoyoteOutputStream.close()
at com.acme.ProxyServlet.closeQuietly()

Please respond with any suggestions.

Response Code Manipulation

It would be great to be able to force a status code on proxy. For Cany chat which I am setting up on spring, the JS is expecting a 200 code but the proxy appears to be passing a 302 "Move temporarily" code... If this is already a parameter we can customize it would be great to get that into the docs.

Thanks, great work so far!

HttpClient proxyClient is not thread safe.

I wanted to note here that I had a huge security issue occurring in my environment.
After tons and tons of investigation I have nailed it down to the ProxyServlet class under org.mitre.dsmiley.httpproxy.

A servlet instance is created only once when the server starts and it is used by all users.

Amazing explanation under BalusC's comment here http://stackoverflow.com/questions/3106452/how-do-servlets-work-instantiation-shared-variables-and-multithreading

In your ProxyServlet you have the HttpClient proxyClient created only once in the init() of the servlet.
This proxyClient instance is getting used by all users and it looks like it holds some variables from the one user when moving to the next one. I am using this proxy servlet to establish and grab login information from another web application that does NTLM authentication.

A quick fix is that you generate a proxyClient instance for each user and each session...

So under ProxyServlet class within protected void service

add these lines of code :

        HttpClient theadSafeProxyClient = null;
        HttpSession session = servletRequest.getSession();

        if(session.getAttribute("proxyClient")!=null)
            theadSafeProxyClient = (HttpClient)session.getAttribute("proxyClient");
        else {
            BasicHttpParams hcParams = new BasicHttpParams();
            hcParams.setParameter("http.protocol.cookie-policy", "ignoreCookies");
            this.readConfigParam(hcParams, "http.protocol.handle-redirects", Boolean.class);
            theadSafeProxyClient = this.createHttpClient(hcParams);
            session.setAttribute("proxyClient", theadSafeProxyClient );
        }

before :

proxyResponse1 = theadSafeproxyClient.execute(this.getTargetHost(servletRequest), (HttpRequest)proxyRequest);

Servlet instance field use causes race conditions under load

Hey,

I extended ProxyServlet to modify targetUri etc. based on request fields. Depending on the value of a field outgoing proxy requests are made to host1 or host2.

Since this data is moved back and forth in instance fields (do_, target_, proxyClient) and instances are re-used by servlet containers instead of being destroyed and re-created, under heavy load my use case results in target* fields being overwritten by another thread and easily results in a race condition:

  • Thread1 requests http://host1/a while thread2 requests http://host2/b
  • thread2 overwrites thread1's targetUri (or may abuse proxyClient)
  • output from thread2 proxyClient is returned by thread1 to its ServletResponse.

This is because I had to extend and override service() method and modified field variables in it and just called super.service() with the same set of parameters.

I have ditched all non-final fields and converted to local variables, I'll post a patch soon.

Environmental Variable for Proxy URL

I'm loving your ProxyServlet except for one thing. Since the URL that the servlet is proxying to is set in the web.xml file, I am not able to modify it and set it more dynamically. My specific case is that I want to be able to hit a different URL given the environment (Dev, Testing, Prod). I have yet to find an elegant way to dynamically load the URL on startup using a property file that is environment specific. Is there an easy way to do this that I have overlooked?

I looked into servlet filters, maven like tokens in the web.xml, and even extending your servlet class to use spring to inject the URL value in from a property file. The best solution I can think of is to copy your code and manipulate it to not use the initParams, but instead use a spring injected property. My case does not need to change the URL once it is loaded, but I want to be able to have an environment specific value without packaging a separate build for the Testing and Prod environments.

Tests fail on Windows 7

Hey,

when I built this on my windows machine, the tests failed due to the '\n' in line 166, replacing it with System.getProperty("line.separator") obviously fixed the build.

Spaces in URL path handled incorrectly.

Spaces in URL path (encoded as %20) cause "org.apache.http.client.ClientProtocolException" caused by "java.net.URISyntaxException: Illegal character in path at index XXX: [URL with space in path at index XXX]"

The simple fix is to modify rewriteUrlFromRequest(HttpServletRequest) method in the line:
uri.append(servletRequest.getPathInfo());
to:
uti.append(encodeSpaces(servletRequest.getPathInfo()));

Where encodeSpaces(String) is like:
private String encodeSpaces ( String pathInfo ) {
return pathInfo.replaceAll( " ", "%20" );
}

First, please add "/p?id=p%20i" and "/p%20i" to String[] testUrlSuffixes in ProxyServletTest to prove that encoded spaces in URLs have issues or are working. As is, the first one (with space char in query) will pass, but the second (with space char in path) will fail.

how to handle AutoRedirect?

my client send url to my server , throw this proxy , and my server want to redirect other web site , but this redirect seem to be auto handel by the proxy ,my client did not receive the 302 or 303 redirect message .i do not want this

how do do that , let proxy do not autoRedirect , let browser client handle it by it self?

Cookie empty value copy

should be:

protected void copyRequestHeaders(HttpServletRequest servletRequest,
HttpRequest proxyRequest) {
// Get an Enumeration of all of the header names sent by the client
Enumeration enumerationOfHeaderNames = servletRequest.getHeaderNames();
while (enumerationOfHeaderNames.hasMoreElements()) {
String headerName = (String) enumerationOfHeaderNames.nextElement();
// Instead the content-length is effectively set via
// InputStreamEntity
if (headerName.equalsIgnoreCase(HttpHeaders.CONTENT_LENGTH))
continue;
if (hopByHopHeaders.containsHeader(headerName))
continue;

        Enumeration headers = servletRequest.getHeaders(headerName);
        while (headers.hasMoreElements()) {// sometimes more than one value
            String headerValue = (String) headers.nextElement();
            // In case the proxy host is running multiple virtual servers,
            // rewrite the Host header to ensure that we get content from
            // the correct virtual server
            if (headerName.equalsIgnoreCase(HttpHeaders.HOST)) {
                HttpHost host = getTargetHost(servletRequest);
                headerValue = host.getHostName();
                if (host.getPort() != -1)
                    headerValue += ":" + host.getPort();
            } else if (headerName
                    .equalsIgnoreCase(org.apache.http.cookie.SM.COOKIE)) {
                    headerValue = getRealCookie(headerValue);
            }
            if (headerValue != null && !headerValue.equals("")) {
                proxyRequest.addHeader(headerName, headerValue);
            }
        }
    }
}

to avoid "Cookie: "

example: with Grizzly Server as target after proxy will couse in target 500 error, bcs of sending "Cookie: "

URL with encoded ":" or "%" cannot be redirected

Hi,
a URL like the following cannot be redirected to the target uri:
http:localhost:8080/mywebapp/myServletPath/%3Asda%25a

The reason is that the ProxyServlet uses servletRequest.getPathInfo() to create the rewriteURL and getPathInfo() returns the decoded path:
/:sda%a

This decoded path is used to create the redirect URL, which leads to an invalid URL in this case. We get an exception like this:

org.apache.http.ProtocolException: Invalid request URI: http:localhost:8080/mywebapp/myServletPath/:sda%a
org.apache.http.impl.client.RequestWrapper.<init>(RequestWrapper.java:83)
org.apache.http.impl.client.EntityEnclosingRequestWrapper.<init>(EntityEnclosingRequestWrapper.java:64)
org.apache.http.impl.client.DefaultRequestDirector.wrapRequest(DefaultRequestDirector.java:328)
org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:379)
org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:863)
org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:115)
org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:57)
org.mitre.dsmiley.httpproxy.ProxyServlet.service(ProxyServlet.java:245)

Suggestion: Use servletRequest.getRequestURI() instead of servletRequest.getPathInfo() to create the rewriteURL, because servletRequest.getRequestURI() returns the URI not decoded (see also http://stackoverflow.com/questions/966077/java-reading-undecoded-url-from-servlet).

protected rewriteUrlFromRequest

Great proxy !

Please could you increase the visibility for your private methods to protected to provide better possibility to extend the functionality of the proxy.

For example "rewriteUrlFromRequest", I want to add some rules to redirect requests to set of URIs based on matching some regular expression for request path. For example:
/gui/* -> forward to production server and /controller/* keep on localhost server

Thanks for help

Incompatibility with servlet filters that consume the inputStream

This proxy does not support POST form requests.
If you do a POST request in the proxy with content type "application/x-www-form-urlencoded" the proxy gets stuck.
After a lot of debugging I figured out that the servletRequest.getInputStream() is empty when the content type is "application/x-www-form-urlencoded".

In the ProxyServlet class under the else statement of the code bellow in service(...) method, it is trying to copy to the proxyRequest the body of the servletRequest. This body is empty so the line proxyResponse1 = this.proxyClient.execute(this.getTargetHost(servletRequest), (HttpRequest)proxyRequest); hangs.

if(servletRequest.getHeader("Content-Length") == null && servletRequest.getHeader("Transfer-Encoding") == null) {
proxyRequest = new BasicHttpRequest(method, proxyRequestUri);
} else {
BasicHttpEntityEnclosingRequest proxyResponse = new BasicHttpEntityEnclosingRequest(method, proxyRequestUri);
proxyResponse.setEntity(new InputStreamEntity(servletRequest.getInputStream(), (long)servletRequest.getContentLength()));
proxyRequest = proxyResponse;
}

A workaround is to manually copy the form body of the servletRequest, servletRequest.getParameterMap().

HTTPS SNI connections

I can not connect to an HTTPS server with SNI with version 1.6 of the HTTP-Proxy-Servlet.

I locally patched the org.mitre.dsmiley.httpproxy.ProxyServlet.createHttpClient(HttpParams) method to enable SNI like the page [1] describes.

I used the following code:

SSLContext sslcontext = SSLContexts.createSystemDefault();
SSLSocketFactory sslsf = new SSLSocketFactory(sslcontext) {
  // here the code from [1]
}
HttpClientBuilder builder = HttpClients.custom().setConnectionManager(new PoolingHttpClientConnectionManager()).setSSLSocketFactory(sslsf);
builder.disableCookieManagement();
if (hcParams.isParameterFalse(ClientPNames.HANDLE_REDIRECTS)) {
  builder.disableRedirectHandling();
}
return builder.build();

I'm not sure if this is compatible with the code for org.apache.http.impl.client.SystemDefaultHttpClient in createHttpClient().

[1] https://wiki.apache.org/HttpComponents/SNISupport

HttpResponse not closed

The method consumeQuietly just closes the HttpEntity and not the HttpResponse.

I am using the HTTP-Proxy-Servlet to proxy requests from one tomcat to another tomcat. I have observed an issue on tomcat: All default HTTP threads of tomcat are getting exhausted as observedJVM jstack thread dump and it is not able to accept any further requests.

I think that ProxyServlet is not closing the connection cleanly as suggested in the https://hc.apache.org/httpcomponents-client-ga/quickstart.html
It is consuming the response but not closing the httpresponse. Suggested finally block

finally {
    if(response != null) {
      // This call is necessary to consume the entire content of the response (entity) so that 
the manager can release the connection back to the pool.
       EntityUtils.consume(response.getEntity());
       **response.close();**
     }
}

Sample jvm thread stack for 1 tomcat http thread.

"http-bio-8080-exec-944" daemon prio=10 tid=0x00007f876c202800 nid=0x5de6 waiting on condition [0x00007f874dd5b000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x000000074385c758> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
    at org.apache.http.pool.PoolEntryFuture.await(PoolEntryFuture.java:133)
    at org.apache.http.pool.AbstractConnPool.getPoolEntryBlocking(AbstractConnPool.java:282)
    at org.apache.http.pool.AbstractConnPool.access$000(AbstractConnPool.java:64)
    at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:177)
    at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:170)
    at org.apache.http.pool.PoolEntryFuture.get(PoolEntryFuture.java:102)
    at org.apache.http.impl.conn.PoolingClientConnectionManager.leaseConnection(PoolingClientConnectionManager.java:208)
    at org.apache.http.impl.conn.PoolingClientConnectionManager$1.getConnection(PoolingClientConnectionManager.java:195)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:422)
    at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:863)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:115)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:57)
    at org.mitre.dsmiley.httpproxy.ProxyServlet.service(ProxyServlet.java:227)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.tomee.catalina.OpenEJBValve.invoke(OpenEJBValve.java:45)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at com.ca.emm.essfilter.AuthzTomcatValve.invoke(AuthzTomcatValve.java:154)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:313)
    - locked <0x0000000743845020> (a org.apache.tomcat.util.net.SocketWrapper)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:724)

Header parameter names are converted to lower case by proxy

Our internal server ran into problems when it experienced that all parameter names of the HTTP header have been converted to lower case by the proxy. More precisely: The first letter is converted to lower case. A direct request is handled correctly by our server, because it can read the header names as expected. The proxy request is different because the parameters are now lower case:

Direct request:

Http-Header Accept=text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Http-Header Accept-Encoding=gzip, deflate
Http-Header Accept-Language=de,en-US;q=0.7,en;q=0.3
Http-Header Cache-Control=max-age=0
Http-Header Connection=keep-alive
Http-Header Host=136.XXX.XXX.XXX:6600
Http-Header User-Agent=Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0

Via Proxy:

Http-Header X-Forwarded-For=194.xxx.xxx.xxx
Http-Header accept=text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Http-Header accept-encoding=gzip, deflate
Http-Header accept-language=de,en-US;q=0.7,en;q=0.3
Http-Header cache-control=max-age=0
Http-Header host=127.0.0.1:6601
Http-Header user-agent=Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0

Is this a bug or is this specific to the library which is used? Are the parameter names of the HTTP protocol case sensitive?

Copied cookie path may be invalid

In copyProxyCookie method the new path may be invalid because it uses getServletContext().getServletContextName().

From the documentation of getServletContextName :
Returns the name of this web application corresponding to this ServletContext as specified in the deployment descriptor for this web application by the display-name element.

Hence you can specify any name for the servlet context which may not be a valid path.

Deploy 1.6. (was: HttpClient not ignoring Set-Cookie header.)

I see there has been a lot of activity lately, both in the issues and commits, related to cookies. I've gone through the code but don't follow all of it exactly. I noticed in Issue #37 there was a reference to HttpClient being set to ignore cookies, but that's not what I was finding.

As a result the proxy is sending old cookies that should no longer apply, but because HttpClient has them cached, it continues to send them.

I was able to get around this by extending ProxyServlet and overriding createHttpClient(). Here's the code:

@Override
protected HttpClient createHttpClient(HttpParams hcParams) {
    hcParams.setParameter("http.protocol.cookie-policy", CookiePolicy.IGNORE_COOKIES);
    return super.createHttpClient(hcParams);
}

When the policy is set to ignore the cookies, the issue goes away.

I realize that being able to customize the servlet is very useful, but is this something that should be included in the core proxy? Would there be any reason cookies should not be ignored in a proxy? If so, I would be happy to create a pull request, just let me know.

Thanks for your help and time.

Using version 1.5.

Support multiple targets

Support proxying single requests to multiple targets in configuration (not via parameters to URI template). Useful if you want to be able to send requests to multiple servers in a cluster or pool, but don't want the client to have to know how to address each node.
Could also be implemented as special new query parameter(s) that allows user to specify a list of URLs to forward to.

Proxy SOAP request, Headers not being forwarded

I have the proxy working with the exception of forwarding a SOAP request. A few headers are not being forwarded.

I am making my SOAP request via jquery.soap

$.soap({
    url: webServiceURL,
    type: 'POST',
    SOAPAction: 'GET_'+method,
    appendMethodToURL: false,
    data: soapEnvelopeHeader + soapBodyHead + params + soapBodyFooter + soapEnvelopeFooter,
    HTTPHeaders: {
      Authorization: 'Basic ' + btoa('username:password')
    },
    ...
});

The Authorization header and the SOAPAction headers are both being stripped.

I went through and logged the HeaderName as each header is being copied and they are getting stripped out before that point.

Any suggestions.

Stream incorrectly closed

Hi

In method copyResponseEntity you close stream with closeQuietly before is flushed to service output !?

I must remove this line to see xml service response.

Handling unnecessary "?" signs

I configure URITemplateProxyServlet like this:

<init-param>
    <param-name>targetUri</param-name>
    <param-value>{_server}</param-value>
</init-param>

So I have to provide _server param via ?_server=. But while using Dojo Framework with dgrid I faced a problem that once I assigned some url to dgid, it would consider that url to be a "path without any query params". And while sorting or performing other queries dgid adds ?sort=(+param) for example. This way if I have url like this:

http://localhost:8080?num=?sort=(+param)

To get rid of this behaviour of some frameworks I suggest to filter any occurence of "?" sign in query string like this:

Integer indexOfQuerySign = queryString.indexOf("?");
queryString = queryString.substring(0, indexOfQuerySign+1) + queryString.substring(indexOfQuerySign+1).replaceAll("\\?", "&");

-Dhttp.proxyHost option ignored?

Hi.

Prevoiusly I was using http://www.servletsuite.com/servlets/httpproxy.htm , but I had the problem with multipart POST requests. Therefore I tried dsmiley http proxy, and multipart POST requests are working fine.

But: my application doesn't have direct access to the internet. I have to use outgoing proxy, which I define in JAVA_OPTS, like -Dhttp.proxyHost=myoutgingproxy.lan

It seems to me that dsmiley proxy doesn't use this variable, since all request are failing.
When I deploy on another computer which has direct access to the internet, everything works fine. So, can I use outgoing httpproxy with dsmiley httpproxy?

Add how to install section to Readme

Hi,

could you add a how to install section to the readme? E.g. in which repository can this artifact be found? It doesn't seem to be at mavencentral.

Robin

stycky session

i have problem when it comes on proxying webapps with authentication, i think the webapps sees all different client behind this http proxy as single client, which is the proxy http client,

i think there should be some cookie or session management,...

Give the option to not copy auth credentials

The Proxy Servlet might be protected for access. In this case, when a client sends a request the credentials (in a Basic auth scheme, for ex.) are passed to the target URL. So, it might be leaking the credentials for the Proxy Servlet access.

In case that the target URL is protected with another auth scheme, like NTLM, the server receives the headers for a different auth scheme and it might reject the request. IIS does this.

NIO ?

Hi,

I've been using your servlet and found it very convenient. It solves my problem for the moment, thanks for the sharing.

The only problem I have with it is that it's "blocking" everywhere. It uses a synchronous HttpClient, and a threaded request model. This can have a big impact on the overall app server performance (retained threads). I had even considered using Node.js for that : they have this neat non-blocking http-proxy module which is quite appealing. But I'd rather prefer to manage this in Java , as it would be easier for sharing code/services that I already have in Java (e.g. DAOs and the like), and that I need in the proxy to route the requests.

I'm wondering if you have plans to support NIO in a future release ?

I have started to hack something that seems to work and that I'm gonna put to use right away. Are you interested in a contrib ?

I forked your repo and checked in my changes in 'develop' :
https://github.com/pojosontheweb/HTTP-Proxy-Servlet/tree/develop

It still supports the current synchronous mode, and allows to use async too, via an additional web.xml init param. It will then use a HttpAsyncClient instead of the blocking one, and also put AsyncContext to use in the servlet, to make it all non-blocking.

I can submit a PR if you're interested.

Cheers

Rémi

Removing deprecated method usage

Hi, in general, for several obvious reasons, as usage of deprecated API is discouraged, it is better to replace the deprecated API usages with new equivalent method.

Test with HTTPS

From Thomas Kramer:

There seems to be a problem when using https. apparently the proxy
works fine with http access, but does not receive the response from solr
resp. send it back to the ajax-solr running in a users browser.
Did you code the servlet for http / non-ssl access only?

Basic Auth support

Just sharing solution which I implemented for basic auth.

package com.kegs.v4.custom;

import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.mitre.dsmiley.httpproxy.ProxyServlet;

import javax.servlet.ServletException;

public class HttpBasicAuthProxyServlet extends ProxyServlet {

protected static final String P_AUTH_BASIC_USERNAME = "authBasicUsername";
protected static final String P_AUTH_BASIC_PASSWORD = "authBasicPassword";

private String authBasicPassword;
private String authBasicUsername;
@Override
public void init() throws ServletException {

    String doLogStr = getServletConfig().getInitParameter(P_LOG);
    if (doLogStr != null) {
        this.doLog = Boolean.parseBoolean(doLogStr);
    }

    String doForwardIPString = getServletConfig().getInitParameter(P_FORWARDEDFOR);
    if (doForwardIPString != null) {
        this.doForwardIP = Boolean.parseBoolean(doForwardIPString);
    }
    initAuthBasic();
    initTarget();

    proxyClient = createHttpClient();
}

private void initAuthBasic() throws ServletException{
    authBasicPassword = getServletConfig().getInitParameter(P_AUTH_BASIC_PASSWORD);
    authBasicUsername = getServletConfig().getInitParameter(P_AUTH_BASIC_USERNAME);

    if (authBasicPassword == null) {
        throw new ServletException(P_AUTH_BASIC_PASSWORD+" is required.");
    }

    if (authBasicUsername == null) {
        throw new ServletException(P_AUTH_BASIC_USERNAME+" is required.");
    }

}

protected HttpClient createHttpClient() {
    BasicCredentialsProvider provider = new BasicCredentialsProvider();
    UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(authBasicUsername, authBasicPassword);
    provider.setCredentials(AuthScope.ANY, credentials);

    RequestConfig requestConfig = RequestConfig.custom().setRedirectsEnabled(true).build();
    HttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).setDefaultCredentialsProvider(provider).build();

    return client;
}

}

HttpClientContext support for 'Preemptive authentication'

Hi,

Currently, ProxyServlet executing request like below:

proxyResponse = proxyClient.execute(getTargetHost(servletRequest), proxyRequest);

Adding support for HttpClientContext (or, via some overriden method) will allow Preemptive authentication support. Ex:

proxyResponse = proxyClient.execute(getTargetHost(servletRequest), proxyRequest, context);

or

proxyResponse = proxyClient.execute(getTargetHost(servletRequest), proxyRequest, getClientContext());

What do you think?

Log more information for debug

What about log all information of both request and response?

Including headers, bodies and request uri. Which is very helpful for debugging restful service which developer do not have source code.

Thanks!

the lib claims it supports HttpClient 4.1 but it has dependency on 4.2

The problem is that if a project that currently uses version 4.1 adds a dependency to smiley-http-proxy-servlet then it will inherit the dependency on 4.2 and the project will end up using this newer version.

Setting scope to provided should fix this and the project depending on the proxy servlet will be responsible to adding a direct dependency on HttpClient:

<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpclient</artifactId>
  <version>${httpclient.version}</version>
  <scope>provided</scope>
</dependency>

Not suitable for dynamic urls calculated for each request

Hello:
First, thank you very much for sharing your excellent work.

In my case, I need a proxy for which I get the full (complete) url through a service, like this: http://user:[email protected]/112/2015_04/file88d78d.mp3

For this case, your servlet does not work unless some methods are overridden, because you code assumes that targetUri and targetHost are fixed and initialized once.

Then my solution working:

    @Override
    public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException,
            IOException {
        log.trace("<== {}?{}",request.getRequestURL(),request.getQueryString());
        if (cat.verify(request.getQueryString())) {
            try {
                targetUriObj = new URI(sercomResources.getRecord(request.getParameter("id")).getUrl());
                targetHost = URIUtils.extractHost(targetUriObj);
                log.trace("==> {}",targetUriObj);
                super.service(request, response);
            } catch (Exception e) {
                log.warn("Error obteniendo destino",e);
                throw new ServletException("Trying to process targetUri init parameter: " + e, e);
            }
        } else {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, CAT.CESTEL_AUTH_TOKEN
                    + " missing.");
            log.warn("Intento de acceso prohibido: {}", request.getRequestURI());
        }
    }

    @Override
    protected void initTarget() throws ServletException {
        /**
         * evitar super.initTarget() porque, al no estabecer parámetros en la
         * inicialización, esta llamada genera NPE
         */
        // super.initTarget();
    }

    @Override
    protected String rewriteUrlFromRequest(HttpServletRequest servletRequest) {
        /**
         * super.rewriteUrlFromRequest(servletRequest) genera Url errónea
         */
        return targetUriObj.toString();
    }

Thanks again.
Regards.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.