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/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