1// Copyright 2014 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/quic/quic_spdy_server_stream.h"
6
7#include "base/memory/singleton.h"
8#include "base/strings/string_number_conversions.h"
9#include "net/quic/quic_in_memory_cache.h"
10#include "net/quic/quic_session.h"
11#include "net/quic/spdy_utils.h"
12#include "net/spdy/spdy_framer.h"
13#include "net/spdy/spdy_header_block.h"
14#include "net/spdy/spdy_http_utils.h"
15
16using base::StringPiece;
17using std::string;
18
19namespace net {
20
21static const size_t kHeaderBufInitialSize = 4096;
22
23QuicSpdyServerStream::QuicSpdyServerStream(QuicStreamId id,
24                                           QuicSession* session)
25    : QuicDataStream(id, session),
26      read_buf_(new GrowableIOBuffer()),
27      request_headers_received_(false) {
28  read_buf_->SetCapacity(kHeaderBufInitialSize);
29}
30
31QuicSpdyServerStream::~QuicSpdyServerStream() {
32}
33
34uint32 QuicSpdyServerStream::ProcessData(const char* data, uint32 data_len) {
35  if (data_len > INT_MAX) {
36    LOG(DFATAL) << "Data length too long: " << data_len;
37    return 0;
38  }
39  // Are we still reading the request headers.
40  if (!request_headers_received_) {
41    // Grow the read buffer if necessary.
42    while (read_buf_->RemainingCapacity() < static_cast<int>(data_len)) {
43      read_buf_->SetCapacity(read_buf_->capacity() * 2);
44    }
45    memcpy(read_buf_->data(), data, data_len);
46    read_buf_->set_offset(read_buf_->offset() + data_len);
47    // Try parsing the request headers. This will set request_headers_received_
48    // if successful; if not, it will be tried again with more data.
49    ParseRequestHeaders();
50  } else {
51    body_.append(data, data_len);
52  }
53  return data_len;
54}
55
56void QuicSpdyServerStream::OnFinRead() {
57  ReliableQuicStream::OnFinRead();
58  if (write_side_closed() || fin_buffered()) {
59    return;
60  }
61
62  if (!request_headers_received_) {
63    SendErrorResponse();  // We're not done reading headers.
64    return;
65  }
66
67  SpdyHeaderBlock::const_iterator it = headers_.find("content-length");
68  size_t content_length;
69  if (it != headers_.end() &&
70      (!base::StringToSizeT(it->second, &content_length) ||
71       body_.size() != content_length)) {
72    SendErrorResponse();  // Invalid content length
73    return;
74  }
75
76  SendResponse();
77}
78
79// Try parsing the request headers. If successful, sets
80// request_headers_received_. If not successful, it can just be tried again once
81// there's more data.
82void QuicSpdyServerStream::ParseRequestHeaders() {
83  SpdyFramer framer((kDefaultSpdyMajorVersion));
84  const char* data = read_buf_->StartOfBuffer();
85  size_t read_buf_len = static_cast<size_t>(read_buf_->offset());
86  size_t len = framer.ParseHeaderBlockInBuffer(data, read_buf_len, &headers_);
87  if (len == 0) {
88    // Not enough data yet, presumably. (If we still don't succeed by the end of
89    // the stream, then we'll error in OnFinRead().)
90    return;
91  }
92
93  // Headers received and parsed: extract the request URL.
94  request_url_ = GetUrlFromHeaderBlock(headers_,
95                                       kDefaultSpdyMajorVersion,
96                                       false);
97  if (!request_url_.is_valid()) {
98    SendErrorResponse();
99    return;
100  }
101
102  // Add any data past the headers to the request body.
103  size_t delta = read_buf_len - len;
104  if (delta > 0) {
105    body_.append(data + len, delta);
106  }
107
108  request_headers_received_ = true;
109}
110
111void QuicSpdyServerStream::SendResponse() {
112  // Find response in cache. If not found, send error response.
113  const QuicInMemoryCache::Response* response =
114      QuicInMemoryCache::GetInstance()->GetResponse(request_url_);
115  if (response == NULL) {
116    SendErrorResponse();
117    return;
118  }
119
120  if (response->response_type() == QuicInMemoryCache::CLOSE_CONNECTION) {
121    DVLOG(1) << "Special response: closing connection.";
122    CloseConnection(QUIC_NO_ERROR);
123    return;
124  }
125
126  if (response->response_type() == QuicInMemoryCache::IGNORE_REQUEST) {
127    DVLOG(1) << "Special response: ignoring request.";
128    return;
129  }
130
131  DVLOG(1) << "Sending response for stream " << id();
132  SendHeadersAndBody(response->headers(), response->body());
133}
134
135void QuicSpdyServerStream::SendErrorResponse() {
136  DVLOG(1) << "Sending error response for stream " << id();
137  scoped_refptr<HttpResponseHeaders> headers
138      = new HttpResponseHeaders(string("HTTP/1.1 500 Server Error") + '\0' +
139                                "content-length: 3" + '\0' + '\0');
140  SendHeadersAndBody(*headers.get(), "bad");
141}
142
143void QuicSpdyServerStream::SendHeadersAndBody(
144    const HttpResponseHeaders& response_headers,
145    StringPiece body) {
146  // We only support SPDY and HTTP, and neither handles bidirectional streaming.
147  if (!read_side_closed()) {
148    CloseReadSide();
149  }
150
151  SpdyHeaderBlock header_block;
152  CreateSpdyHeadersFromHttpResponse(response_headers,
153                                    kDefaultSpdyMajorVersion,
154                                    &header_block);
155
156  WriteHeaders(header_block, body.empty(), NULL);
157
158  if (!body.empty()) {
159    WriteOrBufferData(body, true, NULL);
160  }
161}
162
163}  // namespace net
164