Преглед изворни кода

simple servlet container: app1

runningwater пре 2 година
родитељ
комит
71fd5b26f6

+ 9 - 0
.idea/libraries/servlet.xml

@@ -0,0 +1,9 @@
+<component name="libraryTable">
+  <library name="servlet">
+    <CLASSES>
+      <root url="jar://$PROJECT_DIR$/lib/servlet.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>

+ 124 - 0
.idea/uiDesigner.xml

@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Palette2">
+    <group name="Swing">
+      <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
+      </item>
+      <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
+        <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
+        <initial-values>
+          <property name="text" value="Button" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="RadioButton" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="CheckBox" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="Label" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
+          <preferred-size width="-1" height="20" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
+      </item>
+    </group>
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 1 - 0
HowTomcatWorks.iml

@@ -7,5 +7,6 @@
     </content>
     <orderEntry type="inheritedJdk" />
     <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="servlet" level="project" />
   </component>
 </module>


+ 32 - 0
src/PrimitiveServlet.java

@@ -0,0 +1,32 @@
+import javax.servlet.*;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+public class PrimitiveServlet implements Servlet {
+
+  public void init(ServletConfig config) throws ServletException {
+    System.out.println("init");
+  }
+
+  public void service(ServletRequest request, ServletResponse response)
+      throws ServletException, IOException {
+    System.out.println("from service");
+    PrintWriter out = response.getWriter();
+    String header = "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n" + "\r\n";
+    out.write(header);
+    out.println("Hello. Roses are red.");
+    out.print("Violets are blue.");
+  }
+
+  public void destroy() {
+    System.out.println("destroy");
+  }
+
+  public String getServletInfo() {
+    return null;
+  }
+
+  public ServletConfig getServletConfig() {
+    return null;
+  }
+}

+ 1 - 1
src/pyrmont/HttpServer.java

@@ -1,4 +1,4 @@
-package pyrmont;
+package pyrmont.ex01;
 
 import java.net.Socket;
 import java.net.ServerSocket;

+ 1 - 1
src/pyrmont/Request.java

@@ -1,4 +1,4 @@
-package pyrmont;
+package pyrmont.ex01;
 
 import java.io.InputStream;
 import java.io.IOException;

+ 1 - 1
src/pyrmont/Response.java

@@ -1,4 +1,4 @@
-package pyrmont;
+package pyrmont.ex01;
 
 import java.io.OutputStream;
 import java.io.IOException;

+ 88 - 0
src/pyrmont/ex02/HttpServer1.java

@@ -0,0 +1,88 @@
+/* Copyright (C) 2019-2023 Hangzhou HSH Co. Ltd.
+ * All right reserved.*/
+package pyrmont.ex02;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+/**
+ * @author simon
+ * @date 2023-09-27 17:10
+ * @desc
+ */
+public class HttpServer1 {
+
+  public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot";
+
+  /**
+   * WEB_ROOT is the directory where our HTML and other files reside. For this package, WEB_ROOT is
+   * the "webroot" directory under the working directory. The working directory is the location in
+   * the file system from where the java command was invoked.
+   */
+  // shutdown command
+  private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
+
+  // the shutdown command received
+  private boolean shutdown = false;
+
+  public static void main(String[] args) {
+    HttpServer1 server = new HttpServer1();
+    server.await();
+  }
+
+  private void await() {
+    ServerSocket serverSocket = null;
+    int port = 8080;
+    try {
+      serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
+    } catch (IOException e) {
+      e.printStackTrace();
+      System.exit(1);
+    }
+
+    // Loop waiting for request
+    while (!shutdown) {
+      Socket socket = null;
+      InputStream input = null;
+      OutputStream output = null;
+      try {
+        socket = serverSocket.accept();
+        input = socket.getInputStream();
+        output = socket.getOutputStream();
+
+        // create Request object and parse
+        Request request = new Request(input);
+        request.parse();
+
+        // create Response object
+        Response response = new Response(output);
+        response.setRequest(request);
+
+        // check if this is a request for a servlet or
+        // a static resource
+        // a request for a servlet begins with "/servlet"
+        if (request.getUri().startsWith("/servlet")) {
+          ServletProcessor1 processor = new ServletProcessor1();
+          processor.process(request, response);
+        } else {
+          StaticResourceProcessor processor = new StaticResourceProcessor();
+          processor.process(request, response);
+        }
+
+        // Close the socket
+        socket.close();
+        // check if the previous URI is a shutdown command
+        shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
+
+      } catch (Exception e) {
+        e.printStackTrace();
+        System.exit(1);
+      }
+    }
+  }
+}

+ 181 - 0
src/pyrmont/ex02/Request.java

@@ -0,0 +1,181 @@
+/* Copyright (C) 2019-2023 Hangzhou HSH Co. Ltd.
+ * All right reserved.*/
+package pyrmont.ex02;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * @author simon
+ * @date 2023-09-27 17:11
+ * @desc
+ */
+public class Request implements ServletRequest {
+  private final InputStream inputStream;
+  private String uri;
+
+  public Request(InputStream input) {
+    this.inputStream = input;
+  }
+
+  public String getUri() {
+    return uri;
+  }
+
+  public void parse() {
+    // Read a set of characters from the socket
+    StringBuffer request = new StringBuffer(2048);
+    int i;
+    byte[] buffer = new byte[2048];
+    try {
+      i = inputStream.read(buffer);
+    } catch (IOException e) {
+      e.printStackTrace();
+      i = -1;
+    }
+    for (int j = 0; j < i; j++) {
+      request.append((char) buffer[j]);
+    }
+    System.out.print(request);
+    uri = parseUri(request.toString());
+  }
+
+  private String parseUri(String requestString) {
+    int index1, index2;
+    index1 = requestString.indexOf(' ');
+    if (index1 != -1) {
+      index2 = requestString.indexOf(' ', index1 + 1);
+      if (index2 > index1) {
+        return requestString.substring(index1 + 1, index2);
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public Object getAttribute(String s) {
+    return null;
+  }
+
+  @Override
+  public Enumeration getAttributeNames() {
+    return null;
+  }
+
+  @Override
+  public String getCharacterEncoding() {
+    return null;
+  }
+
+  @Override
+  public void setCharacterEncoding(String s) throws UnsupportedEncodingException {}
+
+  @Override
+  public int getContentLength() {
+    return 0;
+  }
+
+  @Override
+  public String getContentType() {
+    return null;
+  }
+
+  @Override
+  public ServletInputStream getInputStream() throws IOException {
+    return null;
+  }
+
+  @Override
+  public String getParameter(String s) {
+    return null;
+  }
+
+  @Override
+  public Enumeration getParameterNames() {
+    return null;
+  }
+
+  @Override
+  public String[] getParameterValues(String s) {
+    return new String[0];
+  }
+
+  @Override
+  public Map getParameterMap() {
+    return null;
+  }
+
+  @Override
+  public String getProtocol() {
+    return null;
+  }
+
+  @Override
+  public String getScheme() {
+    return null;
+  }
+
+  @Override
+  public String getServerName() {
+    return null;
+  }
+
+  @Override
+  public int getServerPort() {
+    return 0;
+  }
+
+  @Override
+  public BufferedReader getReader() throws IOException {
+    return null;
+  }
+
+  @Override
+  public String getRemoteAddr() {
+    return null;
+  }
+
+  @Override
+  public String getRemoteHost() {
+    return null;
+  }
+
+  @Override
+  public void setAttribute(String s, Object o) {}
+
+  @Override
+  public void removeAttribute(String s) {}
+
+  @Override
+  public Locale getLocale() {
+    return null;
+  }
+
+  @Override
+  public Enumeration getLocales() {
+    return null;
+  }
+
+  @Override
+  public boolean isSecure() {
+    return false;
+  }
+
+  @Override
+  public RequestDispatcher getRequestDispatcher(String s) {
+    return null;
+  }
+
+  @Override
+  public String getRealPath(String s) {
+    return null;
+  }
+}

+ 117 - 0
src/pyrmont/ex02/Response.java

@@ -0,0 +1,117 @@
+/* Copyright (C) 2019-2023 Hangzhou HSH Co. Ltd.
+ * All right reserved.*/ package pyrmont.ex02;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletResponse;
+import java.io.*;
+import java.util.Locale;
+
+/**
+ * @author simon
+ * @date 2023-09-27 17:11
+ * @desc /* HTTP Response = Status-Line *(( general-header | response-header | entity-header ) CRLF)
+ *     CRLF [ message-body ] Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
+ */
+public class Response implements ServletResponse {
+  private static final int BUFFER_SIZE = 1024;
+  Request request;
+  OutputStream output;
+  PrintWriter writer;
+
+  public Response(OutputStream output) {
+    this.output = output;
+  }
+
+  public void setRequest(Request request) {
+    this.request = request;
+  }
+
+  /* This method is used to serve static pages */
+  public void sendStaticResource() throws IOException {
+    byte[] bytes = new byte[BUFFER_SIZE];
+    FileInputStream fis = null;
+    try {
+      /* request.getUri has been replaced by request.getRequestURI */
+      File file = new File(HttpServer1.WEB_ROOT, request.getUri());
+      fis = new FileInputStream(file);
+      /*
+         HTTP Response = Status-Line
+           *(( general-header | response-header | entity-header ) CRLF)
+           CRLF
+           [ message-body ]
+         Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
+      */
+      int ch = fis.read(bytes, 0, BUFFER_SIZE);
+      String header = "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n" + "\r\n";
+      output.write(header.getBytes());
+      while (ch != -1) {
+        output.write(bytes, 0, ch);
+        ch = fis.read(bytes, 0, BUFFER_SIZE);
+      }
+    } catch (FileNotFoundException e) {
+      String errorMessage =
+          "HTTP/1.1 404 File Not Found\r\n"
+              + "Content-Type: text/html\r\n"
+              + "Content-Length: 23\r\n"
+              + "\r\n"
+              + "<h1>File Not Found</h1>";
+      output.write(errorMessage.getBytes());
+    } finally {
+      if (fis != null) fis.close();
+    }
+  }
+
+  @Override
+  public String getCharacterEncoding() {
+    return null;
+  }
+
+  @Override
+  public ServletOutputStream getOutputStream() throws IOException {
+    return null;
+  }
+
+  @Override
+  public PrintWriter getWriter() throws IOException {
+    // autoflush is true, println() will flush,
+    // but print() will not.
+    writer = new PrintWriter(output, true);
+    return writer;
+  }
+
+  @Override
+  public void setContentLength(int i) {}
+
+  @Override
+  public void setContentType(String s) {}
+
+  @Override
+  public void setBufferSize(int i) {}
+
+  @Override
+  public int getBufferSize() {
+    return 0;
+  }
+
+  @Override
+  public void flushBuffer() throws IOException {}
+
+  @Override
+  public void resetBuffer() {}
+
+  @Override
+  public boolean isCommitted() {
+    return false;
+  }
+
+  @Override
+  public void reset() {}
+
+  @Override
+  public void setLocale(Locale locale) {}
+
+  @Override
+  public Locale getLocale() {
+    return null;
+  }
+}

+ 52 - 0
src/pyrmont/ex02/ServletProcessor1.java

@@ -0,0 +1,52 @@
+/* Copyright (C) 2019-2023 Hangzhou HSH Co. Ltd.
+ * All right reserved.*/
+package pyrmont.ex02;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLStreamHandler;
+import javax.servlet.Servlet;
+
+/**
+ * @author simon
+ * @date 2023-09-27 17:11
+ * @desc
+ */
+public class ServletProcessor1 {
+  public void process(Request request, Response response) {
+    String uri = request.getUri();
+    String servletName = uri.substring(uri.lastIndexOf("/") + 1);
+    URLClassLoader loader = null;
+
+    try {
+      URL[] urls = new URL[1];
+      URLStreamHandler streamHandler = null;
+      File classPath = new File(HttpServer1.WEB_ROOT);
+      String repository =
+          (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString();
+      urls[0] = new URL(null, repository, streamHandler);
+      loader = new URLClassLoader(urls);
+    } catch (IOException e) {
+      System.out.println(e);
+    }
+
+    Class myClass = null;
+    try {
+      myClass = loader.loadClass(servletName);
+    } catch (ClassNotFoundException e) {
+      System.out.println(e);
+      System.exit(2);
+    }
+    Servlet servlet = null;
+    try {
+      servlet = (Servlet) myClass.getDeclaredConstructor().newInstance();
+      //      String header = "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n" + "\r\n";
+      //      response.getWriter().print(header.getBytes());
+      servlet.service(request, response);
+    } catch (Exception e) {
+      System.out.println(e);
+    }
+  }
+}

+ 19 - 0
src/pyrmont/ex02/StaticResourceProcessor.java

@@ -0,0 +1,19 @@
+/* Copyright (C) 2019-2023 Hangzhou HSH Co. Ltd.
+ * All right reserved.*/ package pyrmont.ex02;
+
+import java.io.IOException;
+
+/**
+ * @author simon
+ * @date 2023-09-27 17:11
+ * @desc
+ */
+public class StaticResourceProcessor {
+  public void process(Request request, Response response) {
+    try {
+      response.sendStaticResource();
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+  }
+}

BIN
webroot/PrimitiveServlet.class