OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include <algorithm> | |
12 | |
13 #include "webrtc/base/httpcommon-inl.h" | |
14 | |
15 #include "webrtc/base/asyncsocket.h" | |
16 #include "webrtc/base/checks.h" | |
17 #include "webrtc/base/httpserver.h" | |
18 #include "webrtc/base/logging.h" | |
19 #include "webrtc/base/socketstream.h" | |
20 #include "webrtc/base/thread.h" | |
21 | |
22 namespace rtc { | |
23 | |
24 /////////////////////////////////////////////////////////////////////////////// | |
25 // HttpServer | |
26 /////////////////////////////////////////////////////////////////////////////// | |
27 | |
28 HttpServer::HttpServer() : next_connection_id_(1), closing_(false) { | |
29 } | |
30 | |
31 HttpServer::~HttpServer() { | |
32 if (closing_) { | |
33 LOG(LS_WARNING) << "HttpServer::CloseAll has not completed"; | |
34 } | |
35 for (ConnectionMap::iterator it = connections_.begin(); | |
36 it != connections_.end(); | |
37 ++it) { | |
38 StreamInterface* stream = it->second->EndProcess(); | |
39 delete stream; | |
40 delete it->second; | |
41 } | |
42 } | |
43 | |
44 int | |
45 HttpServer::HandleConnection(StreamInterface* stream) { | |
46 int connection_id = next_connection_id_++; | |
47 RTC_DCHECK(connection_id != HTTP_INVALID_CONNECTION_ID); | |
48 Connection* connection = new Connection(connection_id, this); | |
49 connections_.insert(ConnectionMap::value_type(connection_id, connection)); | |
50 connection->BeginProcess(stream); | |
51 return connection_id; | |
52 } | |
53 | |
54 void | |
55 HttpServer::Respond(HttpServerTransaction* transaction) { | |
56 int connection_id = transaction->connection_id(); | |
57 if (Connection* connection = Find(connection_id)) { | |
58 connection->Respond(transaction); | |
59 } else { | |
60 delete transaction; | |
61 // We may be tempted to SignalHttpComplete, but that implies that a | |
62 // connection still exists. | |
63 } | |
64 } | |
65 | |
66 void | |
67 HttpServer::Close(int connection_id, bool force) { | |
68 if (Connection* connection = Find(connection_id)) { | |
69 connection->InitiateClose(force); | |
70 } | |
71 } | |
72 | |
73 void | |
74 HttpServer::CloseAll(bool force) { | |
75 if (connections_.empty()) { | |
76 SignalCloseAllComplete(this); | |
77 return; | |
78 } | |
79 closing_ = true; | |
80 std::list<Connection*> connections; | |
81 for (ConnectionMap::const_iterator it = connections_.begin(); | |
82 it != connections_.end(); ++it) { | |
83 connections.push_back(it->second); | |
84 } | |
85 for (std::list<Connection*>::const_iterator it = connections.begin(); | |
86 it != connections.end(); ++it) { | |
87 (*it)->InitiateClose(force); | |
88 } | |
89 } | |
90 | |
91 HttpServer::Connection* | |
92 HttpServer::Find(int connection_id) { | |
93 ConnectionMap::iterator it = connections_.find(connection_id); | |
94 if (it == connections_.end()) | |
95 return nullptr; | |
96 return it->second; | |
97 } | |
98 | |
99 void | |
100 HttpServer::Remove(int connection_id) { | |
101 ConnectionMap::iterator it = connections_.find(connection_id); | |
102 if (it == connections_.end()) { | |
103 RTC_NOTREACHED(); | |
104 return; | |
105 } | |
106 Connection* connection = it->second; | |
107 connections_.erase(it); | |
108 SignalConnectionClosed(this, connection_id, connection->EndProcess()); | |
109 delete connection; | |
110 if (closing_ && connections_.empty()) { | |
111 closing_ = false; | |
112 SignalCloseAllComplete(this); | |
113 } | |
114 } | |
115 | |
116 /////////////////////////////////////////////////////////////////////////////// | |
117 // HttpServer::Connection | |
118 /////////////////////////////////////////////////////////////////////////////// | |
119 | |
120 HttpServer::Connection::Connection(int connection_id, HttpServer* server) | |
121 : connection_id_(connection_id), | |
122 server_(server), | |
123 current_(nullptr), | |
124 signalling_(false), | |
125 close_(false) {} | |
126 | |
127 HttpServer::Connection::~Connection() { | |
128 // It's possible that an object hosted inside this transaction signalled | |
129 // an event which caused the connection to close. | |
130 Thread::Current()->Dispose(current_); | |
131 } | |
132 | |
133 void | |
134 HttpServer::Connection::BeginProcess(StreamInterface* stream) { | |
135 base_.notify(this); | |
136 base_.attach(stream); | |
137 current_ = new HttpServerTransaction(connection_id_); | |
138 if (base_.mode() != HM_CONNECT) | |
139 base_.recv(¤t_->request); | |
140 } | |
141 | |
142 StreamInterface* | |
143 HttpServer::Connection::EndProcess() { | |
144 base_.notify(nullptr); | |
145 base_.abort(HE_DISCONNECTED); | |
146 return base_.detach(); | |
147 } | |
148 | |
149 void | |
150 HttpServer::Connection::Respond(HttpServerTransaction* transaction) { | |
151 RTC_DCHECK(current_ == nullptr); | |
152 current_ = transaction; | |
153 if (current_->response.begin() == current_->response.end()) { | |
154 current_->response.set_error(HC_INTERNAL_SERVER_ERROR); | |
155 } | |
156 bool keep_alive = HttpShouldKeepAlive(current_->request); | |
157 current_->response.setHeader(HH_CONNECTION, | |
158 keep_alive ? "Keep-Alive" : "Close", | |
159 false); | |
160 close_ = !HttpShouldKeepAlive(current_->response); | |
161 base_.send(¤t_->response); | |
162 } | |
163 | |
164 void | |
165 HttpServer::Connection::InitiateClose(bool force) { | |
166 bool request_in_progress = (HM_SEND == base_.mode()) || (nullptr == current_); | |
167 if (!signalling_ && (force || !request_in_progress)) { | |
168 server_->Remove(connection_id_); | |
169 } else { | |
170 close_ = true; | |
171 } | |
172 } | |
173 | |
174 // | |
175 // IHttpNotify Implementation | |
176 // | |
177 | |
178 HttpError | |
179 HttpServer::Connection::onHttpHeaderComplete(bool chunked, size_t& data_size) { | |
180 if (data_size == SIZE_UNKNOWN) { | |
181 data_size = 0; | |
182 } | |
183 RTC_DCHECK(current_ != nullptr); | |
184 bool custom_document = false; | |
185 server_->SignalHttpRequestHeader(server_, current_, &custom_document); | |
186 if (!custom_document) { | |
187 current_->request.document.reset(new MemoryStream); | |
188 } | |
189 return HE_NONE; | |
190 } | |
191 | |
192 void | |
193 HttpServer::Connection::onHttpComplete(HttpMode mode, HttpError err) { | |
194 if (mode == HM_SEND) { | |
195 RTC_DCHECK(current_ != nullptr); | |
196 signalling_ = true; | |
197 server_->SignalHttpRequestComplete(server_, current_, err); | |
198 signalling_ = false; | |
199 if (close_) { | |
200 // Force a close | |
201 err = HE_DISCONNECTED; | |
202 } | |
203 } | |
204 if (err != HE_NONE) { | |
205 server_->Remove(connection_id_); | |
206 } else if (mode == HM_CONNECT) { | |
207 base_.recv(¤t_->request); | |
208 } else if (mode == HM_RECV) { | |
209 RTC_DCHECK(current_ != nullptr); | |
210 // TODO: do we need this? | |
211 //request_.document_->rewind(); | |
212 HttpServerTransaction* transaction = current_; | |
213 current_ = nullptr; | |
214 server_->SignalHttpRequest(server_, transaction); | |
215 } else if (mode == HM_SEND) { | |
216 Thread::Current()->Dispose(current_->response.document.release()); | |
217 current_->request.clear(true); | |
218 current_->response.clear(true); | |
219 base_.recv(¤t_->request); | |
220 } else { | |
221 RTC_NOTREACHED(); | |
222 } | |
223 } | |
224 | |
225 void | |
226 HttpServer::Connection::onHttpClosed(HttpError err) { | |
227 server_->Remove(connection_id_); | |
228 } | |
229 | |
230 /////////////////////////////////////////////////////////////////////////////// | |
231 // HttpListenServer | |
232 /////////////////////////////////////////////////////////////////////////////// | |
233 | |
234 HttpListenServer::HttpListenServer() { | |
235 SignalConnectionClosed.connect(this, &HttpListenServer::OnConnectionClosed); | |
236 } | |
237 | |
238 HttpListenServer::~HttpListenServer() { | |
239 } | |
240 | |
241 int HttpListenServer::Listen(const SocketAddress& address) { | |
242 AsyncSocket* sock = | |
243 Thread::Current()->socketserver()->CreateAsyncSocket(address.family(), | |
244 SOCK_STREAM); | |
245 if (!sock) { | |
246 return SOCKET_ERROR; | |
247 } | |
248 listener_.reset(sock); | |
249 listener_->SignalReadEvent.connect(this, &HttpListenServer::OnReadEvent); | |
250 if ((listener_->Bind(address) != SOCKET_ERROR) && | |
251 (listener_->Listen(5) != SOCKET_ERROR)) | |
252 return 0; | |
253 return listener_->GetError(); | |
254 } | |
255 | |
256 bool HttpListenServer::GetAddress(SocketAddress* address) const { | |
257 if (!listener_) { | |
258 return false; | |
259 } | |
260 *address = listener_->GetLocalAddress(); | |
261 return !address->IsNil(); | |
262 } | |
263 | |
264 void HttpListenServer::StopListening() { | |
265 if (listener_) { | |
266 listener_->Close(); | |
267 } | |
268 } | |
269 | |
270 void HttpListenServer::OnReadEvent(AsyncSocket* socket) { | |
271 RTC_DCHECK(socket == listener_.get()); | |
272 AsyncSocket* incoming = listener_->Accept(nullptr); | |
273 if (incoming) { | |
274 StreamInterface* stream = new SocketStream(incoming); | |
275 //stream = new LoggingAdapter(stream, LS_VERBOSE, "HttpServer", false); | |
276 HandleConnection(stream); | |
277 } | |
278 } | |
279 | |
280 void HttpListenServer::OnConnectionClosed(HttpServer* server, | |
281 int connection_id, | |
282 StreamInterface* stream) { | |
283 Thread::Current()->Dispose(stream); | |
284 } | |
285 | |
286 /////////////////////////////////////////////////////////////////////////////// | |
287 | |
288 } // namespace rtc | |
OLD | NEW |