Іноді трапляється, що для написання двигуна, що працює з Web, інтерпретовані мови типу PHP/Perl/ASP не підходять. Це буває, наприклад, коли потрібна високопродуктивна CMS або щось низькорівневе (наприклад, збір даних з веб-камери). Звичайно, існують такі мови, як C#, але іноді для невеликих проектів їх застосування не окупить витрати.

Тому перше, що слід знати для написання таких програм як в загальних рисах влаштований інтерфейс CGI. Про інтерфейсі ви можете прочитати з Вікіпедії, я ж просто наведу приклад реалізації найпростішої cgi-програми типу PE/ELF.

#include
#include
#include // без розширення, підключає клас std::string
#include // strlen, strcat, strncpy, …

using std::string;
using std::cout;
using std::cin;
using std::endl;

int main(int argc, char *argv[])
{
string POST_data;
string QUERY_STRING;
cout << «content-type: text/plain; charset=windows-1251» << endl << endl;
char* var = 0;
var = getenv(«CONTENT_LENGTH»);
if ((var != 0) && (var) != «0»)
{
int post_length = atoi(var);
free(var); var = 0;
cout << «POST data: n»;
var = (char*)malloc(post_length+1);
cin.get(var, post_length+1);
cout << var;
free(var);
}
var = getenv(«QUERY_STRING»);
if (var)
{
QUERY_STRING = var;
free(var); var = 0;
cout << endl << «QUERY_STRING: » << QUERY_STRING << endl;
}
return EXIT_SUCCESS;
}

Як бачите, для спрощення роботи з рядками використовується клас string з бібліотеки std.

Першим ділом cgi-програма повинна відправити заголовки. У нашому випадку тут все просто: content-type визначає тип інформації, що передається (в даному випадку, звичайний текст), після чого йдуть два символу нового рядка. Якщо не передати заголовок, сервер видасть помилку ‘Internal Server Error’. Як ви вже зрозуміли, відправляти всі дані на стандартний пристрій виводу (так, до речі, додаток повинен бути консольним).

Далі, необхідно навчитися зчитувати отримані дані від сервера і змінні оточення. Значення конкретної змінної оточення можна отримати використовуючи функцію getenv(const char* ім’я_змінної). Ця функція повертає 0, якщо змінна не існує.

Щоб дізнатися, які змінні сервер передав скрипту, можна використовувати наступну конструкцію:

extern char** environ; // Глобальна змінна, оголошується на початку модуля

for (int i=0; environ[i] != 0; i++)
printf(%sn, environ[i]);

Зовнішня змінна environ стандартизована POSIX і доступна на більшості платформ і операційних систем (сумісних з POSIX).

Ті параметри, які передаються через URI, можуть бути знайдені в змінної QUERY_STRING.

З методом POST справа йде дещо складніше. Спочатку ми повинні дізнатися довжину даних. Вона зберігається в змінної CONTENT_LENGTH у вигляді рядка з числом. На щастя, в бібліотеці С/C++ є функція atoi, яка вміє переводити рядок на число.

Після того, як довжина даних відома, ми просто зчитуємо вміст стандартного пристрою вводу (їм буде не клавіатура, а канал між web-сервером і cgi-програмою)

Дані, що зберігаються в QUERY_STRING і в потоці стандартного вводу зашифровані так званим urlencode. Тому наступним кроком стане дешифрування та розбір всіх параметрів, ніж наша невелика програма займатися не стане.

Так як ми написали CGI-програму, то для її тестування вам знадобиться Web-сервер. Можете використовувати свій, а можна і на хостингу (якщо, звичайно, він дозволяє виконання програм, а не тільки скриптів). Для тестування необхідно скопіювати програму в папку cgi-bin на сервері або будь-яку іншу, яка допускає виконання сценаріїв. І доведеться написати невелику html-сторінку, щоб було зручніше посилати POST-запити:

Test Page

Text Entry:

Змініть шлях до cgi-програми і запустіть сторінку на сервері через браузер (не локально збережений html, а саме на сервері).

Власне, основний цикл будь-якого cgi-програми включає в себе три стадії: аналіз отриманих даних, підготовка контенту, висновок контенту. Причому висновок не обов’язково повинен бути текстовим; саме для цього передбачений заголовок типу документу. Ви можете, наприклад, відправити сформований Flash-документ, зображення, файл або будь-який інший тип, що має MIME.

Мета цієї статті досягнута ви тепер знаєте, як отримати дані від сервера (а може бути знали й до цього :))

By MBR, 2008