1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// TODO(rtenhove) clean up frame buffer size calculations so that we aren't
6201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// constantly adding and subtracting header sizes; this is ugly and error-
7201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// prone.
8201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/spdy/spdy_framer.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h"
12731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/metrics/stats_counters.h"
130888ad5615957327be92abf6dcbb768a1977ab49Kristian Monsen#ifndef ANDROID
14dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/third_party/valgrind/memcheck.h"
150888ad5615957327be92abf6dcbb768a1977ab49Kristian Monsen#endif
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/spdy/spdy_frame_builder.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/spdy/spdy_bitmasks.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(USE_SYSTEM_ZLIB)
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <zlib.h>
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "third_party/zlib/zlib.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsennamespace {
2672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
2772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// The following compression setting are based on Brian Olson's analysis. See
2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// https://groups.google.com/group/spdy-dev/browse_thread/thread/dfaf498542fac792
2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// for more details.
30de6c9f9aec5e2e7e66cb77140f7418fc29644ef0Selim Gurun#ifdef ANDROID
31de6c9f9aec5e2e7e66cb77140f7418fc29644ef0Selim Gurunconst int kCompressorLevel = 0;
32de6c9f9aec5e2e7e66cb77140f7418fc29644ef0Selim Gurun#else
3372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst int kCompressorLevel = 9;
34de6c9f9aec5e2e7e66cb77140f7418fc29644ef0Selim Gurun#endif
3572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst int kCompressorWindowSizeInBits = 11;
3672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst int kCompressorMemLevel = 1;
3772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
382c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun// Adler ID for the SPDY header compressor dictionary.
3972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenuLong dictionary_id = 0;
4072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
4172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}  // namespace
4272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace spdy {
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// This is just a hacked dictionary to use for shrinking HTTP-like headers.
4672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// TODO(mbelshe): Use a scientific methodology for computing the dictionary.
4772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst char SpdyFramer::kDictionary[] =
4872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-"
4972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi"
5072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser"
5172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  "-agent10010120020120220320420520630030130230330430530630740040140240340440"
5272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  "5406407408409410411412413414415416417500501502503504505accept-rangesageeta"
5372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic"
5472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran"
5572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati"
5672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo"
5772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe"
5872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic"
5972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1"
6072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ".1statusversionurl";
6172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst int SpdyFramer::kDictionarySize = arraysize(kDictionary);
6272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// By default is compression on or off.
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SpdyFramer::compression_default_ = true;
653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint SpdyFramer::spdy_version_ = kSpdyProtocolVersion;
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
67201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// The initial size of the control frame buffer; this is used internally
68201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// as we parse through control frames. (It is exposed here for unit test
69201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// purposes.)
70201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochsize_t SpdyFramer::kControlFrameBufferInitialSize = 8 * 1024;
71201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
72201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// The maximum size of the control frame buffer that we support.
73201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// TODO(mbelshe): We should make this stream-based so there are no limits.
74201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochsize_t SpdyFramer::kControlFrameBufferMaxSize = 16 * 1024;
75201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
762c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurunconst SpdyStreamId SpdyFramer::kInvalidStream = -1;
772c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurunconst size_t SpdyFramer::kHeaderDataChunkMaxSize = 1024;
782c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#ifdef DEBUG_SPDY_STATE_CHANGES
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define CHANGE_STATE(newstate) \
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch{ \
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  do { \
83201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    LOG(INFO) << "Changing state from: " \
84201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      << StateToString(state_) \
85201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      << " to " << StateToString(newstate) << "\n"; \
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    state_ = newstate; \
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } while (false); \
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define CHANGE_STATE(newstate) (state_ = newstate)
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
932c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurunint DecompressHeaderBlockInZStream(z_stream* decompressor) {
942c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  int rv = inflate(decompressor, Z_SYNC_FLUSH);
952c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  if (rv == Z_NEED_DICT) {
962c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    // Need to try again with the right dictionary.
972c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    if (decompressor->adler == dictionary_id) {
982c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      rv = inflateSetDictionary(decompressor,
992c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                                (const Bytef*)SpdyFramer::kDictionary,
1002c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                                SpdyFramer::kDictionarySize);
1012c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      if (rv == Z_OK)
1022c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        rv = inflate(decompressor, Z_SYNC_FLUSH);
1032c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    }
1042c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
1052c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return rv;
1062c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
1072c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
1082c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun// Retrieve serialized length of SpdyHeaderBlock.
1092c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurunsize_t GetSerializedLength(const SpdyHeaderBlock* headers) {
1102c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  size_t total_length = SpdyControlFrame::kNumNameValuePairsSize;
1112c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  SpdyHeaderBlock::const_iterator it;
1122c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  for (it = headers->begin(); it != headers->end(); ++it) {
1132c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    // We add space for the length of the name and the length of the value as
1142c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    // well as the length of the name and the length of the value.
1152c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    total_length += SpdyControlFrame::kLengthOfNameSize +
1162c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                    it->first.size() +
1172c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                    SpdyControlFrame::kLengthOfValueSize +
1182c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                    it->second.size();
1192c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
1202c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return total_length;
1212c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
1222c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
1232c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun// Serializes a SpdyHeaderBlock.
1242c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurunvoid WriteHeaderBlock(SpdyFrameBuilder* frame, const SpdyHeaderBlock* headers) {
1252c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  frame->WriteUInt16(headers->size());  // Number of headers.
1262c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  SpdyHeaderBlock::const_iterator it;
1272c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  for (it = headers->begin(); it != headers->end(); ++it) {
1282c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    bool wrote_header;
1292c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    wrote_header = frame->WriteString(it->first);
1302c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    wrote_header &= frame->WriteString(it->second);
1312c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    DCHECK(wrote_header);
1322c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
1332c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
1342c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
1352c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun// Creates a FlagsAndLength.
1362c4085b2006233b5e3a3fe507d62642377b5dc2eSelim GurunFlagsAndLength CreateFlagsAndLength(SpdyControlFlags flags, size_t length) {
1372c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask));
1382c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  FlagsAndLength flags_length;
1392c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  flags_length.length_ = htonl(static_cast<uint32>(length));
1402c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  DCHECK_EQ(0, flags & ~kControlFlagsMask);
1412c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  flags_length.flags_[0] = flags;
1422c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return flags_length;
1432c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
1442c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSpdyFramer::SpdyFramer()
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : state_(SPDY_RESET),
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_code_(SPDY_NO_ERROR),
1482c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      remaining_data_(0),
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      remaining_control_payload_(0),
1502c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      remaining_control_header_(0),
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      current_frame_buffer_(NULL),
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      current_frame_len_(0),
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      current_frame_capacity_(0),
1542c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      validate_control_frame_sizes_(true),
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      enable_compression_(compression_default_),
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      visitor_(NULL) {
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSpdyFramer::~SpdyFramer() {
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (header_compressor_.get()) {
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    deflateEnd(header_compressor_.get());
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (header_decompressor_.get()) {
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    inflateEnd(header_decompressor_.get());
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CleanupStreamCompressorsAndDecompressors();
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete [] current_frame_buffer_;
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1702c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurunconst char* SpdyFramer::StatusCodeToString(int status_code) {
1712c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  switch (status_code) {
1722c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case INVALID:
1732c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return "INVALID";
1742c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case PROTOCOL_ERROR:
1752c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return "PROTOCOL_ERROR";
1762c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case INVALID_STREAM:
1772c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return "INVALID_STREAM";
1782c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case REFUSED_STREAM:
1792c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return "REFUSED_STREAM";
1802c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case UNSUPPORTED_VERSION:
1812c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return "UNSUPPORTED_VERSION";
1822c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case CANCEL:
1832c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return "CANCEL";
1842c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case INTERNAL_ERROR:
1852c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return "INTERNAL_ERROR";
1862c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case FLOW_CONTROL_ERROR:
1872c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return "FLOW_CONTROL_ERROR";
1882c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
1892c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return "UNKNOWN_STATUS";
1902c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
1912c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
1922c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurunconst char* SpdyFramer::ControlTypeToString(SpdyControlType type) {
1932c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  switch (type) {
1942c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case SYN_STREAM:
1952c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return "SYN_STREAM";
1962c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case SYN_REPLY:
1972c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return "SYN_REPLY";
1982c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case RST_STREAM:
1992c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return "RST_STREAM";
2002c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case SETTINGS:
2012c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return "SETTINGS";
2022c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case NOOP:
2032c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return "NOOP";
2042c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case PING:
2052c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return "PING";
2062c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case GOAWAY:
2072c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return "GOAWAY";
2082c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case HEADERS:
2092c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return "HEADERS";
2102c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case WINDOW_UPDATE:
2112c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return "WINDOW_UPDATE";
2122c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case NUM_CONTROL_FRAME_TYPES:
2132c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      break;
2142c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
2152c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return "UNKNOWN_CONTROL_TYPE";
2162c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
2172c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochsize_t SpdyFramer::ProcessInput(const char* data, size_t len) {
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(visitor_);
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(data);
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t original_len = len;
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (len != 0) {
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    switch (state_) {
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case SPDY_ERROR:
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case SPDY_DONE:
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        goto bottom;
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case SPDY_AUTO_RESET:
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case SPDY_RESET:
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        Reset();
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        CHANGE_STATE(SPDY_READING_COMMON_HEADER);
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case SPDY_READING_COMMON_HEADER: {
2363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        size_t bytes_read = ProcessCommonHeader(data, len);
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        len -= bytes_read;
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        data += bytes_read;
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Arguably, this case is not necessary, as no bytes are consumed here.
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // I felt it was a nice partitioning, however (which probably indicates
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // that it should be refactored into its own function!)
2452c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      // TODO(hkhalil): Remove -- while loop above prevents proper handling of
2462c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      // zero-length control frames.
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER:
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ProcessControlFrameHeader();
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2512c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      case SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK: {
2522c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        // Control frames that contain header blocks (SYN_STREAM, SYN_REPLY,
2532c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        // HEADERS) take a different path through the state machine - they
2542c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        // will go:
2552c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        //   1. SPDY_INTERPRET_CONTROL_FRAME_COMMON HEADER
2562c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        //   2. SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK
2572c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        //   3. SPDY_CONTROL_FRAME_HEADER_BLOCK
2582c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        //
2592c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        //  All other control frames will use the alternate route:
2602c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        //   1. SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER
2612c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        //   2. SPDY_CONTROL_FRAME_PAYLOAD
2622c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        int bytes_read = ProcessControlFrameBeforeHeaderBlock(data, len);
2632c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        len -= bytes_read;
2642c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        data += bytes_read;
2652c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        continue;
2662c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      }
2672c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
2682c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      case SPDY_CONTROL_FRAME_HEADER_BLOCK: {
2692c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        int bytes_read = ProcessControlFrameHeaderBlock(data, len);
2702c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        len -= bytes_read;
2712c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        data += bytes_read;
2722c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        continue;
2732c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      }
2742c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case SPDY_CONTROL_FRAME_PAYLOAD: {
2763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        size_t bytes_read = ProcessControlFramePayload(data, len);
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        len -= bytes_read;
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        data += bytes_read;
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // intentional fallthrough
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case SPDY_IGNORE_REMAINING_PAYLOAD:
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // control frame has too-large payload
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // intentional fallthrough
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case SPDY_FORWARD_STREAM_FRAME: {
2853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        size_t bytes_read = ProcessDataFramePayload(data, len);
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        len -= bytes_read;
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        data += bytes_read;
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      default:
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bottom:
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return original_len - len;
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
29872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid SpdyFramer::Reset() {
29972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  state_ = SPDY_RESET;
30072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  error_code_ = SPDY_NO_ERROR;
3012c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  remaining_data_ = 0;
30272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  remaining_control_payload_ = 0;
3032c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  remaining_control_header_ = 0;
30472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  current_frame_len_ = 0;
30572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (current_frame_capacity_ != kControlFrameBufferInitialSize) {
30672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    delete [] current_frame_buffer_;
30772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    current_frame_buffer_ = 0;
30872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    current_frame_capacity_ = 0;
30972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ExpandControlFrameBuffer(kControlFrameBufferInitialSize);
31072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
31372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool SpdyFramer::ParseHeaderBlock(const SpdyFrame* frame,
31472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                  SpdyHeaderBlock* block) {
31572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  SpdyControlFrame control_frame(frame->data(), false);
31672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  uint32 type = control_frame.type();
31772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (type != SYN_STREAM && type != SYN_REPLY && type != HEADERS)
31872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return false;
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
32072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Find the header data within the control frame.
32172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  scoped_ptr<SpdyFrame> decompressed_frame(DecompressFrame(*frame));
32272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!decompressed_frame.get())
32372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return false;
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
32572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  const char *header_data = NULL;
32672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int header_length = 0;
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
32872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  switch (type) {
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case SYN_STREAM:
33072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      {
33172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        SpdySynStreamControlFrame syn_frame(decompressed_frame->data(), false);
33272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        header_data = syn_frame.header_block();
33372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        header_length = syn_frame.header_block_len();
33472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      }
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case SYN_REPLY:
33772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      {
33872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        SpdySynReplyControlFrame syn_frame(decompressed_frame->data(), false);
33972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        header_data = syn_frame.header_block();
34072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        header_length = syn_frame.header_block_len();
34172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      }
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
343201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    case HEADERS:
34472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      {
34572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        SpdyHeadersControlFrame header_frame(decompressed_frame->data(), false);
34672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        header_data = header_frame.header_block();
34772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        header_length = header_frame.header_block_len();
34872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      }
349201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      break;
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFrameBuilder builder(header_data, header_length);
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void* iter = NULL;
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  uint16 num_headers;
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (builder.ReadUInt16(&iter, &num_headers)) {
356201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    int index;
357201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    for (index = 0; index < num_headers; ++index) {
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::string name;
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::string value;
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!builder.ReadString(&iter, &name))
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!builder.ReadString(&iter, &value))
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!name.size() || !value.size())
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (block->find(name) == block->end()) {
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        (*block)[name] = value;
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return index == num_headers &&
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        iter == header_data + header_length;
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3782c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurunsize_t SpdyFramer::UpdateCurrentFrameBuffer(const char** data, size_t* len,
3792c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                                            size_t max_bytes) {
3802c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  size_t bytes_to_read = std::min(*len, max_bytes);
3812c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  DCHECK_GE(current_frame_capacity_, current_frame_len_ + bytes_to_read);
3822c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  memcpy(&current_frame_buffer_[current_frame_len_], *data, bytes_to_read);
3832c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  current_frame_len_ += bytes_to_read;
3842c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  *data += bytes_to_read;
3852c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  *len -= bytes_to_read;
3862c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return bytes_to_read;
3872c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
3882c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
3892c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurunsize_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
3902c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                                                        size_t len) {
3912c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  DCHECK_EQ(SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK, state_);
3922c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  DCHECK_GT(remaining_control_header_, 0u);
3932c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  size_t original_len = len;
3942c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
3952c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  if (remaining_control_header_) {
3962c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    size_t bytes_read = UpdateCurrentFrameBuffer(&data, &len,
3972c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                                                 remaining_control_header_);
3982c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    remaining_control_header_ -= bytes_read;
3992c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    if (remaining_control_header_ == 0) {
4002c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      SpdyControlFrame control_frame(current_frame_buffer_, false);
4012c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      DCHECK(control_frame.type() == SYN_STREAM ||
4022c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun             control_frame.type() == SYN_REPLY ||
4032c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun             control_frame.type() == HEADERS);
4042c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      visitor_->OnControl(&control_frame);
4052c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
4062c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK);
4072c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    }
4082c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
4092c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return original_len - len;
4102c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
4112c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
4122c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun// Does not buffer the control payload. Instead, either passes directly to the
4132c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun// visitor or decompresses and then passes directly to the visitor, via
4142c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun// IncrementallyDeliverControlFrameHeaderData() or
4152c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun// IncrementallyDecompressControlFrameHeaderData() respectively.
4162c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurunsize_t SpdyFramer::NewProcessControlFrameHeaderBlock(const char* data,
4172c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                                                     size_t data_len) {
4182c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  DCHECK_EQ(SPDY_CONTROL_FRAME_HEADER_BLOCK, state_);
4192c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  SpdyControlFrame control_frame(current_frame_buffer_, false);
4202c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  bool processed_successfully = true;
4212c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  DCHECK(control_frame.type() == SYN_STREAM ||
4222c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun         control_frame.type() == SYN_REPLY ||
4232c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun         control_frame.type() == HEADERS);
4242c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  size_t process_bytes = std::min(data_len, remaining_control_payload_);
4252c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  DCHECK_GT(process_bytes, 0u);
4262c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
4272c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  if (enable_compression_) {
4282c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    processed_successfully = IncrementallyDecompressControlFrameHeaderData(
4292c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        &control_frame, data, process_bytes);
4302c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  } else {
4312c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    processed_successfully = IncrementallyDeliverControlFrameHeaderData(
4322c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        &control_frame, data, process_bytes);
4332c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
4342c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  remaining_control_payload_ -= process_bytes;
4352c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
4362c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  // Handle the case that there is no futher data in this frame.
4372c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  if (remaining_control_payload_ == 0 && processed_successfully) {
4382c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    // The complete header block has been delivered. We send a zero-length
4392c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    // OnControlFrameHeaderData() to indicate this.
4402c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    visitor_->OnControlFrameHeaderData(
4412c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        GetControlFrameStreamId(&control_frame), NULL, 0);
4422c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
4432c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    // If this is a FIN, tell the caller.
4442c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    if (control_frame.flags() & CONTROL_FLAG_FIN) {
4452c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      visitor_->OnStreamFrameData(GetControlFrameStreamId(&control_frame),
4462c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                                  NULL, 0);
4472c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    }
4482c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
4492c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    CHANGE_STATE(SPDY_RESET);
4502c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
4512c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
4522c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  // Handle error.
4532c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  if (!processed_successfully) {
4542c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    return data_len;
4552c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
4562c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
4572c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  // Return amount processed.
4582c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return process_bytes;
4592c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
4602c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
4612c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurunsize_t SpdyFramer::ProcessControlFrameHeaderBlock(const char* data,
4622c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                                                  size_t data_len) {
4632c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  DCHECK_EQ(SPDY_CONTROL_FRAME_HEADER_BLOCK, state_);
4642c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  size_t original_data_len = data_len;
4652c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  SpdyControlFrame control_frame(current_frame_buffer_, false);
4662c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  bool read_successfully = true;
4672c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  DCHECK(control_frame.type() == SYN_STREAM ||
4682c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun         control_frame.type() == SYN_REPLY ||
4692c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun         control_frame.type() == HEADERS);
4702c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
4712c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  if (enable_compression_) {
4722c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    // Note that the header block is held in the frame's payload, and is not
4732c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    // part of the frame's headers.
4742c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    if (remaining_control_payload_ > 0) {
4752c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      size_t bytes_read = UpdateCurrentFrameBuffer(
4762c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun          &data,
4772c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun          &data_len,
4782c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun          remaining_control_payload_);
4792c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      remaining_control_payload_ -= bytes_read;
4802c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      if (remaining_control_payload_ == 0) {
4812c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        read_successfully = IncrementallyDecompressControlFrameHeaderData(
4822c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun            &control_frame);
4832c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      }
4842c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    }
4852c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  } else {
4862c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    size_t bytes_to_send = std::min(data_len, remaining_control_payload_);
4872c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    DCHECK_GT(bytes_to_send, 0u);
4882c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    read_successfully = IncrementallyDeliverControlFrameHeaderData(
4892c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        &control_frame, data, bytes_to_send);
4902c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    data_len -= bytes_to_send;
4912c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    remaining_control_payload_ -= bytes_to_send;
4922c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
4932c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  if (remaining_control_payload_ == 0 && read_successfully) {
4942c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    // The complete header block has been delivered.
4952c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    visitor_->OnControlFrameHeaderData(GetControlFrameStreamId(&control_frame),
4962c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                                       NULL, 0);
4972c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
4982c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    // If this is a FIN, tell the caller.
4992c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    if (control_frame.flags() & CONTROL_FLAG_FIN) {
5002c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      visitor_->OnStreamFrameData(GetControlFrameStreamId(&control_frame),
5012c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                                  NULL, 0);
5022c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    }
5032c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
5042c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    CHANGE_STATE(SPDY_RESET);
5052c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
5062c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  if (!read_successfully) {
5072c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    return original_data_len;
5082c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
5092c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return original_data_len - data_len;
5102c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
5112c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
5122c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun/* static */
5132c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurunbool SpdyFramer::ParseHeaderBlockInBuffer(const char* header_data,
5142c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                                          size_t header_length,
5152c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                                          SpdyHeaderBlock* block) {
5162c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  SpdyFrameBuilder builder(header_data, header_length);
5172c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  void* iter = NULL;
5182c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  uint16 num_headers;
5192c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  if (builder.ReadUInt16(&iter, &num_headers)) {
5202c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    for (int index = 0; index < num_headers; ++index) {
5212c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      std::string name;
5222c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      std::string value;
5232c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      if (!builder.ReadString(&iter, &name))
5242c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        return false;
5252c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      if (!builder.ReadString(&iter, &value))
5262c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        return false;
5272c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      if (block->find(name) == block->end()) {
5282c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        (*block)[name] = value;
5292c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      } else {
5302c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        return false;
5312c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      }
5322c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    }
5332c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    return true;
5342c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
5352c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return false;
5362c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
5372c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSpdySynStreamControlFrame* SpdyFramer::CreateSynStream(
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SpdyStreamId stream_id, SpdyStreamId associated_stream_id, int priority,
5402c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    SpdyControlFlags flags, bool compressed, const SpdyHeaderBlock* headers) {
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFrameBuilder frame;
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_GT(stream_id, static_cast<SpdyStreamId>(0));
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(0u, associated_stream_id & ~kStreamIdMask);
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  frame.WriteUInt16(kControlFlagMask | spdy_version_);
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt16(SYN_STREAM);
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32(0);  // Placeholder for the length and flags
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32(stream_id);
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32(associated_stream_id);
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt16(ntohs(priority) << 6);  // Priority.
553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt16(headers->size());  // Number of headers.
5552c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  SpdyHeaderBlock::const_iterator it;
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (it = headers->begin(); it != headers->end(); ++it) {
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool wrote_header;
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    wrote_header = frame.WriteString(it->first);
559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    wrote_header &= frame.WriteString(it->second);
560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(wrote_header);
561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Write the length and flags.
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t length = frame.length() - SpdyFrame::size();
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask));
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FlagsAndLength flags_length;
567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  flags_length.length_ = htonl(static_cast<uint32>(length));
568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(0, flags & ~kControlFlagsMask);
569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  flags_length.flags_[0] = flags;
570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteBytesToOffset(4, &flags_length, sizeof(flags_length));
571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5722c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  scoped_ptr<SpdySynStreamControlFrame> syn_frame(
5732c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      reinterpret_cast<SpdySynStreamControlFrame*>(frame.take()));
574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (compressed) {
575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return reinterpret_cast<SpdySynStreamControlFrame*>(
5762c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        CompressControlFrame(*syn_frame.get()));
577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
5782c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return syn_frame.release();
579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
581201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben MurdochSpdySynReplyControlFrame* SpdyFramer::CreateSynReply(SpdyStreamId stream_id,
5822c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    SpdyControlFlags flags, bool compressed, const SpdyHeaderBlock* headers) {
583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_GT(stream_id, 0u);
584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFrameBuilder frame;
587201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
5883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  frame.WriteUInt16(kControlFlagMask | spdy_version_);
589201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt16(SYN_REPLY);
590201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt32(0);  // Placeholder for the length and flags.
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32(stream_id);
592201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt16(0);  // Unused
593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
594201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt16(headers->size());  // Number of headers.
5952c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  SpdyHeaderBlock::const_iterator it;
596201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  for (it = headers->begin(); it != headers->end(); ++it) {
597201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    bool wrote_header;
598201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    wrote_header = frame.WriteString(it->first);
599201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    wrote_header &= frame.WriteString(it->second);
600201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    DCHECK(wrote_header);
601201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
603201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Write the length and flags.
604201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  size_t length = frame.length() - SpdyFrame::size();
605201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask));
606201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  FlagsAndLength flags_length;
607201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  flags_length.length_ = htonl(static_cast<uint32>(length));
608201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK_EQ(0, flags & ~kControlFlagsMask);
609201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  flags_length.flags_[0] = flags;
610201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteBytesToOffset(4, &flags_length, sizeof(flags_length));
611201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
6122c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  scoped_ptr<SpdySynReplyControlFrame> reply_frame(
6132c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      reinterpret_cast<SpdySynReplyControlFrame*>(frame.take()));
614201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (compressed) {
615201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return reinterpret_cast<SpdySynReplyControlFrame*>(
6162c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        CompressControlFrame(*reply_frame.get()));
617201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
6182c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return reply_frame.release();
619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/* static */
622201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben MurdochSpdyRstStreamControlFrame* SpdyFramer::CreateRstStream(SpdyStreamId stream_id,
623201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                                                       SpdyStatusCodes status) {
624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_GT(stream_id, 0u);
625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
626201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK_NE(status, INVALID);
627201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK_LT(status, NUM_STATUS_CODES);
628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFrameBuilder frame;
6303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  frame.WriteUInt16(kControlFlagMask | spdy_version_);
631201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt16(RST_STREAM);
632201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt32(8);
633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32(stream_id);
634201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt32(status);
635201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return reinterpret_cast<SpdyRstStreamControlFrame*>(frame.take());
636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/* static */
639c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSpdySettingsControlFrame* SpdyFramer::CreateSettings(
640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SpdySettings& values) {
641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFrameBuilder frame;
6423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  frame.WriteUInt16(kControlFlagMask | spdy_version_);
643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt16(SETTINGS);
644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t settings_size = SpdySettingsControlFrame::size() - SpdyFrame::size() +
645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      8 * values.size();
646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32(settings_size);
647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32(values.size());
648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdySettings::const_iterator it = values.begin();
649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (it != values.end()) {
650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    frame.WriteUInt32(it->first.id_);
651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    frame.WriteUInt32(it->second);
652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ++it;
653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return reinterpret_cast<SpdySettingsControlFrame*>(frame.take());
655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
657201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch/* static */
6582c4085b2006233b5e3a3fe507d62642377b5dc2eSelim GurunSpdyNoOpControlFrame* SpdyFramer::CreateNopFrame() {
659201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SpdyFrameBuilder frame;
660201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt16(kControlFlagMask | spdy_version_);
661201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt16(NOOP);
662201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt32(0);
6632c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return reinterpret_cast<SpdyNoOpControlFrame*>(frame.take());
6642c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
6652c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
6662c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun/* static */
6672c4085b2006233b5e3a3fe507d62642377b5dc2eSelim GurunSpdyPingControlFrame* SpdyFramer::CreatePingFrame(uint32 unique_id) {
6682c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  SpdyFrameBuilder frame;
6692c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  frame.WriteUInt16(kControlFlagMask | kSpdyProtocolVersion);
6702c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  frame.WriteUInt16(PING);
6712c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  size_t ping_size = SpdyPingControlFrame::size() - SpdyFrame::size();
6722c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  frame.WriteUInt32(ping_size);
6732c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  frame.WriteUInt32(unique_id);
6742c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return reinterpret_cast<SpdyPingControlFrame*>(frame.take());
675201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
676201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
677201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch/* static */
678201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben MurdochSpdyGoAwayControlFrame* SpdyFramer::CreateGoAway(
679201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    SpdyStreamId last_accepted_stream_id) {
680201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK_EQ(0u, last_accepted_stream_id & ~kStreamIdMask);
681201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
682201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SpdyFrameBuilder frame;
683201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt16(kControlFlagMask | spdy_version_);
684201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt16(GOAWAY);
685201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  size_t go_away_size = SpdyGoAwayControlFrame::size() - SpdyFrame::size();
686201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt32(go_away_size);
687201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt32(last_accepted_stream_id);
688201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return reinterpret_cast<SpdyGoAwayControlFrame*>(frame.take());
689201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
690201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
691201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben MurdochSpdyHeadersControlFrame* SpdyFramer::CreateHeaders(SpdyStreamId stream_id,
6922c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    SpdyControlFlags flags, bool compressed, const SpdyHeaderBlock* headers) {
693201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Basically the same as CreateSynReply().
694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_GT(stream_id, 0u);
695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFrameBuilder frame;
698201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt16(kControlFlagMask | kSpdyProtocolVersion);
699201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt16(HEADERS);
700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32(0);  // Placeholder for the length and flags.
701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32(stream_id);
702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt16(0);  // Unused
703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt16(headers->size());  // Number of headers.
7052c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  SpdyHeaderBlock::const_iterator it;
706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (it = headers->begin(); it != headers->end(); ++it) {
707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool wrote_header;
708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    wrote_header = frame.WriteString(it->first);
709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    wrote_header &= frame.WriteString(it->second);
710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(wrote_header);
711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Write the length and flags.
714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t length = frame.length() - SpdyFrame::size();
715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask));
716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FlagsAndLength flags_length;
717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  flags_length.length_ = htonl(static_cast<uint32>(length));
718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(0, flags & ~kControlFlagsMask);
719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  flags_length.flags_[0] = flags;
720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteBytesToOffset(4, &flags_length, sizeof(flags_length));
721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7222c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  scoped_ptr<SpdyHeadersControlFrame> headers_frame(
7232c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      reinterpret_cast<SpdyHeadersControlFrame*>(frame.take()));
724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (compressed) {
725201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return reinterpret_cast<SpdyHeadersControlFrame*>(
7262c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        CompressControlFrame(*headers_frame.get()));
727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
7282c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return headers_frame.release();
729201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
730201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
731201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch/* static */
732201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben MurdochSpdyWindowUpdateControlFrame* SpdyFramer::CreateWindowUpdate(
733201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    SpdyStreamId stream_id,
734201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    uint32 delta_window_size) {
735201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK_GT(stream_id, 0u);
736201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
737201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK_GT(delta_window_size, 0u);
738201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK_LE(delta_window_size, spdy::kSpdyStreamMaximumWindowSize);
739201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
740201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SpdyFrameBuilder frame;
741201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt16(kControlFlagMask | spdy_version_);
742201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt16(WINDOW_UPDATE);
743201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  size_t window_update_size = SpdyWindowUpdateControlFrame::size() -
744201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      SpdyFrame::size();
745201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt32(window_update_size);
746201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt32(stream_id);
747201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  frame.WriteUInt32(delta_window_size);
748201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return reinterpret_cast<SpdyWindowUpdateControlFrame*>(frame.take());
749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
75172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen/* static */
75272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool SpdyFramer::ParseSettings(const SpdySettingsControlFrame* frame,
75372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                               SpdySettings* settings) {
75472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK_EQ(frame->type(), SETTINGS);
75572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(settings);
75672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
75772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  SpdyFrameBuilder parser(frame->header_block(), frame->header_block_len());
75872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  void* iter = NULL;
75972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  for (size_t index = 0; index < frame->num_entries(); ++index) {
76072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    uint32 id;
76172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    uint32 value;
76272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!parser.ReadUInt32(&iter, &id))
76372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return false;
76472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!parser.ReadUInt32(&iter, &value))
76572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return false;
76672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    settings->insert(settings->end(), std::make_pair(id, value));
76772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
76872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return true;
76972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
77072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
771c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSpdyDataFrame* SpdyFramer::CreateDataFrame(SpdyStreamId stream_id,
772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           const char* data,
773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           uint32 len, SpdyDataFlags flags) {
774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFrameBuilder frame;
775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_GT(stream_id, 0u);
777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32(stream_id);
779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(0u, len & ~static_cast<size_t>(kLengthMask));
781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FlagsAndLength flags_length;
782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  flags_length.length_ = htonl(len);
783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(0, flags & ~kDataFlagsMask);
784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  flags_length.flags_[0] = flags;
785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteBytes(&flags_length, sizeof(flags_length));
786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
78772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  frame.WriteBytes(data, len);
78872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  scoped_ptr<SpdyFrame> data_frame(frame.take());
78972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  SpdyDataFrame* rv;
79072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (flags & DATA_FLAG_COMPRESSED) {
79172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    rv = reinterpret_cast<SpdyDataFrame*>(CompressFrame(*data_frame.get()));
79272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else {
79372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    rv = reinterpret_cast<SpdyDataFrame*>(data_frame.release());
79472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
79572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
79672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (flags & DATA_FLAG_FIN) {
79772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    CleanupCompressorForStream(stream_id);
79872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
79972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
80072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return rv;
80172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
80272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
80372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenSpdyFrame* SpdyFramer::CompressFrame(const SpdyFrame& frame) {
80472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (frame.is_control_frame()) {
80572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return CompressControlFrame(
80672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        reinterpret_cast<const SpdyControlFrame&>(frame));
80772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
80872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return CompressDataFrame(reinterpret_cast<const SpdyDataFrame&>(frame));
80972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
81072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
81172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenSpdyFrame* SpdyFramer::DecompressFrame(const SpdyFrame& frame) {
81272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (frame.is_control_frame()) {
81372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return DecompressControlFrame(
81472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        reinterpret_cast<const SpdyControlFrame&>(frame));
81572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
81672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return DecompressDataFrame(reinterpret_cast<const SpdyDataFrame&>(frame));
81772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
81872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
81972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenSpdyFrame* SpdyFramer::DuplicateFrame(const SpdyFrame& frame) {
82072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int size = SpdyFrame::size() + frame.length();
82172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  SpdyFrame* new_frame = new SpdyFrame(size);
82272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  memcpy(new_frame->data(), frame.data(), size);
82372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return new_frame;
82472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
82572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
82672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool SpdyFramer::IsCompressible(const SpdyFrame& frame) const {
82772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // The important frames to compress are those which contain large
82872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // amounts of compressible data - namely the headers in the SYN_STREAM
82972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // and SYN_REPLY.
83072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // TODO(mbelshe): Reconcile this with the spec when the spec is
83172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // explicit about which frames compress and which do not.
83272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (frame.is_control_frame()) {
83372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const SpdyControlFrame& control_frame =
83472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        reinterpret_cast<const SpdyControlFrame&>(frame);
83572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return control_frame.type() == SYN_STREAM ||
83672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen           control_frame.type() == SYN_REPLY;
83772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
83872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
83972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  const SpdyDataFrame& data_frame =
84072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      reinterpret_cast<const SpdyDataFrame&>(frame);
84172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return (data_frame.flags() & DATA_FLAG_COMPRESSED) != 0;
84272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
84372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
84472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst char* SpdyFramer::StateToString(int state) {
84572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  switch (state) {
84672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_ERROR:
84772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return "ERROR";
84872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_DONE:
84972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return "DONE";
85072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_AUTO_RESET:
85172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return "AUTO_RESET";
85272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_RESET:
85372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return "RESET";
85472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_READING_COMMON_HEADER:
85572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return "READING_COMMON_HEADER";
85672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER:
85772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return "INTERPRET_CONTROL_FRAME_COMMON_HEADER";
85872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_CONTROL_FRAME_PAYLOAD:
85972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return "CONTROL_FRAME_PAYLOAD";
86072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_IGNORE_REMAINING_PAYLOAD:
86172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return "IGNORE_REMAINING_PAYLOAD";
86272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_FORWARD_STREAM_FRAME:
86372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return "FORWARD_STREAM_FRAME";
8642c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK:
8652c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return "SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK";
8662c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case SPDY_CONTROL_FRAME_HEADER_BLOCK:
8672c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return "SPDY_CONTROL_FRAME_HEADER_BLOCK";
86872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
86972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return "UNKNOWN_STATE";
87072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
87172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
87272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst char* SpdyFramer::ErrorCodeToString(int error_code) {
87372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  switch (error_code) {
87472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_NO_ERROR:
87572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return "NO_ERROR";
87672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_INVALID_CONTROL_FRAME:
87772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return "INVALID_CONTROL_FRAME";
87872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_CONTROL_PAYLOAD_TOO_LARGE:
87972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return "CONTROL_PAYLOAD_TOO_LARGE";
88072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_ZLIB_INIT_FAILURE:
88172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return "ZLIB_INIT_FAILURE";
88272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_UNSUPPORTED_VERSION:
88372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return "UNSUPPORTED_VERSION";
88472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_DECOMPRESS_FAILURE:
88572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return "DECOMPRESS_FAILURE";
88672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_COMPRESS_FAILURE:
88772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return "COMPRESS_FAILURE";
88872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
88972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return "UNKNOWN_ERROR";
89072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
89172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
89272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid SpdyFramer::set_enable_compression(bool value) {
89372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  enable_compression_ = value;
89472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
89572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
89672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid SpdyFramer::set_enable_compression_default(bool value) {
89772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  compression_default_ = value;
89872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
89972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
90072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsensize_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) {
90172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // This should only be called when we're in the SPDY_READING_COMMON_HEADER
90272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // state.
90372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK_EQ(state_, SPDY_READING_COMMON_HEADER);
90472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
90572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  size_t original_len = len;
90672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  SpdyFrame current_frame(current_frame_buffer_, false);
90772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
90872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  do {
90972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (current_frame_len_ < SpdyFrame::size()) {
91072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      size_t bytes_desired = SpdyFrame::size() - current_frame_len_;
9112c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      UpdateCurrentFrameBuffer(&data, &len, bytes_desired);
91272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      // Check for an empty data frame.
91372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (current_frame_len_ == SpdyFrame::size() &&
91472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          !current_frame.is_control_frame() &&
91572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          current_frame.length() == 0) {
91672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        if (current_frame.flags() & CONTROL_FLAG_FIN) {
91772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          SpdyDataFrame data_frame(current_frame_buffer_, false);
91872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          visitor_->OnStreamFrameData(data_frame.stream_id(), NULL, 0);
91972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        }
92072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        CHANGE_STATE(SPDY_AUTO_RESET);
92172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      }
92272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      break;
92372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
9242c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    remaining_data_ = current_frame.length();
92572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
92672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // This is just a sanity check for help debugging early frame errors.
9272c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    if (remaining_data_ > 1000000u) {
92872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      LOG(WARNING) <<
92972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          "Unexpectedly large frame.  Spdy session is likely corrupt.";
93072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
93172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
93272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // if we're here, then we have the common header all received.
93372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!current_frame.is_control_frame())
93472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME);
93572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    else
93672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      CHANGE_STATE(SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER);
93772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } while (false);
93872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
93972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return original_len - len;
94072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
94172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
94272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid SpdyFramer::ProcessControlFrameHeader() {
94372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK_EQ(SPDY_NO_ERROR, error_code_);
94472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK_LE(SpdyFrame::size(), current_frame_len_);
94572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  SpdyControlFrame current_control_frame(current_frame_buffer_, false);
94672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
94772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // We check version before we check validity: version can never be 'invalid',
94872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // it can only be unsupported.
94972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (current_control_frame.version() != spdy_version_) {
95072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    set_error(SPDY_UNSUPPORTED_VERSION);
95172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return;
95272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
95372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
95472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Next up, check to see if we have valid data.  This should be after version
95572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // checking (otherwise if the the type were out of bounds due to a version
95672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // upgrade we would misclassify the error) and before checking the type
95772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // (type can definitely be out of bounds)
95872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!current_control_frame.AppearsToBeAValidControlFrame()) {
95972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    set_error(SPDY_INVALID_CONTROL_FRAME);
96072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return;
96172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
96272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
96372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Do some sanity checking on the control frame sizes.
96472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  switch (current_control_frame.type()) {
96572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SYN_STREAM:
96672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (current_control_frame.length() <
96772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          SpdySynStreamControlFrame::size() - SpdyControlFrame::size())
96872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        set_error(SPDY_INVALID_CONTROL_FRAME);
96972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      break;
97072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SYN_REPLY:
97172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (current_control_frame.length() <
97272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          SpdySynReplyControlFrame::size() - SpdyControlFrame::size())
97372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        set_error(SPDY_INVALID_CONTROL_FRAME);
97472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      break;
97572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case RST_STREAM:
97672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (current_control_frame.length() !=
97772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          SpdyRstStreamControlFrame::size() - SpdyFrame::size())
97872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        set_error(SPDY_INVALID_CONTROL_FRAME);
97972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      break;
98072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SETTINGS:
98172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (current_control_frame.length() <
98272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          SpdySettingsControlFrame::size() - SpdyControlFrame::size())
98372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        set_error(SPDY_INVALID_CONTROL_FRAME);
98472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      break;
9852c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    // TODO(hkhalil): Remove NOOP.
98672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case NOOP:
98772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      // NOOP.  Swallow it.
9882c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      DLOG(INFO) << "Attempted frame size validation for NOOP. Resetting.";
98972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      CHANGE_STATE(SPDY_AUTO_RESET);
99072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return;
99172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case GOAWAY:
99272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (current_control_frame.length() !=
99372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          SpdyGoAwayControlFrame::size() - SpdyFrame::size())
99472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        set_error(SPDY_INVALID_CONTROL_FRAME);
99572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      break;
99672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case HEADERS:
99772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (current_control_frame.length() <
99872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          SpdyHeadersControlFrame::size() - SpdyControlFrame::size())
99972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        set_error(SPDY_INVALID_CONTROL_FRAME);
100072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      break;
100172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case WINDOW_UPDATE:
100272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (current_control_frame.length() !=
100372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          SpdyWindowUpdateControlFrame::size() - SpdyControlFrame::size())
100472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        set_error(SPDY_INVALID_CONTROL_FRAME);
100572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      break;
10062c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case PING:
10072c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      if (current_control_frame.length() !=
10082c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun          SpdyPingControlFrame::size() - SpdyControlFrame::size())
10092c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        set_error(SPDY_INVALID_CONTROL_FRAME);
10102c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      break;
101172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    default:
10122c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      LOG(WARNING) << "Valid spdy control frame with unhandled type: "
101372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                   << current_control_frame.type();
101472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      DCHECK(false);
101572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      set_error(SPDY_INVALID_CONTROL_FRAME);
101672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      break;
101772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
101872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
101972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  remaining_control_payload_ = current_control_frame.length();
102072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (remaining_control_payload_ > kControlFrameBufferMaxSize) {
102172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
102272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return;
102372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
102472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
102572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ExpandControlFrameBuffer(remaining_control_payload_);
102672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  CHANGE_STATE(SPDY_CONTROL_FRAME_PAYLOAD);
102772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
102872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
102972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsensize_t SpdyFramer::ProcessControlFramePayload(const char* data, size_t len) {
103072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  size_t original_len = len;
103172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  do {
103272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (remaining_control_payload_) {
10332c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      size_t bytes_read = UpdateCurrentFrameBuffer(&data, &len,
10342c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                                                   remaining_control_payload_);
10352c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      remaining_control_payload_ -= bytes_read;
10362c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      remaining_data_ -= bytes_read;
103772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (remaining_control_payload_)
103872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        break;
103972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
104072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    SpdyControlFrame control_frame(current_frame_buffer_, false);
104172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    visitor_->OnControl(&control_frame);
104272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
104372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // If this is a FIN, tell the caller.
104472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (control_frame.type() == SYN_REPLY &&
104572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        control_frame.flags() & CONTROL_FLAG_FIN) {
104672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      visitor_->OnStreamFrameData(reinterpret_cast<SpdySynReplyControlFrame*>(
104772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                      &control_frame)->stream_id(),
104872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                  NULL, 0);
104972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
105072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
105172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    CHANGE_STATE(SPDY_IGNORE_REMAINING_PAYLOAD);
105272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } while (false);
105372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return original_len - len;
105472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
105572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
105672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsensize_t SpdyFramer::ProcessDataFramePayload(const char* data, size_t len) {
105772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  size_t original_len = len;
105872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
105972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  SpdyDataFrame current_data_frame(current_frame_buffer_, false);
10602c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  if (remaining_data_) {
10612c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    size_t amount_to_forward = std::min(remaining_data_, len);
106272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (amount_to_forward && state_ != SPDY_IGNORE_REMAINING_PAYLOAD) {
106372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (current_data_frame.flags() & DATA_FLAG_COMPRESSED) {
106472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        z_stream* decompressor =
106572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            GetStreamDecompressor(current_data_frame.stream_id());
106672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        if (!decompressor)
106772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          return 0;
106872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
106972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        size_t decompressed_max_size = amount_to_forward * 100;
107072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        scoped_array<char> decompressed(new char[decompressed_max_size]);
107172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        decompressor->next_in = reinterpret_cast<Bytef*>(
107272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            const_cast<char*>(data));
107372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        decompressor->avail_in = amount_to_forward;
107472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        decompressor->next_out =
107572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            reinterpret_cast<Bytef*>(decompressed.get());
107672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        decompressor->avail_out = decompressed_max_size;
107772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
107872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        int rv = inflate(decompressor, Z_SYNC_FLUSH);
107972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        if (rv != Z_OK) {
108072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          LOG(WARNING) << "inflate failure: " << rv;
108172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          set_error(SPDY_DECOMPRESS_FAILURE);
108272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          return 0;
108372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        }
108472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        size_t decompressed_size = decompressed_max_size -
108572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                   decompressor->avail_out;
108672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
108772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        // Only inform the visitor if there is data.
108872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        if (decompressed_size)
108972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          visitor_->OnStreamFrameData(current_data_frame.stream_id(),
109072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                      decompressed.get(),
109172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                      decompressed_size);
109272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        amount_to_forward -= decompressor->avail_in;
109372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      } else {
109472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        // The data frame was not compressed.
109572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        // Only inform the visitor if there is data.
109672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        if (amount_to_forward)
109772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          visitor_->OnStreamFrameData(current_data_frame.stream_id(),
109872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                      data, amount_to_forward);
109972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      }
110072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
110172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    data += amount_to_forward;
110272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    len -= amount_to_forward;
11032c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    remaining_data_ -= amount_to_forward;
1104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
110572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // If the FIN flag is set, and there is no more data in this data
110672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // frame, inform the visitor of EOF via a 0-length data frame.
11072c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    if (!remaining_data_ &&
110872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        current_data_frame.flags() & DATA_FLAG_FIN) {
110972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      visitor_->OnStreamFrameData(current_data_frame.stream_id(), NULL, 0);
111072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      CleanupDecompressorForStream(current_data_frame.stream_id());
111172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
111272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else {
111372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    CHANGE_STATE(SPDY_AUTO_RESET);
1114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
111572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return original_len - len;
1116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochz_stream* SpdyFramer::GetHeaderCompressor() {
1119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (header_compressor_.get())
1120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return header_compressor_.get();  // Already initialized.
1121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  header_compressor_.reset(new z_stream);
1123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memset(header_compressor_.get(), 0, sizeof(z_stream));
1124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int success = deflateInit2(header_compressor_.get(),
1126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             kCompressorLevel,
1127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             Z_DEFLATED,
1128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             kCompressorWindowSizeInBits,
1129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             kCompressorMemLevel,
1130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             Z_DEFAULT_STRATEGY);
1131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (success == Z_OK)
1132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    success = deflateSetDictionary(header_compressor_.get(),
1133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   reinterpret_cast<const Bytef*>(kDictionary),
1134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   kDictionarySize);
1135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (success != Z_OK) {
1136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "deflateSetDictionary failure: " << success;
1137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    header_compressor_.reset(NULL);
1138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
1139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return header_compressor_.get();
1141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochz_stream* SpdyFramer::GetHeaderDecompressor() {
1144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (header_decompressor_.get())
1145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return header_decompressor_.get();  // Already initialized.
1146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  header_decompressor_.reset(new z_stream);
1148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memset(header_decompressor_.get(), 0, sizeof(z_stream));
1149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Compute the id of our dictionary so that we know we're using the
1151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // right one when asked for it.
1152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (dictionary_id == 0) {
1153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dictionary_id = adler32(0L, Z_NULL, 0);
1154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dictionary_id = adler32(dictionary_id,
1155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            reinterpret_cast<const Bytef*>(kDictionary),
1156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            kDictionarySize);
1157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int success = inflateInit(header_decompressor_.get());
1160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (success != Z_OK) {
1161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "inflateInit failure: " << success;
1162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    header_decompressor_.reset(NULL);
1163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
1164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return header_decompressor_.get();
1166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochz_stream* SpdyFramer::GetStreamCompressor(SpdyStreamId stream_id) {
1169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CompressorMap::iterator it = stream_compressors_.find(stream_id);
1170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (it != stream_compressors_.end())
1171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return it->second;  // Already initialized.
1172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<z_stream> compressor(new z_stream);
1174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memset(compressor.get(), 0, sizeof(z_stream));
1175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int success = deflateInit2(compressor.get(),
1177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             kCompressorLevel,
1178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             Z_DEFLATED,
1179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             kCompressorWindowSizeInBits,
1180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             kCompressorMemLevel,
1181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             Z_DEFAULT_STRATEGY);
1182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (success != Z_OK) {
1183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "deflateInit failure: " << success;
1184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
1185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return stream_compressors_[stream_id] = compressor.release();
1187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochz_stream* SpdyFramer::GetStreamDecompressor(SpdyStreamId stream_id) {
1190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CompressorMap::iterator it = stream_decompressors_.find(stream_id);
1191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (it != stream_decompressors_.end())
1192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return it->second;  // Already initialized.
1193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<z_stream> decompressor(new z_stream);
1195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memset(decompressor.get(), 0, sizeof(z_stream));
1196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int success = inflateInit(decompressor.get());
1198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (success != Z_OK) {
1199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "inflateInit failure: " << success;
1200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
1201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return stream_decompressors_[stream_id] = decompressor.release();
1203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1205c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSpdyControlFrame* SpdyFramer::CompressControlFrame(
1206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SpdyControlFrame& frame) {
1207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  z_stream* compressor = GetHeaderCompressor();
1208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!compressor)
1209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
1210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return reinterpret_cast<SpdyControlFrame*>(
1211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CompressFrameWithZStream(frame, compressor));
1212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
121472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenSpdyDataFrame* SpdyFramer::CompressDataFrame(const SpdyDataFrame& frame) {
121572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  z_stream* compressor = GetStreamCompressor(frame.stream_id());
121672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!compressor)
121772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return NULL;
121872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return reinterpret_cast<SpdyDataFrame*>(
121972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      CompressFrameWithZStream(frame, compressor));
122072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
122172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
1222c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSpdyControlFrame* SpdyFramer::DecompressControlFrame(
1223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SpdyControlFrame& frame) {
1224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  z_stream* decompressor = GetHeaderDecompressor();
1225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!decompressor)
1226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
1227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return reinterpret_cast<SpdyControlFrame*>(
1228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DecompressFrameWithZStream(frame, decompressor));
1229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
12312c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun// Incrementally decompress the control frame's header block, feeding the
12322c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun// result to the visitor in chunks. Continue this until the visitor
12332c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun// indicates that it cannot process any more data, or (more commonly) we
12342c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun// run out of data to deliver.
12352c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurunbool SpdyFramer::IncrementallyDecompressControlFrameHeaderData(
12362c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    const SpdyControlFrame* control_frame) {
12372c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  z_stream* decomp = GetHeaderDecompressor();
12382c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  int payload_length;
12392c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  int header_length;
12402c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  const char* payload;
12412c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  bool read_successfully = true;
12422c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  bool more = true;
12432c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  char buffer[kHeaderDataChunkMaxSize];
12442c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
12452c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  if (!GetFrameBoundaries(
12462c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      *control_frame, &payload_length, &header_length, &payload)) {
12472c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    DLOG(ERROR) << "Control frame of type "
12482c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                << SpdyFramer::ControlTypeToString(control_frame->type())
12492c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                <<" doesn't have headers";
12502c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    return false;
12512c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
12522c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  decomp->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(payload));
12532c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  decomp->avail_in = payload_length;
12542c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  const SpdyStreamId stream_id = GetControlFrameStreamId(control_frame);
12552c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  DCHECK_LT(0u, stream_id);
12562c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  while (more && read_successfully) {
12572c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    decomp->next_out = reinterpret_cast<Bytef*>(buffer);
12582c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    decomp->avail_out = arraysize(buffer);
12592c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    int rv = DecompressHeaderBlockInZStream(decomp);
12602c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    if (rv != Z_OK) {
12612c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      set_error(SPDY_DECOMPRESS_FAILURE);
12622c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      DLOG(WARNING) << "inflate failure: " << rv;
12632c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      more = read_successfully = false;
12642c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    } else {
12652c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      DCHECK_GT(arraysize(buffer), decomp->avail_out);
12662c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      size_t len = arraysize(buffer) - decomp->avail_out;
12672c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      read_successfully = visitor_->OnControlFrameHeaderData(stream_id, buffer,
12682c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                                                             len);
12692c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      if (!read_successfully) {
12702c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        // Assume that the problem was the header block was too large for the
12712c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        // visitor.
12722c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
12732c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      }
12742c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      more = decomp->avail_in > 0;
12752c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    }
12762c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
12772c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return read_successfully;
12782c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
12792c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
12802c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun// Incrementally decompress the control frame's header block, feeding the
12812c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun// result to the visitor in chunks. Continue this until the visitor
12822c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun// indicates that it cannot process any more data, or (more commonly) we
12832c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun// run out of data to deliver.
12842c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurunbool SpdyFramer::IncrementallyDecompressControlFrameHeaderData(
12852c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    const SpdyControlFrame* control_frame,
12862c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    const char* data,
12872c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    size_t len) {
12882c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  // Get a decompressor or set error.
12892c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  z_stream* decomp = GetHeaderDecompressor();
12902c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  if (decomp == NULL) {
12912c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    LOG(DFATAL) << "Couldn't get decompressor for handling compressed headers.";
12922c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    set_error(SPDY_DECOMPRESS_FAILURE);
12932c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    return false;
12942c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
12952c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
12962c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  bool processed_successfully = true;
12972c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  char buffer[kHeaderDataChunkMaxSize];
12982c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
12992c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  decomp->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data));
13002c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  decomp->avail_in = len;
13012c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  const SpdyStreamId stream_id = GetControlFrameStreamId(control_frame);
13022c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  DCHECK_LT(0u, stream_id);
13032c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  while (decomp->avail_in > 0 && processed_successfully) {
13042c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    decomp->next_out = reinterpret_cast<Bytef*>(buffer);
13052c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    decomp->avail_out = arraysize(buffer);
13062c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    int rv = DecompressHeaderBlockInZStream(decomp);
13072c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    if (rv != Z_OK) {
13082c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      set_error(SPDY_DECOMPRESS_FAILURE);
13092c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      DLOG(WARNING) << "inflate failure: " << rv;
13102c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      processed_successfully = false;
13112c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    } else {
13122c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      size_t decompressed_len = arraysize(buffer) - decomp->avail_out;
13132c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      if (decompressed_len > 0) {
13142c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        processed_successfully = visitor_->OnControlFrameHeaderData(
13152c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun            stream_id, buffer, decompressed_len);
13162c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      }
13172c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      if (!processed_successfully) {
13182c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        // Assume that the problem was the header block was too large for the
13192c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        // visitor.
13202c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
13212c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      }
13222c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    }
13232c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
13242c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return processed_successfully;
13252c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
13262c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
13272c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurunbool SpdyFramer::IncrementallyDeliverControlFrameHeaderData(
13282c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    const SpdyControlFrame* control_frame, const char* data, size_t len) {
13292c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  bool read_successfully = true;
13302c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  const SpdyStreamId stream_id = GetControlFrameStreamId(control_frame);
13312c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  DCHECK_LT(0u, stream_id);
13322c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  while (read_successfully && len > 0) {
13332c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    size_t bytes_to_deliver = std::min(len, kHeaderDataChunkMaxSize);
13342c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    read_successfully = visitor_->OnControlFrameHeaderData(stream_id, data,
13352c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                                                           bytes_to_deliver);
13362c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    data += bytes_to_deliver;
13372c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    len -= bytes_to_deliver;
13382c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    if (!read_successfully) {
13392c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      // Assume that the problem was the header block was too large for the
13402c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      // visitor.
13412c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
13422c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    }
13432c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
13442c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return read_successfully;
13452c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
13462c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
13472c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurunsize_t SpdyFramer::GetMinimumControlFrameSize(SpdyControlType type) {
13482c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  switch (type) {
13492c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case SYN_STREAM:
13502c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return SpdySynStreamControlFrame::size();
13512c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case SYN_REPLY:
13522c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return SpdySynReplyControlFrame::size();
13532c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case RST_STREAM:
13542c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return SpdyRstStreamControlFrame::size();
13552c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case SETTINGS:
13562c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return SpdySettingsControlFrame::size();
13572c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case NOOP:
13582c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return SpdyNoOpControlFrame::size();
13592c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case PING:
13602c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return SpdyPingControlFrame::size();
13612c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case GOAWAY:
13622c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return SpdyGoAwayControlFrame::size();
13632c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case HEADERS:
13642c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return SpdyHeadersControlFrame::size();
13652c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case WINDOW_UPDATE:
13662c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return SpdyWindowUpdateControlFrame::size();
13672c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case NUM_CONTROL_FRAME_TYPES:
13682c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      break;
13692c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
13702c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  LOG(ERROR) << "Unknown SPDY control frame type " << type;
13712c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return 0x7FFFFFFF;  // Max signed 32bit int
13722c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
13732c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
13742c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun/* static */
13752c4085b2006233b5e3a3fe507d62642377b5dc2eSelim GurunSpdyStreamId SpdyFramer::GetControlFrameStreamId(
13762c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    const SpdyControlFrame* control_frame) {
13772c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  SpdyStreamId stream_id = kInvalidStream;
13782c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  if (control_frame != NULL) {
13792c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    switch (control_frame->type()) {
13802c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      case SYN_STREAM:
13812c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        stream_id = reinterpret_cast<const SpdySynStreamControlFrame*>(
13822c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun            control_frame)->stream_id();
13832c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        break;
13842c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      case SYN_REPLY:
13852c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        stream_id = reinterpret_cast<const SpdySynReplyControlFrame*>(
13862c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun            control_frame)->stream_id();
13872c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        break;
13882c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      case HEADERS:
13892c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        stream_id = reinterpret_cast<const SpdyHeadersControlFrame*>(
13902c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun            control_frame)->stream_id();
13912c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        break;
13922c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      case RST_STREAM:
13932c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        stream_id = reinterpret_cast<const SpdyRstStreamControlFrame*>(
13942c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun            control_frame)->stream_id();
13952c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        break;
13962c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      case WINDOW_UPDATE:
13972c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        stream_id = reinterpret_cast<const SpdyWindowUpdateControlFrame*>(
13982c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun            control_frame)->stream_id();
13992c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        break;
14002c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      // All of the following types are not part of a particular stream.
14012c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      // They all fall through to the invalid control frame type case.
14022c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      // (The default case isn't used so that the compile will break if a new
14032c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      // control frame type is added but not included here.)
14042c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      case SETTINGS:
14052c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      case NOOP:
14062c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      case PING:
14072c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      case GOAWAY:
14082c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      case NUM_CONTROL_FRAME_TYPES:  // makes compiler happy
14092c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun        break;
14102c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    }
14112c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
14122c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return stream_id;
14132c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
14142c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
14152c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurunvoid SpdyFramer::set_validate_control_frame_sizes(bool value) {
14162c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  validate_control_frame_sizes_ = value;
14172c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
14182c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
1419c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSpdyDataFrame* SpdyFramer::DecompressDataFrame(const SpdyDataFrame& frame) {
1420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  z_stream* decompressor = GetStreamDecompressor(frame.stream_id());
1421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!decompressor)
1422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
1423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return reinterpret_cast<SpdyDataFrame*>(
1424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DecompressFrameWithZStream(frame, decompressor));
1425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1427c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSpdyFrame* SpdyFramer::CompressFrameWithZStream(const SpdyFrame& frame,
1428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                z_stream* compressor) {
1429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int payload_length;
1430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int header_length;
1431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char* payload;
1432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1433ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::StatsCounter compressed_frames("spdy.CompressedFrames");
1434ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::StatsCounter pre_compress_bytes("spdy.PreCompressSize");
1435ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::StatsCounter post_compress_bytes("spdy.PostCompressSize");
1436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!enable_compression_)
1438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return DuplicateFrame(frame);
1439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!GetFrameBoundaries(frame, &payload_length, &header_length, &payload))
1441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
1442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Create an output frame.
1444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int compressed_max_size = deflateBound(compressor, payload_length);
1445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int new_frame_size = header_length + compressed_max_size;
1446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdyFrame> new_frame(new SpdyFrame(new_frame_size));
1447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memcpy(new_frame->data(), frame.data(), frame.length() + SpdyFrame::size());
1448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  compressor->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(payload));
1450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  compressor->avail_in = payload_length;
1451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  compressor->next_out = reinterpret_cast<Bytef*>(new_frame->data()) +
1452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          header_length;
1453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  compressor->avail_out = compressed_max_size;
1454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Data packets have a 'compressed' flag.
1456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!new_frame->is_control_frame()) {
1457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SpdyDataFrame* data_frame =
1458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        reinterpret_cast<SpdyDataFrame*>(new_frame.get());
1459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    data_frame->set_flags(data_frame->flags() | DATA_FLAG_COMPRESSED);
1460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
14620888ad5615957327be92abf6dcbb768a1977ab49Kristian Monsen#ifndef ANDROID
1463dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Make sure that all the data we pass to zlib is defined.
1464dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // This way, all Valgrind reports on the compressed data are zlib's fault.
1465dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  (void)VALGRIND_CHECK_MEM_IS_DEFINED(compressor->next_in,
1466dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                      compressor->avail_in);
14670888ad5615957327be92abf6dcbb768a1977ab49Kristian Monsen#endif
1468dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int rv = deflate(compressor, Z_SYNC_FLUSH);
1470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv != Z_OK) {  // How can we know that it compressed everything?
1471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // This shouldn't happen, right?
1472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "deflate failure: " << rv;
1473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
1474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int compressed_size = compressed_max_size - compressor->avail_out;
1477dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
14780888ad5615957327be92abf6dcbb768a1977ab49Kristian Monsen#ifndef ANDROID
1479dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // We trust zlib. Also, we can't do anything about it.
1480dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // See http://www.zlib.net/zlib_faq.html#faq36
1481dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  (void)VALGRIND_MAKE_MEM_DEFINED(new_frame->data() + header_length,
1482dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                  compressed_size);
14830888ad5615957327be92abf6dcbb768a1977ab49Kristian Monsen#endif
1484dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_frame->set_length(header_length + compressed_size - SpdyFrame::size());
1486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  pre_compress_bytes.Add(payload_length);
1488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  post_compress_bytes.Add(new_frame->length());
1489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  compressed_frames.Increment();
1491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return new_frame.release();
1493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1495c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSpdyFrame* SpdyFramer::DecompressFrameWithZStream(const SpdyFrame& frame,
1496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                  z_stream* decompressor) {
1497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int payload_length;
1498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int header_length;
1499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char* payload;
1500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1501ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::StatsCounter decompressed_frames("spdy.DecompressedFrames");
1502ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::StatsCounter pre_decompress_bytes("spdy.PreDeCompressSize");
1503ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::StatsCounter post_decompress_bytes("spdy.PostDeCompressSize");
1504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!enable_compression_)
1506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return DuplicateFrame(frame);
1507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!GetFrameBoundaries(frame, &payload_length, &header_length, &payload))
1509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
1510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!frame.is_control_frame()) {
1512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SpdyDataFrame& data_frame =
1513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        reinterpret_cast<const SpdyDataFrame&>(frame);
1514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if ((data_frame.flags() & DATA_FLAG_COMPRESSED) == 0)
1515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return DuplicateFrame(frame);
1516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Create an output frame.  Assume it does not need to be longer than
1519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the input data.
1520201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  size_t decompressed_max_size = kControlFrameBufferInitialSize;
1521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int new_frame_size = header_length + decompressed_max_size;
1522201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (frame.length() > decompressed_max_size)
1523201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return NULL;
1524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdyFrame> new_frame(new SpdyFrame(new_frame_size));
1525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memcpy(new_frame->data(), frame.data(), frame.length() + SpdyFrame::size());
1526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  decompressor->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(payload));
1528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  decompressor->avail_in = payload_length;
1529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  decompressor->next_out = reinterpret_cast<Bytef*>(new_frame->data()) +
1530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      header_length;
1531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  decompressor->avail_out = decompressed_max_size;
1532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int rv = inflate(decompressor, Z_SYNC_FLUSH);
1534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv == Z_NEED_DICT) {
1535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Need to try again with the right dictionary.
1536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (decompressor->adler == dictionary_id) {
1537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      rv = inflateSetDictionary(decompressor, (const Bytef*)kDictionary,
1538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                kDictionarySize);
1539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (rv == Z_OK)
1540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        rv = inflate(decompressor, Z_SYNC_FLUSH);
1541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv != Z_OK) {  // How can we know that it decompressed everything?
1544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "inflate failure: " << rv;
1545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
1546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Unset the compressed flag for data frames.
1549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!new_frame->is_control_frame()) {
1550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SpdyDataFrame* data_frame =
1551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        reinterpret_cast<SpdyDataFrame*>(new_frame.get());
1552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    data_frame->set_flags(data_frame->flags() & ~DATA_FLAG_COMPRESSED);
1553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int decompressed_size = decompressed_max_size - decompressor->avail_out;
1556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_frame->set_length(header_length + decompressed_size - SpdyFrame::size());
1557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1558ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If there is data left, then the frame didn't fully decompress.  This
1559ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // means that there is stranded data at the end of this frame buffer which
1560ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // will be ignored.
1561ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(decompressor->avail_in, 0u);
1562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  pre_decompress_bytes.Add(frame.length());
1564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  post_decompress_bytes.Add(new_frame->length());
1565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  decompressed_frames.Increment();
1567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return new_frame.release();
1569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SpdyFramer::CleanupCompressorForStream(SpdyStreamId id) {
1572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CompressorMap::iterator it = stream_compressors_.find(id);
1573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (it != stream_compressors_.end()) {
1574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    z_stream* compressor = it->second;
1575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    deflateEnd(compressor);
1576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete compressor;
1577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    stream_compressors_.erase(it);
1578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SpdyFramer::CleanupDecompressorForStream(SpdyStreamId id) {
1582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CompressorMap::iterator it = stream_decompressors_.find(id);
1583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (it != stream_decompressors_.end()) {
1584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    z_stream* decompressor = it->second;
1585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    inflateEnd(decompressor);
1586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete decompressor;
1587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    stream_decompressors_.erase(it);
1588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SpdyFramer::CleanupStreamCompressorsAndDecompressors() {
1592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CompressorMap::iterator it;
1593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  it = stream_compressors_.begin();
1595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (it != stream_compressors_.end()) {
1596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    z_stream* compressor = it->second;
1597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    deflateEnd(compressor);
1598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete compressor;
1599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ++it;
1600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  stream_compressors_.clear();
1602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  it = stream_decompressors_.begin();
1604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (it != stream_decompressors_.end()) {
1605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    z_stream* decompressor = it->second;
1606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    inflateEnd(decompressor);
1607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete decompressor;
1608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ++it;
1609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  stream_decompressors_.clear();
1611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
161372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsensize_t SpdyFramer::BytesSafeToRead() const {
161472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  switch (state_) {
161572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_ERROR:
161672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_DONE:
161772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_AUTO_RESET:
161872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_RESET:
161972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return 0;
162072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_READING_COMMON_HEADER:
162172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      DCHECK_LT(current_frame_len_, SpdyFrame::size());
162272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return SpdyFrame::size() - current_frame_len_;
162372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER:
162472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return 0;
16252c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    // TODO(rtenneti): Add support for SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK
16262c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    // and SPDY_CONTROL_FRAME_HEADER_BLOCK.
16272c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK:
16282c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    case SPDY_CONTROL_FRAME_HEADER_BLOCK:
16292c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return 0;
163072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_CONTROL_FRAME_PAYLOAD:
163172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_IGNORE_REMAINING_PAYLOAD:
163272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case SPDY_FORWARD_STREAM_FRAME:
16332c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      return remaining_data_;
1634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
163572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // We should never get to here.
163672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return 0;
163772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
1638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
163972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid SpdyFramer::set_error(SpdyError error) {
164072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(visitor_);
164172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  error_code_ = error;
164272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  CHANGE_STATE(SPDY_ERROR);
164372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  visitor_->OnError(this);
1644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
164672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid SpdyFramer::ExpandControlFrameBuffer(size_t size) {
164772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  size_t alloc_size = size + SpdyFrame::size();
16482c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  DCHECK_LE(alloc_size, kControlFrameBufferMaxSize);
164972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (alloc_size <= current_frame_capacity_)
165072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return;
165172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  char* new_buffer = new char[alloc_size];
165272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  memcpy(new_buffer, current_frame_buffer_, current_frame_len_);
165372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  delete [] current_frame_buffer_;
165472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  current_frame_capacity_ = alloc_size;
165572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  current_frame_buffer_ = new_buffer;
1656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
165872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool SpdyFramer::GetFrameBoundaries(const SpdyFrame& frame,
165972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                    int* payload_length,
166072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                    int* header_length,
166172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                    const char** payload) const {
166272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  size_t frame_size;
166372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (frame.is_control_frame()) {
166472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const SpdyControlFrame& control_frame =
166572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        reinterpret_cast<const SpdyControlFrame&>(frame);
166672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    switch (control_frame.type()) {
166772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      case SYN_STREAM:
166872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        {
166972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          const SpdySynStreamControlFrame& syn_frame =
167072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              reinterpret_cast<const SpdySynStreamControlFrame&>(frame);
167172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          frame_size = SpdySynStreamControlFrame::size();
167272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          *payload_length = syn_frame.header_block_len();
167372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          *header_length = frame_size;
167472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          *payload = frame.data() + *header_length;
167572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        }
167672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        break;
167772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      case SYN_REPLY:
167872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        {
167972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          const SpdySynReplyControlFrame& syn_frame =
168072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              reinterpret_cast<const SpdySynReplyControlFrame&>(frame);
168172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          frame_size = SpdySynReplyControlFrame::size();
168272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          *payload_length = syn_frame.header_block_len();
168372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          *header_length = frame_size;
168472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          *payload = frame.data() + *header_length;
168572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        }
168672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        break;
168772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      case HEADERS:
168872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        {
168972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          const SpdyHeadersControlFrame& headers_frame =
169072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              reinterpret_cast<const SpdyHeadersControlFrame&>(frame);
169172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          frame_size = SpdyHeadersControlFrame::size();
169272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          *payload_length = headers_frame.header_block_len();
169372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          *header_length = frame_size;
169472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          *payload = frame.data() + *header_length;
169572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        }
169672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        break;
169772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      default:
169872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        // TODO(mbelshe): set an error?
169972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        return false;  // We can't compress this frame!
170072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
170172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else {
170272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    frame_size = SpdyFrame::size();
170372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    *header_length = frame_size;
170472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    *payload_length = frame.length();
170572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    *payload = frame.data() + SpdyFrame::size();
170672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
170772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return true;
1708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace spdy
1711