Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / net / quic / quic_spdy_server_stream.cc
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
16 using base::StringPiece;
17 using std::string;
18
19 namespace net {
20
21 static const size_t kHeaderBufInitialSize = 4096;
22
23 QuicSpdyServerStream::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
31 QuicSpdyServerStream::~QuicSpdyServerStream() {
32 }
33
34 uint32 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
56 void 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.
82 void 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
111 void 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
135 void 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
143 void 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