1. 程式人生 > >自己實現httpsever和httpproxy

自己實現httpsever和httpproxy

package gaofeng.myhttp.v1;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Inet4Address;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class WebServer {
	private static Executor pool = Executors.newFixedThreadPool(5);
	public static void main(String[] args) {
		try (ServerSocket server = new ServerSocket(5566, 5, Inet4Address.getLoopbackAddress());){
			while(true) {
				Socket socket= server.accept();
				pool.execute(()->dealRequest(socket));
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}		

	}
	private static void dealRequest(Socket socket) {
		System.out.println("---- RemoteSocketAddress : " + socket.getRemoteSocketAddress());
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			
			String firstline = null;
			while(true) {
				String line = reader.readLine();
				if(line==null || line.equals("") ) {
					System.out.println("---- end:"+line);
					break;
				}
				
				if(firstline==null) {
					firstline=line;
				}
				System.out.println(">"+line);
			}
			String s[] = firstline.split(" ");
			OutputStream output = socket.getOutputStream();
			try {
				if(s[0].equalsIgnoreCase("get")) {
					String filename = URLDecoder.decode(s[1],"utf-8");
					
					int index = s[1].indexOf(":5566/");
					if(index>-1) {
						String path = s[1].substring(index + ":5566/".length());
						filename = path;
					}
					
					String baseDir = System.getProperty("user.dir") + "/webroot/";
					Path filePath = Paths.get(baseDir, filename);
					if(filePath.toFile().isDirectory()){
						StringBuilder sb = new StringBuilder();
						for (File file : filePath.toFile().listFiles()) {
							if(file.isFile()) {
								sb.append("<a href=\"" + file.getName()+"\">"+file.getName()+"</a><br>");
							}else {
								sb.append("<a href=\"" + file.getName()+"/\">"+file.getName()+"</a><br>");
							}
						} 
						byte[] content = sb.toString().getBytes("GBK");
						output.write(String.format("http/1.1 200 ok\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n", content.length).getBytes());
						output.write(content);
					}else {
						byte[] fileContent = Files.readAllBytes(filePath);
						output.write(String.format("http/1.1 200 ok\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n", fileContent.length).getBytes());
						output.write(fileContent);						
					}
	
					return;
				}
			}catch(Exception e) {e.printStackTrace();}
			
			String notfound = "<h1>File not found!</h1>";
			byte[] response = String.format("http/1.1 404 File not found\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n%s",notfound.length(), notfound).getBytes();
			output.write(response);
		}catch(Throwable e) {
			e.printStackTrace();
		}finally {
			try {
				socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

}

curl -sv --proxy 127.0.0.1:80 http://www.baidu.com

curl -sv --proxy 127.0.0.1:80 https://www.baidu.com

curl --proxy 127.0.0.1:80 http://127.0.0.1:5566/mm/

package gaofeng.myhttp.v1;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class HttpProxy {

	public static void main(String[] args) throws IOException {
		ServerSocket serverSocket = new ServerSocket(80);
		for (;;) {
			new SocketHandle(serverSocket.accept()).start();
		}
	}
}
class SocketHandle extends Thread{
	private Socket socket;
	public SocketHandle(Socket socket) {
		this.socket = socket;
	}
	@Override
    public void run() {
		try {
			_run();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

    public void _run() throws IOException {
		BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		StringBuilder headStr = new StringBuilder();
		
		String host="",port="";//http協議頭  Host: 127.0.0.1
		while(true) {
			String line = reader.readLine();
			if(line==null) {
				System.out.println("---- end:"+line);
				break;
			}else {
				System.out.println(line);
				headStr.append(line).append("\r\n");
			}
			if (line.length() == 0) {
                break;
			}
			
            if (line.startsWith("Host:")) {
                host = line.substring(line.indexOf(' ')+1);
                if(host.contains(":")) {
                	port=host.split(":")[1];
                	host=host.split(":")[0];
                }else {
                	port="80";
                }
            }
		}
		
        String httpMethod="";
        if(headStr.length()>0) {
        	httpMethod = headStr.substring(0, headStr.indexOf(" "));//http協議第一行   GET /mm/ HTTP/1.1
        }
        try(Socket proxySocket = new Socket(host, Integer.parseInt(port))){
        	InputStream proxyInput = proxySocket.getInputStream();
        	OutputStream proxyOutput = proxySocket.getOutputStream();
            //根據HTTP method來判斷是https還是http請求
            if ("CONNECT".equalsIgnoreCase(httpMethod)) {//https先建立隧道
                socket.getOutputStream().write("HTTP/1.1 200 Connection Established\r\n\r\n".getBytes());
                socket.getOutputStream().flush();
            } else {//http直接將請求頭轉發
                proxyOutput.write(headStr.toString().getBytes());
            }
            //新開執行緒轉發客戶端請求至目標伺服器
            new ProxyHandleThread(socket.getInputStream(), proxyOutput).start();
            //轉發目標伺服器響應至客戶端
            while (true) {
            	int b = proxyInput.read();
            	
            	if(b==-1) {
            		socket.getOutputStream().close();
            		break;
            	}else {
            		socket.getOutputStream().write(b);
            	}
            	
            }
        }		
	}
}
class ProxyHandleThread extends Thread{
	private InputStream input;
    private OutputStream output;

    public ProxyHandleThread(InputStream input, OutputStream output) {
        this.input = input;
        this.output = output;
    }

    @Override
    public void run() {
        try {
            while (true) {
            	int b = input.read();
            	if(b==-1) {
            		break;
            	}else {
            		System.out.println("ddd"+b);
            		output.write(b);
            	}
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}