- PVSM.RU - https://www.pvsm.ru -
Эта статья является попыткой ответа на старый вопрос для собеседований: «Что же случается, когда вы печатаете в адресной строке google.com и нажимаете Enter?» Мы попробуем разобраться в этом максимально подробно, не пропуская ни одной детали.
Примечание: публикация основана на содержании репозитория What happens when... [2]
Представленный контент изобилует большим количеством терминов, в переводе некоторых из них могут присутствовать различные неточности. Если вы обнаружите какую-то ошибку в нашем переводе — напишите личным сообщением, и мы всё исправим.
Далее в статье содержится информация о работе физической клавиатуры и прерывания операционной системы. Но много чего происходит и помимо этого — когда вы нажимаете клавишу «g», браузер получает событие и запускается механизм автоподстановки. В зависимости от алгоритма браузера и его режима (включена ли функция «инкогнито») в выпадающем окне под строкой URL пользователю будет предложено определённое количество вариантов для автоподстановки.
Большинство алгоритмов автоподстановки ранжируют рекомендации в зависимости от истории поиска и оставленных закладках. Некоторые браузеры (например, Rockmelt) даже предлагают профили друзей на Facebook. Когда пользователь планирует напечатать в адресной строке «google.com», ничего из вышеперечисленного не играет роли, но тем не менее выполнится большое количество кода, а рекомендации будут обновляться с каждой новой напечатанной буквой. Возможно, браузер предложит перейти на google.com, до того, как пользователь вобьёт адрес целиком.
В качестве некой нулевой точки можно выбрать момент, когда клавиша Enter на клавиатуре нажата до конца и находится в нижнем положении. В этой точке замыкается электрическая цепь этой клавиши и небольшое количество тока отправляется по электросхеме клавиатуры, которая сканирует состояние каждого переключателя клавиши и конвертирует сигнал в целочисленный код клавиши (в данном случае — 13). Затем контроллер клавиатуры конвертирует код клавиши для передачи его компьютеру. Как правило, сейчас передача происходит через USB или Bluetooth, а раньше клавиатура подключалась к компьютеру с помощью коннекторов PS/2 или ADB.
В случае USB-клавиатуры:
В случае виртуальной клавиатуры (тачскрин):
Клавиатура отправляет сигналы в свою «линию запросов прерываний» (IRQ), которая затем сопоставляется с «вектором прерывания» (целое число) контроллером прерываний. Процессор использует «таблицу дескрипторов прерываний» (IDT) для сопоставления векторов прерываний с функциями («обработчики прерываний») ядра. Когда появляется прерывание, процессор (CPU) обновляет IDT вектором прерывания и запускает соответствующий обработчик. Таким образом, в дело вступает ядро.
WM_KEYDOWN
отправлено приложению
HID передаёт событие нажатой клавиши драйверу KBDHID.sys
, который конвертирует его в скан-код [3] (scancode). В данном конкретном случае скан-код — VK_RETURN
(0x0D
). Драйвер KDBHID.sys
связывается с драйвером KBDCLASS.sys
(драйвер классов клавиатуры). Он отвечает за безопасную обработку всего ввода с клавиатуры. В дальнейшем этот драйвер вызывает Win32K.sys
(после возможной передачи сообщения через установленные сторонние клавиатурные фильтры). Все это происходит в режиме ядра.
Win32K.sys определяет, какое окно активно в данный момент, с помощью функции GetForegroundWindow()
. Этот API обеспечивает обработку окна адресной строки в браузере. Затем главный «насос сообщений» Windows вызывает SendMessage(hWnd, WM_KEYDOWN, VK_RETURN, lParam)
. lParam
— это битовая маска, которая указывает на дальнейшую информацию о нажатии клавиши: счётчик повторов (в этом случае 0), актуальный скан-код (может зависеть от OEM, но VK_RETURN
обычно не зависит от этого), информацию о том, были ли нажаты дополнительные клавиши (например, Alt, Shift, Ctrl — в нашем случае не были) и некоторые другие данные.
В API Windows есть функция SendMessage
, которая помещает сообщение в очередь для конкретного обработчика окон (hWnd
). После этого для обработки всех сообщений очереди вызывается главная функция обработки сообщений (WindowProc
), присвоенная обработчику hWnd
.
Окно (hWnd
), активное в данный момент, представляет из себя контрол обработки и в этом случае у WindowsProc есть обработчик для сообщений WM_KEYDOWN
. Этот код изучает третий параметр, который поступил в SendMessage (wParam)
и, поскольку это VK_RETURN
, понимает, что пользователь нажал клавишу ENTER.
NSEVent KeyDown
отправлено приложению
Сигнал прерывания активирует событие прерывания в драйвере I/O Kit клавиатуры. Драйвер переводит сигнал в код клавиатуры, который затем передаётся процессу OS X под названием WindowServer
. В результате, WindowsServer
передаёт событие любому подходящему (активному или «слушающему») приложению через Mach-порт, в котором событие помещается в очередь. Затем события могут быть прочитаны из этой очереди потоками с достаточными привилегиями, чтобы вызывать функцию mach_ipc_dispatch
. Чаще всего это происходит и обрабатывается с помощью основного цикла NSApplication
через NSEvent
в NSEventype KeyDown
.
В случае графического X server, для получения нажатия клавиши будет использован общий драйвер событий evdev
. Переназначение клавиатурных кодов скан-кодам осуществляется с помощью специальных правил и карт X Server. Когда маппинг [4] скан-кода нажатой клавиши завершён, X server посылает символ в window manager (DWM, metacity, i3), который затем отправляет его в активное окно. Графический API окна, получившего символ, печатает соответствующий символ шрифта в нужном поле.
Теперь у браузера есть следующая информация об URL:
Protocol «HTTP»
Использовать «Hyper Text Transfer Protocol»Resource «/»
Показать главную (индексную) страницу
Когда пользователь не вводит протокол или доменное имя, то браузер «скармливает» то, что человек напечатал, поисковой машине, установленной по умолчанию. Часто к URL добавляется специальный текст, который позволяет поисковой машине понять, что информация передана из URL-строки определённого браузера.
a-z
, A-Z
, 0-9
, -
, или .
.gethostbyname
(отличается в разных ОС) для поиска нужного адреса.gethostbyname
пытается найти нужный адрес в файле hosts
(его расположение отличается в разных ОС).hosts
, gethostbyname
отправляет запрос к сетевому DNS-серверу. Как правило, это локальный роутер или DNS-сервер интернет-провайдера.Для того, чтобы отправить широковещательный ARP-запрос необходимо отыскать целевой IP-адрес, а также знать MAC-адрес интерфейса, который будет использоваться для отправки ARP-запроса.
Кэш ARP проверяется для каждого целевого IP-адреса — если адрес есть в кэше, то библиотечная функция возвращает результат: Target IP = MAC
.
Если же записи в кэше нет:
ARP-запрос:
Sender MAC: interface:mac:address:here
Sender IP: interface.ip.goes.here
Target MAC: FF:FF:FF:FF:FF:FF (Broadcast)
Target IP: target.ip.goes.here
В зависимости от того, какое «железо» расположено между компьютером и роутером (маршрутизатором):
Прямое соединение:
Между ними концентратор (Хаб):
Между ними коммутатор (свитч):
ARP-ответ:
Sender MAC: target:mac:address:here
Sender IP: target.ip.goes.here
Target MAC: interface:mac:address:here
Target IP: interface.ip.goes.here
Теперь у сетевой библиотеки есть IP-адрес либо DNS-сервера либо шлюза по умолчанию, который можно использовать для разрешения доменного имени:
Когда браузер получает IP-адрес конечного сервера, то он берёт эту информацию и данные об используемом порте из URL (80 порт для HTTP, 443 для HTTPS) и осуществляет вызов функции socket
системной библиотеки и запрашивает поток TCP сокета — AF_INET
и SOCK_STREAM
.
ip_local_port_range
в Linux).На этой точке пакет готов к передаче через:
В случае интернет-соединения большинства частных пользователей или небольших компаний пакет будет отправлен с компьютера, через локальную сеть, а затем через модем (MOdulator/DEModulator
), который транслирует цифровые единицы и нули в аналоговый сигнал, подходящий для передачи по телефонной линии, кабелю или беспроводным телефонным соединениям. На другой стороне соединения расположен другой модем, который конвертирует аналоговый сигнал в цифровые данные и передаёт их следующему сетевому узлу [11], где происходит дальнейший анализ данных об отправителе и получателе.
В конечном итоге пакет доберётся до маршрутизатора, управляющего локальной подсетью. Затем он продолжит путешествовать от одного роутера к другому, пока не доберётся до сервера назначения. Каждый маршрутизатор на пути будет извлекать адрес назначения из IP-заголовка и отправлять пакет на следующий хоп. Значение поля TTL (time to live) в IP-заголовке будет каждый раз уменьшаться после прохождения каждого роутера. Если значение поля TTL достигнет нуля, пакет будет отброшен (это произойдёт также если у маршрутизатора не будет места в текущей очереди — например, из-за перегрузки сети).
Во время TCP-соединения происходит множество подобных запросов и ответов.
a. Клиент выбирает номер начальной последовательности (ISN) и отправляет пакет серверу с установленным битом SYN для открытия соединения.
b. Сервер получает пакет с битом SYN и, если готов к установлению соединения, то:
c. Клиент подтверждает соединение путём отправки пакета:
d. Данные передаются следующим образом:
e. Закрытие соединения:
ClientHello
серверу со своей версией протокола TLS [12], списком поддерживаемых алгоритмов шифрования и методов компрессии данных.ServerHello
, содержащим версию TLS, выбранный метод шифрования, выбранные методы компрессии и публичный сертификат сервиса, подписанный центром сертификации. Сертификат содержит публичный ключ, который будет использоваться клиентом для шифрования оставшейся части процедуры «рукопожатия» (handshake
), пока не будет согласован симметричный ключ.Finished
, шифруя хеш передачи с помощью симметричного ключа.Finished
, также зашифрованный симметричным ключом.Если используемый браузер был создан Google, то вместо отправки HTTP-запроса для получения страницы, он отправит запрос, чтобы попытаться «договориться» с сервером об «апгрейде» протокола с HTTP до SPDY [13] («спиди»).
Если клиент использует HTTP-протокол и не поддерживает SPDY, то отправляет серверу запрос следующей формы:
GET / HTTP/1.1
Host: google.com
Connection: close
[другие заголовки]
где [другие заголовки]
— это серия пар «ключ: значение», разбитых переносом строки. (Здесь предполагается, что в использованном браузере нет никаких ошибок, нарушающих спецификацию HTTP. Также предполагается, что браузер использует HTTP/1.1
, в противном случае он может не включать заголовок Host
в запрос и версия, отданная в ответ на GET-запрос может быть HTTP/1.0
или HTTP/0.9
).
HTTP/1.1
определяет опцию закрытия соединения («close») для отправителя — с её помощью происходит уведомление о закрытии соединения после завершения ответа. К примеру:
Connection: close
Приложения HTTP/1.1
, которые не поддерживают постоянные соединения, обязаны включать опцию «close» в каждое сообщение.
После отправки запроса и заголовков, браузер отправляет серверу единичную пустую строку, сигнализируя о том, что содержимое сообщения закончилось.
Сервер отвечает специальным кодом, который обозначает статус запроса и включает ответ следующей формы:
200 OK
[заголовки ответа]
После этого посылается пустая строка, а затем оставшийся контент HTML-страницы www.google.com [14]. Сервер может затем закрыть соединение, или, если того требуют отправленные клиентом заголовки, сохранять соединение открытым для его использования следующими запросами.
Если HTTP-заголовки отправленные веб-браузером включают информацию, которой серверу достаточно для определения версии файла, закэшированного в браузере и этот файл не менялся со времени последнего запроса, то ответ может принять следующую форму:
304 Not Modified
[заголовки ответа]
и, соответственно, клиенту не посылается никакого контента, вместо этого браузер «достаёт» HTML из кэша.
После разбора HTML, браузер (и сервер) повторяет процесс загрузки для каждого ресурса (изображения, стили, скрипты, favicon.ico и так далее), на который ссылается HTML-страница, но при этом изменяется адрес каждого запроса c GET / HTTP/1.1
на GET /$(относительный URL ресурса www.google.com) HTTP/1.1
.
Если HTML ссылается на ресурс, размещённый на домене, отличном от google.com, то браузер возвращается к шагам, включающим разрешение доменного имени, а затем заново проходит процесс до текущего состояния, но уже для другого домена. Заголовок Host
в запросе вместо google.com будет установлен на нужное доменное имя.
HTTPD
(HTTP Daemon) является одним из инструментов обработки запросов/ответов на стороне сервера. Наиболее популярные HTTPD-серверы это Apache или Nginx для Linux и IIS для Windows.
— HTTPD (HTTP Daemon) получает запрос.
— Сервер разбирает запрос по следующим параметрам:
GET
, POST
, HEAD
, PUT
или DELETE
). В случае URL-адреса, который пользователь напечатал в строке браузера, мы имеем дело с GET-запросом./
(нет запрошенных путей, /
— это путь по умолчанию).— Сервер проверяет существование виртуального хоста, который соответствует google.com.
— Сервер проверяет, что google.com может принимать GET-запросы.
— Сервер проверяет, имеет ли клиент право использовать этот метод (на основе IP-адреса, аутентификации и прочее).
— Если на сервере установлен модуль перезаписи (mod_rewrite
для Apache или URL Rewrite
для IIS), то он сопоставляет запрос с одним из сконфигурированных правил. Если находится совпадающее правило, то сервер использует его, чтобы переписать запрос.
— Сервер находит контент, который соответствует запросу, в нашем случае он изучит индексный файл.
— Далее сервер разбирает («парсит») файл с помощью обработчика. Если Google работает на PHP, то сервер использует PHP для интерпретации индексного файла и направляет результат клиенту.
Задача браузера заключается в том, чтобы показывать пользователю выбранные им веб-ресурсы, запрашивая их с сервера и отображая в окне просмотра. Как правило такими ресурсами являются HTML-документы, но это может быть и PDF, изображения или контент другого типа. Расположение ресурсов определяется с помощью URL.
Способ, который браузер использует для интерпретации и отображения HTML-файлов описан в спецификациях HTML и CSS. Эти документы разработаны и поддерживаются консорциумом W3C (World Wide Wib Consortium), которая занимается стандартизацией веба.
Интерфейсы браузеров сильно похожи между собой. У них есть большое количество одинаковых элементов:
Браузер включает следующие компоненты:
localStorage
, IndexedDB
, WebSQL
и FileSystem
.Движок рендеринга начинает получать содержимое запрашиваемого документа от сетевого механизма браузера. Как правило, контент поступает кусками по 8Кб. Главной задачей HTML-парсера является разбор разметки в специальное дерево.
Получающееся на выходе дерево («parse tree») — это дерево DOM-элементов и узлов атрибутов. DOM — сокращение от Document Object Model
. Это модель объектного представления HTML-документа и интерфейс для взаимодействия HTML-элементов с «внешним миром» (например, JavaScript-кодом). Корнем дерева является объект «Документ».
HTML-нельзя «распарсить» с помощью обычных анализаторов (нисходящих или восходящих). Тому есть несколько причин:
document.write()
) могут добавляться дополнительные токены, в результате чего сам процесс парсинга модифицирует вывод.Невозможность использования привычных технологий парсинга приводит к тому, что разработчики браузеров реализуют собственные механизмы разбора HTML. Алгоритм парсинга подробно описан в спецификации HTML5 [15].
Алгоритм состоит из двух этапов: токенизации и создания дерева.
После этого браузер начинает подгружать внешние ресурсы, связанные со страницей (стили, изображения, скрипты и так далее).
На этом этапе браузер помечает документ, как интерактивный и начинает разбирать скрипты, находящиеся в «отложенном» состоянии: то есть те из них, что должны быть исполнены после парсинга. После этого статус документа устанавливается в состояние «complete
» и инициируется событие загрузки («load
»).
Важный момент: ошибки «Invalid Syntax»
при разборе не может быть, поскольку браузеры исправляют любой «невалидный» контент и продолжают работу.
<style>
и атрибутов «style» c помощью «лексической и синтаксической грамматики CSS [16]».StyleSheet
, каждый из таких объектов содержит правила CSS с селекторами и объектами в соответствии с грамматикой CSS.После завершения рендеринга, браузер исполняет JavaScript-код в результате срабатывания некоего часового механизма (так работают дудлы на странице Google) или в результате действий пользователя (ввод поискового запроса в строку и получение рекомендаций в ответ). Также могут срабатывать плагины вроде Flash или Java (но не в рассматриваемом примере с домашней страницей Google). Скрипты могут потребовать обработки дополнительных сетевых запросов, изменять страницу или её шаблон, что приведёт к следующему этапу рендеринга и отрисовки.
Автор: htmlacademy
Источник [19]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/it-infrastruktura/87845
Ссылки в тексте:
[1] Image: http://habrahabr.ru/company/htmlacademy/blog/254825/
[2] What happens when...: https://github.com/alex/what-happens-when
[3] скан-код: https://ru.wikipedia.org/wiki/%D0%A1%D0%BA%D0%B0%D0%BD-%D0%BA%D0%BE%D0%B4
[4] маппинг: https://ru.wikipedia.org/wiki/%D0%9C%D0%B0%D0%BF%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5
[5] downgrade-атакам: https://en.wikipedia.org/wiki/Moxie_Marlinspike#Notable_research
[6] Punycode: https://en.wikipedia.org/wiki/Punycode
[7] ARP-запрос: https://ru.wikipedia.org/wiki/ARP
[8] Ethernet: http://en.wikipedia.org/wiki/IEEE_802.3
[9] WiFi: https://en.wikipedia.org/wiki/IEEE_802.11
[10] По сотовой связи: https://en.wikipedia.org/wiki/Cellular_data_communication_protocol
[11] сетевому узлу: https://en.wikipedia.org/wiki/Computer_network#Network_nodes
[12] TLS: https://ru.wikipedia.org/wiki/TLS
[13] SPDY: https://ru.wikipedia.org/wiki/SPDY
[14] www.google.com: http://www.google.com
[15] спецификации HTML5: http://www.w3.org/TR/html5/
[16] лексической и синтаксической грамматики CSS: http://www.w3.org/TR/CSS2/grammar.html
[17] здесь: http://dev.w3.org/csswg/css2/
[18] здесь: http://www.w3.org/Style/CSS/current-work
[19] Источник: http://habrahabr.ru/post/254825/
Нажмите здесь для печати.