Hi Christoph,

Thank you for your review and comment!

2018-03-06 20:38 GMT+09:00 Langer, Christoph <christoph.lan...@sap.com>:
> I had a look and to me it seems safe to do like webrev.03 suggests. That is, 
> remove the throws clause. As Daniel pointed out, it seems that all callers of 
> the "handle" method would do merely the same. The only thing I'm not sure 
> about is the CancelledKeyException caught in line 413. In that case no 
> exception would be logged currently. With your change, it would now inside 
> "handle". Maybe you want to handle a CancelledKeyException explicitly in 
> "handle" now and suppress the log?

SelectionKey::isReadable might throw CancelledKeyException in line
397, so the logging in line 413 still work except the exceptions from
inside "handle". I want to handle unexpected exceptions and errors
from "handle" to minimize the risk of connection leak. Separating
logging also would help developers.

> What tests did you run?

I've tested test/jdk/com/sun/net/httpserver and passed.
I can not access Mach5 because I'm not a committer.

> BTW: you could remove line 396: ' boolean closed;' while you are touching 
> this file. It is not needed.

Nice catch! I removed this unused variable.
http://cr.openjdk.java.net/~ykubota/8169358/webrev.04/

Best regards
Yuji

> Best regards
> Christoph
>
>> -----Original Message-----
>> From: net-dev [mailto:net-dev-boun...@openjdk.java.net] On Behalf Of
>> KUBOTA Yuji
>> Sent: Donnerstag, 1. März 2018 12:41
>> To: OpenJDK Network Dev list <net-dev@openjdk.java.net>
>> Cc: Yasumasa Suenaga <yasue...@gmail.com>
>> Subject: Re: httpserver does not close connections when
>> RejectedExecutionException occurs
>>
>> Hi all,
>>
>> Could you please review my patch(s)?
>>
>> Thanks,
>> Yuji
>>
>> 2018-02-20 14:21 GMT+09:00 KUBOTA Yuji <kubota.y...@gmail.com>:
>> > Hi Daniel,
>> >
>> > Thank you for your comment.
>> >
>> > Dispatcher is package-private class and handle method is called at
>> > only this file in the package (sun.net.httpserver), and all call sites
>> > look like to handle exception suitably. So we can remove `throws
>> > IOException` clause without modifying the call site logic as like
>> > webrev.03.
>> > http://cr.openjdk.java.net/~ykubota/8169358/webrev.03
>> >
>> > However, I could not find whether can I change a signature of public
>> > method without specified steps. If we need to write CSR to remove
>> > `throws IOException` clause, we should remove the clause by other
>> > issue. And I want to commit webrev.02  at this issue.
>> > http://cr.openjdk.java.net/~ykubota/8169358/webrev.02
>> >
>> > I'd like to get your thoughts on that.
>> >
>> > P.S. I'm an author, not a committer, so I cannot access Mach5.
>> >
>> > Thanks,
>> > Yuji
>> >
>> > 2018-02-17 1:11 GMT+09:00 Daniel Fuchs <daniel.fu...@oracle.com>:
>> >> Hi,
>> >>
>> >> On the surface I'd say that this change looks reasonable.
>> >> However, handle is declared to throw IOException, and
>> >> with this change it is guaranteed to never throw even
>> >> RuntimeException.
>> >>
>> >> It seems that the code that calls handle() - at least in
>> >> this file, has some logic to handle IOException - or
>> >> other exception possibly thrown by Dispatcher::handle,
>> >> which as far as I can see is not doing much more than what
>> >> closeConnection does. So it looks as if calling
>> >> closeConnection in handle() instead of throwing could be OK.
>> >>
>> >> However it would be good to at least try to figure out
>> >> whether there are any other call sites for Dispatcher::handle,
>> >> validate that no longer throwing will not modify the call site
>> >> logic, and possibly investigate if the 'throws IOException' clause
>> >> can be removed from Dispatcher::handle (that is: look
>> >> whether Dispatcher is exposed and/or can be subclassed and
>> >> if there are any existing subclasses).
>> >>
>> >> best regards,
>> >>
>> >> -- daniel
>> >>
>> >>
>> >> On 16/02/2018 15:29, KUBOTA Yuji wrote:
>> >>>
>> >>> 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/ThreadPoolExecut
>> or.java:842)
>> >>>>>>>>>>>        at
>> >>>>>>>>>>>
>> >>>>>>>>>>>
>> java.util.concurrent.ThreadPoolExecutor.execute(java.base/ThreadPoolExec
>> utor.java:1388)
>> >>>>>>>>>>>        at
>> >>>>>>>>>>>
>> >>>>>>>>>>>
>> sun.net.httpserver.ServerImpl$Dispatcher.handle(jdk.httpserver/ServerImp
>> l.java:440)
>> >>>>>>>>>>>        at
>> >>>>>>>>>>>
>> >>>>>>>>>>>
>> sun.net.httpserver.ServerImpl$Dispatcher.run(jdk.httpserver/ServerImpl.ja
>> va: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