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/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"
15 HttpSM::HttpSM(SMConnection
* connection
,
16 SMInterface
* sm_spdy_interface
,
17 EpollServer
* epoll_server
,
18 MemoryCache
* memory_cache
,
19 FlipAcceptor
* acceptor
)
21 http_framer_(new BalsaFrame
),
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()),
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);
40 void 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);
48 void HttpSM::ProcessHeaders(const BalsaHeaders
& headers
) {
49 if (acceptor_
->flip_handler_type_
== FLIP_HANDLER_HTTP_SERVER
) {
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(),
57 NewStream(stream_id_
, 0, filename
);
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
);
67 void 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_
);
73 VLOG(2) << ACCEPTOR_CLIENT_IDENT
<< "HttpSM: MessageDone.";
77 void HttpSM::HandleHeaderError(BalsaFrame
* framer
) {
81 void HttpSM::HandleChunkingError(BalsaFrame
* framer
) {
85 void HttpSM::HandleBodyError(BalsaFrame
* framer
) {
89 void HttpSM::HandleError() {
90 VLOG(1) << ACCEPTOR_CLIENT_IDENT
<< "Error detected";
93 void HttpSM::AddToOutputOrder(const MemCacheIter
& mci
) {
94 output_ordering_
.AddToOutputOrder(mci
);
97 void HttpSM::SendOKResponse(uint32 stream_id
, std::string
* output
) {
98 SendOKResponseImpl(stream_id
, output
);
101 void HttpSM::InitSMInterface(SMInterface
* sm_spdy_interface
,
103 sm_spdy_interface_
= sm_spdy_interface
;
104 server_idx_
= server_idx
;
107 void HttpSM::InitSMConnection(SMConnectionPoolInterface
* connection_pool
,
108 SMInterface
* sm_interface
,
109 EpollServer
* epoll_server
,
111 std::string server_ip
,
112 std::string server_port
,
113 std::string remote_ip
,
115 VLOG(2) << ACCEPTOR_CLIENT_IDENT
<< "HttpSM: Initializing server "
117 connection_
->InitSMConnection(connection_pool
,
127 size_t HttpSM::ProcessReadInput(const char* data
, size_t len
) {
128 VLOG(2) << ACCEPTOR_CLIENT_IDENT
<< "HttpSM: Process read input: stream "
130 return http_framer_
->ProcessInput(data
, len
);
133 size_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
);
146 bool HttpSM::MessageFullyRead() const {
147 return http_framer_
->MessageFullyRead();
150 void HttpSM::SetStreamID(uint32 stream_id
) {
151 stream_id_
= stream_id
;
154 bool HttpSM::Error() const {
155 return http_framer_
->Error();
158 const char* HttpSM::ErrorAsString() const {
159 return BalsaFrameEnums::ErrorCodeToString(http_framer_
->ErrorCode());
162 void HttpSM::Reset() {
163 VLOG(1) << ACCEPTOR_CLIENT_IDENT
<< "HttpSM: Reset: stream "
165 http_framer_
->Reset();
168 void 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_
<< " ";
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_
);
182 output_ordering_
.Reset();
183 http_framer_
->Reset();
184 if (sm_spdy_interface_
) {
185 sm_spdy_interface_
->ResetForNewInterface(server_idx_
);
189 void 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");
196 int HttpSM::PostAcceptHook() {
200 void HttpSM::NewStream(uint32 stream_id
, uint32 priority
,
201 const std::string
& filename
) {
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
);
210 AddToOutputOrder(mci
);
214 void 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_
);
221 void HttpSM::SendErrorNotFound(uint32 stream_id
) {
222 SendErrorNotFoundImpl(stream_id
);
225 size_t HttpSM::SendSynStream(uint32 stream_id
, const BalsaHeaders
& headers
) {
229 size_t HttpSM::SendSynReply(uint32 stream_id
, const BalsaHeaders
& headers
) {
230 return SendSynReplyImpl(stream_id
, headers
);
233 void HttpSM::SendDataFrame(uint32 stream_id
, const char* data
, int64 len
,
234 uint32 flags
, bool compress
) {
235 SendDataFrameImpl(stream_id
, data
, len
, flags
, compress
);
238 void HttpSM::SendEOFImpl(uint32 stream_id
) {
239 DataFrame
* df
= new DataFrame
;
240 df
->data
= "0\r\n\r\n";
242 df
->delete_when_done
= false;
243 EnqueueDataFrame(df
);
244 if (acceptor_
->flip_handler_type_
== FLIP_HANDLER_HTTP_SERVER
) {
249 void 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
);
260 void 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
);
271 size_t HttpSM::SendSynReplyImpl(uint32 stream_id
, const BalsaHeaders
& headers
) {
273 headers
.WriteHeaderAndEndingToBuffer(&sb
);
274 DataFrame
* df
= new DataFrame
;
275 df
->size
= sb
.ReadableBytes();
276 char* buffer
= new char[df
->size
];
278 df
->delete_when_done
= true;
279 sb
.Read(buffer
, df
->size
);
280 VLOG(2) << ACCEPTOR_CLIENT_IDENT
<< "Sending HTTP Reply header "
282 size_t df_size
= df
->size
;
283 EnqueueDataFrame(df
);
287 size_t HttpSM::SendSynStreamImpl(uint32 stream_id
,
288 const BalsaHeaders
& headers
) {
290 headers
.WriteHeaderAndEndingToBuffer(&sb
);
291 DataFrame
* df
= new DataFrame
;
292 df
->size
= sb
.ReadableBytes();
293 char* buffer
= new char[df
->size
];
295 df
->delete_when_done
= true;
296 sb
.Read(buffer
, df
->size
);
297 VLOG(2) << ACCEPTOR_CLIENT_IDENT
<< "Sending HTTP Reply header "
299 size_t df_size
= df
->size
;
300 EnqueueDataFrame(df
);
304 void HttpSM::SendDataFrameImpl(uint32 stream_id
, const char* data
, int64 len
,
305 uint32 flags
, bool compress
) {
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
];
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
);
320 void HttpSM::EnqueueDataFrame(DataFrame
* df
) {
321 VLOG(2) << ACCEPTOR_CLIENT_IDENT
<< "HttpSM: Enqueue data frame: stream "
323 connection_
->EnqueueDataFrame(df
);
326 void HttpSM::GetOutput() {
327 MemCacheIter
* mci
= output_ordering_
.GetIter();
329 VLOG(2) << ACCEPTOR_CLIENT_IDENT
<< "HttpSM: GetOutput: nothing to "
330 << "output!?: stream " << stream_id_
;
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
<< "]";
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
<< "]";
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
;
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
;