code: def _http_parser(self):
          
          # first, find first EOL (i.e. get request line)
          yield from self._receive_eol_token()
  
          # split the request line and headers (modifies buffer)
          yield from self._parse_and_store_req_line(self.EOL_TOKEN)
  
          # completes when all headers have been processed and stored
          yield from self._parse_and_store_headers()
  
          # we send back the rest of the body
          yield self._buffer
docs: Meat of the parsing algorithm. This is a generator that data is
          'sent' to by the consume method. Using the generator type allows
          state to be maintained despite not having all data. It is assumed
          that this is more efficient than checking state (headers parsed,
          EOL found, etc) on every consume call, but I'm not going to check
          this.
  
          Yields:
              None: Indicates headers have not been completed and the
                  parser is expecting more bytes to be sent to it (via
                  'send()')
              bytes: The (potentially incomplete) body data. This signifies
                  the parser has completed parsing HTTP headers (stored in
                  parser.headers) and should no longer be sent any data.