Простой веб-сервер на Дельфи или компонент idHTTPServer, описание и применение. Целью данной статьи было описание возможностей и указание примеров использования INDY-компонента idHTTPServer в Дельфи. К статье прилагается прокомментированный исходный код и демонстрационное приложение. Скачать можно здесь. Статья рассчитана на читателей, знакомых с технологией Web и освоивших среду разработки приложений Дельфи на начальном уровне. Некоторые термины: INDY – Internet Dyrect, набор компонентов для Дельфи, ориентированный преимущественно на работу с сетевыми функциями. idHTTPServer – INDY компонент, предназначенный для построения HTTP-сервера. Поставленная для разбора задача – ПО «Sample HTTPServer» (или SHTTPS) должно предоставлять следующие возможности: передавать запрошенные страницы, как полноценный веб-сервер; запрашивать пароль на доступ при необходимости; иметь страницу управления. Создание основы приложения: формы и её элементов. Для выполнения задачи потребуется всего одна форма. И следующие поля ввода на ней: для задания порта, имя пользователя, пароль пользователя, путь к папке проекта и его индексу, название страницы управления, имя администратора, пароль администратора. Также нужны два чекбокса для: вклбчения/выключения авторизации и страницы управления. Для вызова диалога обзора и открытия файлов поставим кнопку. И ещё две: для запуска сервера и для завершения работы приложения. Подписи к элементам управления (Label’ы) ставим по усмотрению. Затем положим на форму компонент idHTTPServer, находящийся на вкладке компонентов INDY Servers. Другие, требующиеся нам не визуальные компоненты, это Timer и OpenDialog. Программирование приложения. Фактически, вся работа будет связана с событием IdHTTPServer1CommandGet ( AThread: TIdPeerThread; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo ). Где нужные нам параметры – ARequestInfo и AResponseInfo. Состав структуры ARequestInfo: Code: TIdHTTPRequestInfo = class(TIdRequestHeaderInfo) protected FAuthExists: Boolean; FCookies: TIdServerCookies; FParams: TStrings; FPostStream: TStream; FRawHTTPCommand: string; FRemoteIP: string; FSession: TIdHTTPSession; FDocument: string; FCommand: string; FVersion: string; FAuthUsername: string; FAuthPassword: string; FUnparsedParams: string; FQueryParams: string; FFormParams: string; procedure DecodeAndSetParams(const AValue: String); public constructor Create; override; destructor Destroy; override; property Session: TIdHTTPSession read FSession; property AuthExists: Boolean read FAuthExists; property AuthPassword: string read FAuthPassword; property AuthUsername: string read FAuthUsername; property Command: string read FCommand; property Cookies: TIdServerCookies read FCookies; property Document: string read FDocument write FDocument property Params: TStrings read FParams; property PostStream: TStream read FPostStream write FPostStream; property RawHTTPCommand: string read FRawHTTPCommand; property RemoteIP: String read FRemoteIP; property UnparsedParams: string read FUnparsedParams write FUnparsedParams; property FormParams: string read FFormParams write FFormParams; property QueryParams: string read FQueryParams write FQueryParams; property Version: string read FVersion; end; Состав структуры AResponseInfo: Code: TIdHTTPResponseInfo = class(TIdResponseHeaderInfo) protected FAuthRealm: string; FContentType: string; FConnection: TIdTCPServerConnection; FResponseNo: Integer; FCookies: TIdServerCookies; FContentStream: TStream; FContentText: string; FCloseConnection: Boolean; FFreeContentStream: Boolean; FHeaderHasBeenWritten: Boolean; FResponseText: string; FSession: TIdHTTPSession; FServerSoftware: string; procedure ReleaseContentStream; procedure SetCookies(const AValue: TIdServerCookies); procedure SetHeaders; override; procedure SetResponseNo(const AValue: Integer); procedure SetCloseConnection(const Value: Boolean); public procedure CloseSession; constructor Create(AConnection: TIdTCPServerConnection); reintroduce; destructor Destroy; override; procedure Redirect(const AURL: string); procedure WriteHeader; procedure WriteContent; property AuthRealm: string read FAuthRealm write FAuthRealm; property CloseConnection: Boolean read FCloseConnection write SetCloseConnection; property ContentStream: TStream read FContentStream write FContentStream; property ContentText: string read FContentText write FContentText; property Cookies: TIdServerCookies read FCookies write SetCookies; property FreeContentStream: Boolean read FFreeContentStream write FFreeContentStream; property HeaderHasBeenWritten: Boolean read FHeaderHasBeenWritten write FHeaderHasBeenWritten; property ResponseNo: Integer read FResponseNo write SetResponseNo; property ResponseText: String read FResponseText write FResponseText; property ServerSoftware: string read FServerSoftware write FServerSoftware; property Session: TIdHTTPSession read FSession; end; Для того чтобы был запрос ввода пароля, когда нам это нужно, на событие onCommandGet, сразу после описания процедуры (т.е. перед begin) ставим следующее: Code: procedure AuthFailed; begin AResponseInfo.AuthRealm :='Авторизация на SHTTPS:'; end; Смотрим: в структуре AResponseInfo AuthRealm предназначен для запроса авторизации с текстом, ему присвоенным. Сразу после begin ставим AResponseInfo.Server : = 'версия сервера' ; AResponseInfo . CacheControl : = 'no-cache' ; Это задаст версию сервера и укажет браузеру не кэшировать документы с сервера. Потом проверяем состояние чекбокса для авторизации (нужна/нет). Если нужна, то проверка: (ARequestInfo.AuthUsername <> ‘имя_пользователя’) or (ARequestInfo.AuthPassword <> ‘пароль’). В случае непрохождения её вызов AuthFailed. После просто обрабатываем введённый адрес, находящийся в ARequestInfo.Document (см. структуру ARequestInfo). При запросе “/” показываем индексный файл. А при запросе вида “/1/file.htm” отдаём файл 1/file.htm. Для передачи файла используем AResponseInfo.ContentStream := TFileStream.Create (‘filename’,fmOpenRead). При запросе страницы управления в нашем случае отдаём не файл с диска, а html-код, непосредственно генерирующийся здесь. Потому что нужно получить и показать в полях ввода страницы управления их текущие значения. Страница управления будет похожа видом на форму сервера. Часть её исходного кода шаблонна и будет задана фрагментами в Resourcestring, откуда эти фрагменты будут вставляться в ContentText (AResponseInfo) вперемежку с иными вставками. Получается, что в html-странице управления будет форма и поля ввода. При отправке, их значения методом POST будут направлены серверу. Считывать их на сервере можно из структуры ARequestInfo, в которой они есть Params.values. Полностью обращаться: ARequestInfo.Params.Values['имя_элемента']. Запуск сервера производится так: idHTTPServer1.DefaultPort := #порта; idHTTPServer1.Active:=true; (Порт указываем именно перед запуском). Для остановки сервера через страницу управления нужен таймер, по которому выполнится Application.Terminate. Напрямую вызвать в ходе IdHTTPServer1CommandGet завершение приложения нельзя, следует делать активным таймер. Заключение. Для разработки ПО Sample HTTPServer использовалась среда Дельфи 7.0, упаковщик исполняемых файлов UPX 1.95. Весь код данного ПО, кроме автокода модулей Дельфи и структур ARequestInfo, AResponseInfo, взятых из исходного кода SvrHTTPIndy.pas был написан автором. Сама статья и ПО были созданы в учебных целях, а также, как основа будующей статьи, посвящённой созданию программы-сервера удалённого администрирования на основе idHTTPServer, без отдельного клиента (управление по http). ПО предложено только для сопровождения статьи и его использование в качестве сервера неактуально, но возможно. Статью (как и исходный код) можно дополнять, переопубликовывать, ссылаясь на первоисточник, при этом критика ожидаема и желательна. __________________________ Думаю важное и нужное дополнение: полезные ссылки по тематике INDY HTTP. 1. Веб-сервер своими руками 2. SeverMain.pas 3. Веб-сервер своими руками (2) 4. idHttp Server 5. INDY - Internet Direct (komponenty otwarte) Замечу, что в структурах ARequestInfo и AResponseInfo много прочих полезных параметров и создание полноценного веб-сервера на Delphi, применяя INDY действительно возможно и быстро.
Статья шикарная. Но прошу объяснить новичку, для чего может понадобиться создавать руками такой сервер? Примеры хотелось бы... потому что есть ведь Денвер, или Апач. А вот такой самодельный сервер - это наверное более гибко. Но какие варианты применения?
Так говорят те кто вообще ничего не шарит в технологиях! Плюсы очевидны: безопасность - всё в одном, можно закодить как тебе удобно а не так как кто-то до тебя сделал! Минусы: Apache+PHP+MySQL - скорость, память, безопасность + настройка!