OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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/spdy_interface.h" | |
6 | |
7 #include <algorithm> | |
8 #include <string> | |
9 #include <utility> | |
10 | |
11 #include "net/spdy/spdy_framer.h" | |
12 #include "net/spdy/spdy_protocol.h" | |
13 #include "net/tools/flip_server/constants.h" | |
14 #include "net/tools/flip_server/flip_config.h" | |
15 #include "net/tools/flip_server/http_interface.h" | |
16 #include "net/tools/flip_server/spdy_util.h" | |
17 #include "net/tools/flip_server/url_utilities.h" | |
18 | |
19 namespace net { | |
20 | |
21 // static | |
22 std::string SpdySM::forward_ip_header_; | |
23 | |
24 class SpdyFrameDataFrame : public DataFrame { | |
25 public: | |
26 explicit SpdyFrameDataFrame(SpdySerializedFrame* spdy_frame) | |
27 : frame(spdy_frame) { | |
28 data = spdy_frame->data(); | |
29 size = spdy_frame->size(); | |
30 } | |
31 | |
32 ~SpdyFrameDataFrame() override { delete frame; } | |
33 | |
34 const SpdySerializedFrame* frame; | |
35 }; | |
36 | |
37 SpdySM::SpdySM(SMConnection* connection, | |
38 SMInterface* sm_http_interface, | |
39 EpollServer* epoll_server, | |
40 MemoryCache* memory_cache, | |
41 FlipAcceptor* acceptor) | |
42 : buffered_spdy_framer_(new BufferedSpdyFramer()), | |
43 valid_spdy_session_(false), | |
44 connection_(connection), | |
45 client_output_list_(connection->output_list()), | |
46 client_output_ordering_(connection), | |
47 next_outgoing_stream_id_(2), | |
48 epoll_server_(epoll_server), | |
49 acceptor_(acceptor), | |
50 memory_cache_(memory_cache), | |
51 close_on_error_(false) { | |
52 buffered_spdy_framer_->set_visitor(this); | |
53 } | |
54 | |
55 SpdySM::~SpdySM() { } | |
56 | |
57 void SpdySM::InitSMConnection(SMConnectionPoolInterface* connection_pool, | |
58 SMInterface* sm_interface, | |
59 EpollServer* epoll_server, | |
60 int fd, | |
61 std::string server_ip, | |
62 std::string server_port, | |
63 std::string remote_ip, | |
64 bool use_ssl) { | |
65 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Initializing server connection."; | |
66 connection_->InitSMConnection(connection_pool, | |
67 sm_interface, | |
68 epoll_server, | |
69 fd, | |
70 server_ip, | |
71 server_port, | |
72 remote_ip, | |
73 use_ssl); | |
74 } | |
75 | |
76 SMInterface* SpdySM::NewConnectionInterface() { | |
77 SMConnection* server_connection = | |
78 SMConnection::NewSMConnection(epoll_server_, | |
79 NULL, | |
80 memory_cache_, | |
81 acceptor_, | |
82 "http_conn: "); | |
83 if (server_connection == NULL) { | |
84 LOG(ERROR) << "SpdySM: Could not create server connection"; | |
85 return NULL; | |
86 } | |
87 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Creating new HTTP interface"; | |
88 SMInterface* sm_http_interface = | |
89 new HttpSM(server_connection, this, memory_cache_, acceptor_); | |
90 return sm_http_interface; | |
91 } | |
92 | |
93 SMInterface* SpdySM::FindOrMakeNewSMConnectionInterface( | |
94 const std::string& server_ip, | |
95 const std::string& server_port) { | |
96 SMInterface* sm_http_interface; | |
97 int32_t server_idx; | |
98 if (unused_server_interface_list.empty()) { | |
99 sm_http_interface = NewConnectionInterface(); | |
100 server_idx = server_interface_list.size(); | |
101 server_interface_list.push_back(sm_http_interface); | |
102 VLOG(2) << ACCEPTOR_CLIENT_IDENT | |
103 << "SpdySM: Making new server connection on index: " << server_idx; | |
104 } else { | |
105 server_idx = unused_server_interface_list.back(); | |
106 unused_server_interface_list.pop_back(); | |
107 sm_http_interface = server_interface_list.at(server_idx); | |
108 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Reusing connection on " | |
109 << "index: " << server_idx; | |
110 } | |
111 | |
112 sm_http_interface->InitSMInterface(this, server_idx); | |
113 sm_http_interface->InitSMConnection(NULL, | |
114 sm_http_interface, | |
115 epoll_server_, | |
116 -1, | |
117 server_ip, | |
118 server_port, | |
119 std::string(), | |
120 false); | |
121 | |
122 return sm_http_interface; | |
123 } | |
124 | |
125 int SpdySM::SpdyHandleNewStream(SpdyStreamId stream_id, | |
126 SpdyPriority priority, | |
127 const SpdyHeaderBlock& headers, | |
128 std::string& http_data, | |
129 bool* is_https_scheme) { | |
130 *is_https_scheme = false; | |
131 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: OnSyn(" << stream_id << ")"; | |
132 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: # headers: " << headers.size(); | |
133 | |
134 SpdyHeaderBlock::const_iterator method = headers.end(); | |
135 SpdyHeaderBlock::const_iterator host = headers.end(); | |
136 SpdyHeaderBlock::const_iterator path = headers.end(); | |
137 SpdyHeaderBlock::const_iterator scheme = headers.end(); | |
138 SpdyHeaderBlock::const_iterator version = headers.end(); | |
139 SpdyHeaderBlock::const_iterator url = headers.end(); | |
140 | |
141 std::string path_string, host_string, version_string; | |
142 | |
143 method = headers.find(":method"); | |
144 host = headers.find(":host"); | |
145 path = headers.find(":path"); | |
146 scheme = headers.find(":scheme"); | |
147 if (method == headers.end() || host == headers.end() || | |
148 path == headers.end() || scheme == headers.end()) { | |
149 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: A mandatory header is " | |
150 << "missing. Not creating stream"; | |
151 return 0; | |
152 } | |
153 host_string = host->second.as_string(); | |
154 path_string = path->second.as_string(); | |
155 version_string = "HTTP/1.1"; | |
156 | |
157 if (scheme->second.compare("https") == 0) { | |
158 *is_https_scheme = true; | |
159 } | |
160 | |
161 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_SPDY_SERVER) { | |
162 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Request: " << method->second | |
163 << " " << path_string; | |
164 std::string filename = | |
165 EncodeURL(path_string, host_string, method->second.as_string()); | |
166 NewStream(stream_id, priority, filename); | |
167 } else { | |
168 http_data += method->second.as_string() + " " + path_string + " " + | |
169 version_string + "\r\n"; | |
170 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Request: " << method->second << " " | |
171 << path_string << " " << version_string; | |
172 http_data += "Host: " + (*is_https_scheme ? | |
173 acceptor_->https_server_ip_ : | |
174 acceptor_->http_server_ip_) + "\r\n"; | |
175 for (SpdyHeaderBlock::const_iterator i = headers.begin(); | |
176 i != headers.end(); ++i) { | |
177 if ((i->first.size() > 0 && i->first[0] == ':') || | |
178 i->first == "host" || | |
179 i == method || | |
180 i == host || | |
181 i == path || | |
182 i == scheme || | |
183 i == version || | |
184 i == url) { | |
185 // Ignore the entry. | |
186 } else { | |
187 http_data += | |
188 i->first.as_string() + ": " + i->second.as_string() + "\r\n"; | |
189 VLOG(2) << ACCEPTOR_CLIENT_IDENT << i->first << ":" << i->second; | |
190 } | |
191 } | |
192 if (forward_ip_header_.length()) { | |
193 // X-Client-Cluster-IP header | |
194 http_data += forward_ip_header_ + ": " + | |
195 connection_->client_ip() + "\r\n"; | |
196 } | |
197 http_data += "\r\n"; | |
198 } | |
199 | |
200 VLOG(3) << ACCEPTOR_CLIENT_IDENT << "SpdySM: HTTP Request:\n" << http_data; | |
201 return 1; | |
202 } | |
203 | |
204 void SpdySM::OnStreamFrameData(SpdyStreamId stream_id, | |
205 const char* data, | |
206 size_t len) { | |
207 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: StreamData(" << stream_id | |
208 << ", [" << len << "])"; | |
209 StreamToSmif::iterator it = stream_to_smif_.find(stream_id); | |
210 if (it == stream_to_smif_.end()) { | |
211 VLOG(2) << "Dropping frame from unknown stream " << stream_id; | |
212 if (!valid_spdy_session_) | |
213 close_on_error_ = true; | |
214 return; | |
215 } | |
216 | |
217 SMInterface* interface = it->second; | |
218 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) | |
219 interface->ProcessWriteInput(data, len); | |
220 } | |
221 | |
222 void SpdySM::OnStreamEnd(SpdyStreamId stream_id) { | |
223 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: StreamEnd(" << stream_id << ")"; | |
224 StreamToSmif::iterator it = stream_to_smif_.find(stream_id); | |
225 if (it == stream_to_smif_.end()) { | |
226 VLOG(2) << "Dropping frame from unknown stream " << stream_id; | |
227 if (!valid_spdy_session_) | |
228 close_on_error_ = true; | |
229 return; | |
230 } | |
231 | |
232 SMInterface* interface = it->second; | |
233 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) | |
234 interface->ProcessWriteInput(nullptr, 0); | |
235 } | |
236 | |
237 void SpdySM::OnStreamPadding(SpdyStreamId stream_id, size_t len) { | |
238 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: StreamPadding(" << stream_id | |
239 << ", [" << len << "])"; | |
240 } | |
241 | |
242 void SpdySM::OnHeaders(SpdyStreamId stream_id, | |
243 bool has_priority, | |
244 int weight, | |
245 SpdyStreamId parent_stream_id, | |
246 bool exclusive, | |
247 bool fin, | |
248 const SpdyHeaderBlock& headers) { | |
249 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: OnHeaders(" << stream_id << ")"; | |
250 } | |
251 | |
252 void SpdySM::OnRstStream(SpdyStreamId stream_id, SpdyRstStreamStatus status) { | |
253 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: OnRstStream(" << stream_id | |
254 << ")"; | |
255 client_output_ordering_.RemoveStreamId(stream_id); | |
256 } | |
257 | |
258 bool SpdySM::OnUnknownFrame(SpdyStreamId stream_id, int frame_type) { | |
259 return false; | |
260 } | |
261 | |
262 size_t SpdySM::ProcessReadInput(const char* data, size_t len) { | |
263 DCHECK(buffered_spdy_framer_); | |
264 return buffered_spdy_framer_->ProcessInput(data, len); | |
265 } | |
266 | |
267 size_t SpdySM::ProcessWriteInput(const char* data, size_t len) { return 0; } | |
268 | |
269 bool SpdySM::MessageFullyRead() const { | |
270 DCHECK(buffered_spdy_framer_); | |
271 return buffered_spdy_framer_->MessageFullyRead(); | |
272 } | |
273 | |
274 bool SpdySM::Error() const { | |
275 DCHECK(buffered_spdy_framer_); | |
276 return close_on_error_ || buffered_spdy_framer_->HasError(); | |
277 } | |
278 | |
279 const char* SpdySM::ErrorAsString() const { | |
280 DCHECK(Error()); | |
281 DCHECK(buffered_spdy_framer_); | |
282 return SpdyFramer::ErrorCodeToString(buffered_spdy_framer_->error_code()); | |
283 } | |
284 | |
285 void SpdySM::ResetForNewInterface(int32_t server_idx) { | |
286 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Reset for new interface: " | |
287 << "server_idx: " << server_idx; | |
288 unused_server_interface_list.push_back(server_idx); | |
289 } | |
290 | |
291 void SpdySM::ResetForNewConnection() { | |
292 // seq_num is not cleared, intentionally. | |
293 buffered_spdy_framer_.reset(); | |
294 valid_spdy_session_ = false; | |
295 client_output_ordering_.Reset(); | |
296 next_outgoing_stream_id_ = 2; | |
297 } | |
298 | |
299 // Send a settings frame | |
300 int SpdySM::PostAcceptHook() { | |
301 // We should have buffered_spdy_framer_ set after reuse | |
302 DCHECK(buffered_spdy_framer_); | |
303 SettingsMap settings; | |
304 settings[SETTINGS_MAX_CONCURRENT_STREAMS] = | |
305 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, 100); | |
306 SpdySerializedFrame* settings_frame = | |
307 buffered_spdy_framer_->CreateSettings(settings); | |
308 | |
309 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Sending Settings Frame"; | |
310 EnqueueDataFrame(new SpdyFrameDataFrame(settings_frame)); | |
311 return 1; | |
312 } | |
313 | |
314 void SpdySM::NewStream(uint32_t stream_id, | |
315 uint32_t priority, | |
316 const std::string& filename) { | |
317 MemCacheIter mci; | |
318 mci.stream_id = stream_id; | |
319 mci.priority = priority; | |
320 // TODO(yhirano): The program will crash when | |
321 // acceptor_->flip_handler_type_ != FLIP_HANDLER_SPDY_SERVER. | |
322 // It should be fixed or an assertion should be placed. | |
323 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_SPDY_SERVER) { | |
324 if (!memory_cache_->AssignFileData(filename, &mci)) { | |
325 // error creating new stream. | |
326 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Sending ErrorNotFound"; | |
327 SendErrorNotFound(stream_id); | |
328 } else { | |
329 AddToOutputOrder(mci); | |
330 } | |
331 } else { | |
332 AddToOutputOrder(mci); | |
333 } | |
334 } | |
335 | |
336 void SpdySM::AddToOutputOrder(const MemCacheIter& mci) { | |
337 client_output_ordering_.AddToOutputOrder(mci); | |
338 } | |
339 | |
340 void SpdySM::SendEOF(uint32_t stream_id) { | |
341 SendEOFImpl(stream_id); | |
342 } | |
343 | |
344 void SpdySM::SendErrorNotFound(uint32_t stream_id) { | |
345 SendErrorNotFoundImpl(stream_id); | |
346 } | |
347 | |
348 size_t SpdySM::SendSynStream(uint32_t stream_id, const BalsaHeaders& headers) { | |
349 return SendSynStreamImpl(stream_id, headers); | |
350 } | |
351 | |
352 size_t SpdySM::SendSynReply(uint32_t stream_id, const BalsaHeaders& headers) { | |
353 return SendSynReplyImpl(stream_id, headers); | |
354 } | |
355 | |
356 void SpdySM::SendDataFrame(uint32_t stream_id, | |
357 const char* data, | |
358 int64_t len, | |
359 uint32_t flags, | |
360 bool compress) { | |
361 SpdyDataFlags spdy_flags = static_cast<SpdyDataFlags>(flags); | |
362 SendDataFrameImpl(stream_id, data, len, spdy_flags, compress); | |
363 } | |
364 | |
365 void SpdySM::SendEOFImpl(uint32_t stream_id) { | |
366 SendDataFrame(stream_id, NULL, 0, DATA_FLAG_FIN, false); | |
367 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Sending EOF: " << stream_id; | |
368 KillStream(stream_id); | |
369 stream_to_smif_.erase(stream_id); | |
370 } | |
371 | |
372 void SpdySM::SendErrorNotFoundImpl(uint32_t stream_id) { | |
373 BalsaHeaders my_headers; | |
374 my_headers.SetFirstlineFromStringPieces("HTTP/1.1", "404", "Not Found"); | |
375 SendSynReplyImpl(stream_id, my_headers); | |
376 SendDataFrame(stream_id, "wtf?", 4, DATA_FLAG_FIN, false); | |
377 client_output_ordering_.RemoveStreamId(stream_id); | |
378 } | |
379 | |
380 void SpdySM::KillStream(uint32_t stream_id) { | |
381 client_output_ordering_.RemoveStreamId(stream_id); | |
382 } | |
383 | |
384 void SpdySM::CopyHeaders(SpdyHeaderBlock& dest, const BalsaHeaders& headers) { | |
385 for (BalsaHeaders::const_header_lines_iterator hi = | |
386 headers.header_lines_begin(); | |
387 hi != headers.header_lines_end(); | |
388 ++hi) { | |
389 // It is illegal to send SPDY headers with empty value or header | |
390 // names. | |
391 if (!hi->first.length() || !hi->second.length()) | |
392 continue; | |
393 | |
394 // Key must be all lower case in SPDY headers. | |
395 std::string key = hi->first.as_string(); | |
396 std::transform(key.begin(), key.end(), key.begin(), ::tolower); | |
397 SpdyHeaderBlock::iterator fhi = dest.find(key); | |
398 if (fhi == dest.end()) { | |
399 dest[key] = hi->second.as_string(); | |
400 } else { | |
401 dest[key] = (std::string(fhi->second.data(), fhi->second.size()) + "\0" + | |
402 std::string(hi->second.data(), hi->second.size())); | |
403 } | |
404 } | |
405 | |
406 // These headers have no value | |
407 dest.erase("X-Associated-Content"); // TODO(mbelshe): case-sensitive | |
408 dest.erase("X-Original-Url"); // TODO(mbelshe): case-sensitive | |
409 } | |
410 | |
411 size_t SpdySM::SendSynStreamImpl(uint32_t stream_id, | |
412 const BalsaHeaders& headers) { | |
413 SpdyHeaderBlock block; | |
414 CopyHeaders(block, headers); | |
415 block[":method"] = headers.request_method().as_string(); | |
416 block[":version"] = headers.request_version().as_string(); | |
417 if (headers.HasHeader("X-Original-Url")) { | |
418 std::string original_url = headers.GetHeader("X-Original-Url").as_string(); | |
419 block[":path"] = UrlUtilities::GetUrlPath(original_url); | |
420 block[":host"] = UrlUtilities::GetUrlPath(original_url); | |
421 } else { | |
422 block[":path"] = headers.request_uri().as_string(); | |
423 if (block.find("host") != block.end()) { | |
424 block[":host"] = headers.GetHeader("Host").as_string(); | |
425 block.erase("host"); | |
426 } | |
427 } | |
428 | |
429 DCHECK(buffered_spdy_framer_); | |
430 SpdySerializedFrame* fsrcf = buffered_spdy_framer_->CreateSynStream( | |
431 stream_id, 0, 0, CONTROL_FLAG_NONE, std::move(block)); | |
432 size_t df_size = fsrcf->size(); | |
433 EnqueueDataFrame(new SpdyFrameDataFrame(fsrcf)); | |
434 | |
435 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Sending SynStreamheader " | |
436 << stream_id; | |
437 return df_size; | |
438 } | |
439 | |
440 size_t SpdySM::SendSynReplyImpl(uint32_t stream_id, | |
441 const BalsaHeaders& headers) { | |
442 SpdyHeaderBlock block; | |
443 CopyHeaders(block, headers); | |
444 block[":status"] = headers.response_code().as_string() + " " + | |
445 headers.response_reason_phrase().as_string(); | |
446 block[":version"] = headers.response_version().as_string(); | |
447 | |
448 DCHECK(buffered_spdy_framer_); | |
449 SpdySerializedFrame* fsrcf = buffered_spdy_framer_->CreateSynReply( | |
450 stream_id, CONTROL_FLAG_NONE, std::move(block)); | |
451 size_t df_size = fsrcf->size(); | |
452 EnqueueDataFrame(new SpdyFrameDataFrame(fsrcf)); | |
453 | |
454 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Sending SynReplyheader " | |
455 << stream_id; | |
456 return df_size; | |
457 } | |
458 | |
459 void SpdySM::SendDataFrameImpl(uint32_t stream_id, | |
460 const char* data, | |
461 int64_t len, | |
462 SpdyDataFlags flags, | |
463 bool compress) { | |
464 DCHECK(buffered_spdy_framer_); | |
465 // TODO(mbelshe): We can't compress here - before going into the | |
466 // priority queue. Compression needs to be done | |
467 // with late binding. | |
468 if (len == 0) { | |
469 SpdySerializedFrame* fdf = | |
470 buffered_spdy_framer_->CreateDataFrame(stream_id, data, len, flags); | |
471 EnqueueDataFrame(new SpdyFrameDataFrame(fdf)); | |
472 return; | |
473 } | |
474 | |
475 // Chop data frames into chunks so that one stream can't monopolize the | |
476 // output channel. | |
477 while (len > 0) { | |
478 int64_t size = std::min(len, static_cast<int64_t>(kSpdySegmentSize)); | |
479 SpdyDataFlags chunk_flags = flags; | |
480 | |
481 // If we chunked this block, and the FIN flag was set, there is more | |
482 // data coming. So, remove the flag. | |
483 if ((size < len) && (flags & DATA_FLAG_FIN)) | |
484 chunk_flags = static_cast<SpdyDataFlags>(chunk_flags & ~DATA_FLAG_FIN); | |
485 | |
486 SpdySerializedFrame* fdf = buffered_spdy_framer_->CreateDataFrame( | |
487 stream_id, data, size, chunk_flags); | |
488 EnqueueDataFrame(new SpdyFrameDataFrame(fdf)); | |
489 | |
490 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Sending data frame " | |
491 << stream_id << " [" << size << "] shrunk to " | |
492 << (fdf->size() - kSpdyOverhead) << ", flags=" << flags; | |
493 | |
494 data += size; | |
495 len -= size; | |
496 } | |
497 } | |
498 | |
499 void SpdySM::EnqueueDataFrame(DataFrame* df) { | |
500 connection_->EnqueueDataFrame(df); | |
501 } | |
502 | |
503 void SpdySM::GetOutput() { | |
504 while (client_output_list_->size() < 2) { | |
505 MemCacheIter* mci = client_output_ordering_.GetIter(); | |
506 if (mci == NULL) { | |
507 VLOG(2) << ACCEPTOR_CLIENT_IDENT | |
508 << "SpdySM: GetOutput: nothing to output!?"; | |
509 return; | |
510 } | |
511 if (!mci->transformed_header) { | |
512 mci->transformed_header = true; | |
513 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: GetOutput transformed " | |
514 << "header stream_id: [" << mci->stream_id << "]"; | |
515 if ((mci->stream_id % 2) == 0) { | |
516 // this is a server initiated stream. | |
517 // Ideally, we'd do a 'syn-push' here, instead of a syn-reply. | |
518 BalsaHeaders headers; | |
519 headers.CopyFrom(*(mci->file_data->headers())); | |
520 headers.ReplaceOrAppendHeader("status", "200"); | |
521 headers.ReplaceOrAppendHeader("version", "http/1.1"); | |
522 headers.SetRequestFirstlineFromStringPieces( | |
523 "PUSH", mci->file_data->filename(), ""); | |
524 mci->bytes_sent = SendSynStream(mci->stream_id, headers); | |
525 } else { | |
526 BalsaHeaders headers; | |
527 headers.CopyFrom(*(mci->file_data->headers())); | |
528 mci->bytes_sent = SendSynReply(mci->stream_id, headers); | |
529 } | |
530 return; | |
531 } | |
532 if (mci->body_bytes_consumed >= mci->file_data->body().size()) { | |
533 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: GetOutput " | |
534 << "remove_stream_id: [" << mci->stream_id << "]"; | |
535 SendEOF(mci->stream_id); | |
536 return; | |
537 } | |
538 size_t num_to_write = | |
539 mci->file_data->body().size() - mci->body_bytes_consumed; | |
540 if (num_to_write > mci->max_segment_size) | |
541 num_to_write = mci->max_segment_size; | |
542 | |
543 bool should_compress = false; | |
544 if (!mci->file_data->headers()->HasHeader("content-encoding")) { | |
545 if (mci->file_data->headers()->HasHeader("content-type")) { | |
546 std::string content_type = | |
547 mci->file_data->headers()->GetHeader("content-type").as_string(); | |
548 if (content_type.find("image") == content_type.npos) | |
549 should_compress = true; | |
550 } | |
551 } | |
552 | |
553 SendDataFrame(mci->stream_id, | |
554 mci->file_data->body().data() + mci->body_bytes_consumed, | |
555 num_to_write, | |
556 0, | |
557 should_compress); | |
558 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: GetOutput SendDataFrame[" | |
559 << mci->stream_id << "]: " << num_to_write; | |
560 mci->body_bytes_consumed += num_to_write; | |
561 mci->bytes_sent += num_to_write; | |
562 } | |
563 } | |
564 | |
565 void SpdySM::CreateFramer() { | |
566 DCHECK(!buffered_spdy_framer_); | |
567 buffered_spdy_framer_.reset(new BufferedSpdyFramer()); | |
568 buffered_spdy_framer_->set_visitor(this); | |
569 } | |
570 | |
571 } // namespace net | |
OLD | NEW |