Почему в поле заголовка HTTP Content-Length используется значение, отличное от указанного в коде Java?

У меня есть фрагмент кода Java для передачи массива байтов на HTTP-сервер:

HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary="
    + myBoundary);
connection.setRequestProperty("Content-Length", 1024);

Я использовал этот код для передачи массива байтов, размер которого больше 1024. Он работал хорошо. Но фактическое сообщение HTTP (захваченное Wireshark) показывает, что значение Content-Length - это фактический размер, а не 1024. Почему?

Я поискал в спецификации HTTP, но не нашел намеков. Я не использовал кодирование передачи или кодирование передачи.


person chance    schedule 19.05.2011    source источник


Ответы (2)


Я предполагаю, что HttpURLConnection просто заменит заголовок Content-Length правильным значением, поскольку он знает, что врать об этом бесполезно ;-)

И действительно: в строках 535-550 sun.net.www.protocol.HttpURLConnection Content-Length устанавливается, если необходимо. Это происходит после установки заданных пользователем заголовков, поэтому это значение будет перезаписано.

И это правильно: если объем передаваемых вами данных не соответствует заявленной сумме, то вы только запутаете другой конец.

Проверка источник sun.net.www.protocol.http.HttpURLConnection кажется, что существует список заголовков, которые ограничены и будут игнорироваться при вызове setRequestProperty. Content-Length входит в этот список. К сожалению, это кажется недокументированным (по крайней мере, я не смог найти никакой документации по этому поводу, только обсуждение связанной проблемы здесь).

Поиск в Google идентификаторов ошибок (?), Упомянутых в набор изменений, который представил эту "функциональность", похоже, что это изменение было введено как реакция на уязвимости системы безопасности CVE-2010-3541 и CVE-2010-3573 (Ошибка Redhat по этой теме).

Ограничение можно отключить вручную, установив для системного свойства sun.net.http.allowRestrictedHeaders значение true при запуске JVM.

person Joachim Sauer    schedule 19.05.2011
comment
Значение Content-Length было жестко запрограммировано по ошибке. Что меня удивляет, так это то, что это работает. Я хочу знать почему. - person chance; 19.05.2011
comment
Ваше предположение звучит разумно. Но где найти на него документацию? - person chance; 19.05.2011
comment
@ Joachim-sauer: Отличный ответ! Но я протестировал с sun.net.http.allowRestrictedHeaders = true и обнаружил, что результат такой же, как и раньше. - person chance; 19.05.2011
comment
@wang: мой долгий анализ здесь не применим, так как Content-Length в любом случае будет перезаписан правильным значением. Я обновил свой ответ. - person Joachim Sauer; 19.05.2011

Это решило для меня:

connection.setFixedLengthStreamingMode(myString.getBytes().length);
conn.setRequestProperty("Content-length", String.valueOf(myString.getBytes().length));

"connection.setFixedLengthStreamingMode (myString.getBytes (). length);" перед установкой заголовка Content-Length.

person Community    schedule 06.11.2018