From 2db7b80dcecd98977a510f385ad4cc56c805c500 Mon Sep 17 00:00:00 2001 From: Philip Helger Date: Fri, 10 Dec 2021 20:03:50 +0100 Subject: [PATCH] Fix Servlet processing --- .../receiver/net/AS2MDNReceiverHandler.java | 4 +- .../receiver/net/AS2ReceiverHandler.java | 4 +- .../AS2HttpRequestDataProviderSocket.java | 197 ++++++++++++++++++ .../http/AS2InputStreamProviderSocket.java | 86 -------- .../helger/as2lib/util/http/HTTPHelper.java | 106 ++-------- ....java => IAS2HttpRequestDataProvider.java} | 34 ++- .../main/MainSendToLocalhost8080.java | 2 +- .../as2lib/util/http/HTTPHelperTest.java | 32 +-- ...va => MockAS2HttpRequestDataProvider.java} | 36 +++- ...ttpRequestDataProviderServletRequest.java} | 46 +++- ...AbstractAS2ReceiveBaseXServletHandler.java | 2 +- 11 files changed, 345 insertions(+), 204 deletions(-) create mode 100644 as2-lib/src/main/java/com/helger/as2lib/util/http/AS2HttpRequestDataProviderSocket.java delete mode 100644 as2-lib/src/main/java/com/helger/as2lib/util/http/AS2InputStreamProviderSocket.java rename as2-lib/src/main/java/com/helger/as2lib/util/http/{IAS2InputStreamProvider.java => IAS2HttpRequestDataProvider.java} (72%) rename as2-lib/src/test/java/com/helger/as2lib/util/http/{MockAS2InputStreamProvider.java => MockAS2HttpRequestDataProvider.java} (72%) rename as2-servlet/src/main/java/com/helger/as2servlet/{AS2InputStreamProviderServletRequest.java => AS2HttpRequestDataProviderServletRequest.java} (68%) diff --git a/as2-lib/src/main/java/com/helger/as2lib/processor/receiver/net/AS2MDNReceiverHandler.java b/as2-lib/src/main/java/com/helger/as2lib/processor/receiver/net/AS2MDNReceiverHandler.java index 268a0a78..f94cb420 100644 --- a/as2-lib/src/main/java/com/helger/as2lib/processor/receiver/net/AS2MDNReceiverHandler.java +++ b/as2-lib/src/main/java/com/helger/as2lib/processor/receiver/net/AS2MDNReceiverHandler.java @@ -72,7 +72,7 @@ import com.helger.as2lib.util.dump.IHTTPIncomingDumper; import com.helger.as2lib.util.http.AS2HttpClient; import com.helger.as2lib.util.http.AS2HttpResponseHandlerSocket; -import com.helger.as2lib.util.http.AS2InputStreamProviderSocket; +import com.helger.as2lib.util.http.AS2HttpRequestDataProviderSocket; import com.helger.as2lib.util.http.HTTPHelper; import com.helger.as2lib.util.http.IAS2HttpResponseHandler; import com.helger.as2lib.util.http.IAS2IncomingMDNCallback; @@ -523,7 +523,7 @@ public void handle (@Nonnull final AbstractActiveNetModule aOwner, @Nonnull fina { // Read in the message request, headers, and data final IHTTPIncomingDumper aIncomingDumper = getEffectiveHttpIncomingDumper (); - aMdnDataSource = HTTPHelper.readAndDecodeHttpRequest (new AS2InputStreamProviderSocket (aSocket), + aMdnDataSource = HTTPHelper.readAndDecodeHttpRequest (new AS2HttpRequestDataProviderSocket (aSocket), aResponseHandler, aMsg, aIncomingDumper); diff --git a/as2-lib/src/main/java/com/helger/as2lib/processor/receiver/net/AS2ReceiverHandler.java b/as2-lib/src/main/java/com/helger/as2lib/processor/receiver/net/AS2ReceiverHandler.java index 9bdc790b..43d48b3d 100644 --- a/as2-lib/src/main/java/com/helger/as2lib/processor/receiver/net/AS2ReceiverHandler.java +++ b/as2-lib/src/main/java/com/helger/as2lib/processor/receiver/net/AS2ReceiverHandler.java @@ -79,7 +79,7 @@ import com.helger.as2lib.util.AS2ResourceHelper; import com.helger.as2lib.util.dump.IHTTPIncomingDumper; import com.helger.as2lib.util.http.AS2HttpResponseHandlerSocket; -import com.helger.as2lib.util.http.AS2InputStreamProviderSocket; +import com.helger.as2lib.util.http.AS2HttpRequestDataProviderSocket; import com.helger.as2lib.util.http.HTTPHelper; import com.helger.as2lib.util.http.IAS2HttpResponseHandler; import com.helger.as2lib.util.http.TempSharedFileInputStream; @@ -744,7 +744,7 @@ public void handle (@Nonnull final AbstractActiveNetModule aOwner, @Nonnull fina { // Read in the message request, headers, and data final IHTTPIncomingDumper aIncomingDumper = getEffectiveHttpIncomingDumper (); - aMsgDataSource = HTTPHelper.readAndDecodeHttpRequest (new AS2InputStreamProviderSocket (aSocket), + aMsgDataSource = HTTPHelper.readAndDecodeHttpRequest (new AS2HttpRequestDataProviderSocket (aSocket), aResponseHandler, aMsg, aIncomingDumper); diff --git a/as2-lib/src/main/java/com/helger/as2lib/util/http/AS2HttpRequestDataProviderSocket.java b/as2-lib/src/main/java/com/helger/as2lib/util/http/AS2HttpRequestDataProviderSocket.java new file mode 100644 index 00000000..1827aa2d --- /dev/null +++ b/as2-lib/src/main/java/com/helger/as2lib/util/http/AS2HttpRequestDataProviderSocket.java @@ -0,0 +1,197 @@ +/* + * The FreeBSD Copyright + * Copyright 1994-2008 The FreeBSD Project. All rights reserved. + * Copyright (C) 2013-2021 Philip Helger philip[at]helger[dot]com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies, either expressed or implied, of the FreeBSD Project. + */ +package com.helger.as2lib.util.http; + +import java.io.IOException; +import java.io.InputStream; +import java.net.Socket; +import java.util.Enumeration; +import java.util.StringTokenizer; + +import javax.annotation.Nonnull; +import javax.annotation.WillNotClose; +import javax.annotation.concurrent.Immutable; +import javax.mail.Header; +import javax.mail.MessagingException; +import javax.mail.internet.InternetHeaders; + +import com.helger.commons.ValueEnforcer; +import com.helger.commons.annotation.Nonempty; +import com.helger.commons.http.HttpHeaderMap; +import com.helger.commons.io.stream.NonClosingInputStream; +import com.helger.commons.io.stream.StreamHelper; + +/** + * Implementation of {@link IAS2HttpRequestDataProvider} based on a + * {@link Socket} {@link InputStream}. + * + * @author Philip Helger + */ +@Immutable +public class AS2HttpRequestDataProviderSocket implements IAS2HttpRequestDataProvider +{ + @WillNotClose + private final InputStream m_aSocketIS; + private final String m_sHttpRequestMethod; + private final String m_sHttpRequestUrl; + private final String m_sHttpRequestVersion; + private final HttpHeaderMap m_aHttpHeaders = new HttpHeaderMap (); + + /** + * Read the first line of the HTTP request InputStream and parse out HTTP + * method (e.g. "GET" or "POST"), request URL (e.g "/as2") and HTTP version + * (e.g. "HTTP/1.1") + * + * @param aIS + * Stream to read the first line from + * @return An array with 3 elements, containing method, URL and HTTP version + * @throws IOException + * In case of IO error + */ + @Nonnull + @Nonempty + private static String [] _readRequestInfo (@Nonnull final InputStream aIS) throws IOException + { + int nByteBuf = aIS.read (); + final StringBuilder aSB = new StringBuilder (); + while (nByteBuf != -1 && nByteBuf != '\r') + { + aSB.append ((char) nByteBuf); + nByteBuf = aIS.read (); + } + if (nByteBuf != -1) + { + // read in the \n following the "\r" + aIS.read (); + } + + final StringTokenizer aTokens = new StringTokenizer (aSB.toString (), " "); + final int nTokenCount = aTokens.countTokens (); + if (nTokenCount >= 3) + { + // Return all tokens + final String [] aRequestParts = new String [nTokenCount]; + for (int i = 0; i < nTokenCount; i++) + aRequestParts[i] = aTokens.nextToken (); + return aRequestParts; + } + + if (nTokenCount == 2) + { + // Default the request URL to "/" + final String [] aRequestParts = new String [3]; + aRequestParts[0] = aTokens.nextToken (); + aRequestParts[1] = "/"; + aRequestParts[2] = aTokens.nextToken (); + return aRequestParts; + } + throw new IOException ("Invalid HTTP Request (" + aSB.toString () + ")"); + } + + /** + * Constructor + * + * @param aSocket + * Socket to read from. May not be null. + * @throws IOException + * If reading from the Socket fails + * @throws MessagingException + * If reading the HTTP headers failed + */ + public AS2HttpRequestDataProviderSocket (@Nonnull final Socket aSocket) throws IOException, MessagingException + { + ValueEnforcer.notNull (aSocket, "Socket"); + + m_aSocketIS = aSocket.getInputStream (); + + // Read the HTTP meta data first line + final String [] aRequest = _readRequestInfo (m_aSocketIS); + m_sHttpRequestMethod = aRequest[0]; + m_sHttpRequestUrl = aRequest[1]; + m_sHttpRequestVersion = aRequest[2]; + + // Read the HTTP headers next + // Parse all HTTP headers from stream + final InternetHeaders aHeaders = new InternetHeaders (m_aSocketIS); + // Convert to header map + final Enumeration
aEnum = aHeaders.getAllHeaders (); + while (aEnum.hasMoreElements ()) + { + final Header aHeader = aEnum.nextElement (); + m_aHttpHeaders.addHeader (aHeader.getName (), aHeader.getValue ()); + } + + } + + /** + * Will return a buffered, {@link NonClosingInputStream} that when closed, + * will not close in source stream. This is useful when working with + * java.net.SocketInputStream as close() on a socket stream + * closes the {@link Socket} + * + * @return {@link InputStream} + * @throws IOException + * in case of error + */ + @Nonnull + public InputStream getHttpInputStream () throws IOException + { + // Use "NonClosing" internally to that the returned stream is easily + // discovered as "buffered" + return StreamHelper.getBuffered (new NonClosingInputStream (m_aSocketIS)); + } + + @Nonnull + public String getHttpRequestMethod () + { + return m_sHttpRequestMethod; + } + + @Nonnull + public String getHttpRequestUrl () + { + return m_sHttpRequestUrl; + } + + @Nonnull + public String getHttpRequestVersion () + { + return m_sHttpRequestVersion; + } + + @Nonnull + public HttpHeaderMap getHttpHeaderMap () + { + return m_aHttpHeaders; + } +} diff --git a/as2-lib/src/main/java/com/helger/as2lib/util/http/AS2InputStreamProviderSocket.java b/as2-lib/src/main/java/com/helger/as2lib/util/http/AS2InputStreamProviderSocket.java deleted file mode 100644 index a87513da..00000000 --- a/as2-lib/src/main/java/com/helger/as2lib/util/http/AS2InputStreamProviderSocket.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * The FreeBSD Copyright - * Copyright 1994-2008 The FreeBSD Project. All rights reserved. - * Copyright (C) 2013-2021 Philip Helger philip[at]helger[dot]com - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies, either expressed or implied, of the FreeBSD Project. - */ -package com.helger.as2lib.util.http; - -import java.io.IOException; -import java.io.InputStream; -import java.net.Socket; - -import javax.annotation.Nonnull; -import javax.annotation.concurrent.Immutable; - -import com.helger.commons.ValueEnforcer; -import com.helger.commons.io.stream.NonClosingInputStream; -import com.helger.commons.io.stream.StreamHelper; - -/** - * Implementation of {@link IAS2InputStreamProvider} based on a {@link Socket} - * {@link InputStream}. - * - * @author Philip Helger - */ -@Immutable -public class AS2InputStreamProviderSocket implements IAS2InputStreamProvider -{ - private final Socket m_aSocket; - - /** - * Constructor - * - * @param aSocket - * Socket to read from. May not be null. - */ - public AS2InputStreamProviderSocket (@Nonnull final Socket aSocket) - { - ValueEnforcer.notNull (aSocket, "Socket"); - m_aSocket = aSocket; - } - - /** - * Will return a buffered, {@link NonClosingInputStream} that when closed, - * will not close in source stream. This is useful when working with - * java.net.SocketInputStream as close() on a socket stream - * closes the {@link Socket} - * - * @return {@link InputStream} - * @throws IOException - * in case of error - */ - @Nonnull - public InputStream getInputStream () throws IOException - { - // Use "NonClosing" internally to that the returned stream is easily - // discovered as "buffered" - return StreamHelper.getBuffered (new NonClosingInputStream (m_aSocket.getInputStream ())); - } -} diff --git a/as2-lib/src/main/java/com/helger/as2lib/util/http/HTTPHelper.java b/as2-lib/src/main/java/com/helger/as2lib/util/http/HTTPHelper.java index 513c2525..d75aa246 100644 --- a/as2-lib/src/main/java/com/helger/as2lib/util/http/HTTPHelper.java +++ b/as2-lib/src/main/java/com/helger/as2lib/util/http/HTTPHelper.java @@ -38,8 +38,6 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; -import java.util.Enumeration; -import java.util.StringTokenizer; import java.util.function.Supplier; import javax.activation.DataSource; @@ -49,9 +47,7 @@ import javax.annotation.WillNotClose; import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.ThreadSafe; -import javax.mail.Header; import javax.mail.MessagingException; -import javax.mail.internet.InternetHeaders; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -63,7 +59,6 @@ import com.helger.as2lib.util.dump.HTTPIncomingDumperDirectoryBased; import com.helger.as2lib.util.dump.IHTTPIncomingDumper; import com.helger.commons.ValueEnforcer; -import com.helger.commons.annotation.Nonempty; import com.helger.commons.annotation.ReturnsMutableCopy; import com.helger.commons.codec.IByteArrayCodec; import com.helger.commons.codec.IdentityCodec; @@ -136,66 +131,13 @@ private HTTPHelper () @Nonnull @ReturnsMutableCopy - public static ICommonsList getAllHTTPHeaderLines (@Nonnull final InternetHeaders aHeaders) + public static ICommonsList getAllHTTPHeaderLines (@Nonnull final HttpHeaderMap aHeaders) { final ICommonsList ret = new CommonsArrayList <> (); - final Enumeration aEnum = aHeaders.getAllHeaderLines (); - while (aEnum.hasMoreElements ()) - ret.add ((String) aEnum.nextElement ()); + aHeaders.forEachHeaderLine (ret::add, true); return ret; } - /** - * Read the first line of the HTTP request InputStream and parse out HTTP - * method (e.g. "GET" or "POST"), request URL (e.g "/as2") and HTTP version - * (e.g. "HTTP/1.1") - * - * @param aIS - * Stream to read the first line from - * @return An array with 3 elements, containing method, URL and HTTP version - * @throws IOException - * In case of IO error - */ - @Nonnull - @Nonempty - private static String [] _readRequestInfo (@Nonnull final InputStream aIS) throws IOException - { - int nByteBuf = aIS.read (); - final StringBuilder aSB = new StringBuilder (); - while (nByteBuf != -1 && nByteBuf != '\r') - { - aSB.append ((char) nByteBuf); - nByteBuf = aIS.read (); - } - if (nByteBuf != -1) - { - // read in the \n following the "\r" - aIS.read (); - } - - final StringTokenizer aTokens = new StringTokenizer (aSB.toString (), " "); - final int nTokenCount = aTokens.countTokens (); - if (nTokenCount >= 3) - { - // Return all tokens - final String [] aRequestParts = new String [nTokenCount]; - for (int i = 0; i < nTokenCount; i++) - aRequestParts[i] = aTokens.nextToken (); - return aRequestParts; - } - - if (nTokenCount == 2) - { - // Default the request URL to "/" - final String [] aRequestParts = new String [3]; - aRequestParts[0] = aTokens.nextToken (); - aRequestParts[1] = "/"; - aRequestParts[2] = aTokens.nextToken (); - return aRequestParts; - } - throw new IOException ("Invalid HTTP Request (" + aSB.toString () + ")"); - } - /** * @return the global dumper for incoming HTTP requests or null * if none is present @@ -235,7 +177,7 @@ public static void setHTTPIncomingDumperFactory (@Nonnull final Supplier null. * @param aResponseHandler @@ -251,38 +193,29 @@ public static void setHTTPIncomingDumperFactory (@Nonnull final Supplier aEnum = aHeaders.getAllHeaders (); - while (aEnum.hasMoreElements ()) - { - final Header aHeader = aEnum.nextElement (); - aMsg.headers ().addHeader (aHeader.getName (), aHeader.getValue ()); - } + aMsg.headers ().setAllHeaders (aRDP.getHttpHeaderMap ()); // Generate DataSource // Put received data in a MIME body part final String sReceivedContentType = AS2HttpHelper.getCleanContentType (aMsg.getHeader (CHttpHeader.CONTENT_TYPE)); - byte [] aBytePayLoad = null; + final byte [] aBytePayload; final DataSource aPayload; final String sContentLength = aMsg.getHeader (CHttpHeader.CONTENT_LENGTH); if (sContentLength == null) @@ -318,6 +251,7 @@ public static DataSource readHttpRequest (@Nonnull final IAS2InputStreamProvider } // Content-length present, or chunked encoding + aBytePayload = null; aPayload = new InputStreamDataSource (aRealIS, aMsg.getAS2From () == null ? "" : aMsg.getAS2From (), sReceivedContentType, true); } else @@ -337,20 +271,20 @@ public static DataSource readHttpRequest (@Nonnull final IAS2InputStreamProvider Integer.MAX_VALUE + " are allowed."); } - aBytePayLoad = new byte [(int) nContentLength]; + aBytePayload = new byte [(int) nContentLength]; try (final DataInputStream aDataIS = new DataInputStream (aIS)) { - aDataIS.readFully (aBytePayLoad); + aDataIS.readFully (aBytePayload); } - aPayload = new ByteArrayDataSource (aBytePayLoad, sReceivedContentType, null); + aPayload = new ByteArrayDataSource (aBytePayload, sReceivedContentType, null); } // Dump on demand if (aIncomingDumper != null) { - aIncomingDumper.dumpIncomingRequest (getAllHTTPHeaderLines (aHeaders), - aBytePayLoad != null ? aBytePayLoad + aIncomingDumper.dumpIncomingRequest (getAllHTTPHeaderLines (aRDP.getHttpHeaderMap ()), + aBytePayload != null ? aBytePayload : "Payload body was not read yet, and therefore it cannot be dumped (yet) - sorry".getBytes (StandardCharsets.ISO_8859_1), aMsg); } @@ -361,14 +295,14 @@ public static DataSource readHttpRequest (@Nonnull final IAS2InputStreamProvider } @Nonnull - public static DataSource readAndDecodeHttpRequest (@Nonnull final IAS2InputStreamProvider aISP, + public static DataSource readAndDecodeHttpRequest (@Nonnull final IAS2HttpRequestDataProvider aRDP, @Nonnull final IAS2HttpResponseHandler aResponseHandler, @Nonnull final IMessage aMsg, @Nullable final IHTTPIncomingDumper aIncomingDumper) throws IOException, MessagingException { // Main read - DataSource aPayload = HTTPHelper.readHttpRequest (aISP, aResponseHandler, aMsg, aIncomingDumper); + DataSource aPayload = HTTPHelper.readHttpRequest (aRDP, aResponseHandler, aMsg, aIncomingDumper); // Check the transfer encoding of the request. If none is provided, check // the partnership for a default one. If none is in the partnership used the diff --git a/as2-lib/src/main/java/com/helger/as2lib/util/http/IAS2InputStreamProvider.java b/as2-lib/src/main/java/com/helger/as2lib/util/http/IAS2HttpRequestDataProvider.java similarity index 72% rename from as2-lib/src/main/java/com/helger/as2lib/util/http/IAS2InputStreamProvider.java rename to as2-lib/src/main/java/com/helger/as2lib/util/http/IAS2HttpRequestDataProvider.java index c2533884..77c35602 100644 --- a/as2-lib/src/main/java/com/helger/as2lib/util/http/IAS2InputStreamProvider.java +++ b/as2-lib/src/main/java/com/helger/as2lib/util/http/IAS2HttpRequestDataProvider.java @@ -36,13 +36,16 @@ import java.io.InputStream; import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import com.helger.commons.http.HttpHeaderMap; /** * Provider interface to retrieve an AS2 {@link InputStream}. * * @author Philip Helger */ -public interface IAS2InputStreamProvider +public interface IAS2HttpRequestDataProvider { /** * Get the input stream to read from. May not be null. @@ -52,5 +55,32 @@ public interface IAS2InputStreamProvider * In case of error */ @Nonnull - InputStream getInputStream () throws IOException; + InputStream getHttpInputStream () throws IOException; + + /** + * @return The HTTP request method used. Usually this should be + * POST. + */ + @Nullable + String getHttpRequestMethod (); + + /** + * @return The HTTP request URL used. Something like /as2. + */ + @Nullable + String getHttpRequestUrl (); + + /** + * @return The HTTP request version used. Something like + * HTTP/1.1. + */ + @Nonnull + String getHttpRequestVersion (); + + /** + * @return The provided HTTP header map. Mutable map is returned. Never + * null. + */ + @Nonnull + HttpHeaderMap getHttpHeaderMap (); } diff --git a/as2-lib/src/test/java/com/helger/as2lib/supplementary/main/MainSendToLocalhost8080.java b/as2-lib/src/test/java/com/helger/as2lib/supplementary/main/MainSendToLocalhost8080.java index e1a55313..60fb6a73 100644 --- a/as2-lib/src/test/java/com/helger/as2lib/supplementary/main/MainSendToLocalhost8080.java +++ b/as2-lib/src/test/java/com/helger/as2lib/supplementary/main/MainSendToLocalhost8080.java @@ -92,7 +92,7 @@ public static void main (final String [] args) throws Exception aSettings.setSenderData ("mycompanyAS2", "phax.as2-lib@github.com", "openas2a_alias"); // Fixed receiver - key alias must be "openas2b_alias" - aSettings.setReceiverData ("as2-lib-receiver", "openas2b_alias", "http://localhost:8080/as2"); + aSettings.setReceiverData ("openas2b_alias", "openas2b_alias", "http://localhost:8080/as2"); final X509Certificate aReceiverCertificate = AS2KeyStoreHelper.readX509Certificate ("src/test/resources/mendelson/key4.cer"); aSettings.setReceiverCertificate (aReceiverCertificate); diff --git a/as2-lib/src/test/java/com/helger/as2lib/util/http/HTTPHelperTest.java b/as2-lib/src/test/java/com/helger/as2lib/util/http/HTTPHelperTest.java index 3f742c4e..503247f1 100644 --- a/as2-lib/src/test/java/com/helger/as2lib/util/http/HTTPHelperTest.java +++ b/as2-lib/src/test/java/com/helger/as2lib/util/http/HTTPHelperTest.java @@ -249,14 +249,14 @@ public void testReadHttpRequestRegularMessage () throws Exception // non stream NonBlockingByteArrayInputStream is = new NonBlockingByteArrayInputStream (m_sRegularMessage.getBytes (StandardCharsets.UTF_8)); AS2Message aMsg = new AS2Message (); - IAS2InputStreamProvider mockStreamProvider = new MockAS2InputStreamProvider (is); - final DataSource resRegular = HTTPHelper.readHttpRequest (mockStreamProvider, MOCK_RH, aMsg, INCOMING_DUMPER); + IAS2HttpRequestDataProvider aMockProvider = new MockAS2HttpRequestDataProvider (is); + final DataSource resRegular = HTTPHelper.readHttpRequest (aMockProvider, MOCK_RH, aMsg, INCOMING_DUMPER); // stream is = new NonBlockingByteArrayInputStream (m_sRegularMessage.getBytes (StandardCharsets.UTF_8)); aMsg = new AS2Message (); - mockStreamProvider = new MockAS2InputStreamProvider (is); - final DataSource resStream = HTTPHelper.readHttpRequest (mockStreamProvider, MOCK_RH, aMsg, INCOMING_DUMPER); + aMockProvider = new MockAS2HttpRequestDataProvider (is); + final DataSource resStream = HTTPHelper.readHttpRequest (aMockProvider, MOCK_RH, aMsg, INCOMING_DUMPER); assertTrue ("Compare regular and stream read", _compareLineByLine (resRegular.getInputStream (), resStream.getInputStream ())); } @@ -266,14 +266,14 @@ public void testReadHttpRequestStreamMessage () throws Exception // non stream NonBlockingByteArrayInputStream is = new NonBlockingByteArrayInputStream (m_sChunkedMessage.getBytes (StandardCharsets.UTF_8)); AS2Message aMsg = new AS2Message (); - IAS2InputStreamProvider mockStreamProvider = new MockAS2InputStreamProvider (is); - final DataSource resRegular = HTTPHelper.readHttpRequest (mockStreamProvider, MOCK_RH, aMsg, INCOMING_DUMPER); + IAS2HttpRequestDataProvider aMockProvider = new MockAS2HttpRequestDataProvider (is); + final DataSource resRegular = HTTPHelper.readHttpRequest (aMockProvider, MOCK_RH, aMsg, INCOMING_DUMPER); // stream is = new NonBlockingByteArrayInputStream (m_sChunkedMessage.getBytes (StandardCharsets.UTF_8)); aMsg = new AS2Message (); - mockStreamProvider = new MockAS2InputStreamProvider (is); - final DataSource resStream = HTTPHelper.readHttpRequest (mockStreamProvider, MOCK_RH, aMsg, INCOMING_DUMPER); + aMockProvider = new MockAS2HttpRequestDataProvider (is); + final DataSource resStream = HTTPHelper.readHttpRequest (aMockProvider, MOCK_RH, aMsg, INCOMING_DUMPER); assertTrue ("Compare regular and stream read", _compareLineByLine (resRegular.getInputStream (), resStream.getInputStream ())); } @@ -284,8 +284,8 @@ public void testNoLengthMessageRegular () throws Exception final NonBlockingByteArrayInputStream is = new NonBlockingByteArrayInputStream (m_sNoLengthMessage.getBytes (StandardCharsets.UTF_8)); // non stream final AS2Message aMsg = new AS2Message (); - final IAS2InputStreamProvider mockStreamProvider = new MockAS2InputStreamProvider (is); - HTTPHelper.readHttpRequest (mockStreamProvider, MOCK_RH, aMsg, INCOMING_DUMPER); + final IAS2HttpRequestDataProvider aMockProvider = new MockAS2HttpRequestDataProvider (is); + HTTPHelper.readHttpRequest (aMockProvider, MOCK_RH, aMsg, INCOMING_DUMPER); } @Test (expected = IOException.class) @@ -294,8 +294,8 @@ public void testNoLengthMessageStream () throws Exception final NonBlockingByteArrayInputStream is = new NonBlockingByteArrayInputStream (m_sNoLengthMessage.getBytes (StandardCharsets.UTF_8)); // stream final AS2Message aMsg = new AS2Message (); - final IAS2InputStreamProvider mockStreamProvider = new MockAS2InputStreamProvider (is); - HTTPHelper.readHttpRequest (mockStreamProvider, MOCK_RH, aMsg, INCOMING_DUMPER); + final IAS2HttpRequestDataProvider aMockProvider = new MockAS2HttpRequestDataProvider (is); + HTTPHelper.readHttpRequest (aMockProvider, MOCK_RH, aMsg, INCOMING_DUMPER); } @Test (expected = IOException.class) @@ -304,8 +304,8 @@ public void testBadTRansferEncodingMessageRegular () throws Exception final NonBlockingByteArrayInputStream is = new NonBlockingByteArrayInputStream (m_sBadTransferEncodingMessage.getBytes (StandardCharsets.UTF_8)); // stream final AS2Message aMsg = new AS2Message (); - final IAS2InputStreamProvider mockStreamProvider = new MockAS2InputStreamProvider (is); - HTTPHelper.readHttpRequest (mockStreamProvider, MOCK_RH, aMsg, INCOMING_DUMPER); + final IAS2HttpRequestDataProvider aMockProvider = new MockAS2HttpRequestDataProvider (is); + HTTPHelper.readHttpRequest (aMockProvider, MOCK_RH, aMsg, INCOMING_DUMPER); } @Test (expected = IOException.class) @@ -314,8 +314,8 @@ public void testBadTRansferEncodingMessageStream () throws Exception final NonBlockingByteArrayInputStream is = new NonBlockingByteArrayInputStream (m_sBadTransferEncodingMessage.getBytes (StandardCharsets.UTF_8)); // stream final AS2Message aMsg = new AS2Message (); - final IAS2InputStreamProvider mockStreamProvider = new MockAS2InputStreamProvider (is); - HTTPHelper.readHttpRequest (mockStreamProvider, MOCK_RH, aMsg, INCOMING_DUMPER); + final IAS2HttpRequestDataProvider aMockProvider = new MockAS2HttpRequestDataProvider (is); + HTTPHelper.readHttpRequest (aMockProvider, MOCK_RH, aMsg, INCOMING_DUMPER); } private static boolean _compareLineByLine (@Nonnull @WillClose final InputStream is1, @Nonnull @WillClose final InputStream is2) diff --git a/as2-lib/src/test/java/com/helger/as2lib/util/http/MockAS2InputStreamProvider.java b/as2-lib/src/test/java/com/helger/as2lib/util/http/MockAS2HttpRequestDataProvider.java similarity index 72% rename from as2-lib/src/test/java/com/helger/as2lib/util/http/MockAS2InputStreamProvider.java rename to as2-lib/src/test/java/com/helger/as2lib/util/http/MockAS2HttpRequestDataProvider.java index df01b8d2..6ed7c99d 100644 --- a/as2-lib/src/test/java/com/helger/as2lib/util/http/MockAS2InputStreamProvider.java +++ b/as2-lib/src/test/java/com/helger/as2lib/util/http/MockAS2HttpRequestDataProvider.java @@ -38,20 +38,50 @@ import javax.annotation.Nonnull; import com.helger.commons.ValueEnforcer; +import com.helger.commons.annotation.Nonempty; +import com.helger.commons.http.EHttpMethod; +import com.helger.commons.http.HttpHeaderMap; -final class MockAS2InputStreamProvider implements IAS2InputStreamProvider +final class MockAS2HttpRequestDataProvider implements IAS2HttpRequestDataProvider { private final InputStream m_aIS; - public MockAS2InputStreamProvider (@Nonnull final InputStream aIS) + public MockAS2HttpRequestDataProvider (@Nonnull final InputStream aIS) { ValueEnforcer.notNull (aIS, "IS"); m_aIS = aIS; } @Nonnull - public InputStream getInputStream () throws IOException + public InputStream getHttpInputStream () throws IOException { return m_aIS; } + + @Nonnull + @Nonempty + public String getHttpRequestMethod () + { + return EHttpMethod.POST.getName (); + } + + @Nonnull + @Nonempty + public String getHttpRequestUrl () + { + return "/"; + } + + @Nonnull + @Nonempty + public String getHttpRequestVersion () + { + return "HTTP/1.1"; + } + + @Nonnull + public HttpHeaderMap getHttpHeaderMap () + { + return new HttpHeaderMap (); + } } diff --git a/as2-servlet/src/main/java/com/helger/as2servlet/AS2InputStreamProviderServletRequest.java b/as2-servlet/src/main/java/com/helger/as2servlet/AS2HttpRequestDataProviderServletRequest.java similarity index 68% rename from as2-servlet/src/main/java/com/helger/as2servlet/AS2InputStreamProviderServletRequest.java rename to as2-servlet/src/main/java/com/helger/as2servlet/AS2HttpRequestDataProviderServletRequest.java index 0b960cb9..55a3d89b 100644 --- a/as2-servlet/src/main/java/com/helger/as2servlet/AS2InputStreamProviderServletRequest.java +++ b/as2-servlet/src/main/java/com/helger/as2servlet/AS2HttpRequestDataProviderServletRequest.java @@ -40,33 +40,42 @@ import javax.servlet.ServletInputStream; import javax.servlet.ServletRequest; -import com.helger.as2lib.util.http.IAS2InputStreamProvider; +import com.helger.as2lib.util.http.IAS2HttpRequestDataProvider; import com.helger.commons.ValueEnforcer; +import com.helger.commons.annotation.Nonempty; +import com.helger.commons.http.HttpHeaderMap; import com.helger.commons.io.stream.NonClosingInputStream; import com.helger.commons.io.stream.StreamHelper; +import com.helger.web.scope.IRequestWebScope; /** - * Implementation of {@link IAS2InputStreamProvider} based on a + * Implementation of {@link IAS2HttpRequestDataProvider} based on a * {@link ServletRequest} {@link InputStream}. * * @author Philip Helger * @since 4.8.0 */ @Immutable -final class AS2InputStreamProviderServletRequest implements IAS2InputStreamProvider +final class AS2HttpRequestDataProviderServletRequest implements IAS2HttpRequestDataProvider { + private final IRequestWebScope m_aRequestScope; private final ServletInputStream m_aRequestIS; /** * Constructor * + * @param aRequestScope + * HTTP Servlet Request. May not be null. * @param aRequestIS * Servlet request InputStream to read from. Will not be closed. May * not be null. */ - public AS2InputStreamProviderServletRequest (@Nonnull @WillNotClose final ServletInputStream aRequestIS) + public AS2HttpRequestDataProviderServletRequest (@Nonnull final IRequestWebScope aRequestScope, + @Nonnull @WillNotClose final ServletInputStream aRequestIS) { + ValueEnforcer.notNull (aRequestScope, "RequestScope"); ValueEnforcer.notNull (aRequestIS, "RequestIS"); + m_aRequestScope = aRequestScope; m_aRequestIS = aRequestIS; } @@ -77,10 +86,37 @@ public AS2InputStreamProviderServletRequest (@Nonnull @WillNotClose final Servle * @return {@link InputStream} */ @Nonnull - public InputStream getInputStream () + public InputStream getHttpInputStream () { // Use "NonClosing" internally to that the returned stream is easily // discovered as "buffered" return StreamHelper.getBuffered (new NonClosingInputStream (m_aRequestIS)); } + + @Nonnull + @Nonempty + public String getHttpRequestMethod () + { + return m_aRequestScope.getHttpMethod ().getName (); + } + + @Nonnull + @Nonempty + public String getHttpRequestUrl () + { + return m_aRequestScope.getRequestURIDecoded (); + } + + @Nonnull + @Nonempty + public String getHttpRequestVersion () + { + return m_aRequestScope.getHttpVersion ().getName (); + } + + @Nonnull + public HttpHeaderMap getHttpHeaderMap () + { + return m_aRequestScope.headers (); + } } diff --git a/as2-servlet/src/main/java/com/helger/as2servlet/AbstractAS2ReceiveBaseXServletHandler.java b/as2-servlet/src/main/java/com/helger/as2servlet/AbstractAS2ReceiveBaseXServletHandler.java index b76b23a7..6eacb8f4 100644 --- a/as2-servlet/src/main/java/com/helger/as2servlet/AbstractAS2ReceiveBaseXServletHandler.java +++ b/as2-servlet/src/main/java/com/helger/as2servlet/AbstractAS2ReceiveBaseXServletHandler.java @@ -222,7 +222,7 @@ public final void onRequest (@Nonnull final HttpServletRequest aHttpRequest, { // Read in the message request, headers, and data final IHTTPIncomingDumper aIncomingDumper = getEffectiveHttpIncomingDumper (); - aMsgDataSource = HTTPHelper.readAndDecodeHttpRequest (new AS2InputStreamProviderServletRequest (aRequestIS), + aMsgDataSource = HTTPHelper.readAndDecodeHttpRequest (new AS2HttpRequestDataProviderServletRequest (aRequestScope, aRequestIS), aResponseHandler, aMsg, aIncomingDumper);