Updated "Introduction to Python Web Application Homebrew for Slow 3rd Year Web Engineers"

Updated the book

Chapter "Allow HTML files to be delivered" has been updated. ..

If you want to read more, please like the book or follow the author ;-)


The following is an excerpt of the contents of the book.


Interpret the request and allow it to return the specified HTML file

Up to the previous chapter, we were able to create a server that can return a response in HTTP format.

However, it doesn't implement any processing to interpret the request sent from the browser, so the body always returns It works! No matter what request comes in.

This is not enough, so prepare an HTML file separately from the program source code in advance so that the file specified in the request path can be returned as the response body.

This is a so-called * static file distribution * function.

Since it is not necessary to publish the source code of the server through the server, ** put the files you want to publish through the server in the directory study / static / **.

Example) Request path is /index.html => The contents of study / static / index.html are returned as a response body

And so on.

Source code

I won't explain anything else, so let's go straight to the source code.

Here is an improved version that can return the HTML file prepared in advance as a response body.

study/WebServer.py

import os
import socket
from datetime import datetime


class WebServer:
    """
A class that represents a web server
    """
    #Directory with executable files
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))
    #Directory to put files for static distribution
    DOCUMENT_ROOT = os.path.join(BASE_DIR, "static")

    def serve(self):
        """
Start the server
        """

        print("===Start the server===")

        try:
            #Generate socket
            server_socket = socket.socket()
            server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

            #Assign socket to localhost port 8080
            server_socket.bind(("localhost", 8080))
            server_socket.listen(10)

            #Wait for a connection from the outside and establish a connection if there is a connection
            print("===Wait for a connection from the client===")
            (client_socket, address) = server_socket.accept()
            print(f"===The connection with the client is complete remote_address: {address} ===")

            #Get the data sent from the client
            request = client_socket.recv(4096)

            #Write the data sent from the client to a file
            with open("server_recv.txt", "wb") as f:
                f.write(request)

            #The entire request
            # 1.Request line(The first line)
            # 2.Request body(2nd line-blank line)
            # 3.Request body(Blank line~)
            #Perth to
            request_line, remain = request.split(b"\r\n", maxsplit=1)
            request_headers, request_body = remain.split(b"\r\n\r\n", maxsplit=1)

            #Parse the request line
            method, path, http_version = request_line.decode().split(" ")

            #At the beginning of path/And keep it as a relative path
            relative_path = path.lstrip("/")
            #Get the path of the file
            static_file_path = os.path.join(self.DOCUMENT_ROOT, relative_path)

            #Generate a response body from a file
            with open(static_file_path, "r") as f:
                response_body = f.read()

            #Generate response line
            response_line = "HTTP/1.1 200 OK\r\n"
            #Generate response header
            response_header = ""
            response_header += f"Date: {datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')}\r\n"
            response_header += "Host: HenaServer/0.1\r\n"
            response_header += f"Content-Length: {len(response_body.encode())}\r\n"
            response_header += "Connection: Close\r\n"
            response_header += "Content-Type: text/html\r\n"

            #Generate the entire response
            response = (response_line + response_header + "\r\n" + response_body).encode()

            #Send a response to the client
            client_socket.send(response)

            #End communication
            client_socket.close()

        finally:
            print("===Stop the server.===")


if __name__ == '__main__':
    server = WebServer()
    server.serve()

https://github.com/bigen1925/introduction-to-web-application-with-python/blob/main/codes/chapter11/WebServer.py

Also, to check if the program is working properly, you need to prepare an HTML file separately, so create that as well. Create a new static directory directly under the study directory and create index.html in it.

Since it's a big deal, I changed it to something that is not Apache's puck. You can use whatever you like. However, if you change the file name, it will not work as described in this manual, so leave the file name as index.html.

study/static/index.html

<!doctype html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>HenaServer</title>
</head>
<body>
  <h1>Welcome to HenaServer!</h1>
</body>
</html>

https://github.com/bigen1925/introduction-to-web-application-with-python/blob/main/codes/chapter11/static/index.html

Commentary

Lines 10-13: Definition of the directory to put the HTML file

Defines the directory where the HTML files will be placed (called DOCUMENT_ROOT).

    #Directory with executable files
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))
    #Directory to put files for static distribution
    DOCUMENT_ROOT = os.path.join(BASE_DIR, "static")

It may be difficult to read if you are not familiar with file paths in python, --BASE_DIR: study absolute path to the directory --DOCUMENT_ROOT: study / static directory absolute path

Is stored.

Lines 43-61: Generate a response body from a file

This is the main.

The HTTP request is parsed (decomposed) and the path information is extracted.

After that, the file is read based on the path and the response body is generated.

            #The entire request
            # 1.Request line(The first line)
            # 2.Request body(2nd line-blank line)
            # 3.Request body(Blank line~)
            #Perth to
            request_line, remain = request.split(b"\r\n", maxsplit=1)
            request_headers, request_body = remain.split(b"\r\n\r\n", maxsplit=1)

            #Parse the request line
            method, path, http_version = request_line.decode().split(" ")

            #At the beginning of path/And keep it as a relative path
            relative_path = path.lstrip("/")
            #Get the path of the file
            static_file_path = os.path.join(self.DOCUMENT_ROOT, relative_path)

            #Generate a response body from a file
            with open(static_file_path, "r") as f:
                response_body = f.read()

After getting the path, I combine it with DOCUMENT_ROOT to get the static_file_path, but note that I've removed the leading / before that.

This is because, as a specification of os.path.join (base, path) of python, if the absolute path starting with / is given to the second argument path, the first argument base will be ignored. is.

Try to move

If you know what you want to do, the source code is not difficult, so let's move it immediately.


Continue with Book!

Chapter "Allow HTML files to be delivered"

Recommended Posts

Updated "Introduction to Python Web Application Homebrew for Slow 3rd Year Web Engineers"
Updated "Introduction to Python Web Application Homebrew for Slow 3rd Year Web Engineers"
Updated "Introduction to Python Web Application Homebrew for Slow 3rd Year Web Engineers"
Updated "Introduction to Python Web Application Homebrew for Slow 3rd Year Web Engineers"
Updated "Introduction to Python Web Application Homebrew for Slow 3rd Year Web Engineers"
Updated "Introduction to Python Web Application Homebrew for Slow 3rd Year Web Engineers"
Updated "Introduction to Python Web Application Homebrew for Slow 3rd Year Web Engineers"
[Introduction to Udemy Python3 + Application] 43. for else statement
Introduction to Python For, While
[Introduction to Udemy Python3 + Application] 42. for statement, break statement, and continue statement
[Introduction to Udemy Python 3 + Application] 58. Lambda
[Introduction to Udemy Python 3 + Application] 31. Comments
[Introduction to Udemy Python 3 + Application] 57. Decorator
[Introduction to Udemy Python 3 + Application] 56. Closure
[Introduction to Udemy Python3 + Application] 59. Generator
[Introduction to Udemy Python 3 + Application] Summary
An introduction to Python for non-engineers
Easy-to-understand explanation of Python Web application (Django) even for beginners (5) [Introduction to DB operation with Django shell]
[Introduction to Udemy Python3 + Application] 18. List methods
[Introduction to Udemy Python3 + Application] 63. Generator comprehension
[Introduction to Udemy Python3 + Application] 28. Collective type
[Introduction to Udemy Python3 + Application] 25. Dictionary-type method
[Introduction to Udemy Python3 + Application] 33. if statement
[Introduction to Udemy Python3 + Application] 13. Character method
[Introduction to Udemy Python3 + Application] 55. In-function functions
[Introduction to Udemy Python3 + Application] 48. Function definition
[Introduction to Udemy Python 3 + Application] 10. Numerical values
[Introduction to Udemy Python3 + Application] 21. Tuple type
[Introduction to Udemy Python3 + Application] 45. enumerate function
[Introduction to Udemy Python3 + Application] 41. Input function
[Introduction to Udemy Python3 + Application] 17. List operation
[Introduction to Udemy Python3 + Application] 65. Exception handling
[Introduction to Udemy Python3 + Application] 11. Character strings
[Introduction to Udemy Python3 + Application] 44. range function
[Introduction to Udemy Python3 + Application] 46. Zip function
[Introduction to Udemy Python3 + Application] 24. Dictionary type
[Python] Web application design for machine learning
An introduction to Python for machine learning
[Introduction to Udemy Python3 + Application] 8. Variable declaration
[Introduction to Udemy Python3 + Application] 29. Set method
[Introduction to Udemy Python3 + Application] 16. List type
[Introduction to Udemy Python3 + Application] 61. Dictionary comprehension
[Introduction to Udemy Python 3 + Application] 22. Tuple unpacking
An introduction to Python for C programmers
[Introduction to Udemy Python3 + Application] 47. Process the dictionary with a for statement
Take the free "Introduction to Python for Machine Learning" online until 4/27 application
An introduction to self-made Python web applications for a sluggish third-year web engineer
Easy-to-understand explanation of Python web application (Django) even for beginners (4) [Routing settings / Introduction to MTV design patterns]
Updated to Python 2.7.9
[Introduction to Udemy Python 3 + Application] 26. Copy of dictionary
[Introduction to Udemy Python3 + Application] 60. List comprehension notation
[Introduction to Udemy Python 3 + Application] 19. Copy of list
[Introduction to Udemy Python 3 + Application] 38. When judging None
Introduction to Tornado (1): Python web framework started with Tornado
[Introduction to Udemy Python3 + Application] 40.while else statement
[Introduction to Udemy Python3 + Application] 62. Set comprehension notation
Steps to develop a web application in Python
[Introduction to Udemy Python3 + Application] 64. Namespace and Scope
[Introduction to Python3 Day 20] Chapter 9 Unraveling the Web (9.1-9.4)
[Introduction to Udemy Python3 + Application] 67. Command line arguments
[Introduction to Udemy Python3 + Application] 9. First, print with print