Базовой вопрос по Http.
От: Sharov Россия  
Дата: 05.06.20 22:06
Оценка:
Здравствуйте.

Имеется базовое непонимание работы http.

1)Допустим имеется клиент. Пусть имеется api, когда клиент что-то заращивает у сервера http get(большой json объект с 10000 записей). Правильно ли я понимаю, что в данном случае у меня http собирает данные (копит в буфере), и когда все данные будут доступны (в памяти), мой клиент получит один обычный http get ответ?

2)Допустим имеется сервер, который получает огромный (8гб) файл от клиента. Вот у меня в api есть stream параметр (networkstream в случае дотнет). Верно, что в данном случае мой сервер получит http post, хотя его тело (т.е. 8гб), еще до конца не получено? Т.е. я получю один http post и начинаю читать содержимое, которое до конца-то может и не придти, т.е. получается что http post в данном случае может не знать свой размер.

Т.е. я понимаю разницу между буферизацией и потоком, но я не понимаю как 2) случае все это будет физически оформлено в один http post.

3)Про физику процесса -- я правильно понимаю, что у меня данные копятся в буфере http, а tcp просто прокидывает chunk'и данных? И когда у меня данные закончились — все пришло, либо разрыв — то tcp манифистирует об этом http, и уже http либо оформляет стандартный запрос\ответ, либо у меня вылезает ошибка о разрыве (но в этом случае это не ошибка http, а tcp socket что-то там).

Заранее благодарю.
Кодом людям нужно помогать!
Re: Базовой вопрос по Http.
От: reversecode google
Дата: 05.06.20 22:14
Оценка: 13 (2)
http контент лен передается общая один раз к примеру
а дальше чункед или не чункед, зависит какая хттп и поддерживает ли его
дописывает все остальное

или можно byte range кусками запрашивать

в гугле полно pcap http дампов
стяните любой и посмотрите
или семулируйте вмваре+тспдамп+курл+какой то большой файл откуда то директ линком
Re: Базовой вопрос по Http.
От: vsb Казахстан  
Дата: 06.06.20 00:46
Оценка: 13 (2) +1
Здравствуйте, Sharov, Вы писали:

S>1)Допустим имеется клиент. Пусть имеется api, когда клиент что-то заращивает у сервера http get(большой json объект с 10000 записей). Правильно ли я понимаю, что в данном случае у меня http собирает данные (копит в буфере), и когда все данные будут доступны (в памяти), мой клиент получит один обычный http get ответ?


Неправильно. Любой адекватный клиент позволяет вычитывать ответ в виде потока. Получать полный буферизованный ответ это лишь опция, которая не должна использоваться для огромных ответов.

S>2)Допустим имеется сервер, который получает огромный (8гб) файл от клиента. Вот у меня в api есть stream параметр (networkstream в случае дотнет). Верно, что в данном случае мой сервер получит http post, хотя его тело (т.е. 8гб), еще до конца не получено? Т.е. я получю один http post и начинаю читать содержимое, которое до конца-то может и не придти, т.е. получается что http post в данном случае может не знать свой размер.


S>Т.е. я понимаю разницу между буферизацией и потоком, но я не понимаю как 2) случае все это будет физически оформлено в один http post.


В HTTP 1.1 есть два режима передачи тела сообщения. Первый режим это когда указывается заголовок content-length. В этом случае просто передаётся тело сообщения после заголовков и всё. Этот режим удобно применять, когда длина сообщения известна заранее. Второй режим это когда заголовок content-length не указывается. В этом случае тело сообщения передаётся кусками. Каждый кусок предваряется его длиной. Конец всего сообщения маркируется куском нулевой длины.

Это то, как оно устроено на уровне байтов. Описание справедливо и для запроса и для ответа.

На уровне API всегда есть возможность читать тело в виде потока, а не целиком. Просто в первом случае будет заранее доступна длина этого потока, во втором случае не будет.

Если речь именно о загрузке файлов через браузер, то там идёт т.н. multipart encoding. Это отдельный протокол уровня выше HTTP.

S>3)Про физику процесса -- я правильно понимаю, что у меня данные копятся в буфере http, а tcp просто прокидывает chunk'и данных? И когда у меня данные закончились — все пришло, либо разрыв — то tcp манифистирует об этом http, и уже http либо оформляет стандартный запрос\ответ, либо у меня вылезает ошибка о разрыве (но в этом случае это не ошибка http, а tcp socket что-то там).


Тут ничего не понял, если честно. TCP ничего не сигнализирует. HTTP это протокол более высокого уровня и от низлежащего протокола ему нужна только "труба с байтами", больше ничего не нужно. Если в середине чтения сообщения внезапно закроется сокет, вылезет ошибка, да.

Ну, точней, определённую связь между HTTP и TCP найти можно. В частности заголовки вроде keep-alive, чтобы переиспользовать соединения для нескольких запросов. Но в целом это можно считать скорей оптимизацией, чем фундаментальной связью.

Это всё касается HTTP 1.1 (и, возможно, 1.0, уже плохо помню различия). Что там в HTTP 2.0, не знаю. Но с точки зрения прикладного программиста, пользующегося этим всем через API, всё вышеописанное должно быть справедливо и там.
Отредактировано 06.06.2020 1:44 vsb . Предыдущая версия . Еще …
Отредактировано 06.06.2020 0:49 vsb . Предыдущая версия .
Отредактировано 06.06.2020 0:48 vsb . Предыдущая версия .
Re: Базовой вопрос по Http.
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 06.06.20 01:44
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Имеется базовое непонимание работы http.


HTTP разный. Есть 0.9, 1.0, 1.1, даже 2.0 вроде есть
Все различия в версиях — в заголовках и реакции на них. В RFC всё расписано

ЗЫ 2.0 вроде двоичный, но имхо, там аналогично
Маньяк Робокряк колесит по городу
Re: Базовой вопрос по Http.
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 06.06.20 06:45
Оценка: 29 (2)
Здравствуйте, Sharov, Вы писали:

S>1)Допустим имеется клиент. Пусть имеется api, когда клиент что-то заращивает у сервера http get(большой json объект с 10000 записей). Правильно ли я понимаю, что в данном случае у меня http собирает данные (копит в буфере), и когда все данные будут доступны (в памяти), мой клиент получит один обычный http get ответ?


Нет, зависит от того, как работает генератор ответа.
В HTTP/1.1 и последующих есть chunked encoding, позволяющее отдавать ответ по частям — и клиент может его обрабатывать по частям по мере получения. Но можно и цельным телом. Это уже как серверу удобно. Оба варианта должны поддерживаться полноценными клиентами.

S>2)Допустим имеется сервер, который получает огромный (8гб) файл от клиента. Вот у меня в api есть stream параметр (networkstream в случае дотнет). Верно, что в данном случае мой сервер получит http post, хотя его тело (т.е. 8гб), еще до конца не получено? Т.е. я получю один http post и начинаю читать содержимое, которое до конца-то может и не придти, т.е. получается что http post в данном случае может не знать свой размер.


Точно так же, можно chunked. Но тут уже вопрос дизайна повыше HTTP. Если отправляется 8GB, вероятность разрыва огромна — значит, у клиента должен быть какой-то аплоадер (скрипт в браузере или аналог), который вызывает команду отправки по частям, и закончив отправку — говорит "фиксируй и сохраняй на постоянное".
Как это будет в вашем API — не знаю, не видел. Может, оно и попытается одним куском выслать.

S>Т.е. я понимаю разницу между буферизацией и потоком, но я не понимаю как 2) случае все это будет физически оформлено в один http post.


Оформить-то можно, но удобно ли.

S>3)Про физику процесса -- я правильно понимаю, что у меня данные копятся в буфере http, а tcp просто прокидывает chunk'и данных? И когда у меня данные закончились — все пришло, либо разрыв — то tcp манифистирует об этом http, и уже http либо оформляет стандартный запрос\ответ, либо у меня вылезает ошибка о разрыве (но в этом случае это не ошибка http, а tcp socket что-то там).


Для HTTP настоятельно рекомендуется или Content-Length заранее, или chunked encoding. Тогда при обрыве TCP принимающая сторона поймёт, что данные неполные.
Можно отправлять и без этого, разрешается, но не рекомендуется — опасно.
Ошибку по самому TCP можете и не увидеть, если программа, например, упала с той стороны — в этом случае просто сокет закрывается (да, увы, такой дизайн — многие на него жалуются).

S>И когда у меня данные закончились — все пришло, либо разрыв — то tcp манифистирует об этом http


В общем случае следует считать, что TCP не скажет, что был разрыв. Он может, но не гарантируется. Проверяйте таки по длине или финальному чанку.
The God is real, unless declared integer.
Re[2]: Базовой вопрос по Http.
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 06.06.20 06:47
Оценка:
Здравствуйте, Marty, Вы писали:

S>>Имеется базовое непонимание работы http.


M>HTTP разный. Есть 0.9, 1.0, 1.1, даже 2.0 вроде есть

M>Все различия в версиях — в заголовках и реакции на них. В RFC всё расписано

Ну с учётом того, что стандарт на 1.1 это 1999-й год... про 0.9 можно забыть окончательно (по-моему, ни один внятный сервер его уже не поддерживает), 1.0 рассматривается только в режиме совместимости (если сказали про 1.0, включаем пару опций) и то не всеми.

M>ЗЫ 2.0 вроде двоичный, но имхо, там аналогично


Уже можно говорить про 3.0 (поверх QUIC), и да, в обоих аналогично (явная длина или chunked).
The God is real, unless declared integer.
Re[2]: Базовой вопрос по Http.
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 06.06.20 07:03
Оценка: 23 (3)
Здравствуйте, vsb, Вы писали:

vsb>В HTTP 1.1 есть два режима передачи тела сообщения. Первый режим это когда указывается заголовок content-length. В этом случае просто передаётся тело сообщения после заголовков и всё. Этот режим удобно применять, когда длина сообщения известна заранее. Второй режим это когда заголовок content-length не указывается. В этом случае тело сообщения передаётся кусками. Каждый кусок предваряется его длиной. Конец всего сообщения маркируется куском нулевой длины.


Немного не так. Chunked должно быть явно указано через "Content-Encoding: chunked". Отсутствие и chunked, и content-length допускается, но не рекомендуется — в таком случае конец ответа показывается закрытием TCP с передающей стороны. Так как HTTP/1.1 рекомендует сохранение соединения между запросами-ответами, и преждевременное закрытие без chunked или content-length не детектируется, то это совсем уж ленивый запасной вариант.

Кроме того, RFC говорит

>> Whenever a transfer-coding is applied to a message-body, the set of transfer-codings MUST include "chunked", unless the message is terminated by closing the connection.


Дословно из этого следует, что потоковое сжатие (gzip, deflate) должно сопровождаться итоговым chunked.

vsb>На уровне API всегда есть возможность читать тело в виде потока, а не целиком. Просто в первом случае будет заранее доступна длина этого потока, во втором случае не будет.


Ну от API зависит. Во всех нормальных — да, дают такое. Но стиль как-то часто неудобен.

vsb>Это всё касается HTTP 1.1 (и, возможно, 1.0, уже плохо помню различия). Что там в HTTP 2.0, не знаю. Но с точки зрения прикладного программиста, пользующегося этим всем через API, всё вышеописанное должно быть справедливо и там.


HTTP/2 чуть меняет стиль, например:

>> The last frame in the sequence bears an END_STREAM flag, noting that a HEADERS frame bearing the END_STREAM flag can be followed by CONTINUATION frames that carry any remaining portions of the header block.


по сути это такой же chunked с явным флагом конца. Причём END_STREAM обязан быть и в случае предварительно переданного content-length, тогда сверяется реальный полученный размер.
The God is real, unless declared integer.
Re[2]: Базовой вопрос по Http.
От: Sharov Россия  
Дата: 06.06.20 16:41
Оценка:
Здравствуйте, netch80, Вы писали:

S>>1)Допустим имеется клиент. Пусть имеется api, когда клиент что-то заращивает у сервера http get(большой json объект с 10000 записей). Правильно ли я понимаю, что в данном случае у меня http собирает данные (копит в буфере), и когда все данные будут доступны (в памяти), мой клиент получит один обычный http get ответ?

N>Нет, зависит от того, как работает генератор ответа.
N>В HTTP/1.1 и последующих есть chunked encoding, позволяющее отдавать ответ по частям — и клиент может его обрабатывать по частям по мере получения. Но можно и цельным телом. Это уже как серверу удобно. Оба варианта должны поддерживаться полноценными клиентами.

Как это будет ваглядить с тз http и api моего приложения? Т.е. в случае буфера у меня вызывается метод, к которому пришел http запрос\ответ. Все, http отработал, ибо уже работает мой код(rest api\web srv) с полученными данными из буфера(ram). Это в случае буфера, а в случае потока мой код уже вызвался, но http протокол продолжает работать подгружая данные (chunked encoding), т.е. такой себе http post растянутый во времени. Т.е. мое приложение начинает работать над запросом\ответом при том, что сам http свою работу не закончил. Вот чего я не могу понять. Или он свою работу закончил и когда я читаю из потока, работает уже тупо tcp сокет?
Кодом людям нужно помогать!
Re[3]: Базовой вопрос по Http.
От: reversecode google
Дата: 06.06.20 17:27
Оценка: 14 (1)
считайте http это как хидер
дальше идет боди, может быть чанками если хттп поддерживает

обрыв тсп сессии потеря всего запроса
и начинаем качать сначала

что бы такого не было юзают байт ренж запросы
где каждый запрос — отдельная сессия
Re[4]: Базовой вопрос по Http.
От: Sharov Россия  
Дата: 06.06.20 18:47
Оценка:
Здравствуйте, reversecode, Вы писали:

R>считайте http это как хидер

R>дальше идет боди, может быть чанками если хттп поддерживает

Ну да, как-то так и считаю.

R>обрыв тсп сессии потеря всего запроса

R>и начинаем качать сначала

Как обрыв сессии, если запрос уже отработал и пришел? Мой метод уже работает, выкачивает данные, что-то с ними делает...

R>что бы такого не было юзают байт ренж запросы

R>где каждый запрос — отдельная сессия

Можно подробнее.
Кодом людям нужно помогать!
Re[5]: Базовой вопрос по Http.
От: reversecode google
Дата: 06.06.20 18:59
Оценка:
tcp таймаут например, канал передачи данных хреновый
и все что вы там посылали итд прийдется сбрасывать, закрывать сокет
и начинать все по новой

поймите, протоколы включая даже http, на пальцах по форумам не изучают
вам на пальцах уже много рассказали
если понимания не пришло
то только прыгать в реку, по другому плавать не научитесь
и как работает http не поймете
ищите исходники на понятном вам языке, и разбирайте, если рфц не осилите
Re[3]: Базовой вопрос по Http.
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 07.06.20 09:48
Оценка: 14 (1)
Здравствуйте, Sharov, Вы писали:

S>Как это будет ваглядить с тз http и api моего приложения? Т.е. в случае буфера у меня вызывается метод, к которому пришел http запрос\ответ. Все, http отработал, ибо уже работает мой код(rest api\web srv) с полученными данными из буфера(ram). Это в случае буфера, а в случае потока мой код уже вызвался, но http протокол продолжает работать подгружая данные (chunked encoding), т.е. такой себе http post растянутый во времени. Т.е. мое приложение начинает работать над запросом\ответом при том, что сам http свою работу не закончил. Вот чего я не могу понять. Или он свою работу закончил и когда я читаю из потока, работает уже тупо tcp сокет?


Я так понимаю, речь о поведении клиента?
Послали, например, GET. Ушёл полностью запрос, сервер начал отдавать ответ. Вот он выслал заголовок. Предположим для простоты, всякие gzip не используются. Тогда уже по заголовку ясна одна из ситуаций:
1) Длина известна, задана в заголовке ответа;
2) Длина неизвестна, следует забирать ответ порциями, конец явно обозначен через чанк размера 0;
3) Длина неизвестна, следует забирать ответ порциями, конец обозначен завершением передачи TCP.

В API, предположим, вы вызвали что-то типа
    request.send();
    response = request.startGettingResponse();
    if response.isRejected():
        ... идём отсюда, мы чужие на этом празднике жизни ...
    ... можно читать ответ ...


теперь будет что-то вроде isLengthSpecified() и getLength(); для Python могут совместить в один метод (будет возвращать число или None), для Java — тоже в один (ответ -1 для неопределённой длины, -2 для ошибки... всё по вкусу).
Теперь вы можете читать ответ порциями, типа: getPortion(max_length: int, wait: bool) — если надо, библиотека будет буферизовать ответ. Можно захотеть прочитать всё сразу, поставив max_length в какой-нибудь LONG_MAX.

Если вы, наоборот, отдающая сторона, то API будет содержать варианты типа:

sendResponseWithBody(код, строка) — всё одной порцией
sendResponseWithBodyFromFile(код, файловый поток) — извлечь всё из файла
sendResponseWithStream(код) — посылает знак, что chunked
sendPortion(строка байтов) — явно передать данные
sendPortionFromFile(файловый поток)
finishStream() — завершить передачу

Можете сравнить с реальными API, будут заметно похожи.
The God is real, unless declared integer.
Re[4]: Базовой вопрос по Http.
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 07.06.20 09:49
Оценка:
Здравствуйте, reversecode, Вы писали:

R>что бы такого не было юзают байт ренж запросы

R>где каждый запрос — отдельная сессия

Почему так сразу и отдельная сессия?
The God is real, unless declared integer.
Re[5]: Базовой вопрос по Http.
От: reversecode google
Дата: 08.06.20 16:04
Оценка:
там есть и кипалив http в пределах одной tcp сессии
но для тс это будет сложно сразу все
да и на практике залипший tcp лучше закрыть и открыть новую сессию
чем ждать и пытаться пробиться через него
поэтому apple hls чанками, где на каждый чанк новая сессия
в выиграше
Re: Базовой вопрос по Http.
От: Pzz Россия https://github.com/alexpevzner
Дата: 08.06.20 18:57
Оценка: 7 (1)
Здравствуйте, Sharov, Вы писали:

S>1)Допустим имеется клиент. Пусть имеется api, когда клиент что-то заращивает у сервера http get(большой json объект с 10000 записей). Правильно ли я понимаю, что в данном случае у меня http собирает данные (копит в буфере), и когда все данные будут доступны (в памяти), мой клиент получит один обычный http get ответ?


Не обязательно. Может и по частям получать, потоком.

S>2)Допустим имеется сервер, который получает огромный (8гб) файл от клиента. Вот у меня в api есть stream параметр (networkstream в случае дотнет). Верно, что в данном случае мой сервер получит http post, хотя его тело (т.е. 8гб), еще до конца не получено? Т.е. я получю один http post и начинаю читать содержимое, которое до конца-то может и не придти, т.е. получается что http post в данном случае может не знать свой размер.


Может и не знать. В этом случае используется chunked encoding, он позволяет передавать поток данных, длинна которого заранее не известна.

То, как это выглядит с точки зрения программирования, очень зависит от используемых языков и библиотек. Но реализации, рассчитанные на использование взрослыми людьми, разделяют HTTP header и HTTP body. Header ты получаешь в тот момент, когда он пришел и распарсился, а body у тебя есть возможность получать по мере поступления — либо в виде callback'а, которого периодически зовут, передав ему очередную порцию полученных данных, либо в виде какого-то объекта, из которого можно читать данные по мере их поступления.

Кстати, на клиентской стороне то же самое. Header уходит одним куском, body можно писать по частям, потом приходит header ответа и body, которые можно читать по мере поступления.

Конечно, бывают и реализации, которые сразу все отправляют и получают одним куском. Но это вопрос именно API, а не протокола. С таким API работать проще, но стриминг гигабайта данных с помощью такого API не организуешь.

S>Т.е. я понимаю разницу между буферизацией и потоком, но я не понимаю как 2) случае все это будет физически оформлено в один http post.


S>3)Про физику процесса -- я правильно понимаю, что у меня данные копятся в буфере http, а tcp просто прокидывает chunk'и данных? И когда у меня данные закончились — все пришло, либо разрыв — то tcp манифистирует об этом http, и уже http либо оформляет стандартный запрос\ответ, либо у меня вылезает ошибка о разрыве (но в этом случае это не ошибка http, а tcp socket что-то там).


Совершенно не обязательно. Вполне возможна реализация HTTP с крошечным буфером. Если мы говорим о HTTP/1.1, разрыв TCP-соединения во время HTTP-транзакции — это всегда ошибка. HTTP/1.0 использовал факт закрытия сокета со стороны сервера как признак окончания возвращаемых данных, и из-за этого не всегда было возможно понять, пришли тебе данные целиком, или в обрезанном виде. Ну и переиспользование уже открытого сокета для следующих запросов было невозможно.
Re[2]: Базовой вопрос по Http.
От: Pzz Россия https://github.com/alexpevzner
Дата: 08.06.20 19:07
Оценка:
Здравствуйте, reversecode, Вы писали:

R>http контент лен передается общая один раз к примеру

R>а дальше чункед или не чункед, зависит какая хттп и поддерживает ли его

Content-Length — штука, взаимо-исключающаяся с chunked transfer encoding, там либо одно, либо другое.

HTTP версии меньше 1.1 имеют лишь историческое значение, все остальные поддерживают chunked encoding (в HTTP/2, вероятно, используется для этих целей свое какое-то кодирование, но суть та же).

R>или можно byte range кусками запрашивать


Очень трудно себе представить, чтобы это работало с нестатическими данными.

Вообще, на этом этапе беседы я не стал бы углубляться в такие детали.
Re[2]: Базовой вопрос по Http.
От: Pzz Россия https://github.com/alexpevzner
Дата: 08.06.20 19:17
Оценка: 3 (1)
Здравствуйте, vsb, Вы писали:

vsb>Тут ничего не понял, если честно. TCP ничего не сигнализирует. HTTP это протокол более высокого уровня и от низлежащего протокола ему нужна только "труба с байтами", больше ничего не нужно. Если в середине чтения сообщения внезапно закроется сокет, вылезет ошибка, да.


Граждане, которые придумали IPP over USB (принтеровский протокол, позволяющий использовать IPP с принтерами, у которых нет нормального сетевого подсоединения, а есть только USB; на самом деле, это HTTP over USB) тоже так думали. К сожалению, они не учли того факта, что закрытие TCP-соединения со стороны клиента позволяет серверу осознать, что запрос прерван клиентом. В USB такого сигнала нет, это действительно просто "труба с байтами", поэтому если клиент бросил запрос до завершения, куски ответа так и будут болтаться в USB-буферах, и достанутся в качестве ответа следующему запросу.
Re[3]: Базовой вопрос по Http.
От: vsb Казахстан  
Дата: 08.06.20 19:50
Оценка:
Здравствуйте, Pzz, Вы писали:

vsb>>Тут ничего не понял, если честно. TCP ничего не сигнализирует. HTTP это протокол более высокого уровня и от низлежащего протокола ему нужна только "труба с байтами", больше ничего не нужно. Если в середине чтения сообщения внезапно закроется сокет, вылезет ошибка, да.


Pzz>Граждане, которые придумали IPP over USB (принтеровский протокол, позволяющий использовать IPP с принтерами, у которых нет нормального сетевого подсоединения, а есть только USB; на самом деле, это HTTP over USB) тоже так думали. К сожалению, они не учли того факта, что закрытие TCP-соединения со стороны клиента позволяет серверу осознать, что запрос прерван клиентом. В USB такого сигнала нет, это действительно просто "труба с байтами", поэтому если клиент бросил запрос до завершения, куски ответа так и будут болтаться в USB-буферах, и достанутся в качестве ответа следующему запросу.


Не, ну труба новая нужна каждый раз )
Re[3]: Базовой вопрос по Http.
От: reversecode google
Дата: 08.06.20 20:36
Оценка:
ему нужно было общее понимание

и где было в сообщении про нестатические данные?
хватит уже додумывать
Re[5]: Базовой вопрос по Http.
От: Mr.Delphist  
Дата: 11.06.20 18:06
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, reversecode, Вы писали:


R>>что бы такого не было юзают байт ренж запросы

R>>где каждый запрос — отдельная сессия

S>Можно подробнее.


https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.