Не совсем тривиальный HTTP-прокси на Erlang
24 декабря 2012
Написал тут HTTP-проксю на Erlang’е. Зачем? Ну, например, мне захотелось попробовать Cowboy и написать на Erlang относительно серьезное приложение. Кода получилось довольно много, целых 300 строк! Разбирать его здесь я смысла не вижу, желающие сами ознакомятся и разберутся. Лучше я расскажу, что прокся умеет и как ею пользоваться.
Итак, что прокся умеет:
- Скрывать ваш IP, при этом вы сможете нормально загружать странички, отправлять формочки и даже закачивать небольшие файлики;
- Скачивать большие объемы данных;
- Сжимать данные gzip’ом, если они не были сжаты;
- Работать в режиме reverse proxy с буфферизацией данных и рерайтами;
- Игнорировать рекурсивные запросы;
- Читать конфигурационный файл;
Что прокся не умеет:
- Ограничивать доступ к самой себе по логину-паролю;
- Кэшировать страницы;
- Самостоятельно раздавать статику;
- Понимать запросы, отличные от GET, POST и HEAD;
- Хорошо обрабатывать большие POST-запросы;
- Работать с SSL;
- И многое другое;
Собираем:
git clone git://github.com/afiskon/erlang-http-proxy.git
cd erlang-http-proxy
make build
Прогоняем простенький тест:
В этом тесте прокся поднимается на 8080-м порту и через нее загружается ya.ru. Если приходит код 200, тест пройден. Если вы располагаете большим количеством времени, то можете прогнать все-все-все тесты:
Настраивается прокси через app.config. Основные параметры следующие:
{ port, 8080 },
Номер порта, на котором поднимается прокси.
Количество воркеров.
Сколько миллисекунд дается клиенту на отправку запроса.
Если false, данные буферизируются, если true — не буферизируются.
Какими кусками отдавать данные клиенту. Имеет смысл только при sync_stream = false. Например, если вы решили использовать сервер в качестве reverse proxy для того, чтобы Apache не занимался передачей данных по медленным соединениям, нужно присвоить sync_stream значение false, а stream_chunk_size — максимальный размер веб-страницы.
Если данные никак не закодированы, сжимать их gzip’ом.
{ "^http://[^/]+/mail/(.*)$", "http://mail.ru/\\1" }
]}
]}
Если запрашиваемый URL соответствует регулярному выражению (первый элемент пары), заменить его в соответствии с правилом (второй элемент пары). Если не соответствует, идем дальше по списку пар. Если в списке больше не осталось элементов, оставляем URL без изменений.
Запускаем:
Проверяем:
Сказав браузеру работать через прокси, я:
- Скачал ISO образ размером 4 Гб на скорости около 200 Кб/сек при включенном сжатии gzip’ом, проверил значение MD5;
- Почитал бложики, послушал музыку во Вконтакте, посмотрел видео на YouTube;
- Открыл десяток вкладок с «тяжелыми» сайтами типа lenta.ru, заставил их обновляться каждую минуту с помощью специального плагина, после чего отправился спать;
- На утро написал этот пост;
Прокся работает шустренько и стабильненько. В худшем случае на моем слабеньком домашнем компьютере она кушала 5-7% CPU и около 18 Мб памяти. Притом с ростом количества соединений это число как-то не особо думает увеличиваться. Не падает, ошибками не сыпет.
Весь код лежит на GitHub’е. Надеюсь, кому-нибудь он пригодится. Буду рад вашим багрепортам и пуллреквестам.
Дополнение: См также заметку про получение load average в Erlang.
Метки: Erlang, Функциональное программирование.
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.