{"action":"created","issue":{"url":"https://api.github.com/repos/jetty-project/jetty-alpn/issues/8","labels_url":"https://api.github.com/repos/jetty-project/jetty-alpn/issues/8/labels{/name}","comments_url":"https://api.github.com/repos/jetty-project/jetty-alpn/issues/8/comments","events_url":"https://api.github.com/repos/jetty-project/jetty-alpn/issues/8/events","html_url":"https://github.com/jetty-project/jetty-alpn/issues/8","id":70540784,"number":8,"title":"ALPN API should allow throwing IOException or SSLException","user":{"login":"ejona86","id":2811396,"avatar_url":"https://avatars.githubusercontent.com/u/2811396?v=3","gravatar_id":"","url":"https://api.github.com/users/ejona86","html_url":"https://github.com/ejona86","followers_url":"https://api.github.com/users/ejona86/followers","following_url":"https://api.github.com/users/ejona86/following{/other_user}","gists_url":"https://api.github.com/users/ejona86/gists{/gist_id}","starred_url":"https://api.github.com/users/ejona86/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ejona86/subscriptions","organizations_url":"https://api.github.com/users/ejona86/orgs","repos_url":"https://api.github.com/users/ejona86/repos","events_url":"https://api.github.com/users/ejona86/events{/privacy}","received_events_url":"https://api.github.com/users/ejona86/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":16,"created_at":"2015-04-23T23:36:39Z","updated_at":"2015-05-21T22:22:54Z","closed_at":null,"body":"On its foundation, the problem is simple: in the event that protocol selection fails, an ALPN.Provider wants to throw an exception. An SSLException is attractive as existing error handling can appropriately deal with the exception.\r\n\r\n## Netty\r\n\r\nNetty is [currently throwing SSLHandshakeException](https://github.com/netty/netty/blob/4.1/handler/src/main/java/io/netty/handler/ssl/JdkBaseApplicationProtocolNegotiator.java#L205) if protocol selection fails within ServerProvider.select() or ClientProvider.selected(). I initially thought that Netty was doing something unreasonable, as it uses [Generic tricks/Unsafe](https://github.com/netty/netty/blob/772482559db96598be0663dde7fa8221b2e69d04/common/src/main/java/io/netty/util/internal/PlatformDependent.java#L204) to [throw the checked exception from select()](https://github.com/netty/netty/blob/4.1/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java#L69).\r\n\r\nHowever, due to the [Sun SSL Handler](http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/sun/security/ssl/Handshaker.java/#1344) all exceptions thrown are wrapped, but a select few (including SSLHandshakeException) maintain their type.\r\n\r\n## Jetty\r\n\r\nJetty has a filter that only exposes \"system classes\" from the bootstrap class loader. Although it is supposed to be possible to configure what classes are \"system classes,\" we had considerable trouble getting it to work. Even if we figured out a recipe to get Jetty working, Jetty is not the only container performing such tricks. Most importantly, the failure mode is that the ALPN-using application code loads a _different_ ALPN class than the one that exists in the bootstrap class loader. This means that registering the ALPN provider appears to work and we can verify that the ALPNExtension is loaded, but nothing functions because ALPN is no longer a true singleton.\r\n\r\nA much more reliable method for users that Just Works™ (although uglier for library developers) is to [use reflection to get the ALPN Class from the bootstrap class loader (by passing \"null\" as the ClassLoader)](https://github.com/grpc/grpc-java/blob/master/netty/src/main/java/io/grpc/transport/netty/Http2Negotiator.java#L291). This will succeed if and only if ALPN boot is in the bootclasspath. Since ALPN.ServerProvider and similar may be hidden just like ALPN, you have to use java.lang.reflect.Proxy to implement them.\r\n\r\n## Netty + Jetty\r\n\r\nNetty's current hack works today, but it is unable to be used with Proxy, and thus is harder to run within Jetty and other containers. Proxy notices that a checked exception was thrown from a method not throwing checked exceptions and wraps the SSLHandshakeException in UndeclaredThrowableException. The UndeclaredThrowableException is then subsequently wrapped in a RuntimeException by the SSL code.\r\n\r\nI have investigated fixing Netty to no longer throw a checked exception and no longer throw an exception at all, but these did not prove very feasible. I have investigated further hacks on top of the current set, and although there are some options, they are _highly_ unpalatable.\r\n\r\nI've already confirmed that ALPN boot would need no changes to support checked exceptions from select()/selected() Provider methods. Given the other constraints involved it seems the best approach is to change the ALPN API to allow throwing SSLException."},"comment":{"url":"https://api.github.com/repos/jetty-project/jetty-alpn/issues/comments/104439108","html_url":"https://github.com/jetty-project/jetty-alpn/issues/8#issuecomment-104439108","issue_url":"https://api.github.com/repos/jetty-project/jetty-alpn/issues/8","id":104439108,"user":{"login":"ejona86","id":2811396,"avatar_url":"https://avatars.githubusercontent.com/u/2811396?v=3","gravatar_id":"","url":"https://api.github.com/users/ejona86","html_url":"https://github.com/ejona86","followers_url":"https://api.github.com/users/ejona86/followers","following_url":"https://api.github.com/users/ejona86/following{/other_user}","gists_url":"https://api.github.com/users/ejona86/gists{/gist_id}","starred_url":"https://api.github.com/users/ejona86/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ejona86/subscriptions","organizations_url":"https://api.github.com/users/ejona86/orgs","repos_url":"https://api.github.com/users/ejona86/repos","events_url":"https://api.github.com/users/ejona86/events{/privacy}","received_events_url":"https://api.github.com/users/ejona86/received_events","type":"User","site_admin":false},"created_at":"2015-05-21T22:22:53Z","updated_at":"2015-05-21T22:22:53Z","body":"My exact problem was the intersection of multiple problems and pre-existing workarounds preventing using ALPN in a client-provided library running in Jetty. I originally worried that it was not a Jetty-specific problem, but now believe it may only impact Jetty and WildFly.\r\n\r\nThe [Jetty bug](https://bugs.eclipse.org/bugs/show_bug.cgi?id=467929) I filed would eventually take care of Jetty. In the mean time it seems we'll recommend our users to use a WEB-INF/jetty-env.xml. WildFly would require a jboss-deployment-structure.xml for now as well.\r\n\r\nThis entire exercise exposed that the ALPN API _should_ allow throwing an SSLException, as there aren't really any alternatives when ALPN protocol negotiation fails such that you can trigger no_application_protocol _and_ communicate the error locally. I've not found a bug tracker for alpn-api (e.g., no component in Eclipse), but it did seem that such a change would impact alpn_boot most directly."}}