Tornado source analysis – ETag implementation

Etag (URL of the Entity Tag) :

For specific Etag is what, request process and realize the principle of not described here, you can refer to the following link: http://www.oschina.net/questi… https://zh.wikipedia.org/wiki…

Tornado realization analysis:

First from the Tornado handle a request to call order began to watch (from document: http://www.tornadoweb.cn/documentation) : The program creates a RequestHandler object for each request. The program calls the initialize() function, which takes the keyword parameter definitions in the Application configuration. (The initialize method is a new addition to Tornado 1.1, in older versions you would have to override __init__ for the same purpose.) Initialize methods generally just store the passed parameters in member variables. Without producing any output or calling methods like send_error. The program calls prepare(). Prepare is called regardless of which HTTP method is used, so this method is usually defined in a base class and reused in subclasses. Prepare can produce an output message. If it calls finish (or a function like send_error '), the entire process ends. A program invokes an HTTP method: for example, get(), post(), put(), and so on. If there is a grouping match in the regular expression pattern of the URL, then the correlation match is passed in as a parameter to the method. ETag processing is expected at the end of a request, so find the call's finish() function:

Finish () —- : Tornado /web.py (deleted part of code not in this topic)

def finish(self, chunk=None): # Automatically support ETags and add the Content-Length header if # we have not flushed any content yet. if not self._headers_written: if (self._status_code == 200 and self.request.method in ("GET", "HEAD") and "Etag" not in self._headers): self.set_etag_header() if self.check_etag_header(): self._write_buffer = [] self.set_status(304) if self._status_code in (204, 304): assert not self._write_buffer, "Cannot send body with %s" % self._status_code self._clear_headers_for_304() elif "Content-Length" not in self._headers:  content_length = sum(len(part) for part in self._write_buffer) self.set_header("Content-Length", content_length)

When calling finish(), verify the HTTP request. If the status code is 200, the request method is GET or HEAD, and the ETag is not in the HTTP header, then the request has occurred for the first time. Next, the set_etag_header() function is called to write the etag to the header information

The set_etag_header() function —- address: tornado/web.py

def set_etag_header(self):
    etag = self.compute_etag()
    if etag is not None:
        self.set_header("Etag", etag)

Analysis: Then call compute_etag() to generate the etag. If the return is successful, call set_header() to write the etag to the “etag” field of the header information. See the function compute_etag() :

Compute_etag () function —- : Tornado /web.py

def compute_etag(self):
    hasher = hashlib.sha1()
    for part in self._write_buffer:
        hasher.update(part)
    return '"%s"' % hasher.hexdigest()

Analysis: The etag is generated by calling the hashlib library, and then through the loop of self._write_buffer, when the server file changes, the new object hasher is updated by calling the update() function in the hashlib. To return the latest ETag note: Self._write_buffer = []. If a page changes, it will be recorded to determine whether the page requested by the client has changed on the server side. The set_etag_header() function is used to generate ETag, and the check_etag_header() function is used to generate ETag.

Check_etag_header () check function —- : Tornado /web.py

def check_etag_header(self): etags = re.findall( br'\*|(? :W/)?" [^"]*"', utf8(self.request.headers.get("If-None-Match", "")) ) if not computed_etag or not etags: return False match = False if etags[0] == b'*': match = True else: # Use a weak comparison when comparing entity-tags. def val(x): return x[2:] if x.startswith(b'W/') else x for etag in etags: if val(etag) == val(computed_etag): match = True break return match

Analysis: First, the server gets the “If-None-Match” field in the header message sent by the client, gets the ETag, and matches it with the regular expression to see If it is the same as the ETag saved by the server. If the etag field in the header is not retrieved or does not match the server’s etag, False is returned. Then, if the check_etag_header() function returns True, the request contains the etag and the etag is the same as the one stored by the server. T then clears this field with self._write_buffer = [] (indicating that the requested page has not been modified) and returns the status code 304 to the client.

Solve problem 304

Remove ‘if-none-match’ from request header

del self.request.headers['If-None-Match']

The resources