Устройство приложения ConsoleHttp
Рассмотрим теперь устройство приложения ConsoleHttp. Первая часть приложения ConsoleHttp практически совпадает с приложением ConsoleFtp, работа которого была рассмотрена нами выше в разделе “Устройство приложения ConsoleFtp”. Поэтому мы не будем на нем останавливаться. Скажем только что функция main сначала проверяет командную строку приложения. Если приложение было вызвано без параметров, или их больше чем один, то на экран выводится информация о формате вызова приложения.
Если пользователь правильно указал в командной строке ConsoleHttp только один параметр, он записывается в строку sUrlAdress и отображается на экране:
CString sUrlAdress;
sUrlAdress = argv[1];
Далее строка sUrlAdress передается для обработки функции AfxParseURL, которая разбирает адрес, записанный в ней на составные части и помещает их в переменные dwServiceType, sServer, sObject и nPort:
DWORD dwServiceType; // Тип сервиса
CString sServer; // Имя сервера
CString sObject; // Имя объекта на который указывает адрес
INTERNET_PORT nPort; // Номер порта
if(!AfxParseURL( sUrlAdress, dwServiceType,
sServer, sObject, nPort))
{
cout << "AfxParseURL Error" << endl;
return -1;
}
В том случае если пользователь указал в командной строке приложения неправильный адрес, не соответствующий формату URL, то функция AfxParseURL возвращает нулевое значение. Наше приложение отображает сообщение об ошибке и завершается с кодом -1.
Далее приложение проверяет, что указанный адрес соответствует адресу сервера WWW. В этом случае тип сервиса dwServiceType должен быть равен значению AFX_INET_SERVICE_HTTP. Если это не так, например, вместо адреса сервера WWW вы указали адрес сервера FTP, который начинается с ftp://, то на экран будет выведено сообщение об ошибке и приложение завершится с кодом возврата -2:
if(dwServiceType != AFX_INET_SERVICE_HTTP)
{
cout << "URL Address not WWW server" << endl;
return -2;
}
Если адрес сервера указан верно, приложение создает сеанс связи с Internet. Для этого мы объявляем указатель на объект класса CInternetSession а затем создаем сам объект, используя функцию new:
// Указатель на объект класса CInternetSession
CInternetSession* m_InternetSession = NULL;
// Инициализируем сеанс работы с WinInet - создаем объект
// класса CInternetSession catch
m_InternetSession = new CInternetSession("WWW Connecter");
Конструктор класса CInternetSession имеет много параметров, но мы все их используем по умолчанию, кроме первого параметра, через который мы задаем имя сеанса - WWW Connecter.
Теперь можно попытаться соединиться с сервером и запросить с него файл. Для этого следует вызвать метод GetHttpConnection класса CInternetSession только что созданного объекта m_InternetSession. В случае ошибки этот метод может вызвать исключение CInternetException. Поэтому вызов метода GetHttpConnection мы помещаем в блок try и определяем для него соответствующий блок catch, обрабатывающий исключение CInternetException:
// Исключения, вызванные в этом блоке try обрабатываются
// следующим блоком catch
try
{
// . . .
}
catch (CInternetException* pEx)
{
// . . .
}
Обработчик исключения CInternetException вызывает метод GetErrorMessage для полученного исключения, который записывает во временный буфер szErr причину вызова исключения. Если текстовое описание исключения доступно, метод GetErrorMessage возвращает ненулевое значение. В этом случае мы отображаем полученный текст на экране.
Затем мы завершаем обработку исключения, вызывая для него метод Delete. Он удаляет объект, представляющий исключение из оперативной памяти:
// Удаляем исключение
pEx->Delete();
Рассмотрим блоку try более подробно. В нем приложение исполняет свою главную задачу - пытается установить соединение с сервером WWW. Адрес сервера WWW передается методу GetHttpConnection класса CInternetSession. Если соединение с сервером будет установлено, то этот метод вернет указатель на объект класса GetHttpConnection и мы запишем его во временную переменную m_HttpConnection:
// Определяем указатель на объект класса CHttpConnection
CHttpConnection* m_HttpConnection = NULL;
// Пытаемся соединиться с сервером sServer
m_HttpConnection =
m_InternetSession -> GetHttpConnection( sServer );
Далее приложение HttpConnection вызывает для установленного соединения метод OpenRequest. Первый параметр метода OpenRequest определяет действие. В данном случае в качестве этого параметра используется константа HTTP_VERB_HEAD, означающая что мы желаем только получить информацию о объекте указанном во втором параметре метода sObject:
CHttpFile* pFile=NULL;
. . .
pFile = m_HttpConnection ->
OpenRequest( CHttpConnection::HTTP_VERB_HEAD,
sObject
);
Если метод OpenRequest завершился успешно, он возвращает указатель на объект класса CHttpFile. Далее вы можете использовать методы класса CHttpFile чтобы узнать данные полученные с сервера. Если вам надо получить с сервера файл, вы должны использовать вместо команды HTTP_VERB_HEAD команду HTTP_VERB_GET.
Сначала для объекта pFile вызывается метод AddRequestHeaders. Он добавляет дополнительный заголовок headerInfo к запросу HTTP. Сам заголовок headerInfo содержит текстовую строку, в которой определяются тип файлов, которые может принимать наше приложение и его имя:
CString headerInfo(
_T("Accept: text/*\r\nUser-Agent: Console Http\r\n"));
if(pFile->AddRequestHeaders(headerInfo))
{
}
Если метод AddRequestHeaders завершился без ошибок, он возвращает ненулевое значение. В этом случае наше приложение вызывает метод SendRequest, который и передает сформированный запрос серверу WWW. Если запрос передан успешно, то метод SendRequest возвращает ненулевое значение. В противном случае возвращается нуль. В случае возникновения ошибок метод SendRequest может вызвать исключение CInternetException:
if(pFile->SendRequest())
{
}
Обратите внимание, что исключение CInternetException может также быть вызвано методом GetHttpConnection. Мы поместили эти методы в один блок try, поэтому исключение вызванное любым из них будет обработано одним и тем же блоком catch.
Метод SendRequest только передает запрос серверу. Чтобы получить от него ответ, мы обращаемся к методу QueryInfoStatusCode. Этот метод получает код состояния, связанный с последним запросом к серверу и записывает его во временную переменную dwReturnCode.
Если метод QueryInfoStatusCode отработал успешно, он возвращает ненулевое значение. В этом случае мы преобразуем значение dwReturnCode в текстовую форму и отображаем его на экране:
DWORD dwReturnCode;
if(pFile -> QueryInfoStatusCode(dwReturnCode))
{
CString sMessage;
sMessage.Format("%d",dwReturnCode);
cout << "SendRequest: " << sMessage << endl << endl;
}
Больше приложение ConsoleHttp ничего не делает с сервером, поэтому закрываем объект pFile и удаляем его из памяти:
pFile->Close();
if(pFile)
delete pFile;
Затем закрываем соединение с сервером и удаляем соответствующий объект m_HttpConnection из памяти (этот объект создается методом GetHttpConnection):
// Закрываем соединение с сервером WWW
m_HttpConnection -> Close();
// Удаляем объект m_HttpConnection
delete( m_HttpConnection );
Перед окончанием работы приложения, завершаем сеанс связи, вызывая метод Close класса CInternetSession, а затем удаляем соответствующий объект из памяти, вызывая функцию delete:
// Завершаем сеанс связи
m_InternetSession -> Close();
// Удаляем объект m_InternetSession
delete(m_InternetSession);