Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

227
LINES

< > BotCompany Repo | #1002822 // HTTP Proxy (with partial close, OK)

JavaX source code [tags: use-pretranspiled] - run with: x30.jar

Libraryless. Click here for Pure Java version (5434L/32K/107K).

!7

static S vmArgs = "-XX:+PrintGC -Xmx32m";
static boolean debug = false;

static int port = 80;
static S forwardServer = "localhost";

static Map<S, Integer> forwardMap = litmap(
  "thedevchannel.com", 3000,
  "default", 8081);
  
static L<S> blockedIPs = litlist("41.193.22.107");

p {
  // Safety Rebooter - to hold up thedevchannel.com and ai1.lol when admin sleeps!
  
  thread "Rebooter" {
    sleepSeconds(60*60*24);
    nohupJavax(programID(), vmArgs);
    System.exit(0);
  }
  
  // turn off memory leak
  
  noPrintLog();
  
  // Some regular GC to see accurate mem stats
  
  thread "Auto GC" {
    while true {
      sleepSeconds(60*10);
      System.gc();
    }
  }
  
  // Now for the actual server...
  
  final ServerSocket serverSocket = new ServerSocket(port);

  Thread thread = new Thread("HTTP Proxy Accept Port " + port) { public void run() {
   try {
    while (true) {
      try {
        final Socket s = serverSocket.accept();
        
        /*thread "Lister" {
          sleepSeconds(5);
          listThreads();
        }*/
        
        final S client = dropPrefix("/", s.getInetAddress().toString()); // Hmm... how to get the actual IP properly?
        String threadName = "PROXY: Handling client " + client;
        
        if (blockedIPs.contains(client)) {
          print("Blocked IP!! " + client);
          pcall { s.close(); }
          continue;
        }

        Thread t2 = new Thread(threadName) {
          public void run() ctex {
            Socket outSocket = null;
            final new AtomicLong transmitted;
            final new AtomicLong outTransmitted;
            try {
              print("HTTP Proxy Incoming!");
              
              final OutputStream out = s.getOutputStream();
              final InputStream in = s.getInputStream();
              
              // collect headers
              
              new ByteArrayOutputStream headersOut;
              //BufferedReader headerReader = new BufferedReader(new InputStreamReader(in, "US-ASCII"), 1);
              boolean forwardedFor = false;
              S host = null;
              while (true) {
                S line = readHeaderLine(in);
                if (line == null) ret;
                print("Header line read: " + quote(line));
                
                if (startsWithIgnoreCase(line, "Host:"))
                  host = dropPrefixIgnoreCase("Host:", line).trim();
                else {
                  S rewritten;
                  if (startsWithIgnoreCase(line, "X-Forwarded-For:")) {
                    forwardedFor = true;
                    rewritten = line + ", " + client;
                  } else
                    rewritten = empty(line) ? line : rewriteHeaderLine(line);
                  if (!eq(rewritten, line))
                    print("Rewritten as: " + quote(rewritten));
                  if (nempty(rewritten)) {
                    byte[] bytes = (rewritten + "\r\n").getBytes("US-ASCII");
                    //print("Sending: " + bytesToHex(bytes));
                    headersOut.write(bytes);
                  }
                }
                
                if (l(line) == 0)
                  break;
              }
              
              int port = getForwardPort(host);
              
              outSocket = new Socket(forwardServer, port);
final Socket outS = outSocket;
              print("Connected to " + forwardServer + ":" + port);
              final OutputStream outOut = outSocket.getOutputStream();
              final InputStream outIn = outSocket.getInputStream();
              
              outOut.write(headersOut.toByteArray());
              
              if (!forwardedFor)
                headerSend(outOut, "X-Forwarded-For: " + client);
                
              headerSend(outOut, "Host: " + addPortToHost(host, port));
              
              headerSend(outOut, ""); // end of headers
                
              outOut.flush();
              
              // forward content in both directions
              
              //copyStream(outIn, out);
              
              Thread inThread = new Thread("Proxy In") {
                public void run() ctex {
                  try {
byte[] buf = new byte[1];
                  while (true) {
                    int n = outIn.read(buf);
                    if (n <= 0) return;
                    out.write(buf, 0, n);
                    long t = transmitted.addAndGet(n);
                    if (t % 100000 == 0) print("Transmitted to client: " + t);
                  }
} finally {
print("Shutting down client output.");
s.shutdownOutput();
}
                }
              };
              inThread.start();
              
              Thread outThread = new Thread("Proxy Out") {
                public void run() ctex {
try {
                  print("Proxy Out started.");
                  byte[] buf = new byte[1];
                  while (true) {
                    int n = in.read(buf);
                    if (n <= 0) return;
                    outOut.write(buf, 0, n);
                    if (outTransmitted.get() == 0)
                      print("Proxy Out first byte!");
                    long t = outTransmitted.addAndGet(n);
                    if (t % (debug ? 10 : 100000) == 0) print("Transmitted to server: " + t);
                  }
} finally {
  print("Shutting down server output.");
  outS.shutdownOutput();
}
                }
              };
              outThread.start();
              
              inThread.join();
              outThread.join();
            } catch (IOException e) {
              print("[internal] " + e);
            } finally {
              print("Proxy request done, got " + transmitted.get() + ", sent " + outTransmitted.get() + " + headers");
              pcall { s.close(); }
              pcall { if (outSocket != null) outSocket.close(); }
            }
          }
        }; // Thread t2
        t2.setDaemon(true);
        t2.start();
      } catch (SocketTimeoutException e) {
      }
    }   
   } catch (IOException e) {
     print("[internal] " + e);
   }
  }};
  thread.start();
 
  print("HTTP proxy on port " + port + " started."); 
}

static S rewriteHeaderLine(S line) {
  /*if (startsWithIgnoreCase(line, "Host:"))
    line = "Host: " + forwardServer + ":" + forwardPort;*/
  ret line;
}

static int getForwardPort(S host) {
  int i = host.indexOf(':');
  if (i >= 0)
    host = host.substring(0, i);
  host = host.toLowerCase();
  for (S key : forwardMap.keySet())
    if (eq(host, key) || host.endsWith("." + key))
      ret forwardMap.get(key);
  ret forwardMap.get("default");
}

svoid headerSend(OutputStream out, S header) ctex {
  print("Sending header: " + header);
  out.write((header + "\r\n").getBytes("US-ASCII"));
}

static String readHeaderLine(InputStream inputStream) throws IOException {
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    int c;
    for (c = inputStream.read(); c != '\n' && c != -1 ; c = inputStream.read()) {
        if (c != '\r')
          byteArrayOutputStream.write(c);
    }
    if (c == -1 && byteArrayOutputStream.size() == 0) {
        return null;
    }
    ret byteArrayOutputStream.toString("US-ASCII");
}

Author comment

Began life as a copy of #1002783

download  show line numbers  debug dex  old transpilations   

Travelled to 15 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, irmadwmeruwu, ishqpsrjomds, jtubtzbbkimh, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1002822
Snippet name: HTTP Proxy (with partial close, OK)
Eternal ID of this version: #1002822/5
Text MD5: e820ec479ced0d5428a4dbebb2c328ef
Transpilation MD5: ed270d33b9ca8b3d2cfba60b3fd974b0
Author: stefan
Category: eleu
Type: JavaX source code
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2021-10-03 17:39:40
Source code size: 7495 bytes / 227 lines
Pitched / IR pitched: No / No
Views / Downloads: 750 / 1189
Version history: 4 change(s)
Referenced in: [show references]