diff --git a/proxygen/lib/http/codec/RateLimitFilter.cpp b/proxygen/lib/http/codec/RateLimitFilter.cpp index ec551bdabf..d3be82a2c3 100644 --- a/proxygen/lib/http/codec/RateLimitFilter.cpp +++ b/proxygen/lib/http/codec/RateLimitFilter.cpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace proxygen { @@ -37,7 +38,7 @@ std::unique_ptr RateLimitFilter::createRateLimitFilter( return std::make_unique(timer, httpSessionStats); case Type::RSTS: - return nullptr; + return std::make_unique(timer, httpSessionStats); case Type::DIRECT_ERROR_HANDLING: return std::make_unique(timer, httpSessionStats); diff --git a/proxygen/lib/http/codec/ResetsRateLimitFilter.h b/proxygen/lib/http/codec/ResetsRateLimitFilter.h new file mode 100644 index 0000000000..ac54813162 --- /dev/null +++ b/proxygen/lib/http/codec/ResetsRateLimitFilter.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +namespace proxygen { + +class ResetsRateLimitFilter : public RateLimitFilter { + public: + static const uint32_t kDefaultMaxEventsPerInterval = 200; + static const uint32_t kMaxEventsPerIntervalLowerBound = 100; + static constexpr std::chrono::milliseconds kDefaultTimeoutDuration{1000}; + + explicit ResetsRateLimitFilter(folly::HHWheelTimer* timer, + HTTPSessionStats* httpSessionStats) + : RateLimitFilter(timer, httpSessionStats) { + maxEventsInInterval_ = kDefaultMaxEventsPerInterval; + timeoutDuration_ = kDefaultTimeoutDuration; + } + + void onAbort(HTTPCodec::StreamID streamID, ErrorCode code) override { + if (!incrementNumEventsInCurrentInterval()) { + callback_->onAbort(streamID, code); + } else { + sendErrorCallback(http2::FrameType::RST_STREAM); + } + } + + void recordNumEventsInCurrentInterval(uint32_t numEvents) override { + // TODO: Add stats for number of resets in the current interval + } + + void recordRateLimitBreached() override { + // TODO: Add stats for number of resets in the current interval + } + + uint32_t getMaxEventsPerInvervalLowerBound() const override { + return kMaxEventsPerIntervalLowerBound; + } + + private: + void sendErrorCallback(http2::FrameType frameType) { + HTTPException ex( + HTTPException::Direction::INGRESS_AND_EGRESS, + folly::to( + "dropping connection due to too many control messages, num " + "control messages = ", + numEventsInCurrentInterval_, + ", most recent frame type = ", + getFrameTypeString(http2::FrameType::RST_STREAM))); + ex.setProxygenError(kErrorDropped); + callback_->onError(0, ex, true); + } +}; + +} // namespace proxygen