Hi Chris and Yasumasa,

Sorry to have remained this issue for a long time. I come back.

I updated my patch for the following three reasons.
http://cr.openjdk.java.net/~ykubota/8169358/webrev.02/

* applies to the latest jdk/jdk instead of jdk9/dev
* adds test by modifying reproducer as like tests on
test/jdk/com/sun/net/httpserver
* prevents potential connection leak as Yasumasa said. For example, a
user sets own implementation of the thread pool to HttpServer and then
throws unexpected exceptions and errors. I think that we should save
existing exception handler to keep compatibility and minimize the risk
of connection leak by catching Throwable.

I've tested test/jdk/com/sun/net/httpserver and passed.
I'm not a committer, so I can not access March 5.

Could you review and sponsor it?

Thanks,
Yuji

2016-11-11 12:11 GMT+09:00 KUBOTA Yuji <kubota.y...@gmail.com>:
> Hi Chris and Yasumasa,
>
> Thank you for your comments!
>
> I had faced connection leak on production by this handler. It seems
> like a corner-case but it's a real risk to me.
> I had focused REE on this issue, but it is a subclass of
> RuntimeException, so I think that we should investigate
> RuntimeException, too.
>
> If Chris agrees with the covering RuntimeException by JDK-8169358, I
> will investigate it and update my patch.
> If we should investigate on another issue, I want to add a test case
> to check fixing about REE like existing jtreg, and I will create a new
> issue after an investigation about RuntimeException.
>
> Any thoughts?
>
> Thank you!
> Yuji
>
> 2016-11-11 0:56 GMT+09:00 Chris Hegarty <chris.hega...@oracle.com>:
>>
>>> On 10 Nov 2016, at 14:43, Yasumasa Suenaga <yasue...@gmail.com> wrote:
>>>
>>> Hi,
>>>
>>>> I think it best to just handle the specific case of REE, as it done in 
>>>> Yuji’s patch.
>>>
>>> Will it be a cause of connection leak if RuntimeException is occurred in 
>>> handler method?
>>
>> No, at least not from this point in the code.
>>
>>> I think we should catch RuntimeException at least.
>>
>> Possibly, but it seems like a corner-case of a corner-case.
>>
>>>>> I think you can use finally statement to close the connection in this 
>>>>> case.
>>>>
>>>> I don’t believe that this is possible. The handling of the connection may 
>>>> be
>>>> done in a separate thread, some time after execute() returns.
>>>
>>> So I said we need to check the implementation of HTTP connection and 
>>> dispatcher.
>>
>> To me, this goes beyond the scope of the issue describe in JIRA, but if
>> you want to investigate that, then that’s fine.
>>
>> -Chris.
>>
>>>
>>> Yasumasa
>>>
>>>
>>> On 2016/11/10 23:00, Chris Hegarty wrote:
>>>>
>>>>> On 9 Nov 2016, at 12:38, Yasumasa Suenaga <yasue...@gmail.com> wrote:
>>>>>
>>>>> Hi Yuji,
>>>>>
>>>>>> http://cr.openjdk.java.net/~ykubota/8169358/webrev.01/
>>>>
>>>> I think Yuji’s patch is good as is.
>>>>
>>>>> I think you can use finally statement to close the connection in this 
>>>>> case.
>>>>
>>>> I don’t believe that this is possible. The handling of the connection may 
>>>> be
>>>> done in a separate thread, some time after execute() returns. I think it 
>>>> best
>>>> to just handle the specific case of REE, as it done in Yuji’s patch.
>>>>
>>>>> Your patch cannot close the connection when any other runtime exceptions 
>>>>> are occurred.
>>>>>
>>>>> However, it is concerned double close if custom handler which is 
>>>>> implemented by the user throws runtime exception after closing the 
>>>>> connection.
>>>>> IMHO, you need to check the implementation of HTTP connection and 
>>>>> dispatcher.
>>>>
>>>> -Chris.
>>>>
>>>>>
>>>>> Thanks,
>>>>>
>>>>> Yasumasa
>>>>>
>>>>>
>>>>> On 2016/11/08 18:53, KUBOTA Yuji wrote:
>>>>>> Hi Chris,
>>>>>>
>>>>>> Thank you for your review and updating this issues on JBS.
>>>>>>
>>>>>> I filed an issue:
>>>>>> https://bugs.openjdk.java.net/browse/JDK-8169358
>>>>>>
>>>>>> I don't assign to me because I'm not a committer.
>>>>>>
>>>>>> 2016-11-08 0:28 GMT+09:00 Chris Hegarty <chris.hegarty at oracle.com>:
>>>>>>>> * patch
>>>>>>>> diff --git
>>>>>>>> a/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java
>>>>>>>> b/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java
>>>>>>>> --- 
>>>>>>>> a/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java
>>>>>>>> +++ 
>>>>>>>> b/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java
>>>>>>>> @@ -442,10 +442,13 @@
>>>>>>>>                logger.log (Level.TRACE, "Dispatcher (4)", e1);
>>>>>>>>                closeConnection(conn);
>>>>>>>>            } catch (IOException e) {
>>>>>>>>                logger.log (Level.TRACE, "Dispatcher (5)", e);
>>>>>>>>                closeConnection(conn);
>>>>>>>> +            } catch (RejectedExecutionException e) {
>>>>>>>> +                logger.log (Level.TRACE, "Dispatcher (9)", e);
>>>>>>>> +                closeConnection(conn);
>>>>>>>>            }
>>>>>>>>        }
>>>>>>>>    }
>>>>>>>> _
>>>>>>>>    static boolean debug = ServerConfig.debugEnabled ();
>>>>>>>
>>>>>>>
>>>>>>> This looks ok. I wonder if some of these exceptions could be refactored
>>>>>>> into a catch clause with several exception types?
>>>>>>
>>>>>> Yes, I agree to keep simple. I updated my patch as below.
>>>>>> http://cr.openjdk.java.net/~ykubota/8169358/webrev.01/
>>>>>> Could you review it again?
>>>>>>
>>>>>> Thank you,
>>>>>> Yuji
>>>>>>>
>>>>>>> -Chris.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> * steps to reproduce
>>>>>>>> 1. java -Djava.util.logging.config.file=logging.properties
>>>>>>>> SmallHttpServer
>>>>>>>> 2. post tcp connections by curl or other ways
>>>>>>>>    e.g.: while true; do curl -XPOST --noproxy 127.0.0.1
>>>>>>>> http://127.0.0.1:8080/; done
>>>>>>>> 3. wait RejectedExecutionException occurs as below and then
>>>>>>>> SmallHttpServer stops by this issue.
>>>>>>>> ----
>>>>>>>> Nov 05, 2016 12:01:48 PM sun.net.httpserver.ServerImpl$Dispatcher run
>>>>>>>> FINER: Dispatcher (7)
>>>>>>>> java.util.concurrent.RejectedExecutionException: Task
>>>>>>>> sun.net.httpserver.ServerImpl$Exchange at 37b50d9e rejected from
>>>>>>>> java.util.concurrent.ThreadPoolExecutor at 1b3178d4[Running, pool size 
>>>>>>>> =
>>>>>>>> 1, active threads = 0, queued tasks = 0, completed tasks = 7168]
>>>>>>>>       at
>>>>>>>> java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(java.base/ThreadPoolExecutor.java:2076)
>>>>>>>>       at
>>>>>>>> java.util.concurrent.ThreadPoolExecutor.reject(java.base/ThreadPoolExecutor.java:842)
>>>>>>>>       at
>>>>>>>> java.util.concurrent.ThreadPoolExecutor.execute(java.base/ThreadPoolExecutor.java:1388)
>>>>>>>>       at
>>>>>>>> sun.net.httpserver.ServerImpl$Dispatcher.handle(jdk.httpserver/ServerImpl.java:440)
>>>>>>>>       at
>>>>>>>> sun.net.httpserver.ServerImpl$Dispatcher.run(jdk.httpserver/ServerImpl.java:405)
>>>>>>>>       at java.lang.Thread.run(java.base/Thread.java:844)
>>>>>>>> (SmallHttpServer is stopping by not closing socket)
>>>>>>>> ----
>>>>>>>>
>>>>>>>> *logging.properties
>>>>>>>> handlers = java.util.logging.ConsoleHandler
>>>>>>>> com.sun.net.httpserver.level = FINEST
>>>>>>>> java.util.logging.ConsoleHandler.level = FINEST
>>>>>>>> java.util.logging.ConsoleHandler.formatter =
>>>>>>>> java.util.logging.SimpleFormatter
>>>>>>>>
>>>>>>>> * SmallHttpServer.java
>>>>>>>> import com.sun.net.httpserver.HttpExchange;
>>>>>>>> import com.sun.net.httpserver.HttpHandler;
>>>>>>>> import com.sun.net.httpserver.HttpServer;
>>>>>>>>
>>>>>>>> import java.net.InetSocketAddress;
>>>>>>>> import java.util.Scanner;
>>>>>>>> import java.util.concurrent.LinkedBlockingQueue;
>>>>>>>> import java.util.concurrent.ThreadPoolExecutor;
>>>>>>>> import java.util.concurrent.TimeUnit;
>>>>>>>>
>>>>>>>> public class SmallHttpServer {
>>>>>>>>
>>>>>>>>   public static void main(String[] args) throws Exception {
>>>>>>>>       int POOL_SIZE = 1;
>>>>>>>>       String HOST = args.length < 1 ? "127.0.0.1" : args[0];
>>>>>>>>       int PORT = args.length < 2 ? 8080 : Integer.valueOf(args[1]);
>>>>>>>>
>>>>>>>>       // Setup a minimum thread pool to rise
>>>>>>>> RejectExecutionException in httpserver
>>>>>>>>       ThreadPoolExecutor miniHttpPoolExecutor
>>>>>>>>               = new ThreadPoolExecutor(POOL_SIZE, POOL_SIZE, 0L,
>>>>>>>> TimeUnit.MICROSECONDS,
>>>>>>>>                       new LinkedBlockingQueue<>(1), (Runnable r) -> {
>>>>>>>>                           return new Thread(r);
>>>>>>>>                       });
>>>>>>>>       HttpServer httpServer = HttpServer.create(new
>>>>>>>> InetSocketAddress(HOST, PORT), 0);
>>>>>>>>       httpServer.setExecutor(miniHttpPoolExecutor);
>>>>>>>>
>>>>>>>>       HttpHandler res200handler = (HttpExchange exchange) -> {
>>>>>>>>           exchange.sendResponseHeaders(200, 0);
>>>>>>>>           exchange.close();
>>>>>>>>       };
>>>>>>>>       httpServer.createContext("/", res200handler);
>>>>>>>>
>>>>>>>>       httpServer.start();
>>>>>>>>       // Wait stdin to exit
>>>>>>>>       Scanner in = new Scanner(System.in);
>>>>>>>>       while (in.hasNext()) {
>>>>>>>>           System.out.println(in.nextLine());
>>>>>>>>       }
>>>>>>>>       httpServer.stop(0);
>>>>>>>>       miniHttpPoolExecutor.shutdownNow();
>>>>>>>>   }
>>>>>>>> }
>>>>>>>>
>>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Yuji
>>>>>>>>
>>>>>>>
>>>>>>
>>>>
>>

Reply via email to