Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #31 (permalink)  
Старый 10.12.2021, 23:59
Аспирант
Отправить личное сообщение для developer_ Посмотреть профиль Найти все сообщения от developer_
 
Регистрация: 28.07.2011
Сообщений: 40

Результаты последних экспериментов.

Скачал и установил apache. Сделал страничку - скопировал скрипты что приведены в этом топике. Для сервера установил лимит 100k

Запускаю снифить трафик warshark.

Посылаю файл 10 мегабайт и вижу следующую картину:

Сервер понимает что переданные данные слишком большие и посылает ответку в 0.000688 с. Пока всё по плану.

Но клиент продолжает слать данные. И отсылает все 10 мегабайт на сервер. Сервер их благополучно принимает.

В 0.027085 - страница с данными полностью приходит на сервер и он это подтверждает.

Получается что сервер принял данные которые принимать не должен был.

fetch на клиенте отработал без ошибок и показал нам страницу 413 которую мы отправили ещё на 0.000688 секунде.

Картинки прилагаю:




Последний раз редактировалось developer_, 11.12.2021 в 00:02.
Ответить с цитированием
  #32 (permalink)  
Старый 11.12.2021, 00:09
Аспирант
Отправить личное сообщение для developer_ Посмотреть профиль Найти все сообщения от developer_
 
Регистрация: 28.07.2011
Сообщений: 40

Далее эксперимент. Пытаюсь загрузить 10г

И что я вижу? Страница 413 возвращается сразу. А вот заливка на сервер всех этих 10гиг продолжается аж 30 секунд. Пока apache решает что с него хватит и обрубает соединение.

И при этом fetch - на клиенте ведёт ровным счётом как и у меня - вываливается в исключение. И ни каких страниц 413 не показывает.

И что мы имеем в итоге - как по мне поведение apache менее корректно чем просто сразу обрубать соединение после отсылки страници 413.

Картинки прилагаю





Ответить с цитированием
  #33 (permalink)  
Старый 11.12.2021, 18:19
Профессор
Отправить личное сообщение для Rise Посмотреть профиль Найти все сообщения от Rise
 
Регистрация: 07.11.2013
Сообщений: 4,662

developer_, сначала вам надо понять как устроен XMLHttpRequest и fetch.

Есть загрузка на сервер (upload) и есть загрузка на клиент (download). Другими словами, есть http-запрос (request) и есть http-ответ (response).

Так вот, событие readystatechange это только загрузка на клиент. Так исторически сложилось, изначально не было событий прогресса: loadstart, progress, load, error, abort, timeout, loadend. Сейчас readystatechange - устаревшее:
xhr.onreadystatechange = function() {
    if (this.readyState == 4) {
        if (this.status == 200) {
            // ok
        } else {
            // server error
        }
    }
};

Далее, что касается ошибок. Есть ошибки ответа сервера (http status codes) и есть ошибки сети (network errors). Имя ошибки сети нельзя получить через скрипт. Почему нельзя и какие я писал здесь, повторяться не буду. Событие abort это результат вызова xhr.abort() и отношения к делу не имеет.

Так вот, событие error это только ошибки сети, а ошибки сервера проверяются в другом месте:
var xhr = new XMLHttpRequest;
xhr.open('POST', '/');
xhr.onload = function() {
    if (this.status == 200) {
        // ok
    } else {
        // server error
    }
};
xhr.onerror = function() {
    // network error
};
xhr.send(new FormData);

Тоже самое и в fetch:
fetch('/', {
        method: 'POST',
        body: new FormData,
    })
    .then(response => {
        if (response.ok) {
            // 200-299 status
        } else {
            // server error
        }
    })
    .catch(error => {
        // network error
    });

Далее, нужно понимать последовательность выполнения событий. События load, error, abort, timeout - взаимоисключающие. Остальные имеют определенный порядок:
var xhr = new XMLHttpRequest;

xhr.open('POST', '/');

xhr.onloadstart = log; // 1

xhr.upload.onloadstart = log; // 2
xhr.upload.onprogress = log;  // 3
xhr.upload.onload = log;      // 4
xhr.upload.onerror = log;     // 4
xhr.upload.onabort = log;     // 4
xhr.upload.ontimeout = log;   // 4
xhr.upload.onloadend = log;   // 5

// download
xhr.onprogress = log; // 6
xhr.onload = log;     // 7
xhr.onerror = log;    // 7
xhr.onabort = log;    // 7
xhr.ontimeout = log;  // 7
xhr.onloadend = log;  // 8

xhr.onreadystatechange = log; // 6-8

xhr.send(new FormData);

function log(e) {
    console.log(String(this), e.type, e.loaded, xhr.readyState, xhr.status);
}

В fetch - вообще нет событий прогресса, поэтому ничего понимать не надо.


Вывод, то что вы делаете с сокетами на уровне TCP генерирует ошибку сети, а скрипт ее не видит, во 1-х, потому что он работает на другом уровне - HTTP, во 2-х, потому что чтение таких ошибок запрещено по причине безопасности.


То что касается последних ваших экспериментов можно сказать следующее:

1. Если Apache продолжает обслуживать запрос клиента после отправки ответа об ошибке, вопреки своей же документации, где написано "If the client request exceeds that limit, the server will return an error response instead of servicing the request.", то это баг.

2. Если клиент, Браузер, продолжает отправлять тело сообщения после получения ответа об ошибке, вопреки своей же спецификации, где написано "If the client sees a response that indicates the server does not wish to receive the message body and is closing the connection, the client SHOULD immediately cease transmitting the body and close its side of the connection.", то это тоже баг.

Последний раз редактировалось Rise, 11.12.2021 в 18:27.
Ответить с цитированием
  #34 (permalink)  
Старый 11.12.2021, 18:39
Аспирант
Отправить личное сообщение для developer_ Посмотреть профиль Найти все сообщения от developer_
 
Регистрация: 28.07.2011
Сообщений: 40

Так я как так говорил с самого начала - что это "баг". Просто решил не писать так однозначно.

К fetch(XMLHttpRequest) у меня была только одна претензия - он пока не отправит всё тело, ничего принимать не хочет. Даже если мы ему отправим ответ. Он всё равно его нам не покажет, а тупо вывалится в исключение, если сервер не примет всё тело.

К apachе - у меня нету вообще претензий, хочет принимать гигабайты, флаг ему в руки. Я с ним не работаю.

Так же fetch без танцев с бубном не работает с прогрессом загрузки. Поэтому использую старый добрый XMLHttpRequest.

А по поводу всех экскрементов - так я пытался попробовать всё и логичное и нелогичное.
Ответить с цитированием
  #35 (permalink)  
Старый 11.12.2021, 23:06
Профессор
Отправить личное сообщение для Rise Посмотреть профиль Найти все сообщения от Rise
 
Регистрация: 07.11.2013
Сообщений: 4,662

developer_, вот здесь объяснено что не так с браузерами.

Если отправить ошибку 413 и закрыть сокет, то браузеры покажут ошибку ERR_CONNECTION_RESET:



Если не закрыть сокет, то браузеры покажут ошибку 413:



Очевидно, что второе более информативно для клиента, так как позволяет кастомизировать страницы ошибок, а скрипту получить код ошибки.

Видимо, поэтому Apache, зная эти траблы браузеров, оставляет сокет открытым.
Ответить с цитированием
  #36 (permalink)  
Старый 12.12.2021, 00:13
Аспирант
Отправить личное сообщение для developer_ Посмотреть профиль Найти все сообщения от developer_
 
Регистрация: 28.07.2011
Сообщений: 40

XMLHttpRequest или fetch не вызовут никаких событий пока не отправят всё тело. Если это 10 гигабайт - то сервер должен принят все 10 гигабайт. Если закрыть сокет раньше - то будет ошибка сети. Если отправить ответ и закрыть сокет раньше - то тоже будет ошибка сети.

Разумеется с точки зрения логики и защиты от атак, если сервер не хочет принимать 10 гигабайт - то он не должен принимать их.

Собственно мой эксперимент показал - что apache сдался после 30 секунд "dos" атаки. Что также является бредом. Отказался принимать контент, отослал страницу ошибки - закрывай сокет.
Ответить с цитированием
  #37 (permalink)  
Старый 12.12.2021, 00:16
Аспирант
Отправить личное сообщение для developer_ Посмотреть профиль Найти все сообщения от developer_
 
Регистрация: 28.07.2011
Сообщений: 40

Почитал вашу ссылку - собственно всё так как я и утверждал с самого начала.

Т.к. я являюсь разработчиком - я даже могу представить как устроена архитектура в XMLHttpRequest и fetch что бы так криво работать.
Ответить с цитированием
  #38 (permalink)  
Старый 12.12.2021, 00:18
Аспирант
Отправить личное сообщение для developer_ Посмотреть профиль Найти все сообщения от developer_
 
Регистрация: 28.07.2011
Сообщений: 40

Цитата:
Видимо, поэтому Apache, зная эти траблы браузеров, оставляет сокет открытым.
apache тоже не идеален. Не принял 10 гигабайт. Обрубил сокет.
Ответить с цитированием
  #39 (permalink)  
Старый 12.12.2021, 07:59
Профессор
Отправить личное сообщение для Rise Посмотреть профиль Найти все сообщения от Rise
 
Регистрация: 07.11.2013
Сообщений: 4,662

developer_,
Кстати, на протоколе HTTP/2 всё работает как надо.
Ответить с цитированием
  #40 (permalink)  
Старый 12.12.2021, 09:00
Аватар для voraa
Профессор
Отправить личное сообщение для voraa Посмотреть профиль Найти все сообщения от voraa
 
Регистрация: 03.02.2020
Сообщений: 2,692

Сообщение от Rise
Видимо, поэтому Apache, зная эти траблы браузеров, оставляет сокет открытым.
Просто сами траблы не позволяют серверу вести себя по-другому

Note: If the client is sending data, a server implementation using
TCP should be careful to ensure that the client acknowledges
receipt of the packet(s) containing the response, before the server
closes the input connection.
If the client continues sending data
to the server after the close, the server's TCP stack will send a
reset packet to the client, which may erase the client's
unacknowledged input buffers before they can be read and
interpreted by the HTTP application.
https://datatracker.ietf.org/doc/htm...l#section-10.4

Т.е апач честно посылает код 413 и как положено ждет, что браузер скажет, что получил этот код, прежде, чем закрыть соединения. Но браузер говорит, что получил только после того, как все отошлет.

Сообщение от Rise
Кстати, на протоколе HTTP/2 всё работает как надо.
И правда ведь работает

Последний раз редактировалось voraa, 12.12.2021 в 10:21.
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
как убрать встроенные стили у всех дивов? Kvark Элементы интерфейса 3 08.08.2013 14:20
отправка всех данных store на сервер shepard90 ExtJS 1 03.04.2013 23:52
Как заставить выполняться обработчик после всех имеющихся обработчиков данного элемен Анатолий Саратовцев jQuery 2 08.10.2012 18:49
Двойная Фильтрация данных таблицы David0707 Общие вопросы Javascript 0 19.03.2012 13:00
Как изменить свойство css у всех элементов одного класса AlexJ Events/DOM/Window 7 19.03.2011 06:25