Дело было вечером, делать было нечего, но голова рукам покоя не давала и хотелось чего-то для души… А для души захотелось чего-то новенького, эдакого необычного.
Я, как и многие из хабровчан, люблю новинки. Релиз нового софта — это как праздник. Новые фичи, новые возможности… Новые способы забивать гвозди и кататься на велосипедах. Новые велосипеды… В общем можно придумать кучу аллегорий и метафор. А про что это я? Ах да, про Nginx, HTTP2 и JavaScript. Чем они связаны, спросите вы? А тем, что в последней версии Nginx (1.9.5) добавили много интересных плюшек, а именно:
- добавили протокол HTTP2 и удалили модуль SPDY (нафиг старое барахло)
- интегрировали прямо в nginx модуль ngx_http_js_module и создали свой диалект JavaScript
Го под кат, расскажу детали.
Собственно, меня заинтересовали именно эти две фичи. Я опытный воин, перешедший из лагера (опечатка по фрейду – люблю лагер и темный эль) бекендеров на сторону фронтендеров. Но я продолжаю следить за любимыми инструментами, среди которых Ngnix.
Про HTTP2
Говорить много не буду. Он работает. Причем конфиг проще чем для SPDY. Ну или похожий. Чтобы собрать сервер с поддержкой HTTP2, при конфигурации добавляем параметр:
--with-http_v2_module
И все. Все просто, никаких патчей и сторонних либ, просто одна строчка при конфигурации перед сборкой. На хабре можно найти информацию по HTTP2:
Про JavaScript
О, это самое интересное! Фронтендеры, спешу сообщить вам, что у нас появился новый диалект JavaScript (ну нам не привыкать если чо) — это nginScript (энджин скрипт). Ура! Я всегда знал, что если у программиста есть микроскоп, то все вокруг кажется гвоздями. Шутка, дорогие программисты, шутка.
Скрипты на JavaScript могут использоваться прямо в файле конфигурации (!) для определения расширенной логики обработки запросов. Для формирования конфигурации, для динамической генерации ответа. Так же можно делать модификацию запроса и ответа. А еще можно быстро создавать заглушки с решением проблем в web-приложениях (aka «костыли» или временно сделаем так, а потом переделаем как надо). Это просто крутатошка крутатенюшка, вам скажу!
Сам скрипт запускается посредством директивы js_run и позволяет прямо на стороне сервера (что я несу?)… Нет, прямо в самом сервере выполнять многие низкоуровневые операции с запросом, без необходимости написания отдельного модуля на языке Си/Lua или на чем там еще пишут и решают такие задачи.
Для выполнения скриптов используется собственный движок njs. Для этого команда разработчиков Nginx реализовала свою версию виртуальной машины под урезанное подмножество языка JavaScript. Собственно, этот язык и назвали nginScript, дабы не путали с JavaScript, так как все же это именно подмножество. Что интересно: на каждый запрос запускается отдельная виртуальная машина, что позволяет обойтись без сборщика мусора. Язык JavaScript выбран как наиболее популярный язык программирования. Lua был хорошим претендентом, но он не так широко распространен в кругах web-разработчиков. Необходимость создания собственной виртуальной машины JavaScript обусловлена тем, что существующие движки оптимизированы для работы в браузере, в то время как для Nginx необходима не просто серверная реализация, но интегрированная в движок. В общем не потянули разработчики заюзать полноценный V8. Поэтому это JavaScript, но писать надо как под IE6, без выпендрежа. Все же это конфиг, если что.
NginScript обладает виртуальной машиной и компилятором байт кода с быстрым запуском и завершением работы. Блокирующие операции, такие как подзапросы HTTP, могут быть приостановлены и возобновлены по аналогии с другими блокирующими операциями в JS.
В язык описания конфигов Nginx добавлены синтаксические инструкции, позволяющие встраивать блоки кода на JS прямо в файл конфигурации. Подобные блоки выполняются по мере обработки HTTP-транзакций и позволяют для каждого запроса выполнять такие операции как корректировка внутренних параметров nginx, создание сложных условий, изменение запроса или ответа.
С помощью nginScript можно описывать конфиги, которые без написания дополнительных расширений и модулей могут динамически блокировать вредоносные запросы, эксплуатирующие уязвимости в web-приложениях или ограничивать интенсивность определённых запросов. Так же можно реализовывать гибкие правила перенаправления трафика, использующие информацию из запроса и не только.
А еще можно делать горячие костыли! Мы же можем исправлять ошибки в web-приложениях, изменять бизнес-логику, распределять запросы на несколько серверов с последующей агрегацией ответов от них и много чего еще… И все это прямо в конфиге. И все это на знакомом нам языке, который мы любим.
Так, много буков, давайте перейдем к установке и примерам.
Установка
Если не установлен меркуриал – ставим. А далее по инструкции:
# Obtain the latest source for NGINX from http://nginx.org/en/download.html
$ wget http://nginx.org/download/nginx-1.9.5.tar.gz
$ tar -xzvf nginx-1.9.5.tar.gz
# Obtain the development sources for nginScript
$ hg clone http://hg.nginx.org/njs
# Build and install NGINX
$ cd nginx-1.9.5
$ ./configure --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --user=www --group=www --with-ipv6 --with-pcre-jit --with-http_gzip_static_module --with-http_ssl_module --with-http_v2_module --add-module=../njs/nginx $ make -j2 && make install
nginScript aka JavaScript
Мы можем заранее предопределять переменные с результатами вычисления через директиву js_set:
js_set $js_txt "
var m = 'Hello ';
m += 'world!';
m;
";
server {
listen :443 ssl http2;
server_name edu.tutu.ru;
set $sname edu.tutu.ru;
set $root "/www/sites/$sname/www/public";
ssl_certificate /etc/nginx/ssl/edu.tutu.ru.pem;
ssl_certificate_key /etc/nginx/ssl/edu.tutu.ru.key;
include base.conf;
location /helloworld {
add_header Content-Type text/plain;
return 200 $js_txt;
}
}
Как видите, в качестве возвращаемого значения используется необычная инструкция. Странно, почему не сделали слово return. Прямо неожиданно и необычно. Но да ладно, сделали так сделали.
Как я понял директиву можно устанавливать вне блоков server. Иначе парсер ругается.
Вы можете сразу из конфига сгенерить контент и отдать его в браузер:
location /helloworld {
js_run "
var res;
res = $r.response;
res.contentType = 'text/plain';
res.status = 200;
res.sendHeader();
res.send('Hello, world!');
res.finish();
";
}
Давайте сделаем http_dump, м?
js_set $http_dump "
var a, s, h;
s = 'Request summary\n\n';
s += 'Method: ' + $r.method + '\n';
s += 'HTTP version: ' + $r.httpVersion + '\n';
s += 'Host: ' + $r.headers.host + '\n';
s += 'Remote Address: ' + $r.remoteAddress + '\n';
s += 'URI: ' + $r.uri + '\n';
s += 'Headers:\n';
for (h in $r.headers)
s += ' header \"' + h + '\" is \"' + $r.headers[h] + '\"\n';
s += 'Args:\n';
for (a in $r.args)
s += ' arg \"' + a + '\" is \"' + $r.args[a] + '\"\n';
s;
";
server {
listen :443 ssl http2;
server_name edu.tutu.ru;
set $sname edu.tutu.ru;
set $root "/www/sites/$sname/www/public";
ssl_certificate /etc/nginx/ssl/edu.tutu.ru.pem;
ssl_certificate_key /etc/nginx/ssl/edu.tutu.ru.key;
location /js/httpdump {
add_header Content-Type text/plain;
return 200 $js_summary;
}
}
А давайте напишем сервис для расчёта чисел Фибоначчи
Если есть микроскоп, то почему бы им не забить гвоздь? На вопрос зачем, настоящий программист/ученый/изобретатель всегда ответят: потому что я могу это сделать! Да, я могу написать такой сервис, не выходя из конфига Nginx, не устанавливая Nodejs, PHP или Ruby. Я могу все это сделать внутри сервера! Да!
location /js/getfib {
js_run "
function fib(n) {
var prev = 1,
curr = 1,
newc,
i;
if (n < 2) return n;
for (i = 3; i <= n; i++) {
newc = prev + curr;
prev = curr;
curr = newc;
}
return curr;
}
var n = +$r.args['n'],
txt = 'Fibonacci( ' + n + ' ) = ' + fib(n),
res = $r.response;
res.contentType = 'text/plain';
res.status = 200;
res.sendHeader();
res.send(txt);
res.send('\n');
res.finish();
";
}
Я хотел написать вместо:
newc = prev + curr;
prev = curr;
curr = newc;
деструктурированный код:
[ prev, curr ] = [ curr, prev + $curr ];
Но nginScript ничего не знает про ES2015/ES6. Тогда я написал так:
prev = [ curr, prev += curr ][0];
И тут тоже был фейл. Оказывается так писать тоже нельзя. Так что, друзья, не все можно. Эдакий IE5 получается. Но в целом мне понравилось.
Хорошего вам, чего у вас сейчас там.
Ссылки по теме
UPD
Пример привязки апстримов и динамического роутинга
upstream my_upstream0 {
server server1.example.com;
server server2.example.com;
}
upstream my_upstream1 {
server server3.example.com;
server server4.example.com;
}
js_set $my_upstream "
var s, upstream, upstream_num;
upstream = $r.args.upstream;
// convert upstream number to integer
upstream_num = +upstream | 0;
if (upstream_num < 0 || upstream_num > 1) {
upstream_num = 0;
}
s = 'my_upstream' + upstream_num;
s;
";
server {
listen 80;
location / {
proxy_set_header Host $host;
proxy_pass http://$my_upstream;
}
}
Комментарии (56)
grossws
30.09.2015 03:58+1Сам скрипт запускается посредством директивы js_run и позволяет прямо на стороне сервера (что я несу?)… Нет, прямо в самом сервере выполнять многие низкоуровневые операции с запросом, без необходимости написания отдельного модуля на языке Си/Lua или на чем там еще пишут и решают такие задачи.
Относительно простые вещи раньше можно было делать на lua и perl. Чтобы написать модуль для nginx'а на C надо очень заморочиться. Документации по nginx internals не сильно много, комментарием в коде и того меньше…
ZoomLS
30.09.2015 08:18+9Так скоро и приложения на nginx писать начнут :)
0xy
30.09.2015 09:40Приложения уже писали/пишут, но на Lua и фреймворке habrahabr.ru/post/240217
Но сообщество Lua web-разработчиков сильно меньше, чем сообщество JS разработчиков.
Игорь Сысоев решил это исправить =)
StamPit
30.09.2015 11:47+4«Не нужно программировать на конфигах nginx». Видимо, кто-то уже устал говорить эту фразу, превратив её в «А, чёрт с вами, программируйте!». Мне уже становится страшно, как представлю, что наши товарищи разработчики попытаются запихнуть туда из логики приложения.
0xy
30.09.2015 12:01+16Да, программировать конечно же не нужно. Но вдруг надо сделать какой-то подвыперт…
- Когда-то говорили что на JS не напишешь ничего хорошего… Не пытайтесь даже...
- Потом говорили — Js на сервере? Ха, смешно, но играйтесь, если так нравится. Но оно не взлетит...
- Операционная система на JS? Ой, как забавненько, но оно не взлетит...
- Плагины для браузера на JS — интересная идея, но на С++ будет лучше...
- Браузер на JS — не смешите меня...
- Десктопное приложение на JS — ну хватит уже...
- IDE на JS — да ты упоротый...
- Программировать микроконтроллеры на JS??? — 0_о ...
- Конфиги для Nginx на JS — блин, ну не смешно же...
…
прошло еще 30 лет… В ВУЗЕ преподают низкоуровненвое программирование. Преподаватель:
… JavaScript — это ассемблер, язык на котором написано всё…nsinreal
30.09.2015 12:09Я надеюсь WebAssembly и спрос на производительный веб избавит нас от подобного будущего. Распространеность этого языка обусловлена ростом веба и соответствующим спросом на разработчиков, умеющих программировать под единственый язык, заимплеменченный во всех браузерах.
forgotten
30.09.2015 19:10+2Осталось объяснить популярность всего остального в списке, начиная с Node.js
Вот уж микроконтроллеры явно не фронтендеры программируют.VolCh
30.09.2015 19:30+1Цепная реакция, начавшаяся именно с Node.js во многом благодаря чистым фронтендерам с одной стороны, и фулл-стэкерам, не дождавшимся возможности писать нормально для браузеров на любимом языке :)
forgotten
30.09.2015 19:41Чтобы началась цепная реакция, одной безвыходности недостаточно.
nsinreal
30.09.2015 20:09-1Ну да, еще нужно критическое состояние. По-моему количество веб-сайтов уже является примером критического состояния.
VolCh
30.09.2015 20:19Само по себе нет. Но вот с учетом фронтендеров и фулл-стэкеров, которым JS именно нравится или хотя бы выглядит приемлимым и для бэкенда… Плюс отлаженный движок, конкурирующий по скорости чуть ли не с сями, плюс асинхронный ио по дефолту, плюс интерпретируемость…
nsinreal
30.09.2015 20:03+2Ну давай пройдусь по пунктам:
1. Приложения в браузере. Ну… Эта, давайте я не буду напоминать лишний раз о том, что приложения в браузере не дотягивают до уровня десктопных?
2. Node.js — изоморфные приложения, избавление от необходимости дублировать логику, серверный рендринг страниц и прочие плюшки. Популярность понятна.
3. Операционная система на js? NodeOs что-ли? Это там где взяли linux, выкинули bash и поставили node.js? Мне чё, сделать brainfuck os, чтобы показать абсурдность ситуации? Или может имеются в виду всякого рода веб-оси, которые прикольны только как концепт, но ничего сделать не позволяют?
4. Плагины для браузера на js? Логично их писать на js, раз веб пишется на js. А давать возможность писать их на C++ — упадет, поломает, уязвимости всякие.
5. Браузер на JS? Ну давайте, покажите мне браузер на js. Я например пользуюсь Вивальди, у которого UI сделан на react. Да, UI написан на javascript. Глюки пока списываю на то, что браузер не вышел в релиз, однако некоторые артефакты весьма специфичны для глюкавых html/css. Если подключиться к самому вивальди через developer tools, то можно увидеть засранную консоль от ошибок типичных для языка с динамической типизацией. Однако это UI, сам браузер написан на другом языке.
6. Десктопное приложение на JS? Ну, в эпоху когда люди хотят все онлайн, то написать веб-приложение, а потом упаковать его node-webkit выглядит логичным решением. Или нет?
7. IDE на JS? О да, я даже знаю одну такую — LightTable. Правда она написана на clojurescript. Просто у людей, которые её писали был выбор между clojure (компилится в java) и clojurescript (компилится в javascript). Так уж получилось, что писать UI оптимальнее с использованием html/css/js. Будет WebAssembly — будет транскомпиляция туда. Работает кстати хорошо, быстренько вроде. Правда консоль опять же засрана типичными ошибками для языков с динамической типизацией.
8. Микроконтроллеры на JS? А почему вы уверены, что их не фронтендеры программируют? И вообще, как насчет python, rust? Это просто удешевление рынка игрушек для гиков. Гугление показало, что в тех микроконтроллерах характеристики лучше, чем у моего первого компьютера (если что, я молод душой и телом). Рост характеристик позволил писать программы на языках с динамической типизацией. А я таки уверен, что среди фронтенд разработчиков много людей, которым интересны такого рода игрушки. Спрос есть, возможность есть — банальные законы рынка. Но если рассматривать не игрушечный бизнес, то сколько компаний пишут софт для микроконтроллеров на javascript?
9. Конфиги на JS? Внимательное чтение статьи намекает, что это не javascript, а всего-лишь диалект. Кроме того, ну а чем javascript не хороший язык для скриптов? Ведь он для них и задумывался. Вот приложения на нем писать больно, да, а скрипты норм.
Вообще, еще можно вспомнить mongodb и couchbase, как базы данных, в которых юзается javascript для юзерских скриптов. Но все это не важно. Веб порождает спрос на javascript разработчиков, javascript разработчики порождают спрос на плюшки, с которыми они могут работать. Вопрос заключается в том, как быстро сойдет спрос на javascript разработчиков, когда появятся реальные альтернативы, а не транскомпиляторы недоделанные?
Давайте представим гипотетическую ситуацию. Какая-нибудь компания стартует большой проект. У компании есть выбор между двумя языками программирования: каким-нибудь из хороших и javascriptом. При сравнении эти языки оказываются одинаковыми по дешевизне разработки, количеству разработчиков, количеству библиотек и прочее-прочее в рамках этого проекта. Как много компаний вы знаете, которые выбрали или пожелали бы выбрать javascript потому что ну это же javascript — клёвый язык программирования; и разработчики под него хорошие и толковые; и завершим мы проект пораньше, потому что язык такой хороший?VolCh
30.09.2015 20:08Но если рассматривать не игрушечный бизнес, то сколько компаний пишут софт для микроконтроллеров на javascript?
Может не прямо для микроконтроллеров, но для ембедед девайсов пишут (или аутсорясят разработку) на джс мировые (не ИТ) бренды.nsinreal
30.09.2015 20:10Пруфы?
VolCh
30.09.2015 20:23-1NDA
Но если посмотрите вокруг себя на девайсы с экранами, может даже тач, но не являющиеся пк, смартфонами, планшетами и т. п., то в многих из них как минимум веб-морда к функциональности, будет выглядить достойной для рассмотрения альтернативой нативным гуи-приложениям.nsinreal
30.09.2015 20:54-1Т.е. только отрисовка UI? А альтернативой им будет C++ под кастомную платформу, более дорогие и редкие разработчики и сложности при разработке связанные с тем, что нету эмулятора устройства? Ну в данном случае это действительно хороший выбор по дешевизне разработки.
VolCh
01.10.2015 09:34Разные варианты встречаются. Только работа веб-UI с локальным сервером на Сях или Питоне, взаимодействующим с миром и железом — минимальный. Максимум, пожалуй — всё нестандартное на джсе, если периферия типа купюропреемника или датчика скорости на стандартных интерфейсах типа юсб или ком (не редкость). Средний вариант — обвязка (высокоуровневые драйверы поверх низкоуровневых от вендора) для железа на Сях, локальный сервер и ЮИ на джсе.
DigitalSmile
30.09.2015 16:25Но вдруг надо сделать какой-то подвыперт…
Вроде везде черным по белому пишут, что на nginx не надо программировать. Не сталкивался с ситуацией, когда можно было бы реализовать какую либо фичу только программированием в конфигах… Поправьте, если это не так.0xy
30.09.2015 16:33+1Все что описано в статье предлагают сами разработчики Nginx. Как пример, они говорят про сложные роутинги динамические, персональные ссылки, авторизацию и так далее…
DigitalSmile
30.09.2015 16:43-1Да, я понимаю, что это разработчики nginx. Но ведь согласитесь, что с точки зрения архитектуры, эти задачи находятся на логическом (бизнес) уровне приложения. Мне как то странно думать, что веб сервер, в задачи которого входит отдача статического контента и проксирование, будет вместо приложения рулить роутингом или авторизацией…
Единственное что приходит на ум в качестве примера использования таких модулей, это legacy код, который не можешь физически поправить, но при этом позарез нужен именно nginx. Но такие случаи достаточно редки в общей массе применений, поэтому поддержать это на уровне ядра… Ну не знаю, тот же Lua в модуле и никому не мешает. У кого есть надобность, тот и поставил и использует вполне осознанно.0xy
30.09.2015 16:57С Lua есть засада — его еще учить надо. Так что это те же возможности, но на другой лад. Я не сомневаюсь что это даже просто дань тренду. Вряд ли Луа медленнее получившегося JS. И в Lua больше возможностей из коробки, там интепретатор полноценный, а не урезанный.
На самом деле когда люди сами попробуют пописать конфиги — быстро пыл спадет. Отладка сложная, почему упал сервер — не сразу понятно. Так что это то еще развлечение.
gre
30.09.2015 12:21А что с производительстью?
Сильно тормозить будет?0xy
30.09.2015 12:47+2Хочу на досуге провести тесты. В идеале сравнить с Lua и, соответственно, вообще без встроенной динамики.
AterCattus
30.09.2015 15:59Пока js версия не дорастет по функционалу до lua, как-то не совсем честно. Но все-равно полезно.
igordata
30.09.2015 13:52+1Статья написана в приятной манере хорошим языком. Побольше бы таких статей! Спасибо.
Интересно, на js можно будет в нгиксе сделать привязку агентов к апстримным серверам? Хоть через ту же куку.0xy
30.09.2015 14:01+1Вы про это?
Custom Request Routing.
With the location block in NGINX you can route traffic based on URI. With nginScript you can route traffic based on any data in the request, including cookies, headers, arguments, or any keywords in the request body. The following example routes traffic based on the presence of an argument named upstream:
upstream my_upstream0 { server server1.example.com; server server2.example.com; } upstream my_upstream1 { server server3.example.com; server server4.example.com; } js_set $my_upstream " var s, upstream, upstream_num; upstream = $r.args.upstream; // convert upstream number to integer upstream_num = +upstream | 0; if (upstream_num < 0 || upstream_num > 1) { upstream_num = 0; } s = 'my_upstream' + upstream_num; s; "; server { listen 80; location / { proxy_set_header Host $host; proxy_pass http://$my_upstream; } }
toxicdream
30.09.2015 15:22+1Вирусы в конфигах — фрустрацирую, однако.
0xy
30.09.2015 15:25+4Когда люди качают докер, не вникая что внутри, когда выполняют рекомендации типа sudo wget ...../install.sh | bash. вирусы в конфиге уже не являются злом. Зато вот обфусцированный код в конфиге — это да. Написал конфиг, но не хочешь секрет раскрывать. Мол проприетарный он. Вот это поле для размышления =)
mgremlin
30.09.2015 16:30Прикольная штука. Интересно, будет ли этот модуль в поставке по умолчанию? Lua-то вроде не было, надо было компилить отдельно, а лень.
А вообще — давно пора, роутинг давно требует неких несложных вычислений в конфиге. Очень обидно ставить костылик на отдельный сервер, даже и через сокет, когда вопрос-то — всего лишь хэш от запроса, например.
Mithgol
30.09.2015 17:47-5Читал https://t.co/F9K8oSjgQO и радостно, довольно, заливисто смеялся: сервер NGINX станет напоминать сервер Express.js в скором времени!…
— Mithgol (@FidonetRunes) 24 сентября 2015
BreatheInMyVoid
30.09.2015 21:15Если кому-то интересно то дополню: есть похожая тема openresty.org Это похожая штука со встроенной Lua и кучей либ в придачу.
Antelle
01.10.2015 00:56Диалект будет — значит, они написали движок сами, а не взяли готовую реализацию. Почему, интересно?
Где-то можно почитать про движок?
xandr0s
01.10.2015 12:13В блоге у них есть про причины создания собственной реализации: nginScript – Why Are We Creating Our Own JavaScript Implementation?. Если кратко — это не совсем JS как он есть. Это упрощенная модель для каких-то простых инструкций на высоконагруженном сервере. Для всего остального есть NodeJS =)
gto
01.10.2015 15:23Lua был хорошим претендентом, но он не так широко распространен в кругах web-разработчиков
Кто же допускает веб-разработчиков к серверным конфигам. Если идти дальше, то JavaScript тоже не очень распространён среди, скажем, маркетологов, даёшь nginVBA.0xy
01.10.2015 16:24nginVBA — это JScript
JScript – это версия JavaScript от Microsoft. JScript основан на реализации стандарта ECMAScript. Синтаксис JScript во многом похож на язык JavaScript. Так же используется при создании вэб-страниц ASP.
ru.wikipedia.org/wiki/JScript
grossws
Да, с удалением spdy весело, если mainline репозиторий был подключен и использовалось автоматическое обновление. Т. е. обновишься с 1.9.4 на 1.9.5 и не заметишь, что после reload всё ещё 1.9.4 работает, т. к. конфиги стали невалидными.
Жалко, что server push пока не поддерживается в http2, хотя и не понятно, как он должен работать, если nginx используется в качестве reverse proxy и upstream не использует http2.
ibKpoxa
В http2 устанавливается https соединение и через расширение протокола клиент и сервер переключаются на http2, если оба его поддерживают, иначе работают через https. Да и не факт, что nginx поддерживает http2 соединение с апстримом, скорее всего пока что не поддерживает.
grossws
Это не так. В http2 устанавливается TLS соединение и в client hello обычно используется NPN/ALPN. Далее:
— если сервер поддерживает NPN/ALPN, то он отдаёт доступные протоколы в server hello и клиент, выбрав один, передаёт его в encrypted extensions во второй фазе handshake'а, далее клиент уже работает по http2;
— если сервер не поддерживает NPN/ALPN, то используется http/1.1 over TLS и делается http upgrade (что требует ещё не менее 2x RTT).
VBart
Никакого http upgrade не делается, просто работает и дальше по https.
grossws
Не прав ни я, ни вы. В http/2 upgrade поддерживается только для h2c (cleartext) и запрещено использование upgrade поверх h2.
http2.github.io/http2-spec/#rfc.section.3.2Т. е., если клиент не поддерживает ALPN — он сразу идёт лесом, на обычный http/1.1 over TLS.
Видимо, мне в мозг запало обсуждение этого драфта.