OLD | NEW |
| (Empty) |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "net/tools/flip_server/http_interface.h" | |
6 | |
7 #include "net/tools/balsa/balsa_frame.h" | |
8 #include "net/tools/flip_server/flip_config.h" | |
9 #include "net/tools/flip_server/sm_connection.h" | |
10 #include "net/tools/flip_server/spdy_util.h" | |
11 #include "net/tools/flip_server/url_utilities.h" | |
12 | |
13 namespace net { | |
14 | |
15 HttpSM::HttpSM(SMConnection* connection, | |
16 SMInterface* sm_spdy_interface, | |
17 MemoryCache* memory_cache, | |
18 FlipAcceptor* acceptor) | |
19 : http_framer_(new BalsaFrame), | |
20 stream_id_(0), | |
21 server_idx_(-1), | |
22 connection_(connection), | |
23 sm_spdy_interface_(sm_spdy_interface), | |
24 output_list_(connection->output_list()), | |
25 output_ordering_(connection), | |
26 memory_cache_(connection->memory_cache()), | |
27 acceptor_(acceptor) { | |
28 http_framer_->set_balsa_visitor(this); | |
29 http_framer_->set_balsa_headers(&headers_); | |
30 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) | |
31 http_framer_->set_is_request(false); | |
32 } | |
33 HttpSM::~HttpSM() { | |
34 Reset(); | |
35 } | |
36 | |
37 void HttpSM::ProcessBodyData(const char* input, size_t size) { | |
38 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) { | |
39 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process Body Data: stream " | |
40 << stream_id_ << ": size " << size; | |
41 sm_spdy_interface_->SendDataFrame(stream_id_, input, size, 0, false); | |
42 } | |
43 } | |
44 | |
45 void HttpSM::ProcessHeaders(const BalsaHeaders& headers) { | |
46 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER) { | |
47 std::string host = | |
48 UrlUtilities::GetUrlHost(headers.GetHeader("Host").as_string()); | |
49 std::string method = headers.request_method().as_string(); | |
50 VLOG(1) << ACCEPTOR_CLIENT_IDENT | |
51 << "Received Request: " << headers.request_uri().as_string() << " " | |
52 << method; | |
53 std::string filename = | |
54 EncodeURL(headers.request_uri().as_string(), host, method); | |
55 NewStream(stream_id_, 0, filename); | |
56 stream_id_ += 2; | |
57 } else { | |
58 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Received Response from " | |
59 << connection_->server_ip_ << ":" << connection_->server_port_ | |
60 << " "; | |
61 sm_spdy_interface_->SendSynReply(stream_id_, headers); | |
62 } | |
63 } | |
64 | |
65 void HttpSM::MessageDone() { | |
66 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) { | |
67 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: MessageDone. Sending EOF: " | |
68 << "stream " << stream_id_; | |
69 sm_spdy_interface_->SendEOF(stream_id_); | |
70 } else { | |
71 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: MessageDone."; | |
72 } | |
73 } | |
74 | |
75 void HttpSM::HandleHeaderError(BalsaFrame* framer) { HandleError(); } | |
76 | |
77 void HttpSM::HandleChunkingError(BalsaFrame* framer) { HandleError(); } | |
78 | |
79 void HttpSM::HandleBodyError(BalsaFrame* framer) { HandleError(); } | |
80 | |
81 void HttpSM::HandleError() { | |
82 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Error detected"; | |
83 } | |
84 | |
85 void HttpSM::AddToOutputOrder(const MemCacheIter& mci) { | |
86 output_ordering_.AddToOutputOrder(mci); | |
87 } | |
88 | |
89 void HttpSM::InitSMInterface(SMInterface* sm_spdy_interface, | |
90 int32_t server_idx) { | |
91 sm_spdy_interface_ = sm_spdy_interface; | |
92 server_idx_ = server_idx; | |
93 } | |
94 | |
95 void HttpSM::InitSMConnection(SMConnectionPoolInterface* connection_pool, | |
96 SMInterface* sm_interface, | |
97 EpollServer* epoll_server, | |
98 int fd, | |
99 std::string server_ip, | |
100 std::string server_port, | |
101 std::string remote_ip, | |
102 bool use_ssl) { | |
103 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Initializing server " | |
104 << "connection."; | |
105 connection_->InitSMConnection(connection_pool, | |
106 sm_interface, | |
107 epoll_server, | |
108 fd, | |
109 server_ip, | |
110 server_port, | |
111 remote_ip, | |
112 use_ssl); | |
113 } | |
114 | |
115 size_t HttpSM::ProcessReadInput(const char* data, size_t len) { | |
116 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process read input: stream " | |
117 << stream_id_; | |
118 return http_framer_->ProcessInput(data, len); | |
119 } | |
120 | |
121 size_t HttpSM::ProcessWriteInput(const char* data, size_t len) { | |
122 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process write input: size " | |
123 << len << ": stream " << stream_id_; | |
124 char* dataPtr = new char[len]; | |
125 memcpy(dataPtr, data, len); | |
126 DataFrame* data_frame = new DataFrame; | |
127 data_frame->data = dataPtr; | |
128 data_frame->size = len; | |
129 data_frame->delete_when_done = true; | |
130 connection_->EnqueueDataFrame(data_frame); | |
131 return len; | |
132 } | |
133 | |
134 bool HttpSM::MessageFullyRead() const { | |
135 return http_framer_->MessageFullyRead(); | |
136 } | |
137 | |
138 void HttpSM::SetStreamID(uint32_t stream_id) { | |
139 stream_id_ = stream_id; | |
140 } | |
141 | |
142 bool HttpSM::Error() const { return http_framer_->Error(); } | |
143 | |
144 const char* HttpSM::ErrorAsString() const { | |
145 return BalsaFrameEnums::ErrorCodeToString(http_framer_->ErrorCode()); | |
146 } | |
147 | |
148 void HttpSM::Reset() { | |
149 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Reset: stream " << stream_id_; | |
150 http_framer_->Reset(); | |
151 } | |
152 | |
153 void HttpSM::ResetForNewConnection() { | |
154 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) { | |
155 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Server connection closing " | |
156 << "to: " << connection_->server_ip_ << ":" | |
157 << connection_->server_port_ << " "; | |
158 } | |
159 // Message has not been fully read, either it is incomplete or the | |
160 // server is closing the connection to signal message end. | |
161 if (!MessageFullyRead()) { | |
162 VLOG(2) << "HTTP response closed before end of file detected. " | |
163 << "Sending EOF to spdy."; | |
164 sm_spdy_interface_->SendEOF(stream_id_); | |
165 } | |
166 output_ordering_.Reset(); | |
167 http_framer_->Reset(); | |
168 if (sm_spdy_interface_) { | |
169 sm_spdy_interface_->ResetForNewInterface(server_idx_); | |
170 } | |
171 } | |
172 | |
173 void HttpSM::Cleanup() { | |
174 if (!(acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER)) { | |
175 VLOG(2) << "HttpSM Request Fully Read; stream_id: " << stream_id_; | |
176 connection_->Cleanup("request complete"); | |
177 } | |
178 } | |
179 | |
180 int HttpSM::PostAcceptHook() { return 1; } | |
181 | |
182 void HttpSM::NewStream(uint32_t stream_id, | |
183 uint32_t priority, | |
184 const std::string& filename) { | |
185 MemCacheIter mci; | |
186 mci.stream_id = stream_id; | |
187 mci.priority = priority; | |
188 if (!memory_cache_->AssignFileData(filename, &mci)) { | |
189 // error creating new stream. | |
190 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending ErrorNotFound"; | |
191 SendErrorNotFound(stream_id); | |
192 } else { | |
193 AddToOutputOrder(mci); | |
194 } | |
195 } | |
196 | |
197 void HttpSM::SendEOF(uint32_t stream_id) { | |
198 SendEOFImpl(stream_id); | |
199 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) { | |
200 sm_spdy_interface_->ResetForNewInterface(server_idx_); | |
201 } | |
202 } | |
203 | |
204 void HttpSM::SendErrorNotFound(uint32_t stream_id) { | |
205 SendErrorNotFoundImpl(stream_id); | |
206 } | |
207 | |
208 size_t HttpSM::SendSynStream(uint32_t stream_id, const BalsaHeaders& headers) { | |
209 return 0; | |
210 } | |
211 | |
212 size_t HttpSM::SendSynReply(uint32_t stream_id, const BalsaHeaders& headers) { | |
213 return SendSynReplyImpl(stream_id, headers); | |
214 } | |
215 | |
216 void HttpSM::SendDataFrame(uint32_t stream_id, | |
217 const char* data, | |
218 int64_t len, | |
219 uint32_t flags, | |
220 bool compress) { | |
221 SendDataFrameImpl(stream_id, data, len, flags, compress); | |
222 } | |
223 | |
224 void HttpSM::SendEOFImpl(uint32_t stream_id) { | |
225 DataFrame* df = new DataFrame; | |
226 df->data = "0\r\n\r\n"; | |
227 df->size = 5; | |
228 df->delete_when_done = false; | |
229 EnqueueDataFrame(df); | |
230 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER) { | |
231 Reset(); | |
232 } | |
233 } | |
234 | |
235 void HttpSM::SendErrorNotFoundImpl(uint32_t stream_id) { | |
236 BalsaHeaders my_headers; | |
237 my_headers.SetFirstlineFromStringPieces("HTTP/1.1", "404", "Not Found"); | |
238 my_headers.RemoveAllOfHeader("content-length"); | |
239 my_headers.AppendHeader("transfer-encoding", "chunked"); | |
240 SendSynReplyImpl(stream_id, my_headers); | |
241 SendDataFrame(stream_id, "page not found", 14, 0, false); | |
242 SendEOFImpl(stream_id); | |
243 output_ordering_.RemoveStreamId(stream_id); | |
244 } | |
245 | |
246 size_t HttpSM::SendSynReplyImpl(uint32_t stream_id, | |
247 const BalsaHeaders& headers) { | |
248 SimpleBuffer sb; | |
249 headers.WriteHeaderAndEndingToBuffer(&sb); | |
250 DataFrame* df = new DataFrame; | |
251 df->size = sb.ReadableBytes(); | |
252 char* buffer = new char[df->size]; | |
253 df->data = buffer; | |
254 df->delete_when_done = true; | |
255 sb.Read(buffer, df->size); | |
256 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending HTTP Reply header " | |
257 << stream_id_; | |
258 size_t df_size = df->size; | |
259 EnqueueDataFrame(df); | |
260 return df_size; | |
261 } | |
262 | |
263 size_t HttpSM::SendSynStreamImpl(uint32_t stream_id, | |
264 const BalsaHeaders& headers) { | |
265 SimpleBuffer sb; | |
266 headers.WriteHeaderAndEndingToBuffer(&sb); | |
267 DataFrame* df = new DataFrame; | |
268 df->size = sb.ReadableBytes(); | |
269 char* buffer = new char[df->size]; | |
270 df->data = buffer; | |
271 df->delete_when_done = true; | |
272 sb.Read(buffer, df->size); | |
273 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending HTTP Reply header " | |
274 << stream_id_; | |
275 size_t df_size = df->size; | |
276 EnqueueDataFrame(df); | |
277 return df_size; | |
278 } | |
279 | |
280 void HttpSM::SendDataFrameImpl(uint32_t stream_id, | |
281 const char* data, | |
282 int64_t len, | |
283 uint32_t flags, | |
284 bool compress) { | |
285 char chunk_buf[128]; | |
286 snprintf(chunk_buf, sizeof(chunk_buf), "%x\r\n", (unsigned int)len); | |
287 std::string chunk_description(chunk_buf); | |
288 DataFrame* df = new DataFrame; | |
289 df->size = chunk_description.size() + len + 2; | |
290 char* buffer = new char[df->size]; | |
291 df->data = buffer; | |
292 df->delete_when_done = true; | |
293 memcpy(buffer, chunk_description.data(), chunk_description.size()); | |
294 memcpy(buffer + chunk_description.size(), data, len); | |
295 memcpy(buffer + chunk_description.size() + len, "\r\n", 2); | |
296 EnqueueDataFrame(df); | |
297 } | |
298 | |
299 void HttpSM::EnqueueDataFrame(DataFrame* df) { | |
300 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Enqueue data frame: stream " | |
301 << stream_id_; | |
302 connection_->EnqueueDataFrame(df); | |
303 } | |
304 | |
305 void HttpSM::GetOutput() { | |
306 MemCacheIter* mci = output_ordering_.GetIter(); | |
307 if (mci == NULL) { | |
308 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput: nothing to " | |
309 << "output!?: stream " << stream_id_; | |
310 return; | |
311 } | |
312 if (!mci->transformed_header) { | |
313 mci->bytes_sent = | |
314 SendSynReply(mci->stream_id, *(mci->file_data->headers())); | |
315 mci->transformed_header = true; | |
316 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput transformed " | |
317 << "header stream_id: [" << mci->stream_id << "]"; | |
318 return; | |
319 } | |
320 if (mci->body_bytes_consumed >= mci->file_data->body().size()) { | |
321 SendEOF(mci->stream_id); | |
322 output_ordering_.RemoveStreamId(mci->stream_id); | |
323 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "GetOutput remove_stream_id: [" | |
324 << mci->stream_id << "]"; | |
325 return; | |
326 } | |
327 size_t num_to_write = | |
328 mci->file_data->body().size() - mci->body_bytes_consumed; | |
329 if (num_to_write > mci->max_segment_size) | |
330 num_to_write = mci->max_segment_size; | |
331 | |
332 SendDataFrame(mci->stream_id, | |
333 mci->file_data->body().data() + mci->body_bytes_consumed, | |
334 num_to_write, | |
335 0, | |
336 true); | |
337 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput SendDataFrame[" | |
338 << mci->stream_id << "]: " << num_to_write; | |
339 mci->body_bytes_consumed += num_to_write; | |
340 mci->bytes_sent += num_to_write; | |
341 } | |
342 | |
343 } // namespace net | |
OLD | NEW |