Chris,

that's good to hear, I'll try it out.

Best,
Albert

On 07.08.2018 18:53, Chris Hegarty wrote:
Albert,

I haven’t yet looked at what happens in JDK 10, but just to say, since things 
have moved on a lot in JDK 11 EA, that the same test runs with a reasonable 
amount of memory and CPU with JDK 11 EA [1]. I updated the test a little, since 
some the names have been changed with the standardisation ( see javadoc for 
more details [2] ).

-Chris.

[1] http://jdk.java.net/11/
[2] 
https://download.java.net/java/early_access/jdk11/docs/api/java.net.http/java/net/http/package-summary.html

---

$ cat BadProxyLeak.java

import java.net.InetSocketAddress;
import java.net.ProxySelector;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.concurrent.TimeUnit;

public class BadProxyLeak {
     public static void main(String[] args) throws InterruptedException {
         // 1st heap dump
//        Thread.sleep(10000);

         {
             HttpClient client = HttpClient.newBuilder()
                     // malicious proxy?
                     .proxy(ProxySelector.of(new 
InetSocketAddress("165.165.248.90", 8080)))
                     .build();

             HttpRequest req = HttpRequest
                     // target is not relevant
                     .newBuilder(URI.create("https://www.google.de";))
                     // leak occurs only with HTTP_2
                     .version(HttpClient.Version.HTTP_2)
//                    .version(HttpClient.Version.HTTP_1_1)
                     .GET()
                     .build();


             // use same client for every request
             // most likely happens on the first retry, if not try again or 
increase i
             for (int i = 0; i < 10; i++) {
                 System.out.println("Request " + i);
                 // body handler is not relevant
                 HttpResponse.BodyHandler<?> t = 
HttpResponse.BodyHandlers.ofString();

                 try {
                     // happens with both async and sync send
                     client.sendAsync(req, t).get(15, TimeUnit.SECONDS);
//                client.send(req, handler);
                 } catch (Exception e) {
                     e.printStackTrace();
                 }
             }
         }

         // 3rd heap dump
         System.out.println("Generating heap dump manually");
         // space is not released
         Thread.sleep(60000);
     }
}


On 7 Aug 2018, at 17:05, Chris Hegarty <chris.hega...@oracle.com> wrote:


On 7 Aug 2018, at 16:55, Albert Schimpf <albi...@gmx.de> wrote:

Hi,

by bad I mean that this proxy is the only one out of ~1000 proxies which causes 
this behavior. It's also the only one which causes SSLExceptions (General SSL 
engine problem) and EOFExceptions. I don't think that particular proxy is a 
valid proxy. Using curl indicates that this is a SSL handshake problem (https):

* Rebuilt URL to: www.google.de/
*   Trying 165.165.248.90…
Oh, you mean the proxy at that actual IP address. Ok got it.


* TCP_NODELAY set
* Connected to 165.165.248.90 (165.165.248.90) port 8080 (#0)
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 165.165.248.90:8080
* Closing connection 0
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 
165.165.248.90:8080

I don't know that much about the protocol itself,  so I don't think I can help 
very much.

Thank you for looking into this!

-Chris.


Best,
Albert


On 07.08.2018 12:05, Chris Hegarty wrote:
Hi Albert,

Very strange indeed. Thanks for reporting it, I’ll investigate.

What do your mean by “bad proxy”. What is bad about it, and how does it behave?

-Chris.


On 7 Aug 2018, at 10:25, Albert Schimpf <albi...@gmx.de> wrote:

Hi,

I stumbled upon some strange behavior when using the new Java httpclient.

The issue is very simple to reproduce. Send a GET request via a known bad proxy:

HttpClient client = HttpClient.newBuilder()
                    .proxy(ProxySelector.of(BAD_PROXY))
                    .build();

HttpRequest req = HttpRequest
                    // target is not relevant
                    .newBuilder(...)
                    .GET()
                    .build();

// body handler is not relevant
HttpResponse.BodyHandler<?> t = HttpResponse.BodyHandler.asString();

// happens with both async and sync send
client.sendAsync(req, t).get(30, TimeUnit.SECONDS);

The result is that the heap size increases dramatically (to about 1.5GB) and 
resources are not released. CPU consumption increases by a constant factor, 
too. I have tried many variations of the above code, and the only thing which 
seems to work (i.e. heap size does not explode) is to set the HTTP version to 
1.1.

In my main application this leads to both memory and CPU starvation (4GB memory 
limit, 100% CPU usage). It usually uses only 5% CPU and 200MB memory at worst.

I have attached a working example code with a bad proxy. I uploaded the 
generated garbage collection log and three heap dumps (before, during, and 
after the request) to dropbox:

https://www.dropbox.com/s/ulqnmrmgr58rrul/debug.zip

I tried the 10.0.0-openjdk and 10.0.1-zulu version. I can reproduce the issue 
100% of times.

Am I doing something wrong? Is this to be expected if one somehow happens to 
use a bad proxy? If this is to be expected, how can I protect my application 
against such behavior?


Best,
Albert
<mon.png><Main.java>

Reply via email to