#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 headers; typedef std::list > cookie; std::vector cookies; HTTPReply() : error(HTTP_ERROR_OK), length(0) { } 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 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 soneone */ struct HTTPMessage { std::map headers; std::map cookies; std::map get_data; std::map 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 void OnRequest(HTTPProvider *, const Anope::string &, HTTPClient *, HTTPMessage &, HTTPReply &) = 0; }; class HTTPClient : public ClientSocket, public BufferedSocket, public BinarySocket { protected: void WriteClient(const Anope::string &message) { BinarySocket::Write(message + "\r\n"); } public: HTTPClient(ListenSocket *l, int f, const sockaddrs &a) : ClientSocket(l, a), BufferedSocket(), BinarySocket() { } virtual const Anope::string GetIP() { return this->clientaddr.addr(); } bool ProcessRead() anope_override { return BufferedSocket::ProcessRead(); } bool ProcessWrite() anope_override { return !BinarySocket::ProcessWrite() || BinarySocket::WriteBuffer.empty() ? false : true; } void Write(const char *buffer, size_t l) anope_override { BinarySocket::Write(buffer, l); } virtual void SendError(HTTPError err, const Anope::string &msg) = 0; virtual void SendReply(HTTPReply *) = 0; }; class HTTPProvider : public Service, public ListenSocket { Anope::string ip; unsigned short port; public: Anope::string ext_ip; std::vector ext_headers; HTTPProvider(Module *c, const Anope::string &n, const Anope::string &i, const unsigned short p) : Service(c, "HTTPProvider", n), ListenSocket(i, p, i.find(':') != Anope::string::npos), ip(i), port(p) { } const Anope::string &GetIP() const { return this->ip; } unsigned short GetPort() const { return this->port; } 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; default: dst += src[i]; } } return dst; } } #endif // ANOPE_HTTPD_H