OSDN Git Service

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