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/dump_cache/url_utilities.h" | |
9 #include "net/tools/flip_server/flip_config.h" | |
10 #include "net/tools/flip_server/sm_connection.h" | |
11 #include "net/tools/flip_server/spdy_util.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 delete http_framer_; | |
36 } | |
37 | |
38 void HttpSM::ProcessBodyData(const char* input, size_t size) { | |
39 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) { | |
40 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process Body Data: stream " | |
41 << stream_id_ << ": size " << size; | |
42 sm_spdy_interface_->SendDataFrame(stream_id_, input, size, 0, false); | |
43 } | |
44 } | |
45 | |
46 void HttpSM::ProcessHeaders(const BalsaHeaders& headers) { | |
47 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER) { | |
48 std::string host = | |
49 UrlUtilities::GetUrlHost(headers.GetHeader("Host").as_string()); | |
50 std::string method = headers.request_method().as_string(); | |
51 VLOG(1) << ACCEPTOR_CLIENT_IDENT | |
52 << "Received Request: " << headers.request_uri().as_string() << " " | |
53 << method; | |
54 std::string filename = | |
55 EncodeURL(headers.request_uri().as_string(), host, method); | |
56 NewStream(stream_id_, 0, filename); | |
57 stream_id_ += 2; | |
58 } else { | |
59 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Received Response from " | |
60 << connection_->server_ip_ << ":" << connection_->server_port_ | |
61 << " "; | |
62 sm_spdy_interface_->SendSynReply(stream_id_, headers); | |
63 } | |
64 } | |
65 | |
66 void HttpSM::MessageDone() { | |
67 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) { | |
68 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: MessageDone. Sending EOF: " | |
69 << "stream " << stream_id_; | |
70 sm_spdy_interface_->SendEOF(stream_id_); | |
71 } else { | |
72 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: MessageDone."; | |
73 } | |
74 } | |
75 | |
76 void HttpSM::HandleHeaderError(BalsaFrame* framer) { HandleError(); } | |
77 | |
78 void HttpSM::HandleChunkingError(BalsaFrame* framer) { HandleError(); } | |
79 | |
80 void HttpSM::HandleBodyError(BalsaFrame* framer) { HandleError(); } | |
81 | |
82 void HttpSM::HandleError() { | |
83 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Error detected"; | |
84 } | |
85 | |
86 void HttpSM::AddToOutputOrder(const MemCacheIter& mci) { | |
87 output_ordering_.AddToOutputOrder(mci); | |
88 } | |
89 | |
90 void HttpSM::InitSMInterface(SMInterface* sm_spdy_interface, int32 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 stream_id) { stream_id_ = stream_id; } | |
139 | |
140 bool HttpSM::Error() const { return http_framer_->Error(); } | |
141 | |
142 const char* HttpSM::ErrorAsString() const { | |
143 return BalsaFrameEnums::ErrorCodeToString(http_framer_->ErrorCode()); | |
144 } | |
145 | |
146 void HttpSM::Reset() { | |
147 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Reset: stream " << stream_id_; | |
148 http_framer_->Reset(); | |
149 } | |
150 | |
151 void HttpSM::ResetForNewConnection() { | |
152 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) { | |
153 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Server connection closing " | |
154 << "to: " << connection_->server_ip_ << ":" | |
155 << connection_->server_port_ << " "; | |
156 } | |
157 // Message has not been fully read, either it is incomplete or the | |
158 // server is closing the connection to signal message end. | |
159 if (!MessageFullyRead()) { | |
160 VLOG(2) << "HTTP response closed before end of file detected. " | |
161 << "Sending EOF to spdy."; | |
162 sm_spdy_interface_->SendEOF(stream_id_); | |
163 } | |
164 output_ordering_.Reset(); | |
165 http_framer_->Reset(); | |
166 if (sm_spdy_interface_) { | |
167 sm_spdy_interface_->ResetForNewInterface(server_idx_); | |
168 } | |
169 } | |
170 | |
171 void HttpSM::Cleanup() { | |
172 if (!(acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER)) { | |
173 VLOG(2) << "HttpSM Request Fully Read; stream_id: " << stream_id_; | |
174 connection_->Cleanup("request complete"); | |
175 } | |
176 } | |
177 | |
178 int HttpSM::PostAcceptHook() { return 1; } | |
179 | |
180 void HttpSM::NewStream(uint32 stream_id, | |
181 uint32 priority, | |
182 const std::string& filename) { | |
183 MemCacheIter mci; | |
184 mci.stream_id = stream_id; | |
185 mci.priority = priority; | |
186 if (!memory_cache_->AssignFileData(filename, &mci)) { | |
187 // error creating new stream. | |
188 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending ErrorNotFound"; | |
189 SendErrorNotFound(stream_id); | |
190 } else { | |
191 AddToOutputOrder(mci); | |
192 } | |
193 } | |
194 | |
195 void HttpSM::SendEOF(uint32 stream_id) { | |
196 SendEOFImpl(stream_id); | |
197 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) { | |
198 sm_spdy_interface_->ResetForNewInterface(server_idx_); | |
199 } | |
200 } | |
201 | |
202 void HttpSM::SendErrorNotFound(uint32 stream_id) { | |
203 SendErrorNotFoundImpl(stream_id); | |
204 } | |
205 | |
206 size_t HttpSM::SendSynStream(uint32 stream_id, const BalsaHeaders& headers) { | |
207 return 0; | |
208 } | |
209 | |
210 size_t HttpSM::SendSynReply(uint32 stream_id, const BalsaHeaders& headers) { | |
211 return SendSynReplyImpl(stream_id, headers); | |
212 } | |
213 | |
214 void HttpSM::SendDataFrame(uint32 stream_id, | |
215 const char* data, | |
216 int64 len, | |
217 uint32 flags, | |
218 bool compress) { | |
219 SendDataFrameImpl(stream_id, data, len, flags, compress); | |
220 } | |
221 | |
222 void HttpSM::SendEOFImpl(uint32 stream_id) { | |
223 DataFrame* df = new DataFrame; | |
224 df->data = "0\r\n\r\n"; | |
225 df->size = 5; | |
226 df->delete_when_done = false; | |
227 EnqueueDataFrame(df); | |
228 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER) { | |
229 Reset(); | |
230 } | |
231 } | |
232 | |
233 void HttpSM::SendErrorNotFoundImpl(uint32 stream_id) { | |
234 BalsaHeaders my_headers; | |
235 my_headers.SetFirstlineFromStringPieces("HTTP/1.1", "404", "Not Found"); | |
236 my_headers.RemoveAllOfHeader("content-length"); | |
237 my_headers.AppendHeader("transfer-encoding", "chunked"); | |
238 SendSynReplyImpl(stream_id, my_headers); | |
239 SendDataFrame(stream_id, "page not found", 14, 0, false); | |
240 SendEOFImpl(stream_id); | |
241 output_ordering_.RemoveStreamId(stream_id); | |
242 } | |
243 | |
244 size_t HttpSM::SendSynReplyImpl(uint32 stream_id, const BalsaHeaders& headers) { | |
245 SimpleBuffer sb; | |
246 headers.WriteHeaderAndEndingToBuffer(&sb); | |
247 DataFrame* df = new DataFrame; | |
248 df->size = sb.ReadableBytes(); | |
249 char* buffer = new char[df->size]; | |
250 df->data = buffer; | |
251 df->delete_when_done = true; | |
252 sb.Read(buffer, df->size); | |
253 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending HTTP Reply header " | |
254 << stream_id_; | |
255 size_t df_size = df->size; | |
256 EnqueueDataFrame(df); | |
257 return df_size; | |
258 } | |
259 | |
260 size_t HttpSM::SendSynStreamImpl(uint32 stream_id, | |
261 const BalsaHeaders& headers) { | |
262 SimpleBuffer sb; | |
263 headers.WriteHeaderAndEndingToBuffer(&sb); | |
264 DataFrame* df = new DataFrame; | |
265 df->size = sb.ReadableBytes(); | |
266 char* buffer = new char[df->size]; | |
267 df->data = buffer; | |
268 df->delete_when_done = true; | |
269 sb.Read(buffer, df->size); | |
270 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending HTTP Reply header " | |
271 << stream_id_; | |
272 size_t df_size = df->size; | |
273 EnqueueDataFrame(df); | |
274 return df_size; | |
275 } | |
276 | |
277 void HttpSM::SendDataFrameImpl(uint32 stream_id, | |
278 const char* data, | |
279 int64 len, | |
280 uint32 flags, | |
281 bool compress) { | |
282 char chunk_buf[128]; | |
283 snprintf(chunk_buf, sizeof(chunk_buf), "%x\r\n", (unsigned int)len); | |
284 std::string chunk_description(chunk_buf); | |
285 DataFrame* df = new DataFrame; | |
286 df->size = chunk_description.size() + len + 2; | |
287 char* buffer = new char[df->size]; | |
288 df->data = buffer; | |
289 df->delete_when_done = true; | |
290 memcpy(buffer, chunk_description.data(), chunk_description.size()); | |
291 memcpy(buffer + chunk_description.size(), data, len); | |
292 memcpy(buffer + chunk_description.size() + len, "\r\n", 2); | |
293 EnqueueDataFrame(df); | |
294 } | |
295 | |
296 void HttpSM::EnqueueDataFrame(DataFrame* df) { | |
297 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Enqueue data frame: stream " | |
298 << stream_id_; | |
299 connection_->EnqueueDataFrame(df); | |
300 } | |
301 | |
302 void HttpSM::GetOutput() { | |
303 MemCacheIter* mci = output_ordering_.GetIter(); | |
304 if (mci == NULL) { | |
305 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput: nothing to " | |
306 << "output!?: stream " << stream_id_; | |
307 return; | |
308 } | |
309 if (!mci->transformed_header) { | |
310 mci->bytes_sent = | |
311 SendSynReply(mci->stream_id, *(mci->file_data->headers())); | |
312 mci->transformed_header = true; | |
313 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput transformed " | |
314 << "header stream_id: [" << mci->stream_id << "]"; | |
315 return; | |
316 } | |
317 if (mci->body_bytes_consumed >= mci->file_data->body().size()) { | |
318 SendEOF(mci->stream_id); | |
319 output_ordering_.RemoveStreamId(mci->stream_id); | |
320 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "GetOutput remove_stream_id: [" | |
321 << mci->stream_id << "]"; | |
322 return; | |
323 } | |
324 size_t num_to_write = | |
325 mci->file_data->body().size() - mci->body_bytes_consumed; | |
326 if (num_to_write > mci->max_segment_size) | |
327 num_to_write = mci->max_segment_size; | |
328 | |
329 SendDataFrame(mci->stream_id, | |
330 mci->file_data->body().data() + mci->body_bytes_consumed, | |
331 num_to_write, | |
332 0, | |
333 true); | |
334 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput SendDataFrame[" | |
335 << mci->stream_id << "]: " << num_to_write; | |
336 mci->body_bytes_consumed += num_to_write; | |
337 mci->bytes_sent += num_to_write; | |
338 } | |
339 | |
340 } // namespace net | |
OLD | NEW |