1 /****************************************************************************
3 ** Copyright (C) Qxt Foundation. Some rights reserved.
5 ** This file is part of the QxtWeb module of the Qt eXTension library
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
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.
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.
21 ** <http://libqxt.org> <foundation@libqxt.org>
23 ****************************************************************************/
24 #include "qxtwebcore.h"
25 #include "qxtabstractwebconnector.h"
26 #include "qxtwebcore_p.h"
30 #include "qxtwebcontroller.h"
31 #include <QCoreApplication>
39 \class QxtWebCore QxtWebCore
41 \brief qxtweb application core class. communicates, delegates, does all of the magic ;)
44 QxtWebCore is the base class of your web application.
45 it listens to the scgi protocoll
47 construct one webcore object in the main function of your application.
48 you must contruct it AFTER QCoreApplication and BEFORe any controllers.
51 int main(int argc,char ** argv)
53 QCoreApplication app(argc,argv);
56 QxtWebController controller("root");
63 \fn static QxtWebCore* instance();
65 \fn static void send(QByteArray);
66 Send data to the client. Use this rarely, but use it always when sending binary data such as images. \n
67 normal text/html comunication should be done using the controllers echo() function \n
68 note that after you called send the first time you cannot modify the header anymore \n
69 sending may be ignored by the transport when there is no client currently handled
70 \fn static QIODevice * socket();
71 direct access to a iodevice for writing binary data. \n
72 You shouldn't use that unless it's absolutly nessesary
73 \fn static QxtError parseString(QByteArray str, post_t & POST);
74 much like phps parse_string \n
75 \fn static QByteArray readContent(int maxsize=5000);
76 reads the content from the current socket if any has sent. \n
77 returns an empty QByteArray on any error. \n
78 the content is cut at maxsize and not read from the socket. \n
79 FIXME:\warning: this function is BLOCKING. while content is read from the client, no other requests can be handled.
80 FIXME:\warning: due to paranoid timeouts this might not work for slow clients
84 static QxtWebCore * singleton_m=0;
86 //-----------------------interface----------------------------
87 QxtWebCore::QxtWebCore(QxtAbstractWebConnector * pt):QObject()
90 qFatal("you're trying to construct QxtWebCore twice!");
91 qRegisterMetaType<server_t>("server_t");
92 qRegisterMetaTypeStreamOperators<server_t>("server_t");
95 QXT_INIT_PRIVATE(QxtWebCore);
97 connect(pt,SIGNAL(aboutToClose()),this,SIGNAL(aboutToClose()));
98 connect(pt,SIGNAL(incomming(server_t)),&qxt_d(),SLOT(incomming(server_t)));
101 QxtWebCore::~QxtWebCore()
107 void QxtWebCore::send(QString a)
109 instance()->qxt_d().send(a);
111 void QxtWebCore::header(QString a,QString b)
113 instance()->qxt_d().header(a,b);
116 server_t & QxtWebCore::SERVER()
118 return instance()->qxt_d().currentservert;
121 QIODevice * QxtWebCore::socket()
123 return instance()->qxt_d().connector->socket();
126 int QxtWebCore::start (quint16 port ,const QHostAddress & address )
128 return instance()->qxt_d().connector->start(port,address);
131 void QxtWebCore::redirect(QString location,int code)
133 instance()->qxt_d().redirect(location,code);
136 QxtWebCore * QxtWebCore::instance()
139 qFatal("no QxtWebCore constructed");
142 void QxtWebCore::setCodec ( QTextCodec * codec )
144 instance()->qxt_d().decoder=codec->makeDecoder();
145 instance()->qxt_d().encoder=codec->makeEncoder();
148 void QxtWebCore::close()
150 instance()->qxt_d().close();
152 void QxtWebCore::sendHeader()
154 instance()->qxt_d().sendheader();
158 //-----------------------implementation----------------------------
163 QxtWebCorePrivate::QxtWebCorePrivate(QObject *parent):QObject(parent),QxtPrivate<QxtWebCore>()
170 void QxtWebCorePrivate::send(QString str)
175 connector->socket()->write(encoder->fromUnicode (str));
177 connector->socket()->write(str.toUtf8());
180 void QxtWebCorePrivate::close()
186 void QxtWebCorePrivate::sendheader()
191 connector->sendHeader(answer);
194 void QxtWebCorePrivate::header(QString k,QString v)
197 qWarning("headers already sent");
199 answer[encoder->fromUnicode (k)]=encoder->fromUnicode (v);
201 answer[k.toUtf8()]=v.toUtf8();
204 void QxtWebCorePrivate::redirect(QString l,int code)
206 QByteArray loc =QUrl(l).toEncoded ();
210 QxtWebCore::header("Status",QString::number(code).toUtf8());
211 QxtWebCore::header("Location",loc);
212 send(QString("<a href=\""+loc+"\">"+loc+"</a>"));
220 void QxtWebCorePrivate::incomming(server_t SERVER)
224 qDebug("%i, %s -> %s",(int)time(NULL),SERVER["HTTP_HOST"].constData(),SERVER["REQUEST_URI"].constData());
227 currentservert=SERVER;
229 emit(qxt_p().request());
231 ///--------------find controller ------------------
232 QByteArray path="404";
233 QList<QByteArray> requestsplit = SERVER["REQUEST_URI"].split('/');
234 if (requestsplit.count()>1)
236 path=requestsplit.at(1);
237 if (path.trimmed().isEmpty())path="root";
239 else if (requestsplit.count()>0)
242 ///--------------controller------------------
244 QxtWebController * controller =qFindChild<QxtWebController *> (QCoreApplication::instance(), path );
247 header("Status","404");
248 send("<h1>404 Controller ");
250 send(" not found</h1>");
252 qDebug("404 controller '%s' not found",path.constData());
256 int i=controller->invoke(SERVER);
259 header("Status","404");
261 send(QString::number(i));
262 send("</h1>Sorry,, that didn't work as expected. You might want to contact this systems administrator.");
264 if (i!=2) ///FIXME temporary solution for keepalive
280 //-----------------------helper----------------------------
282 QByteArray QxtWebCore::content(int maxsize)
284 return instance()->qxt_d().connector->content(maxsize);
288 QxtError QxtWebCore::parseString(QByteArray content_in, post_t & POST)
290 QList<QByteArray> posts = content_in.split('&');
294 QList<QByteArray> b =post.split('=');
295 if (b.count()!=2)continue;
296 POST[QUrl::fromPercentEncoding ( b[0].replace("+","%20"))]=QUrl::fromPercentEncoding ( b[1].replace("+","%20") );