|
разуются в форму %XX, где XX — код символа в шестнадцатеричной
системе счисления. Далее представлена функция на Си, которая умеет декодировать
подобные данные и приводить их к нормальному представлению.
Мы не можем сначала все данные (например, полученные из стандартного по-
тока ввода) декодировать, а уж потом работать с ними (в частности, разбивать
по месту вхождения символов & и =). Действительно, вдруг после перекоди-
ровки появятся символы & и =, которые могут быть введены пользователем?
Как мы тогда узнаем, разделяют ли они параметры или просто набраны с кла-
виатуры? Очевидно, никак. Поэтому такой способ нам не подходит, и придется
работать с каждым значением отдельно, уже после разделения строки на час-
ти.
Итак, приходим к следующему алгоритму: сначала разбиваем строку параметров на
блоки (параметр=значение), затем из каждого блока выделяем имя параметра и его
значение (обособленные символом =), а уж потом для них вызываем функцию пере-
кодировки, приведенную ниже:
Листинг 3.5. Функция URL-декодирования
// Функция преобразует строку данных st в нормальное представление.
// Результат помещается в ту же строку, что была передана в параметрах.
void UrlDecode(char *st) {
char *p=st; // указывает на текущий символ строки
char hex[3]; // временный буфер для хранения %XX
int code; // преобразованный код
// запускаем цикл, пока не кончится строка (то есть, пока не
// появится символ с кодом 0, см. ниже)
do {
// Если это %-код ...
if(*st == '%') { // тогда копируем его во временный буфер
hex[0]=*(++st); hex[1]=*(++st); hex[2]=0;
Часть I. Основы Web-программирования 54
// переводим его в число
sscanf(hex,"%X",&code);
// и записываем обратно в строку
*p++=(char)code;
// указатель p всегда отмечает то место в строке, в которое
// будет помещен очередной декодированный символ
}
// иначе, если это "+", то заменяем его на " "
else if(*st=='+') *p++=' ';
// а если не то, ни другое — оставляем как есть
else *p++=*st;
} while(*st++!=0); // пока не найдем нулевой код
}
Функция основана на том свойстве, что длина декодированных данных всегда мень-
ше, чем кодированных, а значит, всегда можно поместить результат в ту же строку,
не опасаясь ее переполнения. Конечно, примененный алгоритм далеко не оптимален,
т. к. использует довольно медлительную функцию sscanf() для перекодирования
каждого символа. Тем не менее, это самое простое, что можно придумать, вот
почему
я так и сделал.
Итак, теперь мы можем слегка модифицировать предыдущий пример сценария, за-
ставив его перед выводом данных декодировать их. Попробуем написать это так:
Листинг 3.6. Получение POST-данных с URL-декодированием
#include
#include
void main(void) {
// получаем значения переменных окружения
char *RemoteAddr = getenv("REMOTE_ADDR");
char *ContentLength = getenv("CONTENT_LENGTH");
// выделяем память для буфера QUERY_STRING
char *QueryString = malloc(strlen(getenv("QUERY_STRING")) + 1);
// копируем QUERY_STRING в созданный буфер
strcpy(QueryString, getenv("QUERY_STRING"));
// декодируем QUERY_STRING
UrlDecode(QueryString);
// вычисляем количество байтов данных — переводим строку в число
int NumBytes = atoi(ContentLength);
Глава 3. CGI изнутри 55
// выделяем в свободной памяти буфер нужного размера
char *Data = (char*)malloc(NumBytes + 1);
// читаем данные из стандартного потока ввода
fread(Data, 1, NumBytes, stdin);
// добавляем нулевой код в конец строки
// (в Си нулевой код сигнализирует о конце строки)
Data[NumBytes] = 0;
// декодируем дан
|
|