Logo    
Деловая газета CitCity.ru CITKIT.ru - все об Open Source Форумы Все публикации Учебный центр Курилка
CitForum    CITForum на CD    Подписка на новости портала Море(!) аналитической информации! :: CITFORUM.RU
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

27.04.2017

Google
WWW CITForum.ru
С Новым годом!

2004 г.

Веб-сервер своими руками

Михаил Продан,,
Издательский Дом "КОМИЗДАТ"

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

Лирическое отступление

Когда мой сайт обитал на boom.ru, с отладкой все было в порядке: изменяешь в блокноте, переходишь в Оперу, жмешь F5 - и все изменения налицо. Но когда я начал переходить (и пока еще, правда, не перешел) на h10.ru с его возможностями PHP, Perl… - с отладкой начались проблемы. Как вам наверняка известно, PHP и Perl исполняются не на стороне браузера, а на стороне сервера. А поскольку Apache из диска "К + П" № 3 я так и не установил (мой CD-ROM приказал долго жить), была предпринята попытка написать собственный веб-сервер (естественно, на Delphi).

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

С чего начать

Начнем мы, как всегда, с запуска нашего Delphi. После появления формы перебросим из палитры компонентов TIdHTTPServer (который, по большому счету, и будет выполнять за нас всю грязную работу по соединению с клиентом и общению с ним). Нам же останется лишь переадресовывать запросы клиента на соответствующие файлы. Кроме того, я порекомендовал бы также перетащить на форму еще и TButton. И в его реакции на нажатие написать код запуска нашего сервера:

procedure TForm1.Button1Click (Sender: TObject);
begin
Self.IdHTTPServer1.Active:=True;
end;
, а в событие Form1.OnDestroy ():
procedure TForm1.FormDestroy (Sender: TObject);
begin
Self.IdHTTPServer1.Active:=False;
end;

Теперь поподробнее рассмотрим событие idHTTPServer.OnCommandGet, которое имеет тип:

TIdHTTPGetEvent = procedure (AThread: TIdPeerThread; 
  RequestInfo: TIdHTTPRequestInfo; ResponseInfo:
    TIdHTTPResponseInfo) of object; 

Где:

  • AThread - поток, который содержит информацию о подключении;
  • параметр RequestInfo содержит информацию о запрашиваемых данных;
  • ResponseInfo используется для передачи результата выполнения запроса.

Для проверки работоспособности нашего сервера создадим файл (Response.txt) примерно следующего содержания:

<html>
<head>
<title>Testing</title>
</head>
<body>
<h1>This is the test</h1>
</body>
</html>

А в обработчике события idHTTPServer1.OnCommandGet напишем такой код:

ResponseInfo.ContentStream:=TFileStream.Create 
('D:\Response.txt',fmOpenRead); 

Настройка браузера предельно проста - нужно всего лишь указать в настройках прокси-сервера название компьютера, на котором находится сервер, и соответствующий порт (я использую 800-й).

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

if RequestInfo.Host='www.test.com' then
begin
ResponseInfo.ContentStream:=TFileStream.Create (
'D:\Projects\HTMLProjects\MySite\'
  +RequestInfo.Document,fmOpenRead);
end;

Что мы здесь делаем:

  • во-первых, проверяем, какой хост запрашивает клиент;
  • если это www.test.com, то переадресовываем запрос на соответствующий файл, содержащийся в каталоге с полной копией нашего сайта (D:\Projects\HTMLProjects\MySite);
  • посылаем результат клиенту.

Теперь, если в поле браузера ввести строку www.test.com/index.html, мы увидим начальную страницу (если она называется index.html) нашего сайта - со всеми ссылками, рисунками, скриптами и аплетами.

CGI

Все это, конечно, хорошо - но что мы с этого имеем? Практически ничего - ведь точно такой же результат мы бы получили, если бы просто набрали в браузере адрес: D:\Projects\HTMLProjects\MySite\Index.html. И, естественно, тот аргумент, что www.test.com/index.html набирать быстрее, устроит не всех (вернее, всех не устроит). К счастью, разрабатываем сервер мы сами - значит, можем внедрять в него все, что нам угодно: Standalone CGI, WinCGI, ISAPI (NSAPI), Apache CGI, PHP, Perl, Python, MySQL…

В этой главе мы остановимся именно на разработке поддержки Standalone CGI.

Итак. StandaloneCGI - программа, работающая под DOS или Windows (и не только, можно и под Linux, только для этого придется перекомпилировать наш сервер), которая при запуске выдает в устройство стандартного вывода требующуюся информацию. Все необходимые параметры передаются ей посредством переменных окружения.

Принцип работы сервера с такими программами таков:

  • задать необходимые переменные окружения;
  • запустить программу;
  • перенаправить результат из стандартного вывода на другой объект (например, в файл);
  • закрытие программы: Закрывается автоматически после вывода всей информации;
  • передать содержимое созданного файла клиенту;
  • удалить файл.

Для того чтобы не засорять память ненужными переменными окружения, воспользуемся функцией запуска приложений CreateProcess, которая перед запуском приложения создает для него частное адресное пространство со своими переменными окружения, которое освобождается после завершения процесса.

Прототип этой функции выглядит так:

function CreateProcess (lpApplicationName: PChar;
  lpCommandLine: PChar;
lpProcessAttributes, lpThreadAttributes: 
  PSecurityAttributes;
bInheritHandles: BOOL; dwCreationFlags: DWORD; 
  lpEnvironment: Pointer;
lpCurrentDirectory: PChar; const lpStartupInfo:
  TStartupInfo;
var lpProcessInformation: TProcessInformation):
   BOOL; stdcall;

Где:

  • LpApplicationName:PChar - название приложения (плюс полный путь к нему);
  • LpCommandLine:PChar - командная строка приложения (все параметры, которые передаются приложению через командную строку);
  • LpProcessAttributes, lpThreadAttributes - в нашем случае NIL (подробнее об этих параметрах читайте Win32 help);
  • BInheritHandles:Bool - в наше случае False;
  • DwCreationFlags - CREATE_NEW_PROCESS_GROUP или DETACHED_PROCESS;
  • LpEnvirounment:Pointer - указатель на строку, которая содержит переменные окружения, необходимые нашей программе;
  • LpCurrentDirectory:PChar - рабочий каталог нашей программы;
  • LpStartupInfo:TStartupInfo - параметры запуска приложения;
  • LpProcessInformation:TProcessInformation - переменная, в которую помещаются все дескрипторы запущенного приложения.

Результат: True - если приложение нормально напустилось, и False - в противном случае.

Для переадресации устройства вывода воспользуемся параметром lpStartupInfo, который имеет следующую структуру (см. таблицу 1).

Таблица 1. Параметры функции CreateProcess
Параметр Описание
cb: DWORD; Размер данной структуры
lpReserved: Pointer; Зарезервировано
lpDesktop: Pointer; Для NT - указатель на строку, которая содержит название дисплея, на который выводится информация приложения (здесь не используется)
lpTitle: Pointer; Для консольных приложений - строка, которая отображается на панели задач
dwX: DWORD; X-координата приложения (нам она не нужна - 0)
dwY: DWORD; Y-координата приложения (нам она не нужна - 0)
dwXSize: DWORD; Ширина окна приложения (нам она не нужна - 0)
dwYSize: DWORD; Высота окна приложения (нам она не нужна - 0)
dwXCountChars: DWORD; Для консольных приложений задает ширину в "текстовых единицах" (для нас - 0)
dwYCountChars: DWORD; Для консольных приложений задает высоту в "текстовых единицах" (для нас - 0)
dwFillAttribute: DWORD; Задает сочетание цвета фона и цвета символа (это не для нас - опять 0)
dwFlags: DWORD; См. таблицу 2
wShowWindow: Word; Одна из констант SW_ - режим отображения приложения (это не для нас)
cbReserved2: Word; Зарезервировано
lpReserved2: PByte; Зарезервировано
hStdInput: THandle; Дескриптор стандартного ввода
hStdOutput: THandle; Дескриптор стандартного вывода
HStdError: THandle; Дескриптор стандартного устройства вывода ошибки
Таблица 2. Описание флагов запускаемого процесса
Значение Описание
STARTF_USESHOWWINDOW Если не задан, wShowWindow игнорируется
STARTF_USEPOSITION Если не задан,, dwX, dwY игнорируются
STARTF_USESIZE Если не задан dwXSize, dwYSize игнорируются
STARTF_USECOUNTCHARS Если не задан, dwXCountChars, dwYCountChars игнорируются
STARTF_USEFILLATTRIBUTE Если не задан, dwFillAttribute игнорируется
STARTF_FORCEONFEEDBACK Очень много написано, все равно не использую
STARTF_FORCEOFFFEEDBACK Очень много написано, все равно не использую
STARTF_USESTDHANDLES Если не задан, hStdInput, hStdOutput, hStdError не используются

Как же все это будет выглядеть в программе? Для начала приведу функцию, которая возвращает в параметре Result:TStringList значения переменных окружения:

procedure CreateServerVariables 
 (RequestInfo:TIdHttpRequestInfo;var
Result:TStringList);
begin
if not Assigned (Result) 
 then Result:=TStringList.Create;
Result.Add ('HTTP_HOST='+RequestInfo.Host);
Result.Add 
 ('REQUEST_METHOD='+RequestInfo.Command);
Result.Add ('URL='+RequestInfo.Document);
Result.Add 
 ('QUERY_STRING='+RequestInfo.UnparsedParams);
Result.Add ('REMOTE_ADDR='+RequestInfo.RemoteIP);
Result.Add 
 ('HTTP_ACCEPT='+RequestInfo.Headers.Values ['Accept']);
Result.Add 
 ('HTTP_USER_AGENT='+RequestInfo.Headers.Values
['User-Agent']);
Result.Add ('SERVER_PROTOCOL='+sServerProtocol);
Result.Add ('SERVER_SOFTWARE='+sServerSoftware);
end;

Но просто передать значения Result в CreateProcess нельзя - для этого используем еще одну сервисную функцию:

function FormEnv (Data:TStringList):String;
var i:integer;
begin
Result:='';
if Data<>nil then
begin
For i:=0 to Data.Count-1 do
Result:=Result+Data [i]+#0;
Result:=Result+#0;
end;
end;

Нам осталось сделать переадресацию со стандартного устройства вывода в наш файл и запустить приложение:

function RunCGI 
 (Command:PChar;Data:TStrings):PChar;
var FS:TFileStream;
SI:TStartupInfo;
PI:TProcessInformation;
SL:TStringList;
Env:Pointer;
EnvStr:String;
begin
Result:=PChar (sNoErrorNoResult);
FS:=TFilestream.Create (ExtractFileDir 
 (ParamStr
(0))+'\temp.html',fmCreate);
try
FillChar (SI,SizeOf (SI),0);
SI.cb:=SizeOf (SI);
SI.dwFlags:=STARTF_USESTDHANDLES;
SI.hStdOutput:=FS.Handle;
SI.hStdInput:=GetStdHandle 
 (STD_INPUT_HANDLE);
SI.hStdError:=GetStdHandle 
 (STD_ERROR_HANDLE);
EnvStr:=FormEnv (Data);
if not CreateProcess
(Command,'',nil,nil,False,
 CREATE_NEW_PROCESS_GROUP
or DETACHED_PROCESS,Pointer 
 (EnvStr),PChar (ExtractFileDir
(ParamStr (0))),SI,PI) then
Result:=PChar (sCGIStartError) else
begin
if WaitForSingleObject 
 (PI.hThread,5000)=WAIT_FAILED then
begin
Result:=PChar (sTimeoutError);
exit;
end;
SL:=TStringList.Create;
try
FS.Position:=0;
SL.LoadFromStream (FS);
Result:=PChar (SL.Text);
finally
SL.Free;
end;
end;
finally
FS.Free;
if FileExists (ExtractFileDir 
 (ParamStr (0))+'\temp.html') then
DeleteFile (ExtractFileDir 
 (ParamStr (0))+'\temp.html');
end;
end;

Порядок работы:

  • сначала мы создаем файл (temp.html), в который будем переадресовывать информацию из приложения, и обнуляем переменную SI;
  • заполняем необходимые поля SI;
  • заполняем строку с переменными окружения;
  • запускаем наш CGI;
  • ждем конца выполнения (5 с);
  • передаем результат выполнения в SL, а тот, в свою очередь,- в переменную Result;
  • удаляем файл temp.html.

После выполнения этой функции возвращаемое значение передаем в ResponseInfo.ContentText.

А как же PHP, Perl…

Возможно, кто-то из читателей посетует: "обещал же о PHP, о Perl рассказать…". Рассказываю. PHP и Perl, как и другие подобные вещи, создаются не для одного IIS или PWS, а для использования со многими серверами и на многих платформах. Для примера: стандартная поставка PHP включает в себя ActiveScript (то есть ActiveX), стандартные ISAPI, NSAPI, Apache и Apache2, а также Standalone CGI. Имеется, кроме того, и библиотека для JavaServlets.

Значит, для того чтобы научить наш сервер работать с PHP, надо, во-первых, скачать пакет PHP, прописать необходимые пути к нему в переменной PATH. В код сервера добавить фильтрацию по расширению запрашиваемого документа (php, php3, php4) и передать эти файлы в качестве параметров (вспомните параметр lpCommandLine) на обработку CGI'шке php.exe. Результат, как и прежде, следует вернуть в ContentText.

Размещение рекламы — тел. +7 495 4119920, ICQ 232284597

Подписка на новости IT-портала CITForum.ru
(библиотека, CITKIT.ru, CitCity)

Новые публикации:

24 декабря

CITKIT.ru:

  • Новогодние поздравления
  • Сергей Кузнецов. Цикл Операционные системы: Ностальгия по будущему:

  • Алексей Федорчук. OpenSolaris 2008.11 Release

  • Сергей Голубев:

  • Евгений Чайкин aka StraNNik (Блогометки):

    17 декабря

  • С.Д.Кузнецов. Базы данных. Вводный курс

    10 декабря

    CITKIT.ru:

  • OpenSolaris 2008.11 Release

  • Альтернативные ОС: две грустные истории (С.Кузнецов)
  • Nokia N810 — доведение до ума
  • CitCity:

  • Платформа 2009: заоблачные перспективы Microsoft

    4 декабря

  • Лекция С.Д.Кузнецова Понятие модели данных. Обзор разновидностей моделей данных

    CITKIT.ru:

  • OpenSolaris 2008.11 Release. Первые впечатления

  • Linux vs FreeBSD: продолжим "Священные войны"?

  • Nokia N810 as is

  • Индульгенция для FOSS

  • Друзья СПО'2008

    26 ноября

  • Нечеткое сравнение коллекций: семантический и алгоритмический аспекты

    CitCity:

    CITKIT.ru:

  • Глава из книги А.Федорчука
    Сага о FreeBSD:
  • 19 ноября

  • Проблемы экономики производства крупных программных продуктов

  • Язык модификации данных формата XML функциональными методами

    CITKIT.ru:

  • Главы из книги А.Федорчука
    Сага о FreeBSD:

    Заметки к книге:

  • FreeBSD: монтирование сменных устройств и механизм HAL
  • Текстовый редактор ee

    12 ноября

  • Правило пяти минут двадцать лет спустя, и как флэш-память изменяет правила (Гоц Грейф, перевод: Сергей Кузнецов)

    CITKIT.ru:

  • Главы из книги А.Федорчука
    Сага о FreeBSD:
  • OSS в России: взгляд правоведа (В.Житомирский)

  • Новая статья из цикла С.Голубева "Железный марш":

    29 октября

  • О некоторых задачах обратной инженерии

  • Веб-сервисы и Ruby

  • Тестирование web-приложений с помощью Ruby

    CITKIT.ru:

  • Главы из книги А.Федорчука
    Сага о FreeBSD:

  • PuppyRus Linux - беседа с разработчиком (С.Голубев)

  • Сергей Кузнецов. Заметка не про Linux

    22 октября

  • Обзор методов описания встраиваемой аппаратуры и построения инструментария кросс-разработки

    CITKIT.ru:

  • Сергей Кузнецов. Почему я равнодушен к Linux

  • Глава из книги А.Федорчука
    Сага о FreeBSD:
  • Что надо иметь
    3. Базовые познания

    CitCity:

  • Управление IT-инфраструктурой на основе продуктов Microsoft

    15 октября

  • Методы бикластеризации для анализа интернет-данных

    CitCity:

  • Разъемы на ноутбуках: что они дают и зачем их так много?
  • AMD Puma и Intel Centrino 2: кто лучше?

    CITKIT.ru:

  • Новый цикл статей С.Голубева
    Железный марш:

  • Главы из книги А.Федорчука
    Сага о FreeBSD:

    8 октября

  • Автоматизация тестирования web-приложений, основанных на скриптовых языках
  • Опыт применения технологии Azov для тестирования библиотеки Qt3

    Обзоры журнала Computer:

  • SOA с гарантией качества
  • Пикоджоуль ватт бережет
  • ICT и всемирное развитие

    CitCity:

  • Пиррова победа корпорации Microsoft

    CITKIT.ru:

  • Главы из книги А.Федорчука
    Сага о FreeBSD:

    Статья из архива:

  • Я живу в FreeBSD (Вадим Колонцов)

    Новые Блогометки:

  • Перекройка шаблона Blogger или N шагов к настоящему
  • Blogger. Comment style
  • Screenie или глянцевый снимок экрана

    2 октября

    CITKIT.ru:

  • Сага о FreeBSD (А. Федорчук)

    Zenwalk: пакет недели

  • Банинг — интеллектуальное развлечение (С.Голубев)

    CitCity:

    25 сентября

  • Клермонтский отчет об исследованиях в области баз данных

    CITKIT.ru:

  • Пользователям просьба не беспокоиться... (В.Попов)

  • Снова про ZFS: диск хорошо, а два лучше
  • Командная оболочка tcsh (А.Федорчук)

    Zenwalk: пакет недели

    17 сентября

  • T2C: технология автоматизированной разработки тестов базовой функциональности программных интерфейсов
  • Технология Azov автоматизации массового создания тестов работоспособности

    CITKIT.ru:

  • FreeBSD: ZFS vs UFS, и обе-две — против всех (А.Федорчук)

    Zenwalk: пакет недели

  • Дачнет — практика без теории (С.Голубев)

    10 сентября

  • За чем следить и чем управлять при работе приложений с Oracle
  • Планировщик заданий в Oracle
    (В.Пржиялковский)

    CITKIT.ru:

  • Microsoft: ответный "боян" (С.Голубев)

  • Причуды симбиоза, или снова "сделай сам" (В.Попов)

  • Файловые системы современного Linux'а: последнее тестирование
  • Zsh. Введение и обзор возможностей
    (А.Федорчук)

    Описания пакетов Zenwalk: Zsh, Thunar, Thunar-bulk-rename, Xfce4-places-plugin, Xfce4-fsguard-plugin

    Блогометки:

  • Google Chrome
  • Лончер для ASUS Eee PC 701

    3 сентября

    CITKIT.ru:

  • Заметки о ядре (А.Федорчук):

    Добавлены описания пакетов Zenwalk: Galculator, Screenshot, Gnumeric, Pidgin

    В дискуссинном клубе:

  • И еще о Википедии и Google Knol

  • Лекция для начинающего линуксоида (С.Голубев)

    26 августа

  • Транзакционная память (Пересказ: С. Кузнецов)

    CITKIT.ru:

  • Открыт новый проект Zenwalk: пакет недели

  • Статья Текстовые процессоры и их быстродействие: конец еще одной легенды?

    21 августа

    CITKIT.ru:

  • Почему школам следует использовать только свободные программы (Ричард Столлман)
  • Беседа Сергея Голубева с учителем В.В.Михайловым

  • Википедия или Гуглезнание? Приглашение к обсуждению (Алексей Федорчук)
  • Народная энциклопедия от Google (StraNNik)

  • Обзор Mandriva 2009.0 Beta 1 Thornicrofti
  • Новичок в Линукс: Оптимизируем Mandriva 2008.1

  • Книга Zenwalk. Приобщение к Linux:

    13 августа

    CitCity:

  • Мирный Atom на службе человеку. Обзор платы Intel D945GCLF с интегрированным процессором
  • Обзор процессоров Intel Atom 230 на ядре Diamondville

  • iPhone - год спустя. Скоро и в России?

    CITKIT.ru:

  • Интермедия 3.4. GRUB: установка и настройка (из книги Zenwalk. Приобщение к Linux)

    6 августа

  • СУБД с хранением данных по столбцами и по строкам: насколько они отличаются в действительности? (Пересказ: С. Кузнецов)

    CITKIT.ru:

  • Интермедия 2.2. Что неплохо знать для начала (из книги Zenwalk. Приобщение к Linux)

  • И снова про шрифты в Иксах (А.Федорчук)

  • 20 самых быстрых и простых оконных менеджеров для Linux

  • Дело о трех миллиардах (С.Голубев)

    30 июля

  • OLTP в Зазеркалье (Пересказ: С. Кузнецов)

    CitCity:

  • Будущее BI в облаках?
  • Тиражные приложения и заказная разработка. Преимущества для заказчика
  • Дискуссия со сторонниками заказной разработки

    CITKIT.ru:

  • Новые главы книги Zenwalk. Приобщение к Linux:
  • Глава 8. Пакеты: средства установки, системы управления, системы построения
  • Глава 9. Zenwalk: репозитории, пакеты, методы установки

    23 июля

    CITKIT.ru:

  • Все против всех. 64 vs 32, Intel vs AMD, tmpfs vs ext3
  • Две головы от Intel

  • Zenwalk: обзор штатных приложений (глава из книги "Zenwalk. Приобщение к Linux")

  • Нормально, Григорий...

    16 июля

    Обзоры журнала Computer:

  • Перспективы и проблемы программной инженерии в XXI веке
  • Большие хлопоты с большими объемами данных
  • Перспективы наноэлектроники

    CITKIT.ru:

  • Интермедия о лицензиях (А.Федорчук. "Zenwalk. Приобщение к Linux")

  • Есть ли будущее у KDE?

  • Linux в школе: альтернативный вариант в задачах

  • Шифр (приключения агента Никодима)

    10 июля

    CITKIT.ru:

  • Новые разделы книги А. Федорчука Zenwalk. Приобщение к Linux:
  • Интермедия вступительная. Linux или GNU/Linux? Как вас теперь называть?
  • Глава 5. Среда Xfce
  • Глава 6. Xfce: приложения и плагины

  • ZUR (Zenwalk User Repository) FAQ

    2 июля

  • Персистентность данных в объектно-ориентированных приложениях (С. Кузнецов)

    CITKIT.ru:

  • Новые разделы книги А. Федорчука Zenwalk. Приобщение к Linux:
  • Интермедия 1.2. Дорога к Zenwalk'у. Период бури и натиска
  • Интермедия 3.3. Немного о Linux'е и "железе"
  • Глава 4. Настройка: инструментами и руками
  • Интермедия 4.1. Zenpanel и конфиги: поиски корреляции

  • Интервью с Жан-Филиппом Гийоменом, создателем дистрибутива Zenwalk

  • Linux в школе: первые итоги (С. Голубев)

    25 июня

    CITKIT.ru:

  • Zenwalk. Приобщение к Linux (А. Федорчук)

  • Логика и риторика (С.Голубев)

  • Технология Tru64 AdvFS

  • Ханс Райзер предлагает отвести полицейских к телу Нины

    18 июня

  • Проекты по управлению данными в Google (Пересказ: С. Кузнецов)

    CITKIT.ru:

  • ОС и поддержка "железа": мифы и реальность (А. Федорчук)

  • Linux в школе: другие дистрибутивы

  • Пинок (С. Голубев)

    4 июня

  • Ландшафт области управления данными: аналитический обзор (С. Кузнецов)

    CITKIT.ru:

  • Linux в школе: слово заинтересованным лицам

  • SlackBuild: пакеты своими руками

  • Linux от компании Novell. Установка и обзор openSUSE Linux

    Все публикации >>>




  • IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

    Информация для рекламодателей PR-акции, размещение рекламы — тел. +7 495 4119920, ICQ 232284597 Пресс-релизы — pr@citcity.ru
    Послать комментарий
    Информация для авторов
    Rambler's Top100 TopList liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня This Web server launched on February 24, 1997
    Copyright © 1997-2000 CIT, © 2001-2007 CIT Forum
    Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...