http_interface.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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
13namespace net {
14
15HttpSM::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}
33HttpSM::~HttpSM() {
34  Reset();
35  delete http_framer_;
36}
37
38void 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
46void 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
66void 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
76void HttpSM::HandleHeaderError(BalsaFrame* framer) { HandleError(); }
77
78void HttpSM::HandleChunkingError(BalsaFrame* framer) { HandleError(); }
79
80void HttpSM::HandleBodyError(BalsaFrame* framer) { HandleError(); }
81
82void HttpSM::HandleError() {
83  VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Error detected";
84}
85
86void HttpSM::AddToOutputOrder(const MemCacheIter& mci) {
87  output_ordering_.AddToOutputOrder(mci);
88}
89
90void HttpSM::InitSMInterface(SMInterface* sm_spdy_interface, int32 server_idx) {
91  sm_spdy_interface_ = sm_spdy_interface;
92  server_idx_ = server_idx;
93}
94
95void 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
115size_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
121size_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
134bool HttpSM::MessageFullyRead() const {
135  return http_framer_->MessageFullyRead();
136}
137
138void HttpSM::SetStreamID(uint32 stream_id) { stream_id_ = stream_id; }
139
140bool HttpSM::Error() const { return http_framer_->Error(); }
141
142const char* HttpSM::ErrorAsString() const {
143  return BalsaFrameEnums::ErrorCodeToString(http_framer_->ErrorCode());
144}
145
146void HttpSM::Reset() {
147  VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Reset: stream " << stream_id_;
148  http_framer_->Reset();
149}
150
151void 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
171void 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
178int HttpSM::PostAcceptHook() { return 1; }
179
180void 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
195void 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
202void HttpSM::SendErrorNotFound(uint32 stream_id) {
203  SendErrorNotFoundImpl(stream_id);
204}
205
206size_t HttpSM::SendSynStream(uint32 stream_id, const BalsaHeaders& headers) {
207  return 0;
208}
209
210size_t HttpSM::SendSynReply(uint32 stream_id, const BalsaHeaders& headers) {
211  return SendSynReplyImpl(stream_id, headers);
212}
213
214void 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
222void 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
233void 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
244size_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
260size_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
277void 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
296void HttpSM::EnqueueDataFrame(DataFrame* df) {
297  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Enqueue data frame: stream "
298          << stream_id_;
299  connection_->EnqueueDataFrame(df);
300}
301
302void 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