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 341