├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ ├── gh-pages.yaml │ └── maven.yml ├── .gitignore ├── .gitmodules ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE.txt ├── README.md ├── httpclient-core ├── pom.xml └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── esastack │ │ │ └── httpclient │ │ │ └── core │ │ │ ├── CompositeRequest.java │ │ │ ├── Context.java │ │ │ ├── ContextKeys.java │ │ │ ├── DelegatingRequest.java │ │ │ ├── ExecutableRequest.java │ │ │ ├── FileRequest.java │ │ │ ├── Handle.java │ │ │ ├── Handler.java │ │ │ ├── HttpClient.java │ │ │ ├── HttpClientBuilder.java │ │ │ ├── HttpMessage.java │ │ │ ├── HttpRequest.java │ │ │ ├── HttpRequestBase.java │ │ │ ├── HttpRequestBaseImpl.java │ │ │ ├── HttpRequestFacade.java │ │ │ ├── HttpResponse.java │ │ │ ├── HttpUri.java │ │ │ ├── Identifiable.java │ │ │ ├── IdentityFactory.java │ │ │ ├── Listener.java │ │ │ ├── ListenerProxy.java │ │ │ ├── ModifiableClient.java │ │ │ ├── Multipart.java │ │ │ ├── MultipartBody.java │ │ │ ├── MultipartBodyImpl.java │ │ │ ├── MultipartConfigure.java │ │ │ ├── MultipartFileItem.java │ │ │ ├── MultipartRequest.java │ │ │ ├── NoopListener.java │ │ │ ├── PlainRequest.java │ │ │ ├── Request.java │ │ │ ├── RequestBaseConfigure.java │ │ │ ├── Response.java │ │ │ ├── Reusable.java │ │ │ ├── Scheme.java │ │ │ ├── SegmentRequest.java │ │ │ ├── config │ │ │ ├── CacheOptions.java │ │ │ ├── CallbackThreadPoolOptions.java │ │ │ ├── ChannelPoolOptions.java │ │ │ ├── Decompression.java │ │ │ ├── Http1Options.java │ │ │ ├── Http2Options.java │ │ │ ├── NetOptions.java │ │ │ ├── RetryOptions.java │ │ │ └── SslOptions.java │ │ │ ├── exception │ │ │ ├── ClosedConnectionException.java │ │ │ ├── ClosedStreamException.java │ │ │ ├── ContentOverSizedException.java │ │ │ ├── ProtocolException.java │ │ │ ├── RedirectException.java │ │ │ └── RetryException.java │ │ │ ├── exec │ │ │ ├── ExecChain.java │ │ │ ├── ExecContext.java │ │ │ ├── ExpectContinueInterceptor.java │ │ │ ├── FilteringExec.java │ │ │ ├── HttpTransceiver.java │ │ │ ├── Interceptor.java │ │ │ ├── LinkedExecChain.java │ │ │ ├── RedirectInterceptor.java │ │ │ ├── RequestExecutor.java │ │ │ ├── RequestExecutorImpl.java │ │ │ ├── RetryInterceptor.java │ │ │ ├── RetryPredicate.java │ │ │ └── RetryPredicateImpl.java │ │ │ ├── filter │ │ │ ├── DuplexFilter.java │ │ │ ├── FilterContext.java │ │ │ ├── RequestFilter.java │ │ │ └── ResponseFilter.java │ │ │ ├── metrics │ │ │ ├── CallbackExecutorMetric.java │ │ │ ├── ConnectionPoolMetric.java │ │ │ ├── ConnectionPoolMetricProvider.java │ │ │ ├── IoThreadGroupMetric.java │ │ │ ├── IoThreadMetric.java │ │ │ └── MetricPoint.java │ │ │ ├── netty │ │ │ ├── CachedChannelPools.java │ │ │ ├── ChannelInitializer.java │ │ │ ├── ChannelPool.java │ │ │ ├── ChannelPoolFactory.java │ │ │ ├── DefaultHandle.java │ │ │ ├── DelegatingResolver.java │ │ │ ├── FileWriter.java │ │ │ ├── FilteringHandle.java │ │ │ ├── H1TransceiverHandle.java │ │ │ ├── H2TransceiverHandle.java │ │ │ ├── HandleImpl.java │ │ │ ├── HandleRegistry.java │ │ │ ├── Http1ChannelHandler.java │ │ │ ├── Http2ChunkedInput.java │ │ │ ├── Http2ConnectionHandler.java │ │ │ ├── Http2ConnectionHandlerBuilder.java │ │ │ ├── Http2FrameHandler.java │ │ │ ├── HttpMessageImpl.java │ │ │ ├── HttpTransceiverImpl.java │ │ │ ├── IdentityFactoryProvider.java │ │ │ ├── MultipartWriter.java │ │ │ ├── NettyClientConfigure.java │ │ │ ├── NettyClientConfigureImpl.java │ │ │ ├── NettyExecContext.java │ │ │ ├── NettyHttpClient.java │ │ │ ├── NettyResponse.java │ │ │ ├── NettyTransceiver.java │ │ │ ├── PlainWriter.java │ │ │ ├── ReadTimeoutTask.java │ │ │ ├── RequestWriter.java │ │ │ ├── RequestWriterImpl.java │ │ │ ├── ResolverGroupImpl.java │ │ │ ├── ResponseHandle.java │ │ │ ├── SegmentRequestImpl.java │ │ │ ├── SegmentWriter.java │ │ │ ├── ServerSelector.java │ │ │ ├── SslEngineFactoryImpl.java │ │ │ ├── ThreadFactoryImpl.java │ │ │ ├── TimeoutHandle.java │ │ │ ├── TransceiverHandle.java │ │ │ └── Utils.java │ │ │ ├── resolver │ │ │ ├── BalancedHostResolver.java │ │ │ ├── HostResolver.java │ │ │ └── SystemDefaultResolver.java │ │ │ ├── spi │ │ │ ├── ChannelPoolOptionsProvider.java │ │ │ ├── DuplexFilterFactory.java │ │ │ ├── DuplexFilterFactoryImpl.java │ │ │ ├── InterceptorFactory.java │ │ │ ├── InterceptorFactoryImpl.java │ │ │ ├── RequestFilterFactory.java │ │ │ ├── RequestFilterFactoryImpl.java │ │ │ ├── ResponseFilterFactory.java │ │ │ ├── ResponseFilterFactoryImpl.java │ │ │ └── SslEngineFactory.java │ │ │ └── util │ │ │ ├── BufferUtils.java │ │ │ ├── Futures.java │ │ │ ├── HttpClientVer.java │ │ │ ├── HttpHeadersUtils.java │ │ │ ├── LoggerUtils.java │ │ │ ├── MultiValueMapUtils.java │ │ │ ├── Ordered.java │ │ │ └── OrderedComparator.java │ └── resources │ │ └── META-INF │ │ └── httpclient │ │ └── HttpClient-Ver.txt │ └── test │ └── java │ └── io │ └── esastack │ └── httpclient │ └── core │ ├── CompositeRequestTest.java │ ├── ContextTest.java │ ├── DelegatingRequestTest.java │ ├── ExecContextUtil.java │ ├── HttpClientBuilderTest.java │ ├── HttpRequestBaseImplTest.java │ ├── HttpUriTest.java │ ├── ListenerProxyTest.java │ ├── MultipartFileItemTest.java │ ├── config │ ├── CacheOptionsTest.java │ ├── CallbackThreadPoolOptionsTest.java │ ├── ChannelPoolOptionsTest.java │ ├── Http1OptionsTest.java │ ├── Http2OptionsTest.java │ ├── NetOptionsTest.java │ ├── RetryOptionsTest.java │ ├── ReusableTest.java │ └── SslOptionsTest.java │ ├── exec │ ├── ExpectContinueInterceptorTest.java │ ├── FilteringExecTest.java │ ├── LinkedExecChainTest.java │ ├── RedirectInterceptorTest.java │ ├── RequestExecutorImplTest.java │ ├── RetryInterceptorTest.java │ └── RetryPredicateImplTest.java │ ├── filter │ └── FilterContextTest.java │ ├── mock │ ├── MockContext.java │ ├── MockFilterContext.java │ └── MockHttpResponse.java │ ├── netty │ ├── CachedChannelPoolsTest.java │ ├── ChannelInitializerTest.java │ ├── ChannelPoolFactoryTest.java │ ├── ChannelPoolTest.java │ ├── DefaultHandleTest.java │ ├── DelegatingResolverTest.java │ ├── FileWriterTest.java │ ├── FilteringHandleTest.java │ ├── H1TransceiverHandleTest.java │ ├── H2TransceiverHandleTest.java │ ├── HandleImplTest.java │ ├── HandleRegistryTest.java │ ├── Helper.java │ ├── Http1ChannelHandlerTest.java │ ├── Http2ChunkedInputTest.java │ ├── Http2ConnectionHandlerBuilderTest.java │ ├── Http2ConnectionHandlerTest.java │ ├── Http2ConnectionHelper.java │ ├── Http2FrameHandlerTest.java │ ├── Http2FrameInboundWriter.java │ ├── HttpMessageImplTest.java │ ├── HttpTransceiverImplTest.java │ ├── MultipartWriterTest.java │ ├── NettyExecContextTest.java │ ├── NettyHttpClientTest.java │ ├── NettyResponseTest.java │ ├── NettyTransceiverTest.java │ ├── PlainWriterTest.java │ ├── ReadTimeoutTaskTest.java │ ├── RequestWriterImplTest.java │ ├── ResolverGroupImplTest.java │ ├── ResponseHandleTest.java │ ├── SegmentRequestImplTest.java │ ├── SegmentWriterTest.java │ ├── ServerSelectorTest.java │ ├── ThreadFactoryImplTest.java │ ├── TimeoutHandleTest.java │ └── UtilsTest.java │ ├── resolver │ └── BalancedHostResolverTest.java │ └── util │ ├── FuturesTest.java │ ├── HttpClientVerTest.java │ ├── HttpHeadersUtilsTest.java │ ├── MultiValueMapUtilsTest.java │ └── OrderedComparatorTest.java ├── pom.xml ├── restclient-ext ├── pom.xml ├── traffic-split-file-config │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── io │ │ │ └── esastack │ │ │ └── restclient │ │ │ └── ext │ │ │ └── rule │ │ │ ├── ActionsConfig.java │ │ │ ├── ConditionConfig.java │ │ │ ├── FileRuleSourceFactory.java │ │ │ ├── RuleConfig.java │ │ │ └── RulesProvider.java │ │ └── resources │ │ └── META-INF │ │ └── esa │ │ └── internal │ │ └── io.esastack.restclient.ext.spi.RuleSourceFactory └── traffic-split-interceptor │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── io │ │ └── esastack │ │ └── restclient │ │ └── ext │ │ ├── TrafficSplitContext.java │ │ ├── TrafficSplitContextImpl.java │ │ ├── action │ │ ├── TrafficSplitAction.java │ │ └── impl │ │ │ ├── HeaderAction.java │ │ │ ├── HeaderActionConfig.java │ │ │ ├── ParamAction.java │ │ │ ├── ParamActionConfig.java │ │ │ ├── RewriteAction.java │ │ │ └── RewriteActionConfig.java │ │ ├── condition │ │ ├── TrafficSplitCondition.java │ │ └── impl │ │ │ ├── AuthorityCondition.java │ │ │ ├── HeaderCondition.java │ │ │ ├── MethodCondition.java │ │ │ ├── ParamCondition.java │ │ │ └── PathCondition.java │ │ ├── interceptor │ │ └── TrafficSplitInterceptorFactory.java │ │ ├── matcher │ │ ├── HeaderMatcher.java │ │ ├── KVMatcher.java │ │ ├── MatchResult.java │ │ ├── MatchResultImpl.java │ │ ├── ParamMatcher.java │ │ └── StringMatcher.java │ │ ├── rule │ │ ├── TrafficSplitRule.java │ │ └── TrafficSplitRuleSource.java │ │ └── spi │ │ └── RuleSourceFactory.java │ └── resources │ └── META-INF │ └── esa │ └── internal │ └── io.esastack.restclient.spi.RestInterceptorFactory ├── restclient ├── pom.xml └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── esastack │ │ │ └── restclient │ │ │ ├── AbstractExecutableRestRequest.java │ │ │ ├── ExecutableRestRequest.java │ │ │ ├── RequestTransceiver.java │ │ │ ├── RestClient.java │ │ │ ├── RestClientBuilder.java │ │ │ ├── RestClientImpl.java │ │ │ ├── RestClientOptions.java │ │ │ ├── RestCompositeRequest.java │ │ │ ├── RestFileRequest.java │ │ │ ├── RestMultipartRequest.java │ │ │ ├── RestRequest.java │ │ │ ├── RestRequestBase.java │ │ │ ├── RestRequestFacade.java │ │ │ ├── RestResponse.java │ │ │ ├── RestResponseBase.java │ │ │ ├── RestResponseBaseImpl.java │ │ │ ├── codec │ │ │ ├── ByteCodec.java │ │ │ ├── ByteDecoder.java │ │ │ ├── ByteEncoder.java │ │ │ ├── Content.java │ │ │ ├── DecodeAdvice.java │ │ │ ├── DecodeAdviceContext.java │ │ │ ├── DecodeChain.java │ │ │ ├── DecodeContext.java │ │ │ ├── Decoder.java │ │ │ ├── EncodeAdvice.java │ │ │ ├── EncodeAdviceContext.java │ │ │ ├── EncodeChain.java │ │ │ ├── EncodeContext.java │ │ │ ├── Encoder.java │ │ │ ├── JsonCodec.java │ │ │ ├── RequestContent.java │ │ │ ├── ResponseContent.java │ │ │ └── impl │ │ │ │ ├── ByteToByteCodec.java │ │ │ │ ├── ContentImpl.java │ │ │ │ ├── DecodeChainImpl.java │ │ │ │ ├── EncodeChainImpl.java │ │ │ │ ├── FastJsonCodec.java │ │ │ │ ├── FileEncoder.java │ │ │ │ ├── FormURLEncodedEncoder.java │ │ │ │ ├── GsonCodec.java │ │ │ │ ├── JacksonCodec.java │ │ │ │ ├── MultipartEncoder.java │ │ │ │ ├── ProtoBufCodec.java │ │ │ │ ├── RequestContentImpl.java │ │ │ │ ├── ResponseContentImpl.java │ │ │ │ └── StringCodec.java │ │ │ ├── exec │ │ │ ├── InvocationChain.java │ │ │ ├── InvocationChainImpl.java │ │ │ ├── RestInterceptor.java │ │ │ ├── RestRequestExecutor.java │ │ │ └── RestRequestExecutorImpl.java │ │ │ ├── spi │ │ │ ├── DecodeAdviceFactory.java │ │ │ ├── DecoderFactory.java │ │ │ ├── EncodeAdviceFactory.java │ │ │ ├── EncoderFactory.java │ │ │ ├── RestInterceptorFactory.java │ │ │ └── impl │ │ │ │ ├── InternalDecoderFactory.java │ │ │ │ └── InternalEncoderFactory.java │ │ │ └── utils │ │ │ ├── Constants.java │ │ │ ├── CookiesUtil.java │ │ │ └── GenericsUtil.java │ └── resources │ │ └── META-INF │ │ └── esa │ │ └── internal │ │ ├── io.esastack.restclient.spi.DecoderFactory │ │ └── io.esastack.restclient.spi.EncoderFactory │ └── test │ └── java │ └── io │ └── esastack │ └── restclient │ ├── ContentTest.java │ ├── RequestMockUtil.java │ ├── RequestTransceiverTest.java │ ├── RestClientBuilderTest.java │ ├── RestClientTest.java │ ├── RestCompositeRequestTest.java │ ├── RestResponseBaseImplTest.java │ ├── codec │ ├── ByteToByteCodecTest.java │ ├── CodecAdviceTest.java │ ├── FastJsonCodecTest.java │ ├── FileToFileEncoderTest.java │ ├── FormURLEncodedEncoderTest.java │ ├── GsonCodecTest.java │ ├── JacksonCodecTest.java │ ├── MultipartToMultipartEncoderTest.java │ ├── Person.java │ ├── ProtoBufCodecTest.java │ └── StringCodecTest.java │ ├── exec │ └── RestRequestExecutorTest.java │ └── it │ ├── CodecTest.java │ ├── FileRequestTest.java │ ├── MockServerUtil.java │ ├── MultipartRequestTest.java │ └── RequestMethodsTest.java └── site ├── .nvmrc ├── README.md ├── assets ├── icons │ └── logo.svg └── scss │ └── _variables_project.scss ├── config.toml ├── content └── en │ ├── _index.html │ ├── blog │ ├── _index.md │ ├── architecture │ │ ├── _index.md │ │ └── esa_restclient_architecture.md │ └── releases │ │ ├── _index.md │ │ ├── v0.1.0.md │ │ ├── v1.0.0.md │ │ └── v1.0.1.md │ ├── docs-v0.1.0 │ ├── _index.md │ ├── connection_pool_config │ │ └── _index.md │ ├── customize_handle │ │ └── _index.md │ ├── dns_ext │ │ └── _index.md │ ├── file_upload_download │ │ └── _index.md │ ├── filter │ │ ├── _index.md │ │ └── useages.md │ ├── getting_started │ │ └── _index.md │ ├── interceptor │ │ ├── _index.md │ │ ├── embedded_interceptors.md │ │ └── useages.md │ ├── metrics │ │ └── _index.md │ └── segemented_read_write │ │ └── _index.md │ ├── docs-v1.0.1 │ ├── _index.md │ ├── codec │ │ ├── _index.md │ │ ├── decoder.md │ │ └── encoder.md │ ├── connection_pool_config │ │ └── _index.md │ ├── dns_ext │ │ └── _index.md │ ├── file_upload_download │ │ └── _index.md │ ├── getting_started │ │ └── _index.md │ ├── interceptor │ │ └── _index.md │ ├── metrics │ │ └── _index.md │ ├── other_config │ │ ├── _index.md │ │ ├── expect_continue.md │ │ ├── read_timeout.md │ │ ├── redirect.md │ │ └── retry.md │ └── process_of_restclient │ │ └── _index.md │ ├── docs │ ├── _index.md │ ├── codec │ │ ├── _index.md │ │ ├── decoder.md │ │ └── encoder.md │ ├── connection_pool_config │ │ └── _index.md │ ├── dns_ext │ │ └── _index.md │ ├── file_upload_download │ │ └── _index.md │ ├── getting_started │ │ └── _index.md │ ├── interceptor │ │ └── _index.md │ ├── metrics │ │ └── _index.md │ ├── other_config │ │ ├── _index.md │ │ ├── expect_continue.md │ │ ├── read_timeout.md │ │ ├── redirect.md │ │ └── retry.md │ ├── process_of_restclient │ │ └── _index.md │ └── traffic_split │ │ └── _index.md │ ├── featured-background.jpg │ ├── img │ ├── architecture │ │ ├── arc.png │ │ ├── decode_advice.png │ │ ├── decoder.png │ │ ├── encode_advice.png │ │ ├── encoder.png │ │ ├── esa_stack.png │ │ ├── fast_thread_local.png │ │ ├── init_netty_transceiver.png │ │ ├── interceptor.png │ │ ├── netty_transceiver.png │ │ ├── optimized_arch.png │ │ ├── optimized_thread_model.png │ │ ├── perf.png │ │ ├── receive_data.png │ │ ├── send_request.png │ │ ├── thread_local.png │ │ └── thread_model.png │ ├── conf.png │ ├── ping_result.png │ └── process_of_restclient.svg │ └── search.md ├── layouts ├── 404.html ├── docs-v0.1.0 │ ├── baseof.html │ ├── baseof.print.html │ ├── list.html │ ├── list.print.html │ └── single.html ├── docs-v1.0.1 │ ├── baseof.html │ ├── baseof.print.html │ ├── list.html │ ├── list.print.html │ └── single.html ├── docs │ └── baseof.html └── partials │ ├── navbar-docs.html │ └── navbar.html ├── package-lock.json ├── package.json └── static └── favicons ├── android-144x144.png ├── android-192x192.png ├── android-36x36.png ├── android-48x48.png ├── android-72x72.png ├── android-96x96.png ├── apple-touch-icon.png ├── favicon-128x128.png ├── favicon-16x16.png ├── favicon-256x256.png ├── favicon-32x32.png ├── favicon-48x48.png ├── favicon-64x64.png ├── favicon-96x96.png ├── favicon.ico ├── tile150x150.png ├── tile310x150.png ├── tile310x310.png └── tile70x70.png /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Expected behavior 11 | 12 | ### Actual behavior 13 | 14 | ### Steps to reproduce 15 | 16 | ### Env 17 | - HttpClient version: 18 | - JVM version: 19 | - OS: 20 | -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yaml: -------------------------------------------------------------------------------- 1 | name: github pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - main # Set a branch to deploy 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-18.04 10 | defaults: 11 | run: 12 | working-directory: ./site 13 | steps: 14 | - uses: actions/checkout@v2 15 | with: 16 | submodules: recursive # Fetch the Docsy theme 17 | fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod 18 | 19 | - name: Setup Hugo 20 | uses: peaceiris/actions-hugo@v2 21 | with: 22 | hugo-version: '0.92.2' 23 | extended: true 24 | 25 | - name: Setup Node 26 | uses: actions/setup-node@v1 27 | with: 28 | node-version: '12.x' 29 | 30 | - name: Cache dependencies 31 | uses: actions/cache@v1 32 | with: 33 | path: ~/.npm 34 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 35 | restore-keys: | 36 | ${{ runner.os }}-node- 37 | - run: npm ci 38 | - run: hugo 39 | env: 40 | HUGO_ENV: production 41 | 42 | - name: Deploy 43 | uses: peaceiris/actions-gh-pages@v3 44 | with: 45 | github_token: ${{ secrets.GITHUB_TOKEN }} 46 | publish_branch: gh-pages 47 | publish_dir: site/public 48 | cname: restclient.esastack.io 49 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 3 | 4 | name: Build 5 | 6 | on: 7 | push: 8 | branches-ignore: 9 | - '**-alpha' 10 | - '**-tmp' 11 | - '**-temp' 12 | pull_request: 13 | branches-ignore: 14 | - '**-alpha' 15 | - '**-tmp' 16 | - '**-temp' 17 | workflow_dispatch: 18 | inputs: 19 | profiles: 20 | description: 'mvn -P ' 21 | required: false 22 | default: '' 23 | 24 | jobs: 25 | build: 26 | 27 | runs-on: ubuntu-latest 28 | 29 | steps: 30 | - uses: actions/checkout@v2 31 | - name: Set up JDK 1.8 32 | uses: actions/setup-java@v1 33 | with: 34 | java-version: 1.8 35 | - name: Clean and Package 36 | if: github.event.inputs.profiles == '' 37 | run: mvn clean package 38 | - name: Clean and Package With Profiles 39 | if: github.event.inputs.profiles != '' 40 | run: mvn -P ${{ github.event.inputs.profiles }} clean package 41 | - name: Upload coverage to Codecov 42 | if: github.event_name == 'push' 43 | uses: codecov/codecov-action@v1.0.15 44 | with: 45 | token: ${{secrets.CODECOV_TOKEN}} 46 | 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # maven ignore 2 | target/ 3 | *.jar 4 | # enable mvnw 5 | !.mvn/wrapper/* 6 | *.war 7 | *.zip 8 | *.tar 9 | *.tar.gz 10 | 11 | # eclipse ignore 12 | .settings/ 13 | .project 14 | .classpath 15 | 16 | # idea ignore 17 | .idea/ 18 | *.ipr 19 | *.iml 20 | *.iws 21 | 22 | # vscode files 23 | .vscode/ 24 | *.factorypath 25 | 26 | # temp ignore 27 | *.log 28 | *.cache 29 | *.diff 30 | *.patch 31 | *.tmp 32 | 33 | # system ignore 34 | .DS_Store 35 | Thumbs.db 36 | 37 | logs/ 38 | tmp/ 39 | dependency-reduced-pom.xml 40 | 41 | # site resources 42 | site/public/ 43 | site/resources/ 44 | site/node_modules/ 45 | site/themes/ 46 | .hugo_build.lock -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "site/themes/docsy"] 2 | path = site/themes/docsy 3 | url = https://github.com/google/docsy 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. 4 | 5 | ## Submitting a pull request 6 | 7 | 1. [Fork][fork] and clone the repository 8 | 2. Create a new branch: `git checkout -b my-branch-name` 9 | 3. Make your change and remember to add tests 10 | 4. Build the project locally and run local tests 11 | 5. Push to your fork and [submit a pull request][pr] 12 | 6. Pat your self on the back and wait for your pull request to be reviewed and merged. 13 | 14 | Thanks for your contributing! 15 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/ContextKeys.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core; 17 | 18 | import esa.commons.collection.AttributeKey; 19 | import io.esastack.httpclient.core.filter.FilterContext; 20 | 21 | public final class ContextKeys { 22 | 23 | public static final AttributeKey 24 | FILTER_CONTEXT_KEY = AttributeKey.valueOf("$filterContext"); 25 | 26 | private ContextKeys() { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/HttpMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core; 17 | 18 | import io.esastack.commons.net.http.HttpHeaders; 19 | import io.esastack.commons.net.http.HttpVersion; 20 | 21 | public interface HttpMessage { 22 | 23 | int status(); 24 | 25 | HttpVersion version(); 26 | 27 | HttpHeaders headers(); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/HttpResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core; 17 | 18 | import io.esastack.commons.net.buffer.Buffer; 19 | 20 | public interface HttpResponse extends Response { 21 | 22 | /** 23 | * Obtains body as {@link Buffer} format. 24 | * 25 | * @return body 26 | */ 27 | Buffer body(); 28 | 29 | /** 30 | * The flag indicates current response should be automatically aggregated or not. 31 | * Be aware that, the result is {@code false} which means that you have specified a {@link Handle} 32 | * or {@link Handler} to handle the inbound message and so that the {@link #body()} may be 33 | * an empty buffer otherwise you have wrote some content while handling inbound message 34 | * by {@link Handle} or {@link Handler}. On the contrary, if the result is {@code true} which 35 | * means the {@link #body()} contains the fully response's content. 36 | * 37 | * @return {@code true} or {@code false} 38 | */ 39 | boolean aggregated(); 40 | 41 | } 42 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/Identifiable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core; 17 | 18 | @FunctionalInterface 19 | public interface Identifiable { 20 | 21 | /** 22 | * Obtains the id of current component. 23 | * 24 | * @return id 25 | */ 26 | String id(); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/IdentityFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core; 17 | 18 | @FunctionalInterface 19 | public interface IdentityFactory { 20 | 21 | /** 22 | * Generates a {@link Identified} of {@code value}. 23 | * 24 | * @param value origin value 25 | * @return identified 26 | */ 27 | Identified generate(T value); 28 | 29 | class Identified implements Identifiable { 30 | 31 | private final T origin; 32 | private final String id; 33 | 34 | public Identified(T origin, String id) { 35 | this.origin = origin; 36 | this.id = id; 37 | } 38 | 39 | public T origin() { 40 | return origin; 41 | } 42 | 43 | @Override 44 | public String id() { 45 | return id; 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/Multipart.java: -------------------------------------------------------------------------------- 1 | package io.esastack.httpclient.core; 2 | 3 | import esa.commons.collection.MultiValueMap; 4 | 5 | import java.util.List; 6 | 7 | public interface Multipart { 8 | 9 | MultiValueMap attrs(); 10 | 11 | List files(); 12 | 13 | boolean multipartEncode(); 14 | } 15 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/MultipartBody.java: -------------------------------------------------------------------------------- 1 | package io.esastack.httpclient.core; 2 | 3 | public interface MultipartBody extends Multipart, MultipartConfigure, Reusable { 4 | MultipartBody multipartEncode(boolean multipartEncode); 5 | } 6 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/MultipartConfigure.java: -------------------------------------------------------------------------------- 1 | package io.esastack.httpclient.core; 2 | 3 | import esa.commons.collection.MultiValueMap; 4 | 5 | import java.io.File; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | public interface MultipartConfigure { 10 | 11 | MultipartConfigure attr(String name, String value); 12 | 13 | MultipartConfigure attrs(Map attrMap); 14 | 15 | MultipartConfigure attrs(MultiValueMap values); 16 | 17 | MultipartConfigure file(String name, File file); 18 | 19 | MultipartConfigure file(String name, File file, String contentType); 20 | 21 | MultipartConfigure file(String name, File file, String contentType, boolean isText); 22 | 23 | MultipartConfigure file(String name, String filename, File file, String contentType, boolean isText); 24 | 25 | MultipartConfigure files(List files); 26 | } 27 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/NoopListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core; 17 | 18 | public class NoopListener implements Listener { 19 | 20 | public static final Listener INSTANCE = new NoopListener(); 21 | 22 | private NoopListener() { 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/Request.java: -------------------------------------------------------------------------------- 1 | package io.esastack.httpclient.core; 2 | 3 | import io.esastack.commons.net.http.HttpHeaders; 4 | import io.esastack.commons.net.http.HttpMethod; 5 | 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | public interface Request { 11 | HttpMethod method(); 12 | 13 | String scheme(); 14 | 15 | String path(); 16 | 17 | HttpUri uri(); 18 | 19 | Request addParam(String name, String value); 20 | 21 | Request addParams(Map params); 22 | 23 | String getParam(String name); 24 | 25 | /** 26 | * Obtains unmodifiable param values by specified {@code name}. 27 | * 28 | * @param name name 29 | * @return value 30 | */ 31 | List getParams(String name); 32 | 33 | /** 34 | * Obtains unmodifiable parameter names. 35 | * 36 | * @return names 37 | */ 38 | Set paramNames(); 39 | 40 | HttpHeaders headers(); 41 | 42 | Request addHeader(CharSequence name, CharSequence value); 43 | 44 | Request addHeaders(Map headers); 45 | 46 | CharSequence getHeader(CharSequence name); 47 | 48 | Request setHeader(CharSequence name, CharSequence value); 49 | 50 | Request removeHeader(CharSequence name); 51 | 52 | /** 53 | * Whether allow uri encode or not 54 | * 55 | * @return true or false 56 | */ 57 | boolean uriEncode(); 58 | 59 | /** 60 | * The readTimeout of current request 61 | * 62 | * @return readTimeout 63 | */ 64 | long readTimeout(); 65 | 66 | Context context(); 67 | } 68 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/RequestBaseConfigure.java: -------------------------------------------------------------------------------- 1 | package io.esastack.httpclient.core; 2 | 3 | public interface RequestBaseConfigure { 4 | 5 | RequestBaseConfigure enableUriEncode(); 6 | 7 | RequestBaseConfigure disableExpectContinue(); 8 | 9 | RequestBaseConfigure maxRedirects(int maxRedirects); 10 | 11 | RequestBaseConfigure maxRetries(int maxRetries); 12 | 13 | RequestBaseConfigure readTimeout(long readTimeout); 14 | } 15 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/Response.java: -------------------------------------------------------------------------------- 1 | package io.esastack.httpclient.core; 2 | 3 | import io.esastack.commons.net.http.HttpHeaders; 4 | 5 | public interface Response extends HttpMessage { 6 | 7 | 8 | /** 9 | * Obtains {@link HttpHeaders} of trailing. 10 | * 11 | * @return headers 12 | */ 13 | HttpHeaders trailers(); 14 | } 15 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/Reusable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core; 17 | 18 | public interface Reusable { 19 | 20 | /** 21 | * Obtains a copy of current {@code T}. 22 | * 23 | * @return t 24 | */ 25 | T copy(); 26 | 27 | /** 28 | * Obtains a copy of specified {@code source}. 29 | * 30 | * @param source source 31 | * @param generic type 32 | * @return copied instance 33 | */ 34 | static M copyOf(Reusable source) { 35 | return source == null ? null : source.copy(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/Scheme.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core; 17 | 18 | import esa.commons.annotation.Internal; 19 | 20 | @Internal 21 | public enum Scheme { 22 | 23 | /** 24 | * Http 25 | */ 26 | HTTP(80, "http"), 27 | 28 | /** 29 | * Https 30 | */ 31 | HTTPS(443, "https"); 32 | 33 | private final int port; 34 | private final String name; 35 | 36 | Scheme(int port, String name) { 37 | this.port = port; 38 | this.name = name; 39 | } 40 | 41 | public int port() { 42 | return port; 43 | } 44 | 45 | public String name0() { 46 | return name; 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/config/Decompression.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.config; 17 | 18 | public enum Decompression { 19 | 20 | /** 21 | * deflate 22 | */ 23 | DEFLATE("deflate"), 24 | 25 | /** 26 | * gzip 27 | */ 28 | GZIP("gzip"), 29 | 30 | /** 31 | * gzip,deflate 32 | */ 33 | GZIP_DEFLATE("gzip,deflate"); 34 | 35 | String format; 36 | 37 | Decompression(String format) { 38 | this.format = format; 39 | } 40 | 41 | public String format() { 42 | return format; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/exception/ClosedConnectionException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.exception; 17 | 18 | import java.io.IOException; 19 | 20 | public class ClosedConnectionException extends IOException { 21 | 22 | private static final long serialVersionUID = -7491330351921922628L; 23 | 24 | public ClosedConnectionException(String msg) { 25 | super(msg); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/exception/ClosedStreamException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.exception; 17 | 18 | import java.io.IOException; 19 | 20 | public class ClosedStreamException extends IOException { 21 | 22 | public static final ClosedStreamException CAUSED_BY_RST = 23 | new ClosedStreamException("Received reset stream"); 24 | 25 | public static final ClosedStreamException CAUSED_BY_REMOVED = 26 | new ClosedStreamException("Stream has been removed, maybe the server has closed."); 27 | 28 | private static final long serialVersionUID = -7491330351921922628L; 29 | 30 | public ClosedStreamException(String msg) { 31 | super(msg); 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/exception/ContentOverSizedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.exception; 17 | 18 | public class ContentOverSizedException extends RuntimeException { 19 | 20 | private static final long serialVersionUID = -5806571404452221724L; 21 | 22 | public ContentOverSizedException(String msg) { 23 | super(msg); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/exception/ProtocolException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.exception; 17 | 18 | public class ProtocolException extends RuntimeException { 19 | 20 | private static final long serialVersionUID = 7344985455362038300L; 21 | 22 | public ProtocolException(String msg, Throwable cause) { 23 | super(msg, cause); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/exception/RedirectException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.exception; 17 | 18 | public class RedirectException extends RuntimeException { 19 | 20 | private static final long serialVersionUID = -6651717069116695990L; 21 | 22 | public RedirectException(String msg, Throwable cause) { 23 | super(msg, cause); 24 | } 25 | 26 | public RedirectException(String msg) { 27 | super(msg); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/exception/RetryException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.exception; 17 | 18 | public class RetryException extends RuntimeException { 19 | 20 | private static final long serialVersionUID = -4549866499436427795L; 21 | 22 | public RetryException(String msg, Throwable cause) { 23 | super(msg, cause); 24 | } 25 | 26 | public RetryException(String msg) { 27 | super(msg); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/exec/ExecChain.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.exec; 17 | 18 | import esa.commons.annotation.Internal; 19 | import io.esastack.httpclient.core.Context; 20 | import io.esastack.httpclient.core.HttpRequest; 21 | import io.esastack.httpclient.core.HttpResponse; 22 | 23 | import java.util.concurrent.CompletableFuture; 24 | 25 | /** 26 | * This chain is designed for {@link Interceptor}s to modify or replace {@link HttpRequest} 27 | * and {@link HttpResponse} around {@link #proceed(HttpRequest)}ing. User can do retry, redirect, 28 | * cache and so on by this. 29 | */ 30 | @Internal 31 | public interface ExecChain { 32 | 33 | /** 34 | * Obtains the {@link Context} associated with current chain. 35 | * 36 | * @return ctx 37 | */ 38 | Context ctx(); 39 | 40 | /** 41 | * Proceeds {@link HttpRequest} and obtains asynchronous result. 42 | * 43 | * @param request request 44 | * @return response 45 | */ 46 | CompletableFuture proceed(HttpRequest request); 47 | 48 | } 49 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/exec/HttpTransceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.exec; 17 | 18 | import io.esastack.httpclient.core.Handle; 19 | import io.esastack.httpclient.core.Handler; 20 | import io.esastack.httpclient.core.HttpRequest; 21 | import io.esastack.httpclient.core.HttpResponse; 22 | 23 | import java.util.concurrent.CompletableFuture; 24 | 25 | /** 26 | * The core transceiver which can transform and write the given {@link HttpRequest} to network and 27 | * then aggregate the inbound messages to the {@link HttpResponse} or handle those messages by custom 28 | * {@link Handle} or {@link Handler}. 29 | */ 30 | public interface HttpTransceiver { 31 | 32 | /** 33 | * Sends the given {@code request} and obtains the corresponding {@link HttpResponse}. 34 | * 35 | * @param request request 36 | * @param execCtx ctx 37 | * @return response 38 | */ 39 | CompletableFuture handle(HttpRequest request, ExecContext execCtx); 40 | 41 | } 42 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/exec/RequestExecutor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.exec; 17 | 18 | import esa.commons.annotation.Internal; 19 | import io.esastack.httpclient.core.HttpRequest; 20 | import io.esastack.httpclient.core.HttpResponse; 21 | 22 | import java.util.concurrent.CompletableFuture; 23 | 24 | /** 25 | * A {@link RequestExecutor} is used to send a {@link HttpRequest} and get the corresponding {@link HttpResponse} 26 | * asynchronously. 27 | */ 28 | @Internal 29 | public interface RequestExecutor { 30 | 31 | /** 32 | * Sends the {@link HttpRequest} and obtains asynchronous {@link HttpResponse}. 33 | * 34 | * @param request request 35 | * @param ctx ctx 36 | * @return response 37 | */ 38 | CompletableFuture execute(HttpRequest request, ExecContext ctx); 39 | } 40 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/exec/RetryPredicate.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.exec; 17 | 18 | import io.esastack.httpclient.core.Context; 19 | import io.esastack.httpclient.core.HttpRequest; 20 | import io.esastack.httpclient.core.HttpResponse; 21 | 22 | @FunctionalInterface 23 | public interface RetryPredicate { 24 | 25 | /** 26 | * Whether to retry specified {@link HttpRequest} when {@code throwable} caught. 27 | * 28 | * @param request request, must not be null 29 | * @param response response, may be null 30 | * @param ctx ctx, must be null 31 | * @param cause cause, may be null 32 | * @return retry or not 33 | */ 34 | boolean canRetry(HttpRequest request, HttpResponse response, Context ctx, Throwable cause); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/filter/DuplexFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.filter; 17 | 18 | /** 19 | * This is a composite filter of {@link RequestFilter} and {@link ResponseFilter}. 20 | */ 21 | public interface DuplexFilter extends RequestFilter, ResponseFilter { 22 | } 23 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/filter/FilterContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.filter; 17 | 18 | import esa.commons.Checks; 19 | import esa.commons.collection.AttributeMap; 20 | import esa.commons.collection.Attributes; 21 | import io.esastack.httpclient.core.Context; 22 | 23 | public class FilterContext { 24 | 25 | private final Context parent; 26 | private final Attributes attrs = new AttributeMap(8); 27 | 28 | public FilterContext(Context parent) { 29 | Checks.checkNotNull(parent, "parent"); 30 | this.parent = parent; 31 | } 32 | 33 | public Context parent() { 34 | return parent; 35 | } 36 | 37 | public Attributes attrs() { 38 | return attrs; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/metrics/CallbackExecutorMetric.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.metrics; 17 | 18 | public interface CallbackExecutorMetric { 19 | 20 | int coreSize(); 21 | 22 | int maxSize(); 23 | 24 | /** 25 | * Obtains keep alive seconds of internal thread. 26 | * 27 | * @return keep alive seconds 28 | */ 29 | long keepAliveSeconds(); 30 | 31 | int activeCount(); 32 | 33 | int poolSize(); 34 | 35 | int largestPoolSize(); 36 | 37 | long taskCount(); 38 | 39 | int queueSize(); 40 | 41 | long completedTaskCount(); 42 | 43 | String executorId(); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/metrics/ConnectionPoolMetric.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.metrics; 17 | 18 | import io.esastack.httpclient.core.config.ChannelPoolOptions; 19 | 20 | public interface ConnectionPoolMetric { 21 | 22 | int maxSize(); 23 | 24 | int maxPendingAcquires(); 25 | 26 | int active(); 27 | 28 | int pendingAcquireCount(); 29 | 30 | ChannelPoolOptions options(); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/metrics/ConnectionPoolMetricProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.metrics; 17 | 18 | import java.net.SocketAddress; 19 | import java.util.Map; 20 | 21 | public interface ConnectionPoolMetricProvider { 22 | 23 | /** 24 | * Obtains all {@link ConnectionPoolMetric}s 25 | * 26 | * @return metrics, must be not null 27 | */ 28 | Map all(); 29 | 30 | /** 31 | * Obtains {@link ConnectionPoolMetric} of specified {@link SocketAddress} 32 | * 33 | * @param address address 34 | * @return metric 35 | */ 36 | default ConnectionPoolMetric get(SocketAddress address) { 37 | return all().get(address); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/metrics/IoThreadGroupMetric.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.metrics; 17 | 18 | import java.util.List; 19 | 20 | public interface IoThreadGroupMetric { 21 | 22 | boolean isShutdown(); 23 | 24 | boolean isTerminated(); 25 | 26 | List childExecutors(); 27 | 28 | String groupId(); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/metrics/IoThreadMetric.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.metrics; 17 | 18 | public interface IoThreadMetric { 19 | 20 | int pendingTasks(); 21 | 22 | int maxPendingTasks(); 23 | 24 | int ioRatio(); 25 | 26 | String name(); 27 | 28 | int priority(); 29 | 30 | String state(); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/metrics/MetricPoint.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.metrics; 17 | 18 | public interface MetricPoint { 19 | 20 | ConnectionPoolMetricProvider connectionPoolMetric(); 21 | 22 | IoThreadGroupMetric ioThreadsMetric(); 23 | 24 | CallbackExecutorMetric callbackExecutorMetric(); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/netty/ChannelPool.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.netty; 17 | 18 | import esa.commons.Checks; 19 | import io.esastack.httpclient.core.config.ChannelPoolOptions; 20 | 21 | final class ChannelPool { 22 | 23 | final boolean ssl; 24 | final io.netty.channel.pool.ChannelPool underlying; 25 | final ChannelPoolOptions options; 26 | 27 | ChannelPool(boolean ssl, io.netty.channel.pool.ChannelPool underlying, ChannelPoolOptions options) { 28 | Checks.checkNotNull(underlying, "underlying"); 29 | Checks.checkNotNull(options, "options"); 30 | this.ssl = ssl; 31 | this.underlying = underlying; 32 | this.options = options; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/netty/NettyClientConfigure.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.netty; 17 | 18 | import esa.commons.annotation.Internal; 19 | import io.netty.bootstrap.Bootstrap; 20 | import io.netty.channel.Channel; 21 | 22 | import java.net.SocketAddress; 23 | 24 | @Internal 25 | public interface NettyClientConfigure { 26 | 27 | /** 28 | * Callback after the creation of {@link Bootstrap}. 29 | * 30 | * @param address address 31 | * @param bootstrap bootstrap 32 | */ 33 | void onBootstrapCreated(SocketAddress address, Bootstrap bootstrap); 34 | 35 | /** 36 | * Callback after the creation of {@link Channel}. 37 | * 38 | * @param channel channel 39 | */ 40 | void onChannelCreated(Channel channel); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/netty/NettyClientConfigureImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.netty; 17 | 18 | import esa.commons.spi.SpiLoader; 19 | import io.netty.bootstrap.Bootstrap; 20 | import io.netty.channel.Channel; 21 | 22 | import java.net.SocketAddress; 23 | import java.util.List; 24 | 25 | class NettyClientConfigureImpl implements NettyClientConfigure { 26 | 27 | private static final List CONFIGURES = SpiLoader.getAll(NettyClientConfigure.class); 28 | 29 | @Override 30 | public void onBootstrapCreated(SocketAddress address, Bootstrap bootstrap) { 31 | CONFIGURES.forEach(configure -> configure.onBootstrapCreated(address, bootstrap)); 32 | } 33 | 34 | @Override 35 | public void onChannelCreated(Channel channel) { 36 | CONFIGURES.forEach(configure -> configure.onChannelCreated(channel)); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/netty/SslEngineFactoryImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.netty; 17 | 18 | import esa.commons.Checks; 19 | import io.esastack.httpclient.core.config.SslOptions; 20 | import io.esastack.httpclient.core.spi.SslEngineFactory; 21 | import io.netty.buffer.ByteBufAllocator; 22 | import io.netty.handler.ssl.SslContext; 23 | import io.netty.util.ReferenceCountUtil; 24 | 25 | import javax.net.ssl.SSLEngine; 26 | 27 | class SslEngineFactoryImpl implements SslEngineFactory { 28 | 29 | private final SslContext sslContext; 30 | 31 | SslEngineFactoryImpl(SslContext sslContext) { 32 | Checks.checkNotNull(sslContext, "sslContext"); 33 | this.sslContext = sslContext; 34 | } 35 | 36 | @Override 37 | public SSLEngine create(SslOptions options, String peerHost, int peerPort) { 38 | return sslContext.newEngine(ByteBufAllocator.DEFAULT, peerHost, peerPort); 39 | } 40 | 41 | @Override 42 | public void onDestroy() { 43 | ReferenceCountUtil.safeRelease(sslContext); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/resolver/HostResolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.resolver; 17 | 18 | import java.io.Closeable; 19 | import java.net.InetAddress; 20 | import java.util.concurrent.CompletionStage; 21 | 22 | /** 23 | * This class is designed to resolve given host to detailed ips. eg: localhost : 127.0.0.1 24 | */ 25 | public interface HostResolver extends Closeable { 26 | 27 | /** 28 | * Resolves the {@code inetHost} to {@link InetAddress} asynchronously. The resolved {@link InetAddress} will be 29 | * used while connecting remote host. 30 | * 31 | * @param inetHost host 32 | * @return address 33 | */ 34 | CompletionStage resolve(String inetHost); 35 | 36 | /** 37 | * Closes the {@link HostResolver}. 38 | */ 39 | @Override 40 | default void close() { 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/resolver/SystemDefaultResolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.resolver; 17 | 18 | import io.esastack.httpclient.core.util.Futures; 19 | 20 | import java.net.InetAddress; 21 | import java.security.AccessController; 22 | import java.security.PrivilegedExceptionAction; 23 | import java.util.Arrays; 24 | import java.util.List; 25 | import java.util.concurrent.CompletableFuture; 26 | 27 | /** 28 | * The default implementation of {@link HostResolver} which use {@link InetAddress#getAllByName(String)} to get 29 | * ips by host name. 30 | */ 31 | public class SystemDefaultResolver extends BalancedHostResolver { 32 | 33 | @Override 34 | protected CompletableFuture> resolveAll(String inetHost) { 35 | try { 36 | return Futures.completed(Arrays.asList(AccessController.doPrivileged( 37 | (PrivilegedExceptionAction) () -> InetAddress.getAllByName(inetHost)))); 38 | } catch (Throwable th) { 39 | return Futures.completed(th); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/spi/ChannelPoolOptionsProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.spi; 17 | 18 | import io.esastack.httpclient.core.config.ChannelPoolOptions; 19 | 20 | import java.net.SocketAddress; 21 | 22 | @FunctionalInterface 23 | public interface ChannelPoolOptionsProvider { 24 | 25 | /** 26 | * Obtains {@link ChannelPoolOptions} by key. 27 | * 28 | * @param key key 29 | * @return options 30 | */ 31 | ChannelPoolOptions get(SocketAddress key); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/spi/DuplexFilterFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.spi; 17 | 18 | import io.esastack.httpclient.core.filter.DuplexFilter; 19 | 20 | import java.util.Collection; 21 | 22 | public interface DuplexFilterFactory { 23 | 24 | DuplexFilterFactory DEFAULT = new DuplexFilterFactoryImpl(); 25 | 26 | /** 27 | * Obtains {@link DuplexFilter}s. 28 | * 29 | * @return request filters 30 | */ 31 | Collection filters(); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/spi/DuplexFilterFactoryImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.spi; 17 | 18 | import esa.commons.spi.SpiLoader; 19 | import io.esastack.httpclient.core.filter.DuplexFilter; 20 | 21 | import java.util.Collection; 22 | import java.util.Collections; 23 | import java.util.List; 24 | 25 | class DuplexFilterFactoryImpl implements DuplexFilterFactory { 26 | 27 | @Override 28 | public Collection filters() { 29 | List filters = SpiLoader.getAll(DuplexFilter.class); 30 | return filters == null ? Collections.emptyList() : Collections.unmodifiableList(filters); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/spi/InterceptorFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.spi; 17 | 18 | import io.esastack.httpclient.core.exec.Interceptor; 19 | 20 | import java.util.Collection; 21 | 22 | public interface InterceptorFactory { 23 | 24 | InterceptorFactory DEFAULT = new InterceptorFactoryImpl(); 25 | 26 | /** 27 | * Obtains {@link Interceptor}s. 28 | * 29 | * @return interceptors 30 | */ 31 | Collection interceptors(); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/spi/InterceptorFactoryImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.spi; 17 | 18 | import esa.commons.spi.SpiLoader; 19 | import io.esastack.httpclient.core.exec.Interceptor; 20 | 21 | import java.util.Collection; 22 | import java.util.Collections; 23 | import java.util.List; 24 | 25 | class InterceptorFactoryImpl implements InterceptorFactory { 26 | 27 | @Override 28 | public Collection interceptors() { 29 | List interceptors = SpiLoader.getAll(Interceptor.class); 30 | return interceptors == null ? Collections.emptyList() : Collections.unmodifiableList(interceptors); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/spi/RequestFilterFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.spi; 17 | 18 | import io.esastack.httpclient.core.filter.RequestFilter; 19 | 20 | import java.util.Collection; 21 | 22 | public interface RequestFilterFactory { 23 | 24 | RequestFilterFactory DEFAULT = new RequestFilterFactoryImpl(); 25 | 26 | /** 27 | * Obtains {@link RequestFilter}s. 28 | * 29 | * @return request filters 30 | */ 31 | Collection filters(); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/spi/RequestFilterFactoryImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.spi; 17 | 18 | import esa.commons.spi.SpiLoader; 19 | import io.esastack.httpclient.core.filter.RequestFilter; 20 | 21 | import java.util.Collection; 22 | import java.util.Collections; 23 | import java.util.List; 24 | 25 | class RequestFilterFactoryImpl implements RequestFilterFactory { 26 | 27 | @Override 28 | public Collection filters() { 29 | List filters = SpiLoader.getAll(RequestFilter.class); 30 | return filters == null ? Collections.emptyList() : Collections.unmodifiableList(filters); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/spi/ResponseFilterFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.spi; 17 | 18 | import io.esastack.httpclient.core.filter.ResponseFilter; 19 | 20 | import java.util.Collection; 21 | 22 | public interface ResponseFilterFactory { 23 | 24 | ResponseFilterFactory DEFAULT = new ResponseFilterFactoryImpl(); 25 | 26 | /** 27 | * Obtains {@link ResponseFilter}s. 28 | * 29 | * @return request filters 30 | */ 31 | Collection filters(); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/spi/ResponseFilterFactoryImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.spi; 17 | 18 | import esa.commons.spi.SpiLoader; 19 | import io.esastack.httpclient.core.filter.ResponseFilter; 20 | 21 | import java.util.Collection; 22 | import java.util.Collections; 23 | import java.util.List; 24 | 25 | class ResponseFilterFactoryImpl implements ResponseFilterFactory { 26 | 27 | @Override 28 | public Collection filters() { 29 | List filters = SpiLoader.getAll(ResponseFilter.class); 30 | return filters == null ? Collections.emptyList() : Collections.unmodifiableList(filters); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/spi/SslEngineFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.spi; 17 | 18 | import io.esastack.httpclient.core.config.SslOptions; 19 | 20 | import javax.net.ssl.SSLEngine; 21 | 22 | public interface SslEngineFactory { 23 | 24 | /** 25 | * Creates a {@link SSLEngine} by given {@code options}, {@code peerHost} and {@code peerPort}. 26 | * 27 | * @param options options 28 | * @param peerHost peerHost 29 | * @param peerPort peerPort 30 | * @return engine 31 | */ 32 | SSLEngine create(SslOptions options, String peerHost, int peerPort); 33 | 34 | /** 35 | * Be informed before destroying. 36 | */ 37 | default void onDestroy() { 38 | 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/util/BufferUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.util; 17 | 18 | import io.esastack.commons.net.buffer.Buffer; 19 | import io.esastack.commons.net.buffer.BufferUtil; 20 | import io.netty.buffer.ByteBuf; 21 | 22 | public class BufferUtils { 23 | 24 | private BufferUtils() { 25 | 26 | } 27 | 28 | public static ByteBuf toByteBuf(Buffer buffer) { 29 | Object unwrap = BufferUtil.unwrap(buffer); 30 | if (unwrap instanceof ByteBuf) { 31 | return (ByteBuf) unwrap; 32 | } 33 | throw new UnsupportedOperationException("The type of unwrap is not ByteBuf! unwrap : " + unwrap); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/util/LoggerUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.util; 17 | 18 | import esa.commons.logging.Logger; 19 | import esa.commons.logging.LoggerFactory; 20 | 21 | public final class LoggerUtils { 22 | 23 | private LoggerUtils() { 24 | } 25 | 26 | private static final Logger LOGGER = LoggerFactory.getLogger("io.esastack.httpclient"); 27 | 28 | public static Logger logger() { 29 | return LOGGER; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/util/Ordered.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.util; 17 | 18 | public interface Ordered { 19 | 20 | /** 21 | * Useful constant for the highest precedence value. 22 | * 23 | * @see java.lang.Integer#MIN_VALUE 24 | */ 25 | int HIGHEST_PRECEDENCE = Integer.MIN_VALUE; 26 | 27 | /** 28 | * Useful constant for the lowest precedence value. 29 | * 30 | * @see java.lang.Integer#MAX_VALUE 31 | */ 32 | int LOWEST_PRECEDENCE = Integer.MAX_VALUE; 33 | 34 | /** 35 | * Default to use the {@link #LOWEST_PRECEDENCE}. 36 | * 37 | * @return order 38 | */ 39 | default int getOrder() { 40 | return LOWEST_PRECEDENCE; 41 | } 42 | 43 | } 44 | 45 | -------------------------------------------------------------------------------- /httpclient-core/src/main/java/io/esastack/httpclient/core/util/OrderedComparator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.util; 17 | 18 | import java.util.Comparator; 19 | import java.util.List; 20 | 21 | public final class OrderedComparator implements Comparator { 22 | 23 | private static final OrderedComparator INSTANCE = new OrderedComparator(); 24 | 25 | public static void sort(List list) { 26 | if (list == null) { 27 | return; 28 | } 29 | if (list.size() > 1) { 30 | list.sort(INSTANCE); 31 | } 32 | } 33 | 34 | @Override 35 | public int compare(Ordered o1, Ordered o2) { 36 | int i1 = getOrder(o1); 37 | int i2 = getOrder(o2); 38 | return Integer.compare(i1, i2); 39 | } 40 | 41 | private static int getOrder(Ordered obj) { 42 | return obj == null ? Ordered.LOWEST_PRECEDENCE : obj.getOrder(); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /httpclient-core/src/main/resources/META-INF/httpclient/HttpClient-Ver.txt: -------------------------------------------------------------------------------- 1 | ${project.version} 2 | -------------------------------------------------------------------------------- /httpclient-core/src/test/java/io/esastack/httpclient/core/ContextTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core; 17 | 18 | import org.junit.jupiter.api.Test; 19 | 20 | import static org.assertj.core.api.Java6BDDAssertions.then; 21 | 22 | class ContextTest { 23 | 24 | @Test 25 | void testBasic() { 26 | final Context ctx = new Context(); 27 | then(ctx.isUseExpectContinue()).isFalse(); 28 | then(ctx.maxRedirects()).isEqualTo(0); 29 | then(ctx.maxRetries()).isEqualTo(0); 30 | 31 | ctx.useExpectContinue(true); 32 | ctx.maxRetries(10); 33 | ctx.maxRedirects(100); 34 | then(ctx.isUseExpectContinue()).isTrue(); 35 | then(ctx.maxRedirects()).isEqualTo(100); 36 | then(ctx.maxRetries()).isEqualTo(10); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /httpclient-core/src/test/java/io/esastack/httpclient/core/ExecContextUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core; 17 | 18 | import esa.commons.annotation.Internal; 19 | import io.esastack.httpclient.core.exec.ExecContext; 20 | import io.esastack.httpclient.core.netty.NettyExecContext; 21 | 22 | /** 23 | * The helper utility for test purpose. 24 | */ 25 | @Internal 26 | public class ExecContextUtil { 27 | 28 | public static ExecContext newAs() { 29 | return new ExecContext(new Context(), NoopListener.INSTANCE, null, null); 30 | } 31 | 32 | public static NettyExecContext newAsNetty() { 33 | return new NettyExecContext(new Context(), NoopListener.INSTANCE, null, null); 34 | } 35 | 36 | public static ExecContext from(Context ctx) { 37 | return new ExecContext(ctx, NoopListener.INSTANCE, null, null); 38 | } 39 | 40 | public static NettyExecContext from(Context ctx, Listener listener) { 41 | return new NettyExecContext(ctx, listener, null, null); 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /httpclient-core/src/test/java/io/esastack/httpclient/core/config/ReusableTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.config; 17 | 18 | import io.esastack.httpclient.core.Reusable; 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.assertj.core.api.BDDAssertions.then; 22 | 23 | class ReusableTest { 24 | 25 | @Test 26 | void testCopyOf() { 27 | then(Reusable.copyOf((CacheOptions) null)).isNull(); 28 | 29 | final CacheOptions options = CacheOptions.ofDefault(); 30 | then(Reusable.copyOf(options)).isNotSameAs(options); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /httpclient-core/src/test/java/io/esastack/httpclient/core/mock/MockContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.mock; 17 | 18 | import io.esastack.httpclient.core.Context; 19 | 20 | public class MockContext extends Context { 21 | 22 | @Override 23 | public void maxRedirects(int maxRedirects) { 24 | this.maxRedirects = maxRedirects; 25 | } 26 | 27 | @Override 28 | public void maxRetries(int maxRetries) { 29 | this.maxRetries = maxRetries; 30 | } 31 | 32 | @Override 33 | public void useExpectContinue(boolean useExpectContinue) { 34 | this.useExpectContinue = useExpectContinue; 35 | } 36 | 37 | public void clear() { 38 | super.attrs().forEach((key, attr) -> attr.set(null)); 39 | useExpectContinue = true; 40 | maxRedirects = 0; 41 | maxRetries = 0; 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /httpclient-core/src/test/java/io/esastack/httpclient/core/mock/MockFilterContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.mock; 17 | 18 | import io.esastack.httpclient.core.Context; 19 | import io.esastack.httpclient.core.filter.FilterContext; 20 | 21 | public class MockFilterContext extends FilterContext { 22 | 23 | public MockFilterContext(Context parent) { 24 | super(parent); 25 | } 26 | 27 | public void clear() { 28 | super.attrs().forEach((key, attr) -> attr.set(null)); 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /httpclient-core/src/test/java/io/esastack/httpclient/core/netty/ChannelPoolTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.netty; 17 | 18 | import io.esastack.httpclient.core.config.ChannelPoolOptions; 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; 22 | import static org.junit.jupiter.api.Assertions.assertThrows; 23 | import static org.mockito.Mockito.mock; 24 | 25 | class ChannelPoolTest { 26 | 27 | @Test 28 | void testConstructor() { 29 | final io.netty.channel.pool.ChannelPool pool = mock(io.netty.channel.pool.ChannelPool.class); 30 | final ChannelPoolOptions options = mock(ChannelPoolOptions.class); 31 | 32 | assertThrows(NullPointerException.class, () -> new ChannelPool(true, null, options)); 33 | assertThrows(NullPointerException.class, () -> new ChannelPool(true, pool, null)); 34 | 35 | assertDoesNotThrow(() -> new ChannelPool(true, pool, options)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /httpclient-core/src/test/java/io/esastack/httpclient/core/netty/DelegatingResolverTest.java: -------------------------------------------------------------------------------- 1 | package io.esastack.httpclient.core.netty; 2 | 3 | import io.netty.util.concurrent.DefaultPromise; 4 | import io.netty.util.concurrent.GlobalEventExecutor; 5 | import io.netty.util.concurrent.Promise; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.net.InetAddress; 9 | import java.net.UnknownHostException; 10 | import java.util.concurrent.CompletableFuture; 11 | import java.util.concurrent.ExecutionException; 12 | 13 | import static org.junit.jupiter.api.Assertions.assertEquals; 14 | import static org.junit.jupiter.api.Assertions.assertThrows; 15 | 16 | class DelegatingResolverTest { 17 | 18 | @Test 19 | void testResolve() throws UnknownHostException, ExecutionException, InterruptedException { 20 | InetAddress inetAddress = InetAddress.getByName("127.0.0.1"); 21 | DelegatingResolver resolver = new DelegatingResolver( 22 | GlobalEventExecutor.INSTANCE, inetHost -> CompletableFuture.completedFuture(inetAddress) 23 | ); 24 | Promise addressPromise = new DefaultPromise<>(GlobalEventExecutor.INSTANCE); 25 | resolver.doResolve("111", addressPromise); 26 | assertEquals(inetAddress, addressPromise.get()); 27 | 28 | assertThrows(UnsupportedOperationException.class, () -> resolver.doResolveAll(null, null)); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /httpclient-core/src/test/java/io/esastack/httpclient/core/netty/ThreadFactoryImplTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.netty; 17 | 18 | import esa.commons.concurrent.NettyInternalThread; 19 | import org.junit.jupiter.api.Test; 20 | 21 | import java.util.concurrent.ThreadFactory; 22 | 23 | import static org.assertj.core.api.Java6BDDAssertions.then; 24 | 25 | class ThreadFactoryImplTest { 26 | 27 | @Test 28 | void testNewThread() { 29 | final String prefix = "HttpClient-Callback"; 30 | 31 | ThreadFactory factory = new ThreadFactoryImpl(prefix, true); 32 | Thread thread = factory.newThread(() -> {}); 33 | then(thread.getName().startsWith("HttpClient-Callback")).isTrue(); 34 | then(thread).isInstanceOf(NettyInternalThread.class); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /httpclient-core/src/test/java/io/esastack/httpclient/core/util/HttpClientVerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.httpclient.core.util; 17 | 18 | import org.junit.jupiter.api.Test; 19 | 20 | import static org.assertj.core.api.BDDAssertions.then; 21 | 22 | class HttpClientVerTest { 23 | 24 | @Test 25 | void testVersion() { 26 | then(HttpClientVer.version()).isNotBlank(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /restclient-ext/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | restclient-parent 20 | io.esastack 21 | 1.0.3-SNAPSHOT 22 | 23 | 4.0.0 24 | 25 | restclient-ext 26 | pom 27 | 28 | traffic-split-interceptor 29 | traffic-split-file-config 30 | 31 | 32 | 33 | 34 | io.esastack 35 | restclient 36 | ${parent.version} 37 | provided 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /restclient-ext/traffic-split-file-config/src/main/resources/META-INF/esa/internal/io.esastack.restclient.ext.spi.RuleSourceFactory: -------------------------------------------------------------------------------- 1 | io.esastack.restclient.ext.rule.FileRuleSourceFactory -------------------------------------------------------------------------------- /restclient-ext/traffic-split-interceptor/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | restclient-ext 20 | io.esastack 21 | 1.0.3-SNAPSHOT 22 | 23 | 4.0.0 24 | 25 | traffic-split-interceptor 26 | 27 | 28 | 8 29 | 8 30 | 31 | 32 | -------------------------------------------------------------------------------- /restclient-ext/traffic-split-interceptor/src/main/java/io/esastack/restclient/ext/TrafficSplitContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.ext; 17 | 18 | import io.esastack.restclient.RestRequest; 19 | import io.esastack.restclient.RestResponse; 20 | 21 | import java.util.concurrent.CompletionStage; 22 | 23 | public interface TrafficSplitContext { 24 | RestRequest request(); 25 | 26 | /** 27 | * Proceed to the next action in the chain.And the final action will proceed next 28 | * {@link io.esastack.restclient.exec.RestInterceptor}. 29 | * 30 | * @return RestResponse 31 | */ 32 | CompletionStage next(); 33 | } 34 | -------------------------------------------------------------------------------- /restclient-ext/traffic-split-interceptor/src/main/java/io/esastack/restclient/ext/action/TrafficSplitAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.ext.action; 17 | 18 | import io.esastack.restclient.RestResponse; 19 | import io.esastack.restclient.ext.TrafficSplitContext; 20 | 21 | import java.util.concurrent.CompletionStage; 22 | 23 | public interface TrafficSplitAction { 24 | 25 | /** 26 | * Do action when request match RedefineRule. 27 | * 28 | * @param context RedefineContext 29 | * @return RestResponse 30 | */ 31 | CompletionStage doAction(TrafficSplitContext context); 32 | } 33 | -------------------------------------------------------------------------------- /restclient-ext/traffic-split-interceptor/src/main/java/io/esastack/restclient/ext/action/impl/RewriteActionConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.ext.action.impl; 17 | 18 | public class RewriteActionConfig { 19 | private String uriAuthority; 20 | private String path; 21 | 22 | public String getUriAuthority() { 23 | return uriAuthority; 24 | } 25 | 26 | public void setUriAuthority(String uriAuthority) { 27 | this.uriAuthority = uriAuthority; 28 | } 29 | 30 | public String getPath() { 31 | return path; 32 | } 33 | 34 | public void setPath(String path) { 35 | this.path = path; 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "RewriteActionConfig{" + 41 | "uriAuthority='" + uriAuthority + '\'' + 42 | ", path='" + path + '\'' + 43 | '}'; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /restclient-ext/traffic-split-interceptor/src/main/java/io/esastack/restclient/ext/condition/TrafficSplitCondition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.ext.condition; 17 | 18 | import io.esastack.restclient.RestRequest; 19 | import io.esastack.restclient.ext.matcher.MatchResult; 20 | 21 | public interface TrafficSplitCondition { 22 | 23 | /** 24 | * @param request RestRequest 25 | * @return MatchResult include whether the request matches. If not, include the reason 26 | * for the mismatch. 27 | */ 28 | MatchResult match(RestRequest request); 29 | } 30 | -------------------------------------------------------------------------------- /restclient-ext/traffic-split-interceptor/src/main/java/io/esastack/restclient/ext/condition/impl/AuthorityCondition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.ext.condition.impl; 17 | 18 | import esa.commons.Checks; 19 | import io.esastack.restclient.RestRequest; 20 | import io.esastack.restclient.ext.condition.TrafficSplitCondition; 21 | import io.esastack.restclient.ext.matcher.MatchResult; 22 | import io.esastack.restclient.ext.matcher.StringMatcher; 23 | 24 | public class AuthorityCondition implements TrafficSplitCondition { 25 | 26 | private final StringMatcher matcher; 27 | 28 | public AuthorityCondition(StringMatcher matcher) { 29 | Checks.checkNotNull(matcher, "matcher"); 30 | this.matcher = matcher; 31 | } 32 | 33 | @Override 34 | public MatchResult match(RestRequest request) { 35 | return matcher.match(request.uri().netURI().getAuthority()); 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "URIAuthorityCondition{" + 41 | "matcher=" + matcher + 42 | '}'; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /restclient-ext/traffic-split-interceptor/src/main/java/io/esastack/restclient/ext/condition/impl/HeaderCondition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.ext.condition.impl; 17 | 18 | import esa.commons.Checks; 19 | import io.esastack.restclient.RestRequest; 20 | import io.esastack.restclient.ext.condition.TrafficSplitCondition; 21 | import io.esastack.restclient.ext.matcher.HeaderMatcher; 22 | import io.esastack.restclient.ext.matcher.MatchResult; 23 | 24 | public class HeaderCondition implements TrafficSplitCondition { 25 | 26 | private final HeaderMatcher matcher; 27 | 28 | public HeaderCondition(HeaderMatcher matcher) { 29 | Checks.checkNotNull(matcher, "matcher"); 30 | this.matcher = matcher; 31 | } 32 | 33 | @Override 34 | public MatchResult match(RestRequest request) { 35 | return matcher.match(request.headers()); 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "HeaderCondition{" + 41 | "matcher=" + matcher + 42 | '}'; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /restclient-ext/traffic-split-interceptor/src/main/java/io/esastack/restclient/ext/condition/impl/ParamCondition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.ext.condition.impl; 17 | 18 | import esa.commons.Checks; 19 | import io.esastack.restclient.RestRequest; 20 | import io.esastack.restclient.ext.condition.TrafficSplitCondition; 21 | import io.esastack.restclient.ext.matcher.MatchResult; 22 | import io.esastack.restclient.ext.matcher.ParamMatcher; 23 | 24 | public class ParamCondition implements TrafficSplitCondition { 25 | 26 | private final ParamMatcher matcher; 27 | 28 | public ParamCondition(ParamMatcher matcher) { 29 | Checks.checkNotNull(matcher, "matcher"); 30 | this.matcher = matcher; 31 | } 32 | 33 | @Override 34 | public MatchResult match(RestRequest request) { 35 | return matcher.match(request); 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "ParamCondition{" + 41 | "matcher=" + matcher + 42 | '}'; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /restclient-ext/traffic-split-interceptor/src/main/java/io/esastack/restclient/ext/condition/impl/PathCondition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.ext.condition.impl; 17 | 18 | import esa.commons.Checks; 19 | import io.esastack.restclient.RestRequest; 20 | import io.esastack.restclient.ext.condition.TrafficSplitCondition; 21 | import io.esastack.restclient.ext.matcher.MatchResult; 22 | import io.esastack.restclient.ext.matcher.StringMatcher; 23 | 24 | public class PathCondition implements TrafficSplitCondition { 25 | private final StringMatcher matcher; 26 | 27 | public PathCondition(StringMatcher matcher) { 28 | Checks.checkNotNull(matcher, "matcher"); 29 | this.matcher = matcher; 30 | } 31 | 32 | @Override 33 | public MatchResult match(RestRequest request) { 34 | return matcher.match(request.path()); 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return "PathCondition{" + 40 | "matcher=" + matcher + 41 | '}'; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /restclient-ext/traffic-split-interceptor/src/main/java/io/esastack/restclient/ext/matcher/HeaderMatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.ext.matcher; 17 | 18 | import io.esastack.commons.net.http.HttpHeaders; 19 | 20 | import java.util.List; 21 | 22 | public class HeaderMatcher { 23 | private List headers; 24 | 25 | public HeaderMatcher(List headers) { 26 | this.headers = headers; 27 | } 28 | 29 | public MatchResult match(HttpHeaders headerMap) { 30 | return KVMatcher.multiMatch(headerMap::get, headers); 31 | } 32 | 33 | public List getHeaders() { 34 | return headers; 35 | } 36 | 37 | public void setHeaders(List headers) { 38 | this.headers = headers; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return "HeaderMatcher{" + 44 | "headers=" + headers + 45 | '}'; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /restclient-ext/traffic-split-interceptor/src/main/java/io/esastack/restclient/ext/matcher/MatchResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.ext.matcher; 17 | 18 | public interface MatchResult { 19 | 20 | boolean isMatch(); 21 | 22 | String unMatchReason(); 23 | 24 | static MatchResult success() { 25 | return MatchResultImpl.SUCCESS_MATCH_RESULT; 26 | } 27 | 28 | static MatchResult fail(String reason) { 29 | return new MatchResultImpl(false, reason); 30 | } 31 | 32 | static MatchResult fail() { 33 | return new MatchResultImpl(false, "Match failed!"); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /restclient-ext/traffic-split-interceptor/src/main/java/io/esastack/restclient/ext/matcher/MatchResultImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.ext.matcher; 17 | 18 | class MatchResultImpl implements MatchResult { 19 | 20 | private final boolean isMatch; 21 | private final String unMatchReason; 22 | static final MatchResult SUCCESS_MATCH_RESULT = new MatchResultImpl(true, null); 23 | 24 | MatchResultImpl(boolean isMatch, String unMatchReason) { 25 | this.isMatch = isMatch; 26 | this.unMatchReason = unMatchReason; 27 | } 28 | 29 | @Override 30 | public boolean isMatch() { 31 | return isMatch; 32 | } 33 | 34 | @Override 35 | public String unMatchReason() { 36 | return unMatchReason; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /restclient-ext/traffic-split-interceptor/src/main/java/io/esastack/restclient/ext/matcher/ParamMatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.ext.matcher; 17 | 18 | import io.esastack.restclient.RestRequest; 19 | 20 | import java.util.List; 21 | 22 | public class ParamMatcher { 23 | private List params; 24 | 25 | public ParamMatcher(List params) { 26 | this.params = params; 27 | } 28 | 29 | public MatchResult match(RestRequest request) { 30 | return KVMatcher.multiMatch(request::getParam, params); 31 | } 32 | 33 | public List getParams() { 34 | return params; 35 | } 36 | 37 | public void setParams(List params) { 38 | this.params = params; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return "ParamMatcher{" + 44 | "params=" + params + 45 | '}'; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /restclient-ext/traffic-split-interceptor/src/main/java/io/esastack/restclient/ext/rule/TrafficSplitRuleSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.ext.rule; 17 | 18 | import java.util.List; 19 | 20 | public interface TrafficSplitRuleSource { 21 | 22 | /** 23 | * It is used to obtain redefineRules. User can specify whether the rules acquisition is 24 | * dynamic or static. 25 | * 26 | * @return rules 27 | */ 28 | List rules(); 29 | } 30 | -------------------------------------------------------------------------------- /restclient-ext/traffic-split-interceptor/src/main/java/io/esastack/restclient/ext/spi/RuleSourceFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.ext.spi; 17 | 18 | import esa.commons.spi.SPI; 19 | import io.esastack.restclient.RestClientOptions; 20 | import io.esastack.restclient.ext.rule.TrafficSplitRuleSource; 21 | 22 | @SPI 23 | public interface RuleSourceFactory { 24 | 25 | /** 26 | * Create RedefineRuleSource by RestClientOptions. Different RedefineRuleSource can be 27 | * provided according to different RestClientOptions to provide users with more flexible 28 | * configuration. 29 | * 30 | * @param options RestClientOptions 31 | * @return RedefineRuleSource 32 | */ 33 | TrafficSplitRuleSource create(RestClientOptions options); 34 | } 35 | -------------------------------------------------------------------------------- /restclient-ext/traffic-split-interceptor/src/main/resources/META-INF/esa/internal/io.esastack.restclient.spi.RestInterceptorFactory: -------------------------------------------------------------------------------- 1 | io.esastack.restclient.ext.interceptor.TrafficSplitInterceptorFactory -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/RestResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient; 17 | 18 | import io.esastack.commons.net.http.Cookie; 19 | import io.esastack.commons.net.http.MediaType; 20 | import io.esastack.httpclient.core.Response; 21 | 22 | import java.util.Set; 23 | 24 | public interface RestResponse extends Response { 25 | 26 | Cookie cookie(String name); 27 | 28 | Set cookies(); 29 | 30 | /** 31 | * @return contentType of response 32 | */ 33 | MediaType contentType(); 34 | } 35 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/RestResponseBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient; 17 | 18 | import java.lang.reflect.Type; 19 | 20 | public interface RestResponseBase extends RestResponse { 21 | T bodyToEntity(Class entityClass) throws Exception; 22 | 23 | T bodyToEntity(Type generics) throws Exception; 24 | } 25 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/ByteCodec.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec; 17 | 18 | import io.esastack.restclient.utils.Constants; 19 | 20 | public interface ByteCodec extends ByteEncoder, ByteDecoder { 21 | 22 | @Override 23 | default int getOrder() { 24 | return Constants.Order.NORMAL; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/ByteDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec; 17 | 18 | public interface ByteDecoder extends Decoder { 19 | 20 | @SuppressWarnings("unchecked") 21 | @Override 22 | default Object decode(DecodeContext ctx) throws Exception { 23 | if (ctx.content().value() instanceof byte[]) { 24 | return doDecode((DecodeContext) ctx); 25 | } 26 | return ctx.next(); 27 | } 28 | 29 | Object doDecode(DecodeContext ctx) throws Exception; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/ByteEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec; 17 | 18 | public interface ByteEncoder extends Encoder { 19 | 20 | @SuppressWarnings("unchecked") 21 | @Override 22 | default RequestContent encode(EncodeContext ctx) throws Exception { 23 | return doEncode((EncodeContext) ctx); 24 | } 25 | 26 | RequestContent doEncode(EncodeContext ctx) throws Exception; 27 | } 28 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/Content.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec; 17 | 18 | public interface Content { 19 | 20 | V value(); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/DecodeAdvice.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec; 17 | 18 | import io.esastack.httpclient.core.util.Ordered; 19 | 20 | /** 21 | * Interface for decode advice that wrap around calls to {@link Decoder#decode}. 22 | * 23 | * @see Decoder 24 | */ 25 | public interface DecodeAdvice extends Ordered { 26 | 27 | /** 28 | * Method wrapping calls to {@link Decoder#decode}. method. 29 | *

30 | * The parameters of the wrapped method called are available from context. Implementations 31 | * of this method SHOULD explicitly call {@link DecodeAdviceContext#next()} to invoke the 32 | * next DecodeAdvice in the chain, and ultimately the wrapped 33 | * {@link Decoder#decode}. method. 34 | * 35 | * @param ctx decode invocation context 36 | * @return decoded object 37 | * @throws Exception error 38 | * @see Decoder 39 | * @see DecodeAdviceContext 40 | */ 41 | Object aroundDecode(DecodeAdviceContext ctx) throws Exception; 42 | } 43 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/DecodeAdviceContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec; 17 | 18 | import io.esastack.restclient.RestRequest; 19 | import io.esastack.restclient.RestResponse; 20 | 21 | /** 22 | * Context class used by {@link DecodeAdvice} to intercept calls to 23 | * {@link Decoder#decode}. 24 | * The member variables in this context class correspond to the 25 | * parameters of the intercepted method {@link Decoder#decode} 26 | * 27 | * @see Decoder 28 | * @see DecodeAdvice 29 | */ 30 | public interface DecodeAdviceContext extends DecodeChain { 31 | 32 | RestRequest request(); 33 | 34 | RestResponse response(); 35 | 36 | /** 37 | * set responseContent,this method is not safe for use by multiple threads 38 | * 39 | * @param responseContent responseContent 40 | */ 41 | void content(ResponseContent responseContent); 42 | } 43 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/DecodeChain.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec; 17 | 18 | import io.esastack.commons.net.http.MediaType; 19 | 20 | import java.lang.reflect.Type; 21 | 22 | public interface DecodeChain { 23 | 24 | /** 25 | * @return The contentType of response 26 | */ 27 | MediaType contentType(); 28 | 29 | /** 30 | * @return The content of response 31 | */ 32 | ResponseContent content(); 33 | 34 | /** 35 | * @return The type of target 36 | */ 37 | Class targetType(); 38 | 39 | /** 40 | * @return The generics of target 41 | */ 42 | Type targetGenerics(); 43 | 44 | /** 45 | * Proceed to the next member in the chain. 46 | * 47 | * @return decoded object 48 | * @throws Exception error 49 | */ 50 | Object next() throws Exception; 51 | } 52 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/DecodeContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec; 17 | 18 | import io.esastack.commons.net.http.HttpHeaders; 19 | 20 | public interface DecodeContext extends DecodeChain { 21 | 22 | /** 23 | * @return The headers of response 24 | */ 25 | HttpHeaders headers(); 26 | 27 | @Override 28 | ResponseContent content(); 29 | } 30 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/EncodeAdvice.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec; 17 | 18 | import io.esastack.httpclient.core.util.Ordered; 19 | 20 | /** 21 | * Interface for encode advice that wrap around calls to {@link Encoder#encode} 22 | * 23 | * @see Encoder 24 | */ 25 | public interface EncodeAdvice extends Ordered { 26 | 27 | /** 28 | * Method wrapping calls to {@link Encoder#encode} method. 29 | *

30 | * The parameters of the wrapped method called are available from context. Implementations 31 | * of this method SHOULD explicitly call {@link EncodeAdviceContext#next()} to invoke the 32 | * next EncodeAdvice in the chain, and ultimately the wrapped {@link 33 | * Encoder#encode} method. 34 | * 35 | * @param ctx encode invocation context 36 | * @return encoded requestContent 37 | * @throws Exception error 38 | * @see Encoder 39 | * @see EncodeAdviceContext 40 | */ 41 | RequestContent aroundEncode(EncodeAdviceContext ctx) throws Exception; 42 | } 43 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/EncodeAdviceContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec; 17 | 18 | import io.esastack.restclient.RestRequest; 19 | 20 | import java.lang.reflect.Type; 21 | 22 | /** 23 | * Context class used by {@link EncodeAdvice} to intercept the call of 24 | * {@link Encoder#encode}. 25 | * The member variables in this context class correspond to the 26 | * parameters of the intercepted method {@link Encoder#encode} 27 | * 28 | * @see Encoder 29 | * @see EncodeAdvice 30 | */ 31 | public interface EncodeAdviceContext extends EncodeChain { 32 | 33 | RestRequest request(); 34 | 35 | /** 36 | * set entity,this method is not safe for use by multiple threads 37 | * 38 | * @param entity entity 39 | */ 40 | void entity(Object entity); 41 | 42 | /** 43 | * set entity and generics,this method is not safe for use by multiple threads 44 | * 45 | * @param entity entity 46 | * @param generics generics 47 | */ 48 | void entity(Object entity, Type generics); 49 | } 50 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/EncodeChain.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec; 17 | 18 | 19 | import io.esastack.commons.net.http.MediaType; 20 | 21 | import java.lang.reflect.Type; 22 | 23 | public interface EncodeChain { 24 | 25 | /** 26 | * @return The contentType of request 27 | */ 28 | MediaType contentType(); 29 | 30 | /** 31 | * @return The entity of request 32 | */ 33 | Object entity(); 34 | 35 | /** 36 | * @return The type of entity 37 | */ 38 | Class entityType(); 39 | 40 | /** 41 | * @return The generics of entity 42 | */ 43 | Type entityGenerics(); 44 | 45 | /** 46 | * Proceed to the next member in the chain. 47 | * 48 | * @return encoded requestContent 49 | * @throws Exception error 50 | */ 51 | RequestContent next() throws Exception; 52 | } 53 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/EncodeContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec; 17 | 18 | import io.esastack.commons.net.http.HttpHeaders; 19 | 20 | public interface EncodeContext extends EncodeChain { 21 | 22 | /** 23 | * @return The headers of request 24 | */ 25 | HttpHeaders headers(); 26 | 27 | @Override 28 | RequestContent next() throws Exception; 29 | } 30 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/RequestContent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec; 17 | 18 | import io.esastack.httpclient.core.MultipartBody; 19 | import io.esastack.restclient.codec.impl.RequestContentImpl; 20 | 21 | import java.io.File; 22 | 23 | public interface RequestContent extends Content { 24 | 25 | static RequestContent of(byte[] content) { 26 | return new RequestContentImpl<>(content); 27 | } 28 | 29 | static RequestContent of(File content) { 30 | return new RequestContentImpl<>(content); 31 | } 32 | 33 | static RequestContent of(MultipartBody content) { 34 | return new RequestContentImpl<>(content); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/ResponseContent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec; 17 | 18 | import io.esastack.restclient.codec.impl.ResponseContentImpl; 19 | 20 | public interface ResponseContent extends Content { 21 | 22 | static ResponseContent of(byte[] content) { 23 | return new ResponseContentImpl<>(content); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/impl/ContentImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec.impl; 17 | 18 | import esa.commons.Checks; 19 | import io.esastack.restclient.codec.Content; 20 | 21 | public class ContentImpl implements Content { 22 | 23 | private final V value; 24 | 25 | protected ContentImpl(V value) { 26 | Checks.checkNotNull(value, "value"); 27 | this.value = value; 28 | } 29 | 30 | @Override 31 | public V value() { 32 | return value; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/impl/FileEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec.impl; 17 | 18 | import io.esastack.restclient.codec.EncodeContext; 19 | import io.esastack.restclient.codec.Encoder; 20 | import io.esastack.restclient.codec.RequestContent; 21 | 22 | import java.io.File; 23 | 24 | public class FileEncoder implements Encoder { 25 | 26 | @Override 27 | public RequestContent encode(EncodeContext ctx) throws Exception { 28 | 29 | if (File.class.isAssignableFrom(ctx.entityType())) { 30 | return RequestContent.of((File) ctx.entity()); 31 | } 32 | return ctx.next(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/impl/FormURLEncodedEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec.impl; 17 | 18 | import io.esastack.commons.net.http.MediaType; 19 | import io.esastack.httpclient.core.MultipartBody; 20 | import io.esastack.restclient.codec.EncodeContext; 21 | import io.esastack.restclient.codec.Encoder; 22 | import io.esastack.restclient.codec.RequestContent; 23 | 24 | public class FormURLEncodedEncoder implements Encoder { 25 | 26 | @Override 27 | public RequestContent encode(EncodeContext ctx) throws Exception { 28 | MediaType contentType = ctx.contentType(); 29 | Class type = ctx.entityType(); 30 | if (contentType != null && MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType) 31 | && MultipartBody.class.isAssignableFrom(type)) { 32 | MultipartBody formBody = (MultipartBody) ctx.entity(); 33 | formBody.multipartEncode(false); 34 | return RequestContent.of(formBody); 35 | } 36 | 37 | return ctx.next(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/impl/MultipartEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec.impl; 17 | 18 | import io.esastack.commons.net.http.MediaType; 19 | import io.esastack.httpclient.core.MultipartBody; 20 | import io.esastack.restclient.codec.EncodeContext; 21 | import io.esastack.restclient.codec.Encoder; 22 | import io.esastack.restclient.codec.RequestContent; 23 | 24 | public class MultipartEncoder implements Encoder { 25 | 26 | @Override 27 | public RequestContent encode(EncodeContext ctx) throws Exception { 28 | MediaType contentType = ctx.contentType(); 29 | if (contentType != null && MediaType.MULTIPART_FORM_DATA.isCompatibleWith(contentType) 30 | && MultipartBody.class.isAssignableFrom(ctx.entityType())) { 31 | return RequestContent.of((MultipartBody) ctx.entity()); 32 | } 33 | 34 | return ctx.next(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/impl/RequestContentImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec.impl; 17 | 18 | import io.esastack.restclient.codec.RequestContent; 19 | 20 | public final class RequestContentImpl extends ContentImpl implements RequestContent { 21 | 22 | public RequestContentImpl(V value) { 23 | super(value); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/codec/impl/ResponseContentImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.codec.impl; 17 | 18 | import io.esastack.restclient.codec.ResponseContent; 19 | 20 | public class ResponseContentImpl extends ContentImpl implements ResponseContent { 21 | 22 | public ResponseContentImpl(V value) { 23 | super(value); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/exec/InvocationChain.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.exec; 17 | 18 | import io.esastack.restclient.RestRequest; 19 | import io.esastack.restclient.RestResponse; 20 | 21 | import java.util.concurrent.CompletionStage; 22 | 23 | public interface InvocationChain { 24 | 25 | /** 26 | * Invoke the registered {@link RestInterceptor}s. 27 | * 28 | * @param request current request 29 | * @return future 30 | */ 31 | CompletionStage proceed(RestRequest request); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/exec/InvocationChainImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.exec; 17 | 18 | import esa.commons.Checks; 19 | import io.esastack.restclient.RestRequest; 20 | import io.esastack.restclient.RestResponse; 21 | 22 | import java.util.concurrent.CompletionStage; 23 | 24 | final class InvocationChainImpl implements InvocationChain { 25 | 26 | private final RestInterceptor current; 27 | private final InvocationChain next; 28 | 29 | InvocationChainImpl(RestInterceptor current, InvocationChain next) { 30 | Checks.checkNotNull(current, "current"); 31 | Checks.checkNotNull(next, "next"); 32 | this.current = current; 33 | this.next = next; 34 | } 35 | 36 | @Override 37 | public CompletionStage proceed(RestRequest request) { 38 | return current.proceed(request, next); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/exec/RestInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.exec; 17 | 18 | import io.esastack.httpclient.core.util.Ordered; 19 | import io.esastack.restclient.RestRequest; 20 | import io.esastack.restclient.RestResponse; 21 | 22 | import java.util.concurrent.CompletionStage; 23 | 24 | /** 25 | * Interceptor is designed for intercept request execution.Users can execute business 26 | * logic or modify the parameters of the request before and after executing the request. 27 | */ 28 | public interface RestInterceptor extends Ordered { 29 | 30 | /** 31 | * Proceeds the RestRequest and obtains RestResponse.Users can execute business 32 | * logic or modify the parameters of the request before and after executing the 33 | * request. 34 | * 35 | * @param request request 36 | * @param next next,{@link InvocationChain#proceed} will continue execute the 37 | * execution chain 38 | * @return response 39 | */ 40 | CompletionStage proceed(RestRequest request, InvocationChain next); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/exec/RestRequestExecutor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.exec; 17 | 18 | import io.esastack.restclient.RestRequest; 19 | import io.esastack.restclient.RestResponseBase; 20 | 21 | import java.util.concurrent.CompletionStage; 22 | 23 | public interface RestRequestExecutor { 24 | 25 | CompletionStage execute(RestRequest request); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/spi/DecodeAdviceFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.spi; 17 | 18 | import esa.commons.spi.SPI; 19 | import io.esastack.restclient.RestClientOptions; 20 | import io.esastack.restclient.codec.DecodeAdvice; 21 | 22 | import java.util.Collection; 23 | 24 | @SPI 25 | public interface DecodeAdviceFactory { 26 | Collection decodeAdvices(RestClientOptions clientOptions); 27 | } 28 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/spi/DecoderFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.spi; 17 | 18 | import esa.commons.spi.SPI; 19 | import io.esastack.restclient.RestClientOptions; 20 | import io.esastack.restclient.codec.Decoder; 21 | 22 | import java.util.Collection; 23 | 24 | @SPI 25 | public interface DecoderFactory { 26 | Collection decoders(RestClientOptions clientOptions); 27 | } 28 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/spi/EncodeAdviceFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.spi; 17 | 18 | import esa.commons.spi.SPI; 19 | import io.esastack.restclient.RestClientOptions; 20 | import io.esastack.restclient.codec.EncodeAdvice; 21 | 22 | import java.util.Collection; 23 | 24 | @SPI 25 | public interface EncodeAdviceFactory { 26 | Collection encodeAdvices(RestClientOptions clientOptions); 27 | } 28 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/spi/EncoderFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.spi; 17 | 18 | import esa.commons.spi.SPI; 19 | import io.esastack.restclient.RestClientOptions; 20 | import io.esastack.restclient.codec.Encoder; 21 | 22 | import java.util.Collection; 23 | 24 | @SPI 25 | public interface EncoderFactory { 26 | Collection encoders(RestClientOptions clientOptions); 27 | } 28 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/spi/RestInterceptorFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.spi; 17 | 18 | import esa.commons.spi.SPI; 19 | import io.esastack.restclient.RestClientOptions; 20 | import io.esastack.restclient.exec.RestInterceptor; 21 | 22 | import java.util.Collection; 23 | 24 | @SPI 25 | public interface RestInterceptorFactory { 26 | 27 | Collection interceptors(RestClientOptions clientOptions); 28 | } 29 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/spi/impl/InternalDecoderFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.spi.impl; 17 | 18 | import io.esastack.restclient.RestClientOptions; 19 | import io.esastack.restclient.codec.Decoder; 20 | import io.esastack.restclient.codec.impl.ByteToByteCodec; 21 | import io.esastack.restclient.codec.impl.JacksonCodec; 22 | import io.esastack.restclient.codec.impl.StringCodec; 23 | import io.esastack.restclient.spi.DecoderFactory; 24 | 25 | import java.util.ArrayList; 26 | import java.util.Collection; 27 | import java.util.List; 28 | 29 | public final class InternalDecoderFactory implements DecoderFactory { 30 | 31 | @Override 32 | public Collection decoders(RestClientOptions clientOptions) { 33 | List decoders = new ArrayList<>(3); 34 | decoders.add(new ByteToByteCodec()); 35 | decoders.add(new JacksonCodec()); 36 | decoders.add(new StringCodec()); 37 | return decoders; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /restclient/src/main/java/io/esastack/restclient/utils/Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 OPPO ESA Stack Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.esastack.restclient.utils; 17 | 18 | public final class Constants { 19 | 20 | private Constants() { 21 | } 22 | 23 | public static final class Order { 24 | public static final int FAST_JSON = -2048; 25 | public static final int GSON = -2048; 26 | public static final int JACKSON = 0; 27 | public static final int NORMAL = 0; 28 | public static final int BYTE_TO_BYTE_CODEC = -4096; 29 | public static final int STRING_CODEC = -4096; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /restclient/src/main/resources/META-INF/esa/internal/io.esastack.restclient.spi.DecoderFactory: -------------------------------------------------------------------------------- 1 | io.esastack.restclient.spi.impl.InternalDecoderFactory -------------------------------------------------------------------------------- /restclient/src/main/resources/META-INF/esa/internal/io.esastack.restclient.spi.EncoderFactory: -------------------------------------------------------------------------------- 1 | io.esastack.restclient.spi.impl.InternalEncoderFactory -------------------------------------------------------------------------------- /site/.nvmrc: -------------------------------------------------------------------------------- 1 | lts/* 2 | -------------------------------------------------------------------------------- /site/assets/scss/_variables_project.scss: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Add styles or override variables from the theme here. 4 | 5 | */ 6 | 7 | $primary: #24292f !default; -------------------------------------------------------------------------------- /site/content/en/_index.html: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "ESA RestClient" 3 | linkTitle = "ESA RestClient" 4 | 5 | +++ 6 | 7 | {{< blocks/cover title="Welcome to ESA RestClient!" image_anchor="top" height="full" color="orange" >}} 8 |

9 | }}"> 10 | Learn More 11 | 12 | }}"> 13 | Get Started 14 | 15 |

An asynchronous event-driven HTTP client based on netty!

16 | {{< blocks/link-down color="info" >}} 17 |
18 | {{< /blocks/cover >}} 19 | 20 | 21 | {{% blocks/lead color="primary" %}} 22 | ESA RestClient is an asynchronous event-driven http client based on netty. Help users quickly build high-performance, easy-to-use, simple rest client. 23 | {{% /blocks/lead %}} 24 | 25 | {{< blocks/section color="white">}} 26 | 27 | {{% blocks/feature icon="fa-solid fa-rocket" title="High Performance" %}} 28 | **110000** RPS(4c8g) 29 | 30 | {{% /blocks/feature %}} 31 | 32 | 33 | {{% blocks/feature icon="fa-solid fa-code" title="Reactive Programing"%}} 34 | Fluent interface based on `CompletionStage` 35 | {{% /blocks/feature %}} 36 | 37 | 38 | {{% blocks/feature icon="fa-solid fa-cubes" title="Rich Features" %}} 39 | Http1/H2c/Https, Interceptor, Codec, Retry, Redirect, Large file... 40 | {{% /blocks/feature %}} 41 | 42 | 43 | {{< /blocks/section >}} 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /site/content/en/blog/_index.md: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | title: "Blog" 4 | linkTitle: "Blog" 5 | weight: 30 6 | description: > 7 | This is the **blog** section. It has categories: Releases. 8 | --- 9 | 10 | -------------------------------------------------------------------------------- /site/content/en/blog/architecture/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Architecture" 3 | linkTitle: "Architecture" 4 | weight: 200 5 | description: > 6 | There are some architecture related documents. 7 | --- 8 | 9 | 10 | -------------------------------------------------------------------------------- /site/content/en/blog/releases/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Releases" 3 | linkTitle: "Releases" 4 | weight: 100 5 | description: > 6 | The newest version is 1.0.1 which fix bug of `codec`。 7 | --- 8 | 9 | 10 | -------------------------------------------------------------------------------- /site/content/en/blog/releases/v0.1.0.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Release v0.1.0" 3 | linkTitle: "Release v0.1.0" 4 | weight: 20 5 | date: 2021-02-02 6 | description: > 7 | First Release! 8 | --- 9 | 10 | - Http1/H2/H2cUpgrade 11 | - Https 12 | - Epoll/NIO 13 | - Interceptor 14 | - Filter 15 | - Retry, Redirect, 100-expect-continue 16 | - Segmented read/write 17 | - Multipart 18 | - Metrics -------------------------------------------------------------------------------- /site/content/en/blog/releases/v1.0.0.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Release v1.0.0" 3 | linkTitle: "Release v1.0.0" 4 | weight: 10 5 | date: 2022-02-16 6 | description: > 7 | Add `codec`! 8 | --- 9 | 10 | Add `codec` which will automatically select the appropriate decoder or encoder to decode or encode according to the user's headers and entity. At the same time, restclient also supports users to insert business logic before and after decode or encode. -------------------------------------------------------------------------------- /site/content/en/blog/releases/v1.0.1.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Release v1.0.1" 3 | linkTitle: "Release v1.0.1" 4 | weight: 10 5 | date: 2022-03-08 6 | description: > 7 | Fix bug of `codec`! 8 | --- 9 | 10 | Fix the bug that the user can,t directly added the encoder and decoder through RestClientBuilder! 11 | -------------------------------------------------------------------------------- /site/content/en/docs-v0.1.0/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "ESA HttpClient" 3 | linkTitle: "ESA HttpClient" 4 | weight: 20 5 | description: > 6 | ESA HttpClient is an asynchronous event-driven http client based on netty. 7 | --- 8 | ## Features 9 | - Http1/H2/H2cUpgrade 10 | - Https 11 | - Epoll/NIO 12 | - Interceptor 13 | - Filter 14 | - Retry, Redirect, 100-expect-continue 15 | - Segmented read/write 16 | - Multipart 17 | - Metrics 18 | - more features... 19 | 20 | -------------------------------------------------------------------------------- /site/content/en/docs-v0.1.0/dns_ext/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["extension"] 3 | title: "DNS扩展" 4 | linkTitle: "DNS扩展" 5 | weight: 40 6 | description: > 7 | 在每次建立连接前,client可能需要将域名解析成IP地址,`HttpClient`通过适配`netty`原生的`AddressResolverGroup`提供了一种更加简单、 8 | 灵活的`NameResolver`扩展,用于将url地址中的域名解析成IP地址。 9 | --- 10 | ## 使用方式 11 | ```java 12 | final HttpClient client = HttpClient.create().resolver(new HostResolver() { 13 | @Override 14 | public CompletableFuture resolve(String inetHost) { 15 | // resolve inetHost 16 | return null; 17 | } 18 | }).build(); 19 | ``` 20 | 在构造`HttpClient`时传入自定义的`HostResolver`,后续建立连接时会调用`resolve()`方法进行Host地址解析。默认情况下,将使用系统默认的命名服务进行Host解析,详情请查看`SystemDefaultResolver`。 -------------------------------------------------------------------------------- /site/content/en/docs-v0.1.0/file_upload_download/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["usage"] 3 | title: "文件上传及下载" 4 | linkTitle: "文件上传及下载" 5 | weight: 70 6 | description: > 7 | `HttpClient`支持文件上传和下载功能。**需要说明地是,对于内容较小的文件,可通过直接将文件内容写入请求body中或者直接从响应body中读取。** 本文只讨论当文件内容过大,直接读取或者写入有OOM风险时的大文件上传和下载功能。 8 | --- 9 | ## 大文件上传 10 | 11 | ### 不使用Multipart编码 12 | ```java 13 | final HttpClient client = HttpClient.ofDefault(); 14 | HttpResponse response = client.post("http://127.0.0.1:8080/abc") 15 | .body(new File("xxxxx")) 16 | .execute() 17 | .get(); 18 | System.out.println(response.status()); 19 | ``` 20 | 如上所示,`HttpClient`将分块读取文件内容并将其写入请求body中,对应请求的Content-Type为**application/octet-stream**。该情形适用于单个大文件内容作为原始body内容上传的情况。 21 | 22 | ### 使用Multipart编码 23 | ```java 24 | final HttpClient client = HttpClient.ofDefault(); 25 | 26 | File file = new File("xxxxx"); 27 | final MultipartRequest request = client.post("http://127.0.0.1:9997/file/upload") 28 | .multipart() 29 | .file("file", file) 30 | .attr("name", "Bob") 31 | .attr("address", "China"); 32 | 33 | HttpResponse response = request.execute().get(); 34 | System.out.println(response.status()); 35 | System.out.println(response.body().string(StandardCharsets.UTF_8)); 36 | ``` 37 | 如上所示,`HttpClient`将添加的文件和表单参数进行Multipart Encode的结果作为请求的body内容,对应的Content-Type为**multipart/form-data。** 该情形适用于需要进行multipart encode或者存在表单参数的情形。**特别地,如果只上传表单参数,不存在文件时,可以设置multipart值为false,后续上传时请求的Content-Type将设置为application/x-www-form-urlencoded。** 38 | 39 | {{< alert title="Note" >}} 40 | 当下载文件内容较大时,建议使用[自定义响应处理](../customize_handle/)功能,分块读取响应body内容并将其直接写入文件,避免产生OOM。 41 | {{< /alert >}} -------------------------------------------------------------------------------- /site/content/en/docs-v0.1.0/filter/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["extension"] 3 | title: "Filter" 4 | linkTitle: "Filter" 5 | weight: 30 6 | description: > 7 | `Filter`分为`RequestFilter`和`ResponseFilter`两种,前者主要用于处理`HttpRequest`,在所有`Interceptor`对`HttpRequest`处理之后执行, 8 | 后者主要用于处理`HttpResponse`,在响应headers到达之后立即执行,此时所有拦截器对`HttpResponse`的处理均未开始执行。 9 | --- 10 | ## 与`Interceptor`的区别 11 | 1. 执行顺序不同:`RequestFilter`在所有拦截器对`HttpRequest`的处理之后才会执行,`ResponseFilter`在响应头接收到之后(响应body处理前)立即执行,此时所有拦截器对`HttpResponse`的处理均未执行。 12 | 2. 关联性不同:`RequestFilter`和`ResponseFilter`中均无法同时获取到请求和响应,因此也不能将两者关联起来,但是同一个请求将在`RequestFilter`和`ResponseFilter`中共享一个`FilterContext`实例, 13 | 因此可以通过该对象传递上下文参数。而`Interceptor`中可以获取`HttpRequest`经过处理后的`HttpResponse`,因此可以通过此种方式将请求和响应关联起来。 14 | 3. 通过`RequestFilter`或`ResponseFilter`无法替换原始的`HttpRequest`或`HttpResponse`,而通过`Interceptor`可以实现。 15 | 16 | 鉴于`Filter`和`Interceptor`的区别,下述场景更适合使用`Filter`: 17 | 1. 只需要单独处理`HttpRequest`或`HttpResponse`,如:对每个`HttpRequest`或`HttpResponse`添加固定的请求header。 18 | 2. `HttpRequest`处理过程中可能需要多次执行的逻辑,比如在发生重试、重定向时会发出多个网络请求,而这些请求均需要执行的逻辑。 19 | 20 | {{< alert title="Note" >}} 21 | - 多个`Filter`之间通过`getOrder()`方法返回值区分执行顺序,值越小,优先级越高 22 | - 同一个`HttpRequest`可以通过共享一个`FitlerContext`实例在多个`RequestFilter`和`ResponseFilter`实例间传递上下文参数 23 | {{< /alert >}} 24 | -------------------------------------------------------------------------------- /site/content/en/docs-v0.1.0/filter/useages.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["extension"] 3 | title: "使用方式" 4 | linkTitle: "使用方式" 5 | weight: 10 6 | description: > 7 | `HttpClient`支持通过builder配置和SPI加载两种方式配置`Filter`。 8 | --- 9 | ## Builder配置 10 | ```java 11 | final HttpClient client = HttpClient.create().addRequestFilter((request, ctx) -> { // 仅处理Request 12 | System.out.println("Request Filter"); 13 | return CompletableFuture.completedFuture(null); 14 | }).addResponseFilter((request, response, ctx) -> { // 仅处理Response 15 | System.out.println("Response Filter"); 16 | return CompletableFuture.completedFuture(null); 17 | }).addFilter(new DuplexFilter() { // 同时处理Request和Response 18 | @Override 19 | public CompletableFuture doFilter(HttpRequest request, FilterContext ctx) { 20 | System.out.println("Request Filter(Duplex)"); 21 | return CompletableFuture.completedFuture(null); 22 | } 23 | 24 | @Override 25 | public CompletableFuture doFilter(HttpRequest request, HttpResponse response, FilterContext ctx) { 26 | System.out.println("Response Filter(Duplex)"); 27 | return CompletableFuture.completedFuture(null); 28 | } 29 | }).build(); 30 | ``` 31 | 32 | ## SPI 33 | `HttpClient`支持通过SPI的方式加载`Filter`,使用时,只需要按照Spi的加载规则将自定义的`Filter`放入指定的目录下即可。 34 | -------------------------------------------------------------------------------- /site/content/en/docs-v0.1.0/getting_started/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["example"] 3 | title: "Getting Started" 4 | linkTitle: "Getting Started" 5 | weight: 10 6 | description: > 7 | It's so easy to get start with `HttpClient`. 8 | --- 9 | ## Step 1: Add dependency 10 | > **Note:`netty` 4.1.52.Final and `tcnative` 2.0.34.Final are directly dependent on.** 11 | 12 | > **Note: Please make sure the version of `tcnative` matches the version of `netty`.** 13 | 14 | 15 | ```xml 16 | 17 | io.esastack 18 | httpclient-core 19 | ${esa-httpclient.version} 20 | 21 | ``` 22 | 23 | ## Step 2: Send a request and handle response 24 | > **Note:执行请求得到的CompletionStage直接由IO线程执行,请勿在该线程内做其他耗时操作,以免阻塞IO线程** 25 | 26 | ```java 27 | final HttpClient client = HttpClient.ofDefault(); 28 | 29 | final HttpResponse response = client.post("http://127.0.0.1:8081/").body("Hello Server".getBytes()).execute().get(); 30 | // handle response here... 31 | ``` 32 | -------------------------------------------------------------------------------- /site/content/en/docs-v0.1.0/interceptor/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["extension"] 3 | title: "Interceptor" 4 | linkTitle: "Interceptor" 5 | weight: 20 6 | description: > 7 | 在`HttpRequest`处理过程中,有时可能需要执行Retry、Redirect、Cache等操作,使用`Interceptor`可以实现类似功能。 8 | --- 9 | 10 | ## 与`Filter`的区别 11 | 与`Filter`不同的是,在`Interceptor`中 12 | 可以同时获取`HttpRequest`及经过处理后的`HttpResponse`,甚至可以替换原始的`HttpRequest`及处理后的`HttpResponse`。更多与`Filter`的不同如下: 13 | 1. 执行时机不同:`RequestFilter`在所有拦截器对`HttpRequest`的处理之后才会执行,`ResponseFilter`在响应头接收到之后(响应body处理前)立即执行,此时所有拦截器对`HttpResponse`的处理均未执行。 14 | 2. 关联性不同:`Interceptor`中可以获取`HttpRequest`经过处理后的`HttpResponse`,通过此种方式可以将请求和响应关联起来,而`RequestFilter`和`ResponseFilter`中均无法同时获取到请求和响应,因此 15 | 也不能将两者关联起来,但是同一个请求将在`RequestFilter`和`ResponseFilter`中共享一个`FilterContext`实例,因此可以通过该对象传递上下文参数。 16 | 3. 通过拦截器可以替换`HttpRequest`或`HttpResponse`,而通过`Filter`无法实现。 17 | 18 | 鉴于`Interceptor`和`Filter`的区别,下述场景更适合使用`Interceptor`: 19 | 1. 需要同时处理`HttpRequest`及`HttpResponse`,如重试、重定向等(因为需要获取`HttpRequest`处理结果后的`HttpResponse`再决定下一步处理逻辑)。 20 | 2. `HttpRequest`处理过程中仅需要执行一次的逻辑,同时需要注意该类拦截器的优先级要高于重试、重定向等内置拦截器,否则发生重试、重定向时该拦类拦截器仍会被 21 | 多次执行。 22 | 3. 需要替换原始的`HttpRequest`或处理后的`HttpResponse`。 23 | -------------------------------------------------------------------------------- /site/content/en/docs-v0.1.0/interceptor/embedded_interceptors.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["extension"] 3 | title: "内置Interceptor" 4 | linkTitle: "内置Interceptor" 5 | weight: 10 6 | description: > 7 | 在`HttpClient`中存在一些内置`Interceptor`,用于实现 100-expect-continue、重试、重定向 等功能。 8 | --- 9 | ## 100-expect-continue 10 | `HttpClient`内置了对100("expect-continue")响应码的支持,使用时可以设置Client或者Request级别的useExpectContinue参数为false来禁用该功能。 11 | ## 重试 12 | `HttpClient`使用内置的`RetryInterceptor`实现重试功能。默认情况下,会对所有抛出连接异常的请求进行重试,其中:最大重试次数为3(不包括原始请求),重试间隔时间为0。使用时,可以通过自定义`RetryOptions`参数更改重试次数、重试条件、重试间隔时间等。 13 | ## 重定向 14 | 默认情况下,`HttpClient`会对响应状态码为301,302,303,307,308的请求重定向,其中:最大重定向次数为5(不包含原始请求)。使用时,可以通过maxRedirects更新重定向次数或者禁用(maxRedirects=0)重定向功能。 15 | ## 覆盖内置拦截器 16 | 当内置拦截器的功能不能满足用户需求时,可重写对应的内置拦截器的相关方法并通过Builder配置或者Spi加载的机制传入,此时,对应的内置拦截器将自动失效。 17 | 18 | {{< alert title="Note" >}} 19 | 内置拦截器默认执行顺序: 100-expect-continue > 重试 > 重定向 20 | {{< /alert >}} 21 | -------------------------------------------------------------------------------- /site/content/en/docs-v0.1.0/interceptor/useages.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["extension"] 3 | title: "使用方式" 4 | linkTitle: "使用方式" 5 | weight: 20 6 | description: > 7 | `HttpClient`支持通过builder配置和SPI加载两种方式配置`Interceptor`。 8 | --- 9 | ## Builder配置 10 | 11 | 在构造`HttpClient`时传入自定义的`Interceptor`实例,如: 12 | ```java 13 | final HttpClient client = HttpClient.create().addInterceptor((request, next) -> { 14 | System.out.println("Interceptor"); 15 | return next.proceed(request); 16 | }).build(); 17 | 18 | ``` 19 | 20 | ## SPI 21 | 22 | `HttpClient`支持通过SPI的方式加载`Interceptor`接口的实现类,使用时只需要按照SPI的加载规则将自定义的`Interceptor`放入指定的目录下即可。 23 | 24 | {{< alert title="Note" >}} 25 | - 使用时可以通过`Interceptor`替换原始的`HttpRequest`和`HttpResponse`; 2.`HttpClient`内置的重试、重定向、100-expect-continue协商等功能通过`Interceptor`实现。 26 | 27 | - 多个拦截器之间通过`getOrder()`方法返回值区分执行顺序,值越小,优先级越高。 28 | {{< /alert >}} 29 | -------------------------------------------------------------------------------- /site/content/en/docs-v0.1.0/metrics/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["usage"] 3 | title: "指标统计" 4 | linkTitle: "指标统计" 5 | weight: 90 6 | description: > 7 | `HttpClient`提供了IO线程池及连接池的Metric指标统计,使用时通过`HttpClient`实例便可直接获取。 8 | --- 9 | 10 | ## 使用方式 11 | 具体使用如下: 12 | ```java 13 | final HttpClient client = HttpClient.ofDefault(); 14 | 15 | ConnectionPoolMetricProvider connectionPoolMetricProvider = client.connectionPoolMetric(); 16 | ConnectionPoolMetric connectionPoolMetric = connectionPoolMetricProvider.get(InetSocketAddress.createUnresolved("127.0.0.1", 8080)); 17 | 18 | // 连接池配置 19 | connectionPoolMetric.options(); 20 | 21 | // 等待获取连接的请求个数 22 | connectionPoolMetric.pendingAcquireCount(); 23 | 24 | // 活跃连接个数 25 | connectionPoolMetric.active(); 26 | 27 | // 等待获取连接队列最大值 28 | connectionPoolMetric.maxPendingAcquires(); 29 | 30 | // 连接池最大值 31 | connectionPoolMetric.maxSize(); 32 | 33 | IoThreadGroupMetric ioThreadGroupMetric = client.ioThreadsMetric(); 34 | 35 | for (IoThreadMetric ioThreadMetric : ioThreadGroupMetric.childExecutors()) { 36 | // 任务队列大小 37 | ioThreadMetric.pendingTasks(); 38 | 39 | // 任务队列最大值 40 | ioThreadMetric.maxPendingTasks(); 41 | 42 | // 线程状态 43 | ioThreadMetric.state(); 44 | 45 | // 线程名称 46 | ioThreadMetric.name(); 47 | } 48 | ``` 49 | -------------------------------------------------------------------------------- /site/content/en/docs-v0.1.0/segemented_read_write/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["usage"] 3 | title: "分块读写" 4 | linkTitle: "分块读写" 5 | weight: 60 6 | description: > 7 | `HttpClient`支持分块写请求数据及分块处理响应数据,分块读功能请参考[自定义响应处理](../customize_handle),此处不再赘述。本文仅介绍分块写请求body相关功能。 8 | --- 9 | ## 使用方式 10 | 11 | ```java 12 | final HttpClient client = HttpClient.ofDefault(); 13 | 14 | final SegmentRequest request = client.post("http://127.0.0.1:8080/").segment(); 15 | 16 | for (int i = 0; i < 100; i++) { 17 | // request.isWritable()判断适用于较大内容的分块写 18 | if (request.isWritable()) { 19 | request.write("It's body".getBytes()); 20 | } else { 21 | throw new IllegalStateException("Channel is unwritable"); 22 | } 23 | } 24 | 25 | HttpResponse response = request.end("It's end".getBytes()).get(); 26 | System.out.println(response.status()); 27 | System.out.println(response.body().string(StandardCharsets.UTF_8)); 28 | ``` 29 | 如上所示,使用时通过`HttpClient`构造一个可分块写的`SegmentRequest`并在有可写数据时直接写入,最后结束请求。 30 | -------------------------------------------------------------------------------- /site/content/en/docs-v1.0.1/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "ESA RestClient" 3 | linkTitle: "ESA RestClient" 4 | weight: 10 5 | description: > 6 | ESA RestClient is an asynchronous event-driven http client based on netty. 7 | --- 8 | ## Features 9 | - Http1/H2/H2cUpgrade 10 | - Https 11 | - Epoll/NIO 12 | - Serialize and Deserialize 13 | - Interceptor 14 | - Filter 15 | - Retry, Redirect, 100-expect-continue 16 | - Segmented read/write 17 | - Multipart 18 | - Metrics 19 | - more features... -------------------------------------------------------------------------------- /site/content/en/docs-v1.0.1/codec/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["extension"] 3 | title: "Codec" 4 | linkTitle: "Codec" 5 | weight: 20 6 | description: > 7 | 用户请求时`RestClient`会自动根据用户的 `Headers` 与 `Entity` 自动选择合适的`Decoder`或`Encoder`进行`Decode`或`Encode`。同时`RestClient`也支持用户在`codec`前后进行插入业务逻辑。 8 | --- -------------------------------------------------------------------------------- /site/content/en/docs-v1.0.1/dns_ext/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["extension"] 3 | title: "DNS扩展" 4 | linkTitle: "DNS扩展" 5 | weight: 40 6 | description: > 7 | 在每次建立连接前,client可能需要将域名解析成IP地址,`RestClient`通过适配`netty`原生的`AddressResolverGroup`提供了一种更加简单、 8 | 灵活的`NameResolver`扩展,用于将url地址中的域名解析成IP地址。 9 | --- 10 | ## 使用方式 11 | ```java 12 | final RestClient client = RestClient.create().resolver(new HostResolver() { 13 | @Override 14 | public CompletionStage resolve(String inetHost) { 15 | // resolve inetHost 16 | return CompletableFuture.completedFuture(null); 17 | } 18 | }).build(); 19 | ``` 20 | 在构造`RestClient`时传入自定义的`HostResolver`,后续建立连接时会调用`resolve()`方法进行Host地址解析。默认情况下,将使用系统默认的命名服务进行Host解析,详情请查看`SystemDefaultResolver`。 -------------------------------------------------------------------------------- /site/content/en/docs-v1.0.1/file_upload_download/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["usage"] 3 | title: "大文件上传" 4 | linkTitle: "大文件上传" 5 | weight: 50 6 | description: > 7 | `RestClient`支持大文件上传功能。**需要说明地是,对于内容较小的文件,可通过直接将文件内容写入请求body。** 本文只讨论当文件内容过大,直接写入有OOM风险时的大文件上传功能。 8 | --- 9 | ## 使用方式 10 | ### 不使用Multipart编码 11 | ```java 12 | final RestClient client = RestClient.ofDefault(); 13 | final String entity = client.post("http://127.0.0.1:8081/") 14 | .entity(new File("aaa")) 15 | .execute() 16 | .toCompletableFuture() 17 | .get() 18 | .bodyToEntity(String.class); 19 | ``` 20 | 如上所示,`RestClient`将分块读取文件内容并将其写入请求body中,对应请求的Content-Type为**application/octet-stream**。该情形适用于单个大文件内容作为原始body内容上传的情况。 21 | 22 | ### 使用Multipart编码 23 | ```java 24 | final RestClient client = RestClient.ofDefault(); 25 | 26 | File file = new File("xxxxx"); 27 | final RestMultipartRequest request = client.post("http://127.0.0.1:9997/file/upload") 28 | .multipart() 29 | .file("file", file) 30 | .attr("name", "Bob") 31 | .attr("address", "China"); 32 | 33 | RestResponseBase response = request 34 | .execute() 35 | .toCompletableFuture() 36 | .get(); 37 | System.out.println(response.status()); 38 | System.out.println(response.bodyToEntity(String.class)); 39 | ``` 40 | 如上所示,`RestClient`将添加的文件和表单参数进行Multipart Encode的结果作为请求的body内容,对应的Content-Type为**multipart/form-data。** 该情形适用于需要进行multipart encode或者存在表单参数的情形。**特别地,如果只上传表单参数,不存在文件时,则可以直接将Content-Type设置为application/x-www-form-urlencoded。** -------------------------------------------------------------------------------- /site/content/en/docs-v1.0.1/getting_started/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["example"] 3 | title: "Getting Started" 4 | linkTitle: "Getting Started" 5 | weight: 10 6 | description: > 7 | It's very easy to get started with `RestClient`! 8 | --- 9 | ## Step 1: Add dependency 10 | 11 | ```xml 12 | 13 | io.esastack 14 | restclient 15 | ${esa-restclient.version} 16 | 17 | ``` 18 | 19 | ## Step 2: Send a request and handle response 20 | 21 | ```java 22 | final RestClient client = RestClient.ofDefault(); 23 | 24 | final String entity = client.post("http://127.0.0.1:8081/") 25 | .entity("Hello Server") 26 | .execute() 27 | .toCompletableFuture() 28 | .get() 29 | .bodyToEntity(String.class); 30 | ``` 31 | 32 | {{< alert title="Note" >}} 33 | 执行请求得到的CompletionStage直接由IO线程执行,**请勿在该线程内做其他耗时操作,以免阻塞IO线程**。 34 | {{< /alert >}} 35 | {{< alert title="Note" >}} 36 | `netty` 4.1.52.Final and `tcnative` 2.0.34.Final are directly dependent on. And please make sure the version of `tcnative` matches the version of `netty`. 37 | {{< /alert >}} -------------------------------------------------------------------------------- /site/content/en/docs-v1.0.1/interceptor/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["extension"] 3 | title: "Interceptor" 4 | linkTitle: "Interceptor" 5 | weight: 30 6 | description: > 7 | `RestClient`支持通过builder配置和SPI加载两种方式配置`RestInterceptor`。 8 | --- 9 | ## Builder配置 10 | 在构造`RestClient`时传入自定义的`RestInterceptor`实例,如: 11 | ```java 12 | final RestClient client = RestClient.create() 13 | .addInterceptor((request, next) -> { 14 | System.out.println("Interceptor"); 15 | return next.proceed(request); 16 | }).build(); 17 | ``` 18 | {{< alert title="Tip" >}} 19 | 多个拦截器之间通过`getOrder()`方法返回值区分执行顺序,值越小,优先级越高。 20 | {{< /alert >}} 21 | 22 | ## SPI 23 | ### 普通SPI 24 | `RestClient`支持通过Spi的方式加载`RestInterceptor`接口的实现类,使用时只需要按照SPI的加载规则将自定义的`RestInterceptor`放入指定的目录下即可。 25 | ##### RestInterceptorFactory 26 | 如果用户自定义的`RestInterceptor`对于不同`RestClient`的配置有不同的实现,则用户可以实现`RestInterceptorFactory`接口,并按照SPI的加载规则将自定义的`RestInterceptorFactory`放入指定的目录下即可。 27 | ```java 28 | public interface RestInterceptorFactory { 29 | Collection interceptors(RestClientOptions clientOptions); 30 | } 31 | ``` 32 | 在`RestClient`构建时将调用`RestInterceptorFactory.interceptors(RestClientOptions clientOptions)`,该方法返回的所有`RestInterceptor`都将加入到构建好的`RestClient`中。 33 | 34 | ## 执行时机 35 | 见[请求处理完整流程](../process_of_restclient/)中的`RestInterceptor`。 -------------------------------------------------------------------------------- /site/content/en/docs-v1.0.1/metrics/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["usage"] 3 | title: "指标统计" 4 | linkTitle: "指标统计" 5 | weight: 80 6 | description: > 7 | `RestClient`提供了IO线程池及连接池的Metric指标统计,使用时通过`RestClient`实例便可直接获取。 8 | --- 9 | 10 | ## 使用方式 11 | ```java 12 | final RestClient client = RestClient.ofDefault(); 13 | 14 | ConnectionPoolMetricProvider connectionPoolMetricProvider = client.connectionPoolMetric(); 15 | ConnectionPoolMetric connectionPoolMetric = connectionPoolMetricProvider.get(InetSocketAddress.createUnresolved("127.0.0.1", 8080)); 16 | 17 | // 连接池配置 18 | connectionPoolMetric.options(); 19 | 20 | // 等待获取连接的请求个数 21 | connectionPoolMetric.pendingAcquireCount(); 22 | 23 | // 活跃连接个数 24 | connectionPoolMetric.active(); 25 | 26 | // 等待获取连接队列最大值 27 | connectionPoolMetric.maxPendingAcquires(); 28 | 29 | // 连接池最大值 30 | connectionPoolMetric.maxSize(); 31 | 32 | IoThreadGroupMetric ioThreadGroupMetric = client.ioThreadsMetric(); 33 | 34 | for (IoThreadMetric ioThreadMetric : ioThreadGroupMetric.childExecutors()) { 35 | // 任务队列大小 36 | ioThreadMetric.pendingTasks(); 37 | 38 | // 任务队列最大值 39 | ioThreadMetric.maxPendingTasks(); 40 | 41 | // 线程状态 42 | ioThreadMetric.state(); 43 | 44 | // 线程名称 45 | ioThreadMetric.name(); 46 | } 47 | ``` 48 | -------------------------------------------------------------------------------- /site/content/en/docs-v1.0.1/other_config/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["usage"] 3 | title: "其他功能" 4 | linkTitle: "其他功能" 5 | weight: 70 6 | description: > 7 | `RestClient`支持用户配置请求级别读超时、请求重试、请求重定向、100-expect-continue 等功能。 8 | --- 9 | -------------------------------------------------------------------------------- /site/content/en/docs-v1.0.1/other_config/expect_continue.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["usage"] 3 | title: "100-expect-continue" 4 | linkTitle: "100-expect-continue" 5 | weight: 40 6 | description: > 7 | `RestClient`的`100-expect-continue`功能通过底层的`HttpClient`来实现,可以分别支持 Client 级别 及 Request 级别。默认`100-expect-continue`为false。 8 | --- 9 | ## Client级别`100-expect-continue` 10 | Client级别的`100-expect-continue`将对该Client下的所有 Request 生效,具体配置方式如下: 11 | ```java 12 | final RestClient client = RestClient.create() 13 | .useExpectContinue(true) 14 | .build(); 15 | ``` 16 | 17 | ## Request级别`100-expect-continue` 18 | 当Request设置了`100-expect-continue`,其数据将覆盖Client设置的`100-expect-continue`,具体配置方式如下: 19 | ```java 20 | final String entity = client.get("http://127.0.0.1:8081/") 21 | .disableExpectContinue() 22 | .execute() 23 | .toCompletableFuture() 24 | .get() 25 | .bodyToEntity(String.class); 26 | ``` -------------------------------------------------------------------------------- /site/content/en/docs-v1.0.1/other_config/read_timeout.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["usage"] 3 | title: "读超时" 4 | linkTitle: "读超时" 5 | weight: 10 6 | description: > 7 | `RestClient`的读超时功能通过底层的`HttpClient`来实现,可以分别支持 Client 级别 及 Request 级别。默认读超时为`6000L`。 8 | --- 9 | ## Client级别读超时 10 | Client级别的读超时将对该Client下的所有请求生效,具体配置方式如下: 11 | ```java 12 | final RestClient client = RestClient.create() 13 | .readTimeout(3000L) 14 | .build(); 15 | ``` 16 | 17 | ## Request级别读超时 18 | 当Request设置了读超时,其数据将覆盖Client设置的读超时,具体配置方式如下: 19 | ```java 20 | final RestClient client = RestClient.ofDefault(); 21 | 22 | final String entity = client.get("http://127.0.0.1:8081/") 23 | .readTimeout(3000L) 24 | .execute() 25 | .toCompletableFuture() 26 | .get() 27 | .bodyToEntity(String.class); 28 | ``` -------------------------------------------------------------------------------- /site/content/en/docs-v1.0.1/other_config/redirect.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["usage"] 3 | title: "重定向" 4 | linkTitle: "重定向" 5 | weight: 30 6 | description: > 7 | `RestClient`的重定向功能通过底层的`HttpClient`来实现,可以分别支持 Client 级别 及 Request 级别。默认最大重定向次数为5。 8 | --- 9 | ## Client级别重定向 10 | Client级别的重定向将对该Client下的所有 Request 生效,具体配置方式如下: 11 | ```java 12 | final RestClient client = RestClient.create() 13 | .maxRedirects(3) 14 | .build(); 15 | ``` 16 | 17 | ## Request级别重定向 18 | 当Request设置了重定向次数,其数据将覆盖Client设置的重定向次数,具体配置方式如下: 19 | ```java 20 | final RestClient client = RestClient.ofDefault(); 21 | 22 | final String entity = client.get("http://127.0.0.1:8081/") 23 | .maxRedirects(3) 24 | .execute() 25 | .toCompletableFuture() 26 | .get() 27 | .bodyToEntity(String.class); 28 | ``` -------------------------------------------------------------------------------- /site/content/en/docs-v1.0.1/other_config/retry.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["usage"] 3 | title: "重试" 4 | linkTitle: "重试" 5 | weight: 20 6 | description: > 7 | `RestClient`的重试功能通过底层的`HttpClient`来实现,可以分别支持 Client 级别 及 Request 级别。默认最大重试次数为3。 8 | --- 9 | ## Client级别重试 10 | Client级别的重试将对该Client下的所有 Request 生效,使用时,可以通过自定义`RetryOptions`参数更改重试次数、重试条件、重试间隔时间等。具体配置方式如下: 11 | ```java 12 | final RestClient client = RestClient.create() 13 | .retryOptions(RetryOptions.options() 14 | .maxRetries(3) 15 | .intervalMs(value -> value) 16 | .predicate((request, response, ctx, cause) -> cause != null) 17 | .build()) 18 | .connectionPoolSize(2048) 19 | .build(); 20 | ``` 21 | 22 | ## Request级别重试 23 | 当Request设置了重试次数,其数据将覆盖Client设置的重试次数,具体配置方式如下: 24 | ```java 25 | final RestClient client = RestClient.ofDefault(); 26 | 27 | final String entity = client.get("http://127.0.0.1:8081/") 28 | .maxRetries(3) 29 | .execute() 30 | .toCompletableFuture() 31 | .get() 32 | .bodyToEntity(String.class); 33 | ``` -------------------------------------------------------------------------------- /site/content/en/docs-v1.0.1/process_of_restclient/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["architecture"] 3 | title: "生命周期" 4 | linkTitle: "生命周期" 5 | weight: 90 6 | description: > 7 | `RestClient`中的每个请求都拥有相同的生命周期,了解请求的生命周期便于用户更好地使用`RestClient`。 8 | --- 9 | 10 | ## 生命周期 11 | ![process_of_restclient](../../../img/process_of_restclient.svg) 12 | -------------------------------------------------------------------------------- /site/content/en/docs/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "ESA RestClient" 3 | linkTitle: "ESA RestClient" 4 | weight: 10 5 | description: > 6 | ESA RestClient is an asynchronous event-driven http client based on netty. 7 | --- 8 | ## Features 9 | - Http1/H2/H2cUpgrade 10 | - Https 11 | - Epoll/NIO 12 | - Serialize and Deserialize 13 | - Interceptor 14 | - Filter 15 | - Retry, Redirect, 100-expect-continue 16 | - Segmented read/write 17 | - Multipart 18 | - Metrics 19 | - more features... -------------------------------------------------------------------------------- /site/content/en/docs/codec/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["extension"] 3 | title: "Codec" 4 | linkTitle: "Codec" 5 | weight: 20 6 | description: > 7 | 用户请求时`RestClient`会自动根据用户的 `Headers` 与 `Entity` 自动选择合适的`Decoder`或`Encoder`进行`Decode`或`Encode`。同时`RestClient`也支持用户在`codec`前后进行插入业务逻辑。 8 | --- -------------------------------------------------------------------------------- /site/content/en/docs/dns_ext/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["extension"] 3 | title: "DNS扩展" 4 | linkTitle: "DNS扩展" 5 | weight: 40 6 | description: > 7 | 在每次建立连接前,client可能需要将域名解析成IP地址,`RestClient`通过适配`netty`原生的`AddressResolverGroup`提供了一种更加简单、 8 | 灵活的`NameResolver`扩展,用于将url地址中的域名解析成IP地址。 9 | --- 10 | ## 使用方式 11 | ```java 12 | final RestClient client = RestClient.create().resolver(new HostResolver() { 13 | @Override 14 | public CompletionStage resolve(String inetHost) { 15 | // resolve inetHost 16 | return CompletableFuture.completedFuture(null); 17 | } 18 | }).build(); 19 | ``` 20 | 在构造`RestClient`时传入自定义的`HostResolver`,后续建立连接时会调用`resolve()`方法进行Host地址解析。默认情况下,将使用系统默认的命名服务进行Host解析,详情请查看`SystemDefaultResolver`。 -------------------------------------------------------------------------------- /site/content/en/docs/file_upload_download/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["usage"] 3 | title: "大文件上传" 4 | linkTitle: "大文件上传" 5 | weight: 50 6 | description: > 7 | `RestClient`支持大文件上传功能。**需要说明地是,对于内容较小的文件,可通过直接将文件内容写入请求body。** 本文只讨论当文件内容过大,直接写入有OOM风险时的大文件上传功能。 8 | --- 9 | ## 使用方式 10 | ### 不使用Multipart编码 11 | ```java 12 | final RestClient client = RestClient.ofDefault(); 13 | final String entity = client.post("http://127.0.0.1:8081/") 14 | .entity(new File("aaa")) 15 | .execute() 16 | .toCompletableFuture() 17 | .get() 18 | .bodyToEntity(String.class); 19 | ``` 20 | 如上所示,`RestClient`将分块读取文件内容并将其写入请求body中,对应请求的Content-Type为**application/octet-stream**。该情形适用于单个大文件内容作为原始body内容上传的情况。 21 | 22 | ### 使用Multipart编码 23 | ```java 24 | final RestClient client = RestClient.ofDefault(); 25 | 26 | File file = new File("xxxxx"); 27 | final RestMultipartRequest request = client.post("http://127.0.0.1:9997/file/upload") 28 | .multipart() 29 | .file("file", file) 30 | .attr("name", "Bob") 31 | .attr("address", "China"); 32 | 33 | RestResponseBase response = request 34 | .execute() 35 | .toCompletableFuture() 36 | .get(); 37 | System.out.println(response.status()); 38 | System.out.println(response.bodyToEntity(String.class)); 39 | ``` 40 | 如上所示,`RestClient`将添加的文件和表单参数进行Multipart Encode的结果作为请求的body内容,对应的Content-Type为**multipart/form-data。** 该情形适用于需要进行multipart encode或者存在表单参数的情形。**特别地,如果只上传表单参数,不存在文件时,则可以直接将Content-Type设置为application/x-www-form-urlencoded。** -------------------------------------------------------------------------------- /site/content/en/docs/getting_started/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["example"] 3 | title: "Getting Started" 4 | linkTitle: "Getting Started" 5 | weight: 10 6 | description: > 7 | It's very easy to get started with `RestClient`! 8 | --- 9 | ## Step 1: Add dependency 10 | 11 | ```xml 12 | 13 | io.esastack 14 | restclient 15 | ${esa-restclient.version} 16 | 17 | ``` 18 | 19 | ## Step 2: Send a request and handle response 20 | 21 | ```java 22 | final RestClient client = RestClient.ofDefault(); 23 | 24 | final String entity = client.post("http://127.0.0.1:8081/") 25 | .entity("Hello Server") 26 | .execute() 27 | .toCompletableFuture() 28 | .get() 29 | .bodyToEntity(String.class); 30 | ``` 31 | 32 | {{< alert title="Note" >}} 33 | 执行请求得到的CompletionStage直接由IO线程执行,**请勿在该线程内做其他耗时操作,以免阻塞IO线程**。 34 | {{< /alert >}} 35 | {{< alert title="Note" >}} 36 | `netty` 4.1.52.Final and `tcnative` 2.0.34.Final are directly dependent on. And please make sure the version of `tcnative` matches the version of `netty`. 37 | {{< /alert >}} -------------------------------------------------------------------------------- /site/content/en/docs/interceptor/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["extension"] 3 | title: "Interceptor" 4 | linkTitle: "Interceptor" 5 | weight: 30 6 | description: > 7 | `RestClient`支持通过builder配置和SPI加载两种方式配置`RestInterceptor`。 8 | --- 9 | ## Builder配置 10 | 在构造`RestClient`时传入自定义的`RestInterceptor`实例,如: 11 | ```java 12 | final RestClient client = RestClient.create() 13 | .addInterceptor((request, next) -> { 14 | System.out.println("Interceptor"); 15 | return next.proceed(request); 16 | }).build(); 17 | ``` 18 | {{< alert title="Tip" >}} 19 | 多个拦截器之间通过`getOrder()`方法返回值区分执行顺序,值越小,优先级越高。 20 | {{< /alert >}} 21 | 22 | ## SPI 23 | ### 普通SPI 24 | `RestClient`支持通过Spi的方式加载`RestInterceptor`接口的实现类,使用时只需要按照SPI的加载规则将自定义的`RestInterceptor`放入指定的目录下即可。 25 | ##### RestInterceptorFactory 26 | 如果用户自定义的`RestInterceptor`对于不同`RestClient`的配置有不同的实现,则用户可以实现`RestInterceptorFactory`接口,并按照SPI的加载规则将自定义的`RestInterceptorFactory`放入指定的目录下即可。 27 | ```java 28 | public interface RestInterceptorFactory { 29 | Collection interceptors(RestClientOptions clientOptions); 30 | } 31 | ``` 32 | 在`RestClient`构建时将调用`RestInterceptorFactory.interceptors(RestClientOptions clientOptions)`,该方法返回的所有`RestInterceptor`都将加入到构建好的`RestClient`中。 33 | 34 | ## 执行时机 35 | 见[请求处理完整流程](../process_of_restclient/)中的`RestInterceptor`。 -------------------------------------------------------------------------------- /site/content/en/docs/metrics/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["usage"] 3 | title: "指标统计" 4 | linkTitle: "指标统计" 5 | weight: 80 6 | description: > 7 | `RestClient`提供了IO线程池及连接池的Metric指标统计,使用时通过`RestClient`实例便可直接获取。 8 | --- 9 | 10 | ## 使用方式 11 | ```java 12 | final RestClient client = RestClient.ofDefault(); 13 | 14 | ConnectionPoolMetricProvider connectionPoolMetricProvider = client.connectionPoolMetric(); 15 | ConnectionPoolMetric connectionPoolMetric = connectionPoolMetricProvider.get(InetSocketAddress.createUnresolved("127.0.0.1", 8080)); 16 | 17 | // 连接池配置 18 | connectionPoolMetric.options(); 19 | 20 | // 等待获取连接的请求个数 21 | connectionPoolMetric.pendingAcquireCount(); 22 | 23 | // 活跃连接个数 24 | connectionPoolMetric.active(); 25 | 26 | // 等待获取连接队列最大值 27 | connectionPoolMetric.maxPendingAcquires(); 28 | 29 | // 连接池最大值 30 | connectionPoolMetric.maxSize(); 31 | 32 | IoThreadGroupMetric ioThreadGroupMetric = client.ioThreadsMetric(); 33 | 34 | for (IoThreadMetric ioThreadMetric : ioThreadGroupMetric.childExecutors()) { 35 | // 任务队列大小 36 | ioThreadMetric.pendingTasks(); 37 | 38 | // 任务队列最大值 39 | ioThreadMetric.maxPendingTasks(); 40 | 41 | // 线程状态 42 | ioThreadMetric.state(); 43 | 44 | // 线程名称 45 | ioThreadMetric.name(); 46 | } 47 | ``` 48 | -------------------------------------------------------------------------------- /site/content/en/docs/other_config/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["usage"] 3 | title: "其他功能" 4 | linkTitle: "其他功能" 5 | weight: 70 6 | description: > 7 | `RestClient`支持用户配置请求级别读超时、请求重试、请求重定向、100-expect-continue 等功能。 8 | --- 9 | -------------------------------------------------------------------------------- /site/content/en/docs/other_config/expect_continue.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["usage"] 3 | title: "100-expect-continue" 4 | linkTitle: "100-expect-continue" 5 | weight: 40 6 | description: > 7 | `RestClient`的`100-expect-continue`功能通过底层的`HttpClient`来实现,可以分别支持 Client 级别 及 Request 级别。默认`100-expect-continue`为false。 8 | --- 9 | ## Client级别`100-expect-continue` 10 | Client级别的`100-expect-continue`将对该Client下的所有 Request 生效,具体配置方式如下: 11 | ```java 12 | final RestClient client = RestClient.create() 13 | .useExpectContinue(true) 14 | .build(); 15 | ``` 16 | 17 | ## Request级别`100-expect-continue` 18 | 当Request设置了`100-expect-continue`,其数据将覆盖Client设置的`100-expect-continue`,具体配置方式如下: 19 | ```java 20 | final String entity = client.get("http://127.0.0.1:8081/") 21 | .disableExpectContinue() 22 | .execute() 23 | .toCompletableFuture() 24 | .get() 25 | .bodyToEntity(String.class); 26 | ``` -------------------------------------------------------------------------------- /site/content/en/docs/other_config/read_timeout.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["usage"] 3 | title: "读超时" 4 | linkTitle: "读超时" 5 | weight: 10 6 | description: > 7 | `RestClient`的读超时功能通过底层的`HttpClient`来实现,可以分别支持 Client 级别 及 Request 级别。默认读超时为`6000L`。 8 | --- 9 | ## Client级别读超时 10 | Client级别的读超时将对该Client下的所有请求生效,具体配置方式如下: 11 | ```java 12 | final RestClient client = RestClient.create() 13 | .readTimeout(3000L) 14 | .build(); 15 | ``` 16 | 17 | ## Request级别读超时 18 | 当Request设置了读超时,其数据将覆盖Client设置的读超时,具体配置方式如下: 19 | ```java 20 | final RestClient client = RestClient.ofDefault(); 21 | 22 | final String entity = client.get("http://127.0.0.1:8081/") 23 | .readTimeout(3000L) 24 | .execute() 25 | .toCompletableFuture() 26 | .get() 27 | .bodyToEntity(String.class); 28 | ``` -------------------------------------------------------------------------------- /site/content/en/docs/other_config/redirect.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["usage"] 3 | title: "重定向" 4 | linkTitle: "重定向" 5 | weight: 30 6 | description: > 7 | `RestClient`的重定向功能通过底层的`HttpClient`来实现,可以分别支持 Client 级别 及 Request 级别。默认最大重定向次数为5。 8 | --- 9 | ## Client级别重定向 10 | Client级别的重定向将对该Client下的所有 Request 生效,具体配置方式如下: 11 | ```java 12 | final RestClient client = RestClient.create() 13 | .maxRedirects(3) 14 | .build(); 15 | ``` 16 | 17 | ## Request级别重定向 18 | 当Request设置了重定向次数,其数据将覆盖Client设置的重定向次数,具体配置方式如下: 19 | ```java 20 | final RestClient client = RestClient.ofDefault(); 21 | 22 | final String entity = client.get("http://127.0.0.1:8081/") 23 | .maxRedirects(3) 24 | .execute() 25 | .toCompletableFuture() 26 | .get() 27 | .bodyToEntity(String.class); 28 | ``` -------------------------------------------------------------------------------- /site/content/en/docs/other_config/retry.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["usage"] 3 | title: "重试" 4 | linkTitle: "重试" 5 | weight: 20 6 | description: > 7 | `RestClient`的重试功能通过底层的`HttpClient`来实现,可以分别支持 Client 级别 及 Request 级别。默认最大重试次数为3。 8 | --- 9 | ## Client级别重试 10 | Client级别的重试将对该Client下的所有 Request 生效,使用时,可以通过自定义`RetryOptions`参数更改重试次数、重试条件、重试间隔时间等。具体配置方式如下: 11 | ```java 12 | final RestClient client = RestClient.create() 13 | .retryOptions(RetryOptions.options() 14 | .maxRetries(3) 15 | .intervalMs(value -> value) 16 | .predicate((request, response, ctx, cause) -> cause != null) 17 | .build()) 18 | .connectionPoolSize(2048) 19 | .build(); 20 | ``` 21 | 22 | ## Request级别重试 23 | 当Request设置了重试次数,其数据将覆盖Client设置的重试次数,具体配置方式如下: 24 | ```java 25 | final RestClient client = RestClient.ofDefault(); 26 | 27 | final String entity = client.get("http://127.0.0.1:8081/") 28 | .maxRetries(3) 29 | .execute() 30 | .toCompletableFuture() 31 | .get() 32 | .bodyToEntity(String.class); 33 | ``` -------------------------------------------------------------------------------- /site/content/en/docs/process_of_restclient/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["architecture"] 3 | title: "生命周期" 4 | linkTitle: "生命周期" 5 | weight: 90 6 | description: > 7 | `RestClient`中的每个请求都拥有相同的生命周期,了解请求的生命周期便于用户更好地使用`RestClient`。 8 | --- 9 | 10 | ## 生命周期 11 | ![process_of_restclient](../../../img/process_of_restclient.svg) 12 | -------------------------------------------------------------------------------- /site/content/en/featured-background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/featured-background.jpg -------------------------------------------------------------------------------- /site/content/en/img/architecture/arc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/img/architecture/arc.png -------------------------------------------------------------------------------- /site/content/en/img/architecture/decode_advice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/img/architecture/decode_advice.png -------------------------------------------------------------------------------- /site/content/en/img/architecture/decoder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/img/architecture/decoder.png -------------------------------------------------------------------------------- /site/content/en/img/architecture/encode_advice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/img/architecture/encode_advice.png -------------------------------------------------------------------------------- /site/content/en/img/architecture/encoder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/img/architecture/encoder.png -------------------------------------------------------------------------------- /site/content/en/img/architecture/esa_stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/img/architecture/esa_stack.png -------------------------------------------------------------------------------- /site/content/en/img/architecture/fast_thread_local.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/img/architecture/fast_thread_local.png -------------------------------------------------------------------------------- /site/content/en/img/architecture/init_netty_transceiver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/img/architecture/init_netty_transceiver.png -------------------------------------------------------------------------------- /site/content/en/img/architecture/interceptor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/img/architecture/interceptor.png -------------------------------------------------------------------------------- /site/content/en/img/architecture/netty_transceiver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/img/architecture/netty_transceiver.png -------------------------------------------------------------------------------- /site/content/en/img/architecture/optimized_arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/img/architecture/optimized_arch.png -------------------------------------------------------------------------------- /site/content/en/img/architecture/optimized_thread_model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/img/architecture/optimized_thread_model.png -------------------------------------------------------------------------------- /site/content/en/img/architecture/perf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/img/architecture/perf.png -------------------------------------------------------------------------------- /site/content/en/img/architecture/receive_data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/img/architecture/receive_data.png -------------------------------------------------------------------------------- /site/content/en/img/architecture/send_request.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/img/architecture/send_request.png -------------------------------------------------------------------------------- /site/content/en/img/architecture/thread_local.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/img/architecture/thread_local.png -------------------------------------------------------------------------------- /site/content/en/img/architecture/thread_model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/img/architecture/thread_model.png -------------------------------------------------------------------------------- /site/content/en/img/conf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/img/conf.png -------------------------------------------------------------------------------- /site/content/en/img/ping_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/content/en/img/ping_result.png -------------------------------------------------------------------------------- /site/content/en/search.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Search Results 3 | layout: search 4 | 5 | --- 6 | 7 | -------------------------------------------------------------------------------- /site/layouts/404.html: -------------------------------------------------------------------------------- 1 | {{ define "main"}} 2 |
3 |
4 |

Not found

5 |

Oops! This page doesn't exist. Try going back to our home page.

6 | 7 |

You can learn how to make a 404 page like this in Custom 404 Pages.

8 |
9 |
10 | {{ end }} 11 | -------------------------------------------------------------------------------- /site/layouts/docs-v0.1.0/baseof.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ partial "head.html" . }} 5 | 6 | 7 |
8 | {{ partial "navbar-docs.html" . }} 9 |
10 |
11 |
12 |
13 | 16 | 21 |
22 | {{ partial "version-banner.html" . }} 23 | {{ if not .Site.Params.ui.breadcrumb_disable }}{{ partial "breadcrumb.html" . }}{{ end }} 24 | {{ block "main" . }}{{ end }} 25 |
26 |
27 |
28 | {{ partial "footer.html" . }} 29 |
30 | {{ partial "scripts.html" . }} 31 | 32 | -------------------------------------------------------------------------------- /site/layouts/docs-v0.1.0/baseof.print.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ partial "head.html" . }} 5 | 6 | 7 |
8 | {{ partial "navbar.html" . }} 9 |
10 |
11 |
12 |
13 |
14 | {{ block "main" . }}{{ end }} 15 |
16 |
17 |
18 | {{ partial "footer.html" . }} 19 |
20 | {{ partial "scripts.html" . }} 21 | 22 | 23 | -------------------------------------------------------------------------------- /site/layouts/docs-v0.1.0/list.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |
3 |

{{ .Title }}

4 | {{ with .Params.description }}
{{ . | markdownify }}
{{ end }} 5 | 20 | {{ .Content }} 21 | {{ partial "section-index.html" . }} 22 | {{ if (and (not .Params.hide_feedback) (.Site.Params.ui.feedback.enable) (.Site.GoogleAnalytics)) }} 23 | {{ partial "feedback.html" .Site.Params.ui.feedback }} 24 |
25 | {{ end }} 26 | {{ if (.Site.DisqusShortname) }} 27 |
28 | {{ partial "disqus-comment.html" . }} 29 | {{ end }} 30 | {{ partial "page-meta-lastmod.html" . }} 31 |
32 | {{ end }} 33 | -------------------------------------------------------------------------------- /site/layouts/docs-v0.1.0/list.print.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{ partial "print/render" . }} 3 | {{ end }} 4 | -------------------------------------------------------------------------------- /site/layouts/docs-v0.1.0/single.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{ .Render "content" }} 3 | {{ end }} -------------------------------------------------------------------------------- /site/layouts/docs-v1.0.1/baseof.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ partial "head.html" . }} 5 | 6 | 7 |
8 | {{ partial "navbar-docs.html" . }} 9 |
10 |
11 |
12 |
13 | 16 | 21 |
22 | {{ partial "version-banner.html" . }} 23 | {{ if not .Site.Params.ui.breadcrumb_disable }}{{ partial "breadcrumb.html" . }}{{ end }} 24 | {{ block "main" . }}{{ end }} 25 |
26 |
27 |
28 | {{ partial "footer.html" . }} 29 |
30 | {{ partial "scripts.html" . }} 31 | 32 | -------------------------------------------------------------------------------- /site/layouts/docs-v1.0.1/baseof.print.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ partial "head.html" . }} 5 | 6 | 7 |
8 | {{ partial "navbar.html" . }} 9 |
10 |
11 |
12 |
13 |
14 | {{ block "main" . }}{{ end }} 15 |
16 |
17 |
18 | {{ partial "footer.html" . }} 19 |
20 | {{ partial "scripts.html" . }} 21 | 22 | 23 | -------------------------------------------------------------------------------- /site/layouts/docs-v1.0.1/list.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |
3 |

{{ .Title }}

4 | {{ with .Params.description }}
{{ . | markdownify }}
{{ end }} 5 | 20 | {{ .Content }} 21 | {{ partial "section-index.html" . }} 22 | {{ if (and (not .Params.hide_feedback) (.Site.Params.ui.feedback.enable) (.Site.GoogleAnalytics)) }} 23 | {{ partial "feedback.html" .Site.Params.ui.feedback }} 24 |
25 | {{ end }} 26 | {{ if (.Site.DisqusShortname) }} 27 |
28 | {{ partial "disqus-comment.html" . }} 29 | {{ end }} 30 | {{ partial "page-meta-lastmod.html" . }} 31 |
32 | {{ end }} 33 | -------------------------------------------------------------------------------- /site/layouts/docs-v1.0.1/list.print.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{ partial "print/render" . }} 3 | {{ end }} 4 | -------------------------------------------------------------------------------- /site/layouts/docs-v1.0.1/single.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{ .Render "content" }} 3 | {{ end }} -------------------------------------------------------------------------------- /site/layouts/docs/baseof.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ partial "head.html" . }} 5 | 6 | 7 |
8 | {{ partial "navbar-docs.html" . }} 9 |
10 |
11 |
12 |
13 | 16 | 21 |
22 | {{ partial "version-banner.html" . }} 23 | {{ if not .Site.Params.ui.breadcrumb_disable }}{{ partial "breadcrumb.html" . }}{{ end }} 24 | {{ block "main" . }}{{ end }} 25 |
26 |
27 |
28 | {{ partial "footer.html" . }} 29 |
30 | {{ partial "scripts.html" . }} 31 | 32 | -------------------------------------------------------------------------------- /site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tech-doc-hugo", 3 | "version": "0.0.1", 4 | "description": "Hugo theme for technical documentation.", 5 | "main": "none.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/google/docsy-example.git" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/google/docsy-example/issues" 17 | }, 18 | "homepage": "https://github.com/google/docsy-example#readme", 19 | "devDependencies": { 20 | "autoprefixer": "^10.4.2", 21 | "hugo-extended": "^0.92.2", 22 | "postcss": "^8.4.6", 23 | "postcss-cli": "^9.1.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /site/static/favicons/android-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/static/favicons/android-144x144.png -------------------------------------------------------------------------------- /site/static/favicons/android-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/static/favicons/android-192x192.png -------------------------------------------------------------------------------- /site/static/favicons/android-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/static/favicons/android-36x36.png -------------------------------------------------------------------------------- /site/static/favicons/android-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/static/favicons/android-48x48.png -------------------------------------------------------------------------------- /site/static/favicons/android-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/static/favicons/android-72x72.png -------------------------------------------------------------------------------- /site/static/favicons/android-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/static/favicons/android-96x96.png -------------------------------------------------------------------------------- /site/static/favicons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/static/favicons/apple-touch-icon.png -------------------------------------------------------------------------------- /site/static/favicons/favicon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/static/favicons/favicon-128x128.png -------------------------------------------------------------------------------- /site/static/favicons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/static/favicons/favicon-16x16.png -------------------------------------------------------------------------------- /site/static/favicons/favicon-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/static/favicons/favicon-256x256.png -------------------------------------------------------------------------------- /site/static/favicons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/static/favicons/favicon-32x32.png -------------------------------------------------------------------------------- /site/static/favicons/favicon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/static/favicons/favicon-48x48.png -------------------------------------------------------------------------------- /site/static/favicons/favicon-64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/static/favicons/favicon-64x64.png -------------------------------------------------------------------------------- /site/static/favicons/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/static/favicons/favicon-96x96.png -------------------------------------------------------------------------------- /site/static/favicons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/static/favicons/favicon.ico -------------------------------------------------------------------------------- /site/static/favicons/tile150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/static/favicons/tile150x150.png -------------------------------------------------------------------------------- /site/static/favicons/tile310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/static/favicons/tile310x150.png -------------------------------------------------------------------------------- /site/static/favicons/tile310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/static/favicons/tile310x310.png -------------------------------------------------------------------------------- /site/static/favicons/tile70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esastack/esa-restclient/748df72dd71946113adbfd384f7dc58d13dddfc1/site/static/favicons/tile70x70.png --------------------------------------------------------------------------------