mirror of
				https://codeberg.org/yeentown/barkey.git
				synced 2025-11-04 07:24:13 +00:00 
			
		
		
		
	use fraction seconds for rate limit headers
This commit is contained in:
		
							parent
							
								
									7c002ce56e
								
							
						
					
					
						commit
						2bcac80092
					
				
					 2 changed files with 72 additions and 4 deletions
				
			
		| 
						 | 
				
			
			@ -126,14 +126,20 @@ export function hasMinLimit(limit: LegacyRateLimit): limit is LegacyRateLimit &
 | 
			
		|||
 | 
			
		||||
export function sendRateLimitHeaders(reply: FastifyReply, info: LimitInfo): void {
 | 
			
		||||
	// Number of seconds until the limit has fully reset.
 | 
			
		||||
	reply.header('X-RateLimit-Clear', info.fullResetSec.toString());
 | 
			
		||||
	const clear = (info.fullResetMs / 1000).toFixed(3);
 | 
			
		||||
	reply.header('X-RateLimit-Clear', clear);
 | 
			
		||||
 | 
			
		||||
	// Number of calls that can be made before being limited.
 | 
			
		||||
	reply.header('X-RateLimit-Remaining', info.remaining.toString());
 | 
			
		||||
	const remaining = info.remaining.toString();
 | 
			
		||||
	reply.header('X-RateLimit-Remaining', remaining);
 | 
			
		||||
 | 
			
		||||
	if (info.blocked) {
 | 
			
		||||
		// Number of seconds to wait before trying again. Left for backwards compatibility.
 | 
			
		||||
		reply.header('Retry-After', info.resetSec.toString());
 | 
			
		||||
		const retry = info.resetSec.toString();
 | 
			
		||||
		reply.header('Retry-After', retry);
 | 
			
		||||
 | 
			
		||||
		// Number of milliseconds to wait before trying again.
 | 
			
		||||
		reply.header('X-RateLimit-Reset', info.resetMs.toString());
 | 
			
		||||
		const reset = (info.resetMs / 1000).toFixed(3);
 | 
			
		||||
		reply.header('X-RateLimit-Reset', reset);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										62
									
								
								packages/backend/test/unit/misc/rate-limit-utils-tests.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								packages/backend/test/unit/misc/rate-limit-utils-tests.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,62 @@
 | 
			
		|||
/*
 | 
			
		||||
 * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
 | 
			
		||||
 * SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import { jest } from '@jest/globals';
 | 
			
		||||
import { Mock } from 'jest-mock';
 | 
			
		||||
import type { FastifyReply } from 'fastify';
 | 
			
		||||
import { LimitInfo, sendRateLimitHeaders } from '@/misc/rate-limit-utils.js';
 | 
			
		||||
 | 
			
		||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
 | 
			
		||||
 | 
			
		||||
describe(sendRateLimitHeaders, () => {
 | 
			
		||||
	let mockHeader: Mock<((name: string, value: unknown) => void)> = null!;
 | 
			
		||||
	let mockReply: FastifyReply = null!;
 | 
			
		||||
	let fakeInfo: LimitInfo = null!;
 | 
			
		||||
 | 
			
		||||
	beforeEach(() => {
 | 
			
		||||
		mockHeader = jest.fn<((name: string, value: unknown) => void)>();
 | 
			
		||||
		mockReply = {
 | 
			
		||||
			header: mockHeader,
 | 
			
		||||
		} as unknown as FastifyReply;
 | 
			
		||||
		fakeInfo = {
 | 
			
		||||
			blocked: false,
 | 
			
		||||
			remaining: 1,
 | 
			
		||||
			resetSec: 1,
 | 
			
		||||
			resetMs: 567,
 | 
			
		||||
			fullResetSec: 10,
 | 
			
		||||
			fullResetMs: 9876,
 | 
			
		||||
		};
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	it('should send X-RateLimit-Clear', () => {
 | 
			
		||||
		sendRateLimitHeaders(mockReply, fakeInfo);
 | 
			
		||||
 | 
			
		||||
		expect(mockHeader).toHaveBeenCalledWith('X-RateLimit-Clear', '9.876');
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	it('should send X-RateLimit-Remaining', () => {
 | 
			
		||||
		sendRateLimitHeaders(mockReply, fakeInfo);
 | 
			
		||||
 | 
			
		||||
		expect(mockHeader).toHaveBeenCalledWith('X-RateLimit-Remaining', '1');
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	describe('when limit is blocked', () => {
 | 
			
		||||
		it('should send X-RateLimit-Reset', () => {
 | 
			
		||||
			fakeInfo.blocked = true;
 | 
			
		||||
 | 
			
		||||
			sendRateLimitHeaders(mockReply, fakeInfo);
 | 
			
		||||
 | 
			
		||||
			expect(mockHeader).toHaveBeenCalledWith('X-RateLimit-Reset', '0.567');
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		it('should send Retry-After', () => {
 | 
			
		||||
			fakeInfo.blocked = true;
 | 
			
		||||
 | 
			
		||||
			sendRateLimitHeaders(mockReply, fakeInfo);
 | 
			
		||||
 | 
			
		||||
			expect(mockHeader).toHaveBeenCalledWith('Retry-After', '1');
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue