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