Microsoft Visual J++. Создание приложений и аплетов на языке Java. Часть 2© Александр Фролов, Григорий ФроловТом 32, М.: Диалог-МИФИ, 1997, 288 стр. Приложение CallCGIВ 29 томе “Библиотеки системного программиста” мы рассказывали о том, как с помощью расширений сервера Web, выполненных на основе интерфейса CGI и ISAPI можно обрабатывать данные из форм, расположенных в документах HTML. В частности, мы привели там исходные тексты программы controls.exe (составленной на языке программирования С), которая динамически создавала и отображала данные, введенные в форме. Внешний вид этой формы показан на рис. 3.6, воспроизведенном нами из указанного тома.
Рис. 3.6. Форма для ввода данных Программа CGI controls.exe получала данные, введенные пользователем в этой форме, после чего динамически создавала документ HTML, в котором отображала состояние переменных серды, полученные данные в исходном и раскодированном виде, а также список значений полей (рис. 3.7).
Рис. 3.7. Документ HTML, сформрованный динамически программой CGI control.exe Создавая приложение CallCGI, мы поставили перед собой задачу заменить форму приложением Java, которое вводит с клавиатуры текстовую строку полей и передает ее программе CGI controls.exe. Содержимое динамически сформированного программой CGI документа HTML приложение CallCGI отображает в своем консольном окне, как это показано на рис. 3.8.
Рис. 3.8. Отображение в окне приложения Java содержимого документа HTML, полученного от программы CGI Исходный текст приложения CallCGIИсходный текст приложения CallCGI приведен в листинге 3.9. Листинг 3.9. Файл CallCGI\CallCGI.java
// =========================================================
// Вызов расширения сервера Web на базе интерфейса CGI
// из приложения Java
//
// (C) Фролов А.В, 1997
//
// E-mail: frolov@glas.apc.org
// WWW: http://www.glasnet.ru/~frolov
// или
// http://www.dials.ccas.ru/frolov
// =========================================================
import java.io.*;
import java.net.*;
import java.util.*;
public class CallCGI
{
// -------------------------------------------------------
// main
// Метод, получающий управление при запуске приложения
// -------------------------------------------------------
public static void main(String args[])
{
// Массив для ввода строки с клавиатуры
byte bKbdInput[] = new byte[256];
// Размер принятого блока данных
int length;
// Рабочая строка
String str;
// Адрес URL вызываемой программы CGI
URL u;
// Канал связи с расширением CGI
URLConnection c;
// Выходной поток для передачи данных расширению CGI
PrintStream ps;
// Входной поток для получения данных от расширения CGI
DataInputStream is;
try
{
// Выводим строку приглашения
System.out.println("CGI extension call" +
"\nEnter any string for send to CGI...");
// Читаем строку, передаваемую расширению,
// с клавиатуры
length = System.in.read(bKbdInput);
// Если строка не пустая, обрабатываем ее
if(length != 1)
{
// Преобразуем строку в формат String
str = new String(bKbdInput, 0);
// Обрезаем строку, удаляя символ конца строки
StringTokenizer st;
st = new StringTokenizer(str, "\n");
str = new String((String)st.nextElement());
// Выполняем кодировку URL для передаваемой строки
String StrEncoded = URLEncoder.encode(str);
// Отображаем перекодированную строку
System.out.println("Encoded string: >" +
StrEncoded + "<");
// Создаем объект класса URL для расширения CGI
u = new URL(
"http://frolov/frolov-cgi/controls.exe");
// Открываем канал связи с расширением CGI
c = u.openConnection();
// Создаем выходной поток данных для передачи
// введенной строки серверу CGI
ps = new PrintStream(c.getOutputStream());
// Передаем закодированную строку расширению CGI
ps.println(StrEncoded);
// Закрываем выходной поток
ps.close();
// Создаем входной поток для приема данных от
// расширения CGI
is = new DataInputStream(c.getInputStream());
System.out.println(
"\n------------------------------------------" +
"\n Data from CGI extension" +
"\n------------------------------------------\n");
// Прием данных выполняем в цикле
while (true)
{
// Получаем очередную строку
str = is.readLine();
// Если последняя строка, прерываем цикл
if(str == null)
break;
// Отображаем принятую строку
System.out.println(str);
}
// Закрываем входной поток
is.close();
}
}
catch(Exception ioe)
{
System.out.println(ioe.toString());
}
try
{
System.out.println(
"Press <Enter> to terminate application...");
System.in.read(bKbdInput);
}
catch(Exception ioe)
{
System.out.println(ioe.toString());
}
}
}
Описание исходного текста приложения CallCGIВнутри метода main мы определили несколько переменных. Массив bKbdInput предназначен для хранения строки, введенной с помощью клавиатуры. В переменную length записывается длина этой строки. Строка str класса String используется в качестве рабочей. Переменная u класса URL предназначена для хранения ссылки на объект URL, созданный для загрузочного файла программы CGI. Ссылка на канал связи с программой CGI хранится в переменной с именем c класса URLConnection. Переменные ps класса PrintStream и is класса DataInputStream хранят ссылки, соответственно, на выходной и входной потоки, через которые наше приложение обменивается данными с программой CGI. После вывода приглашения на консоль наша программа вводит строку, которая будет передана программе CGI: length = System.in.read(bKbdInput); Далее массив bKbdInput преобразуется в строку str и перекодируется в кодировку URL. Эта кодировка была описана нами в 29 томе “Библиотеки системного программиста”. Она выполняется с помощью статического метода encode, определенного в классе URLEncoder: String StrEncoded = URLEncoder.encode(str); Перекодированная строка отображается на консоли:
System.out.println("Encoded string: >" + StrEncoded + "<");
На следующем этапе наше приложение создает объект класса URL для загрузочного файла программы CGI:
u = new URL("http://frolov/frolov-cgi/controls.exe");
Здесь предполагается, что программа CGI находится в файле controls.exe, который записан в виртуальный каталог frolov-cgi на сервере Web с адресом http://frolov). Про создание и настройку виртуальных каталогов для размещения расширений сервера Web мы рассказали в 29 томе “Библиотеки системного программиста”. После создания объекта класса URL мы создаем канал с программой CGI как объект класса URLConnection: c = u.openConnection(); Пользуясь этим каналом, мы вначале получаем выходной поток методом getOutputStream, а затем на его базе создаем форматированный выходной поток класса PrintStream, удобный для записи в него текстовых строк: ps = new PrintStream(c.getOutputStream()); Через канал ps наше приложение передает программе CGI строку StrEncoded, а затем закрывает выходной поток, как это показано ниже: ps.println(StrEncoded); ps.close(); В этот момент на сервере Web уже запущена программа CGI, и она приняла переданные ей данные. Обработав эти данные, программа CGI записала в стандартный выходной поток динамически созданный ей документ HTML. Для получения документа наше приложение CallCGI создала входной форматированный поток данных: is = new DataInputStream(c.getInputStream()); Входной поток создан в два приема. Вначале с помощью метода getInputStream приложение создала обычный входной поток, а затем, на его базе, форматированный входной поток класса DataInputStream. Получение от программы CGI динамически сформированного ей документа HTML наше приложение выполняет в цикле по строкам. Строка документа HTML читается из входного форматированного потока методом readLine и записывается в переменную str: str = is.readLine(); Если в процессе чтения был достигнут конец потока, цикл прерывается: if(str == null) break; Строка, полученная методом readLine, отображается на консоли пиложения: System.out.println(str); После завершения цикла входной поток закрывается методом close: is.close(); Исходные тексты программы CGIВ лситинге 3.10 мы привели исходный текст программы CGI с именем controls. Он несколько упрощен по сравнению с исходным текстом одноименного приложения, описанного в 29 томе “Библиотеки системного программиста” - мы выбросили обработку метода передачи данных GET, так как наше приложение CallCGI передает данные только методом POST. Описание этой программы вы найдете в упомянутом 29 томе. Листинг 3.10. Файл controls\controls.c
// ===============================================
// Программа CGI controls.c
// Демонстрирует методы получения и обработки
// данных от форм, расположенных в документах HTML
//
// (C) Фролов А.В., 1997
// E-mail: frolov@glas.apc.org
// WWW: http://www.glasnet.ru/~frolov
// или
// http://www.dials.ccas.ru/frolov
// ===============================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Прототипы функций перекодировки
void DecodeStr(char *szString);
char DecodeHex(char *str);
// ------------------------------------------------
// Функция main
// Точка входа программы CGI
// ------------------------------------------------
void main(int argc, char *argv[])
{
int lSize;
FILE * fileReceived;
char * szMethod;
char szBuf[8196];
char szSrcBuf[8196];
char * szPtr;
char * szParam;
// Вывод заголовка HTTP и разделительной строки
printf("Content-type: text/html\n\n");
// Вывод начального форагмента документа HTML,
// формируемого динамически
printf("<!DOCTYPE HTML PUBLIC"
" \"-//W3C//DTD HTML 3.2//EN\">");
printf("<HTML><HEAD><TITLE>Call CGI from Java"
"</TITLE></HEAD><BODY BGCOLOR=#FFFFFF>");
// Определяем метод передачи данных
szMethod = getenv("REQUEST_METHOD");
// Обработка метода POST
if(!strcmp(szMethod, "POST"))
{
// Определяем размер данных, полученных от навигатора
// при передаче данных из полей формы
lSize = atoi(getenv("CONTENT_LENGTH"));
// Читаем эти данные в буфер szBuf из
// стандартного потока ввода STDIN
fread(szBuf, lSize, 1, stdin);
// Создаем файл, в который будут записаны
// принятые данные
fileReceived = fopen("received.dat", "w");
// Выполняем запись принятых данных
fwrite(szBuf, lSize, 1, fileReceived);
// Закрываем файл принятых данных
fclose(fileReceived);
// Отображаем значения некоторых переменных среды
printf("<H2>Environment variables</H2>");
// Метод доступа
printf("REQUEST_METHOD = %s", getenv("REQUEST_METHOD"));
// Размер полученных данных в байтах
printf("<BR>CONTENT_LENGTH = %ld", lSize);
// Тип полученных данных
printf("<BR>CONTENT_TYPE = %s", getenv("CONTENT_TYPE"));
// Закрываем буфер данных двоичным нулем,
// превращая его таким образом в строку
szBuf[lSize] = '\0';
// Делаем копию принятых данных в буфер szSrcBuf
strcpy(szSrcBuf, szBuf);
// Отображаем принятые данные без обработки
printf("<H2>Received data</H2>");
printf("<P>%s", szSrcBuf);
// Выполняем перекодировку принятых данных
DecodeStr(szSrcBuf);
// Отображаем результат перекодировки
printf("<H2>Decoded data</H2>");
printf("<P>%s", szSrcBuf);
// Выводим список значений полей формы
printf("<H2>Filds list</H2>");
// Дописываем в конец буфера принятых данных
// символ "&", который используется в качестве
// разделителя значений полей
szBuf[lSize] = '&';
szBuf[lSize + 1] = '\0';
// Цикл по полям формы
for(szParam = szBuf;;)
{
// Ищем очередной разделитель
szPtr = strchr(szParam, '&');
// Если он найден, раскодируем строку параметров
if(szPtr != NULL)
{
*szPtr = '\0';
DecodeStr(szParam);
// Выводим в документ значение параметра
printf("%s<BR>", szParam);
// Переходим к следующему параметру
szParam = szPtr + 1;
// Если достигнут конец буфера, завершаем цикл
if(szParam >= (szBuf + lSize))
break;
}
else
break;
}
// Выводим завершающий фрагмент документа HTML
printf("</BODY></HTML>");
return;
}
}
// ------------------------------------------------
// Функция DecodeStr
// Раскодирование строки из кодировки URL
// ------------------------------------------------
void DecodeStr(char *szString)
{
int src;
int dst;
char ch;
// Цикл по строке
for(src=0, dst=0; szString[src]; src++, dst++)
{
// Получаем очередной символ перекодируемой строки
ch = szString[src];
// Заменяем символ "+" на пробел
ch = (ch == '+') ? ' ' : ch;
// Сохраняем результат
szString[dst] = ch;
// Обработка шестнадцатеричных кодов вида "%xx"
if(ch == '%')
{
// Выполняем преобразование строки "%xx"
// в код символа
szString[dst] = DecodeHex(&szString[src + 1]);
src += 2;
}
}
// Закрываем строку двоичным нулем
szString[dst] = '\0';
}
// ------------------------------------------------
// Функция DecodeHex
// Раскодирование строки "%xx"
// ------------------------------------------------
char DecodeHex(char *str)
{
char ch;
// Обрабатываем старший разряд
if(str[0] >= 'A')
ch = ((str[0] & 0xdf) - 'A') + 10;
else
ch = str[0] - '0';
// Сдвигаем его влево на 4 бита
ch <<= 4;
// Обрабатываем младший разряд и складываем
// его со старшим
if(str[1] >= 'A')
ch += ((str[1] & 0xdf) - 'A') + 10;
else
ch += str[1] - '0';
// Возвращаем результат перекодировки
return ch;
}
|




