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
52 << "Received Request: " << headers
.request_uri().as_string() << " "
54 std::string filename
=
55 EncodeURL(headers
.request_uri().as_string(), host
, method
);
56 NewStream(stream_id_
, 0, filename
);
59 VLOG(1) << ACCEPTOR_CLIENT_IDENT
<< "HttpSM: Received Response from "
60 << connection_
->server_ip_
<< ":" << connection_
->server_port_
62 sm_spdy_interface_
->SendSynReply(stream_id_
, headers
);
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_
);
72 VLOG(2) << ACCEPTOR_CLIENT_IDENT
<< "HttpSM: MessageDone.";
76 void HttpSM::HandleHeaderError(BalsaFrame
* framer
) { HandleError(); }
78 void HttpSM::HandleChunkingError(BalsaFrame
* framer
) { HandleError(); }
80 void HttpSM::HandleBodyError(BalsaFrame
* framer
) { HandleError(); }
82 void HttpSM::HandleError() {
83 VLOG(1) << ACCEPTOR_CLIENT_IDENT
<< "Error detected";
86 void HttpSM::AddToOutputOrder(const MemCacheIter
& mci
) {
87 output_ordering_
.AddToOutputOrder(mci
);
90 void HttpSM::InitSMInterface(SMInterface
* sm_spdy_interface
, int32 server_idx
) {
91 sm_spdy_interface_
= sm_spdy_interface
;
92 server_idx_
= server_idx
;
95 void HttpSM::InitSMConnection(SMConnectionPoolInterface
* connection_pool
,
96 SMInterface
* sm_interface
,
97 EpollServer
* epoll_server
,
99 std::string server_ip
,
100 std::string server_port
,
101 std::string remote_ip
,
103 VLOG(2) << ACCEPTOR_CLIENT_IDENT
<< "HttpSM: Initializing server "
105 connection_
->InitSMConnection(connection_pool
,
115 size_t HttpSM::ProcessReadInput(const char* data
, size_t len
) {
116 VLOG(2) << ACCEPTOR_CLIENT_IDENT
<< "HttpSM: Process read input: stream "
118 return http_framer_
->ProcessInput(data
, len
);
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
);
134 bool HttpSM::MessageFullyRead() const {
135 return http_framer_
->MessageFullyRead();
138 void HttpSM::SetStreamID(uint32 stream_id
) { stream_id_
= stream_id
; }
140 bool HttpSM::Error() const { return http_framer_
->Error(); }
142 const char* HttpSM::ErrorAsString() const {
143 return BalsaFrameEnums::ErrorCodeToString(http_framer_
->ErrorCode());
146 void HttpSM::Reset() {
147 VLOG(1) << ACCEPTOR_CLIENT_IDENT
<< "HttpSM: Reset: stream " << stream_id_
;
148 http_framer_
->Reset();
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_
<< " ";
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_
);
164 output_ordering_
.Reset();
165 http_framer_
->Reset();
166 if (sm_spdy_interface_
) {
167 sm_spdy_interface_
->ResetForNewInterface(server_idx_
);
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");
178 int HttpSM::PostAcceptHook() { return 1; }
180 void HttpSM::NewStream(uint32 stream_id
,
182 const std::string
& filename
) {
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
);
191 AddToOutputOrder(mci
);
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_
);
202 void HttpSM::SendErrorNotFound(uint32 stream_id
) {
203 SendErrorNotFoundImpl(stream_id
);
206 size_t HttpSM::SendSynStream(uint32 stream_id
, const BalsaHeaders
& headers
) {
210 size_t HttpSM::SendSynReply(uint32 stream_id
, const BalsaHeaders
& headers
) {
211 return SendSynReplyImpl(stream_id
, headers
);
214 void HttpSM::SendDataFrame(uint32 stream_id
,
219 SendDataFrameImpl(stream_id
, data
, len
, flags
, compress
);
222 void HttpSM::SendEOFImpl(uint32 stream_id
) {
223 DataFrame
* df
= new DataFrame
;
224 df
->data
= "0\r\n\r\n";
226 df
->delete_when_done
= false;
227 EnqueueDataFrame(df
);
228 if (acceptor_
->flip_handler_type_
== FLIP_HANDLER_HTTP_SERVER
) {
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
);
244 size_t HttpSM::SendSynReplyImpl(uint32 stream_id
, const BalsaHeaders
& headers
) {
246 headers
.WriteHeaderAndEndingToBuffer(&sb
);
247 DataFrame
* df
= new DataFrame
;
248 df
->size
= sb
.ReadableBytes();
249 char* buffer
= new char[df
->size
];
251 df
->delete_when_done
= true;
252 sb
.Read(buffer
, df
->size
);
253 VLOG(2) << ACCEPTOR_CLIENT_IDENT
<< "Sending HTTP Reply header "
255 size_t df_size
= df
->size
;
256 EnqueueDataFrame(df
);
260 size_t HttpSM::SendSynStreamImpl(uint32 stream_id
,
261 const BalsaHeaders
& headers
) {
263 headers
.WriteHeaderAndEndingToBuffer(&sb
);
264 DataFrame
* df
= new DataFrame
;
265 df
->size
= sb
.ReadableBytes();
266 char* buffer
= new char[df
->size
];
268 df
->delete_when_done
= true;
269 sb
.Read(buffer
, df
->size
);
270 VLOG(2) << ACCEPTOR_CLIENT_IDENT
<< "Sending HTTP Reply header "
272 size_t df_size
= df
->size
;
273 EnqueueDataFrame(df
);
277 void HttpSM::SendDataFrameImpl(uint32 stream_id
,
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
];
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
);
296 void HttpSM::EnqueueDataFrame(DataFrame
* df
) {
297 VLOG(2) << ACCEPTOR_CLIENT_IDENT
<< "HttpSM: Enqueue data frame: stream "
299 connection_
->EnqueueDataFrame(df
);
302 void HttpSM::GetOutput() {
303 MemCacheIter
* mci
= output_ordering_
.GetIter();
305 VLOG(2) << ACCEPTOR_CLIENT_IDENT
<< "HttpSM: GetOutput: nothing to "
306 << "output!?: stream " << stream_id_
;
309 if (!mci
->transformed_header
) {
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
<< "]";
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
<< "]";
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
;
329 SendDataFrame(mci
->stream_id
,
330 mci
->file_data
->body().data() + mci
->body_bytes_consumed
,
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
;