385 lines
30 KiB
MQL5
385 lines
30 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Define constants for different URL protocols |
|
|
//+------------------------------------------------------------------+
|
|
#define HTTP "http"
|
|
#define HTTPS "https"
|
|
#define WS "ws"
|
|
#define WSS "wss"
|
|
#define FTP "ftp"
|
|
//+------------------------------------------------------------------+
|
|
//| Include the header file that defines the CQueryParam class |
|
|
//+------------------------------------------------------------------+
|
|
#include "QueryParam.mqh"
|
|
//+------------------------------------------------------------------+
|
|
//| Enum to represent different URL protocol |
|
|
//+------------------------------------------------------------------+
|
|
enum ENUM_URL_PROTOCOL
|
|
{
|
|
URL_PROTOCOL_NULL = 0, // No protocol defined
|
|
URL_PROTOCOL_HTTP, // HTTP protocol
|
|
URL_PROTOCOL_HTTPS, // HTTPS protocol
|
|
URL_PROTOCOL_WS, // WebSocket (WS) protocol
|
|
URL_PROTOCOL_WSS, // Secure WebSocket (WSS) protocol
|
|
URL_PROTOCOL_FTP // FTP protocol
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| class : CURL |
|
|
//| |
|
|
//| [PROPERTY] |
|
|
//| Name : CURL |
|
|
//| Heritage : No heritage |
|
|
//| Description : Define a class CURL to manage and manipulate URLs |
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
class CURL
|
|
{
|
|
private:
|
|
|
|
//--- Structure to hold components of a URL
|
|
struct MqlURLComponents
|
|
{
|
|
ENUM_URL_PROTOCOL protocol; // URL protocol
|
|
string host; // Host name or IP
|
|
uint port; // Port number
|
|
string path; // Path after the host
|
|
CQueryParam query_param; // Query parameters as key-value pairs
|
|
};
|
|
MqlURLComponents m_url; // Instance of MqlURL to store the URL details
|
|
string ProtocolToString(ENUM_URL_PROTOCOL protocol); // Helper method to convert protocol enum to string
|
|
|
|
public:
|
|
CURL(void);
|
|
~CURL(void);
|
|
|
|
|
|
//--- Methods to access and modify URL components
|
|
ENUM_URL_PROTOCOL GetProtocol(void) const; // Get the protocol
|
|
void SetProtocol(ENUM_URL_PROTOCOL protocol); // Set the protocol
|
|
string GetHost(void) const; // Get the host
|
|
void SetHost(const string host); // Set the host
|
|
uint GetPort(void) const; // Get the port
|
|
void SetPort(const uint port); // Set the port
|
|
string GetPath(void) const; // Get the path
|
|
void SetPath(const string path); // Set the path
|
|
CQueryParam *QueryParam(void); // Access query parameters
|
|
|
|
//--- Auxiliary methods
|
|
bool IsEqualTo(CURL &url); // Compare two URLs
|
|
string ToString(); // Show URL details as a string
|
|
|
|
//--- Methods to parse and serialize the URL
|
|
void Clear(void); // Clear/reset the URL
|
|
string GetBaseUrl(void); // Return the base URL (protocol, host, port)
|
|
string GetPathAndQuery(void); // Return the path and query part of the URL
|
|
string GetFullUrl(void); // Return the complete URL
|
|
bool ParseFromString(const string url); // Parse a URL string into components
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| Constructor |
|
|
//+------------------------------------------------------------------+
|
|
CURL::CURL(void)
|
|
{
|
|
this.Clear();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Destructor |
|
|
//+------------------------------------------------------------------+
|
|
CURL::~CURL(void)
|
|
{
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Convert URL protocol enum to string |
|
|
//+------------------------------------------------------------------+
|
|
string CURL::ProtocolToString(ENUM_URL_PROTOCOL protocol)
|
|
{
|
|
if(protocol == URL_PROTOCOL_HTTP) { return(HTTP); }
|
|
if(protocol == URL_PROTOCOL_HTTPS) { return(HTTPS); }
|
|
if(protocol == URL_PROTOCOL_WS) { return(WS); }
|
|
if(protocol == URL_PROTOCOL_WSS) { return(WSS); }
|
|
if(protocol == URL_PROTOCOL_FTP) { return(FTP); }
|
|
return(NULL);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Getter for protocol |
|
|
//+------------------------------------------------------------------+
|
|
ENUM_URL_PROTOCOL CURL::GetProtocol(void) const
|
|
{
|
|
return(m_url.protocol);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Setter for protocol |
|
|
//+------------------------------------------------------------------+
|
|
void CURL::SetProtocol(ENUM_URL_PROTOCOL protocol)
|
|
{
|
|
m_url.protocol = protocol;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Getter for host |
|
|
//+------------------------------------------------------------------+
|
|
string CURL::GetHost(void) const
|
|
{
|
|
return(m_url.host);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Setter for host |
|
|
//+------------------------------------------------------------------+
|
|
void CURL::SetHost(const string host)
|
|
{
|
|
m_url.host = host;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Getter for port |
|
|
//+------------------------------------------------------------------+
|
|
uint CURL::GetPort(void) const
|
|
{
|
|
return(m_url.port);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Setter for port |
|
|
//+------------------------------------------------------------------+
|
|
void CURL::SetPort(const uint port)
|
|
{
|
|
m_url.port = port;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Getter for path |
|
|
//+------------------------------------------------------------------+
|
|
string CURL::GetPath(void) const
|
|
{
|
|
return(m_url.path);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Setter for path |
|
|
//+------------------------------------------------------------------+
|
|
void CURL::SetPath(const string path)
|
|
{
|
|
m_url.path = path;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Accessor for query parameters (returns a pointer) |
|
|
//+------------------------------------------------------------------+
|
|
CQueryParam *CURL::QueryParam(void)
|
|
{
|
|
return(GetPointer(m_url.query_param));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Compare the current URL with another URL |
|
|
//+------------------------------------------------------------------+
|
|
bool CURL::IsEqualTo(CURL &url)
|
|
{
|
|
return (m_url.protocol == url.GetProtocol() &&
|
|
m_url.host == url.GetHost() &&
|
|
m_url.port == url.GetPort() &&
|
|
m_url.path == url.GetPath() &&
|
|
m_url.query_param.ToString() == url.QueryParam().ToString());
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Display the components of the URL as a formatted string |
|
|
//+------------------------------------------------------------------+
|
|
string CURL::ToString(void)
|
|
{
|
|
return(
|
|
"Protocol: "+EnumToString(m_url.protocol)+"\n"+
|
|
"Host: "+m_url.host+"\n"+
|
|
"Port: "+IntegerToString(m_url.port)+"\n"+
|
|
"Path: "+m_url.path+"\n"+
|
|
"Query Param: "+m_url.query_param.ToString()+"\n"
|
|
);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Clear or reset the URL structure |
|
|
//+------------------------------------------------------------------+
|
|
void CURL::Clear(void)
|
|
{
|
|
m_url.protocol = URL_PROTOCOL_NULL;
|
|
m_url.host = "";
|
|
m_url.port = 0;
|
|
m_url.path = "";
|
|
m_url.query_param.Clear();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Construct the base URL from protocol, host, and port |
|
|
//+------------------------------------------------------------------+
|
|
string CURL::GetBaseUrl(void)
|
|
{
|
|
//--- Checks if host is not null or empty
|
|
if(m_url.host != "" && m_url.host != NULL)
|
|
{
|
|
MqlURLComponents url = m_url;
|
|
|
|
//--- Set default protocol if not defined
|
|
if(url.protocol == URL_PROTOCOL_NULL)
|
|
{
|
|
url.protocol = URL_PROTOCOL_HTTPS;
|
|
}
|
|
|
|
//--- Set default port based on the protocol
|
|
if(url.port == 0)
|
|
{
|
|
url.port = (url.protocol == URL_PROTOCOL_HTTPS) ? 443 : 80;
|
|
}
|
|
|
|
//--- Construct base URL (protocol + host)
|
|
string serialized_url = this.ProtocolToString(url.protocol) + "://" + url.host;
|
|
|
|
//--- Include port in URL only if it's not the default port for the protocol
|
|
if(!(url.protocol == URL_PROTOCOL_HTTP && url.port == 80) &&
|
|
!(url.protocol == URL_PROTOCOL_HTTPS && url.port == 443))
|
|
{
|
|
serialized_url += ":" + IntegerToString(m_url.port);
|
|
}
|
|
|
|
return(serialized_url);
|
|
}
|
|
else
|
|
{
|
|
return("Error: Invalid host");
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Construct path and query string from URL components |
|
|
//+------------------------------------------------------------------+
|
|
string CURL::GetPathAndQuery(void)
|
|
{
|
|
MqlURLComponents url = m_url;
|
|
|
|
//--- Ensure path starts with a "/"
|
|
if(url.path == "")
|
|
{
|
|
url.path = "/";
|
|
}
|
|
else if(StringGetCharacter(url.path,0) != '/')
|
|
{
|
|
url.path = "/" + url.path;
|
|
}
|
|
|
|
//--- Remove any double slashes from the path
|
|
StringReplace(url.path,"//","/");
|
|
|
|
//--- Check for invalid spaces in the path
|
|
if(StringFind(url.path," ") >= 0)
|
|
{
|
|
return("Error: Invalid characters in path");
|
|
}
|
|
|
|
//--- Return the full path and query string
|
|
return(url.path + url.query_param.ToString());
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Return the complete URL (base URL + path + query) |
|
|
//+------------------------------------------------------------------+
|
|
string CURL::GetFullUrl(void)
|
|
{
|
|
return(this.GetBaseUrl() + this.GetPathAndQuery());
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Parse a URL string and extract its components |
|
|
//+------------------------------------------------------------------+
|
|
bool CURL::ParseFromString(const string url)
|
|
{
|
|
//--- Create an instance of MqlURL to hold the parsed data
|
|
MqlURLComponents urlObj;
|
|
|
|
//--- Parse protocol from the URL
|
|
int index_end_protocol = 0;
|
|
|
|
//--- Check if the URL starts with "http://"
|
|
if(StringFind(url,"http://") >= 0)
|
|
{
|
|
urlObj.protocol = URL_PROTOCOL_HTTP;
|
|
index_end_protocol = 7;
|
|
}
|
|
else if(StringFind(url,"https://") >= 0)
|
|
{
|
|
urlObj.protocol = URL_PROTOCOL_HTTPS;
|
|
index_end_protocol = 8;
|
|
}
|
|
else if(StringFind(url,"ws://") >= 0)
|
|
{
|
|
urlObj.protocol = URL_PROTOCOL_WS;
|
|
index_end_protocol = 5;
|
|
}
|
|
else if(StringFind(url,"wss://") >= 0)
|
|
{
|
|
urlObj.protocol = URL_PROTOCOL_WSS;
|
|
index_end_protocol = 6;
|
|
}
|
|
else if(StringFind(url,"ftp://") >= 0)
|
|
{
|
|
urlObj.protocol = URL_PROTOCOL_FTP;
|
|
index_end_protocol = 6;
|
|
}
|
|
else
|
|
{
|
|
return(false); // Unsupported protocol
|
|
}
|
|
|
|
//--- Separate the endpoint part after the protocol
|
|
string endpoint = StringSubstr(url,index_end_protocol); // Get the URL part after the protocol
|
|
string parts[]; // Array to hold the split components of the URL
|
|
|
|
//--- Split the endpoint by the "/" character to separate path and query components
|
|
int size = StringSplit(endpoint,StringGetCharacter("/",0),parts);
|
|
|
|
//--- Handle the host and port part of the URL
|
|
string host_port[];
|
|
|
|
//--- If the first part (host) contains a colon (":"), split it into host and port
|
|
if(StringSplit(parts[0],StringGetCharacter(":",0),host_port) > 1)
|
|
{
|
|
urlObj.host = host_port[0]; // Set the host
|
|
urlObj.port = (uint)StringToInteger(host_port[1]); // Convert and set the port
|
|
}
|
|
else
|
|
{
|
|
urlObj.host = parts[0];
|
|
|
|
//--- Set default port based on the protocol
|
|
if(urlObj.protocol == URL_PROTOCOL_HTTP)
|
|
{
|
|
urlObj.port = 80;
|
|
}
|
|
if(urlObj.protocol == URL_PROTOCOL_HTTPS)
|
|
{
|
|
urlObj.port = 443;
|
|
}
|
|
}
|
|
|
|
//--- If there's no path, default to "/"
|
|
if(size == 1)
|
|
{
|
|
urlObj.path += "/"; // Add a default root path "/"
|
|
}
|
|
|
|
//--- Loop through the remaining parts of the URL (after the host)
|
|
for(int i=1;i<size;i++)
|
|
{
|
|
//--- If the path contains an empty part, return false (invalid URL)
|
|
if(parts[i] == "")
|
|
{
|
|
return(false);
|
|
}
|
|
//--- If the part contains a "?" (indicating query parameters)
|
|
else if(StringFind(parts[i],"?") >= 0)
|
|
{
|
|
string resource_query[];
|
|
|
|
//--- Split the part by "?" to separate the resource and query
|
|
if(StringSplit(parts[i],StringGetCharacter("?",0),resource_query) > 0)
|
|
{
|
|
urlObj.path += "/"+resource_query[0];
|
|
urlObj.query_param.ParseQueryString(resource_query[1]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//--- Otherwise, add to the path as part of the URL
|
|
urlObj.path += "/"+parts[i];
|
|
}
|
|
}
|
|
|
|
//--- Assign the parsed URL object to the member variable
|
|
m_url = urlObj;
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|