~apachelogger/ubuntu-sso-client/gsoc

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
}