From be29799f5afc270cd123d739ae53bb3428d0f6d1 Mon Sep 17 00:00:00 2001 From: md_5 Date: Fri, 5 Jul 2013 09:29:28 +1000 Subject: [PATCH] [Beta] Implement own HTTP client for online mode checks, instead of asynchttpclient --- api/pom.xml | 6 ---- .../java/net/md_5/bungee/api/ProxyServer.java | 10 ------ .../main/java/net/md_5/bungee/BungeeCord.java | 10 ------ .../bungee/connection/InitialHandler.java | 34 +++++++++---------- .../java/net/md_5/bungee/http/HttpClient.java | 28 +++++++++------ .../net/md_5/bungee/http/HttpHandler.java | 31 +++++++++++++++-- .../net/md_5/bungee/http/HttpInitializer.java | 7 +++- .../net/md_5/bungee/log/LogDispatcher.java | 2 +- 8 files changed, 69 insertions(+), 59 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 0a8ea195..4d1e24d1 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -25,12 +25,6 @@ 14.0.1 compile - - com.ning - async-http-client - 1.7.17 - compile - net.md-5 bungeecord-event diff --git a/api/src/main/java/net/md_5/bungee/api/ProxyServer.java b/api/src/main/java/net/md_5/bungee/api/ProxyServer.java index f7464571..9c4720ad 100644 --- a/api/src/main/java/net/md_5/bungee/api/ProxyServer.java +++ b/api/src/main/java/net/md_5/bungee/api/ProxyServer.java @@ -2,7 +2,6 @@ package net.md_5.bungee.api; import net.md_5.bungee.api.plugin.PluginManager; import com.google.common.base.Preconditions; -import com.ning.http.client.AsyncHttpClient; import java.io.File; import java.net.InetSocketAddress; import java.util.Collection; @@ -218,15 +217,6 @@ public abstract class ProxyServer */ public abstract TaskScheduler getScheduler(); - /** - * Gets the the web client used by this proxy to facilitate making web - * requests. Care should be taken to ensure that all operations are non - * blocking where applicable. - * - * @return the server's {@link AsyncHttpClient} instance - */ - public abstract AsyncHttpClient getHttpClient(); - /** * Get the current number of connected users. The default implementation is * more efficient than {@link #getPlayers()} as it does not take a lock or diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index 66380ff0..22bcd4a3 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -6,10 +6,6 @@ import net.md_5.bungee.reconnect.SQLReconnectHandler; import net.md_5.bungee.scheduler.BungeeScheduler; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.gson.Gson; -import com.ning.http.client.AsyncHttpClient; -import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; -import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelException; @@ -123,11 +119,6 @@ public class BungeeCord extends ProxyServer @Getter private final TaskScheduler scheduler = new BungeeScheduler(); @Getter - private final AsyncHttpClient httpClient = new AsyncHttpClient( - new NettyAsyncHttpProvider( - new AsyncHttpClientConfig.Builder().setAsyncHttpClientProviderConfig( - new NettyAsyncHttpProviderConfig().addProperty( NettyAsyncHttpProviderConfig.BOSS_EXECUTOR_SERVICE, executors ) ).setExecutorService( executors ).build() ) ); - @Getter private ConsoleReader consoleReader; @Getter private final Logger logger; @@ -302,7 +293,6 @@ public class BungeeCord extends ProxyServer { BungeeCord.this.isRunning = false; - httpClient.close(); executors.shutdown(); stopListeners(); diff --git a/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java b/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java index 21e258d5..fab717f6 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java @@ -1,14 +1,11 @@ package net.md_5.bungee.connection; import com.google.common.base.Preconditions; -import com.ning.http.client.AsyncCompletionHandler; -import com.ning.http.client.Response; import io.netty.util.concurrent.ScheduledFuture; import java.io.DataInput; import java.math.BigInteger; import java.net.InetSocketAddress; import java.net.URLEncoder; -import java.security.GeneralSecurityException; import java.security.MessageDigest; import java.util.ArrayList; import java.util.List; @@ -33,6 +30,7 @@ import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.event.LoginEvent; import net.md_5.bungee.api.event.PostLoginEvent; import net.md_5.bungee.api.event.ProxyPingEvent; +import net.md_5.bungee.http.HttpClient; import net.md_5.bungee.netty.HandlerBoss; import net.md_5.bungee.netty.ChannelWrapper; import net.md_5.bungee.netty.CipherDecoder; @@ -258,35 +256,37 @@ public class InitialHandler extends PacketHandler implements PendingConnection String encodedHash = URLEncoder.encode( new BigInteger( sha.digest() ).toString( 16 ), "UTF-8" ); String authURL = "http://session.minecraft.net/game/checkserver.jsp?user=" + encName + "&serverId=" + encodedHash; - bungee.getHttpClient().prepareGet( authURL ).execute( new AsyncCompletionHandler() + + Callback handler = new Callback() { @Override - public Response onCompleted(Response response) throws Exception + public void done(String result, Throwable error) { - if ( "YES".equals( response.getResponseBody() ) ) + if ( error == null ) { - finish(); + if ( "YES".equals( result ) ) + { + finish(); + } else + { + disconnect( "Not authenticated with Minecraft.net" ); + } } else { - disconnect( "Not authenticated with Minecraft.net" ); + disconnect( bungee.getTranslation( "mojang_fail" ) ); + bungee.getLogger().log( Level.SEVERE, "Error authenticating " + getName() + " with minecraft.net", error ); } - return response; } + }; - @Override - public void onThrowable(Throwable t) - { - disconnect( bungee.getTranslation( "mojang_fail" ) ); - bungee.getLogger().log( Level.SEVERE, "Error authenticating " + getName() + " with minecraft.net", t ); - } - } ); + HttpClient.get( authURL, ch.getHandle().eventLoop(), handler ); } else { finish(); } } - private void finish() throws GeneralSecurityException + private void finish() { // Check for multiple connections ProxiedPlayer old = bungee.getPlayer( handshake.getUsername() ); diff --git a/proxy/src/main/java/net/md_5/bungee/http/HttpClient.java b/proxy/src/main/java/net/md_5/bungee/http/HttpClient.java index 65d3c246..c4ffc539 100644 --- a/proxy/src/main/java/net/md_5/bungee/http/HttpClient.java +++ b/proxy/src/main/java/net/md_5/bungee/http/HttpClient.java @@ -4,7 +4,8 @@ import com.google.common.base.Preconditions; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; -import io.netty.channel.EventLoopGroup; +import io.netty.channel.ChannelOption; +import io.netty.channel.EventLoop; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.http.DefaultHttpRequest; @@ -13,21 +14,22 @@ import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpVersion; import java.net.URI; -import lombok.RequiredArgsConstructor; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import net.md_5.bungee.api.Callback; -@RequiredArgsConstructor +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class HttpClient { - private final EventLoopGroup eventLoop; + public static int TIMEOUT = 5000; - public static void main(String[] args) + public static void get(String url, EventLoop eventLoop, final Callback callback) { - new HttpClient( new NioEventLoopGroup( 1 ) ).get( "https://session.minecraft.net/" ); - } + Preconditions.checkNotNull( url, "url" ); + Preconditions.checkNotNull( eventLoop, "eventLoop" ); + Preconditions.checkNotNull( callback, "callBack" ); - public void get(String url) - { final URI uri = URI.create( url ); Preconditions.checkNotNull( uri.getScheme(), "scheme" ); @@ -56,16 +58,20 @@ public class HttpClient { if ( future.isSuccess() ) { - HttpRequest request = new DefaultHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.GET, uri.getRawPath() ); + String path = uri.getRawPath() + ( ( uri.getRawQuery() == null ) ? "" : "?" + uri.getRawQuery() ); + + HttpRequest request = new DefaultHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.GET, path ); request.headers().set( HttpHeaders.Names.HOST, uri.getHost() ); future.channel().write( request ); } else { + callback.done( null, future.cause() ); } } }; - new Bootstrap().channel( NioSocketChannel.class ).group( eventLoop ).handler( new HttpInitializer( ssl ) ).remoteAddress( uri.getHost(), port ).connect().addListener( future ); + new Bootstrap().channel( NioSocketChannel.class ).group( eventLoop ).handler( new HttpInitializer( callback, ssl ) ). + option( ChannelOption.CONNECT_TIMEOUT_MILLIS, TIMEOUT ).remoteAddress( uri.getHost(), port ).connect().addListener( future ); } } diff --git a/proxy/src/main/java/net/md_5/bungee/http/HttpHandler.java b/proxy/src/main/java/net/md_5/bungee/http/HttpHandler.java index dba073b4..c7e4dcfc 100644 --- a/proxy/src/main/java/net/md_5/bungee/http/HttpHandler.java +++ b/proxy/src/main/java/net/md_5/bungee/http/HttpHandler.java @@ -8,28 +8,53 @@ import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.LastHttpContent; import java.nio.charset.Charset; +import lombok.RequiredArgsConstructor; +import net.md_5.bungee.api.Callback; +@RequiredArgsConstructor public class HttpHandler extends SimpleChannelInboundHandler { + private final Callback callback; + private final StringBuilder buffer = new StringBuilder(); + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception + { + try + { + callback.done( null, cause ); + } finally + { + ctx.channel().close(); + } + } + @Override protected void messageReceived(ChannelHandlerContext ctx, HttpObject msg) throws Exception { if ( msg instanceof HttpResponse ) { HttpResponse response = (HttpResponse) msg; - if ( response.getStatus() != HttpResponseStatus.OK ) + if ( response.getStatus().code() != 200 ) { + throw new IllegalStateException( "Expected HTTP response 200 OK, got " + response.getStatus() ); } } if ( msg instanceof HttpContent ) { HttpContent content = (HttpContent) msg; - String s = content.content().toString( Charset.forName( "UTF-8" ) ); + buffer.append( content.content().toString( Charset.forName( "UTF-8" ) ) ); if ( msg instanceof LastHttpContent ) { - ctx.channel().close(); + try + { + callback.done( buffer.toString(), null ); + } finally + { + ctx.channel().close(); + } } } } diff --git a/proxy/src/main/java/net/md_5/bungee/http/HttpInitializer.java b/proxy/src/main/java/net/md_5/bungee/http/HttpInitializer.java index 19679107..327bf89d 100644 --- a/proxy/src/main/java/net/md_5/bungee/http/HttpInitializer.java +++ b/proxy/src/main/java/net/md_5/bungee/http/HttpInitializer.java @@ -4,20 +4,25 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.handler.codec.http.HttpClientCodec; import io.netty.handler.ssl.SslHandler; +import io.netty.handler.timeout.ReadTimeoutHandler; +import java.util.concurrent.TimeUnit; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.TrustManager; import lombok.RequiredArgsConstructor; +import net.md_5.bungee.api.Callback; @RequiredArgsConstructor public class HttpInitializer extends ChannelInitializer { + private final Callback callback; private final boolean ssl; @Override protected void initChannel(Channel ch) throws Exception { + ch.pipeline().addLast( "timeout", new ReadTimeoutHandler( HttpClient.TIMEOUT, TimeUnit.MILLISECONDS ) ); if ( ssl ) { SSLContext context = SSLContext.getInstance( "TLS" ); @@ -32,6 +37,6 @@ public class HttpInitializer extends ChannelInitializer ch.pipeline().addLast( "ssl", new SslHandler( engine ) ); } ch.pipeline().addLast( "http", new HttpClientCodec() ); - ch.pipeline().addLast( "handler", new HttpHandler() ); + ch.pipeline().addLast( "handler", new HttpHandler( callback ) ); } } diff --git a/proxy/src/main/java/net/md_5/bungee/log/LogDispatcher.java b/proxy/src/main/java/net/md_5/bungee/log/LogDispatcher.java index 2ff69b2f..f1ccd4f6 100644 --- a/proxy/src/main/java/net/md_5/bungee/log/LogDispatcher.java +++ b/proxy/src/main/java/net/md_5/bungee/log/LogDispatcher.java @@ -12,7 +12,7 @@ public class LogDispatcher extends Thread public LogDispatcher(BungeeLogger logger) { - super( "BungeeCord Logger Thread - " + logger ); + super( "BungeeCord Logger Thread" ); this.logger = logger; }