Skip to content

Commit 2029497

Browse files
committed
Handle a socket disconnect before a message has been fully received
1 parent cc39e38 commit 2029497

6 files changed

+94
-2
lines changed

src/qhttpconnection.cpp

+17-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ QHttpConnection::QHttpConnection(QTcpSocket *socket, QObject *parent)
3333
: QObject(parent)
3434
, m_socket(socket)
3535
, m_parser(0)
36+
, m_request(0)
3637
{
3738
qDebug() << "Got new connection" << socket->peerAddress() << socket->peerPort();
3839

@@ -50,7 +51,7 @@ QHttpConnection::QHttpConnection(QTcpSocket *socket, QObject *parent)
5051
m_parser->data = this;
5152

5253
connect(socket, SIGNAL(readyRead()), this, SLOT(parseRequest()));
53-
connect(socket, SIGNAL(disconnected()), this, SLOT(deleteLater()));
54+
connect(socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
5455
}
5556

5657
QHttpConnection::~QHttpConnection()
@@ -62,6 +63,19 @@ QHttpConnection::~QHttpConnection()
6263
m_parser = 0;
6364
}
6465

66+
void QHttpConnection::socketDisconnected()
67+
{
68+
if(m_request) {
69+
if(m_request->successful()) {
70+
return;
71+
}
72+
m_request->setSuccessful(false);
73+
emit m_request->end();
74+
}
75+
76+
deleteLater();
77+
}
78+
6579
void QHttpConnection::parseRequest()
6680
{
6781
Q_ASSERT(m_parser);
@@ -144,6 +158,7 @@ int QHttpConnection::HeadersComplete(http_parser *parser)
144158
if( parser->http_major < 1 || parser->http_minor < 1 )
145159
response->m_keepAlive = false;
146160

161+
connect(theConnection, SIGNAL(destroyed()), response, SLOT(connectionClosed()));
147162
connect(response, SIGNAL(done()), theConnection, SLOT(responseDone()));
148163

149164
// we are good to go!
@@ -157,6 +172,7 @@ int QHttpConnection::MessageComplete(http_parser *parser)
157172
QHttpConnection *theConnection = (QHttpConnection *)parser->data;
158173
Q_ASSERT(theConnection->m_request);
159174

175+
theConnection->m_request->setSuccessful(true);
160176
emit theConnection->m_request->end();
161177
return 0;
162178
}

src/qhttpconnection.h

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class QHttpConnection : public QObject
5252
private slots:
5353
void parseRequest();
5454
void responseDone();
55+
void socketDisconnected();
5556

5657
private:
5758
static int MessageBegin(http_parser *parser);

src/qhttprequest.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ QHttpRequest::QHttpRequest(QHttpConnection *connection, QObject *parent)
2828
: QObject(parent)
2929
, m_connection(connection)
3030
, m_url("http://localhost/")
31+
, m_success(false)
3132
{
3233
}
3334

src/qhttprequest.h

+34
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ class QHttpConnection;
3535

3636
typedef QHash<QString, QString> HeaderHash;
3737

38+
/* Request Methods */
39+
3840
/*! \class QHttpRequest
3941
*
4042
* The QHttpRequest class represents the header and data
@@ -169,6 +171,29 @@ class QHttpRequest : public QObject
169171
*/
170172
quint16 remotePort() const { return m_remotePort; };
171173

174+
/*!
175+
* Post data
176+
*/
177+
const QByteArray &body() const { return m_body; }
178+
179+
/*!
180+
* Set immediately before end has been emitted,
181+
* stating whether the message was properly received.
182+
* Defaults to false untiil the message has completed.
183+
*/
184+
bool successful() const { return m_success; }
185+
186+
/*!
187+
* connect to data and store all data in a QByteArray
188+
* accessible at body()
189+
*/
190+
void storeBody()
191+
{
192+
connect(this, SIGNAL(data(const QByteArray &)),
193+
this, SLOT(appendBody(const QByteArray &)),
194+
Qt::UniqueConnection);
195+
}
196+
172197
signals:
173198
/*!
174199
* This signal is emitted whenever body data is encountered
@@ -196,6 +221,7 @@ class QHttpRequest : public QObject
196221
void setVersion(const QString &version) { m_version = version; }
197222
void setUrl(const QUrl &url) { m_url = url; }
198223
void setHeaders(const HeaderHash headers) { m_headers = headers; }
224+
void setSuccessful(bool success) { m_succes = success; }
199225

200226
QHttpConnection *m_connection;
201227
HeaderHash m_headers;
@@ -204,8 +230,16 @@ class QHttpRequest : public QObject
204230
QString m_version;
205231
QString m_remoteAddress;
206232
quint16 m_remotePort;
233+
QByteArray m_body;
234+
bool m_succes;
207235

208236
friend class QHttpConnection;
237+
238+
private slots:
239+
void appendBody(const QByteArray &body)
240+
{
241+
m_body.append(body);
242+
}
209243
};
210244

211245
#endif

src/qhttpresponse.cpp

+36
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ QHttpResponse::QHttpResponse(QHttpConnection *connection)
3939
, m_keepAlive(true)
4040
, m_last(false)
4141
, m_useChunkedEncoding(false)
42+
, m_finished(false)
4243
{
4344
}
4445

@@ -48,11 +49,19 @@ QHttpResponse::~QHttpResponse()
4849

4950
void QHttpResponse::setHeader(const QString &field, const QString &value)
5051
{
52+
if(m_finished) {
53+
return;
54+
}
55+
5156
m_headers[field] = value;
5257
}
5358

5459
void QHttpResponse::writeHeader(const char *field, const QString &value)
5560
{
61+
if(m_finished) {
62+
return;
63+
}
64+
5665
m_connection->write(field);
5766
m_connection->write(": ");
5867
m_connection->write(value.toUtf8());
@@ -61,6 +70,10 @@ void QHttpResponse::writeHeader(const char *field, const QString &value)
6170

6271
void QHttpResponse::writeHeaders()
6372
{
73+
if(m_finished) {
74+
return;
75+
}
76+
6477
foreach(QString name, m_headers.keys())
6578
{
6679
QString value = m_headers[name];
@@ -121,6 +134,10 @@ void QHttpResponse::writeHeaders()
121134

122135
void QHttpResponse::writeHead(int status)
123136
{
137+
if(m_finished) {
138+
return;
139+
}
140+
124141
if( m_headerWritten ) return;
125142

126143
m_connection->write(QString("HTTP/1.1 %1 %2\r\n").arg(status).arg(STATUS_CODES[status]).toAscii());
@@ -133,6 +150,10 @@ void QHttpResponse::writeHead(int status)
133150

134151
void QHttpResponse::write(const QByteArray &data)
135152
{
153+
if(m_finished) {
154+
return;
155+
}
156+
136157
if( !m_headerWritten )
137158
{
138159
qDebug() << "You MUST call writeHead() before writing body data";
@@ -144,14 +165,29 @@ void QHttpResponse::write(const QByteArray &data)
144165

145166
void QHttpResponse::write(const QString &data)
146167
{
168+
if(m_finished) {
169+
return;
170+
}
171+
147172
m_connection->write(data.toUtf8());
148173
}
149174

150175
void QHttpResponse::end(const QString &data)
151176
{
177+
if(m_finished) {
178+
return;
179+
}
180+
m_finished = true;
181+
152182
write(data);
153183

154184
emit done();
155185
deleteLater();
156186
// TODO: end connection and delete ourselves
157187
}
188+
189+
void QHttpResponse::connectionClosed()
190+
{
191+
m_finished = true;
192+
deleteLater();
193+
}

src/qhttpresponse.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ public slots:
108108
void writeHeaders();
109109
void writeHeader(const char *field, const QString &value);
110110

111-
private:
112111
QHttpConnection *m_connection;
113112

114113
bool m_headerWritten;
@@ -122,6 +121,11 @@ public slots:
122121
bool m_keepAlive;
123122
bool m_last;
124123
bool m_useChunkedEncoding;
124+
bool m_finished;
125+
126+
private slots:
127+
void connectionClosed();
128+
125129
};
126130

127131
#endif

0 commit comments

Comments
 (0)