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