Tim Berners-LeeУ истоков APACHE лежит CERN httpd – веб-сервер, написанный на Cи в 1991 в ЦЕРН — Европейской организации по ядерным исследованиям, крупнейшей в мире лаборатории физики высоких энергий. Разработка программы осуществлялась на компьютере NeXT под управлением операционной системы NeXTSTEP, позже она была перенесена под unix.

 Одним из авторов этого веб-сервера является Tim Berners-Lee, который еще в 1984 году начал работать во внутренней сети института и писать программы с использованием Remote Procedure Call (RPC), которые могли вызывать другие программы удаленно на другом компьютере. В 1988 у Тима созрела в голове модель гипертекстовой системы. К тому времени в институте работало 250 человек, и существующих майнфреймов уже не хватало для выполнения всех запросов. В 1990 году Тим привез из штатов компьютер NeXT и получил добро от начальства на разработку проекта под названием WorldWideWeb. Вскоре Тим уже имел прототип работающего браузера (см. рисунок).


К проекту подключился Nicola Pellow, который написал текстовой браузер, работающий практически на любой платформе. Был принят формат HTML, который пришел на смену уже существующему формату SGML. Для получения файлов в сети был придуман URL:

	scheme : // host.domain:port / path / path # anchor

К тому времени уже давно существовала доменная система имен - Domain Name System (DNS). Клиент создавал соединение TCP-IP к хосту, используя доменное имя либо ip-адрес. В 1991 году новый веб-сервер работал на X-Workstation, Macintosh и PC. В 1992 году число веб-
серверов достигло 50, часть их уже работала в США. В 1993 году сервер компилировался на платформах HP, SGI, Sun, DEC, NeXT, была добавлена авторизация, появилась утилита htadm для работы с файлом паролей, поддержка изображений. В 1994 году перенесен на Solaris, добавлена утилита cgiparse, реализован режим прокси.Обычно CERN httpd работал на 80-м порту, но мог также выступать в качестве прокси для обслуживания внутренней сети, которая была прикрыта межсетевым. В последнем случае для повышения эффективности этот сервер имел возможность кэшировать документы.Его достоинством является то, что для уже существующего межсетевого экрана не нужно модифицировать клиентов для таких протоколов, как ftp, gopher и т.д. - управлением такими клиентами справляется сам CERN. В случае прокси CERN выступает одновременно и как сервер, и как клиент: для внутренней сети он является сервером, для внешней - клиентом.CERN httpd был разработан для обслуживания статических веб-страниц. Он получал из сети URL-запросы с помощью протокола HTTP/0.9 , переводил их в пути и возвращал контент запрашиваемых страниц. На раннем этапе CERN работал с внешними программами для обработки запросов. Была построена система обработки таких запросов, которая вызывала командную оболочку или внешний скрипт. Вывод скрипта перенаправлялся в браузер, в котором страница генерировалась на лету. Эта схема позволяла передавать скрипту список аргументов, создающих поисковую систему.Сегодня мы рассмотрим:

  1. Конфигурация CERN httpd.
  2. Защита CERN httpd.
  3. CERN httpd в роли прокси-сервера.
  4. CERN httpd и CGI.
  5. CERN httpd и графический контент.
  6. Архитектура CERN httpd.
  7. Тест.

Последняя финальная версия 3.0 была выпущена в 1996 году. Конфигурация CERN осуществлялась привычным образом: есть главный файл httpd.conf , в котором прописывался порт по умолчанию. Пример такого файла:

# домашний каталог
ServerRoot /usr/www 

# полное доменное имя
HostName www.rummidge.ac.uk

# порт 
Port	80

# авторизация: сервер запускается от рута, а потом переключается и 
# работает от имени этого пользователя
UserId	nobody
GroupId	nogroup

# страница по умолчанию
Welcome home.html

# логирование
AccessLog	/where/ever/httpd-log
ErrorLog	/where/ever/httpd-errors

#	домашний каталог ~/public_html
# В этом случае, если будет сделан запрос http://www.host.name/~ a_user/mydir/index.html, 
# он будет транслирован в домашний каталог пользователя a_user:
# /home/a_user/public_html/mydir/index.html
UserDir	public_html

# каталог для запуска cgi-скриптов
Exec	/cgi-bin/*	/your/script/directory/*

# правила трансляции
Pass	/*	/local/Web/*

2. Защита CERN httpd

В CERN существует несколько видов защиты, которые можно разделить на 3 основные группы:

  1. Ограничения по хостам.
  2. Ограничения по пользователям.
  3. Ограничения файловой системы на базе Access Control Lists.

Для ограничения по хостам в конфигурационном файле существует параметр Protect: в примере прописано разрешение для клиентских запросов, которые приходят с хостов, оканчивающихся на "ac.uk" или "ja.net". В этом случае клиент получает доступ к любым документам, урлы которые начинаются с /research-grants/ или /grant-awards/:

	Protection UK_ACADEMIC 
	{
		AuthType Basic
		GetMask @*.ac.uk, @*.ja.net
	}

	Protect /research-grants/* UK_ACADEMIC
	Protect /grant-awards/* UK_ACADEMIC

При этом нужно учитывать тот факт, что если в конфигурационном файле перед командой Protect стоит команда Pass на каталог /research-grants/, то разрешение будет получено в любом случае, независимо от того, есть Protect или нет.

Для ограничения доступа по пользователям есть параметр Protection:

	Protection WEBWEAVERS 
	{
		AuthType Basic
		PasswordFile /WWW/Admin/passwd
		GetMask handley, crowcroft
	} 

	Protect /secret/* WEBWEAVERS

Определятся файл с зашифрованными паролями. Работа с файлом паролей выполняется с помощью команды htadm, которая идет в пакете исходников, которую можно применить так:

	htadm -adduser /путь/к/файлу/паролей имя_пользователя

Пользователь должен будет набрать логин и пароль для дальнейшего доступа.

Пользователей можно разбить на группы с помощью специального файла group:

	webweavers: handley, crowcroft
	syspeople: jonathan, barry, ray, steve
	trusted: authors, syspeople, anne
	uclcs: @*.cs.ucl.ac.uk, @128.16.*, @193.63.58.*
	verysecure: trusted@*.cs.ucl.ac.uk

Для них прописываются правила:

	Protection VERYSECURE 
	{
		AuthType Basic
		PasswordFile /WWW/Admin/passwd
		GroupFile /WWW/Admin/group
		GetMask verysecure
	}

	Protect /secret/* VERYSECURE

При этом доступ к каталогу secret будет разрешен только группе trusted.

Доступ на уровне ACL полезен тогда, когда нужно разграничить доступ к отдельным файлам. Создается ACL-файл с именем www_ac:

	ndex.html : GET : @*.cs.ucl.ac.uk
	secret*.html: GET,POST : trusted@*.cs.ucl.ac.uk
	*.html : GET : webweavers

В данном примере для пользователей группы webweavers снимаются вообще все ограничения в доступе.

3. CERN httpd в роли прокси-сервера

CERN httpd в роли прокси-сервера

CERN может работать в качестве прокси. Эта схема состоит из 3 частей: внутренняя сеть, машина-файрвол и внешняя сеть. CERN устанавливается на файрволе и обслуживает запросы пользователей, которые находятся во внутренней сети и делают запросы во внешний мир. В этом случае конфигурация выглядит так:

Port 8080 Pass http:* Pass ftp:* Pass gopher:* Pass wais:*

Защита в прокси реализована как по именам:

    Protection  protname  {
        Mask @(*.cern.ch, *.desy.de)
    }

Так и на уровне IP:

    Protection  protname  {
        Mask  @(128.141.*.*, 131.169.*.*)
    }

Для сайтов, которые не находятся в домене UK, прописывается внешний прокси:

	http_proxy http://www.hensa.ac.uk/
	gopher_proxy http://www.hensa.ac.uk/
	ftp_proxy http://www.hensa.ac.uk/
	no_proxy uk

Настраивается суммарное место на диске - 300 метров, каталог для хранения кеша, перидичность очистки кеша:

Caching ON
NoCaching http://www.cs.ucl.ac.uk/*
CacheRoot /cs/research/mice/boom/scratch1/wwwcache
CacheSize 300 M
CacheLastModifiedFactor 0.2
GcDailyGc 2:00

4. CERN httpd и CGI

Начиная с версии 2.15, в CERN появился интерфейс работы с CGI скриптами. Адрес скрипта прописывался прямо в URL и отдавал контент веб-серверу. CGI настраивался в конфигурационном файле с помощью директивы Exec:

        Exec /url-prefix/*  /physical-path/*

Все скрипты лежали в домашней директории ServerRoot.

Такому скрипту можно было с сервера передавать параметры стандартным образом: через QUERY_STRING. Скрипт возвращал серверу результат, который начинался с Content-Type:

        Content-Type: text/html
        <HEAD>
        <TITLE>Script test></TITLE>
        </HEAD>
        <BODY>
        <H1>Привет !</H1>
        ....
        </BODY>

Скрипт также мог вернуть какой-то статический документ с помощью Location:

	Location: http://www.w3.org/pub/WWW/

В исходниках CERN можно найти утилиту cgiparse, которая обрабатывает методы GET и POST. В случае GET читается стандартный QUERY_STRING, в случае POST читается стандартный ввод. Можно написать сценарий на языке shell, который смоделирует работуcgiparse:

	#!/bin/sh
	eval `cgiparse -form`
	$filename=$FORM_pubname
	$doc_root="/cs/research/www/www/htdocs"
	$fullfilename=$doc_root"/misc/uk/london/pubs/auto-"$filename".html"

	#Write the entry to a file in HTML
	echo "<TITLE>"$FORM_pubname"</TITLE>" > $fullfilename
	echo "<H1>"$FORM_pubname"</H1><HR>" > $fullfilename
	echo "<I>"$FORM_pubaddress"</I><P>" > $fullfilename
	echo "<h2>Area:</h2> "$FORM_area"\n" > $fullfilename
	echo -n "<h2>Description:</H2>" > $fullfilename

5. CERN httpd и графический контент

В CERN был реализован механизм просмотра "кликабельных" картинок внутри html-документа. При клике на нее контент возвращала специальная утилита htimage. Для этого нужно было создать специальный файл, в котором прописывались правила нахождения картинок. При этом внутри html-документа нужно было прописать:

		<A HREF="/img/my_image.conf">
			<IMG SRC="Image.gif" ISMAP>
		</A>

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

6. Архитектура CERN httpd

Исходники CERN версии 3.0 состоят из 2-х частей: библиотеки libwww и, собственно, самого демона httpd. Библиотека libwww была написана в 1992 году в рамках все того же CERN. Эта библиотека написана с прицелом на производительность, имеет модульную структуру и возможность для расширения. Она включает в себя эффективный код для работы с HTTP, URL, может быть использована для создания роботов на стороне клиента, браузеров и т. д. Обработка запросов происходит в асинхронном режиме.

Библиотека libwww имеет модульную архитектуру и состоит из 5 основных частей:

  1. Базовые модули: здесь происходит разделение кода для того, чтобы эта библиотека была платформенно-независимой. Она включает большое количество условных макросов, которые делают библиотеку переносимой.
  2. Ядро: оно невелико по размеру и включает в себя базовые функции для сетевого доступа, анализа сетевых объектов, управления действиями пользователя, выполняет ведение журнала событий. Ядро реализует стандартный интерфейс к пользовательским программам и управляет внешними запросами.
  3. Потоковые модули: данные, передаваемые от приложения в сеть и приходящие обратно, используют потоки. Поток представляет из себя объект в стиле ANSI C файлового потока. Как правило, поток получает входящие данные, обрабатывает их и формирует вывод.

    Модули доступа: протокольно-специфичные модули - HTTP, FTP, Gopher, WAIS, NNTP, Telnet, rlogin, TN3270.

  4. Модули приложений: модули, специфичные для конкретного приложения.

Само приложение при работе с libwww использует напрямую последние 3 группы модулей.

Более подробно мы поговорим о libwww во втором документе нашего Apache-цикла.

CERN httpd на каждый запрос создает новый процесс (fork), который занимает минимальное количество памяти и несет в себе необходимую информацию для системных вызовов. CERN потребляет память в линейной зависимости пропорционально количеству запросов.

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

Главный управляющий файл демона - HTDaemon.c. Инициализация демона происходит следующим образом:

  1. HTDefaultConfig() ( HTConfig.c) - установка конфигурации по умолчанию.
  2. HTFileInit() ( HTSInit.c ) - инициализация таблицы суффиксов.
  3. Обработка аргументов командной строки.
  4. HTServerInit() ( HTConfig.c ) - инициализация таблицы ошибок и иконок.
  5. Вызов функции do_bind() - биндится порт и начинается его прослушивание - вызов стандартных библиотечных функций socket,bind,listen:
    	  socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    	  if ((setsockopt(master_soc,SOL_SOCKET,SO_KEEPALIVE,...)
  6. Далее всю работу на себя берет базовый цикл server_loop() , в котором вызывается системный вызов select с таймаутом для регистрации запросов. При получении клиентского запроса порождается дочерний процесс с вызовом wait3 с параметром WNOHANG, создается новый сокет, который передается дочернему процессу.
  7. Дочерний процесс вызывает функцию HTHandle(), в которой генерируются структуры для хранения информации о запросе. Запрос разбирается и создается обьект HTRequest. Парсинг запроса осуществляется с помощью модуля HTFormat.c из библиотеки libwww.
  8. Вызывается HTHandle(), который создает выходящий поток, куда записывается результат запроса. Запись в поток выполняет модуль HTWriter.c библиотеки libwww.
  9. HTRetrieve() возвращает с диска запрашиваемый документ.

Этот алгоритм можно представить графически (см. рисунок):

Алгоритм

7. Тест

В тесте был использован Apache Bench (далее AB). Данная стандартная утилита входит во многие пакеты, в том числе и в стандартный дистрибутив Apache.

В качестве подопытных материалов были выбраны 3 дистрибутива:

  1. CERN httpd 2.3
  2. Apache 1.3.42
  3. Apache 2.2.15

Все дистрибутивы были собраны на ядре 2.6.34, и были проведены следующие тесты с использованием статичного html-документ размером в 250 килобайт. Следующая команда выполняет 1000 GET-запросов по локальному адресу с числом одновременно посылаемых сообщений, равным 100:

	ab -n 1000 -c 100 http://127.0.0.1/test_doc.html

Вывод для CERN httpd:

This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Benchmarking 127.0.0.1 (be patient)
Server Software:        CERN/3.0A
Server Hostname:        127.0.0.1
Server Port:            80
Document Length:        252665 bytes

Concurrency Level:      100
Time taken for tests:   6.455 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      253127896 bytes
HTML transferred:       252943528 bytes
Requests per second:    154.92 [#/sec] (mean)
Time per request:       645.489 [ms] (mean)
Time per request:       6.455 [ms] (mean, across all concurrent requests)
Transfer rate:          38295.79 [Kbytes/sec] received

Собранный из исходников apache 1.3.42 с конфигурацией по умолчанию:

Concurrency Level:      100
Time taken for tests:   1.080 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      253626632 bytes
HTML transferred:       253374879 bytes
Requests per second:    926.25 [#/sec] (mean)
Time per request:       107.962 [ms] (mean)
Time per request:       1.080 [ms] (mean, across all concurrent requests)
Transfer rate:          229416.78 [Kbytes/sec] received

Собранный из исходников apache 2.2.15 с конфигурацией по умолчанию:

Concurrency Level:      100
Time taken for tests:   0.709 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      252921000 bytes
HTML transferred:       252665000 bytes
Requests per second:    1410.80 [#/sec] (mean)
Time per request:       70.882 [ms] (mean)
Time per request:       0.709 [ms] (mean, across all concurrent requests)
Transfer rate:          348457.80 [Kbytes/sec] received

Т.е. мы видим, что максимальную производительность в этом статическом тесте показывает второй Apache, и скорость выросла за 15 лет - с момента последнего релиза CERN httpd в 1996 г. - примерно на порядок. Производительность первого Apache меньше второго примерно в полтора раза.

Заключение

Сегодня мы рассмотрели проект CERN httpd, который лежит у истоков Apache.

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


Яковлев Сергей — независимый разработчик с многолетним опытом прикладного и системного программирования; вносит вклад в развитие open-source на своем персональном сайте www.iakovlev.org. Консультант. Статья

Вверх