HTTP — Блог Валерия Леонтьева https://valera.ws Место публикации личных заметок. Технологии, управление, бизнес, жизнь Sun, 02 Feb 2014 12:11:19 +0000 ru-RU hourly 1 https://wordpress.org/?v=5.6.2 https://valera.ws/wp-content/uploads/2020/02/favicon.png HTTP — Блог Валерия Леонтьева https://valera.ws 32 32 Архитектура веб приложений: экстерьер (видео-лекция) https://valera.ws/2014.01.18~web-applications-architecture-exterio/ https://valera.ws/2014.01.18~web-applications-architecture-exterio/#respond Sat, 18 Jan 2014 17:34:57 +0000 http://valera.ws/?p=730 Читать далее Архитектура веб приложений: экстерьер (видео-лекция) ]]> Архитектура веб-приложений: экстерьерРассказ о популярной универсальной архитектуре стека, в котором работает веб-приложение. Само приложение может быть написано на любом интерпретируемом языке с использованием любого фреймворка фреймворков. В данном случае это не важно, так как архитектура программной инфраструктуры — технологического стека, в котором оно работает, отличается мало.

Обсуждается путь запроса пользователя до и внутри сервера, его обработка и возврат ответа. Затрагиваются вопросы состояния приложения — работы с хранилищами, кэширования.

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

Смотрите в полноэкранном режиме.

]]>
https://valera.ws/2014.01.18~web-applications-architecture-exterio/feed/ 0
Nginx: пример конфига для сайта с плюшками https://valera.ws/2013.03.23~nginx-bonus-config-example/ https://valera.ws/2013.03.23~nginx-bonus-config-example/#respond Sat, 23 Mar 2013 08:42:26 +0000 http://valera.ws/?p=702 Читать далее Nginx: пример конфига для сайта с плюшками ]]> nginxПросто готвый пример универсального конфига nginx с использованием php-fpm, и секциями для базовых инструментов (phpMyAdmin, RockMongo) и функционалом для закрытия сайта в режим обслуживания. Сервер одновременно слушает и HTTP, и HTTPS. Все запросы с www перекидываются на адрес «без-www».

Листинг /etc/nginx/sites-available/example.com.conf:

map $http_cookie $isDevHack {
    default "";
    ~DEVELOPER_SECRET_COOKIE=10101 "/non-existed-location";
}

server {
    listen 80;
    listen 443 ssl;
    server_name example.com www.example.com;

    access_log /var/log/nginx/example.com.access_log;
    error_log /var/log/nginx/example.com.error_log;

    root /home/example.com/htdocs/;
    index index.html index.php;
    client_max_body_size 15M;

    location /phpmyadmin/ {
        root /usr/share/;
        index index.php index.html index.htm;
        location ~ ^/mysql-pma/(.+\.php)$ {
            try_files $uri =404;
            root /usr/share/;
            fastcgi_pass unix:/tmp/example.com.pool.socket;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include /etc/nginx/fastcgi_params;
        }
    }

    # Redirect www to no-www
    if ($host = 'www.example.com') {
        rewrite ^/(.*)$ http://example.com/$1 permanent;
    }

    # Only requests to our Host are allowed
    if ($host !~ ^(example.com|www.example.com)$ ) {
        return 444;
    }

    # Locations
    location / {
        if (-f "$isDevHack/home/example.com/maintenance") {
            return 503;
        }
        try_files $uri $uri/ /index.php?$args;
    }

    # RockMongo
    location /rockmongo/ {
        root /home/example.com/;
        try_files $uri $uri/ /index.php?$args;
    }
    location ~ ^/rockmongo/.*\.php {
        root /home/example.com/;
        fastcgi_pass unix:/tmp/example.com.pool.socket;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ \.(php|phtml) {
        fastcgi_pass unix:/tmp/example.com.pool.socket;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    # APC status page
    location = /apc-status.php {
        fastcgi_pass unix:/tmp/example.com.pool.socket;
        fastcgi_param SCRIPT_FILENAME /home/example.com/apc.php;
        include fastcgi_params;
    }

    # Memcached status page
    location = /memcached-status.php {
        fastcgi_pass unix:/tmp/example.com.pool.socket;
        fastcgi_param SCRIPT_FILENAME /home/example.com/memcached.php;
        include fastcgi_params;
    }

    location ~ \.(tpl|xml|log)$ {
        deny all;
    }

    # Errors
    error_page 503 @maintenance;
    location @maintenance {
        rewrite ^(.*)$ /maintenance-mode.html break;
    }

    # SSL
    ssl_certificate /etc/nginx/ssl/example.com.chained.crt;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;
    ssl_session_timeout 5m;
    ssl_protocols SSLv2 SSLv3 TLSv1;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
}
]]>
https://valera.ws/2013.03.23~nginx-bonus-config-example/feed/ 0
Nginx: сайт в режиме обслуживания, кроме разработчиков https://valera.ws/2013.03.23~nginx-maintenance-mode-except-developers/ https://valera.ws/2013.03.23~nginx-maintenance-mode-except-developers/#respond Sat, 23 Mar 2013 08:08:20 +0000 http://valera.ws/?p=698 Читать далее Nginx: сайт в режиме обслуживания, кроме разработчиков ]]> nginxНа днях стала задача: сделать средствами nginx возможность перевода сайта в режим обслуживания для всех пользователей, кроме разработчиков. Под режимом обслуживания понимается то, что все запросы к скриптам сайта должны выдавать одну и ту же страницу с сообщением о том, что сайт временно недоступен (плюс HTTP-ответ с кодом 503).

Стоит отметить то, что исполняемый код сайта (PHP) на целевом сервере работает по схема схема nginx—php-fpm, а выбор файла — через try_files. Так же подчеркиваю, что требуется проверка, является ли пользователь разработчиком. Эти два фактора вместе отметали простые классические решения этой проблемы (в Гугле их масса, например).

Самое простое решение без проверки (разработчик или нет) заключается в том, что  бы проверять наличие специального файла в начале до проверки других условий. Это можно сделать с помощью try_files, подставив файл страницы с ошибкой первым в очереди. Но помимо того неудобства, что требуется добавлять/удалять файл в исходниках сайта (что не очень хорошо при заливке исходников через системы контроля версий), этот вариант просто не работает в сочетании с секциями if, которые появятся для добавления проверки «разработчик или нет». После входа в любую секцию if try_files ведет себя своеобразно и неправильно резолвит полные пути к файлам; источник проблемы описан тут.

Кстати, а по какому признаку мы будем проверять, является ли пользователь разработчиком? Ну, вариантов достаточно много. Самый удобный и популярный вариант — по наличию «специальной» cookie. Еще один популярный вариант — по IP. На какой фактор полагаться, большой разницы нет. В любом случае требуется проверка значения некоторой переменной, и осуществить эту проверку можно только с помощью секции if.

Резюмируя описанное выше: мы не можем делать проверку на наличие файла страницы обслуживания вместе с проверкой дополнительного фактора «разработчик или нет», используя try_files. Значит, проверку на наличие файла можно делать только с помощью if. В nginx if не может принимать два условия. Но эта проблема решается. Казалось бы, что цель достигнута. Проверяем 2 фактора: наличие файла и факт того, что пользователь — разработчик. Но такие проверки обязательно требуют входа хотя бы в один if. И тут опять фэйл: после входа в любой if try_files ведет себя своеобразно и неправильно резолвит полные пути к файлам после входа в секцию if; источник проблемы описан тут.

Короче, все довольно запутано и мутно. После нескольких часов мучительного подбора вариантов решение таки было найдено. Я выбрал способ проверки разработчика по cookie. Схема вышла очень простой. Один из if-ов был заменен map-ом, который работает нормально с try_files. А объединение условий (наличия файла и cookie) было реализовано через подмену пути к этому файлу. Т.е. в случае, когда пользователь — разработчик, мы просто портим имя файла, наличие которого свидетельствует о включенном режиме обслуживания.

Итоговая конфигурация.

В секции http (вне секций server) прописываем проверку «разработчик или нет». Она будет распространяться на все сайты в случае виртуального хостинга. В данном случае, если у пользователя установлена cookie DEVELOPER_SECRET_COOKIE со значением 1100110101, то пользователь будет признан разработчиком.

map $http_cookie $isDevHack {
    default "";
    ~DEVELOPER_SECRET_COOKIE=1100110101 "/non-existed-location";
}

В соответствующей секции server объявляем собственный обработчик ошибки 503, которая будет использована для индикации режима обслуживания:

error_page 503 @maintenance;
location @maintenance {
    rewrite ^(.*)$ /maintenance-mode.html break;
}

В данном случае подразумевается, что страница, которую нужно показать в случае работы в режиме обслуживания, находится в файле maintenance-mode.html, который лежит в корне сайта ($document_root данной секции server).

Теперь осталось определить, нужно ли показывать страницу «на обслуживании». В секциях location, для которых должно работать это правило, в начале (до применения других правил, которые работают в нормальном режиме работы сайта) добавляем:

if (-f "$isDevHack/home/site_root/maintenance") {
    return 503;
}

В данном конкретном случае проверяется наличие файла в домашнем каталоге сайта. Вообще, проверять файл можно где-угодно. Проверка будет работать только для обычных пользователей, потому что переменная $isDevHack из нашего map-а выше испортит это имя в случае, если пользователь — разработчик, так что файл никогда не будет найден.

Пример конфига nginx целиком для сайта example.com.

]]>
https://valera.ws/2013.03.23~nginx-maintenance-mode-except-developers/feed/ 0
Бесплатный валидный (подписанный) SSL-сертификат через StartSSL https://valera.ws/2012.03.11~free-valid-signed-ssl-certificate-with-sratssl/ https://valera.ws/2012.03.11~free-valid-signed-ssl-certificate-with-sratssl/#comments Sun, 11 Mar 2012 13:31:25 +0000 http://valera.ws/?p=641 Читать далее Бесплатный валидный (подписанный) SSL-сертификат через StartSSL ]]> Итак, вы хотите получить бесплатный SSL-сертификат для своего сайта (для HTTPS). На сколько я знаю, единственный сервис, который выдает бесплатные валидные годовые сертификаты — это StartSSL. Израильская компания занимается цифровой сертификацией и является официальным Центром сертификации (CA) в PKI.

StartSSL раздает валидные годовые SSL-сертификаты бесплатно. Другие компании берут за это деньги начиная примерно от $20 в год. StartSSL зарабатывает на сертификатах более высоких классов, включая сертификат с расширенной валидацией, а базовый сертификат делает бесплатно. Их идея заключается в том, что они не берут деньги за сервис, в котором не используется труд людей (базовая валидация домена производится автоматически).

1. О системе StartSSL и их сертификатах

Особенность функционирования сайта StartSSL заключается в том, что авторизация в панель управления производится через клиентский S/MIME сертификат. Это большая редкость в наши дни. Отсюда возникает непонимание процесса неподготовленными пользователями и тупняк на этапе освоения сервиса.

Суть заключается в том, что вместо логина и пароля вам выдается сертификат. Почти такой же сертификат, какой выдается для подтверждения подлинности сервера. Этот сертификат отправляет на сервер ваш браузер при авторизации (автоматически после вашего подтверждения). Браузер берет его из хранилища, куда сертификат должен быть импортирован до проведения авторизации. Если сертификата в хранилище не окажется, то при авторизации вы увидите браузерное сообщение об ошибке, на подобии «Не удаётся завершить защищённую транзакцию».

Чтобы получить бесплатный сертификат для вашего сайта, нужно зарегистрироваться в сервисе StartSSL и получить персональный сертификат, войти с его помощью в панель, после чего можно будет заказать и получить бесплатный SSL-сертификат для вашего сайта.

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

Так же следует сразу отметить, что получить сертификат можно только для доменов из фиксированного списка зон. Это домены второго уровня во всех региональных и коммерческих зонах первого уровня, а так же отдельные зоны второго уровня (с доменами третьего уровня).

Кроме того, на домене должна работать почта. На один из ящиков из фиксированного списка (webmaster@домен, postmaster@домен, hostmaster@домен или адреса, указанные в Whois) придет письмо с кодом проверки.

2. Регистрация

Зайдите на сайт StarSSL и начните регистрацию (кликаем Sign-up). При этом нельзя использовать Google Chrome (можно Opera, Firefox, IE).

Страница авторизации StartSSL

2.1. Заполните форму. Укажите свои реальные данные. Во-первых, этого требует соглашение, с которым вы соглашаетесь при регистрации. Во-вторых, эти данные проверяются вручную. В-третьих, указывать здесь фейковый данные смысла мало, т.к. кроме самого StartSSL их никто не увидит.

Страница регистрации StartSSL

2.2. Укажите код подтверждения e-mail-а. Как правило, письмо с кодом приходит сразу или в течение минуты.

Страница ввода кода проверки e-mail-а на StartSSL

2.3. Дождитесь проверки указанных данных персоналом StartSSL. Да, они проверят то, что вы ввели в форме. Вручную. Если их ничего не смутит (а как правило ничего не смущает в реальных данных), вам придет ответ на e-mail, в котором будет указана ссылка на вторую активацию аккаунта (с кодом). Обратите внимание, что ссылка действует только в течение 24 часов.

Они могут задать дополнительные вопросы по e-mail для уточнения регистрационных данных. Отвечать на них имеет смысл, и опять-таки — честно.

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

Страница генерации приватного ключа на StartSSL

Для генерации ключа выбираем 2048 бит (в выпадающем меню), так как меньшую битность StartSSL не поддерживает, а в большей едва ли есть смысл.

После нажатия «Continue» генерируется ключ заданной длины. Он сохраняется в браузере и отправляется на сервер. Там генерируется сертификат на основании этого ключа. После генерации сертификат передается (после нажатия «Install») вам — в браузере появляется окно, предлагающее его установить.

Окно генерации персонального сертификата StartSSL

Окно установки персонального сертификата в Opera

Устанавливаем обязательно.

2.4. На данный момент картина следующая: у вас есть подтвержденная учетная запись StartSSL и персональный сертификат, установленный в браузер, который заменяет для вас одновременно логин и пароль.

Окно об бэкапе сертификата в StartSSL

Этот сертификат необходимо «достать» из браузера и сохранить в надежном месте. В случае потери установленного сертификата (например, переустановка ОС или браузера) вы сможете его вновь импортировать. Кроме того, сертификат нужен для того, чтобы войти в панель с другого компьютера.

Конкретные действия для экспорта сертификата зависят от вашего браузера. Общее лишь то, что вы должны попасть в управление хранилищем сертификатов, найти там свой персональный сертификат StartSSL и экспортировать его в файл. В Opera это делается так:

Экспорт сертификата в Opera

Экспорт сертификата в Opera

Формат экспорта — с секретным ключем PKCS#12. Если такого формата нет и вы не знаете, какой формат экспорта лучше выбрать (при условии, что их несколько), экспортируйте во все :). Если вы экспортируете сертификат без ключа, смысла в этом не будет — он не будет работать.

Если вы потеряете сертификат, утратите доступ к панели. Это значит, что для получения новых сертификатов и продления старых (через выписку нового), необходимо будет заново регистрироваться.

3. Итак, ваша учетная запись подтверждена и у вас есть персональный сертификат для авторизации в панели StartSSL. Теперь самое время зайти в панель. Нажимаем на кнопку с ключами и попадаем на страницу авторизации (смотрите на первом изображении в статье). Нажимаем «Authenticate». Подтверждаем передачу серверу нашего персонального сертификата. Авторизация пройдена — вы в панели.

Если на этом этапе вы получаете ошибки, значит что-то не то с сертификатом. Если браузер при авторизации не выдавал вам предложения отправить сертификат на сервер, значит он не импортирован в хранилище (см. выше).

Самое тяжелое позади. Теперь необходимо заказать и получить сертификат для вашего сайта. Он будет выдан на год. Спустя 11 месяцев необходимо зайти на сайт и получить новый сертификат на тот же сайт (то же имя). Как таковой процедуры продления сертификатов нет ни для сайта, ни для персональных сертификатов. Об окончании срока действия сертификатов StartSSL несколько раз раз предупреждает по почте.

Страница Tool Box панели StartSSL

Панель StartSSL состоит из 3-х разделов (вкладки на изображении выше):

  • Tool Box — инструментарий. Большая его часть бесполезна. Можно отметить только разделы для получения корневых и промежуточных сертификатов StartSSL и получения ранее созданных сертификатов.
  • Certificates Wizard — мастер создания нового сертификата. С него начинается заказ нового сертификата для сайта или персонального сертификата. Для создания сертификата должен быть заранее подтвержден домен или адрес e-mail соответственно.
  • Validations Wizard — это как раз и есть мастер проверки сайта и e-mail (а кроме того платных проверок личности и организации). С него нужно начинать получение сертификата для сайта. Каждая проверка действует 30 дней, так что при «продлении» сертификатов проверки необходимо повторять.

Итак, начинаем процесс получения сертификата для сайта.

3.1. Проверка (валидация) домена. Переходим в Validations Wizard, выбираем проверку домена (Domain Name Validation):

Окно мастера проверки StartSSL

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

Страница выбора e-mail-а для проверки домена StartSSL

3.2. После проверки принадлежности домена нужно заказать для него сертификат. Для этого перейдите в Certificates Wizard, выберите Web Server SSL/TSL Certificate. Далее выберите из списка один из предварительно проверенных доменов.

Получение сертификата StartSSL

На следующем шаге есть два варианта:

  • пропустить шаг и предоставить собственноручно сгенерированный CSR со своим приватным ключем,
  • или заполнить форму и сгенерировать приватный ключ в браузере.

Получение сертификата StartSSL

Первый вариант выбирают те, кто знает, что такое CSR и как его сделать. В любом случае обратите внимание на то, что размер ключа (Keysize) не должен быть менее 2048 бит.

Предположим, что выбран вариант с генерацией ключа. Тогда заполните форму и нажмите «Continue». После некоторой паузы вы получите свой ключ. Сохраните его, он пригодится позже.

Получение приватного ключа StartSSL

На следующем шаге повторно выберите домен. Далее, укажите для него поддомен. Сертификат будет действителен для выбранного домена и указанного сабдомена (например, www).

Указание сабдомена для сертификата StartSSL

На следующем шаге просто подтверждается заказ сертификата. После этого вы получите сам сертификат (PEM-encoded). Сохраните его.

Получение сертификата StartSSL

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

openssl rsa -in ssl.key -out ssl.key

О том, как настроить веб-сервер для использования полученного сертификата, как-нибудь в следующий раз. А вообще, по этой теме хватает информации в Интернете.

]]>
https://valera.ws/2012.03.11~free-valid-signed-ssl-certificate-with-sratssl/feed/ 6
Выдача файла из PHP через nginx (Accel-Redirect) + докачка + некоторые тонкости https://valera.ws/2012.03.06~accel-redirect-apache-dokachka/ https://valera.ws/2012.03.06~accel-redirect-apache-dokachka/#respond Tue, 06 Mar 2012 20:28:27 +0000 http://valera.ws/?p=644 Читать далее Выдача файла из PHP через nginx (Accel-Redirect) + докачка + некоторые тонкости ]]> Как контролировать скачивание больших файлов, проверяя права доступа или считая количество закачек? Как сделать, чтобы при проксировании на Apache работала докачка? Как вообще работает докачка, почему она не работает с nginx в IE 9 и как она работает в других браузерах?

1. Мы хотим контролировать скачивание больших файлов, проверяя права доступа или считая количество закачек. Мы используем nginx и PHP (или другой серверный язык).

Это реализуется очень просто через заголовок Accel-Redirect. nginx получает запрос, передает его скрипту, скрипт в заголовки ответа выдает Accel-Redirect с ссылкой на файл, который нужно выдать пользователю. Если файл выдавать нельзя (например, нет прав), скрипт просто выдаст ошибку (например, 403).

В данном случае не важно, работает ваш PHP через проксирование из nginx на Apache, либо на *CGI. Предположим, что вы хотите отдавать на скачку файлы, которые находятся в каталоге /var/files. Тогда в секции server в nginx добавьте:

location /_download_files {
        root /var/files;
        internal;
}

В скрипте, который контролирует закачку, в том месте, где мы хотим отдать пользователю файл, должен быть следующий код:

header("X-Accel-Redirect: /_download_files/filename.zip");

Никакой выдачи (echo) делать не надо, после отдачи заголовка можно завершить работу скрипта. В этом случае будет скачан файл /var/files/filename.zip. Вместо filename.zip может быть любой длинный путь с каталогами, который должен повторять путь к файлу в /var/files/.

В принципе этого достаточно, чтобы переложить выдачу файла на плечи nginx. Если нужно обязательно показать диалог закачки (даже если файл такого типа, который браузер может показать сам), нужно добавить выдачу заголовка:

header("Content-Type: application/x-force-download");

Обратите так же внимание на то, что в случае проксирования на Apache последний обязательно установит Content-Type (по умолчанию обычно text/html) в случае PHP-скриптов, и этот тип отправится пользователю, так как nginx его не перепишет при выполнении Accel-Redirect. Т.е. в этом случае эту строку нужно писать обязательно. Как будет в случаях с *CGI, не знаю — не проверял.

Чтобы предложить пользователю имя файла для сохранения, отличное от того, что в адресной строке (это особо актуально в случаях «download.php&file_id=12332»), отправим такой заголовок:

Content-Disposition: attachment; filename="Super File Name.zip";

2. В такой схеме при проксировании на Apache не работает докачка. Исправляем.

Докачка в HTTP работает через HTTP-заголовок Range. В нем указывается с какого байта начать передачу. Можно так же указать, сколько байт нужно передать. Это передается в запросе. Например:

Range: bytes=33-
Range: bytes=33-100

Первый вариант просит отдать весь файл, начиная с 33 байта (включительно). Второй вариант просит отдать с 33 байта по 100. Чтобы браузер понял, что докачка поддерживается, сервер отдает в ответе заголовок:

Accept-Ranges: bytes

Докачка не работает из-за того, что HTTP-заголовок Range попадает в Apache после просирования и последний думает, что его просят отдать кусок PHP-файла. А он это делать не хочет и отдает ошибку: HTTP/1.1 416 Requested Range Not Satisfiable.

Исправляется это довольно легко — просто зануляйте при проксировании Range (это нужно добавить туда, где у вас описано проксирование на Apache в конфиге nginx):

proxy_set_header   Range   "";

Тогда Apache (или PHP-скрипт) ничего знать про него не будут и спокойно сделают свое дело. А nginx после Accel-Redirect отдаст ответ в соответствии с запрошенным Range.

Если жизненно необходимо видеть в скрипте запрошенный Range, то его можно либо передать через дополнительный заголовок при проксировании (proxy_add_header), либо последовать совету отсюда.

3. Даже так не работает докачка в IE 9.

Да. На сколько я понял методом простого тыка, IE требует поддержки ETag сервером для работы докачки. Игорь Сысоев (разработчик nginx) отказался внедрять в nginx поддержку ETag. Поэтому из коробки работать докачка в IE 9 не будет точно. Если это жизненно необходимо, пробуйте смотреть сюда (Ctrl+F Etag).

4. А как работает докачка в других браузерах?

Везде есть свои особенности. В общих чертах случай докачки выглядит так. Запрос/ответ на скачку (начало скачки):

GET /file.zip HTTP/1.1
Host: example.com

HTTP/1.1 200 OK
Server: nginx/1.0.3
Date: Tue, 06 Mar 2012 18:09:47 GMT
Content-Type: application/x-force-download
Content-Length: 13686314
Last-Modified: Thu, 23 Feb 2012 13:50:26 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Content-Disposition: attachment; filename="Supre File Name.zip";
Accept-Ranges: bytes

Запрос/ответ на докачку:

GET /file.zip HTTP/1.1
Host: example.com
Range: bytes=5393683-

HTTP/1.1 206 Partial Content
Server: nginx/1.0.3
Date: Tue, 06 Mar 2012 18:10:11 GMT
Content-Type: application/x-force-download
Content-Length: 8292631
Last-Modified: Thu, 23 Feb 2012 13:50:26 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Content-Disposition: attachment; filename="Super File Name.zip";
Content-Range: bytes 5393683-13686313/13686314

На практике ни один браузер не ограничивается таким набором заголовков. Все хотят защитить пользователя от скачки битого файла. Это может получиться так: начал закачку, поставил на паузу; в это время на сервере скачиваемый файл обновился; продолжил закачку с нужно места и получил кусок обновленного файла. В результате скачается «битый» файл — половина старая версия, половина — новая.

Opera. Она шлет указание на то, что «если файл не менялся со времени Last-Modified в первом ответе, дай мне указанный кусок; иначе — отдай мне весь файл заново». Делается это с помощью заголовка If-Range в запросе:

GET /file.zip HTTP/1.1
User-Agent: Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.10.229 Version/11.61
Host: example.com
Accept text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, ..., */*;q=0.1
Accept-Language: ru-RU,ru;q=0.9,en;q=0.8
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
If-Range: Thu, 23 Feb 2012 13:50:26 GMT
Range: bytes=5393683-

Firefox. Он делает немного иначе. Используется заголовок If-Unmodified-Since с указанием того же времени из Last-Modified. В этом случае сервер либо вернет запрошенный кусок (если файл не менялся), либо отдаст ошибку 412 Precondition Failed. Выглядит это так:

GET /file.zip HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.2) Gecko/20100101 Firefox/10.0.2
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Range: bytes=5878651-
If-Unmodified-Since: Thu, 23 Feb 2012 13:50:26 GMT

Chrome. Этот «пильмень» — самый хитрый. Он вообще не поддерживает докачку, хотя делает вид, что поддерживает. При постановке закачка на паузу он просто шлет некие TCP-пакеты для поддержания соединения. Когда сервер понимает, что его дурят, он разрывает соединение. Если дождаться этого момента и нажать в Хроме «Продолжить», он сделает умный вид, будто файл полностью скачался и все ОК, но при этом он останется в том размере, в котором успел скачаться до паузы.

Вся эта информация получена методом наблюдения. Возможно в какой-то другой ситуации Хром повел бы себя иначе, но я через WireShark наблюдал именно такую картину.

IE. Про версию 9 уже сказано выше. Она требует работы Etag для поддержки докачки. В данном контексте ETag — это просто контрольная сумма файла. Когда Etag файла передается в первом ответе от сервера, IE даст возможность прервать скачку. При попытке докачки он отдаст заголовки:

GET /file.zip HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Host: falcongaze.com
Range: bytes=3494051-
Unless-Modified-Since: Mon, 05 Mar 2012 08:31:06 GMT
If-Range: "1448453-f77f31-4ba7abf5a8680"
Connection: Keep-Alive

В добавок к If-Range он передает нестадартный заголовок Unless-Modified-Since — вероятено IIS его обрабатывает (только не понятно, зачем он, если есть стандартный If-Unmodified-Since; может для поддержки старых версий IIS?).

Собственно в первом ответе Etag выглядит примерно так (если он поддерживается сервером, например, Apache):

...
ETag: "1448453-f77f31-4ba7abf5a8680"

Дополнительная информация:

]]>
https://valera.ws/2012.03.06~accel-redirect-apache-dokachka/feed/ 0