Package mineshafter.proxy

Source Code of mineshafter.proxy.MineProxyHandler

package mineshafter.proxy;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.Socket;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.regex.Matcher;

import mineshafter.util.Streams;

public class MineProxyHandler extends Thread {
  private DataInputStream fromClient;
  private DataOutputStream toClient;
  private Socket connection;
 
  private MineProxy proxy;
 
  private static String[] BLACKLISTED_HEADERS = new String[]{"Connection", "Proxy-Connection", "Transfer-Encoding"};
 
  public MineProxyHandler(MineProxy proxy, Socket conn) throws IOException {
    setName("MineProxyHandler Thread");
   
    this.proxy = proxy;
   
    connection = conn;
    fromClient = new DataInputStream(conn.getInputStream());
    toClient = new DataOutputStream(conn.getOutputStream());
  }
 
  public void run() {
    HashMap<String, String> headers = new HashMap<String, String>();
   
    // Read the incoming request
    String[] requestLine = readUntil(fromClient, '\n').split(" ");
    String method = requestLine[0].trim().toUpperCase();
    String url = requestLine[1].trim();
   
    System.out.println("Request: " + method + " " + url);
   
    // Read the incoming headers
    //System.out.println("Headers:");
    String header;
    do {
      header = readUntil(fromClient, '\n').trim();
      //System.out.println("H: " + header + ", " + header.length());
      int splitPoint = header.indexOf(':');
      if (splitPoint != -1) {
        headers.put(header.substring(0, splitPoint).toLowerCase().trim(), header.substring(splitPoint + 1).trim());
      }
    } while (header.length() > 0);
   
    Matcher skinMatcher = MineProxy.SKIN_URL.matcher(url);
    Matcher cloakMatcher = MineProxy.CLOAK_URL.matcher(url);
    Matcher getversionMatcher = MineProxy.GETVERSION_URL.matcher(url);
    Matcher joinserverMatcher = MineProxy.JOINSERVER_URL.matcher(url);
   
    byte[] data = null;
    String contentType = null;
    String params;
   
    if (skinMatcher.matches()) {
      System.out.println("Skin");
     
      String username = skinMatcher.group(1);
      if(proxy.skinCache.containsKey(username)) { // Is the skin in the cache?
        System.out.println("Skin from cache");
       
        data = proxy.skinCache.get(username); // Then get it from there
      } else {
        url = "http://" + MineProxy.authServer + "/mcapi/skin/" + username + ".png";
        System.out.println("To: " + url);
       
        data = getRequest(url); // Then get it...
        System.out.println("Response length: " + data.length);
       
        proxy.skinCache.put(username, data); // And put it in there
      }
     
    } else if (cloakMatcher.matches()) {
      System.out.println("Cloak");
     
      String username = cloakMatcher.group(1);
      if(proxy.cloakCache.containsKey(username)) {
        System.out.println("Cloak from cache");
        data = proxy.cloakCache.get(username);
      } else {
        url = "http://" + MineProxy.authServer + "/mcapi/cloak/" + username + ".png";
        System.out.println("To: " + url);
       
        data = getRequest(url);
        System.out.println("Response length: " + data.length);
       
        proxy.cloakCache.put(username, data);
      }
     
    } else if (getversionMatcher.matches()) {
      System.out.println("GetVersion");
     
      url = "http://" + MineProxy.authServer + "/mcapi/getversion?proxy=" + proxy.version;
      System.out.println("To: " + url);
     
      try {
        int postlen = Integer.parseInt(headers.get("content-length"));
        char[] postdata = new char[postlen];
        InputStreamReader reader = new InputStreamReader(fromClient);
        reader.read(postdata);
       
        data = postRequest(url, new String(postdata), "application/x-www-form-urlencoded");
        //System.out.println(new String(postdata));
        //System.out.println(new String(data));
      } catch(IOException e) {
        System.out.println("Unable to read POST data from getversion request");
        e.printStackTrace();
      }
     
    } else if (joinserverMatcher.matches()) {
      System.out.println("JoinServer");
     
      params = joinserverMatcher.group(1);
      url = "http://" + MineProxy.authServer + "/game/joinserver.jsp" + params;
      System.out.println("To: " + url);
     
      data = getRequest(url);
      contentType = "text/plain";
      // TODO There may be a bug here, keeps causing a hang in the MC thread that tries to read the data from it
     
    } else {
      System.out.println("No handler. Piping.");
     
      try {
        if(!url.startsWith("http://") && !url.startsWith("https://")) {
          url = "http://" + url;
        }
        URL u = new URL(url);
        if(method.equals("CONNECT")) {
          int port = u.getPort();
          if(port == -1) port = 80;
          Socket sock = new Socket(u.getHost(), port);
         
          Streams.pipeStreamsActive(sock.getInputStream(), toClient);
          Streams.pipeStreamsActive(connection.getInputStream(), sock.getOutputStream());
          // TODO Maybe put POST here instead, less to do, but would it work?
         
        } else if(method.equals("GET") || method.equals("POST")) {
          HttpURLConnection c = (HttpURLConnection) u.openConnection(Proxy.NO_PROXY);
          c.setRequestMethod(method);
          boolean post = method.equals("POST");
         
          for(String k : headers.keySet()) {
            c.setRequestProperty(k, headers.get(k)); // TODO Might need to blacklist these as well later
          }
         
          if (post) {
            c.setDoInput(true);
            c.setDoOutput(true);
            c.setUseCaches(false);
            c.connect();
            int postlen = Integer.parseInt(headers.get("content-length"));
            byte[] postdata = new byte[postlen];
            fromClient.read(postdata);
           
            DataOutputStream os = new DataOutputStream(c.getOutputStream());
            os.write(postdata);
          }
          //Collect the headers from the server and retransmit them
          int responseCode = c.getResponseCode();
          String res = "HTTP/1.0 " + responseCode + " " + c.getResponseMessage() + "\r\n";
          res += "Connection: close\r\nProxy-Connection: close\r\n";
         
          Map<String, List<String>> h = c.getHeaderFields();
          headerloop:
          for(String k : h.keySet()) {
            if(k == null) continue;
            k = k.trim();
            for(String forbiddenHeader : BLACKLISTED_HEADERS) {
              if(k.equalsIgnoreCase(forbiddenHeader)) continue headerloop;
            }
           
            List<String> vals = h.get(k);
            for(String v : vals) {
              res += k + ": " + v + "\r\n";
            }
          }
          res += "\r\n";
         
          //System.out.println(res);
          int size = -1;
          if (responseCode / 100 != 5) {
            toClient.writeBytes(res);
            size = Streams.pipeStreams(c.getInputStream(), toClient);
          }
         
          toClient.close();
          connection.close();
         
          System.out.println("Piping finished, data size: " + size);
         
        } else if (method.equals("HEAD")) {
          HttpURLConnection c = (HttpURLConnection) u.openConnection(Proxy.NO_PROXY);
          c.setRequestMethod("HEAD");
         
          for (String k : headers.keySet()) {
            c.setRequestProperty(k, headers.get(k));
          }
         
          String res = "HTTP/1.0 " + c.getResponseCode() + " " + c.getResponseMessage() + "\r\n";
          res += "Proxy-Connection: close\r\n";
         
          java.util.Map<String, java.util.List<String>> h = c.getHeaderFields();
          for (String k : h.keySet()) {
            if(k == null) continue;
            java.util.List<String> vals = h.get(k);
            for(String v : vals) {
              res += k + ": " + v + "\r\n";
            }
          }
          res += "\r\n";
         
          //System.out.println(res);
         
          toClient.writeBytes(res); // TODO Occasional exception socket write error
          toClient.close();
          connection.close();
         
        } else {
          System.out.println("UNEXPECTED REQUEST TYPE: " + method);
        }
       
      } catch (Exception e) {
        e.printStackTrace();
      }
     
      return;
    }
   
    try {
      if (data != null) {
        toClient.writeBytes("HTTP/1.0 200 OK\r\nConnection: close\r\nProxy-Connection: close\r\nContent-Length: " + data.length + "\r\n");
        if (contentType != null) {
          toClient.writeBytes("Content-Type: " + contentType + "\r\n");
        }
        toClient.writeBytes("\r\n");
        toClient.write(data);
        toClient.flush();
      }
      fromClient.close();
      toClient.close();
      connection.close();
      //System.out.println(data.length);
      //System.out.println(new String(data));
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
 
  public static byte[] getRequest(String url) {
    try {
      HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(Proxy.NO_PROXY);
      conn.setUseCaches(false);
      conn.setInstanceFollowRedirects(false);
      Map<String, List<String>> requestHeaders = conn.getRequestProperties();
      int code = conn.getResponseCode();
     
      if(code == 301 || code == 302 || code == 303) {
        System.out.println("Java didn't redirect automatically, going manual: " + Integer.toString(code));
        String l = conn.getHeaderField("location").trim();
        System.out.println("Manual redirection to: " + l);
        return getRequest(l);
      }
     
      System.out.println("Response: " + code);
      if(code == 403) {
        String s = "403 from req to " + url + "\nRequest headers:\n";
       
        for (String k : requestHeaders.keySet()) {
          if(k == null) continue;
          java.util.List<String> vals = requestHeaders.get(k);
          for(String v : vals) {
            s += k + ": " + v + "\n";
          }
        }
       
        s += "Response headers:\n";
        Map<String, List<String>> responseHeaders = conn.getHeaderFields();
        for (String k : responseHeaders.keySet()) {
          if(k == null) continue;
          java.util.List<String> vals = responseHeaders.get(k);
          for(String v : vals) {
            s += k + ": " + v + "\n";
          }
        }
       
        System.out.println(s);
        System.out.println("Contents:\n" + new String(grabData(conn.getErrorStream())));
      }
     
      if(code / 100 == 4) {
        return new byte[0];
      }
      BufferedInputStream in = new BufferedInputStream(conn.getInputStream());
      return grabData(in);
     
    } catch (MalformedURLException e) {
      System.out.println("Bad URL in getRequest:");
      e.printStackTrace();
    } catch (IOException e) {
      System.out.println("IO error during a getRequest:");
      e.printStackTrace();
    }
   
    return new byte[0];
  }
 
  public static byte[] postRequest(String url, String postdata, String contentType) {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    OutputStreamWriter writer = new OutputStreamWriter(out);
    //System.out.println("Postdata: " + postdata);
   
    try {
      writer.write(postdata);
      writer.flush();
    } catch(IOException e) {
      e.printStackTrace();
    }
   
    byte[] rd = postRequest(url, out.toByteArray(), contentType);
   
    return rd;
  }
 
  public static byte[] postRequest(String url, byte[] postdata, String contentType) {
    try {
      URL u = new URL(url);
     
      HttpURLConnection c = (HttpURLConnection) new URL(url).openConnection(Proxy.NO_PROXY);
      c.setDoOutput(true);
      c.setRequestMethod("POST");
     
      //System.out.println("Postdata_bytes: " + new String(postdata));
     
      c.setRequestProperty("Host", u.getHost());
      c.setRequestProperty("Content-Length", Integer.toString(postdata.length));
      c.setRequestProperty("Content-Type", contentType);
     
      BufferedOutputStream out = new BufferedOutputStream(c.getOutputStream());
      out.write(postdata);
      out.flush();
      out.close();
     
      byte[] data = grabData(new BufferedInputStream(c.getInputStream()));
      return data;
     
    } catch(java.net.UnknownHostException e) {
      System.out.println("Unable to resolve remote host, returning null");
      //e.printStackTrace();
    } catch (MalformedURLException e) {
      System.out.println("Bad URL when doing postRequest:");
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
   
    return null;
  }
 
  public static byte[] grabData(InputStream in) {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
   
    while(true) {
      int len;
      try {
        len = in.read(buffer);
        if(len == -1) break;
      } catch(IOException e) {
        break;
      }
      out.write(buffer, 0, len);
    }
   
    return out.toByteArray();
  }
 
  public static String readUntil(DataInputStream is, String endSequence) {
    return readUntil(is, endSequence.getBytes());
  }
 
  public static String readUntil(DataInputStream is, char endSequence) {
    return readUntil(is, new byte[] {(byte) endSequence});
  }
 
  public static String readUntil(DataInputStream is, byte endSequence) {
    return readUntil(is, new byte[] {endSequence});
  }
 
  public static String readUntil(DataInputStream is, byte[] endSequence) { // If there is an edge case, make sure we can see it
    ByteArrayOutputStream out = new ByteArrayOutputStream();
   
    String r = null;
   
    try {
      int i = 0;
      while (true) {
        boolean end = false;
        byte b = is.readByte(); // Read a byte
        if (b == endSequence[i]) { // If equal to current byte of endSequence
          if (i == endSequence.length - 1) {
            end = true; // If we hit the end of endSequence, we're done
          }
          i++; // Increment for next round
        } else {
          i = 0; // Reset
        }
       
        out.write(b);
       
        if (end) break;
      }
    } catch (IOException ex) {
      System.out.println("readUntil unable to read from InputStream, endSeq: " + new String(endSequence));
      ex.printStackTrace();
    }
   
    try {
      r = out.toString("UTF-8");
    } catch (java.io.UnsupportedEncodingException ex) {
      System.out.println("readUntil unable to encode data: " + out.toString());
      ex.printStackTrace();
    }
   
    return r;
  }
}
TOP

Related Classes of mineshafter.proxy.MineProxyHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.