CGI - это стандарт интерфейса, используемый для связи внешней программы для связи с сервером. Программу, которая работает по такому интерфейсу совместно с веб-сервером, принято называть шлюзом, хотя многие предпочитают названия «скрипт» или «CGI-программа». По сути позволяет использовать консоль ввода и вывода для взаимодействия с клиентом.
Сам интерфейс разработан таким образом, чтобы можно было использовать любой язык программирования, который может работать со стандартными устройствами ввода-вывода. Такими возможностями обладают даже скрипты для встроенных командных интерпретаторов операционных систем, поэтому в простых случаях могут использоваться даже командные скрипты.
CGI является одним из наиболее распространённых средств создания динамических сайтов. Этот стандарт используют такие популярные веб-сервера, как например, Nginx или Apache.
Сервер умеет закрепляться на определенному хост:порт и слушать входящие соединения. На заданном адресе выдается HTML-страничка, если запрос корректен, либо страница с ошибкой 404, если запрашиваемой страницы не существует. Также реализован cgi-скрипт показывающий время при нажатии на кнопки на главной странице.
#!
htdocs/
cgi-bin/
install.c
utility.c
utility.h
main.c
Makefile
- htdocs содержит всю статику: HTML и CSS файлы сервера.
- В cgi-bin хранятся используемые cgi-скрипты - на данный момент только программа, выводящая текущую дату/время.
- install.c это установочный скрипт, создающий .service файл для оформления сервера как службы systemd.
- main.c - содержит все функции, отвечающие за настройку и запуск сервера.
- utility.c - включает некоторые вспомогательные функции, такие как парсинг запроса клиента char * parse_request(...), поиск запрашиваемых файлов и отправка их клиенту void GET(...) и тд.
- Makefile - установочный make-file, содержащий все инструкции по компиляции и установке сервера.
Устанавливаем с помощью make. Установочный скрипт скомпилирует и переместит исполняемый файл в папку /usr/local/bin, затем создаст .service файл и поместит его в /etc/systemd/system/:
cd cgi/
make install
Сервер теперь можно запускать так же, как и системные службы(работает только на Ubuntu, т.к помещает юнит-файл в папку /etc/systemd/system/, которая не является установочной на других системах). По дефолту сервер запустится на 127.0.0.1:1235. Чтобы выставить свои настройки, нужно изменить config файл:
service cgi start
service cgi stop
При запуске программа создает PID файл, в который записывает ID текущего процесса, чтобы в дальнейшем можно было послать на него сигнал для завершения работы. Если во время старта сервера возникла ошибка, файл не создается.
#!c
//creating PID file
FILE * file = fopen(path_to_pidfile, "a+");
fprintf(file, "%d", getpid());
fclose(file);
//killing running server
FILE * file = fopen(path_to_pidfile, "r+");
fscanf(file, "%d", &pid);
kill(pid, SIGTERM);
fclose(file);
remove(path_to_pidfile);
Далее с помощью набора функций для работы с сокетами настраиваем наш сервер. Если все прошло без ошибок, начинаем принимать входящие соединения. Для каждого принятого соединения создаем отдельный процесс, родительский процесс при этом продолжает слушать.
#!c
pid_t pid = fork();
if (0 == pid) { //if it is child process - interact connection
handle_request(client_socket, &client_address, htdocs);
exit(0);
} else { //otherwise close socket and continue listening
close(client_socket);
}
Дочерний процесс считывает запрос, обрабатывает его и выдает страницу ответ: если файл был найден, то выдается соответствующая страничка, в противном случае пользователь получит страницу с ошибкой 404. Вся статика хранится в папке htdocs сервера.
#!c
read(client_socket, recv_buffer, sizeof(recv_buffer));
char *query_str = parse_request(recv_buffer);
...
GET(client_socket, query_str, maindir);
При нажатии на главной странице на кнопку "get current time" выполняется скрипт, возвращающий текущую дату/время:
#!c
if (strcmp(query_str + strlen(query_str) - 4, "cgi?") == 0) {
...
execve(main_dir, arg, empty2); //execute cgi-script
close(client_socket);
}
На данный момент реализовано:
- Веб-сервер выдает статические страницы и обслуживает одновременно несколько подключений.
- Сервер оформлен в виде службы для systemd.
- Сервер корректно обрабатывает ошибочные запросы.
- Сервер умеет работать со сторонними программами и выдавать результат их работы(на стадии разработки).
Coming soon:
- Поддержка POST запросов.