mirror of https://github.com/SeanOMik/znc-push.git
Extract HTTP request handling to CPushSocket
When sending HTTP requests, the notification code doesn't need to know how to build arbitrary requests. Issue #226
This commit is contained in:
parent
7817e98dba
commit
0af5679f1d
195
push.cpp
195
push.cpp
|
@ -25,15 +25,118 @@
|
||||||
#define PUSH_AWAY
|
#define PUSH_AWAY
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Debug output
|
// Forward declaration
|
||||||
#define PUSH_DEBUG 0
|
class CPushMod;
|
||||||
|
|
||||||
#if PUSH_DEBUG
|
/**
|
||||||
#define PutDebug(s) PutModule(s)
|
* Socket class for generating HTTP requests.
|
||||||
#else
|
*/
|
||||||
#define PutDebug(s) //s
|
class CPushSocket : public CSocket
|
||||||
#endif
|
{
|
||||||
|
public:
|
||||||
|
CPushSocket(CModule *p) : CSocket(p)
|
||||||
|
{
|
||||||
|
EnableReadLine();
|
||||||
|
parent = (CPushMod*) p;
|
||||||
|
first = true;
|
||||||
|
crlf = "\r\n";
|
||||||
|
user_agent = "ZNC Push";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an HTTP request.
|
||||||
|
*
|
||||||
|
* @param post POST command
|
||||||
|
* @param host Host domain
|
||||||
|
* @param url Resource path
|
||||||
|
* @param parameters Query parameters
|
||||||
|
* @param auth Basic authentication string
|
||||||
|
*/
|
||||||
|
void Request(bool post, const CString& host, const CString& url, MCString& parameters, const CString& auth="")
|
||||||
|
{
|
||||||
|
// query string for the request
|
||||||
|
bool more = false;
|
||||||
|
CString query;
|
||||||
|
CString key;
|
||||||
|
CString value;
|
||||||
|
for (MCString::iterator param = parameters.begin(); param != parameters.end(); param++)
|
||||||
|
{
|
||||||
|
key = urlencode(param->first);
|
||||||
|
value = urlencode(param->second);
|
||||||
|
|
||||||
|
if (more)
|
||||||
|
{
|
||||||
|
query += "&" + key + "=" + value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
query += key + "=" + value;
|
||||||
|
more = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request headers and POST body
|
||||||
|
CString request;
|
||||||
|
|
||||||
|
if (post)
|
||||||
|
{
|
||||||
|
request += "POST " + url + " HTTP/1.1" + crlf;
|
||||||
|
request += "Host: " + host + crlf;
|
||||||
|
request += "Content-Type: application/x-www-form-urlencoded" + crlf;
|
||||||
|
request += "Content-Length: " + CString(query.length()) + crlf;
|
||||||
|
request += "User-Agent: " + user_agent + crlf;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
request += "GET " + url + "?" + query + " HTTP/1.1" + crlf;
|
||||||
|
request += "Host: " + host + crlf;
|
||||||
|
request += "User-Agent: " + user_agent + crlf;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auth != "")
|
||||||
|
{
|
||||||
|
request += "Authorization: Basic " + auth + crlf;
|
||||||
|
}
|
||||||
|
|
||||||
|
request += crlf;
|
||||||
|
|
||||||
|
if (post)
|
||||||
|
{
|
||||||
|
request += query + crlf;
|
||||||
|
}
|
||||||
|
|
||||||
|
Write(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implemented after CPushMod
|
||||||
|
virtual void ReadLine(const CString& data);
|
||||||
|
virtual void Disconnected();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CPushMod *parent;
|
||||||
|
bool first;
|
||||||
|
|
||||||
|
// Too lazy to add CString("\r\n\") everywhere
|
||||||
|
CString crlf;
|
||||||
|
|
||||||
|
// User agent to use
|
||||||
|
CString user_agent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shorthand for encoding a string for a URL.
|
||||||
|
*
|
||||||
|
* @param str String to be encoded
|
||||||
|
* @return Encoded string
|
||||||
|
*/
|
||||||
|
CString urlencode(const CString& str)
|
||||||
|
{
|
||||||
|
return str.Escape_n(CString::EASCII, CString::EURL);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push notification module.
|
||||||
|
*/
|
||||||
class CPushMod : public CModule
|
class CPushMod : public CModule
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
@ -41,9 +144,6 @@ class CPushMod : public CModule
|
||||||
// Application name
|
// Application name
|
||||||
CString app;
|
CString app;
|
||||||
|
|
||||||
// Too lazy to add CString("\r\n\") everywhere
|
|
||||||
CString crlf;
|
|
||||||
|
|
||||||
// BASIC auth string, needs to be encoded each time username/secret is changed
|
// BASIC auth string, needs to be encoded each time username/secret is changed
|
||||||
CString notifo_auth;
|
CString notifo_auth;
|
||||||
|
|
||||||
|
@ -51,9 +151,6 @@ class CPushMod : public CModule
|
||||||
CString notifo_host;
|
CString notifo_host;
|
||||||
CString notifo_url;
|
CString notifo_url;
|
||||||
|
|
||||||
// User agent to use
|
|
||||||
CString user_agent;
|
|
||||||
|
|
||||||
// Time last notification was sent for a given context
|
// Time last notification was sent for a given context
|
||||||
map <CString, unsigned int> last_notification_time;
|
map <CString, unsigned int> last_notification_time;
|
||||||
|
|
||||||
|
@ -77,13 +174,11 @@ class CPushMod : public CModule
|
||||||
|
|
||||||
MODCONSTRUCTOR(CPushMod) {
|
MODCONSTRUCTOR(CPushMod) {
|
||||||
app = "ZNC";
|
app = "ZNC";
|
||||||
crlf = "\r\n";
|
|
||||||
|
|
||||||
idle_time = time(NULL);
|
idle_time = time(NULL);
|
||||||
notifo_auth = "";
|
notifo_auth = "";
|
||||||
notifo_host = "api.notifo.com";
|
notifo_host = "api.notifo.com";
|
||||||
notifo_url = "/v1/send_notification";
|
notifo_url = "/v1/send_notification";
|
||||||
user_agent = "ZNC Push";
|
|
||||||
|
|
||||||
// Current user
|
// Current user
|
||||||
user = GetUser();
|
user = GetUser();
|
||||||
|
@ -112,21 +207,27 @@ class CPushMod : public CModule
|
||||||
// Notification settings
|
// Notification settings
|
||||||
defaults["message_length"] = "100";
|
defaults["message_length"] = "100";
|
||||||
defaults["message_uri"] = "";
|
defaults["message_uri"] = "";
|
||||||
|
|
||||||
|
defaults["debug"] = "off";
|
||||||
}
|
}
|
||||||
virtual ~CPushMod() {}
|
virtual ~CPushMod() {}
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shorthand for encoding a string for a URL.
|
* Debugging messages. Prints to *push when the debug option is enabled.
|
||||||
*
|
*
|
||||||
* @param str String to be encoded
|
* @param data Debug message
|
||||||
* @return Encoded string
|
|
||||||
*/
|
*/
|
||||||
CString urlencode(const CString& str)
|
void PutDebug(const CString& data)
|
||||||
{
|
{
|
||||||
return str.Escape_n(CString::EASCII, CString::EURL);
|
if (options["debug"] == "on")
|
||||||
|
{
|
||||||
|
PutModule(data);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Re-encode the authentication credentials.
|
* Re-encode the authentication credentials.
|
||||||
|
@ -197,28 +298,17 @@ class CPushMod : public CModule
|
||||||
replace["{unixtime}"] = CString(time(NULL));
|
replace["{unixtime}"] = CString(time(NULL));
|
||||||
CString uri = expand(options["message_uri"], replace);
|
CString uri = expand(options["message_uri"], replace);
|
||||||
|
|
||||||
// POST body parameters for the request
|
MCString params;
|
||||||
CString post = "to=" + urlencode(options["username"]);
|
params["to"] = options["username"];
|
||||||
post += "&msg=" + urlencode(short_message);
|
params["msg"] = short_message;
|
||||||
post += "&label=" + urlencode(app);
|
params["label"] = app;
|
||||||
post += "&title=" + urlencode(title);
|
params["title"] = title;
|
||||||
post += "&uri=" + urlencode(uri);
|
params["uri"] = uri;
|
||||||
|
|
||||||
// Request headers and POST body
|
|
||||||
CString request = "POST " + notifo_url + " HTTP/1.1" + crlf;
|
|
||||||
request += "Host: " + notifo_host + crlf;
|
|
||||||
request += "Content-Type: application/x-www-form-urlencoded" + crlf;
|
|
||||||
request += "Content-Length: " + CString(post.length()) + crlf;
|
|
||||||
request += "User-Agent: " + user_agent + crlf;
|
|
||||||
request += "Authorization: Basic " + notifo_auth + crlf;
|
|
||||||
request += crlf;
|
|
||||||
request += post + crlf;
|
|
||||||
|
|
||||||
// Create the socket connection, write to it, and add it to the queue
|
// Create the socket connection, write to it, and add it to the queue
|
||||||
CSocket *sock = new CSocket(this);
|
CPushSocket *sock = new CPushSocket(this);
|
||||||
sock->Connect(notifo_host, 443, true);
|
sock->Connect(notifo_host, 443, true);
|
||||||
sock->Write(request);
|
sock->Request(true, notifo_host, notifo_url, params, notifo_auth);
|
||||||
sock->Close(Csock::CLT_AFTERWRITE);
|
|
||||||
AddSocket(sock);
|
AddSocket(sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1112,4 +1202,29 @@ class CPushMod : public CModule
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read each line of data returned from the HTTP request.
|
||||||
|
*/
|
||||||
|
void CPushSocket::ReadLine(const CString& data)
|
||||||
|
{
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
CString status = data.Token(1);
|
||||||
|
CString message = data.Token(2, true);
|
||||||
|
|
||||||
|
parent->PutDebug(status);
|
||||||
|
parent->PutDebug(message);
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parent->PutDebug(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPushSocket::Disconnected()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
MODULEDEFS(CPushMod, "Send highlights and personal messages to a push notification service")
|
MODULEDEFS(CPushMod, "Send highlights and personal messages to a push notification service")
|
||||||
|
|
Loading…
Reference in New Issue