mirror of
git://git.acid.vegas/anope.git
synced 2024-11-14 19:56:42 +00:00
244 lines
4.9 KiB
C++
244 lines
4.9 KiB
C++
/*
|
|
*
|
|
* (C) 2012-2022 Anope Team
|
|
* Contact us at team@anope.org
|
|
*
|
|
* Please read COPYING and README for further details.
|
|
*/
|
|
|
|
#ifndef ANOPE_HTTPD_H
|
|
#define ANOPE_HTTPD_H
|
|
|
|
enum HTTPError
|
|
{
|
|
HTTP_ERROR_OK = 200,
|
|
HTTP_FOUND = 302,
|
|
HTTP_BAD_REQUEST = 400,
|
|
HTTP_PAGE_NOT_FOUND = 404,
|
|
HTTP_NOT_SUPPORTED = 505
|
|
};
|
|
|
|
/* A message to someone */
|
|
struct HTTPReply
|
|
{
|
|
HTTPError error;
|
|
Anope::string content_type;
|
|
std::map<Anope::string, Anope::string, ci::less> headers;
|
|
typedef std::list<std::pair<Anope::string, Anope::string> > cookie;
|
|
std::vector<cookie> cookies;
|
|
|
|
HTTPReply() : error(HTTP_ERROR_OK), length(0) { }
|
|
|
|
HTTPReply(const HTTPReply& other) : error(other.error), length(other.length)
|
|
{
|
|
content_type = other.content_type;
|
|
headers = other.headers;
|
|
cookies = other.cookies;
|
|
|
|
for (unsigned i = 0; i < other.out.size(); ++i)
|
|
out.push_back(new Data(other.out[i]->buf, other.out[i]->len));
|
|
}
|
|
|
|
~HTTPReply()
|
|
{
|
|
for (unsigned i = 0; i < out.size(); ++i)
|
|
delete out[i];
|
|
out.clear();
|
|
}
|
|
|
|
struct Data
|
|
{
|
|
char *buf;
|
|
size_t len;
|
|
|
|
Data(const char *b, size_t l)
|
|
{
|
|
this->buf = new char[l];
|
|
memcpy(this->buf, b, l);
|
|
this->len = l;
|
|
}
|
|
|
|
~Data()
|
|
{
|
|
delete [] buf;
|
|
}
|
|
};
|
|
|
|
std::deque<Data *> out;
|
|
size_t length;
|
|
|
|
void Write(const Anope::string &message)
|
|
{
|
|
this->out.push_back(new Data(message.c_str(), message.length()));
|
|
this->length += message.length();
|
|
}
|
|
|
|
void Write(const char *b, size_t l)
|
|
{
|
|
this->out.push_back(new Data(b, l));
|
|
this->length += l;
|
|
}
|
|
};
|
|
|
|
/* A message from someone */
|
|
struct HTTPMessage
|
|
{
|
|
std::map<Anope::string, Anope::string> headers;
|
|
std::map<Anope::string, Anope::string> cookies;
|
|
std::map<Anope::string, Anope::string> get_data;
|
|
std::map<Anope::string, Anope::string> post_data;
|
|
Anope::string content;
|
|
};
|
|
|
|
class HTTPClient;
|
|
class HTTPProvider;
|
|
|
|
class HTTPPage : public Base
|
|
{
|
|
Anope::string url;
|
|
Anope::string content_type;
|
|
|
|
public:
|
|
HTTPPage(const Anope::string &u, const Anope::string &ct = "text/html") : url(u), content_type(ct) { }
|
|
|
|
const Anope::string &GetURL() const { return this->url; }
|
|
|
|
const Anope::string &GetContentType() const { return this->content_type; }
|
|
|
|
/** Called when this page is requested
|
|
* @param The server this page is on
|
|
* @param The page name
|
|
* @param The client requesting the page
|
|
* @param The HTTP header sent from the client to request the page
|
|
* @param The HTTP header that will be sent back to the client
|
|
*/
|
|
virtual bool OnRequest(HTTPProvider *, const Anope::string &, HTTPClient *, HTTPMessage &, HTTPReply &) = 0;
|
|
};
|
|
|
|
class HTTPClient : public ClientSocket, public BinarySocket, public Base
|
|
{
|
|
protected:
|
|
void WriteClient(const Anope::string &message)
|
|
{
|
|
BinarySocket::Write(message + "\r\n");
|
|
}
|
|
|
|
public:
|
|
HTTPClient(ListenSocket *l, int f, const sockaddrs &a) : ClientSocket(l, a), BinarySocket() { }
|
|
|
|
virtual const Anope::string GetIP()
|
|
{
|
|
return this->clientaddr.addr();
|
|
}
|
|
|
|
virtual void SendError(HTTPError err, const Anope::string &msg) = 0;
|
|
virtual void SendReply(HTTPReply *) = 0;
|
|
};
|
|
|
|
class HTTPProvider : public ListenSocket, public Service
|
|
{
|
|
Anope::string ip;
|
|
unsigned short port;
|
|
bool ssl;
|
|
public:
|
|
std::vector<Anope::string> ext_ips;
|
|
std::vector<Anope::string> ext_headers;
|
|
|
|
HTTPProvider(Module *c, const Anope::string &n, const Anope::string &i, const unsigned short p, bool s) : ListenSocket(i, p, i.find(':') != Anope::string::npos), Service(c, "HTTPProvider", n), ip(i), port(p), ssl(s) { }
|
|
|
|
const Anope::string &GetIP() const
|
|
{
|
|
return this->ip;
|
|
}
|
|
|
|
unsigned short GetPort() const
|
|
{
|
|
return this->port;
|
|
}
|
|
|
|
bool IsSSL() const
|
|
{
|
|
return this->ssl;
|
|
}
|
|
|
|
virtual bool RegisterPage(HTTPPage *page) = 0;
|
|
virtual void UnregisterPage(HTTPPage *page) = 0;
|
|
virtual HTTPPage* FindPage(const Anope::string &name) = 0;
|
|
};
|
|
|
|
namespace HTTPUtils
|
|
{
|
|
inline Anope::string URLDecode(const Anope::string &url)
|
|
{
|
|
Anope::string decoded;
|
|
|
|
for (unsigned i = 0; i < url.length(); ++i)
|
|
{
|
|
const char& c = url[i];
|
|
|
|
if (c == '%' && i + 2 < url.length())
|
|
{
|
|
Anope::string dest;
|
|
Anope::Unhex(url.substr(i + 1, 2), dest);
|
|
decoded += dest;
|
|
i += 2;
|
|
}
|
|
else if (c == '+')
|
|
decoded += ' ';
|
|
else
|
|
decoded += c;
|
|
}
|
|
|
|
return decoded;
|
|
}
|
|
|
|
inline Anope::string URLEncode(const Anope::string &url)
|
|
{
|
|
Anope::string encoded;
|
|
|
|
for (unsigned i = 0; i < url.length(); ++i)
|
|
{
|
|
const char& c = url[i];
|
|
|
|
if (isalnum(c) || c == '.' || c == '-' || c == '*' || c == '_')
|
|
encoded += c;
|
|
else if (c == ' ')
|
|
encoded += '+';
|
|
else
|
|
encoded += "%" + Anope::Hex(c);
|
|
}
|
|
|
|
return encoded;
|
|
}
|
|
|
|
inline Anope::string Escape(const Anope::string &src)
|
|
{
|
|
Anope::string dst;
|
|
|
|
for (unsigned i = 0; i < src.length(); ++i)
|
|
{
|
|
switch (src[i])
|
|
{
|
|
case '<':
|
|
dst += "<";
|
|
break;
|
|
case '>':
|
|
dst += ">";
|
|
break;
|
|
case '"':
|
|
dst += """;
|
|
break;
|
|
case '&':
|
|
dst += "&";
|
|
break;
|
|
default:
|
|
dst += src[i];
|
|
}
|
|
}
|
|
|
|
return dst;
|
|
}
|
|
}
|
|
|
|
#endif // ANOPE_HTTPD_H
|