普通文本  |  364行  |  11.8 KB

// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/tools/flip_server/http_interface.h"

#include "net/tools/dump_cache/url_utilities.h"
#include "net/tools/flip_server/balsa_frame.h"
#include "net/tools/flip_server/flip_config.h"
#include "net/tools/flip_server/sm_connection.h"
#include "net/tools/flip_server/spdy_util.h"

namespace net {

HttpSM::HttpSM(SMConnection* connection,
               SMInterface* sm_spdy_interface,
               EpollServer* epoll_server,
               MemoryCache* memory_cache,
               FlipAcceptor* acceptor)
    : seq_num_(0),
      http_framer_(new BalsaFrame),
      stream_id_(0),
      server_idx_(-1),
      connection_(connection),
      sm_spdy_interface_(sm_spdy_interface),
      output_list_(connection->output_list()),
      output_ordering_(connection),
      memory_cache_(connection->memory_cache()),
      acceptor_(acceptor) {
  http_framer_->set_balsa_visitor(this);
  http_framer_->set_balsa_headers(&headers_);
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY)
    http_framer_->set_is_request(false);
}
HttpSM::~HttpSM() {
  Reset();
  delete http_framer_;
}

void HttpSM::ProcessBodyData(const char *input, size_t size) {
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process Body Data: stream "
            << stream_id_ << ": size " << size;
    sm_spdy_interface_->SendDataFrame(stream_id_, input, size, 0, false);
  }
}

void HttpSM::ProcessHeaders(const BalsaHeaders& headers) {
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER) {
    std::string host =
      UrlUtilities::GetUrlHost(headers.GetHeader("Host").as_string());
    std::string method = headers.request_method().as_string();
    VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Received Request: "
            << headers.request_uri().as_string() << " " << method;
    std::string filename = EncodeURL(headers.request_uri().as_string(),
                                host, method);
    NewStream(stream_id_, 0, filename);
    stream_id_ += 2;
  } else {
    VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Received Response from "
            << connection_->server_ip_ << ":"
            << connection_->server_port_ << " ";
    sm_spdy_interface_->SendSynReply(stream_id_, headers);
  }
}

void HttpSM::MessageDone() {
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: MessageDone. Sending EOF: "
            << "stream " << stream_id_;
    sm_spdy_interface_->SendEOF(stream_id_);
  } else {
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: MessageDone.";
  }
}

void HttpSM::HandleHeaderError(BalsaFrame* framer) {
  HandleError();
}

void HttpSM::HandleChunkingError(BalsaFrame* framer) {
  HandleError();
}

void HttpSM::HandleBodyError(BalsaFrame* framer) {
  HandleError();
}

void HttpSM::HandleError() {
  VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Error detected";
}

void HttpSM::AddToOutputOrder(const MemCacheIter& mci) {
  output_ordering_.AddToOutputOrder(mci);
}

void HttpSM::SendOKResponse(uint32 stream_id, std::string* output) {
  SendOKResponseImpl(stream_id, output);
}

void HttpSM::InitSMInterface(SMInterface* sm_spdy_interface,
                             int32 server_idx) {
  sm_spdy_interface_ = sm_spdy_interface;
  server_idx_ = server_idx;
}

void HttpSM::InitSMConnection(SMConnectionPoolInterface* connection_pool,
                              SMInterface* sm_interface,
                              EpollServer* epoll_server,
                              int fd,
                              std::string server_ip,
                              std::string server_port,
                              std::string remote_ip,
                              bool use_ssl) {
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Initializing server "
          << "connection.";
  connection_->InitSMConnection(connection_pool,
                                sm_interface,
                                epoll_server,
                                fd,
                                server_ip,
                                server_port,
                                remote_ip,
                                use_ssl);
}

size_t HttpSM::ProcessReadInput(const char* data, size_t len) {
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process read input: stream "
          << stream_id_;
  return http_framer_->ProcessInput(data, len);
}

size_t HttpSM::ProcessWriteInput(const char* data, size_t len) {
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process write input: size "
          << len << ": stream " << stream_id_;
  char * dataPtr = new char[len];
  memcpy(dataPtr, data, len);
  DataFrame* data_frame = new DataFrame;
  data_frame->data = (const char *)dataPtr;
  data_frame->size = len;
  data_frame->delete_when_done = true;
  connection_->EnqueueDataFrame(data_frame);
  return len;
}

bool HttpSM::MessageFullyRead() const {
  return http_framer_->MessageFullyRead();
}

void HttpSM::SetStreamID(uint32 stream_id) {
  stream_id_ = stream_id;
}

bool HttpSM::Error() const {
  return http_framer_->Error();
}

const char* HttpSM::ErrorAsString() const {
  return BalsaFrameEnums::ErrorCodeToString(http_framer_->ErrorCode());
}

void HttpSM::Reset() {
  VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Reset: stream "
          << stream_id_;
  http_framer_->Reset();
}

void HttpSM::ResetForNewConnection() {
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
    VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Server connection closing "
      << "to: " << connection_->server_ip_ << ":"
      << connection_->server_port_ << " ";
  }
  // Message has not been fully read, either it is incomplete or the
  // server is closing the connection to signal message end.
  if (!MessageFullyRead()) {
    VLOG(2) << "HTTP response closed before end of file detected. "
            << "Sending EOF to spdy.";
    sm_spdy_interface_->SendEOF(stream_id_);
  }
  seq_num_ = 0;
  output_ordering_.Reset();
  http_framer_->Reset();
  if (sm_spdy_interface_) {
    sm_spdy_interface_->ResetForNewInterface(server_idx_);
  }
}

void HttpSM::Cleanup() {
  if (!(acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER)) {
    VLOG(2) << "HttpSM Request Fully Read; stream_id: " << stream_id_;
    connection_->Cleanup("request complete");
  }
}

int HttpSM::PostAcceptHook() {
  return 1;
}

void HttpSM::NewStream(uint32 stream_id, uint32 priority,
                       const std::string& filename) {
  MemCacheIter mci;
  mci.stream_id = stream_id;
  mci.priority = priority;
  if (!memory_cache_->AssignFileData(filename, &mci)) {
    // error creating new stream.
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending ErrorNotFound";
    SendErrorNotFound(stream_id);
  } else {
    AddToOutputOrder(mci);
  }
}

void HttpSM::SendEOF(uint32 stream_id) {
  SendEOFImpl(stream_id);
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
    sm_spdy_interface_->ResetForNewInterface(server_idx_);
  }
}

void HttpSM::SendErrorNotFound(uint32 stream_id) {
  SendErrorNotFoundImpl(stream_id);
}

size_t HttpSM::SendSynStream(uint32 stream_id, const BalsaHeaders& headers) {
  return 0;
}

size_t HttpSM::SendSynReply(uint32 stream_id, const BalsaHeaders& headers) {
  return SendSynReplyImpl(stream_id, headers);
}

void HttpSM::SendDataFrame(uint32 stream_id, const char* data, int64 len,
                   uint32 flags, bool compress) {
  SendDataFrameImpl(stream_id, data, len, flags, compress);
}

void HttpSM::SendEOFImpl(uint32 stream_id) {
  DataFrame* df = new DataFrame;
  df->data = "0\r\n\r\n";
  df->size = 5;
  df->delete_when_done = false;
  EnqueueDataFrame(df);
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER) {
    Reset();
  }
}

void HttpSM::SendErrorNotFoundImpl(uint32 stream_id) {
  BalsaHeaders my_headers;
  my_headers.SetFirstlineFromStringPieces("HTTP/1.1", "404", "Not Found");
  my_headers.RemoveAllOfHeader("content-length");
  my_headers.AppendHeader("transfer-encoding", "chunked");
  SendSynReplyImpl(stream_id, my_headers);
  SendDataFrame(stream_id, "page not found", 14, 0, false);
  SendEOFImpl(stream_id);
  output_ordering_.RemoveStreamId(stream_id);
}

void HttpSM::SendOKResponseImpl(uint32 stream_id, std::string* output) {
  BalsaHeaders my_headers;
  my_headers.SetFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
  my_headers.RemoveAllOfHeader("content-length");
  my_headers.AppendHeader("transfer-encoding", "chunked");
  SendSynReplyImpl(stream_id, my_headers);
  SendDataFrame(stream_id, output->c_str(), output->size(), 0, false);
  SendEOFImpl(stream_id);
  output_ordering_.RemoveStreamId(stream_id);
}

size_t HttpSM::SendSynReplyImpl(uint32 stream_id, const BalsaHeaders& headers) {
  SimpleBuffer sb;
  headers.WriteHeaderAndEndingToBuffer(&sb);
  DataFrame* df = new DataFrame;
  df->size = sb.ReadableBytes();
  char* buffer = new char[df->size];
  df->data = buffer;
  df->delete_when_done = true;
  sb.Read(buffer, df->size);
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending HTTP Reply header "
          << stream_id_;
  size_t df_size = df->size;
  EnqueueDataFrame(df);
  return df_size;
}

size_t HttpSM::SendSynStreamImpl(uint32 stream_id,
                                 const BalsaHeaders& headers) {
  SimpleBuffer sb;
  headers.WriteHeaderAndEndingToBuffer(&sb);
  DataFrame* df = new DataFrame;
  df->size = sb.ReadableBytes();
  char* buffer = new char[df->size];
  df->data = buffer;
  df->delete_when_done = true;
  sb.Read(buffer, df->size);
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending HTTP Reply header "
          << stream_id_;
  size_t df_size = df->size;
  EnqueueDataFrame(df);
  return df_size;
}

void HttpSM::SendDataFrameImpl(uint32 stream_id, const char* data, int64 len,
                       uint32 flags, bool compress) {
  char chunk_buf[128];
  snprintf(chunk_buf, sizeof(chunk_buf), "%x\r\n", (unsigned int)len);
  std::string chunk_description(chunk_buf);
  DataFrame* df = new DataFrame;
  df->size = chunk_description.size() + len + 2;
  char* buffer = new char[df->size];
  df->data = buffer;
  df->delete_when_done = true;
  memcpy(buffer, chunk_description.data(), chunk_description.size());
  memcpy(buffer + chunk_description.size(), data, len);
  memcpy(buffer + chunk_description.size() + len, "\r\n", 2);
  EnqueueDataFrame(df);
}

void HttpSM::EnqueueDataFrame(DataFrame* df) {
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Enqueue data frame: stream "
          << stream_id_;
  connection_->EnqueueDataFrame(df);
}

void HttpSM::GetOutput() {
  MemCacheIter* mci = output_ordering_.GetIter();
  if (mci == NULL) {
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput: nothing to "
            << "output!?: stream " << stream_id_;
    return;
  }
  if (!mci->transformed_header) {
    mci->bytes_sent = SendSynReply(mci->stream_id,
                                   *(mci->file_data->headers));
    mci->transformed_header = true;
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput transformed "
            << "header stream_id: [" << mci->stream_id << "]";
    return;
  }
  if (mci->body_bytes_consumed >= mci->file_data->body.size()) {
    SendEOF(mci->stream_id);
    output_ordering_.RemoveStreamId(mci->stream_id);
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "GetOutput remove_stream_id: ["
            << mci->stream_id << "]";
    return;
  }
  size_t num_to_write =
    mci->file_data->body.size() - mci->body_bytes_consumed;
  if (num_to_write > mci->max_segment_size)
    num_to_write = mci->max_segment_size;

  SendDataFrame(mci->stream_id,
                mci->file_data->body.data() + mci->body_bytes_consumed,
                num_to_write, 0, true);
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput SendDataFrame["
          << mci->stream_id << "]: " << num_to_write;
  mci->body_bytes_consumed += num_to_write;
  mci->bytes_sent += num_to_write;
}

}  // namespace net