Libraryless. Click here for Pure Java version (1662L/12K/41K).
1 | !7 |
2 | |
3 | static bool debug = false; |
4 | static int port = 80; |
5 | static L<S> blockedIPs = ll(); |
6 | |
7 | static S forwardURL() { |
8 | ret "http://localhost:4678"; |
9 | //ret smartBotURL(); |
10 | } |
11 | |
12 | p { |
13 | // Now for the actual server... |
14 | |
15 | final ServerSocket serverSocket = new ServerSocket(port); |
16 | |
17 | Thread thread = new Thread("HTTP Proxy Accept Port " + port) { public void run() { |
18 | try { |
19 | while (true) { |
20 | try { |
21 | final Socket s = serverSocket.accept(); |
22 | |
23 | /*thread "Lister" { |
24 | sleepSeconds(5); |
25 | listThreads(); |
26 | }*/ |
27 | |
28 | final S client = dropPrefix("/", s.getInetAddress().toString()); // Hmm... how to get the actual IP properly? |
29 | String threadName = "PROXY: Handling client " + client; |
30 | |
31 | if (blockedIPs.contains(client)) { |
32 | print("Blocked IP!! " + client); |
33 | pcall { s.close(); } |
34 | continue; |
35 | } |
36 | |
37 | Thread t2 = new Thread(threadName) { |
38 | public void run() ctex { |
39 | Socket outSocket = null; |
40 | final new AtomicLong transmitted; |
41 | final new AtomicLong outTransmitted; |
42 | try { |
43 | print("HTTP Proxy Incoming!"); |
44 | |
45 | final OutputStream out = s.getOutputStream(); |
46 | final InputStream in = s.getInputStream(); |
47 | |
48 | // collect headers |
49 | |
50 | new ByteArrayOutputStream headersOut; |
51 | //BufferedReader headerReader = new BufferedReader(new InputStreamReader(in, "US-ASCII"), 1); |
52 | boolean forwardedFor = false; |
53 | S host = null; |
54 | while (true) { |
55 | S line = readHeaderLine(in); |
56 | if (line == null) ret; |
57 | print("Header line read: " + quote(line)); |
58 | |
59 | if (startsWithIgnoreCase(line, "Host:")) |
60 | host = dropPrefixIgnoreCase("Host:", line).trim(); |
61 | else { |
62 | S rewritten; |
63 | if (startsWithIgnoreCase(line, "X-Forwarded-For:")) { |
64 | forwardedFor = true; |
65 | rewritten = line + ", " + client; |
66 | print("Forwarded for: " + rewritten); |
67 | } else |
68 | rewritten = empty(line) ? line : rewriteHeaderLine(line); |
69 | if (!eq(rewritten, line)) |
70 | print("Rewritten as: " + quote(rewritten)); |
71 | if (nempty(rewritten)) { |
72 | byte[] bytes = (rewritten + "\r\n").getBytes("US-ASCII"); |
73 | //print("Sending: " + bytesToHex(bytes)); |
74 | headersOut.write(bytes); |
75 | } |
76 | } |
77 | |
78 | if (l(line) == 0) |
79 | break; |
80 | } |
81 | |
82 | // if (eq(smartBotURL(), smartBotURL_default)) ... |
83 | |
84 | URL url = new URL(forwardURL()); |
85 | S forwardServer = url.getHost(); |
86 | if (isMyIP(hostToIP(forwardServer))) |
87 | fail("Routing to myself"); |
88 | |
89 | int port = ifNegative(url.getPort(), 80); |
90 | outSocket = new Socket(forwardServer, port); |
91 | final Socket outS = outSocket; |
92 | print("Connected to " + forwardServer + ":" + port); |
93 | final OutputStream outOut = outSocket.getOutputStream(); |
94 | final InputStream outIn = outSocket.getInputStream(); |
95 | |
96 | if (!forwardedFor) { |
97 | S rewritten = "X-Forwarded-For: " + client; |
98 | //print("Forwarded for: " + rewritten); |
99 | //headerSend(outOut, rewritten); |
100 | headersOut.write((rewritten + "\r\n").getBytes("US-ASCII")); |
101 | } |
102 | |
103 | printIndent("{" + headersOut + "}"); |
104 | outOut.write(headersOut.toByteArray()); |
105 | |
106 | //headerSend(outOut, "Host: " + hostToPort(host, port)); |
107 | |
108 | headerSend(outOut, ""); // end of headers |
109 | |
110 | outOut.flush(); |
111 | |
112 | // forward content in both directions |
113 | |
114 | //copyStream(outIn, out); |
115 | |
116 | Thread inThread = new Thread("Proxy In") { |
117 | public void run() ctex { |
118 | try { |
119 | byte[] buf = new byte[1]; |
120 | while (true) { |
121 | int n = outIn.read(buf); |
122 | if (n <= 0) return; |
123 | out.write(buf, 0, n); |
124 | long t = transmitted.addAndGet(n); |
125 | if (t % 100000 == 0) print("Transmitted to client: " + t); |
126 | } |
127 | } finally { |
128 | print("Shutting down client output."); |
129 | s.shutdownOutput(); |
130 | } |
131 | } |
132 | }; |
133 | inThread.start(); |
134 | |
135 | Thread outThread = new Thread("Proxy Out") { |
136 | public void run() ctex { |
137 | try { |
138 | print("Proxy Out started."); |
139 | byte[] buf = new byte[1]; |
140 | while (true) { |
141 | int n = in.read(buf); |
142 | if (n <= 0) return; |
143 | outOut.write(buf, 0, n); |
144 | /*if (outTransmitted.get() == 0) |
145 | print("Proxy Out first byte!");*/ |
146 | long t = outTransmitted.addAndGet(n); |
147 | if (t % (debug ? 10 : 100000) == 0) print("Transmitted to server: " + t); |
148 | } |
149 | } finally { |
150 | print("Shutting down server output."); |
151 | outS.shutdownOutput(); |
152 | } |
153 | } |
154 | }; |
155 | outThread.start(); |
156 | |
157 | inThread.join(); |
158 | outThread.join(); |
159 | } catch (IOException e) { |
160 | print("[internal] " + e); |
161 | } finally { |
162 | print("Proxy request done, got " + transmitted.get() + ", sent " + outTransmitted.get() + " + headers"); |
163 | pcall { s.close(); } |
164 | pcall { if (outSocket != null) outSocket.close(); } |
165 | } |
166 | } |
167 | }; // Thread t2 |
168 | t2.setDaemon(true); |
169 | t2.start(); |
170 | } catch (SocketTimeoutException e) { |
171 | } |
172 | } |
173 | } catch (IOException e) { |
174 | print("[internal] " + e); |
175 | } |
176 | }}; |
177 | thread.start(); |
178 | |
179 | print("HTTP proxy on port " + port + " started."); |
180 | } |
181 | |
182 | static S rewriteHeaderLine(S line) { |
183 | /*if (startsWithIgnoreCase(line, "Host:")) |
184 | line = "Host: " + forwardServer + ":" + forwardPort;*/ |
185 | ret line; |
186 | } |
187 | |
188 | static void headerSend(OutputStream out, S header) ctex { |
189 | print("Sending header: " + header); |
190 | out.write((header + "\r\n").getBytes("US-ASCII")); |
191 | } |
192 | |
193 | static String readHeaderLine(InputStream inputStream) throws IOException { |
194 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); |
195 | int c; |
196 | for (c = inputStream.read(); c != '\n' && c != -1 ; c = inputStream.read()) { |
197 | if (c != '\r') |
198 | byteArrayOutputStream.write(c); |
199 | } |
200 | if (c == -1 && byteArrayOutputStream.size() == 0) { |
201 | return null; |
202 | } |
203 | ret byteArrayOutputStream.toString("US-ASCII"); |
204 | } |
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: | 475 / 645 |
Version history: | 12 change(s) |
Referenced in: | [show references] |