| Index: net/tools/quic/quic_simple_server_stream.cc
|
| diff --git a/net/tools/quic/quic_simple_server_stream.cc b/net/tools/quic/quic_simple_server_stream.cc
|
| index 8609999935b17f636347225b8e6cf126801ef9a3..11c310e7e2a3a556a4ff818a1c5dd0bd1a0e617b 100644
|
| --- a/net/tools/quic/quic_simple_server_stream.cc
|
| +++ b/net/tools/quic/quic_simple_server_stream.cc
|
| @@ -25,7 +25,10 @@ namespace net {
|
|
|
| QuicSimpleServerStream::QuicSimpleServerStream(QuicStreamId id,
|
| QuicSpdySession* session)
|
| - : QuicSpdyStream(id, session), content_length_(-1) {}
|
| + : QuicSpdyStream(id, session),
|
| + next_state_(INIT),
|
| + content_length_(-1),
|
| + body_chunks_consumed_(0) {}
|
|
|
| QuicSimpleServerStream::~QuicSimpleServerStream() {}
|
|
|
| @@ -38,6 +41,14 @@ void QuicSimpleServerStream::OnInitialHeadersComplete(bool fin,
|
| DVLOG(1) << "Invalid headers";
|
| SendErrorResponse();
|
| }
|
| +
|
| + const QuicInMemoryCache::Response* response =
|
| + QuicInMemoryCache::GetInstance()->GetResponse(
|
| + request_headers_[":authority"], request_headers_[":path"]);
|
| + if (response != nullptr) {
|
| + response_.set_response_type(response->response_type());
|
| + }
|
| +
|
| MarkHeadersConsumed(decompressed_headers().length());
|
| }
|
|
|
| @@ -68,6 +79,11 @@ void QuicSimpleServerStream::OnDataAvailable() {
|
| }
|
| if (!sequencer()->IsClosed()) {
|
| sequencer()->SetUnblocked();
|
| + if (response_.response_type() == QuicInMemoryCache::BIDIRECTIONAL) {
|
| + // This will continue send multipart body or trailers.
|
| + if (next_state_ != NONE)
|
| + DoLoop();
|
| + }
|
| return;
|
| }
|
|
|
| @@ -93,7 +109,8 @@ void QuicSimpleServerStream::OnDataAvailable() {
|
| return;
|
| }
|
|
|
| - SendResponse();
|
| + if (next_state_ != NONE)
|
| + DoLoop();
|
| }
|
|
|
| void QuicSimpleServerStream::PushResponse(
|
| @@ -111,7 +128,63 @@ void QuicSimpleServerStream::PushResponse(
|
| QuicSpdyStream::OnInitialHeadersComplete(/*fin=*/true, 0);
|
| }
|
|
|
| -void QuicSimpleServerStream::SendResponse() {
|
| +void QuicSimpleServerStream::SendNotFoundResponse() {
|
| + DVLOG(1) << "Sending not found response for stream " << id();
|
| +
|
| + SpdyHeaderBlock response_headers;
|
| + response_headers[":status"] = "404";
|
| + response_headers["content-length"] =
|
| + base::IntToString(strlen(kNotFoundResponseBody));
|
| + response_.set_response_type(QuicInMemoryCache::REGULAR_RESPONSE);
|
| + response_.set_headers(response_headers);
|
| + response_.set_body(kNotFoundResponseBody);
|
| +
|
| + next_state_ = SEND_HEADERS;
|
| + DoLoop();
|
| +}
|
| +
|
| +void QuicSimpleServerStream::SendErrorResponse() {
|
| + DVLOG(1) << "Sending error response for stream " << id();
|
| +
|
| + SpdyHeaderBlock response_headers;
|
| + response_headers[":status"] = "500";
|
| + response_headers["content-length"] =
|
| + base::UintToString(strlen(kErrorResponseBody));
|
| + response_.set_response_type(QuicInMemoryCache::REGULAR_RESPONSE);
|
| + response_.set_headers(response_headers);
|
| + response_.set_body(kErrorResponseBody);
|
| +
|
| + next_state_ = SEND_HEADERS;
|
| + DoLoop();
|
| +}
|
| +
|
| +void QuicSimpleServerStream::DoLoop() {
|
| + DCHECK_NE(NONE, next_state_);
|
| + do {
|
| + State state = next_state_;
|
| + next_state_ = NONE;
|
| + switch (state) {
|
| + case INIT:
|
| + Init();
|
| + break;
|
| + case SEND_HEADERS:
|
| + SendHeaders();
|
| + break;
|
| + case SEND_BODY:
|
| + SendBody();
|
| + break;
|
| + case SEND_TRAILERS:
|
| + SendTrailers();
|
| + break;
|
| + default:
|
| + NOTREACHED();
|
| + }
|
| + } while (next_state_ != NONE &&
|
| + (sequencer()->IsClosed() ||
|
| + response_.response_type() != QuicInMemoryCache::BIDIRECTIONAL));
|
| +}
|
| +
|
| +void QuicSimpleServerStream::Init() {
|
| if (!ContainsKey(request_headers_, ":authority") ||
|
| !ContainsKey(request_headers_, ":path")) {
|
| DVLOG(1) << "Request headers do not contain :authority or :path.";
|
| @@ -186,66 +259,70 @@ void QuicSimpleServerStream::SendResponse() {
|
| }
|
|
|
| DVLOG(1) << "Sending response for stream " << id();
|
| - SendHeadersAndBodyAndTrailers(response->headers(), response->body(),
|
| - response->trailers());
|
| + response_.set_response_type(response->response_type());
|
| + response_.set_headers(response->headers());
|
| + response_.set_body(response->body());
|
| + response_.set_trailers(response->trailers());
|
| + response_.SetBodyChunks(response->body_chunks());
|
| + next_state_ = SEND_HEADERS;
|
| }
|
|
|
| -void QuicSimpleServerStream::SendNotFoundResponse() {
|
| - DVLOG(1) << "Sending not found response for stream " << id();
|
| - SpdyHeaderBlock headers;
|
| - headers[":status"] = "404";
|
| - headers["content-length"] = base::IntToString(strlen(kNotFoundResponseBody));
|
| - SendHeadersAndBody(headers, kNotFoundResponseBody);
|
| -}
|
| -
|
| -void QuicSimpleServerStream::SendErrorResponse() {
|
| - DVLOG(1) << "Sending error response for stream " << id();
|
| - SpdyHeaderBlock headers;
|
| - headers[":status"] = "500";
|
| - headers["content-length"] = base::UintToString(strlen(kErrorResponseBody));
|
| - SendHeadersAndBody(headers, kErrorResponseBody);
|
| -}
|
| -
|
| -void QuicSimpleServerStream::SendHeadersAndBody(
|
| - const SpdyHeaderBlock& response_headers,
|
| - StringPiece body) {
|
| - SendHeadersAndBodyAndTrailers(response_headers, body, SpdyHeaderBlock());
|
| -}
|
| -
|
| -void QuicSimpleServerStream::SendHeadersAndBodyAndTrailers(
|
| - const SpdyHeaderBlock& response_headers,
|
| - StringPiece body,
|
| - const SpdyHeaderBlock& response_trailers) {
|
| - // This server only supports SPDY and HTTP, and neither handles bidirectional
|
| - // streaming.
|
| - if (!reading_stopped()) {
|
| - StopReading();
|
| +void QuicSimpleServerStream::SendHeaders() {
|
| + // Stop reading if this response is not bidirectional.
|
| + if (response_.response_type() != QuicInMemoryCache::BIDIRECTIONAL) {
|
| + if (!reading_stopped()) {
|
| + StopReading();
|
| + }
|
| }
|
| -
|
| // Send the headers, with a FIN if there's nothing else to send.
|
| - bool send_fin = (body.empty() && response_trailers.empty());
|
| + bool send_fin =
|
| + (response_.body().empty() && response_.body_chunks().empty() &&
|
| + response_.trailers().empty());
|
| DVLOG(1) << "Writing headers (fin = " << send_fin
|
| - << ") : " << response_headers.DebugString();
|
| - WriteHeaders(response_headers, send_fin, nullptr);
|
| + << ") : " << response_.headers().DebugString();
|
| + WriteHeaders(response_.headers(), send_fin, nullptr);
|
| if (send_fin) {
|
| // Nothing else to send.
|
| return;
|
| }
|
| + next_state_ = SEND_BODY;
|
| +}
|
|
|
| - // Send the body, with a FIN if there's nothing else to send.
|
| - send_fin = response_trailers.empty();
|
| - DVLOG(1) << "Writing body (fin = " << send_fin
|
| - << ") with size: " << body.size();
|
| - WriteOrBufferData(body, send_fin, nullptr);
|
| - if (send_fin) {
|
| - // Nothing else to send.
|
| - return;
|
| +void QuicSimpleServerStream::SendBody() {
|
| + if (response_.response_type() == QuicInMemoryCache::BIDIRECTIONAL) {
|
| + if (response_.body_chunks().size() > body_chunks_consumed_) {
|
| + WriteOrBufferData(
|
| + response_.body_chunks().at(body_chunks_consumed_),
|
| + response_.trailers().empty() &&
|
| + body_chunks_consumed_ + 1 == response_.body_chunks().size(),
|
| + nullptr);
|
| + body_chunks_consumed_++;
|
| + next_state_ = SEND_BODY;
|
| + } else if (response_.body_chunks().size() == body_chunks_consumed_) {
|
| + if (response_.trailers().empty())
|
| + return;
|
| + next_state_ = SEND_TRAILERS;
|
| + }
|
| + } else {
|
| + // Send the body, with a FIN if there's nothing else to send.
|
| + bool send_fin = response_.trailers().empty();
|
| + DVLOG(1) << "Writing body (fin = " << send_fin
|
| + << ") with size: " << response_.body().size();
|
| + WriteOrBufferData(response_.body(), send_fin, nullptr);
|
| + if (send_fin) {
|
| + // Nothing else to send.
|
| + return;
|
| + }
|
| + next_state_ = SEND_TRAILERS;
|
| }
|
| +}
|
|
|
| +void QuicSimpleServerStream::SendTrailers() {
|
| // Send the trailers. A FIN is always sent with trailers.
|
| DVLOG(1) << "Writing trailers (fin = true): "
|
| - << response_trailers.DebugString();
|
| - WriteTrailers(response_trailers, nullptr);
|
| + << response_.trailers().DebugString();
|
| + WriteTrailers(response_.trailers(), nullptr);
|
| + next_state_ = NONE;
|
| }
|
|
|
| const char* const QuicSimpleServerStream::kErrorResponseBody = "bad";
|
|
|