package shuaicj.hobby.great.free.will.http;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.Socket;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

/**
 * The http proxy server task.
 *
 * @author shuaicj 2017/09/09
 */
@Slf4j
public class HttpProxyServerTask implements Runnable {

    private final String id;
    private final Socket socket;
    private final ExecutorService pool;

    public HttpProxyServerTask(String id, Socket socket, ExecutorService pool) {
        this.id = id;
        this.socket = socket;
        this.pool = pool;
    }

    @Override
    public void run() {
        Socket targetSocket = null;
        try {
            final InputStream clientInput = new BufferedInputStream(socket.getInputStream());
            HttpProxyClientHeader header = HttpProxyClientHeader.parseFrom(clientInput);
            targetSocket = new Socket(header.getHost(), header.getPort());

            OutputStream targetOutput = targetSocket.getOutputStream();
            logger.info(id + " {}\n{}", header, new String(header.getBytes()));

            if (header.isHttps()) { // if https, respond 200 to create tunnel, and do not forward header
                targetOutput.write("HTTP/1.1 200 Connection Established\r\n\r\n".getBytes());
                targetOutput.flush();
            } else { // if http, forward header
                targetOutput.write(header.getBytes());
            }
            Future<?> future = pool.submit(() -> pipe(clientInput, targetOutput));

            InputStream targetInput = targetSocket.getInputStream();
            OutputStream clientOutput = socket.getOutputStream();
            pipe(targetInput, clientOutput);

            future.get();
        } catch (IOException | InterruptedException | ExecutionException e) {
            logger.error(id + " shit happens", e);
        } finally {
            try {
                socket.close();
                if (targetSocket != null) {
                    targetSocket.close();
                }
            } catch (IOException e) {
                logger.error(id + " shit happens", e);
            }
        }
    }

    private void pipe(InputStream in, OutputStream out) {
        byte[] buf = new byte[4096];
        int len;
        try {
            while ((len = in.read(buf)) != -1) {
                out.write(buf, 0, len);
            }
            out.flush();
        } catch (IOException e) {
            logger.error(id + " shit happens", e);
        }
    }
}

@@ -694,16 +694,19 @@
 %0A       
+ //
  Socket 
@@ -738,30 +738,17 @@
     try 
-%7B%0A            
+(
 final In
@@ -819,17 +819,19 @@
 tream())
-;
+) %7B
 %0A       
@@ -916,32 +916,50 @@
 t);%0A            
+try (final Socket 
 targetSocket = n
@@ -1003,17 +1003,19 @@
 tPort())
-;
+) %7B
 %0A%0A      
@@ -1012,32 +1012,42 @@
  %7B%0A%0A            
+    final 
 OutputStream tar
@@ -1098,24 +1098,28 @@
             
+   
+ 
 logger.info(
@@ -1171,24 +1171,28 @@
 Bytes()));%0A%0A
+    
             
@@ -1292,32 +1292,36 @@
                 
+ 
+   
 targetOutput.wri
@@ -1390,32 +1390,36 @@
                 
+    
 targetOutput.flu
@@ -1416,32 +1416,36 @@
 Output.flush();%0A
+    
             %7D el
@@ -1484,32 +1484,36 @@
                 
+ 
+   
 targetOutput.wri
@@ -1539,34 +1539,42 @@
 ));%0A            
-%7D%0A
+    %7D%0A    
             Futu
@@ -1653,16 +1653,20 @@
         
+  
+  
 InputStr
@@ -1706,32 +1706,36 @@
 tInputStream();%0A
+    
             Outp
@@ -1796,16 +1796,20 @@
         
+    
 pipe(tar
@@ -1846,16 +1846,20 @@
         
+  
+  
 future.g
@@ -1860,24 +1860,38 @@
 ture.get();%0A
+            %7D%0A
         %7D ca
@@ -2011,289 +2011,8 @@
 e);%0A
-        %7D finally %7B%0A            try %7B%0A                socket.close();%0A                if (targetSocket != null) %7B%0A                    targetSocket.close();%0A                %7D%0A            %7D catch (IOException e) %7B%0A                logger.error(id + %22 shit happens%22, e);%0A            %7D%0A
     

optimize code with try resources