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.
5 #include "net/tools/flip_server/http_interface.h"
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"
15 HttpSM::HttpSM(SMConnection* connection,
16 SMInterface* sm_spdy_interface,
17 MemoryCache* memory_cache,
18 FlipAcceptor* acceptor)
19 : http_framer_(new BalsaFrame),
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()),
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);
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);
46 void HttpSM::ProcessHeaders(const BalsaHeaders& headers) {
47 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER) {
49 UrlUtilities::GetUrlHost(headers.GetHeader("Host").as_string());
50 std::string method = headers.request_method().as_string();
51 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Received Request: "
52 << headers.request_uri().as_string() << " " << method;
53 std::string filename = EncodeURL(headers.request_uri().as_string(),
55 NewStream(stream_id_, 0, filename);
58 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Received Response from "
59 << connection_->server_ip_ << ":"
60 << connection_->server_port_ << " ";
61 sm_spdy_interface_->SendSynReply(stream_id_, headers);
65 void HttpSM::MessageDone() {
66 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
67 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: MessageDone. Sending EOF: "
68 << "stream " << stream_id_;
69 sm_spdy_interface_->SendEOF(stream_id_);
71 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: MessageDone.";
75 void HttpSM::HandleHeaderError(BalsaFrame* framer) {
79 void HttpSM::HandleChunkingError(BalsaFrame* framer) {
83 void HttpSM::HandleBodyError(BalsaFrame* framer) {
87 void HttpSM::HandleError() {
88 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Error detected";
91 void HttpSM::AddToOutputOrder(const MemCacheIter& mci) {
92 output_ordering_.AddToOutputOrder(mci);
95 void HttpSM::InitSMInterface(SMInterface* sm_spdy_interface,
97 sm_spdy_interface_ = sm_spdy_interface;
98 server_idx_ = server_idx;
101 void HttpSM::InitSMConnection(SMConnectionPoolInterface* connection_pool,
102 SMInterface* sm_interface,
103 EpollServer* epoll_server,
105 std::string server_ip,
106 std::string server_port,
107 std::string remote_ip,
109 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Initializing server "
111 connection_->InitSMConnection(connection_pool,
121 size_t HttpSM::ProcessReadInput(const char* data, size_t len) {
122 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process read input: stream "
124 return http_framer_->ProcessInput(data, len);
127 size_t HttpSM::ProcessWriteInput(const char* data, size_t len) {
128 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process write input: size "
129 << len << ": stream " << stream_id_;
130 char* dataPtr = new char[len];
131 memcpy(dataPtr, data, len);
132 DataFrame* data_frame = new DataFrame;
133 data_frame->data = dataPtr;
134 data_frame->size = len;
135 data_frame->delete_when_done = true;
136 connection_->EnqueueDataFrame(data_frame);
140 bool HttpSM::MessageFullyRead() const {
141 return http_framer_->MessageFullyRead();
144 void HttpSM::SetStreamID(uint32 stream_id) {
145 stream_id_ = stream_id;
148 bool HttpSM::Error() const {
149 return http_framer_->Error();
152 const char* HttpSM::ErrorAsString() const {
153 return BalsaFrameEnums::ErrorCodeToString(http_framer_->ErrorCode());
156 void HttpSM::Reset() {
157 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Reset: stream "
159 http_framer_->Reset();
162 void HttpSM::ResetForNewConnection() {
163 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
164 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Server connection closing "
165 << "to: " << connection_->server_ip_ << ":"
166 << connection_->server_port_ << " ";
168 // Message has not been fully read, either it is incomplete or the
169 // server is closing the connection to signal message end.
170 if (!MessageFullyRead()) {
171 VLOG(2) << "HTTP response closed before end of file detected. "
172 << "Sending EOF to spdy.";
173 sm_spdy_interface_->SendEOF(stream_id_);
175 output_ordering_.Reset();
176 http_framer_->Reset();
177 if (sm_spdy_interface_) {
178 sm_spdy_interface_->ResetForNewInterface(server_idx_);
182 void HttpSM::Cleanup() {
183 if (!(acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER)) {
184 VLOG(2) << "HttpSM Request Fully Read; stream_id: " << stream_id_;
185 connection_->Cleanup("request complete");
189 int HttpSM::PostAcceptHook() {
193 void HttpSM::NewStream(uint32 stream_id, uint32 priority,
194 const std::string& filename) {
196 mci.stream_id = stream_id;
197 mci.priority = priority;
198 if (!memory_cache_->AssignFileData(filename, &mci)) {
199 // error creating new stream.
200 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending ErrorNotFound";
201 SendErrorNotFound(stream_id);
203 AddToOutputOrder(mci);
207 void HttpSM::SendEOF(uint32 stream_id) {
208 SendEOFImpl(stream_id);
209 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
210 sm_spdy_interface_->ResetForNewInterface(server_idx_);
214 void HttpSM::SendErrorNotFound(uint32 stream_id) {
215 SendErrorNotFoundImpl(stream_id);
218 size_t HttpSM::SendSynStream(uint32 stream_id, const BalsaHeaders& headers) {
222 size_t HttpSM::SendSynReply(uint32 stream_id, const BalsaHeaders& headers) {
223 return SendSynReplyImpl(stream_id, headers);
226 void HttpSM::SendDataFrame(uint32 stream_id, const char* data, int64 len,
227 uint32 flags, bool compress) {
228 SendDataFrameImpl(stream_id, data, len, flags, compress);
231 void HttpSM::SendEOFImpl(uint32 stream_id) {
232 DataFrame* df = new DataFrame;
233 df->data = "0\r\n\r\n";
235 df->delete_when_done = false;
236 EnqueueDataFrame(df);
237 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER) {
242 void HttpSM::SendErrorNotFoundImpl(uint32 stream_id) {
243 BalsaHeaders my_headers;
244 my_headers.SetFirstlineFromStringPieces("HTTP/1.1", "404", "Not Found");
245 my_headers.RemoveAllOfHeader("content-length");
246 my_headers.AppendHeader("transfer-encoding", "chunked");
247 SendSynReplyImpl(stream_id, my_headers);
248 SendDataFrame(stream_id, "page not found", 14, 0, false);
249 SendEOFImpl(stream_id);
250 output_ordering_.RemoveStreamId(stream_id);
253 size_t HttpSM::SendSynReplyImpl(uint32 stream_id, const BalsaHeaders& headers) {
255 headers.WriteHeaderAndEndingToBuffer(&sb);
256 DataFrame* df = new DataFrame;
257 df->size = sb.ReadableBytes();
258 char* buffer = new char[df->size];
260 df->delete_when_done = true;
261 sb.Read(buffer, df->size);
262 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending HTTP Reply header "
264 size_t df_size = df->size;
265 EnqueueDataFrame(df);
269 size_t HttpSM::SendSynStreamImpl(uint32 stream_id,
270 const BalsaHeaders& headers) {
272 headers.WriteHeaderAndEndingToBuffer(&sb);
273 DataFrame* df = new DataFrame;
274 df->size = sb.ReadableBytes();
275 char* buffer = new char[df->size];
277 df->delete_when_done = true;
278 sb.Read(buffer, df->size);
279 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending HTTP Reply header "
281 size_t df_size = df->size;
282 EnqueueDataFrame(df);
286 void HttpSM::SendDataFrameImpl(uint32 stream_id, const char* data, int64 len,
287 uint32 flags, bool compress) {
289 snprintf(chunk_buf, sizeof(chunk_buf), "%x\r\n", (unsigned int)len);
290 std::string chunk_description(chunk_buf);
291 DataFrame* df = new DataFrame;
292 df->size = chunk_description.size() + len + 2;
293 char* buffer = new char[df->size];
295 df->delete_when_done = true;
296 memcpy(buffer, chunk_description.data(), chunk_description.size());
297 memcpy(buffer + chunk_description.size(), data, len);
298 memcpy(buffer + chunk_description.size() + len, "\r\n", 2);
299 EnqueueDataFrame(df);
302 void HttpSM::EnqueueDataFrame(DataFrame* df) {
303 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Enqueue data frame: stream "
305 connection_->EnqueueDataFrame(df);
308 void HttpSM::GetOutput() {
309 MemCacheIter* mci = output_ordering_.GetIter();
311 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput: nothing to "
312 << "output!?: stream " << stream_id_;
315 if (!mci->transformed_header) {
316 mci->bytes_sent = SendSynReply(mci->stream_id,
317 *(mci->file_data->headers()));
318 mci->transformed_header = true;
319 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput transformed "
320 << "header stream_id: [" << mci->stream_id << "]";
323 if (mci->body_bytes_consumed >= mci->file_data->body().size()) {
324 SendEOF(mci->stream_id);
325 output_ordering_.RemoveStreamId(mci->stream_id);
326 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "GetOutput remove_stream_id: ["
327 << mci->stream_id << "]";
330 size_t num_to_write =
331 mci->file_data->body().size() - mci->body_bytes_consumed;
332 if (num_to_write > mci->max_segment_size)
333 num_to_write = mci->max_segment_size;
335 SendDataFrame(mci->stream_id,
336 mci->file_data->body().data() + mci->body_bytes_consumed,
337 num_to_write, 0, true);
338 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput SendDataFrame["
339 << mci->stream_id << "]: " << num_to_write;
340 mci->body_bytes_consumed += num_to_write;
341 mci->bytes_sent += num_to_write;