We now have a current svn snapshot of libqxt in our contrib dir, and
[quassel.git] / src / contrib / libqxt-2007-10-24 / src / web / qxtscgiconnector.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) Qxt Foundation. Some rights reserved.
4 **
5 ** This file is part of the QxtWeb  module of the Qt eXTension library
6 **
7 ** This library is free software; you can redistribute it and/or modify it
8 ** under the terms of th Common Public License, version 1.0, as published by
9 ** IBM.
10 **
11 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
12 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
13 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
14 ** FITNESS FOR A PARTICULAR PURPOSE.
15 **
16 ** You should have received a copy of the CPL along with this file.
17 ** See the LICENSE file and the cpl1.0.txt file included with the source
18 ** distribution for more information. If you did not receive a copy of the
19 ** license, contact the Qxt Foundation.
20 **
21 ** <http://libqxt.org>  <foundation@libqxt.org>
22 **
23 ****************************************************************************/
24 #include "qxtscgiconnector.h"
25 #include <QTcpSocket>
26 #include <QTcpServer>
27 #include <QtDebug>
28 #include <ctime>
29 #include <QDebug>
30
31 class QxtScgiConnectorPrivate : public QTcpServer,public QxtPrivate<QxtScgiConnector>
32 {
33     QXT_DECLARE_PUBLIC(QxtScgiConnector);
34
35 protected:
36
37     void incomingConnection ( int socketDescriptor )
38     {
39         qDebug("%i, -> incomming",(int)time(NULL));
40         QTcpSocket * tcpSocket = new QTcpSocket;
41         if (!tcpSocket->setSocketDescriptor(socketDescriptor))
42         {
43             delete tcpSocket;
44             socket_m=0;
45             return;
46         }
47         socket_m=tcpSocket;
48         connect(tcpSocket,SIGNAL(disconnected()),tcpSocket,SLOT(deleteLater())); ///TODO:right. and what id the client disconnects earlier?
49         SERVER.clear();
50         int eee1=readHeaderFromSocket(tcpSocket,SERVER);
51         if (eee1)
52         {
53             tcpSocket->write("Status: 500 INTERNAL SERVER ERROR\r\ncontent-type: text/html\r\n\r\nHEADER NOT READABLE");
54         }
55
56         emit(qxt_p().incomming(SERVER));
57     }
58
59     QTcpSocket * socket_m;
60     server_t SERVER;
61
62
63     int readHeaderFromSocket(QTcpSocket * tcpSocket,server_t & SERVER)
64     {
65         if (!tcpSocket)
66             return 5012;
67
68
69         ///--------------get the header size----------------
70
71         QByteArray size_in;
72         while (!size_in.endsWith(':'))
73         {
74             if (!tcpSocket->bytesAvailable ())
75                 if (!tcpSocket->waitForReadyRead (200))
76                     return 50033;
77
78             char a[4]; ///4? yes, i know i'm paranoid about bounds.
79
80
81             if (!tcpSocket->read (a, 1 ))
82                 return 50034;
83
84             size_in+=a[0];
85
86             if (size_in.size()>20)/// after the 20ths char is an attack atemp for sure
87                 return 50034;
88
89         }
90
91
92         size_in.chop(1);
93         int size=size_in.toInt()+1;
94
95
96         if (size>10240)  ///do not accept headers over 10kb
97             return 50037;
98
99
100         ///--------------read the header------------------
101
102         while (tcpSocket->bytesAvailable ()<size)
103         {
104             if (!tcpSocket->waitForReadyRead (200))
105                 return 50033;
106         }
107         QByteArray header_in;
108         header_in.resize(size);
109
110         if (tcpSocket->read (header_in.data(), size )!=size)
111             return 50034;
112
113         if (!header_in.endsWith(','))
114             return 50090;
115         ///--------------parse the header------------------
116
117
118         int i=0;
119         QByteArray name="";
120         QByteArray a =header_in;
121         while ((i=a.indexOf('\0'))>-1)
122         {
123             if (name=="")
124             {
125                 name= a.left(i).replace('\0',"");
126             }
127             else
128             {
129                 SERVER[name]=a.left(i).replace('\0',"").replace("%20"," ");
130                 name="";
131             }
132
133             a=a.mid(i+1);
134         }
135
136
137         return 0;
138     }
139
140
141
142
143
144
145 };
146
147 QxtScgiConnector::QxtScgiConnector():QxtAbstractWebConnector()
148 {
149     QXT_INIT_PRIVATE(QxtScgiConnector);
150     qxt_d().socket_m=0;
151 }
152
153 int QxtScgiConnector::start (quint16 port,const QHostAddress & address)
154 {
155     return qxt_d().listen(address,port);
156 }
157
158 QIODevice * QxtScgiConnector::socket()
159 {
160     return qxt_d().socket_m;
161 }
162 void QxtScgiConnector::sendHeader(server_t & answer)
163 {
164     if (!answer.contains("Status"))
165         answer["Status"]="200 OK";
166     if (!answer.contains("Content-Type"))
167         answer["Content-Type"]="text/html; charset=utf-8";
168
169     server_t::const_iterator i = answer.constBegin();
170     while (i != answer.constEnd())
171     {
172         qxt_d().socket_m->write(i.key()+": "+i.value()+"\r\n");
173         ++i;
174     }
175     qxt_d().socket_m->write("\r\n");
176 }
177
178 void  QxtScgiConnector::close()
179 {
180     emit(aboutToClose());
181     qxt_d().socket_m->close();
182 }
183
184
185 QByteArray QxtScgiConnector::content(quint64 maxsize)
186 {
187     QIODevice * tcpSocket=  qxt_d().socket_m;
188
189     if (!tcpSocket)
190         return QByteArray();
191
192
193     unsigned int content_size= qxt_d().SERVER["CONTENT_LENGTH"].toUInt();
194
195     qDebug()<<"receiving content"<<content_size;
196
197
198     if (content_size<1)
199     {
200         return QByteArray();
201     }
202
203     if (content_size>maxsize)
204         content_size=maxsize;
205
206     ///--------------read the content------------------
207
208
209
210
211
212     while (tcpSocket->bytesAvailable ()<content_size)
213     {
214         if (!tcpSocket->waitForReadyRead (2000))
215             return QByteArray();
216     }
217
218     QByteArray content_in;
219     content_in.resize(content_size);
220
221
222     if (tcpSocket->read (content_in.data(), content_size )!=content_size)
223         return QByteArray();
224
225
226     tcpSocket->readAll(); //fix apache fcgi bug
227     return content_in;
228 }
229
230
231
232