Skip to main content

· 8 min read
Pavel Ratmanov
Mark Fomin

В этой статье мы, разработчики Elan, рассмотрим различные методы захвата вывода процесса в тестирующей системе Elan и сравним их производительность.

В тестирующей системе есть отдельная подсистема, которая выполняет запуск процесса в изолированной среде. Она применяет некоторые ограничения для безопасности (например, ограничения потребления памяти и времени выполнения, контроль запускаемых процессом системных вызовов и многое другое). Мы называем ее runner engine. Runner также умеет передавать данные в stdin процесса и захватывать вывод в stdout (стандартном потоке вывода) и stderr (стандартном потоке вывода информации об ошибках).

Отрывок презентации про runner engine из доклада команды разработчиков Elan (листайте)
Отрывок презентации про runner engine из доклада команды разработчиков Elan (листайте)

Подробнее о тестирующей системе и о runner engine можно прочитать в одном из наших докладов, а в этой статье мы разберем различные способы захвата вывода процесса в поток, сравним их производительность и рассмотрим их особенности.

Словарь

Для начала определимся с двумя основными механизмами ОС, которые мы используем для захвата вывода.

  • tmpfs - файловая система, предназначенная для использования как временное хранилище во многих Unix-подобных ОС. Tmpfs можно примонтировать как обычную файловую систему, но размещается она в ОЗУ, а не на физическом диске, что дает большой прирост к скорости чтения и записи.
  • pipe - механизм межпроцессного взаимодействия, который позволяет передавать данные между процессами в одну сторону.

Методика оценки

Замер скорости захвата вывода в runner

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

#pragma GCC optimize("O0")
#include <iostream>
int main() {
int i;
std::cin >> i;
while (--i) {
std::cout << 0;
}
}

Как видно, она принимает число i и генерирует выходной поток из i байт (i раз повторенного символа "0").

С помощью прагмы мы также отключаем все оптимизации компилятора, чтобы статистика была максимально точной.

Чтобы оценить скорость различных методов захвата вывода, мы запускали эту программу с различными значениями i (степени двойки от 1 до 2^26≈6.7e7) с помощью runner и сохраняли значения real time и CPU time.

Устройство, на котором замеряли

Тестирование проводилось на ноутбуке Lenovo ThinkPad 15 Gen1 с такими характеристиками:

  • процессор Intel Core i7-1065g7
  • 32gb ОЗУ
  • диск HDD WDC WD5000LPVX-75V0TT0
  • OS - Manjaro Linux

Основные методы захвата вывода

  • Вывод в обычный файл - average 1'200 ms (CPU time), 4'300 ms (real time)
  • Вывод в файл в tmpfs - average 1'200 ms (CPU time), 1'600 ms (real time)
  • Вывод в pipe (с перенаправлением в строку) - average 1'150 ms (CPU time), 1700 ms (real time)
  • Вывод в pipe (с перенаправлением в файл) - average 1'200 ms (CPU time), 1650 ms (real time)
  • Вывод в pipe (с перенаправлением в файл в tmpfs) - average 1'200 ms (CPU time), 1650 ms (real time)
  • Вывод в строку через считывание системных вызовов - average 1'200 ms (CPU time), 15'000 ms (real time)

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

Info

Вы можете скачать Jupyter Notebook с кодом и данными для построения графиков здесь.

Вывод в обычный файл

При помощи dup2(2) вывод просто перенаправляется в файловый дескриптор, полученный с помощью open(2).

Особенности:

  • ✅ Не потребляет оперативную память
  • ❌ Работает довольно медленно

To file

Вывод в строку через считывание системных вызовов

В цикле ptrace(2) получаем информацию о том, что процесс вызвал write(2) и через PTRACE_PEEKDATA считываем данные. При этом вывод самого процесса перенаправлен в /dev/null.

Особенности:

  • ❌ Работает КРАЙНЕ медленно из-за того, что PTRACE_PEEKDATA позволяет считывать данные только по 8 байт

To string from syscalls

Вывод в файл в tmpfs

При помощи dup2(2) вывод просто перенаправляется в файловый дескриптор, полученный с помощью open(2), но открывается файл, который находится в tmpfs.

Особенности:

  • ❌ Потребляет много оперативной памяти
  • ✅ Работает быстро

To file in tmpfs

Вывод в pipe с перенаправлением в строку

При помощи dup2(2) вывод перенаправляется в файловый дескриптор, полученный с помощью pipe(2), но когда в цикле ptrace(2) мы узнаем, что pipe переполнился, то все текущие данные в pipe считываем в строку.

Особенности:

  • ✅ Работает достаточно быстро
  • ❌ Ест оперативную память
  • ❌ Возвращает крайне тяжеловесный объект

To string from pipe

Вывод в pipe с перенаправлением в файл в tmpfs

При помощи dup2(2) вывод перенаправляется в файловый дескриптор, полученный с помощью pipe(2), но когда в цикле ptrace(2) мы узнаем, что pipe переполнился, то все текущие данные в pipe считываем в файл в tmpfs.

Особенности:

  • ✅ Работает быстро
  • ❌ Ест оперативную память

To file in tmpfs through pipe

Вывод в pipe с перенаправлением в обычный файл

При помощи dup2(2) вывод перенаправляется в файловый дескриптор, полученный с помощью pipe(2), но когда в цикле ptrace(2) мы узнаем, что pipe переполнился, то все текущие данные в pipe считываем в обычный файл, открытый с помощью open(2).

Особенности:

  • ✅ Работает достаточно быстро
  • ✅ Не ест оперативную память

To file through pipe

Графики

Дальше мы решили оценить скорость разных методов захвата относительно друг друга. Так как мы решаем задачу, которую выполняет runner, в рамках тестирующей системы, в которой нужно корректно оценивать время выполнения программы, а в спортивном программировании основное значение имеет процессорное время (а реальное время нужно только для оценки idleness limit, лимита времени простоя), то давайте сравним сначала процессорное время.

CPU time

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

В таком случае сравним реальное время:

Real time

Тут уже различия существенны. Нужно понимать, что программа в реальности почти никогда не упрется в лимит по реальному времени, так что реальное время всего лишь улучшает или ухудшает скорость тестирования.

Вывод

  • Для классических задач лучше всего использовать вывод в pipe с перенаправлением в файл, потому что он использует для вывода не более 67 Кбайт
  • Для интерактивных задач лучшим вариантом будет вывод в файл в tmpfs, потому что он не имеет буфера и позволяет получать вывод процесса в реальном времени
Справка

Интерактивные задачи - это задачи, в которых ввод и вывод программы участника соревнования передаются специальной программе-интерактору, которая взаимодействует с программой участника и проверяет корректность ее работы. Например, с помощью интерактивных задач можно создавать задачи на игры. В таком случае участнику надо написать программу, которая делает какие-то ходы, а ответы интерактора на эти ходы зависят от того, как именно сходила программа. Здесь в качестве игр могут выступать не только типичные игры, но и «угадайки». Например: было загадано число от 1 до n. Программа участника пытается его угадать, а интерактивный модуль отвечает больше или меньше загаданное число очередной попытки участника. Требуется отгадать число, сделав не более 2 log2 n попыток. В качестве решения здесь участник может использовать бинарный поиск.

· 5 min read
Mark Fomin

Кто такие ваши мокапы и зачем они нужны

Смешная картинка для привлечения внимания

Он нам и даром не нужен, этот ваш мокап!

Немного моих наблюдений про мокапы со смартфонами.

Большинство идей для этого поста взято из моего личного опыта, но что-то было взято из сообщества VK Designers.

Мокап — это модель объекта, с помощью которой можно наглядно продемонстрировать дизайн чего-либо (правда, тут мы говорим только о приложениях) и до производства (разработки) оценить, как продукт будет выглядеть в реальности.

В случае с приложениями, мокап представляет собой изображение смартфона, в котором открыто презентуемое приложение.

Пример мокапа

Пример мокапа

Note

Мокапы - быстрый и эффективный способ презентовать идею заказчику.

Требования к мокапам

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

Чуть более подробно про реалистичность:

  • Обращайте внимание на блики, отражения и тени. На хорошем мокапе они обязательно будут в правильных местах. Если для реалистичности нужно добавить блики, это можно сделать в Photoshop или Figma. Также стоит добавлять тени (мне нравится концепция Material Design касательно использования теней для того, чтобы передать объем и расстояние между объектами мокапа по оси Z)
  • Среди шаблонов мокапов (о которых, кстати, есть пару слов ниже) довольно много шаблонов, в которых искусственность 3D-графики бросается в глаза. Из-за отсутствия внимания к деталям они не похожи на фотоснимок. Перенести дизайн на такое изображение можно, но результат будет недостаточно убедителен, поскольку дизайн будет показан не в реальной, а полностью цифровой среде. Лучше отложить такой мокап и попробовать найти более реалистичное изображение.

Пример слишком искусственной графики

Пример слишком искусственной (нереалистичной) графики - особенно если посмотреть на задний блок камер

Устройство

Еще стоит обратить внимание на устройство, на основе которого вы делаете мокап. Здесь нужно найти грань между убедительностью и естественностью.

Иногда вы разрабатываете проект под специфический набор устройств, и понятно, что именно эти устройства должны быть использованы в мокапах. Например, недавно вышел таск-трекер Dothing специально для Nothing Phone. Очевидно, что для презентации этого продукта вряд ли подойдет iPhone - в подобных кейсах используем специфические устройства, чтобы не совершать прям совсем смешные ляпы.

Dothing

Если ваш проект ориентируется на специфические устройства, их и нужно использовать в мокапах

Но как выбрать устройство для мокапа в общем случае? В своем выпускном проекте в Samsung я экспериментировал с Google Pixel 6, мне в принципе понравился результат. В общем, если ваше приложение заточено под Android, использование флагманских устройств Google - идеальный вариант.

VK GPT

Довольно реалистичный и красивый мокап устройства Google, по внешнему дизайну (с передней стороны) ставший де-факто стандартом для устройств на Android

А еще в общем случае можно использовать последние версии iPhone - их внешний дизайн, возможно, довольно заезжен, но точно будет выглядеть дорого и убедительно.

iPhone

Красота!

А можно совсем без устройства?

Да! Если вы не хотите акцентировать внимание на специфическом устройстве (например, у вас мультиплатформенное приложение, сайт или миниап), можно полностью избавиться от устройства, а вместо него использовать полупрозрачные рамки. Например:

без устройства

Выглядит минималистично, красиво и не привлекает лишнего внимания к устройству.

Еще можно полупрозрачные рамки заменить на тени (эта идея взята из дизайн-концепта Миши Суханова): rapzer

Где брать готовые мокапы

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

  • во вкладке Community в Figma
  • используя специальные плагины в Figma:
    • плагин для красивого поворота изображения в 3D: 3D Transformer
    • плагин, позволяющий выбрать разные устройства от iPhone 15 Pro Max до Google Pixel 8 Pro: iMockup
    • Rotato 3D Mockups (конкретно этот не использовал лично)
    • Wireframer для генерации красивых плейсхолдеров для текста (напоминает спойлеры в Telegram)
  • используя известные каждому дизайнеру behance.net и Dribbble

· 6 min read
Mark Fomin

Что такое fastapi?

fastapi - имхо, самый лучший фреймворк для веб-разработки на Python, основными фичами которого являются:

  • высокая производительность относительно других фреймворков на Python за счет использования starlette и uvicorn в качестве ASGI-сервера, сравним по скорости с фреймворками на Go и NodeJS
  • простота использования - благодаря pydantic (для валидации запросов) и целой куче готовых подмодулей для любых задач (websockets, background tasks, система зависимостей компонентов приложения, middlewares и многое другое) очень легко и интуитивно понятно, как написать какую-то вещь
  • полная типизация фреймворка и поддержка редакторами - меньше времени на дебаг и подсказки IDE
  • автоматическая генерация документации (по схеме OpenAPI, Swagger и Redoc)

Что такое cython?

Cython - это промежуточный слой между Python и C/C++. Cython позволяет писать обычный Python-код, добавляя функции из стандаратной библиотеки языков C/C++ и ускоряя код за счет использования C-типов (что, впрочем, не обязательно), который затем напрямую транслируется в C-код.

Что будем делать?

В этом блоге попробуем ускорить и без того довольно быстрый проект на fastapi, ситонизируя (cythonize) его. Для примера возьмем вот такой код (выдрал минимальный код из одного из текущих проектов, поэтому такая структура):

routes/ftl/ftl.py
from fastapi import APIRouter

router = APIRouter(
prefix="/ftl.",
tags=["ftl"]
)


@router.get("test")
async def test_method():
return {"ping": "pong"}
routes/__init__.py
from .ftl import ftl
main.pyx
from fastapi import FastAPI
import uvicorn
from routers import ftl


app = FastAPI()
app.include_router(ftl.router, prefix="/method")


@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}

uvicorn.run("main:app", host="127.0.0.1", port=5000, log_level="critical")

Тут мы создаем роутер для группы методов под названием ftl с одним методом - ftl.test. Обычно для запуска fastapi-приложений используют uvicorn из терминала (примерно так):

python3 -m uvicorn main:app --host 0.0.0.0 --port 5000

Но так как мы скомпилируем проект в один бинарник, который можно будет запускать через ./app, запуск ASGI-сервера мы засунули в код проекта.

Теперь установим нужные зависимости (желательно в виртуальном окружении):

pip3 install fastapi
pip3 install cython
pip3 install 'uvicorn[standard]'
warning

Обратите внимание, что мы ставим не обычный uvicorn, а uvicorn[standart] - его ситонизированную версию. Это даст некоторую прибавку в скорости даже при запуске pure python кода.

Ситонизируем и оцениваем!

Чтобы ситонизировать наш проект, потребуется написать олдскульный файл setup.py:

setup.py
from setuptools import setup
from Cython.Build import cythonize

setup(
ext_modules = cythonize("main.pyx")
)

Теперь напишем builder.c - файл для генерации единого бинарника со всем проектом:

builder.c
#include <Python.h>

int main(int argc, char *argv[]) {
// Инициализация интерпретатора Python
Py_Initialize();

// Вызов вашей функции из скомпилированной библиотеки
PyObject *pName, *pModule, *pDict, *pFunc, *pValue;

pName = PyUnicode_DecodeFSDefault("main.cpython-310-x86_64-linux-gnu");
pModule = PyImport_Import(pName);
pDict = PyModule_GetDict(pModule);
pFunc = PyDict_GetItemString(pDict, "root");
pValue = PyObject_CallObject(pFunc, NULL);

// Вывод результата или обработка его каким-либо образом

// Завершение интерпретатора Python
Py_Finalize();

return 0;
}

Да, он написан ChatGPT. Я не умею в Python API 😢

Собираем проект в единый бинарь:

cython main.pyx
python3 setup.py build_ext --build-lib=. # создаст файл main.c и скомпилит его в .so
gcc -o app.o builder.c -I/usr/include/python3.10 -lpython3.10 -Wall -g # компилим main.c в обычный бинарь (.o)

Запускаем:

export PYTHONPATH=`pwd` # укажем pythonpath в нашем виртуальном окружении
./app.o

Если все прошло хорошо, не будет выведено ничего, но проект запустится на 5000 порте. Проверить можно, сходив по адресу http://localhost:5000/method/ftl.test

Теперь пришло время бенчмарков. Для тестов будем использовать Apache Benchmark.

sudo apt install -y apache2-utils
ab -n 10000 -c 10 http://localhost:5000/method/ftl.test

Желательно не нагружать сеть во время проведения оценки.

Info

Мы используем log-level="critical", чтобы отключить логи о запросах. Логи выводятся в терминал и сильно и непредсказуемо замедляют работу приложения, из-за чего нельзя корректно оценить его скорость на бенчмарке.

Оцениваем этот же код без ситонизации

Для начала удалим main.c и main.<arch>.so из папки проекта, чтобы uvicorn использовал питоновскую версию, а не скомпиленную cythonized.

Далее нужно переименовать main.pyx в main.py и удалить (закомментировать) строчки, связанные с uvicorn:

main.py
from fastapi import FastAPI
# import uvicorn
from routers import ftl


app = FastAPI()
app.include_router(ftl.router, prefix="/method")


@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}

# uvicorn.run("main:app", host="127.0.0.1", port=5000, log_level="critical")

Запускаем через терминал:

python3 -m uvicorn main:app --port 5000 --log-level critical

Далее используем ту же команду для запуска Apache Brenchmark:

ab -n 10000 -c 10 http://localhost:5000/method/ftl.test

Результаты

В левом терминале запуск ситонизированного кода, в правом - обычного, на чистом Python. Результаты

В случае с Cython 90% запросов были обработаны за 6 миллисекунд, а самый долгий запрос был обработан за 17 миллисекунд (против 57 в бенчмарке обычного Python).

Что-то вроде вывода

Даже не используя какие-то специфические вещи, вроде сложных вычислений или работы с памятью, которые были бы значительно быстрее в Cython, чем в Python, Cython оказался в 3.35 раза быстрее точно такого же кода на чистом Python. Это означает, что можно в несколько ускорить ваш проект, не внося почти никаких изменений, просто подключив Cython.

Используйте Cython, господа!

— я

· 4 min read
Mark Fomin

Это первый пост в этом блоге! Спустя кучу часов, проведенных за дебагом и настройки docusaurus, сотни раз введенные в терминал npm run start, финальное npm run build && npm run serve и вуаля - мы здесь.

Что тут будет публиковаться?

Сюда я буду переносить технические статьи и свои мысли из своего Obsidian, благо, движок docusaurus, упомянутый ранее, автоматически генерирует красивые странички из Markdown-файлов. Я довольно давно пытался найти способ делиться записями из своей базы знаний с другими, перепробовал кучу способов, начиная от статей ВКонтакте и telegra.ph, заканчивая GitHub и Notion. Но по итогу, как вы видите, я пришел к куда более простому решению - одному GitHub-репозиторию со всеми заметками, который с магией CI/CD автоматически развертывает мой блог на сайте.

Note

Раз уж я решил написать первую статью, то расскажу, как работает мой блог.

Технический обзор блога

Блог - React-приложение, использующее фреймворк docusaurus. Этот фреймворк создан для генерации простых и красивых сайтов документации к проектам, но в моем случае основную фичу я отключил за ненадобностью простым добавлением docs: false в файл конфига. Docusaurus из коробки умеет в генерацию статичных HTML-страниц из Markdown (MD, язык разметки) и MDX (тоже самое, что и MD, но еще с поддержкой JSX), причем я даже сейчас не про блог - вы можете вставить в любое место MD-файл и будет создана страница с его именем: например, в /pages я создал файл test.md (можете посмотреть исходники блога на GitHub), и теперь он доступен по адресу https://difhel.dev/test.

Кажется, я уже упоминал про JSX? Да, тут можно просто в файле вставлять JS-код:

<button onClick={() => alert('Вы нажали кнопку!')}>Нажми сюда!</button>

Помимо этого, функционал сайта на Docusaurus можно практически бесконечно увеличивать за счет поддержки большого количества плагинов. Например, я установил плагин i18n, чтобы добавить поддержку как английского, так и русского языка. Ну и после всего вышеописанного, наверное, покажется банальным, но все-все-все внутренние страницы сайта можно изменить ручками в коде - сам сайт написан на React.

Где хранятся публикации в блоге и статика?

Публикации (MD/MDX) файлы лежат в папке /blog проекта. Весь мой сайт доступен на GitHub, включая исходники постов в Markdown. Сайт автоматически деплоится после коммита на Vercel, это бесплатно и очень удобно, всем рекомендую.

Какие планы на будущее блога?

Добавить больше CI/CD - написать GitHub Action для проверки орфографических ошибок. Еще сильнее упросить процесс загрузки новых постов на сайт (сейчас нужно просто закинуть файл в папку и сделать коммит), поскольку Markdown в Docusaurus и в Obsidian не всегда совместим (например, Callouts работают по разному):

Markdown в Docusaurus
:::info
В Docusaurus они работают вот так
:::
Info

В Docusaurus они работают вот так

А в Obsidian - так:

Markdown в Obsidian
> [!info]
> Вот так.

[!info] Вот так.

Написать GitHub Action в виде Telegram-бота, для автоматических уведомлений в канал о новых статьях

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

· 6 min read
Mark Fomin

Вступление

Info

Статья перенесена на сайт difhel.dev 21 декабря 2023 года с внесением незначительных изменений.

Смотреть оригинальную статью в веб-архиве - https://vk.com/@superdev-mobile-traffic-interception

Если вы так же, как и я редко бываете дома и часто не имеете доступа к ноутбуку с Charles Proxy / Burp Suite, то эта статья для вас.

Тут - о том, как перехватывать (и, конечно, изменять) HTTP/HTTPS трафик, имея доступ только к телефону.

Нам понадобится

Магическое приложение (aka чарлик мобайл) - это и есть SandroProxy. Программа была создана в 2012 и не обновлялась с 2016 года. Тем не менее, мне удалось ее запустить в 2023 на Android 13, хотя некоторые фичи не работают.

Начинаем магию!

Для начала выдаем разрешения SandroProxy, далее нужно предоставить root-права. Для удобства можно в Magisk временно включить автоматическое предоставление прав при запросе.

Программа встречает нас современным интерфейсом в стиле последней версии Material Design 3 /s

1. Выбираем режим Plain proxy, выделенный режим помечается звездочкой (вообще нам нужен developers mode, но у меня с ним возникло много проблем).
1. Выбираем режим Plain proxy, выделенный режим помечается звездочкой (вообще нам нужен developers mode, но у меня с ним возникло много проблем).

Далее нужно настроить систему для перенаправления всего трафика на localhost:8008. Есть вариант подключиться к WiFi и использовать прокси. Но у меня это не заработало.

Поэтому нам нужен оберточный прокси Drony. В нем нужно настроить перенаправление всего трафика системы на localhost:8008. Для этого Drony будет использовать VPN-соединение.

1. Интерфейс Drony. Не включаем прокси до настройки!
1. Интерфейс Drony. Не включаем прокси до настройки!

Далее выбираем тип соединения с интернетом - WiFi или другое (например, мобильный интернет).

1. Выбираем Hostname localhost и порт 8008, proxy type - manual
1. Выбираем Hostname localhost и порт 8008, proxy type - manual

Выбираем Hostname localhost и порт 8008, proxy type - manual.

Если мы сейчас запустим Drony, то произойдет примерно следующее.

  1. SandroProxy ловит запрос и отправляет его на заданный сервер.
  2. Поскольку запрос исходит с телефона, он проходит по VPN-соединению Drony.
  3. Drony редиректит запрос на localhost:8008.
  4. Запрос дублируется.
  5. Приложение уходит в вечную рекурсию и падает.

Чтобы остановить такое поведение, надо разрешить в Drony устанавливать прямое соединение для приложения SandroProxy. Таким образом, запросы SandroProxy не будут проксироваться Drony и ошибка возникать не будет.

Для этого на вкладке Settings Drony ищем Filter → Edit filter rules → нажимаем на + → выставляем значения Network ID: all networks, Action: Direct, Application: выбираем SandroProxy в списке. Все остальные поля оставляем пустыми и сохраняем. После этого перезапускаем Drony.

Сама магия

Далее включаем Drony и смотрим, чтобы в логе не было ошибок. SandroProxy уже должен быть включен.

Drony

Если в логах есть что-то такое:

VK Messenger < - > 87.240.137.130:443

ConnectionHandler got an error:

java.net.ConnectException: failed to connect to localhost/127.0.0.1 (port 8008) > from /127.0.0.1 (port 48495)

after 30000ms: isConnected failed: ECONNREFUSED

(Connection refused)

Значит, не удается соединиться с SandroProxy, и стоит копать в эту сторону. Такая ошибка может возникать, если сначала был включен Drony, а потом - SandroProxy, поэтому запускать их надо в обратном порядке.

Теперь возвращаемся в SandroProxy.

Как создать breakpoints

В приложении есть такая вкладка, как Apps - местный аналог breakpoint'ов. Оно ловит соединения (можно настроить http/https/extra) у заданных приложений. Советую выбирать только нужные приложения, если не хотите вручную обрабатывать кучу фоновых запросов от системы (ну а если вам не лень, то смело ставьте галочки в All).

Для примера будем ломать сайт https://eth0.me - сайт показывает IP-адрес клиента.

Будем перехватывать запросы из Chrome. Выбираем приложение и ставим нужные галочки.

SandroProxy

Теперь идем в Chrome и открываем тестовый сайт. Для примера я буду использовать https://eth0.me - сайт возвращает IP-адрес клиента plaintext'ом. Если сделали все правильно, сайт зависнет (так же, как и в Charles), пока вы не пропустите запрос вручную.

Вот так выглядит окно request'а:

Request in proxy

Вот так - окно response'а: Response in proxy

Заменим текст на наш собственный.

Editing response

Сохраним response (и еще пропустить запрос favicon.ico, чтобы страница запустилась), и - вуаля!

Final screenshot


Вместо заключения

Понятно, что такой инструмент не позволит полностью обойтись без Charles при тестировании безопасности веб-сервисов. Однако это точно поможет быстро проверить запросы/ответы к серверу и провести минимальные проверки, находясь в любой точке мира без компьютера.

Comments to this post are disabled