This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch backport/29843-to-camel-4-18-x in repository https://gitbox.apache.org/repos/asf/camel.git
commit d5eef20a067169b465cd0c1634e624813e119e5c Author: Vignesh Nayak Manel <[email protected]> AuthorDate: Fri Oct 30 03:00:50 2026 +0530 CAMEL-26130: camel-oaipmh - the CamelOaimphOnlyFirst and CamelOaimphIgnoreSSLWarnings headers apply to their exchange only (#28690) The producer wrote both headers onto the shared endpoint, so one exchange with CamelOaimphOnlyFirst=true made every later exchange return only the first page, and one with CamelOaimphIgnoreSSLWarnings=true made every later exchange accept a self-signed certificate. The headers are now read for the exchange only. Co-Authored-By: Claude Opus 5.5 <[email protected]> (cherry picked from commit 00f66540c4ce9e24b483c2fc622fab13756db4db) Signed-off-by: Claus Ibsen <[email protected]> --- .../camel/oaipmh/component/OAIPMHProducer.java | 18 ++-- .../OAIPMHProducerHeadersPerExchangeTest.java | 112 +++++++++++++++++++++ 2 files changed, 124 insertions(+), 6 deletions(-) diff --git a/components/camel-oaipmh/src/main/java/org/apache/camel/oaipmh/component/OAIPMHProducer.java b/components/camel-oaipmh/src/main/java/org/apache/camel/oaipmh/component/OAIPMHProducer.java index a7fdf84cd88f..7ba958f02be3 100644 --- a/components/camel-oaipmh/src/main/java/org/apache/camel/oaipmh/component/OAIPMHProducer.java +++ b/components/camel-oaipmh/src/main/java/org/apache/camel/oaipmh/component/OAIPMHProducer.java @@ -50,13 +50,16 @@ public class OAIPMHProducer extends DefaultProducer { endpoint.getFrom(), endpoint.getSet(), endpoint.getIdentifier()); - overrideHarvesterConfigs(exchange.getIn(), harvester); - if (endpoint.isIgnoreSSLWarnings()) { + Message msg = exchange.getIn(); + overrideHarvesterConfigs(msg, harvester); + // the headers apply to this exchange only, the endpoint is shared by all exchanges + boolean onlyFirst = getBooleanHeader(msg, OAIPMHConstants.ONLY_FIRST, endpoint.isOnlyFirst()); + if (getBooleanHeader(msg, OAIPMHConstants.IGNORE_SSL_WARNINGS, endpoint.isIgnoreSSLWarnings())) { harvester.getHttpClient().setIgnoreSSLWarnings(true); } - List<String> synHarvest = harvester.synHarvest(endpoint.isOnlyFirst()); + List<String> synHarvest = harvester.synHarvest(onlyFirst); exchange.getMessage().setBody(synHarvest); - if (endpoint.isOnlyFirst() && harvester.getResumptionToken() != null) { + if (onlyFirst && harvester.getResumptionToken() != null) { exchange.getMessage().setHeader(OAIPMHConstants.RESUMPTION_TOKEN, harvester.getResumptionToken()); } else { exchange.getMessage().removeHeader(OAIPMHConstants.RESUMPTION_TOKEN); @@ -73,8 +76,11 @@ public class OAIPMHProducer extends DefaultProducer { checkAndSetConfigs(msg, OAIPMHConstants.SET, harvester::setSet, String.class); checkAndSetConfigs(msg, OAIPMHConstants.IDENTIFIER, harvester::setIdentifier, String.class); checkAndSetConfigs(msg, OAIPMHConstants.RESUMPTION_TOKEN, harvester::setResumptionToken, String.class); - checkAndSetConfigs(msg, OAIPMHConstants.ONLY_FIRST, endpoint::setOnlyFirst, Boolean.class); - checkAndSetConfigs(msg, OAIPMHConstants.IGNORE_SSL_WARNINGS, endpoint::setIgnoreSSLWarnings, Boolean.class); + } + + private static boolean getBooleanHeader(Message message, String key, boolean defaultValue) { + Boolean header = message.getHeader(key, Boolean.class); + return header != null ? header : defaultValue; } private <T> void checkAndSetConfigs(final Message message, final String key, final Consumer<T> fn, final Class<T> type) { diff --git a/components/camel-oaipmh/src/test/java/org/apache/camel/oaipmh/OAIPMHProducerHeadersPerExchangeTest.java b/components/camel-oaipmh/src/test/java/org/apache/camel/oaipmh/OAIPMHProducerHeadersPerExchangeTest.java new file mode 100644 index 000000000000..7b607557b644 --- /dev/null +++ b/components/camel-oaipmh/src/test/java/org/apache/camel/oaipmh/OAIPMHProducerHeadersPerExchangeTest.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.oaipmh; + +import java.util.List; + +import javax.net.ssl.SSLException; + +import org.apache.camel.CamelExecutionException; +import org.apache.camel.oaipmh.component.OAIPMHEndpoint; +import org.apache.camel.oaipmh.component.model.OAIPMHConstants; +import org.apache.camel.oaipmh.utils.MockOaipmhServer; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * The CamelOaimphOnlyFirst and CamelOaimphIgnoreSSLWarnings headers apply to the exchange that has them, not to the + * later exchanges sent to the same (shared) endpoint. + */ +class OAIPMHProducerHeadersPerExchangeTest extends CamelTestSupport { + + private static MockOaipmhServer mockOaipmhServer; + + @BeforeAll + static void startServer() { + mockOaipmhServer = MockOaipmhServer.create(); + mockOaipmhServer.start(); + } + + @AfterAll + static void stopServer() { + mockOaipmhServer.stop(); + } + + @Test + void onlyFirstHeaderAppliesToItsExchangeOnly() { + String uri = "oaipmh://localhost:" + mockOaipmhServer.getHttpPort() + "/oai/request?from=2020-06-01T00:00:00Z"; + + List<?> allPages = template.requestBody(uri, null, List.class); + List<?> firstPage = template.requestBodyAndHeader(uri, null, OAIPMHConstants.ONLY_FIRST, true, List.class); + List<?> nextAllPages = template.requestBody(uri, null, List.class); + + assertTrue(allPages.size() > 1, "all the pages: " + allPages.size()); + assertEquals(1, firstPage.size()); + assertEquals(allPages.size(), nextAllPages.size(), "an exchange without the header harvests all the pages"); + assertFalse(context.getEndpoint(uri, OAIPMHEndpoint.class).isOnlyFirst()); + } + + @Test + void onlyFirstHeaderFalseOverridesTheEndpointOption() { + String uri = "oaipmh://localhost:" + mockOaipmhServer.getHttpPort() + + "/oai/request?from=2020-06-01T00:00:00Z&onlyFirst=true"; + + List<?> allPages = template.requestBodyAndHeader(uri, null, OAIPMHConstants.ONLY_FIRST, false, List.class); + List<?> firstPage = template.requestBody(uri, null, List.class); + + assertTrue(allPages.size() > 1, "a header of false harvests all the pages: " + allPages.size()); + assertEquals(1, firstPage.size(), "an exchange without the header uses the endpoint option"); + assertTrue(context.getEndpoint(uri, OAIPMHEndpoint.class).isOnlyFirst()); + } + + @Test + void ignoreSSLWarningsHeaderFalseOverridesTheEndpointOption() { + String uri = "oaipmh://localhost:" + mockOaipmhServer.getHttpsPort() + + "/oai/request?ssl=true&verb=Identify&ignoreSSLWarnings=true"; + + CamelExecutionException e = assertThrows(CamelExecutionException.class, + () -> template.requestBodyAndHeader(uri, null, OAIPMHConstants.IGNORE_SSL_WARNINGS, false, List.class), + "a header of false rejects the self-signed certificate"); + assertInstanceOf(SSLException.class, e.getCause(), "cause: " + e.getCause()); + + List<?> identify = template.requestBody(uri, null, List.class); + assertEquals(1, identify.size(), "an exchange without the header uses the endpoint option"); + assertTrue(context.getEndpoint(uri, OAIPMHEndpoint.class).isIgnoreSSLWarnings()); + } + + @Test + void ignoreSSLWarningsHeaderAppliesToItsExchangeOnly() { + String uri = "oaipmh://localhost:" + mockOaipmhServer.getHttpsPort() + "/oai/request?ssl=true&verb=Identify"; + + List<?> identify = template.requestBodyAndHeader(uri, null, OAIPMHConstants.IGNORE_SSL_WARNINGS, true, List.class); + assertEquals(1, identify.size()); + + CamelExecutionException e = assertThrows(CamelExecutionException.class, + () -> template.requestBody(uri, null, List.class), + "the self-signed certificate is rejected for an exchange without the header"); + assertInstanceOf(SSLException.class, e.getCause(), "cause: " + e.getCause()); + assertFalse(context.getEndpoint(uri, OAIPMHEndpoint.class).isIgnoreSSLWarnings()); + } +}
