//+------------------------------------------------------------------+
//| SocketTlsReadAvailable.mq5 |
//| Copyright 2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link "https://www.mql5.com
#property version "1.00"
#property script_show_inputs
//+------------------------------------------------------------------+
//| Входные параметры скрипта |
//+------------------------------------------------------------------+
input string InpMethod ="GET"; // Method (HEAD,GET)
input string InpServer ="www.google.com"; // Server
input uint InpPort =443; // Port
input uint InpTimeout=5000; // Timeouts
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart(void)
{
Print("Server: ",InpServer);
Print("Port: ",InpPort);
//--- создаём сокет и получаем его хэндл
const int socket=SocketCreate();
if(socket==INVALID_HANDLE)
{
Print("SocketCreate() failed. Error ",GetLastError());
return;
}
//--- устанавливаем таймауты получения и отправки данных для системного объекта сокета
if(!SocketTimeouts(socket,InpTimeout,InpTimeout))
{
PrintFormat("SocketTimeouts(%u, %u) failed. Error %d",InpTimeout,InpTimeout,GetLastError());
SocketClose(socket);
return;
}
//--- подключаемся к серверу Server по порту Port
if(!SocketConnect(socket,InpServer,InpPort,InpTimeout))
{
PrintFormat("SocketConnect('%s', %u, %u) failed. Error %d",InpServer,InpPort,InpTimeout,GetLastError());
SocketClose(socket);
return;
}
//--- получаем данные о сертификате, используемом для защиты сетевого соединения
string subject,issuer,serial,thumbprint;
datetime expiration;
if(SocketTlsCertificate(socket,subject,issuer,serial,thumbprint,expiration))
{
Print("TLS certificate:");
Print(" Owner: ",subject);
Print(" Issuer: ",issuer);
Print(" Number: ",serial);
Print(" Print: ",thumbprint);
Print(" Expiration: ",expiration);
}
else
{
//--- сервер не предоставляет сертификат - сообщаем о незащищенном соединении и уходим
Print("The connection is not secured by a certificate");
SocketClose(socket);
return;
}
//--- отправляем запрос на сервер
string request=StringFormat("%s / HTTP/1.1\r\nHost: %s\r\nUser-Agent: MetaTrader 5\r\n\r\n",InpMethod,InpServer);
if(HTTPSendTLS(socket,request))
{
//--- запрос отправлен - получаем ответ
Print("\nRequest sent. Starting page loading...");
uchar response[]; // все полученные данные (заголовок и тело документа)
if(!HTTPRecvTLS(socket,response,InpTimeout))
{
Print("There were errors while reading the page");
SocketClose(socket);
return;
}
//--- сообщим о количестве байт принятых данных
PrintFormat("%u bytes received",response.Size());
//--- распечатаем только заголовок полученной страницы
string result =CharArrayToString(response,0,WHOLE_ARRAY,CP_UTF8);
int header_end=StringFind(result,"\r\n\r\n");
if(header_end>0)
{
Print("\nHTTP answer header received:");
Print(StringSubstr(result,0,header_end));
}
}
//--- закроем сокет после использования
SocketClose(socket);
/*
результат:
Server: www.google.com
Port: 443
TLS certificate:
Owner: /CN=www.google.com
Issuer: /C=US/O=Google Trust Services/CN=WR2
Number: 0d:43:b1:4a:bb:9c:15:96:10:e1:3d:55:23:9f:25:4e
Print: 89167618e5017f813aff981c88ce422dc1016bdf
Expiration: 2024.12.30 08:26:35
Request sent. Starting page loading...
HTTPRecvTLS: Document received within 27 attempts
25185 bytes received
HTTP answer header received:
HTTP/1.1 200 OK
Date: Fri, 25 Oct 2024 17:12:42 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
Content-Security-Policy-Report-Only: object-src 'none';base-uri 'self';script-src 'nonce-CUL2rdUOeAN7xIV6v0WUuQ' 'strict-dynamic' 'report-sample' 'unsafe-eval' 'unsafe-inline' https: http:;report-uri https://csp.withgoogle.com/csp/gws/other-hp
Accept-CH: Sec-CH-Prefers-Color-Scheme
P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info."
Server: gws
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
Set-Cookie: AEC=AVYB7coyYMCdweTDTaWeGYzmRnxzKGqsOEosH_VkbCn8xhWkFz6v0kxQFw; expires=Wed, 23-Apr-2025 17:12:42 GMT; path=/; domain=.google.com; Secure; HttpOnly; SameSite=lax
Set-Cookie: NID=518=J02X02Ff4v_9sMcNoUz-1SolmuG08E26Gs438ik0J_SOJUMy7of-P-qup-LaNSWVXUL8OjhOXpGIGuJQGIoEPBnzqDKCH-46_FN4J2foHeWTlGG8bVVvQ44AHWLg1OXjrGp3CUBexYdczLWNy3LxEcb7eh6mxSvFzOelPC6-vpXkaumLQ80x9gF_RpLcAYfN4ehT; expires=Sat, 26-Apr-2025 17:12:42 GMT; path=/; domain=.google.com; HttpOnly
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
Accept-Ranges: none
Vary: Accept-Encoding
Transfer-Encoding: chunked
*/
}
//+------------------------------------------------------------------+
//| Отправляет HTTP-запрос через защищенное соединение |
//+------------------------------------------------------------------+
bool HTTPSendTLS(int socket,const string request)
{
//--- конвертируем строку в массив символов, терминирующий ноль отбрасываем
char req[];
int len=StringToCharArray(request,req,0,WHOLE_ARRAY,CP_UTF8)-1;
if(len<0)
return false;
return(SocketTlsSend(socket,req,len)==len);
}
//+------------------------------------------------------------------+
//| Получает веб-страницу через безопасное соединение |
//+------------------------------------------------------------------+
bool HTTPRecvTLS(int socket,uchar &response[],const uint timeout_ms)
{
//--- читаем доступные данные из защищенного TLS-соединения, пока не истекло время ожидания
ulong timeout_check=GetTickCount64()+timeout_ms;
uchar block[1024]; // буфер блочного чтения данных из сокета
uint attempt=0; // запрошенное количество блоков данных
int err =0; // код ошибки
ResetLastError();
do
{
//--- читаем блоками, максимум по 1024 байта
int len=SocketTlsReadAvailable(socket,block,1024);
if(len>0)
{
attempt++;
//--- объединяем полученные блоки данных
ArrayCopy(response,block,response.Size());
//--- здесь анализируем полученные данные, определяем заголовок, тело страницы, окончание, или ошибку загрузки, и т.д.
//...
//...
//...
timeout_check=GetTickCount64()+timeout_ms;
}
else
Sleep(10);
err=GetLastError();
}
while(!IsStopped() && GetTickCount()<timeout_check && !err);
//--- при чтении были ошибки?
if(err)
{
Print("Error ",err);
return(false);
}
PrintFormat("%s: Document received within %d attempts",__FUNCTION__,attempt);
return(true);
}
|