mirror of
https://github.com/Doczom/simple-httpd.git
synced 2025-09-21 02:50:09 +02:00
- Added support for uploading a configuration file over a long path - Added support for special uri paths (using the "*" symbol) in the configuration for groups of similar uri paths - Added the function of reading the contents of an http request - Changed the format of the uri address in the configuration file - Added a request redirection module - Added a module for blocking access to files by url path - Updated documentation - Updated module examples
339 lines
32 KiB
HTML
339 lines
32 KiB
HTML
<html>
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta lang="ru">
|
||
<title>Simple-httpd</title>
|
||
<style>
|
||
code {
|
||
background-color: #babfc766;
|
||
}
|
||
.menu {
|
||
background-color: aliceblue;
|
||
border: 1px solid black;
|
||
width: 40%;
|
||
margin-left: 20pt;
|
||
}
|
||
h1 {
|
||
text-align: center;
|
||
}
|
||
h3 {
|
||
margin-left: 20pt;
|
||
}
|
||
.menu-header {
|
||
margin-left: 20pt;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<h1>Simple-httpd</h1>
|
||
|
||
<div class="menu">
|
||
<h2 class="menu-header">Оглавление:</h2>
|
||
<ul>
|
||
<li><a href="#about">Описание программы и её возможностей</a></li>
|
||
<li><a href="#install">Установка и настройка</a></li>
|
||
<li><a href="#api">Документация на API модулей</a></li>
|
||
<ul>
|
||
<li><a href="#api.response">Создание ответа на запрос</a></li>
|
||
<li><a href="#api.request">Обработка данных запроса</a></li>
|
||
<li><a href="#api.file">Работа с файлами</a></li>
|
||
<li><a href="#api.control">Управление сервером</a></li>
|
||
<li><a href="#api.other">Дополнительные функции и возможности</a></li>
|
||
</ul>
|
||
<li><a href="#other-soft">Дополнительные программы и средства </a>
|
||
<ul>
|
||
<li><a href="#MIME-macro">Генерация файла MIME типов</a></li>
|
||
<li><a href="#redirect">Модуль перенаправления запросов</a></li>
|
||
<li><a href="#block_access">Модуль блокировки доступа к файлам</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#Bugs">Известные баги и особенности</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<hr>
|
||
<!-- Описание -->
|
||
<h2 id="about">Описание программы и её возможностей</h2>
|
||
<p>
|
||
Simple-httpd - это небольшой http сервер для Колибри ОС, позволяющий размещать файлы, создавать
|
||
динамические сайты и различные сетевые ресурсы.
|
||
|
||
</p>
|
||
<!-- Установка -->
|
||
<hr>
|
||
<h2 id="install">Установка и настройка</h2>
|
||
<p>
|
||
Для упрощения установки в репозитории находится директория bin, которая представляет из себя сервер, файл конфигурации и
|
||
некоторое количество демонстрационных модулей. Файл конфигурации в этой директории рассчитан на то, что сервер будет размещён
|
||
в корне раздела "/usbhd0/3/".
|
||
</p>
|
||
<p>
|
||
Дальнейшая настройка содержимого директории зависит от значений в файле httpd.ini .
|
||
</p>
|
||
<p><b>Примечание:</b> Файл должен использовать кодировку UTF-8. Другие кодировки могут привести к неправильной работе сервера.</p>
|
||
<p>
|
||
В файле конфигурации можно выделяются 3 основных раздела:
|
||
<ol>
|
||
<li>
|
||
<code>[MAIN]</code>
|
||
<p> Данный раздел содержит в себе базовые элементы конфигурации, такие как:</p>
|
||
<ul>
|
||
<li><code>ip</code><p> IPv4 адрес, на котором будет работать сервер. Параметр обязателен для заполнения </p></li>
|
||
<li><code>port</code><p> Порт подключения к серверу. При отсутствии параметра используется порт 80</p></li>
|
||
<li><code>conn</code><p> Максимальное количество открытых соединений. При отсутствии параметра используется значение 10</p></li>
|
||
<li><code>work_dir</code><p> Директория для размещения статичных файлов сервера, является корнем для uri путей. Параметр обязателен для заполнения </p></li>
|
||
<li><code>mime_file</code><p> Путь до файла сопоставления mime типов. Если параметр не указан используется встроенная таблица соответствия.</p></li>
|
||
<li><code>modules_dir</code><p> Директория, относительно которой в разделе [MODULES] указываются модули расширения.</p></li>
|
||
<li><code></code><p> </p></li>
|
||
</ul>
|
||
<p><b>Примечание:</b> В качестве modules_dir могут использоватьбся только ASCII символы.</p>
|
||
</li>
|
||
<li>
|
||
<code>[MODULES]</code>
|
||
<p> Данный раздел может содержать множество элементов, представленных в виде: <br>
|
||
<code>uri_path=file_name;cmdline</code> , где </p>
|
||
<ul>
|
||
<li><b>uri_path</b> - uri путь ресурса с начальным символом "/" </li>
|
||
<li><b>file_name</b> - путь к файлу модуля, относительно "modules_dir"</li>
|
||
<li><b>cmdline</b> - Строка передаваемая модулю во время инициализации каждого ресурса, ассоциированного с ним</li>
|
||
</ul>
|
||
<p>
|
||
<b>Особенности работы:</b> каждый модуль добавляется последовательно и поиск нужного модуля также производится последовательно. Из-за этой особенности нужно учитывать расположение uri в данной секции.
|
||
Для того, чтобы uri модуля сравнивался с путём в запросе раньше всех остальных он должен находится в самом конце списка, чтобы
|
||
</p>
|
||
<p><b>Примечание:</b> В качестве uri_path и cmdline может использоваться строка в UTF-8 с любыми символами, но путь к модулю
|
||
всегда должен использовать только ASCII символы и не использовать символ ",". Кодировка cmdline не стандартизированна, но желательно использовать
|
||
ASCII символы и проверять какую кодировку поддерживает модуль.</p>
|
||
<p> Сервер имеет возможность установить модуль для некоторого диапазона uri путей, для этого используется символ "*", обозначающий неопределённое количество(включая ноль) любых символов.
|
||
Например: При наличии записи <code>/img/*=img_module.obj</code> в секции модулей, сервер будет вызывать модуль для любых uri путей, имеющих в начале "/img/".
|
||
Также для установки модуля на все возможные uri пути необходимо прописать соответствие модуля с путём "/*".
|
||
</p>
|
||
<p> Другие примеры:
|
||
<code>*.lua=lua_module.obj</code> Любой путь, имеющий в конце ".lua".<br>
|
||
<code>*/.*=err401.obj</code> Любой путь, имеющий в названии директорию, начинающуюся с символа ".".<br>
|
||
</p>
|
||
</li>
|
||
<li><code>[TLS]</code>
|
||
<p><b>ВНИМАНИЕ!!! TLS шифрование на данный момент не поддерживается сервером</b></p>
|
||
<p>Данный раздел содержит необходимые данные для использования TLS сервером. Все поля обязательны для заполнения.</p>
|
||
<ul>
|
||
<li><code>mbedtls</code><p> Полный путь до библиотеки MbedTLS.</p></li>
|
||
<li><code>ca_cer</code><p> Полный путь до файла корневого сертификата.</p></li>
|
||
<li><code>srv_crt</code><p> Полный путь до файла сертификата сервера.</p></li>
|
||
<li><code>srv_key</code><p> Полный путь до файла содержащего секретный ключ сервера</p></li>
|
||
</ul>
|
||
<p>Если сервер находит этот раздел, то он автоматически предполагает использоваться в режиме HTTPS сервера. Переход в
|
||
этот режим будет использовать TLS для получения и отправки http данных, при этом порт подключения всё равно выбирается
|
||
полем port в разделе [MAIN]. Если порт не задан, то в качестве стандартного порта будет выбран порт 443.</p>
|
||
<p>Сервер одновременно может функционировать только в одном режиме, либо полностью использовать TLS, либо полностью не
|
||
использовать. Это необходимо для предотвращения использования модулей, опирающихся на шифрование HTTPS протокола,
|
||
в незащищённой среде передачи данных.</p>
|
||
</li>
|
||
</ol>
|
||
</p>
|
||
|
||
<!-- АПИ модулей -->
|
||
<hr>
|
||
<h2 id="api">Документация на API модулей</h2>
|
||
<p>
|
||
Модули сервера позволяют обрабатывать запросы и отправлять отправлять ответ, в том числе и формируемый динамически.
|
||
По своей структуре, модуль является обычной динамической библиотекой, экспортирующей 3 специальные функции:
|
||
</p>
|
||
<ol>
|
||
<li><code>uint32_t __stdcall httpd_init(IMPORT_DATA* import, char* cmdline, char* uri_path)</code>
|
||
<p> Функция для инициализации ресурса(uri_path), ассоциированного с модулем .
|
||
В файле конфигурации для каждого ресурса можно добавить командную строку, передаваемую в эту функцию. Например
|
||
|
||
<code> test3=test_unit4.obj; -database="file.sqlite" </code>
|
||
|
||
Для большей совместимости рекомендуется обрабатывать эту командную строку в кодировке UTF-8.
|
||
</p>
|
||
<p>
|
||
При успешной инициализации функция должна вернуть ненулевое значение, если же инициализация прошла неуспешно, то должен возвращаться ноль.
|
||
</p>
|
||
<p> Также для дальнейшей работы модуля предаётся указатель на таблицу экспортируемых сервером функций.</p>
|
||
</li>
|
||
<li><code>void __stdcall httpd_serv(CONNECT_DATA* request_data, uint32_t pdata)</code>
|
||
<p>
|
||
Данная функция вызывается сервером при получении запроса на ресурс(uri_path) ассоциированным с модулем . Для обеспечения работы сервер передаёт
|
||
в функцию уникальное значение, которое вернула функция "httpd_init" и указатель на структуру контекста запроса.
|
||
</p>
|
||
<p> В этой функции модуль производит обработку запроса используя экспортируемые сервером функции и прямой доступ к некоторым полями структуры контекста.
|
||
Эти имеющиеся возможности позволяют реализовать максимально гибкую обработку запросов, в том числе для протоколов, производных от http, например RTSP.
|
||
</p>
|
||
</li>
|
||
<li><code>void __stdcall httpd_close(uint32_t pdata)</code>
|
||
<p> Функция вызывается сервером при завершении работы и необходима для правильности завершения обработки запросов в
|
||
модулях и сохранения различных временных данных, если это необходимо. В функцию передаётся уникальное значение,
|
||
возвращённое функцией "httpd_init".</p>
|
||
<p> Завершение работы сервера производится вызовом экспортируемой функции "close_server".</p>
|
||
<p> Алгоритм завершения работы модулей и самого сервера заключается в том, что сервер блокирует все новые запросы на
|
||
подключение и вызывает функцию "httpd_close", для того чтобы модули завершили все открытые запросы и сохранили свои
|
||
данные. После завершения всех модулей сервер полностью завершает свою работу.</p>
|
||
</li>
|
||
</ol>
|
||
<h3 id="api.response">Создание ответа на запрос</h3>
|
||
<p> Любой запрос так или иначе требует ответа со стороны модуля. Этот ответ можно отправить используя экспортируемые ядром функции,
|
||
позволяющие создать экземпляр класса RESPD и через него производить отправку ответа на запрос.
|
||
</p>
|
||
<p>Далее будут перечислены некоторые функции для данного класса. Для полного ознакомления с функциями следует ознакомиться с примерами в директории example и файлом modules_api.inc в репозитории проекта.</p>
|
||
<ul>
|
||
<li><code>RESPD* __stdcall create_resp(CONNECT_DATA* session, uint32_t flags);</code>
|
||
<p> Функция создаёт объект RESPD, который имеет базовые настройки:</p>
|
||
<table border="1">
|
||
<thead>
|
||
<tr><th>Параметр</th><th>Значение</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr><td>Статус ответа</td><td>"200"</td> </tr>
|
||
<tr><td>Версия протокола</td><td>"HTTP/1.1"</td></tr>
|
||
<tr><td>Content-type</td><td>"text/html"</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p> Также разработчик может указать битовые флаги конфигурации ответа, например следующие:</p>
|
||
<ul>
|
||
<li><code>FLAG_TRANSFER_CHUNKED</code>
|
||
<p>Этот флаг выбирает "chunked" тип передачи данных с сервера к клиенту, что позволяет отправлять данные
|
||
неограниченной или неизвестной длины. </p></li>
|
||
<li><code>FLAG_RAW_STREAM</code>
|
||
<p>Этот флаг позволяет отправлять тело ответа небольшими пакетами, что можно использовать потоковую передачу
|
||
данных поверх http протокола, например для реализации интернет радио</p></li>
|
||
<li><code>FLAG_NO_CACHE_CONTROL</code>
|
||
<p>Этот флаг указывает, что в ответе не будет дефолтного заголовка "Cache-Control"</p></li>
|
||
<li><code>FLAG_KEEP_ALIVE</code>
|
||
<p>Этот флаг указывает, что в ответе будет дефолтный заголовок "Connection: keep-alive"</p></li>
|
||
</ul>
|
||
</li>
|
||
<li><code>void __stdcall destruct_resp(RESPD* ptr);</code>
|
||
<p>Функция производит удаление объекта RESPD.</p>
|
||
</li>
|
||
<li><code>void __stdcall set_http_status(RESPD* ptr, uint32_t status); </code>
|
||
<p>Функция производит изменение статуса ответа. Статус записывается в виде строки вида "201 " упакованной в dword(0x20313032).</p>
|
||
</li>
|
||
<li><code>void __stdcall set_http_ver(RESPD* ptr, char* version, uint32_t length);</code>
|
||
<p>Функция производит изменение версии, отправляемой в ответе. Версия должна иметь вид строки, например "RTSP/1.1"</p>
|
||
</li>
|
||
<li><code>uint32_t __stdcall add_http_header(RESPD* ptr, char* ptr_header, uint32_t length);</code>
|
||
<p>Функция производит добавление новых заголовков в виде стоки. Функция не производит проверки содержимого строки.</p>
|
||
</li>
|
||
<li><code>uint32_t __stdcall del_http_header(RESPD* ptr, char* ptr_header);</code>
|
||
<p>Функция производит удаление дополнительного заголовка. Память под строку никак не изменяется.</p>
|
||
</li>
|
||
<li><code>uint32_t __stdcall begin_send_resp(RESPD* ptr, uint64_t content_length); </code>
|
||
<p>Функция производит отправку HTTP строки статуса и заголовков для флагов FLAG_TRANSFER_CHUNKED и FLAG_RAW_STREAM.</p>
|
||
</li>
|
||
<li><code>uint32_t __stdcall send_resp(RESPD* ptr, char* content, uint32_t length); </code>
|
||
<p>Функция производит отправку http ответа целиком или его части для флагов FLAG_TRANSFER_CHUNKED и FLAG_RAW_STREAM .</p>
|
||
</li>
|
||
<li><code>uint32_t __stdcall finish_send_resp(RESPD* ptr);</code>
|
||
<p>Функция производит завершение отправки данных для флагов FLAG_TRANSFER_CHUNKED</p>
|
||
</li>
|
||
</ul>
|
||
<p>В использовании функций добавления дополнительных заголовков и изменения версии есть особенность: строки должны существовать
|
||
до момента деструктуризации объекта RESPD. Также модуль сам должен отслеживать и освобождать память под эти строки.
|
||
</p>
|
||
<h3 id="api.request">Обработка данных запроса </h3>
|
||
<ul>
|
||
<li><code>char* __stdcall find_uri_arg(CONNECT_DATA* session, char* key); </code>
|
||
<p>Функция производит поиск аргумента uri строки по его названию. Если аргумент найден, то возвращается указатель на
|
||
строку с его значением, иначе ноль</p>
|
||
</li>
|
||
<li><code>char* __stdcall find_header(CONNECT_DATA* session, char* key);</code>
|
||
<p>Функция производит поиск http заголовка по его названию. Если аргумент найден, то возвращается указатель на
|
||
строку с его значением, иначе ноль</p>
|
||
</li>
|
||
<li><code>uint32_t __stdcall read_http_body(CONNECT_DATA* session, char* buff, uint32_t len);</code>
|
||
<p>Функция производит чтение части содержимого http запроса в буфер и возвращает количество прочитанных байт.
|
||
В случае ошибки сервер вернёт значение -1</p>
|
||
</li>
|
||
<p>Для получения остальной информации, такой как: метод запроса, версии протокола и фрагмент uri строки
|
||
используется доступ к структуре CONNECT_DATA. Описание этой структуры есть в файле modules_api.inc репозитория.</p>
|
||
</ul>
|
||
<h3 id="api.file">Работа с файлами</h3>
|
||
<ul>
|
||
<li><code>void __stdcall FileInitFILED(FILED* buffer, char* path);</code>
|
||
<p> Функция производит инициализацию структуры FILED для её использования в файловых операциях.</p>
|
||
</li>
|
||
<li><code>FS_STATUS __stdcall FileInfo(char* path, void* buffer);</code>
|
||
<p> Функция производит чтение информации о файле в буфер по его пути и возвращает код ответа файловой системы.
|
||
Если возвращён 0 - операция выполнена успешно, иначе возникла ошибка.
|
||
</p>
|
||
</li>
|
||
<li><code>uint32_t __stdcall FileRead(FILED* file, void* buffer, uint32_t size);</code>
|
||
<p> Функция производит чтение части файла и автоматически увеличивает смещение чтение на количество прочитанных байт.
|
||
По завершению чтения функция вернёт количество прочитанных байт в буфер, при ошибках чтение это значение равно нулю.
|
||
</p>
|
||
</li>
|
||
<li><code>void __stdcall FileSetOffset(FILED* file, uint64_t offset);</code>
|
||
<p> Функция изменяет смещения чтения из файла. </p>
|
||
</li>
|
||
<li><code>uint32_t __stdcall FileReadOfName(char* path, void* buffer, uint32_t size)</code>
|
||
<p> Функция производит чтение файла по его названию начиная с нулевого смещения. Может использоваться для работы с небольшими
|
||
файлами с различными настройками модуля. Функция возвращает количество прочитанных байт, если же возвращён 0, то вероятно
|
||
произошла ошибка чтения.
|
||
</p>
|
||
</li>
|
||
</ul>
|
||
<p><b>Примечание:</b> Все пути на файл или директорию должны быть в кодировке UTF-8 или совместимой с ней ASCII.
|
||
Строки должны использовать Null-турминатор. Кодировки UTF-16LE, cp866, cp1251 и тд нельзя использовать.</p>
|
||
<h3 id="api.control">Управление сервером</h3>
|
||
<code>void close_server();</code>
|
||
<p> Функция производит завершение работы всех модулей, и основного потока этого сервера. На время завершения работы модулей сервер
|
||
блокирует все новые подключения, позволяя модулям завершить открытые соединения.
|
||
</p>
|
||
|
||
<h3 id="api.other">Дополнительные функции и возможности</h3>
|
||
<code>char* __stdcall Get_MIME_Type(FILED* fd);</code>
|
||
<p> Функция производит анализ названия файла по его структуре FILED и возвращает MIME тип, соответствующий расширению файла.
|
||
Данные о MIME типах берутся из встроенной таблицы соответствий либо из дополнительно загружаемого <a href="#MIME-macro">файла</a>.
|
||
</p>
|
||
|
||
<!-- Дополнительные средства -->
|
||
<hr>
|
||
<h2 id="other-soft">Дополнительные программы и средства</h2>
|
||
<h3 id="MIME-macro">Генератор файла MIME типов</h3>
|
||
<p>Хоть сервер и имеет встроенную таблицу сопоставления расширения файла и MIME типа, но этого недостаточно. По этой причине
|
||
у сервера есть возможность загружать внешний файл с такой таблицей. Для генерации этого файла был создан макрос для fasm,
|
||
позволяющий в удобном виде создать такой файл и указать все необходимые MIME типы.
|
||
</p>
|
||
<p> Файл с расширенными MIME типами находится в репозитории в директории "utils" в этом же файле написан сам макрос.
|
||
Последовательность передаваемых параметров в макрос следующая:
|
||
<ol>
|
||
<li>Строка с MIME типом, который должен использоваться если не один другой тип не подходит</li>
|
||
<li>Неопределённое количество последовательно идущих пар аргументов: сначала строка с расширением, например ".pdf",
|
||
а после неё строка с MIME типом.
|
||
</li>
|
||
</ol>
|
||
</p>
|
||
<h3 id="redirect">Модуль перенаправления запросов</h3>
|
||
<p>
|
||
При эксплуатации сервера может потребоваться возможность перенаправить запросы на какой-либо определённый файл(например на index.html) или модуль. Для данных целей к серверу был создан модуль "redirect.obj", позволяющий огранизовать перенаправление на определённые ресурсы как в пределах сервера, так и на внешние ресурсы. Для использования модуля необходимо задать модуль для всех необходимых uri путей и прописать для каждого такого uri командную строку, содержащую либо полный путь к ресурсу на этом сервере, либо полную uri ссылку. Пример использования:
|
||
</p>
|
||
<code>/=redirect.obj, /docs/index.htm</code> <p> перенаправление запросов на главную страницу сервера из корня.</p>
|
||
|
||
<h3 id="block_access">Модуль блокировки доступа к файлам </h3>
|
||
<p>
|
||
При работе сервера, модули могут создавать различные "системные" файлы, например логи, к которым должен быть заблокирован доступ из запросов клиентов. Для этих целей к серверу был создан модуль "block_access.obj", позволяющий задать http код статуса и короткое сообщение в теле ответа сервера. Для использования необходимо связать модуль с uri путём и задать строку параметров: код статуса ответа и, через пробел, короткое сообщение. Пример использования:
|
||
</p>
|
||
<code>*/.*=block_access.obj, 400 access error</code> <p>Блокировка доступа к файлам и дерикториям начинающимся с символа "." .</p>
|
||
<p>Также можно не указывать текстовое сообщение, тогда сервер отправит только http статус. Если не указывать никаких параметров, то сервер будет по умолчанию отправлять код "403".</p>
|
||
|
||
<!-- Баги -->
|
||
<hr>
|
||
<h2 id="Bugs">Известные баги и особенности</h2>
|
||
<ol>
|
||
<li>Сетевой стек нестабилен и что-то может пойти не так.</li>
|
||
<li>При отправки больших объёмов данных может быть утеря или изменение порядка пакетов</li>
|
||
<li>Отсутствует поддержка частичных http запросов</li>
|
||
<li>Сервер не рассчитан на большие нагрузки</li>
|
||
<li>Отсутствует поддержка TLS</li>
|
||
</ol>
|
||
|
||
<!-- Авторы -->
|
||
<hr>
|
||
<footer id="Autor">
|
||
<p>Автор: Махаил Фролов aka Doczom</p>
|
||
</footer>
|
||
|
||
</body>
|
||
</html> |