• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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/quic/quic_spdy_server_stream.h"
6 
7 #include "base/memory/singleton.h"
8 #include "net/quic/quic_session.h"
9 #include "net/spdy/spdy_framer.h"
10 #include "net/tools/quic/quic_in_memory_cache.h"
11 #include "net/tools/quic/spdy_utils.h"
12 
13 using base::StringPiece;
14 using std::string;
15 
16 namespace net {
17 namespace tools {
18 
19 static const size_t kHeaderBufInitialSize = 4096;
20 
QuicSpdyServerStream(QuicStreamId id,QuicSession * session)21 QuicSpdyServerStream::QuicSpdyServerStream(QuicStreamId id,
22                                            QuicSession* session)
23     : QuicDataStream(id, session),
24       read_buf_(new GrowableIOBuffer()),
25       request_headers_received_(false) {
26 }
27 
~QuicSpdyServerStream()28 QuicSpdyServerStream::~QuicSpdyServerStream() {
29 }
30 
ProcessData(const char * data,uint32 length)31 uint32 QuicSpdyServerStream::ProcessData(const char* data, uint32 length) {
32   uint32 total_bytes_processed = 0;
33 
34   // Are we still reading the request headers.
35   if (!request_headers_received_) {
36     // Grow the read buffer if necessary.
37     if (read_buf_->RemainingCapacity() < (int)length) {
38       read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize);
39     }
40     memcpy(read_buf_->data(), data, length);
41     read_buf_->set_offset(read_buf_->offset() + length);
42     ParseRequestHeaders();
43   } else {
44     body_.append(data + total_bytes_processed, length - total_bytes_processed);
45   }
46   return length;
47 }
48 
OnFinRead()49 void QuicSpdyServerStream::OnFinRead() {
50   ReliableQuicStream::OnFinRead();
51   if (write_side_closed() || fin_buffered()) {
52     return;
53   }
54 
55   if (!request_headers_received_) {
56     SendErrorResponse();  // We're not done reading headers.
57   } else if ((headers_.content_length_status() ==
58              BalsaHeadersEnums::VALID_CONTENT_LENGTH) &&
59              body_.size() != headers_.content_length()) {
60     SendErrorResponse();  // Invalid content length
61   } else {
62     SendResponse();
63   }
64 }
65 
ParseRequestHeaders()66 int QuicSpdyServerStream::ParseRequestHeaders() {
67   size_t read_buf_len = static_cast<size_t>(read_buf_->offset());
68   SpdyFramer framer(SPDY3);
69   SpdyHeaderBlock headers;
70   char* data = read_buf_->StartOfBuffer();
71   size_t len = framer.ParseHeaderBlockInBuffer(data, read_buf_->offset(),
72                                                &headers);
73   if (len == 0) {
74     return -1;
75   }
76 
77   if (!SpdyUtils::FillBalsaRequestHeaders(headers, &headers_)) {
78     SendErrorResponse();
79     return -1;
80   }
81 
82   size_t delta = read_buf_len - len;
83   if (delta > 0) {
84     body_.append(data + len, delta);
85   }
86 
87   request_headers_received_ = true;
88   return len;
89 }
90 
SendResponse()91 void QuicSpdyServerStream::SendResponse() {
92   // Find response in cache. If not found, send error response.
93   const QuicInMemoryCache::Response* response =
94       QuicInMemoryCache::GetInstance()->GetResponse(headers_);
95   if (response == NULL) {
96     SendErrorResponse();
97     return;
98   }
99 
100   DLOG(INFO) << "Sending response for stream " << id();
101   SendHeadersAndBody(response->headers(), response->body());
102 }
103 
SendErrorResponse()104 void QuicSpdyServerStream::SendErrorResponse() {
105   DLOG(INFO) << "Sending error response for stream " << id();
106   BalsaHeaders headers;
107   headers.SetResponseFirstlineFromStringPieces(
108       "HTTP/1.1", "500", "Server Error");
109   headers.ReplaceOrAppendHeader("content-length", "3");
110   SendHeadersAndBody(headers, "bad");
111 }
112 
SendHeadersAndBody(const BalsaHeaders & response_headers,StringPiece body)113 void QuicSpdyServerStream:: SendHeadersAndBody(
114     const BalsaHeaders& response_headers,
115     StringPiece body) {
116   // We only support SPDY and HTTP, and neither handles bidirectional streaming.
117   if (!read_side_closed()) {
118     CloseReadSide();
119   }
120 
121   SpdyHeaderBlock header_block =
122       SpdyUtils::ResponseHeadersToSpdyHeaders(response_headers);
123 
124   string headers_string =
125       session()->compressor()->CompressHeaders(header_block);
126     WriteOrBufferData(headers_string, body.empty());
127 
128   if (!body.empty()) {
129     WriteOrBufferData(body, true);
130   }
131 }
132 
133 }  // namespace tools
134 }  // namespace net
135