Pull to refresh

Вы не можете закачать файлы на сервер в мобильном Safari 8.0

Reading time 3 min
Views 20K
Original author: Uploadcare
Печально, но факт. Новая версия iOS содержит баг, который делает невозможным отправку любых файлов на сервер из браузера. Когда вы выбираете файл в любой форме на HTML странице и пытатесь его отправить, браузер посылает запрос без файла. Он показывает, что ждет ответа на запрос, но на самом деле ответ не приходит.

Более того, баг касается не только HTML-форм. Если вы отправляете файл из Javascript, конструируя объект FormData (часть API XMLHttpRequest Level 2), это приводит к тому же результату. И даже если вы делаете то же самое из нативного приложения, которое является оберткой над HTML-браузером (например, Apache Cordova), то получаете такой же результат.

Почему же не приходит ответ. Если бы файл просто не отсылался, мы могли бы ожидать, что на сервер приходил бы пустой файл или сервер возвращал бы ошибку, что форма отправлена без файла. Однако сервер просто не шлет никакого ответа (даже 400 bad request) и не закрывает соединение. Все дело в том, какой именно запрос шлет Safari.

POST /form/ HTTP/1.1
Host: 192.168.5.59:8000
Referer: http://192.168.5.59:8000/
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryGVP84V9BXQSqpZw2
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Content-Length: 134573
Accept-Language: ru
Origin: http://192.168.5.59:8000
Accept-Encoding: gzip, deflate
Connection: keep-alive
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12A365 Safari/600.1.4

------WebKitFormBoundaryGVP84V9BXQSqpZw2
Content-Disposition: form-data; name="file"; filename="image.jpg"
Content-Type: image/jpeg


------WebKitFormBoundaryGVP84V9BXQSqpZw2--

Из заголовков видно, что запрос с отправкой файла должен иметь длину 134573 байта (заголовок Content-Length), а на самом деле в теле запроса отсутствует тело файла, из-за чего реальная длина запроса составляет 176 байт. В результате сервер ждет, когда браузер пошлет недостающие 134397 байт, а браузер думает, что он послал уже весь запрос и ждет ответа от сервера. Ни того ни другого не произойдет никогда и соединение просто закрывается по таймауту.

Баг проявляется в Safari 8.0 (билд 600.1.4) под iOS 8.0 (билд 12A365). Что интересно, под симулятором iOS, который идет в комплекте с XCode, данный баг не проявляется, хотя номера билдов там такие же. Однако на реальных устройствах (были проверены iPhone 4S, iPhone 5, iPad 3) баг воспроизводится всегда. Мы надеемся, что баг будет исправлен уже в ближайшем минорном обновлении.

Если кто-то хочет увидеть ошибку сам или попробовать другие девайсы.

Дебагер в Сафари тут бесполезен, потому что в любом случае показывает тело запроса без содержимого файлов. Т.к. ошибка непосредственно в работе с HTTP, сделать онлайн-пример достаточно сложно. Ничего умнее не придумал, чем запустить netcat и слать запросы на него. Вот инструкция:

1) Запускаете netcat -l 8000 на компе в одной wi-fi сетке с устройством.
2) Делаете простейшую форму на jsbin или jsfiddle:
<form action="http://192.168.5.59:8000/form/" method="post" enctype="multipart/form-data">
  <input type="file" name="file">
  <input type="submit">
</form>

Где 192.168.5.59 — ip адрес компа, где запущен netcat.

3) Открываете сделанный bin или fiddle на устройстве. Выбираете любой файл, шлете.
4) Смотрите на вывод netcat.

Если ответ похож на тот, что в статье, то баг присутствует. Если перед последней строчкой есть содержимое файла, то нет.
Tags:
Hubs:
+35
Comments 19
Comments Comments 19

Articles