Home | History | Annotate | Download | only in flip_server
      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 
     13 namespace net {
     14 
     15 HttpSM::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 }
     35 HttpSM::~HttpSM() {
     36   Reset();
     37   delete http_framer_;
     38 }
     39 
     40 void 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 
     48 void 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 
     67 void 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 
     77 void HttpSM::HandleHeaderError(BalsaFrame* framer) {
     78   HandleError();
     79 }
     80 
     81 void HttpSM::HandleChunkingError(BalsaFrame* framer) {
     82   HandleError();
     83 }
     84 
     85 void HttpSM::HandleBodyError(BalsaFrame* framer) {
     86   HandleError();
     87 }
     88 
     89 void HttpSM::HandleError() {
     90   VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Error detected";
     91 }
     92 
     93 void HttpSM::AddToOutputOrder(const MemCacheIter& mci) {
     94   output_ordering_.AddToOutputOrder(mci);
     95 }
     96 
     97 void HttpSM::SendOKResponse(uint32 stream_id, std::string* output) {
     98   SendOKResponseImpl(stream_id, output);
     99 }
    100 
    101 void HttpSM::InitSMInterface(SMInterface* sm_spdy_interface,
    102                              int32 server_idx) {
    103   sm_spdy_interface_ = sm_spdy_interface;
    104   server_idx_ = server_idx;
    105 }
    106 
    107 void 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 
    127 size_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 
    133 size_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 
    146 bool HttpSM::MessageFullyRead() const {
    147   return http_framer_->MessageFullyRead();
    148 }
    149 
    150 void HttpSM::SetStreamID(uint32 stream_id) {
    151   stream_id_ = stream_id;
    152 }
    153 
    154 bool HttpSM::Error() const {
    155   return http_framer_->Error();
    156 }
    157 
    158 const char* HttpSM::ErrorAsString() const {
    159   return BalsaFrameEnums::ErrorCodeToString(http_framer_->ErrorCode());
    160 }
    161 
    162 void HttpSM::Reset() {
    163   VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Reset: stream "
    164           << stream_id_;
    165   http_framer_->Reset();
    166 }
    167 
    168 void 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 
    189 void 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 
    196 int HttpSM::PostAcceptHook() {
    197   return 1;
    198 }
    199 
    200 void 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 
    214 void 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 
    221 void HttpSM::SendErrorNotFound(uint32 stream_id) {
    222   SendErrorNotFoundImpl(stream_id);
    223 }
    224 
    225 size_t HttpSM::SendSynStream(uint32 stream_id, const BalsaHeaders& headers) {
    226   return 0;
    227 }
    228 
    229 size_t HttpSM::SendSynReply(uint32 stream_id, const BalsaHeaders& headers) {
    230   return SendSynReplyImpl(stream_id, headers);
    231 }
    232 
    233 void 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 
    238 void 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 
    249 void 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 
    260 void 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 
    271 size_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 
    287 size_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 
    304 void 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 
    320 void HttpSM::EnqueueDataFrame(DataFrame* df) {
    321   VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Enqueue data frame: stream "
    322           << stream_id_;
    323   connection_->EnqueueDataFrame(df);
    324 }
    325 
    326 void 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