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

204
LINES

< > BotCompany Repo | #1011937 // Smart Bot HTTP Proxy (OK) - should now be safe from endless loops

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

Libraryless. Click here for Pure Java version (1662L/12K/41K).

!7

static bool debug = false;
static int port = 80;
static L<S> blockedIPs = ll();

static S forwardURL() {
  ret "http://localhost:4678";
  //ret smartBotURL();
}

p {
  // 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;
                    print("Forwarded for: " + rewritten);
                  } 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;
              }
              
              // if (eq(smartBotURL(), smartBotURL_default)) ...
              
              URL url = new URL(forwardURL());
              S forwardServer = url.getHost();
              if (isMyIP(hostToIP(forwardServer)))
                fail("Routing to myself");
              
              int port = ifNegative(url.getPort(), 80);
              outSocket = new Socket(forwardServer, port);
              final Socket outS = outSocket;
              print("Connected to " + forwardServer + ":" + port);
              final OutputStream outOut = outSocket.getOutputStream();
              final InputStream outIn = outSocket.getInputStream();
              
              if (!forwardedFor) {
                S rewritten = "X-Forwarded-For: " + client;
                //print("Forwarded for: " + rewritten);
                //headerSend(outOut, rewritten);
                headersOut.write((rewritten + "\r\n").getBytes("US-ASCII"));
              }
                
              printIndent("{" + headersOut + "}");
              outOut.write(headersOut.toByteArray());
              
              //headerSend(outOut, "Host: " + hostToPort(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 void 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 #1002822

download  show line numbers  debug dex  old transpilations   

Travelled to 16 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, ppjhyzlbdabe, pyentgdyhuwx, pzhvpgtvlbxg, sgthpswjdnle, tslmcundralx, tvejysmllsmz, vouqrxazstgt, vupmehlpavxc

No comments. add comment

-
Snippet ID: #1011937
Snippet name: Smart Bot HTTP Proxy (OK) - should now be safe from endless loops
Eternal ID of this version: #1011937/13
Text MD5: a152878e082697209618425bf8ac7ace
Transpilation MD5: 82111ef8027c53025e22eb373c48f6fc
Author: stefan
Category: javax / a.i. / html
Type: JavaX source code
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2017-12-25 00:24:18
Source code size: 7265 bytes / 204 lines
Pitched / IR pitched: No / No
Views / Downloads: 476 / 647
Version history: 12 change(s)
Referenced in: