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();
}
}
}
}
参考 https://blog.csdn.net/dotalee/article/details/77838659
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();
}
}
}
ServletServer (注意,socket流只能读一次。所以一般由框架读取http头,应用读取body。)
package gaofeng.myhttp.v2;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.Inet4Address;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javax.servlet.AsyncContext;
import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpUpgradeHandler;
import javax.servlet.http.Part;
public class ServletServer {
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 {
String firstLine = Util.readLine(socket.getInputStream());
String[] s = firstLine.split(" ");
String method = s[0],url = s[1],protocal = s[2];
List<String> headerList= new ArrayList<>();
while(true) {
String line = Util.readLine(socket.getInputStream());
System.out.println("===" + line);
headerList.add(line);
if(line.length()==0) break;
}
if(url.startsWith("/servlet/")) {
new ServletProcessor().handle(firstLine,socket);
}else if(url.startsWith("/static/")) {
new StaticProcessor().handle(firstLine,socket);
}else {
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();
socket.getOutputStream().write(response);
}
} catch (Throwable e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class ServletProcessor{
public void handle(String firstLine, Socket socket) throws ClassNotFoundException, InstantiationException, IllegalAccessException, ServletException, IOException {
URL[] urls = { ServletServer.class.getResource("/")};//{ new URL("file://Users/apple/temp")};
System.out.println(ServletServer.class.getResource("/"));
Class<?> clazz = new URLClassLoader(urls).loadClass("gaofeng.myhttp.v2.MyServlet");
HttpServlet httpServlet = (HttpServlet) clazz.newInstance();
Request request = new Request();
request.init(firstLine, socket);
Response response = new Response();
response.init( socket);
httpServlet.service(request, response);
}
}
class Request implements HttpServletRequest{
private Socket socket;
private String method,url,protocal;
public void init(String firstLine, Socket socket) {
this.socket = socket;
String[] s = firstLine.split(" ");
method = s[0];
url = s[1];
protocal = s[2];
}
@Override
public Object getAttribute(String name) {
// TODO Auto-generated method stub
return null;
}
@Override
public Enumeration<String> getAttributeNames() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getCharacterEncoding() {
// TODO Auto-generated method stub
return null;
}
@Override
public void setCharacterEncoding(String env) throws UnsupportedEncodingException {
// TODO Auto-generated method stub
}
@Override
public int getContentLength() {
// TODO Auto-generated method stub
return 0;
}
@Override
public long getContentLengthLong() {
// TODO Auto-generated method stub
return 0;
}
@Override
public String getContentType() {
// TODO Auto-generated method stub
return null;
}
@Override
public ServletInputStream getInputStream() throws IOException {
return null;
}
@Override
public String getParameter(String name) {
// TODO Auto-generated method stub
return null;
}
@Override
public Enumeration<String> getParameterNames() {
// TODO Auto-generated method stub
return null;
}
@Override
public String[] getParameterValues(String name) {
// TODO Auto-generated method stub
return null;
}
@Override
public Map<String, String[]> getParameterMap() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getProtocol() {
return this.protocal;
}
@Override
public String getScheme() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getServerName() {
// TODO Auto-generated method stub
return null;
}
@Override
public int getServerPort() {
// TODO Auto-generated method stub
return 0;
}
@Override
public BufferedReader getReader() throws IOException {
// TODO Auto-generated method stub
return null;
}
@Override
public String getRemoteAddr() {
return socket.getRemoteSocketAddress().toString();
}
@Override
public String getRemoteHost() {
// TODO Auto-generated method stub
return null;
}
@Override
public void setAttribute(String name, Object o) {
// TODO Auto-generated method stub
}
@Override
public void removeAttribute(String name) {
// TODO Auto-generated method stub
}
@Override
public Locale getLocale() {
// TODO Auto-generated method stub
return null;
}
@Override
public Enumeration<Locale> getLocales() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isSecure() {
// TODO Auto-generated method stub
return false;
}
@Override
public RequestDispatcher getRequestDispatcher(String path) {
// TODO Auto-generated method stub
return null;
}
@Override
public String getRealPath(String path) {
// TODO Auto-generated method stub
return null;
}
@Override
public int getRemotePort() {
// TODO Auto-generated method stub
return 0;
}
@Override
public String getLocalName() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getLocalAddr() {
// TODO Auto-generated method stub
return null;
}
@Override
public int getLocalPort() {
// TODO Auto-generated method stub
return 0;
}
@Override
public ServletContext getServletContext() {
// TODO Auto-generated method stub
return null;
}
@Override
public AsyncContext startAsync() throws IllegalStateException {
// TODO Auto-generated method stub
return null;
}
@Override
public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)
throws IllegalStateException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isAsyncStarted() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isAsyncSupported() {
// TODO Auto-generated method stub
return false;
}
@Override
public AsyncContext getAsyncContext() {
// TODO Auto-generated method stub
return null;
}
@Override
public DispatcherType getDispatcherType() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getAuthType() {
// TODO Auto-generated method stub
return null;
}
@Override
public Cookie[] getCookies() {
// TODO Auto-generated method stub
return null;
}
@Override
public long getDateHeader(String name) {
// TODO Auto-generated method stub
return 0;
}
@Override
public String getHeader(String name) {
// TODO Auto-generated method stub
return null;
}
@Override
public Enumeration<String> getHeaders(String name) {
// TODO Auto-generated method stub
return null;
}
@Override
public Enumeration<String> getHeaderNames() {
// TODO Auto-generated method stub
return null;
}
@Override
public int getIntHeader(String name) {
// TODO Auto-generated method stub
return 0;
}
@Override
public String getMethod() {
return this.method;
}
@Override
public String getPathInfo() {
return this.url;
}
@Override
public String getPathTranslated() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getContextPath() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getQueryString() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getRemoteUser() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isUserInRole(String role) {
// TODO Auto-generated method stub
return false;
}
@Override
public Principal getUserPrincipal() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getRequestedSessionId() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getRequestURI() {
// TODO Auto-generated method stub
return null;
}
@Override
public StringBuffer getRequestURL() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getServletPath() {
// TODO Auto-generated method stub
return null;
}
@Override
public HttpSession getSession(boolean create) {
// TODO Auto-generated method stub
return null;
}
@Override
public HttpSession getSession() {
// TODO Auto-generated method stub
return null;
}
@Override
public String changeSessionId() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isRequestedSessionIdValid() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isRequestedSessionIdFromCookie() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isRequestedSessionIdFromURL() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isRequestedSessionIdFromUrl() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
// TODO Auto-generated method stub
return false;
}
@Override
public void login(String username, String password) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void logout() throws ServletException {
// TODO Auto-generated method stub
}
@Override
public Collection<Part> getParts() throws IOException, ServletException {
// TODO Auto-generated method stub
return null;
}
@Override
public Part getPart(String name) throws IOException, ServletException {
// TODO Auto-generated method stub
return null;
}
@Override
public <T extends HttpUpgradeHandler> T upgrade(Class<T> httpUpgradeHandlerClass)
throws IOException, ServletException {
// TODO Auto-generated method stub
return null;
}
}
class Response implements HttpServletResponse{
private Socket socket;
public void init(Socket socket) {
this.socket = socket;
}
@Override
public String getCharacterEncoding() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getContentType() {
// TODO Auto-generated method stub
return null;
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
// TODO Auto-generated method stub
return null;
}
@Override
public PrintWriter getWriter() throws IOException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setCharacterEncoding(String charset) {
// TODO Auto-generated method stub
}
@Override
public void setContentLength(int len) {
// TODO Auto-generated method stub
}
@Override
public void setContentLengthLong(long length) {
// TODO Auto-generated method stub
}
@Override
public void setContentType(String type) {
// TODO Auto-generated method stub
}
@Override
public void setBufferSize(int size) {
// TODO Auto-generated method stub
}
@Override
public int getBufferSize() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void flushBuffer() throws IOException {
// TODO Auto-generated method stub
}
@Override
public void resetBuffer() {
// TODO Auto-generated method stub
}
@Override
public boolean isCommitted() {
// TODO Auto-generated method stub
return false;
}
@Override
public void reset() {
// TODO Auto-generated method stub
}
@Override
public void setLocale(Locale loc) {
// TODO Auto-generated method stub
}
@Override
public Locale getLocale() {
// TODO Auto-generated method stub
return null;
}
@Override
public void addCookie(Cookie cookie) {
// TODO Auto-generated method stub
}
@Override
public boolean containsHeader(String name) {
// TODO Auto-generated method stub
return false;
}
@Override
public String encodeURL(String url) {
// TODO Auto-generated method stub
return null;
}
@Override
public String encodeRedirectURL(String url) {
// TODO Auto-generated method stub
return null;
}
@Override
public String encodeUrl(String url) {
// TODO Auto-generated method stub
return null;
}
@Override
public String encodeRedirectUrl(String url) {
// TODO Auto-generated method stub
return null;
}
@Override
public void sendError(int sc, String msg) throws IOException {
this.socket.getOutputStream().write(String.format("http/1.1 %d %s\r\n", sc,msg).getBytes());
}
@Override
public void sendError(int sc) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void sendRedirect(String location) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void setDateHeader(String name, long date) {
// TODO Auto-generated method stub
}
@Override
public void addDateHeader(String name, long date) {
// TODO Auto-generated method stub
}
@Override
public void setHeader(String name, String value) {
// TODO Auto-generated method stub
}
@Override
public void addHeader(String name, String value) {
// TODO Auto-generated method stub
}
@Override
public void setIntHeader(String name, int value) {
// TODO Auto-generated method stub
}
@Override
public void addIntHeader(String name, int value) {
// TODO Auto-generated method stub
}
@Override
public void setStatus(int sc) {
// TODO Auto-generated method stub
}
@Override
public void setStatus(int sc, String sm) {
// TODO Auto-generated method stub
}
@Override
public int getStatus() {
// TODO Auto-generated method stub
return 0;
}
@Override
public String getHeader(String name) {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<String> getHeaders(String name) {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<String> getHeaderNames() {
// TODO Auto-generated method stub
return null;
}
}
class StaticProcessor{
public void handle( String firstLine, Socket socket){
try {
_handle(firstLine, socket);
} catch (Exception e) {
String notfound = "<h1>File not found!</h1>";
notfound = "File not found!";
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();
try {
socket.getOutputStream().write(response);
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
public void _handle(String firstLine, Socket socket) throws IOException {
String s[] = firstLine.split(" ");
String filename = URLDecoder.decode(s[1].substring(s[1].indexOf('/',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);
OutputStream output = socket.getOutputStream();
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 if(filePath.toFile().isFile()){
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);
}else {
throw new IOException();
}
}
}
class MyServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = "http.method_get_not_supported";
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}
}
class Util{
public static String readLine(InputStream input) {
try {
byte[] buff = new byte[512];
int length = 0;
while(true) {
int c = input.read();
if(c==-1) {
return new String(buff,0,length);
}else if(c=='\n') {// "\r\n"
return new String(buff,0,length-1);
}else {
buff[length++]=(byte)c;
}
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}