#java #http #http-headers #http-content-length
#java #http #http-заголовки #http-content-length
Вопрос:
У меня есть фрагмент 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, но не нашел подсказки. Я не использовал никакого кодирования передачи или Transfer-coding.
Ответ №1:
Я бы предположил, что HttpURLConnection
просто переопределит Content-Length
заголовок правильным значением, поскольку он знает, что лгать об этом нехорошо 😉
И действительно: в строках 535-550 из sun.net.www.protocol.HttpURLConnection
the 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.
Комментарии:
1. Значение
Content-Length
было жестко задано по ошибке. Что меня удивляет, так это то, что это работает. Я хочу знать почему.2. Ваше предположение звучит разумно. Но где найти документацию по нему?
3. @joachim-sauer: Отличный ответ! Но я протестировал с sun.net.http.allowRestrictedHeaders= true, и обнаружил, что результат такой же, как и раньше.
4. @wang: мой подробный анализ здесь на самом деле неприменим, поскольку
Content-Length
в любом случае будет перезаписано правильное значение. Я обновил свой ответ.
Ответ №2:
Это решило для меня:
connection.setFixedLengthStreamingMode(myString.getBytes().length);
conn.setRequestProperty("Content-length", String.valueOf(myString.getBytes().length));
«connection.setFixedLengthStreamingMode(myString.getBytes().length);» перед установкой заголовка Content-Length.