mirror of
https://github.com/csd4ni3l/browser.git
synced 2026-01-01 04:03:43 +01:00
Add backgrounds to finish layout tutorial, add inline and remote CSS support with a default of browser.css which currently supports fonts and backgrounds
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import socket, logging, ssl, threading, os
|
||||
import socket, logging, ssl, threading, os, ujson, time
|
||||
|
||||
from http_client.html_parser import HTML, CSSParser, Element, tree_to_list, get_inline_styles
|
||||
|
||||
class HTTPClient():
|
||||
def __init__(self):
|
||||
@@ -11,6 +13,8 @@ class HTTPClient():
|
||||
self.response_headers = {}
|
||||
self.response_http_version = None
|
||||
self.response_status = None
|
||||
self.nodes = []
|
||||
self.css_rules = []
|
||||
self.content_response = ""
|
||||
self.view_source = False
|
||||
self.redirect_count = 0
|
||||
@@ -20,7 +24,7 @@ class HTTPClient():
|
||||
with open(url.split("file://", 1)[1], "r") as file:
|
||||
self.content_response = file.read()
|
||||
|
||||
def get_request(self, url, request_headers):
|
||||
def get_request(self, url, request_headers, css=False):
|
||||
if url.startswith("view-source:"):
|
||||
url = url.split("view-source:")[1]
|
||||
self.view_source = True
|
||||
@@ -54,7 +58,7 @@ class HTTPClient():
|
||||
|
||||
cache_filename = f"{self.scheme}_{self.host}_{self.port}_{self.path.replace('/', '_')}.json"
|
||||
if os.path.exists(f"http_cache/{cache_filename}"):
|
||||
self.needs_render = True
|
||||
threading.Thread(target=self.parse, daemon=True).start()
|
||||
return
|
||||
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
@@ -75,9 +79,9 @@ class HTTPClient():
|
||||
|
||||
self.socket.send(request.encode())
|
||||
|
||||
threading.Thread(target=self.receive_response, daemon=True).start()
|
||||
threading.Thread(target=self.receive_response, daemon=True, args=(css,)).start()
|
||||
|
||||
def receive_response(self):
|
||||
def receive_response(self, css=False):
|
||||
buffer = b""
|
||||
headers_parsed = False
|
||||
content_length = None
|
||||
@@ -123,6 +127,9 @@ class HTTPClient():
|
||||
logging.error(f"Error receiving messages: {e}")
|
||||
break
|
||||
|
||||
self.socket.close()
|
||||
self.socket = None
|
||||
|
||||
if 300 <= int(self.response_status) < 400:
|
||||
if self.redirect_count >= 4:
|
||||
return
|
||||
@@ -134,9 +141,9 @@ class HTTPClient():
|
||||
self.get_request(f"{self.scheme}://{self.host}{location_header}", self.request_headers)
|
||||
else:
|
||||
self.redirect_count = 0
|
||||
self.socket.close()
|
||||
|
||||
self.needs_render = True
|
||||
|
||||
if not css:
|
||||
self.parse()
|
||||
|
||||
def _parse_headers(self, header_data):
|
||||
lines = header_data.splitlines()
|
||||
@@ -164,3 +171,61 @@ class HTTPClient():
|
||||
except ValueError:
|
||||
logging.error(f"Error parsing header line: {line}")
|
||||
self.response_headers = headers
|
||||
|
||||
def parse(self):
|
||||
self.css_rules = []
|
||||
|
||||
cache_filename = f"{self.scheme}_{self.host}_{self.port}_{self.path.replace('/', '_')}.json"
|
||||
|
||||
original_scheme = self.scheme
|
||||
original_host = self.host
|
||||
original_port = self.port
|
||||
original_path = self.path
|
||||
original_response = self.content_response
|
||||
|
||||
if cache_filename in os.listdir("http_cache"):
|
||||
with open(f"http_cache/{cache_filename}", "r") as file:
|
||||
self.nodes = HTML.from_json(ujson.load(file))
|
||||
else:
|
||||
self.nodes = HTML(self.content_response).parse()
|
||||
with open(f"http_cache/{cache_filename}", "w") as file:
|
||||
json_list = HTML.to_json(self.nodes)
|
||||
file.write(ujson.dumps(json_list))
|
||||
|
||||
css_links = [
|
||||
node.attributes["href"]
|
||||
for node in tree_to_list(self.nodes, [])
|
||||
if isinstance(node, Element)
|
||||
and node.tag == "link"
|
||||
and node.attributes.get("rel") == "stylesheet"
|
||||
and "href" in node.attributes
|
||||
]
|
||||
|
||||
for css_link in css_links:
|
||||
self.content_response = ""
|
||||
|
||||
if "://" in css_link:
|
||||
self.get_request(css_link, self.request_headers, True)
|
||||
|
||||
if not css_link.startswith("/"):
|
||||
dir, _ = self.path.rsplit("/", 1)
|
||||
css_link = dir + "/" + css_link
|
||||
|
||||
if css_link.startswith("//"):
|
||||
self.get_request(self.scheme + ":" + css_link, self.request_headers, True)
|
||||
else:
|
||||
self.get_request(self.scheme + "://" + self.host + ":" + str(self.port) + css_link, self.request_headers, True)
|
||||
|
||||
while not self.content_response:
|
||||
time.sleep(0.025)
|
||||
|
||||
self.css_rules.extend(CSSParser(self.content_response).parse())
|
||||
|
||||
self.css_rules.extend(get_inline_styles(self.nodes))
|
||||
|
||||
self.scheme = original_scheme
|
||||
self.host = original_host
|
||||
self.port = original_port
|
||||
self.path = original_path
|
||||
self.content_response = original_response
|
||||
self.needs_render = True
|
||||
Reference in New Issue
Block a user