Skip to content

Commit f3f11cc

Browse files
committed
First working code.
Requests are parsed partially, responses are sent partially, but not legal HTTP replies. TODO ---- * Memory management * Handle proper response headers based on what the user has sent * Handle proper request headers * Provide connection information in request object
1 parent 2df2096 commit f3f11cc

18 files changed

Lines changed: 642 additions & 140 deletions

examples/examples.pro

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
TEMPLATE = subdirs
2+
SUBDIRS += \
3+
helloworld

examples/helloworld/helloworld.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include "helloworld.h"
2+
3+
#include <QCoreApplication>
4+
#include <QDebug>
5+
6+
#include <qhttpserver.h>
7+
#include <qhttprequest.h>
8+
#include <qhttpresponse.h>
9+
10+
Hello::Hello()
11+
{
12+
QHttpServer *server = new QHttpServer;
13+
server->listen(QHostAddress::Any, 5000);
14+
connect(server, SIGNAL(newRequest(QHttpRequest*, QHttpResponse*)),
15+
this, SLOT(handle(QHttpRequest*, QHttpResponse*)));
16+
}
17+
18+
void Hello::handle(QHttpRequest *req, QHttpResponse *resp)
19+
{
20+
qDebug() << "Handling request";
21+
qDebug() << "Method" << req->method();
22+
qDebug() << "HTTP Version" << req->httpVersion();
23+
qDebug() << "URL" << req->url();
24+
resp->setHeader("Content-Type", "text/html");
25+
resp->writeHead(200);
26+
resp->write(QString("Hello World"));
27+
resp->end();
28+
}
29+
30+
int main(int argc, char **argv)
31+
{
32+
QCoreApplication app(argc, argv);
33+
34+
Hello hello;
35+
36+
app.exec();
37+
}

examples/helloworld/helloworld.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include <QObject>
2+
3+
class QHttpRequest;
4+
class QHttpResponse;
5+
6+
class Hello : public QObject
7+
{
8+
Q_OBJECT
9+
public:
10+
Hello();
11+
12+
private slots:
13+
void handle(QHttpRequest *req, QHttpResponse *resp);
14+
};

examples/helloworld/helloworld.pro

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
TARGET=helloworld
2+
QT += network
3+
QT -= gui
4+
5+
INCLUDEPATH += ../../src
6+
LIBS += -L../../lib -lqhttpserver
7+
8+
SOURCES=helloworld.cpp
9+
HEADERS=helloworld.h

qhttpserver.pro

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
TEMPLATE = subdirs
22
SUBDIRS += \
33
src\
4-
tests
4+
tests\
5+
examples

src/Makefile

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#############################################################################
22
# Makefile for building: libqhttpserver.so.0.1.0
3-
# Generated by qmake (2.01a) (Qt 4.7.1) on: Sun Jan 30 17:37:37 2011
3+
# Generated by qmake (2.01a) (Qt 4.7.1) on: Tue Feb 1 13:14:27 2011
44
# Project: src.pro
55
# Template: lib
66
# Command: /usr/bin/qmake -o Makefile src.pro
@@ -43,15 +43,28 @@ OBJECTS_DIR = ../build/
4343

4444
####### Files
4545

46-
SOURCES = qhttpserver.cpp \
47-
../http-parser/http_parser.c ../build/moc_qhttpserver.cpp
48-
OBJECTS = ../build/qhttpserver.o \
46+
SOURCES = qhttpconnection.cpp \
47+
qhttprequest.cpp \
48+
qhttpresponse.cpp \
49+
qhttpserver.cpp \
50+
../http-parser/http_parser.c ../build/moc_qhttpconnection.cpp \
51+
../build/moc_qhttpserver.cpp \
52+
../build/moc_qhttprequest.cpp \
53+
../build/moc_qhttpresponse.cpp
54+
OBJECTS = ../build/qhttpconnection.o \
55+
../build/qhttprequest.o \
56+
../build/qhttpresponse.o \
57+
../build/qhttpserver.o \
4958
../build/http_parser.o \
50-
../build/moc_qhttpserver.o
59+
../build/moc_qhttpconnection.o \
60+
../build/moc_qhttpserver.o \
61+
../build/moc_qhttprequest.o \
62+
../build/moc_qhttpresponse.o
5163
DIST = /usr/share/qt/mkspecs/common/g++.conf \
5264
/usr/share/qt/mkspecs/common/unix.conf \
5365
/usr/share/qt/mkspecs/common/linux.conf \
5466
/usr/share/qt/mkspecs/qconfig.pri \
67+
/usr/share/qt/mkspecs/modules/qt_phonon.pri \
5568
/usr/share/qt/mkspecs/modules/qt_webkit_version.pri \
5669
/usr/share/qt/mkspecs/features/qt_functions.prf \
5770
/usr/share/qt/mkspecs/features/qt_config.prf \
@@ -129,6 +142,7 @@ Makefile: src.pro /usr/share/qt/mkspecs/linux-g++/qmake.conf /usr/share/qt/mksp
129142
/usr/share/qt/mkspecs/common/unix.conf \
130143
/usr/share/qt/mkspecs/common/linux.conf \
131144
/usr/share/qt/mkspecs/qconfig.pri \
145+
/usr/share/qt/mkspecs/modules/qt_phonon.pri \
132146
/usr/share/qt/mkspecs/modules/qt_webkit_version.pri \
133147
/usr/share/qt/mkspecs/features/qt_functions.prf \
134148
/usr/share/qt/mkspecs/features/qt_config.prf \
@@ -154,6 +168,7 @@ Makefile: src.pro /usr/share/qt/mkspecs/linux-g++/qmake.conf /usr/share/qt/mksp
154168
/usr/share/qt/mkspecs/common/unix.conf:
155169
/usr/share/qt/mkspecs/common/linux.conf:
156170
/usr/share/qt/mkspecs/qconfig.pri:
171+
/usr/share/qt/mkspecs/modules/qt_phonon.pri:
157172
/usr/share/qt/mkspecs/modules/qt_webkit_version.pri:
158173
/usr/share/qt/mkspecs/features/qt_functions.prf:
159174
/usr/share/qt/mkspecs/features/qt_config.prf:
@@ -179,7 +194,7 @@ qmake: FORCE
179194

180195
dist:
181196
@$(CHK_DIR_EXISTS) ../build/qhttpserver0.1.0 || $(MKDIR) ../build/qhttpserver0.1.0
182-
$(COPY_FILE) --parents $(SOURCES) $(DIST) ../build/qhttpserver0.1.0/ && $(COPY_FILE) --parents ../http-parser/http_parser.h qhttpserver.h ../build/qhttpserver0.1.0/ && $(COPY_FILE) --parents qhttpserver.cpp ../http-parser/http_parser.c ../build/qhttpserver0.1.0/ && (cd `dirname ../build/qhttpserver0.1.0` && $(TAR) qhttpserver0.1.0.tar qhttpserver0.1.0 && $(COMPRESS) qhttpserver0.1.0.tar) && $(MOVE) `dirname ../build/qhttpserver0.1.0`/qhttpserver0.1.0.tar.gz . && $(DEL_FILE) -r ../build/qhttpserver0.1.0
197+
$(COPY_FILE) --parents $(SOURCES) $(DIST) ../build/qhttpserver0.1.0/ && $(COPY_FILE) --parents ../http-parser/http_parser.h qhttpconnection.h qhttpserver.h qhttprequest.h qhttpresponse.h ../build/qhttpserver0.1.0/ && $(COPY_FILE) --parents qhttpconnection.cpp qhttprequest.cpp qhttpresponse.cpp qhttpserver.cpp ../http-parser/http_parser.c ../build/qhttpserver0.1.0/ && (cd `dirname ../build/qhttpserver0.1.0` && $(TAR) qhttpserver0.1.0.tar qhttpserver0.1.0 && $(COMPRESS) qhttpserver0.1.0.tar) && $(MOVE) `dirname ../build/qhttpserver0.1.0`/qhttpserver0.1.0.tar.gz . && $(DEL_FILE) -r ../build/qhttpserver0.1.0
183198

184199

185200
clean:compiler_clean
@@ -201,12 +216,21 @@ mocclean: compiler_moc_header_clean compiler_moc_source_clean
201216

202217
mocables: compiler_moc_header_make_all compiler_moc_source_make_all
203218

204-
compiler_moc_header_make_all: ../build/moc_qhttpserver.cpp
219+
compiler_moc_header_make_all: ../build/moc_qhttpconnection.cpp ../build/moc_qhttpserver.cpp ../build/moc_qhttprequest.cpp ../build/moc_qhttpresponse.cpp
205220
compiler_moc_header_clean:
206-
-$(DEL_FILE) ../build/moc_qhttpserver.cpp
221+
-$(DEL_FILE) ../build/moc_qhttpconnection.cpp ../build/moc_qhttpserver.cpp ../build/moc_qhttprequest.cpp ../build/moc_qhttpresponse.cpp
222+
../build/moc_qhttpconnection.cpp: qhttpconnection.h
223+
/usr/bin/moc $(DEFINES) $(INCPATH) qhttpconnection.h -o ../build/moc_qhttpconnection.cpp
224+
207225
../build/moc_qhttpserver.cpp: qhttpserver.h
208226
/usr/bin/moc $(DEFINES) $(INCPATH) qhttpserver.h -o ../build/moc_qhttpserver.cpp
209227

228+
../build/moc_qhttprequest.cpp: qhttprequest.h
229+
/usr/bin/moc $(DEFINES) $(INCPATH) qhttprequest.h -o ../build/moc_qhttprequest.cpp
230+
231+
../build/moc_qhttpresponse.cpp: qhttpresponse.h
232+
/usr/bin/moc $(DEFINES) $(INCPATH) qhttpresponse.h -o ../build/moc_qhttpresponse.cpp
233+
210234
compiler_rcc_make_all:
211235
compiler_rcc_clean:
212236
compiler_image_collection_make_all: qmake_image_collection.cpp
@@ -226,15 +250,36 @@ compiler_clean: compiler_moc_header_clean
226250

227251
####### Compile
228252

229-
../build/qhttpserver.o: qhttpserver.cpp qhttpserver.h
253+
../build/qhttpconnection.o: qhttpconnection.cpp qhttpconnection.h \
254+
qhttprequest.h \
255+
qhttpresponse.h
256+
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o ../build/qhttpconnection.o qhttpconnection.cpp
257+
258+
../build/qhttprequest.o: qhttprequest.cpp qhttprequest.h
259+
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o ../build/qhttprequest.o qhttprequest.cpp
260+
261+
../build/qhttpresponse.o: qhttpresponse.cpp qhttpresponse.h
262+
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o ../build/qhttpresponse.o qhttpresponse.cpp
263+
264+
../build/qhttpserver.o: qhttpserver.cpp qhttpserver.h \
265+
qhttpconnection.h
230266
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o ../build/qhttpserver.o qhttpserver.cpp
231267

232268
../build/http_parser.o: ../http-parser/http_parser.c
233269
$(CC) -c $(CFLAGS) $(INCPATH) -o ../build/http_parser.o ../http-parser/http_parser.c
234270

271+
../build/moc_qhttpconnection.o: ../build/moc_qhttpconnection.cpp
272+
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o ../build/moc_qhttpconnection.o ../build/moc_qhttpconnection.cpp
273+
235274
../build/moc_qhttpserver.o: ../build/moc_qhttpserver.cpp
236275
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o ../build/moc_qhttpserver.o ../build/moc_qhttpserver.cpp
237276

277+
../build/moc_qhttprequest.o: ../build/moc_qhttprequest.cpp
278+
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o ../build/moc_qhttprequest.o ../build/moc_qhttprequest.cpp
279+
280+
../build/moc_qhttpresponse.o: ../build/moc_qhttpresponse.cpp
281+
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o ../build/moc_qhttpresponse.o ../build/moc_qhttpresponse.cpp
282+
238283
####### Install
239284

240285
install_target: first FORCE

src/qhttpconnection.cpp

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
#include "qhttpconnection.h"
2+
3+
#include <QTcpSocket>
4+
#include <QHostAddress>
5+
#include <QDebug>
6+
7+
#include <qhttprequest.h>
8+
#include <qhttpresponse.h>
9+
10+
QHttpConnection::QHttpConnection(QTcpSocket *socket, QObject *parent)
11+
: QObject(parent)
12+
, m_socket(socket)
13+
, m_parser(0)
14+
{
15+
qDebug() << "Got new connection" << socket->peerAddress() << socket->peerPort();
16+
17+
m_parser = (http_parser*)malloc(sizeof(http_parser));
18+
http_parser_init(m_parser, HTTP_REQUEST);
19+
20+
m_parserSettings.on_message_begin = MessageBegin;
21+
m_parserSettings.on_path = Path;
22+
m_parserSettings.on_query_string = 0;
23+
//m_parserSettings.on_query_string = QueryString;
24+
m_parserSettings.on_url = Url;
25+
m_parserSettings.on_fragment = Fragment;
26+
m_parserSettings.on_header_field = HeaderField;
27+
m_parserSettings.on_header_value = HeaderValue;
28+
m_parserSettings.on_headers_complete = HeadersComplete;
29+
m_parserSettings.on_body = Body;
30+
m_parserSettings.on_message_complete = MessageComplete;
31+
32+
m_parser->data = this;
33+
34+
connect(socket, SIGNAL(readyRead()), this, SLOT(parseRequest()));
35+
connect(socket, SIGNAL(disconnected()), this, SLOT(deleteLater()));
36+
}
37+
38+
QHttpConnection::~QHttpConnection()
39+
{
40+
qDebug() << "Disconnected. Deleting this connection object";
41+
delete m_socket;
42+
m_socket = 0;
43+
44+
free(m_parser);
45+
m_parser = 0;
46+
}
47+
48+
void QHttpConnection::parseRequest()
49+
{
50+
Q_ASSERT(m_parser);
51+
52+
while(m_socket->bytesAvailable())
53+
{
54+
QByteArray arr = m_socket->read(80*1024);
55+
56+
if( arr.size() < 0 ) {
57+
// TODO
58+
qDebug() << "Handle closed connection";
59+
}
60+
else {
61+
int nparsed = http_parser_execute(m_parser, &m_parserSettings, arr.data(), arr.size());
62+
if( nparsed != arr.size() ) {
63+
qDebug() << "ERROR PARSING!";
64+
}
65+
}
66+
}
67+
}
68+
69+
void QHttpConnection::write(const QByteArray &data)
70+
{
71+
m_socket->write(data);
72+
}
73+
74+
void QHttpConnection::flush()
75+
{
76+
m_socket->flush();
77+
}
78+
79+
/********************
80+
* Static Callbacks *
81+
*******************/
82+
int QHttpConnection::MessageBegin(http_parser *parser)
83+
{
84+
QHttpConnection *theConnection = (QHttpConnection *)parser->data;
85+
theConnection->m_request = new QHttpRequest(theConnection);
86+
return 0;
87+
}
88+
89+
int QHttpConnection::HeadersComplete(http_parser *parser)
90+
{
91+
qDebug() << "header complete";
92+
qDebug() << parser->method << parser->http_major << parser->http_minor;
93+
QHttpConnection *theConnection = (QHttpConnection *)parser->data;
94+
Q_ASSERT(theConnection->m_request);
95+
96+
/** set method **/
97+
QString method;
98+
switch(parser->method)
99+
{
100+
case HTTP_DELETE: method = "DELETE"; break;
101+
case HTTP_GET: method = "GET"; break;
102+
case HTTP_HEAD: method = "HEAD"; break;
103+
case HTTP_POST: method = "POST"; break;
104+
case HTTP_PUT: method = "PUT"; break;
105+
case HTTP_CONNECT: method = "CONNECT"; break;
106+
case HTTP_OPTIONS: method = "OPTIONS"; break;
107+
case HTTP_TRACE: method = "TRACE"; break;
108+
}
109+
theConnection->m_request->setMethod(method);
110+
111+
/** set version **/
112+
theConnection->m_request->setVersion(QString("%1.%2").arg(parser->http_major).arg(parser->http_minor));
113+
114+
// TODO don't create a response object just like that
115+
emit theConnection->newRequest(theConnection->m_request, new QHttpResponse(theConnection));
116+
return 0;
117+
}
118+
119+
int QHttpConnection::MessageComplete(http_parser *parser)
120+
{
121+
qDebug() << "Message complete";
122+
return 0;
123+
}
124+
125+
int QHttpConnection::Path(http_parser *parser, const char *at, size_t length)
126+
{
127+
QHttpConnection *theConnection = (QHttpConnection *)parser->data;
128+
Q_ASSERT(theConnection->m_request);
129+
QString path = QString::fromAscii(at, length);
130+
131+
QUrl url = theConnection->m_request->url();
132+
url.setPath(path);
133+
theConnection->m_request->setUrl(url);
134+
qDebug() << "GOT Path" << theConnection->m_request->url();
135+
return 0;
136+
}
137+
138+
int QHttpConnection::QueryString(http_parser *parser, const char *at, size_t length)
139+
{
140+
QHttpConnection *theConnection = (QHttpConnection *)parser->data;
141+
Q_ASSERT(theConnection->m_request);
142+
143+
qDebug() << "GOT query string" << QString::fromAscii(at, length) << "FAILING DUE TO NON-IMPLEMENTATION";
144+
Q_ASSERT(false);
145+
return 0;
146+
}
147+
148+
int QHttpConnection::Url(http_parser *parser, const char *at, size_t length)
149+
{
150+
QHttpConnection *theConnection = (QHttpConnection *)parser->data;
151+
theConnection->m_request->setUrl(QString::fromAscii(at, length));
152+
153+
qDebug() << "GOT URL" << theConnection->m_request->url();
154+
return 0;
155+
}
156+
157+
int QHttpConnection::Fragment(http_parser *parser, const char *at, size_t length)
158+
{
159+
return 0;
160+
}
161+
162+
int QHttpConnection::HeaderField(http_parser *parser, const char *at, size_t length)
163+
{
164+
return 0;
165+
}
166+
167+
int QHttpConnection::HeaderValue(http_parser *parser, const char *at, size_t length)
168+
{
169+
return 0;
170+
}
171+
172+
int QHttpConnection::Body(http_parser *parser, const char *at, size_t length)
173+
{
174+
return 0;
175+
}

0 commit comments

Comments
 (0)