OSDN Git Service

a2移行前のバックアップ。
[wordring-tm/wordring-tm.git] / http / httpserver.cpp
1 #include "settings.h"
2
3 #include "httpserver.h"
4 #include "httprequest.h"
5 #include "httphandler.h"
6
7 #include <QString>
8 #include <QByteArray>
9 #include <QList>
10
11 #include <QTcpSocket>
12
13 #include <QSettings>
14
15 #include "debug.h"
16
17 // HttpConnection -------------------------------------------------------------
18
19 HttpConnection::HttpConnection(HttpServer *server, QTcpSocket *socket)
20         : QObject(socket)
21         , m_server(server)
22         , m_handler(nullptr)
23 {
24         setup_connections(socket);
25 }
26
27 HttpConnection::~HttpConnection()
28 {
29         if(m_handler) m_server->destroy_handler(m_handler);
30 }
31
32 void HttpConnection::setup_connections(QTcpSocket *socket)
33 {
34         connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
35         connect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
36 }
37
38 void HttpConnection::delete_connections(QTcpSocket *socket)
39 {
40         disconnect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
41         disconnect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
42 }
43
44 void HttpConnection::setup_connections(HttpHandler *handler)
45 {
46         connect(this, SIGNAL(attach(QSharedPointer<HttpRequest>)),
47                         handler, SLOT(attach(QSharedPointer<HttpRequest>)));
48
49         connect(handler, SIGNAL(writeSocket(QByteArray)),
50                         this, SLOT(onWriteSocket(QByteArray)));
51         connect(handler, SIGNAL(flushSocket()), this, SLOT(onFlushSocket()));
52         connect(handler, SIGNAL(closeSocket()), this, SLOT(onCloseSocket()));
53
54         connect(handler, SIGNAL(finished()), this, SLOT(end_response()));
55 }
56
57 void HttpConnection::delete_connections(HttpHandler *handler)
58 {
59         disconnect(this, SIGNAL(attach(QSharedPointer<HttpRequest>)),
60                            handler, SLOT(attach(QSharedPointer<HttpRequest>)));
61
62         disconnect(handler, SIGNAL(writeSocket(QByteArray)),
63                            this, SLOT(onWriteSocket(QByteArray)));
64         disconnect(handler, SIGNAL(flushSocket()), this, SLOT(onFlushSocket()));
65         disconnect(handler, SIGNAL(closeSocket()), this, SLOT(onCloseSocket()));
66
67         disconnect(handler, SIGNAL(finished()), this, SLOT(end_response()));
68 }
69
70 QTcpSocket* HttpConnection::socket()
71 {
72         return qobject_cast<QTcpSocket*>(parent());
73 }
74
75 void HttpConnection::onReadyRead()
76 {
77         QTcpSocket* sock = socket();
78         assert(sock);
79         int size = sock->bytesAvailable();
80         assert(size);
81         QByteArray bytes = sock->read(size);
82         int nRead = 0;
83
84         for(int i = 0; i <= LoopLimit; i++)
85         {
86                 if(m_request.isNull())
87                 {
88                         m_request.reset(new HttpRequest);
89                         m_parser.attach(m_request.data());
90                 }
91                 if(m_request->state() == HttpRequest::Initial
92                                 || m_request->state() == HttpRequest::Partial)
93                 {
94                         int n = m_parser.push(nRead, bytes);
95                         assert(n || m_request->state() == HttpRequest::Ready);
96                         nRead += n;
97                 }
98                 if(m_request->state() == HttpRequest::Ready)
99                 {
100                         m_requests.push_back(m_request);
101                         m_parser.detach(m_request.data());
102                         m_request.clear();
103                         begin_response();
104                 }
105                 if(nRead == size) break;
106         }
107 }
108
109 void HttpConnection::onWriteSocket(QByteArray bytes)
110 {
111         QTcpSocket *sock = socket();
112         int result = sock->write(bytes);
113         assert(bytes.size() == result);
114 }
115
116 void HttpConnection::onFlushSocket()
117 {
118         socket()->flush();
119 }
120
121 void HttpConnection::onCloseSocket()
122 {
123         socket()->close();
124 }
125
126 /*!
127  * \brief 出力を開始します。
128  */
129 void HttpConnection::begin_response()
130 {
131         m_debug.clear();
132
133         if(m_handler) return; // 処理中の場合
134         if(m_requests.isEmpty()) return; // 処理すべきリクエストがない場合
135
136         QSharedPointer<HttpRequest> request(m_requests.front());
137         m_requests.pop_front();
138         m_handler = m_server->create_handler(request->method(), request->url());
139         if(!m_handler) // ハンドラが返ってこない場合、即断する。
140         {
141                 QTcpSocket *sock = socket();
142                 delete_connections(sock);
143                 sock->deleteLater();
144                 return;
145         }
146         setup_connections(m_handler);
147         emit attach(request); // ハンドラと接続する。
148 }
149
150 /*!
151  * \brief 出力を終了します。
152  */
153 void HttpConnection::end_response()
154 {
155         assert(m_handler);
156         delete_connections(m_handler);
157         m_server->destroy_handler(m_handler);
158         m_handler = nullptr;
159         begin_response();
160 }
161
162 // HttpServer -----------------------------------------------------------------
163
164 HttpServer::HttpServer(Settings *settings, QObject *parent)
165         : QObject(parent)
166         , m_settings(settings)
167         , m_server(/* QObject */new QTcpServer(this))
168         , m_handler(/* QObject */new HttpHandler(this))
169 {
170         qRegisterMetaType<QSharedPointer<HttpRequest> >("QSharedPointer<HttpRequest>");
171         /* QObject */install(new HttpModule404(this));
172         connect(m_server, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
173
174         quint16 port = m_settings->value("HttpServer/port").toUInt();
175         bool result = m_server->listen(QHostAddress::LocalHost, port);
176         if(!result) result = m_server->listen(QHostAddress::LocalHost, 0);
177         if(!result) qFatal("An error occured in HttpServer().");
178 }
179
180 quint16 HttpServer::port() const
181 {
182         return m_server->serverPort();
183 }
184
185 void HttpServer::install(HttpModule *module)
186 {
187         m_modules.push_front(module);
188 }
189
190 HttpHandler* HttpServer::create_handler(QByteArray method, QByteArray url)
191 {
192         for(HttpModule *module : m_modules)
193                 if(HttpHandler *handler = module->create_handler(method, url))
194                 {
195                         m_handlers[handler] = module;
196                         return handler;
197                 }
198         return nullptr;
199 }
200
201 void HttpServer::destroy_handler(HttpHandler *handler)
202 {
203         auto it = m_handlers.find(handler);
204         assert(it != m_handlers.end());
205         it.value()->destroy_handler(handler);
206         int n = m_handlers.remove(handler);
207         assert(n == 1);
208 }
209
210 void HttpServer::onNewConnection()
211 {
212         QTcpSocket *socket = m_server->nextPendingConnection();
213         /*ソケットによって保持*/ new HttpConnection(this, socket);
214 }
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234