|
48.1.35
by Harald Sitter
add license headers |
1 |
/*
|
2 |
Copyright © 2010 Harald Sitter <apachelogger@ubuntu.com>
|
|
3 |
||
4 |
This program is free software; you can redistribute it and/or
|
|
5 |
modify it under the terms of the GNU General Public License as
|
|
6 |
published by the Free Software Foundation; either version 2 of
|
|
7 |
the License or (at your option) version 3 or any later version
|
|
8 |
accepted by the membership of KDE e.V. (or its successor approved
|
|
9 |
by the membership of KDE e.V.), which shall act as a proxy
|
|
10 |
defined in Section 14 of version 3 of the license.
|
|
11 |
||
12 |
This program is distributed in the hope that it will be useful,
|
|
13 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15 |
GNU General Public License for more details.
|
|
16 |
||
17 |
You should have received a copy of the GNU General Public License
|
|
18 |
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
19 |
*/
|
|
20 |
||
|
48.1.16
by Harald Sitter
Add httpdaemon + fix all sorts of wrongness + implement oauth + do all sorts of new wrongness + fix some more wrongness in CMakeListst |
21 |
#include "HttpDaemon.h"
|
22 |
||
23 |
#include <QtCore/QStringList>
|
|
|
256
by Harald Sitter
more performance, less heap, more reliable, more generic, simply put more awesome |
24 |
#include <QtCore/QUrl>
|
|
48.1.16
by Harald Sitter
Add httpdaemon + fix all sorts of wrongness + implement oauth + do all sorts of new wrongness + fix some more wrongness in CMakeListst |
25 |
#include <QtNetwork/QTcpSocket>
|
26 |
||
|
167
by Harald Sitter
httpd only reacts to callbacks with appropriate nonce |
27 |
static const int INIT_NONCE = -1; |
28 |
||
|
242
by Harald Sitter
astyle++ |
29 |
HttpDaemon::HttpDaemon(quint16 port, QObject *parent) : |
30 |
QTcpServer(parent), |
|
31 |
m_nonce(INIT_NONCE) |
|
32 |
{
|
|
33 |
listen(QHostAddress::LocalHost, port); |
|
34 |
}
|
|
35 |
||
36 |
int HttpDaemon::nonce() |
|
37 |
{
|
|
38 |
if (m_nonce == INIT_NONCE) { |
|
39 |
qsrand(100000); |
|
40 |
m_nonce = qrand(); |
|
41 |
}
|
|
42 |
return m_nonce; |
|
43 |
}
|
|
44 |
||
45 |
void HttpDaemon::incomingConnection(int socket) |
|
46 |
{
|
|
47 |
QTcpSocket *s = new QTcpSocket(this); |
|
48 |
connect(s, SIGNAL(readyRead()), this, SLOT(readClient())); |
|
49 |
connect(s, SIGNAL(disconnected()), this, SLOT(discardClient())); |
|
50 |
s->setSocketDescriptor(socket); |
|
51 |
}
|
|
52 |
||
53 |
void HttpDaemon::readClient() |
|
54 |
{
|
|
55 |
QTcpSocket *socket = (QTcpSocket *)sender(); |
|
56 |
||
57 |
if (!socket->canReadLine()) { |
|
58 |
return; |
|
59 |
}
|
|
60 |
||
61 |
qDebug() << "reading from socket"; |
|
62 |
||
63 |
QStringList tokens = QString(socket->readLine()).split(QRegExp("[ \r\n][ \r\n]*")); |
|
64 |
qDebug() << tokens; |
|
65 |
||
66 |
if (tokens[0] != "GET" || !tokens[1].startsWith(QLatin1String("/?"))) { |
|
67 |
emit parsingFailed(); |
|
68 |
} else { // GET and tokens provided -> do processing |
|
|
256
by Harald Sitter
more performance, less heap, more reliable, more generic, simply put more awesome |
69 |
const QList<QPair<QString, QString> > items = QUrl(tokens[1]).queryItems(); |
|
242
by Harald Sitter
astyle++ |
70 |
|
71 |
QHash<QString, QString> paramHash; |
|
|
256
by Harald Sitter
more performance, less heap, more reliable, more generic, simply put more awesome |
72 |
typedef QPair<QString, QString> QStringPair; |
73 |
Q_FOREACH(const QStringPair &item, items) { |
|
74 |
paramHash.insert(item.first, item.second); |
|
|
167
by Harald Sitter
httpd only reacts to callbacks with appropriate nonce |
75 |
}
|
|
242
by Harald Sitter
astyle++ |
76 |
|
77 |
if (!paramHash.contains("nonce") || paramHash.value("nonce").toInt() != m_nonce) { |
|
78 |
// If the nonce is not what we expected, just reject the call assuming
|
|
79 |
// that it was targetting another daemon previously using this port.
|
|
|
167
by Harald Sitter
httpd only reacts to callbacks with appropriate nonce |
80 |
return; |
81 |
}
|
|
82 |
||
|
242
by Harald Sitter
astyle++ |
83 |
if (paramHash.contains("return")) { |
84 |
QString r = paramHash.value("return"); |
|
85 |
paramHash.remove("return"); |
|
86 |
||
87 |
QTextStream os(socket); |
|
88 |
os.setAutoDetectUnicode(true); |
|
89 |
os << "HTTP/1.0 200 Ok\r\n" |
|
90 |
"Content-Type: text/html; charset=\"utf-8\"\r\n" |
|
91 |
"\r\n" |
|
92 |
"<html><head>"
|
|
93 |
"<meta http-equiv=\"refresh\" content=\"0;url=" << r << "\">" |
|
94 |
"</head><body>"
|
|
95 |
"<p>You should now automatically <a"
|
|
96 |
"href=\"" << r << "\">return to " << r << "</a>.</p>" |
|
97 |
"</body></html>"; |
|
98 |
socket->close(); |
|
99 |
}
|
|
100 |
||
101 |
// FIXME: It appears that the emitting is blocking, so ideally
|
|
102 |
// this should be moved to the very bottom of this if-block as to
|
|
103 |
// prevent any timing issues at all!
|
|
104 |
// Alternatively we could run the daemon in a QThread?
|
|
105 |
if (paramHash.contains("oauth_token") && paramHash.contains("oauth_token")) { |
|
|
253
by Harald Sitter
random cleanup |
106 |
emit gotToken(paramHash.value("oauth_token"), |
107 |
paramHash.value("oauth_verifier")); |
|
|
242
by Harald Sitter
astyle++ |
108 |
|
109 |
// Clean, so we can ensure all did go well later on.
|
|
110 |
paramHash.remove("oauth_token"); |
|
111 |
paramHash.remove("oauth_verifier"); |
|
112 |
} else { |
|
113 |
emit authDenied(); |
|
114 |
}
|
|
115 |
||
116 |
if (paramHash.size() != 0) { |
|
117 |
emit gotInvalidParams(); |
|
118 |
}
|
|
119 |
}
|
|
120 |
||
121 |
// Once we got called back we can stop listening.
|
|
122 |
close(); |
|
123 |
}
|
|
124 |
||
125 |
void HttpDaemon::discardClient() |
|
126 |
{
|
|
127 |
QTcpSocket *socket = (QTcpSocket *)sender(); |
|
128 |
socket->deleteLater(); |
|
129 |
}
|