Данный репозиторий - попытка ответить на извечный вопрос на интервью "Что происходит, когда вы набираете google.com в строке вашего браузера и нажимаете Ввод?"
Только вместо обычного рассказа, мы постараемся ответить на этот вопрос как можно более подробно, ничего не упуская. Это коллективная процедура, так что вникайте и старайтесь помочь! Не хватает множества деталей, мы просто ждем, когда вы их добавите! Поэтому, пожалуйста, отправьте нам Pull Request!
Распространяется на условиях Лицензии Creative Commons Zero
.
- Нажата клавиша "G".
- Клавиша "Ввод" опускается до самого низа.
2.1 В случае USB-клавиатуры:
2.2 В случае виртуальной клавиатуры (как в устройствах с сенсорным экраном): - Срабатывает прерывание (Не для USB-клавиатур).
3.1 (В Windows) Сообщение "WM_KEYDOWN" отправляется приложению.
3.2 (В OS X) NSEvent KeyDown отправляется приложению.
3.3 (В GNU/Linux) Сервер Xorg слушает коды клавиш. - Парсинг URL.
- Это URL или поисковый запрос?
- Преобразование не-ASCII символов Unicode в имени хоста.
- Проверка списка HSTS.
- Поиск DNS.
- Процесс ARP.
9.1 Запрос ARP
9.2 Прямое подключение
9.3 Переключатель - Открытие сокета.
- Установление связи TLS.
- Если пакет отброшен?!
- Протокол HTTP.
- Обработка запроса HTTP сервера.
- За кулисами браузера.
- Синтаксический анализ - HTML, CSS, JS
16.1 Высокоуровневая структура браузера - Парсинг HTML.
- Интерпретация CSS.
- Рендеринг страницы.
- Рендеринг процессора.
- Сервер Windows.
- Последующий рендеринг и пользовательское выполнение.
В следующих разделах объясняются физические действия с клавиатуры и прерывания работы операционной системы.
При нажатии клавиши "G" браузер получает сообщение о событии и запускает функции автозаполнения. В зависимости от алгоритма работы вашего браузера и от того, находитесь ли вы в режиме приватности / инкогнито или нет, вам будут представлены различные предложения в выпадающем списке под строкой URL. Большинство из этих алгоритмов сортируют и определяют приоритетность результатов на основе истории поиска, закладок, файлов cookie и популярных поисковых запросов в Интернете в целом. При вводе "google.com" запускается множество блоков кода, и предложения будут уточняться с каждым нажатием клавиши. Он может даже предложить "google.com" до того, как вы закончите вводить его.
Чтобы выбрать нулевую точку, давайте нажмем клавишу Ввод на клавиатуре в нижней части диапазона клавиш. В этот момент электрическая цепь, соответствующая клавише Ввод, замыкается (либо напрямую, либо емкостно). Это позволяет небольшому количеству тока поступать в логическую схему клавиатуры, которая сканирует состояние каждого переключателя клавиш, устраняет электрические помехи, возникающие при быстром прерывистом замыкании переключателя, и преобразует их в целое число с кодом клавиши, в данном случае 13. Затем контроллер клавиатуры кодирует код клавиши для передачи на компьютер. В настоящее время это почти повсеместно осуществляется через универсальную последовательную шину (USB) или Bluetooth-соединение, но исторически это происходило через PS/2 или ADB-соединения.
USB-схема клавиатуры питается от источника питания напряжением 5 В, подключенного к контакту 1 USB-контроллера компьютера. Сгенерированный код ключа сохраняется во внутренней памяти клавиатуры в регистре, называемом "конечная точка". Главный USB-контроллер опрашивает эту "конечную точку" каждые ~10 мс (минимальное значение, объявленное клавиатурой), поэтому он получает сохраненное на нем значение кода ключа. Это значение передается в USB SIE (модуль последовательного интерфейса) для преобразования в один или несколько USB-пакетов, которые соответствуют низкоуровневому USB-протоколу. Эти пакеты передаются с помощью дифференциального электрического сигнала по контактам D+ и D- (средние 2) с максимальной скоростью 1,5 Мб/с, поскольку устройство HID (устройство для взаимодействия с человеком) всегда считается "низкоскоростным устройством" (соответствует стандарту USB 2.0). Этот последовательный сигнал затем декодируется на главном USB-контроллере компьютера и интерпретируется драйвером универсального клавиатурного устройства HID компьютера. Значение ключа затем передается на уровень аппаратной абстракции операционной системы.
Когда пользователь прикасается пальцем к современному емкостному сенсорному экрану, к пальцу передается небольшое количество тока. Это замыкает цепь через электростатическое поле проводящего слоя и создает падение напряжения в этой точке экрана. Затем экранный контроллер выдает прерывание, сообщающее о координате нажатия клавиши.
Затем мобильная операционная система уведомляет приложение, на котором в данный момент сосредоточено внимание, о событии нажатия в одном из элементов графического интерфейса (который теперь является кнопками приложения виртуальной клавиатуры).
Виртуальная клавиатура теперь может вызывать программное прерывание для отправки сообщения "нажата клавиша" обратно в операционную систему. Это прерывание уведомляет текущее приложение о событии "нажата клавиша".
Клавиатура отправляет сигналы в строке запроса на прерывание (IRQ), которая преобразуется контроллером прерываний в вектор прерываний (целое число). Центральный процессор использует таблицу дескрипторов прерываний (IDT) для сопоставления векторов прерываний с функциями (обработчиками прерываний), которые предоставляются ядром. Когда поступает прерывание, центральный процессор индексирует IDT с вектором прерывания и запускает соответствующий обработчик. Таким образом, вступает ядро.
Транспорт HID передает событие нажатия клавиши драйверу KBDHID.sys, который преобразует использование HID в скан-код. В данном случае скан-кодом является VK_RETURN (0x0D). Драйвер KBDHID.sys взаимодействует с KBDCLASS.sys (драйвер класса клавиатуры). Этот драйвер отвечает за безопасную обработку всех данных, вводимых с клавиатуры. Затем он обращается к Win32K.sys (возможно, после прохождения сообщения через установленные фильтры клавиатуры сторонних производителей). Все это происходит в режиме ядра.
'Win32K.sys' определяет, какое окно является активным, с помощью 'API GetForegroundWindow()'. Этот API предоставляет дескриптор окна для адресной строки браузера. Затем основной "поток сообщений" Windows вызывает SendMessage('hWnd, WM_KEYDOWN, VK_RETURN, lParam'). lParam - это битовая маска, которая указывает дополнительную информацию о нажатии клавиши: количество повторений (в данном случае 0), фактический код сканирования (может зависеть от производителя, но, как правило, не относится к 'VK_RETURN'), были ли также нажаты дополнительные клавиши (например, 'alt, shift, ctrl') (они не были нажаты), и какое-то другое состояние.
Windows SendMessage API - это простая функция, которая добавляет сообщение в очередь для конкретного дескриптора окна (hWnd). Позже вызывается основная функция обработки сообщений (называемая 'WindowProc'), назначенная hWnd, для обработки каждого сообщения в очереди.
Активное окно ('hWnd') на самом деле является элементом управления редактированием, и WindowProc в этом случае имеет обработчик сообщений для сообщений 'WM_KEYDOWN'. Этот код просматривается в пределах 3-го параметра, который был передан в SendMessage (wParam), и, поскольку именно 'VK_RETURN' знает, что пользователь нажал клавишу 'ENTER'.
Сигнал прерывания запускает событие прерывания в драйвере клавиатуры kext Kit ввода-вывода. Драйвер преобразует сигнал в код клавиши, который передается серверному процессу OS X WindowServer. В результате оконный сервер отправляет событие любым подходящим приложениям (например, активным или прослушивающим) через их Mach-порт, где оно помещается в очередь событий. Затем события могут быть считаны из этой очереди потоками с достаточными привилегиями, вызывающими функцию mach_ipc_dispatch. Чаще всего это происходит через основной цикл обработки событий NSApplication и обрабатывается им с помощью NSEvent из NSEventType KeyDown.
Когда используется графический сервер X, X будет использовать универсальный драйвер событий evdev для получения нажатия клавиши. Повторное сопоставление кодов клавиш со сканкодами выполняется с использованием специальных сопоставлений клавиш и правил для X-сервера. Когда отображение сканкода нажатой клавиши завершено, X-сервер отправляет символ оконному менеджеру (DWM, metacity, i3 и т.д.), а оконный менеджер, в свою очередь, отправляет символ в сфокусированное окно. Графический API окна, принимающего символ, выводит соответствующий символ шрифта в соответствующем выделенном поле.
Теперь браузер имеет следующую информацию, содержащуюся в URL-адресе (единый указатель ресурсов):
Протокол "http"
Используйте "Протокол передачи гипертекста"
Ресурс "/"
Извлеките главную (индексную) страницу
Если не указан протокол или действительное доменное имя, браузер отправляет текст, указанный в адресной строке, в поисковую систему браузера по умолчанию. Во многих случаях к URL-адресу добавляется специальный фрагмент текста, сообщающий поисковой системе, что он взят из строки URL-адреса конкретного браузера.
Браузер проверяет имя хоста на наличие символов, отличных от a-z, A-Z, 0-9, -, или .. Поскольку имя хоста google.com, его там не будет, но если бы оно было, браузер применил бы кодировку Punycode к части URL, содержащей имя хоста.
Браузер проверяет свой список "предварительно загруженных HSTS (HTTP Strict Transport Security)". Это список веб-сайтов, которые запросили доступ только по протоколу HTTPS. Если веб-сайт есть в списке, браузер отправляет запрос по протоколу HTTPS, а не по протоколу HTTP. В противном случае первоначальный запрос отправляется по протоколу HTTP. (Обратите внимание, что веб-сайт все равно может использовать политику HSTS, не находясь в списке HSTS. При первом HTTP-запросе пользователя к веб-сайту будет получен ответ с просьбой отправлять только HTTPS-запросы. Однако этот единственный HTTP-запрос потенциально может сделать пользователя уязвимым для атаки с понижением версии, поэтому в современных веб-браузерах включен список HSTS.)
Браузер проверяет, есть ли домен в его кэше. (чтобы просмотреть кэш DNS в Chrome, перейдите по ссылке chrome://net-internals/#dns). Если он не найден, браузер вызывает библиотечную функцию gethostbyname (зависит от операционной системы) для выполнения поиска. Gethostbyname проверяет, можно ли разрешить имя хоста по ссылке в локальном файле hosts (расположение которого зависит от операционной системы), прежде чем пытаться разрешить имя хоста через DNS. Если gethostbyname не сохранен в кэше и не может быть найден в файле hosts, он отправляет запрос на DNS-сервер, настроенный в сетевом стеке. Обычно это локальный маршрутизатор или кэширующий DNS-сервер интернет-провайдера. Если DNS-сервер находится в той же подсети, сетевая библиотека выполняет описанный ниже процесс ARP для DNS-сервера. Если DNS-сервер находится в другой подсети, сетевая библиотека выполняет описанный ниже процесс ARP для IP-адреса шлюза по умолчанию.
Для отправки широковещательной передачи по протоколу ARP (протокол разрешения адресов) библиотеке сетевого стека необходим целевой IP-адрес для поиска. Ей также необходимо знать MAC-адрес интерфейса, который она будет использовать для отправки широковещательной передачи по протоколу ARP. Сначала кэш ARP проверяется на наличие записи ARP для нашего целевого IP. Если она есть в кэше, библиотечная функция возвращает результат: Целевой IP = MAC.
Если записи нет в кэше ARP:
Выполняется просмотр таблицы маршрутов, чтобы узнать, находится ли целевой IP-адрес в какой-либо из подсетей в локальной таблице маршрутов. Если это так, библиотека использует интерфейс, связанный с этой подсетью. Если это не так, библиотека использует интерфейс, который имеет подсеть нашего шлюза по умолчанию. Выполняется поиск MAC-адреса выбранного сетевого интерфейса. Сетевая библиотека отправляет ARP-запрос уровня 2 (канальный уровень модели OSI):
MAC отправителя: interface:mac:address:here
IP отправителя: interface.ip.goes.here
Целевой MAC: FF:FF:FF:FF:FF:FF (Broadcast)
Целевой IP: target.ip.goes.here
В зависимости от того, какой тип оборудования находится между компьютером и маршрутизатором:
Если компьютер напрямую подключен к маршрутизатору, маршрутизатор ответит ARP-ответом (см. ниже) Хаб:
Если компьютер подключен к концентратору, концентратор будет транслировать запрос ARP со всех других портов. Если маршрутизатор подключен к тому же "проводу", он отправит ответ ARP (см. ниже).
Если компьютер подключен к коммутатору, коммутатор проверит свою локальную таблицу CAM/MAC, чтобы узнать, какой порт содержит искомый MAC-адрес. Если у коммутатора нет данных для MAC-адреса, он повторно передаст запрос ARP на все остальные порты.
Если у коммутатора есть запись в таблице MAC/CAM, он отправит запрос ARP на порт, который имеет искомый MAC-адрес.
Если маршрутизатор подключен к тому же "проводу", он отправит ответ ARP (см. ниже).
Теперь, когда у сетевой библиотеки есть IP-адрес либо нашего DNS-сервера, либо шлюза по умолчанию, она может возобновить процесс tsDNS:
MAC отправителя: target:mac:address:here
IP отправителя: target.ip.goes.here
Целевой MAC: interface:mac:address:here
Целевой IP: interface.ip.goes.here
DNS-клиент устанавливает сокет на UDP-порт 53 на DNS-сервере, используя исходный порт выше 1023. Если размер ответа слишком велик, вместо него будет использоваться протокол TCP. Если у локального DNS-сервера/интернет-провайдера его нет, то запрашивается рекурсивный поиск, который перемещается вверх по списку DNS-серверов до тех пор, пока не будет достигнут SOA, и, если он найден, возвращается ответ.
Как только браузер получает IP-адрес конечного сервера, он берет его и указанный номер порта из URL-адреса (по умолчанию для протокола HTTP используется порт 80, а для HTTPS - порт 443), вызывает функцию системной библиотеки с именем socket и запрашивает поток сокетов TCP - AF_INET/AF_INET6 и SOCK_STREAM.
Этот запрос сначала передается на транспортный уровень, где создается сегмент TCP. Порт назначения добавляется в заголовок, а порт источника выбирается из динамического диапазона портов ядра (ip_local_port_range в Linux). Этот сегмент отправляется на сетевой уровень, который передает дополнительный IP-заголовок. Для формирования пакета вводятся IP-адреса сервера назначения, а также текущего компьютера. Затем пакет поступает на канальный уровень. Добавляется заголовок фрейма, который включает MAC-адрес сетевой карты компьютера, а также MAC-адрес шлюза (локального маршрутизатора). Как и прежде, если ядро не знает MAC-адрес шлюза, оно должно отправить запрос ARP, чтобы найти его. На этом этапе пакет готов к передаче через любой из:
Локальная сеть
Wi-Fi
Сотовая сеть передачи данных
Для большинства подключений к Интернету для дома или малого бизнеса пакет передается с вашего компьютера, возможно, через локальную сеть, а затем через модем (модулятор/демодулятор), который преобразует цифровые 1 и 0 в аналоговый сигнал, пригодный для передачи по телефонным, кабельным или беспроводным телефонным соединениям. На другом конце соединения находится другой модем, который преобразует аналоговый сигнал обратно в цифровые данные для обработки следующим узлом сети, где адреса "от" и "к" будут проанализированы дополнительно. Большинство крупных предприятий и некоторые новые жилые комплексы имеют оптоволоконные или прямые Ethernet-соединения, и в этом случае данные остаются цифровыми и передаются непосредственно на следующий сетевой узел для обработки. В конце концов, пакет достигнет маршрутизатора, управляющего локальной подсетью. Оттуда он продолжит путь к пограничным маршрутизаторам автономной системы (AS), в других случаях и, наконец, к целевому серверу. Каждый маршрутизатор на своем пути извлекает адрес назначения из IP-заголовка и перенаправляет его на соответствующий следующий переход. Поле time to live (TTL) в IP-заголовке уменьшается на единицу для каждого проходящего маршрутизатора. Пакет будет отброшен, если поле TTL достигнет нуля или если у текущего маршрутизатора не будет свободного места в очереди (возможно, из-за перегрузки сети).
Эта отправка и получение происходят несколько раз в соответствии с потоком TCP-соединений:
- Клиент выбирает начальный порядковый номер (ISN) и отправляет пакет на сервер с установленным битом SYN, указывающим на то, что он устанавливает ISN
- Сервер получает SYN и, если он в хорошем настроении:
- Сервер сам выбирает свой начальный порядковый номер
- Сервер устанавливает SYN, чтобы указать, что он выбирает свой ISN
- Сервер копирует (client ISN +1) в свое поле подтверждения и добавляет флаг подтверждения, чтобы указать, что он подтверждает получение первого пакета
- Клиент подтверждает соединение, отправляя пакет:
- Увеличивает свой собственный порядковый номер
- Увеличивает номер подтверждения получателя
- Устанавливает поле подтверждения
Передача данных осуществляется следующим образом:
Когда одна сторона отправляет N байт данных, она увеличивает свой SEQ на это число.
Когда другая сторона подтверждает получение этого пакета (или цепочки пакетов), она отправляет подтверждающий пакет со значением подтверждения, равным последней полученной последовательности от другой стороны.
Чтобы закрыть соединение:
Closer отправляет пакет FIN
Другая сторона подтверждает получение пакета FIN и отправляет свой собственный FIN
Closer подтверждает подтверждение FIN другой стороны
- Клиентский компьютер отправляет серверу сообщение ClientHello с указанием версии протокола Transport Layer Security (TLS), списка доступных алгоритмов шифрования и методов сжатия.
- Сервер отправляет клиенту сообщение ServerHello с версией TLS, выбранным шифром, методами сжатия и открытым сертификатом сервера, подписанным Центром сертификации (CA). Сертификат содержит открытый ключ, который будет использоваться клиентом для шифрования остальной части квитирования до тех пор, пока не будет согласован симметричный ключ.
- Клиент проверяет цифровой сертификат сервера на соответствие своему списку доверенных центров сертификации. Если доверие может быть установлено на основе центра сертификации, клиент генерирует строку псевдослучайных байтов и шифрует ее с помощью открытого ключа сервера. Эти случайные байты могут быть использованы для определения симметричного ключа.
- Сервер расшифровывает случайные байты с помощью своего закрытого ключа и использует эти байты для создания собственной копии симметричного мастер-ключа.
- Клиент отправляет готовое сообщение на сервер, зашифровывая хэш-код, который был передан до этого момента, с помощью симметричного ключа.
- Сервер генерирует свой собственный хэш, а затем расшифровывает отправленный клиентом хэш, чтобы убедиться в его совпадении. Если это так, он отправляет клиенту свое собственное готовое сообщение, также зашифрованное симметричным ключом.
- С этого момента сеанс TLS передает данные приложения (HTTP), зашифрованные с помощью согласованного симметричного ключа.
Иногда из-за перегрузки сети или сбоев в подключении оборудования пакеты TLS отбрасываются до того, как они дойдут до конечного пункта назначения. Затем отправитель должен решить, как реагировать. Алгоритм для этого называется TCP congestion control. Это зависит от отправителя; наиболее распространенными алгоритмами являются cubic в новых операционных системах и New Reno почти во всех остальных.
Клиент выбирает время перегрузки на основе максимального размера сегмента (MSS) соединения. Для каждого подтвержденного пакета размер окна увеличивается вдвое, пока не достигнет "порога медленного запуска". В некоторых реализациях этот порог является адаптивным. После достижения порогового значения медленного запуска окно увеличивается для каждого подтвержденного пакета. Если пакет отбрасывается, окно уменьшается экспоненциально до тех пор, пока не будет подтвержден другой пакет.
Если используемый веб-браузер был создан компанией Google, то вместо отправки HTTP-запроса для получения страницы он отправит запрос на попытку согласовать с сервером "обновление" с HTTP до протокола SPDY. Если клиент использует протокол HTTP и не поддерживает SPDY, он отправляет запрос на сервер вида:
ПОЛУЧИТЬ / HTTP/1.1
Хост: google.com
Соединение: закрыть
[другие заголовки]
где [другие заголовки] относятся к серии пар ключ-значение, разделенных двоеточием, отформатированных в соответствии со спецификацией HTTP и разделенных отдельными символами новой строки. (Предполагается, что в используемом веб-браузере нет ошибок, нарушающих спецификацию HTTP. Это также предполагает, что веб-браузер использует HTTP/1.1, в противном случае он может не включать заголовок Host в запрос, и версия, указанная в запросе GET, будет либо HTTP/1.0, либо HTTP/0.9.).
HTTP/1.1 определяет параметр "закрыть" соединение, чтобы отправитель мог сигнализировать о том, что соединение будет закрыто после завершения ответа. Например, Connection: закрыть. Приложения HTTP/1.1, которые не поддерживают постоянные соединения, должны включать параметр "закрыть" соединение в каждое сообщение.
После отправки запроса и заголовков веб-браузер отправляет на сервер одну пустую строку перевода текста, указывающую на то, что содержание запроса выполнено.
Сервер выдает код ответа, обозначающий статус запроса, и выдает ответ следующего вида:
200 ОК
[заголовки ответа]
За которыми следует одна новая строка, а затем отправляется полезная нагрузка в виде HTML-содержимого www.google.com. Затем сервер может либо закрыть соединение, либо, если заголовки, отправленные клиентом, запрашивают это, сохранить соединение открытым для повторного использования для дальнейших запросов.
Если HTTP-заголовки, отправленные веб-браузером, содержат достаточную информацию для веб-сервера, чтобы определить, была ли версия файла, кэшированного веб-браузером, неизменена с момента последнего извлечения (т.е. если веб-браузер включил заголовок ETag), он может вместо этого ответить запросом формы:
304 Не изменено
[заголовки ответов]
[заголовки ответов] и нет полезной нагрузки, а веб-браузер вместо этого извлекает HTML из своего кэша.
После синтаксического анализа HTML веб-браузер (и сервер) повторяет этот процесс для каждого ресурса (изображения, CSS, favicon.ico и т.д.), на который ссылается HTML-страница, за исключением того, что вместо GET / HTTP/1.1 запрос будет GET /$(URL относительно www.google.com) HTTP/1.1. Если HTML-код ссылается на ресурс, расположенный в домене, отличном от www.google.com, веб-браузер возвращается к шагам, связанным с разрешением доступа к другому домену, и выполняет все действия до этого момента для этого домена. В заголовке Host в запросе будет указано соответствующее имя сервера вместо google.com.
Сервер HTTPD (HTTP-демон) обрабатывает запросы и ответы на стороне сервера. Наиболее распространенными HTTPD-серверами являются Apache или nginx для Linux и IIS для Windows.
Запрос получает HTTPD (HTTP-демон). Сервер разбивает запрос на следующие параметры:
Метод HTTP-запроса
(GET, HEAD, POST, PUT, PATCH, DELETE, CONNECT, OPTIONS или TRACE
).
В случае URL-адреса, введенного непосредственно в адресную строку, это будет GET. Домен, в данном случае - 'google.com'. Запрашиваемый путь/страница, в данном случае - / (поскольку конкретный путь/страница не запрашивались, по умолчанию используется путь "/").
- Сервер проверяет, настроен ли на сервере виртуальный хост, соответствующий google.com.
- Сервер проверяет, может ли google.com принимать запросы GET.
- Сервер проверяет, разрешено ли клиенту использовать этот метод (по IP, аутентификации и т.д.).
Если на сервере установлен модуль перезаписи (например, mod_rewrite для Apache или URL Rewrite для IIS), он пытается сопоставить запрос с одним из настроенных правил. Если найдено подходящее правило, сервер использует это правило для перезаписи запроса. Сервер извлекает содержимое, соответствующее запросу, в нашем случае оно возвращается к индексному файлу, поскольку "/" является основным файлом (в некоторых случаях это можно переопределить, но это наиболее распространенный метод). Сервер анализирует файл в соответствии с обработчиком. Если Google работает на PHP, сервер использует PHP для интерпретации индексного файла и передает выходные данные клиенту.
Как только сервер предоставляет ресурсы
(HTML, CSS, JS, изображения и т.д.
)
браузеру, он выполняет описанный ниже процесс:
- Синтаксический анализ - HTML, CSS, JS
- Рендеринг - Построение дерева DOM → Дерево рендеринга → Макет дерева рендеринга → Отображение дерева рендеринга в браузере
Функциональность браузера заключается в представлении выбранного вами веб-ресурса путем запроса его с сервера и отображения в окне браузера. Ресурс обычно представляет собой HTML-документ, но также может быть в формате PDF, с изображением или каким-либо другим типом содержимого. Местоположение ресурса определяется пользователем с помощью URI (Единый Идентификатор Ресурса).
Способ, которым браузер интерпретирует и отображает HTML-файлы, указан в спецификациях HTML и CSS. Эти спецификации поддерживаются организацией W3C (World Wide Web Consortium), которая является организацией по стандартизации в Интернете.
Пользовательские интерфейсы браузеров имеют много общего друг с другом. К числу общих элементов пользовательского интерфейса относятся:
- Адресная строка для ввода URI
- Кнопки "Назад" и "Вперед"
- Параметры закладок
- Кнопки "Обновить" и "Остановить" для обновления или остановки загрузки текущих документов
- Кнопка "Домой", которая приведет вас на вашу домашнюю страницу
Компонентами браузеров являются:
- Пользовательский интерфейс: Пользовательский интерфейс включает в себя адресную строку, кнопки возврата/перемотки вперед, меню закладок и т.д. Все части экрана браузера, кроме окна, в котором вы видите запрашиваемую страницу.
- Движок браузера: Движок браузера управляет действиями между пользовательским интерфейсом и движком рендеринга.
- Движок рендеринга: движок рендеринга отвечает за отображение запрошенного контента. Например, если запрошенный контент является HTML, движок рендеринга анализирует HTML и CSS и отображает обработанный контент на экране.
- Сетевое взаимодействие: Сеть обрабатывает сетевые вызовы, такие как HTTP-запросы, используя различные реализации для разных платформ, используя независимый от платформы интерфейс.
- Внутренний интерфейс пользовательского интерфейса: Внутренний интерфейс пользовательского интерфейса используется для создания базовых виджетов, таких как поля со списком и окна. Этот внутренний интерфейс предоставляет общий интерфейс, который не зависит от платформы. В своей основе он использует методы пользовательского интерфейса операционной системы.
- Движок JavaScript: Движок JavaScript используется для анализа и выполнения кода JavaScript.
- Хранение данных: Хранилище данных представляет собой постоянный уровень. Браузеру может потребоваться локальное сохранение всех видов данных, таких как файлы cookie. Браузеры также поддерживают такие механизмы хранения, как localStorage, IndexedDB, WebSQL и файловая система.
Механизм рендеринга начинает получать содержимое запрошенного документа с сетевого уровня. Обычно это выполняется фрагментами по 8 Кб.
Основная задача HTML-анализатора - преобразовать HTML-разметку в дерево синтаксического анализа.
Дерево вывода ("дерево синтаксического анализа") - это дерево элементов DOM и узлов атрибутов. DOM - это сокращение от Document Object Model. Это объектное представление HTML-документа и интерфейс HTML-элементов с внешним миром, такой как JavaScript. Корнем дерева является объект "Document". Перед выполнением любых манипуляций с помощью сценариев DOM имеет почти однозначное отношение к разметке.
Алгоритм синтаксического анализа
HTML не может быть проанализирован с помощью обычных синтаксических анализаторов "сверху вниз" или "снизу вверх". Причины в том, что: Язык прост в использовании. Тот факт, что браузеры традиционно допускают ошибки для поддержки хорошо известных случаев некорректного HTML. Процесс синтаксического анализа является повторным. Для других языков исходный код не меняется во время синтаксического анализа, но в HTML динамический код (например, элементы скрипта, содержащие вызовы document.write()), может добавлять дополнительные токены, поэтому процесс синтаксического анализа фактически изменяет входные данные. Не имея возможности использовать обычные методы синтаксического анализа, браузер использует пользовательский синтаксический анализатор для анализа HTML. Алгоритм синтаксического анализа подробно описан в спецификации HTML5. Алгоритм состоит из двух этапов: токенизации и построения дерева.
Действия по завершении синтаксического анализа
Браузер начинает извлекать внешние ресурсы, связанные со страницей (CSS, изображения, файлы JavaScript и т.д.). На этом этапе браузер помечает документ как интерактивный и запускает синтаксический анализ сценариев, которые находятся в "отложенном" режиме: те, которые должны быть выполнены после анализа документа. Состояние документа устанавливается на "завершено" и запускается событие "загрузка". Обратите внимание, что на HTML-странице никогда не появляется ошибка "Недопустимый синтаксис". Браузеры исправляют любое недопустимое содержимое и продолжают работу.
Анализируются файлы CSS, содержимое тега <style> и значения атрибутов стиля, используя "лексическую и синтаксическую грамматику CSS". Каждый файл CSS преобразуется в объект таблицы стилей, где каждый объект содержит правила CSS с селекторами и объектами, соответствующими грамматике CSS. Синтаксический анализатор CSS может работать как сверху вниз, так и снизу вверх, когда используется определенный генератор синтаксических анализаторов. Создается "Дерево фреймов" или "Дерево рендеринга", пройдя по узлам DOM и вычислив значения стиля CSS для каждого узла. Вычисляется предпочтительная ширина каждого узла в "Дереве фреймов" снизу вверх, суммируя предпочтительную ширину дочерних узлов и горизонтальные поля, границы и отступы узла.
Вычисляется фактическая ширина каждого узла сверху вниз, распределив доступную ширину каждого узла между его дочерними узлами. Рассчитывается высота каждого узла снизу вверх, применяя перенос текста и суммируя высоты дочерних узлов, а также поля, границы и отступы узла. Рассчитываются координаты каждого узла, используя информацию, полученную выше.
Более сложные действия выполняются при перемещении элементов, их абсолютном или относительном расположении или при использовании других сложных функций. Более подробную информацию смотрите в разделах http://dev.w3.org/csswg/css2/ и http://www.w3.org/Style/CSS/current-work.
Создаются слои, чтобы описать, какие части страницы можно анимировать как группу, не подвергая их повторной растеризации. Каждый кадр/объект рендеринга присваивается слою. Текстуры выделяются для каждого слоя страницы. Выполняется обход объектов кадрирования/рендеринга для каждого слоя и выполняются команды рисования для соответствующего слоя. Это может быть растеризовано центральным процессором или отрисовано непосредственно на графическом процессоре с использованием D2D/SkiaGL.
Все вышеперечисленные действия могут уменьшить вычисленные значения с момента последнего отображения веб-страницы, так что постепенные изменения потребуют меньше усилий.
Слои страницы отправляются в процесс компоновки, где они объединяются со слоями для другого видимого контента, такого как браузер chrome, iframes и дополнительные панели. Вычисляются окончательные позиции слоев и выполняются команды компоновки с помощью Direct3D/OpenGL. Буферы команд графического процессора загружаются в графический процессор для асинхронного рендеринга, и кадр отправляется на оконный сервер.
В процессе рендеринга графические вычислительные уровни также могут использовать CPU общего назначения или графический процессор GPU. При использовании графического процессора для вычислений графического рендеринга уровни графического программного обеспечения разделяют задачу на несколько частей, что позволяет использовать преимущества массового параллелизма графического процессора для вычислений с плавающей запятой, необходимых для процесса рендеринга.
После завершения рендеринга браузер выполняет код JavaScript в результате некоторого механизма синхронизации (например, анимации Google Doodle) или взаимодействия с пользователем (ввод запроса в поле поиска и получение предложений). Плагины, такие как Flash или Java, также могут запускаться, хотя в данный момент их нет на главной странице Google. Скрипты могут вызывать выполнение дополнительных сетевых запросов, а также изменять страницу или ее макет, вызывая повторный цикл рендеринга и перерисовки страницы.