ErrorCode HTTP2Codec::handleSettings()

in proxygen/lib/http/codec/HTTP2Codec.cpp [813:914]


ErrorCode HTTP2Codec::handleSettings(const std::deque<SettingPair>& settings) {
  SettingsList settingsList;
  for (auto& setting : settings) {
    switch (setting.first) {
      case SettingsId::HEADER_TABLE_SIZE: {
        uint32_t tableSize = setting.second;
        if (setting.second > http2::kMaxHeaderTableSize) {
          VLOG(2) << "Limiting table size from " << tableSize << " to "
                  << http2::kMaxHeaderTableSize;
          tableSize = http2::kMaxHeaderTableSize;
        }
        headerCodec_.setEncoderHeaderTableSize(tableSize);
      } break;
      case SettingsId::ENABLE_PUSH:
        if ((setting.second != 0 && setting.second != 1) ||
            (setting.second == 1 &&
             transportDirection_ == TransportDirection::UPSTREAM)) {
          goawayErrorMessage_ =
              folly::to<string>("GOAWAY error: ENABLE_PUSH invalid setting=",
                                setting.second,
                                " for streamID=",
                                curHeader_.stream);
          VLOG(4) << goawayErrorMessage_;
          return ErrorCode::PROTOCOL_ERROR;
        }
        break;
      case SettingsId::MAX_CONCURRENT_STREAMS:
        break;
      case SettingsId::INITIAL_WINDOW_SIZE:
        if (setting.second > http2::kMaxWindowUpdateSize) {
          goawayErrorMessage_ = folly::to<string>(
              "GOAWAY error: INITIAL_WINDOW_SIZE invalid size=",
              setting.second,
              " for streamID=",
              curHeader_.stream);
          VLOG(4) << goawayErrorMessage_;
          return ErrorCode::PROTOCOL_ERROR;
        }
        break;
      case SettingsId::MAX_FRAME_SIZE:
        if (setting.second < http2::kMaxFramePayloadLengthMin ||
            setting.second > http2::kMaxFramePayloadLength) {
          goawayErrorMessage_ =
              folly::to<string>("GOAWAY error: MAX_FRAME_SIZE invalid size=",
                                setting.second,
                                " for streamID=",
                                curHeader_.stream);
          VLOG(4) << goawayErrorMessage_;
          return ErrorCode::PROTOCOL_ERROR;
        }
        ingressSettings_.setSetting(SettingsId::MAX_FRAME_SIZE, setting.second);
        break;
      case SettingsId::MAX_HEADER_LIST_SIZE:
        break;
      case SettingsId::ENABLE_EX_HEADERS: {
        auto ptr = egressSettings_.getSetting(SettingsId::ENABLE_EX_HEADERS);
        if (ptr && ptr->value > 0) {
          VLOG(4) << getTransportDirectionString(getTransportDirection())
                  << " got ENABLE_EX_HEADERS=" << setting.second;
          if (setting.second != 0 && setting.second != 1) {
            goawayErrorMessage_ =
                folly::to<string>("GOAWAY error: invalid ENABLE_EX_HEADERS=",
                                  setting.second,
                                  " for streamID=",
                                  curHeader_.stream);
            VLOG(4) << goawayErrorMessage_;
            return ErrorCode::PROTOCOL_ERROR;
          }
          break;
        } else {
          // egress ENABLE_EX_HEADERS is disabled, consider the ingress
          // ENABLE_EX_HEADERS as unknown setting, and ignore it.
          continue;
        }
      }
      case SettingsId::ENABLE_CONNECT_PROTOCOL:
        if (setting.second > 1) {
          goawayErrorMessage_ = folly::to<string>(
              "GOAWAY error: ENABLE_CONNECT_PROTOCOL invalid number=",
              setting.second,
              " for streamID=",
              curHeader_.stream);
          VLOG(4) << goawayErrorMessage_;
          return ErrorCode::PROTOCOL_ERROR;
        }
        break;
      case SettingsId::THRIFT_CHANNEL_ID:
      case SettingsId::THRIFT_CHANNEL_ID_DEPRECATED:
        break;
      case SettingsId::SETTINGS_HTTP_CERT_AUTH:
        break;
      default:
        continue; // ignore unknown setting
    }
    ingressSettings_.setSetting(setting.first, setting.second);
    settingsList.push_back(*ingressSettings_.getSetting(setting.first));
  }
  if (callback_) {
    callback_->onSettings(settingsList);
  }
  return ErrorCode::NO_ERROR;
}