Sub-scope 04 (httpclient) restclient/** + webclient/** — manifest and probes revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5 generatedAt=2026-08-30T05:31:16+00:00 === OWNED FILES === 3317df91c6c64d62d0c1b0ac6634f8d2209a5503 main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/BlockingAttemptExecutor.java 269 5e5cb1380bdb79df615d583ab3e644fb000e9c57 main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/BlockingClientRuntime.java 132 06d394b8d3116511a7407980e57276e067cb87db main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/BlockingExecutionSupport.java 86 d4e4d3188f8fb13ee72a849e101303bfbde4a83e main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/BlockingOperationContext.java 41 8b0b348f9ff5f5577a913f934d2ced7f163cd6a5 main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/BlockingRedirectCoordinator.java 114 f0c6a30368119d4fb939f8850b23603f5d945759 main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/BlockingResponseMapper.java 78 9589a9f172c77738aaab1a689e812d3185ccc5bf main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/BlockingStreamingGateway.java 169 90e67085b700cfdfe637b2c8643a8b2054035a6e main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/BoundedErrorBody.java 54 bad7193da46442324dcc5bc325870c2b3ff3f156 main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/CountingBoundedInputStream.java 50 6c72a175d065e5ae317c6992120a166661bae83b main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/DefaultBlockingStreamingResponse.java 67 17e787852f7b4762ff280b68bc510a5f986be3ee main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/DefaultGenericHttpGateway.java 304 473cf6085dfdd827822e938915f5bf43321f36ef main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/GenericHttpGateway.java 26 35f9f94dff3fdcc2f24cf29f99cfbca04466e352 main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/RemoteProblemDecoder.java 88 e88961bc440727c875270af1e8b6e559db0a53ec main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/ResponseSizeLimiter.java 62 ce9cc87429faccd4effe19ada9b017187485abd8 main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/RestClientBodyWriter.java 76 de93a1bec3b600f203894ff5d9641e041a9db54c main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/RestClientResponseReader.java 206 42518b6727c4dfc884f9bec5eb29752b8272b132 main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/RestClientRuntimeFactory.java 144 e4305dce6f69236a4465bafa9328e53a5f1cf3ce main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/StableBlockingExceptionMapper.java 40 fdd77212d4830a37192a6550834673d31d45579b main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/StatusHandlingPolicy.java 12 f7e354c4783a8d1cfa91589c7c08ad51eb3e245f main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/BoundedDataBufferFlux.java 39 158094336c522fda6ee08642b47b512cdd32536f main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/DefaultReactiveHttpGateway.java 330 5b9588c32fd9099c168b058f7a23e40878b1838c main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/DefaultReactiveSseGateway.java 183 33ff26665dca2064611531748084a305826b13fe main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/FirstByteDeliveryGuard.java 24 f4ca87199cfb463223d496f950d2b2e87a952ed2 main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/MultipartReplayability.java 37 36f2d940765828913d1adbf5eee49ecf82d1a927 main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/ReactiveAttemptExecutor.java 184 b193badebdecca660699403d87b7847bb2e802d5 main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/ReactiveBodySource.java 38 ad4f8e67414ef821f8d49822bfb4b7dca138b1c2 main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/ReactiveClientRuntime.java 111 dbadac6d34f55b4b5795988e83448e1cf3732d51 main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/ReactiveHttpGateway.java 18 f250530402a4b0c849e8d7cbbc117faca481c030 main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/ReactiveSseGateway.java 13 134d3c2baa033be52419c164b4792f3501c92a30 main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/ReactiveStreamingGateway.java 107 e5f5779004a000c5bb830f7ed512dcf5f77ca342 main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/SseIdleTimeoutException.java 22 f82ef76d8b89077ee50820179ab93d287ef9cae4 main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/SseOperation.java 49 90f65c72d6580e715f7bd72e49d6d236b81ac8f8 main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/SseReconnectPolicy.java 28 ece8e712de4c2dd97ba98a9a182e972a7d8dc24f main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/WebClientBodyWriter.java 98 225bd9843d62843034dcab53ac51fa2497f5ea45 main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/WebClientResponseMapper.java 54 9c2e47f592ae3462e72e7b4a803f1b37bba3df71 main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/WebClientRuntimeFactory.java 123 b1990e1b941ed8157e1ae3964c7c5e3d4323511f test/java/dev/caskeleton/adapter/outbound/httpclient/restclient/BlockingRedirectCoordinatorTest.java 175 8acd49e49ff84f29f2c539b875d7b78c3c97e65b test/java/dev/caskeleton/adapter/outbound/httpclient/restclient/BlockingResponseMapperTest.java 63 0f841cd744743ac058c99ca2c841593d4ecc01fa test/java/dev/caskeleton/adapter/outbound/httpclient/restclient/BlockingStreamingLifecycleTest.java 145 a88e2e1c08e8e037a4124d30db718bdc82c0de57 test/java/dev/caskeleton/adapter/outbound/httpclient/restclient/DefaultGenericHttpGatewayTest.java 200 b308025e96311ce3b8d80359ff3431f9b28bff87 test/java/dev/caskeleton/adapter/outbound/httpclient/restclient/ResponseSizeLimiterTest.java 37 d4241ae02359c7306800a410da417a746593ad8e test/java/dev/caskeleton/adapter/outbound/httpclient/webclient/BlockHoundEventLoopTest.java 110 fa0419d599ca04b74b29762ceefe0724de505074 test/java/dev/caskeleton/adapter/outbound/httpclient/webclient/DefaultReactiveHttpGatewayTest.java 95 fb8fe20deeee336dd793926f2ab3dd8cf7b343ff test/java/dev/caskeleton/adapter/outbound/httpclient/webclient/FirstByteRetryBoundaryTest.java 64 6541bc4bffaa675074e3886c12fa6e1f3b48384d test/java/dev/caskeleton/adapter/outbound/httpclient/webclient/ReactiveSseGatewayTest.java 101 eb13dd777f8beedb48057001c2fe7c6ebd4194b4 test/java/dev/caskeleton/adapter/outbound/httpclient/webclient/ReactiveStreamingLifecycleTest.java 121 main: 36 test: 10 === 8.1 BoundedDataBufferFlux의 두 연산자가 실제로 하는 일 === $ grep -n 'doOnCancel\|onErrorResume\|doOnDiscard\|doOnNext' adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/BoundedDataBufferFlux.java 25: .doOnNext( 30: .doOnDiscard(DataBuffer.class, DataBufferUtils::release) 31: .doOnCancel(() -> {}) 32: .onErrorResume( 35: // discarded through doOnDiscard above. exit=0 $ git grep -rn 'BoundedDataBufferFlux' -- 'adapter/outbound/httpclient/src' | grep -v 'BoundedDataBufferFlux.java' adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/ReactiveStreamingGateway.java:102: return BoundedDataBufferFlux.bound( exit=0 === 8.2 ResponseSizeLimiter의 UNBOUND 메타데이터 생성자 사용처 === $ grep -n 'UNBOUND\|public ResponseSizeLimiter' adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/ResponseSizeLimiter.java 15: private static final HttpFailureMetadata UNBOUND = 25: public ResponseSizeLimiter(long maxWireBytes, long maxDecodedBytes) { 26: this(maxWireBytes, maxDecodedBytes, UNBOUND); 29: public ResponseSizeLimiter( exit=0 $ git grep -rn 'new ResponseSizeLimiter(' -- 'adapter/outbound/httpclient/src' adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/BlockingAttemptExecutor.java:52: new ResponseSizeLimiter( adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/BlockingStreamingGateway.java:60: new ResponseSizeLimiter( adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/ReactiveStreamingGateway.java:69: new ResponseSizeLimiter( adapter/outbound/httpclient/src/test/java/dev/caskeleton/adapter/outbound/httpclient/restclient/BlockingResponseMapperTest.java:59: ResponseSizeLimiter limiter = new ResponseSizeLimiter(10, 20); adapter/outbound/httpclient/src/test/java/dev/caskeleton/adapter/outbound/httpclient/restclient/ResponseSizeLimiterTest.java:16: ResponseSizeLimiter limiter = new ResponseSizeLimiter(10, 100); adapter/outbound/httpclient/src/test/java/dev/caskeleton/adapter/outbound/httpclient/restclient/ResponseSizeLimiterTest.java:21: ResponseSizeLimiter decodedLimiter = new ResponseSizeLimiter(100, 10); adapter/outbound/httpclient/src/test/java/dev/caskeleton/adapter/outbound/httpclient/restclient/ResponseSizeLimiterTest.java:29: ResponseSizeLimiter limiter = new ResponseSizeLimiter(4, 1024); exit=0 === 8.3 리다이렉트 hop 상한이 실제로 강제되는가 === $ grep -n 'for (int hop' -A 3 adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/BlockingRedirectCoordinator.java 77: for (int hop = 0; isRedirect(response.status()); hop++) { 78- Optional location = response.firstHeader("Location"); 79- if (location.isEmpty()) { 80- return response; exit=0 $ git grep -n 'maxHops' -- 'adapter/outbound/httpclient/src/main' adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientProfileValidator.java:71: if (redirect.maxHops() == 0) { adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/RedirectSettings.java:7:public record RedirectSettings(boolean enabled, int maxHops, boolean allowCrossOrigin) { adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/RedirectSettings.java:12: if (maxHops < 0) { adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/security/RedirectEvaluator.java:16: if (context.hop() >= context.policy().maxHops()) { adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/security/RedirectPolicy.java:18: boolean enabled, int maxHops, boolean allowCrossOrigin, boolean callerManaged) { adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/security/RedirectPolicy.java:23: public RedirectPolicy(boolean enabled, int maxHops, boolean allowCrossOrigin) { adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/security/RedirectPolicy.java:24: this(enabled, maxHops, allowCrossOrigin, false); adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/security/RedirectPolicy.java:38: settings.enabled(), settings.maxHops(), settings.allowCrossOrigin(), false); exit=0 === 8.4 게이트웨이 test === $ git ls-files 'adapter/outbound/httpclient/src/test/java/dev/caskeleton/adapter/outbound/httpclient/restclient' 'adapter/outbound/httpclient/src/test/java/dev/caskeleton/adapter/outbound/httpclient/webclient' | xargs -n1 basename BlockingRedirectCoordinatorTest.java BlockingResponseMapperTest.java BlockingStreamingLifecycleTest.java DefaultGenericHttpGatewayTest.java ResponseSizeLimiterTest.java BlockHoundEventLoopTest.java DefaultReactiveHttpGatewayTest.java FirstByteRetryBoundaryTest.java ReactiveSseGatewayTest.java ReactiveStreamingLifecycleTest.java exit=0 $ git grep -h ' void [a-z]' -- 'adapter/outbound/httpclient/src/test/java/dev/caskeleton/adapter/outbound/httpclient/restclient' 'adapter/outbound/httpclient/src/test/java/dev/caskeleton/adapter/outbound/httpclient/webclient' | sed 's/^ *//' void refusesRedirectsWhenTheProfileDisablesThem() throws Exception { void followsABoundedSameOriginHopWhenEnabled() throws Exception { void stopsAtTheConfiguredHopLimit() throws Exception { void aHopIsRejectedWhenTheProfileAllowlistExcludesIt() throws Exception { void aSeeOtherHopDropsTheRequestBody() throws Exception { void mapsProblemJsonWithoutTrustingBodyStatus() { void dropsExtensionsThatAreNotAllowlisted() { void treatsANonProblemContentTypeAsAnEmptyProblem() { void survivesAnUnparseableProblemDocument() { void abortsWhenDecodedBytesExceedLimit() { void closeReturnsConnectionAfterPartialRead() throws Exception { void validatesStatusBeforeDeliveringAnyBodyByte() throws Exception { void enforcesTheWireBudgetWhileStreaming() throws Exception { void closeIsIdempotent() { void expandsRelativeTemplateAndReturnsTypedResult() throws Exception { void worksIdenticallyOnTheJdkTransport() throws Exception { void rejectsAnAbsoluteUriFromTheCaller() throws Exception { void mapsProblemResponsesToStableExceptions() throws Exception { void canReturnANonSuccessStatusAsAResultWhenThePolicySaysSo() throws Exception { void throwsRemoteErrorWithoutAProblemDocument() throws Exception { void recordsSeparateLogicalAndAttemptMetrics() throws Exception { void refusesAnUnregisteredProfile() throws Exception { void enforcesTheProfileResponseSizeLimit() throws Exception { void boundsWireAndDecodedBytesIndependently() { void failsWhileReadingRatherThanAfterBuffering() throws IOException { void theDetectorItselfCatchesABlockingCallOnANonBlockingScheduler() { void theReactiveGatewayCompletesWithoutBlockingAnEventLoop() throws Exception { void theReactiveRetryBackoffDoesNotBlockAnEventLoop() throws Exception { void returnsTypedResultWithoutBlocking() throws Exception { void appliesTheSameTargetPolicyAsTheBlockingGateway() throws Exception { void producesTheSameStableFailureTypeForANonSuccessStatus() throws Exception { void releasesTheRuntimeLeaseAfterCompletion() throws Exception { void theGuardLatchesExactlyOnce() { void doesNotRetryAfterFirstBufferWasDelivered() { void aPartialResponseNotYetDeliveredMayStillBeRetriedForASafeOperation() { void multipartReplayabilityFollowsTheWeakestPart() { void decodesEventsFromTheStream() throws Exception { void closesSilentStreamAtStreamingIdleTimeout() throws Exception { void setupAndStreamingBudgetsAreSeparateSettings() { void lastEventIdIsOptInAndOffByDefault() { void cancellationReleasesTheConnectionForTheNextCall() throws Exception { void statusIsValidatedBeforeAnyBufferIsEmitted() throws Exception { void marksTheFirstByteBoundaryWhileStreaming() throws Exception { exit=0