Created
March 27, 2026 04:08
-
-
Save hkneptune/3d5490e758593fdecfb4be863cce4f1d to your computer and use it in GitHub Desktop.
SOAP Request Samples
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.IO; | |
| using System.Net.Http; | |
| using System.Net.Http.Headers; | |
| using System.Text; | |
| using System.Threading.Tasks; | |
| /// <summary>Holds file attachment metadata for a SOAP request.</summary> | |
| public class AttachmentData | |
| { | |
| public string FilePath { get; set; } | |
| public string ContentType { get; set; } | |
| public string ContentID { get; set; } | |
| } | |
| /// <summary> | |
| /// Sends a SOAP 1.2 request with multiple attachments using MTOM | |
| /// (Message Transmission Optimization Mechanism / XOP packaging). | |
| /// | |
| /// MTOM encodes the SOAP envelope as an application/xop+xml MIME part and | |
| /// each binary file as a separate raw-binary MIME part. The SOAP body must | |
| /// reference each attachment with an XOP Include element: | |
| /// <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" | |
| /// href="cid:attachment1@example.com"/> | |
| /// | |
| /// Wire format: | |
| /// Content-Type: multipart/related; type="application/xop+xml"; boundary="…" | |
| /// --boundary | |
| /// Content-Type: application/xop+xml; charset=UTF-8; type="application/soap+xml" | |
| /// Content-ID: <rootpart> | |
| /// [SOAP 1.2 envelope with <xop:Include> elements] | |
| /// --boundary | |
| /// Content-Type: application/pdf | |
| /// Content-Transfer-Encoding: binary | |
| /// Content-ID: <attachment1@example.com> | |
| /// [raw binary file bytes] | |
| /// --boundary-- | |
| /// </summary> | |
| /// <param name="soapXml">SOAP 1.2 envelope with <xop:Include> references in the body.</param> | |
| /// <param name="attachments">Files to attach; each ContentID must match a cid: reference in the XML.</param> | |
| /// <param name="endpointUrl">Target web service URL.</param> | |
| /// <param name="soapAction">SOAPAction / action value for the operation.</param> | |
| /// <returns>Raw response body string (SOAP envelope or MTOM response).</returns> | |
| public static async Task<string> SendMtomSoapRequestAsync( | |
| string soapXml, | |
| IEnumerable<AttachmentData> attachments, | |
| string endpointUrl, | |
| string soapAction) | |
| { | |
| // ── Step 1: Generate a collision-resistant MIME boundary ─────────────────── | |
| // The boundary string must not occur anywhere inside the message content. | |
| // A GUID-based prefix makes accidental collisions with binary data negligible. | |
| string boundary = "MtomBoundary_" + Guid.NewGuid().ToString("N"); | |
| string rootPartId = "rootpart@mtom.example.com"; | |
| // ── Step 2: Build the raw multipart/related body ─────────────────────────── | |
| using var bodyStream = new MemoryStream(); | |
| // leaveOpen:true keeps bodyStream alive after the StreamWriter is disposed, | |
| // so we can still read/seek the stream before posting it. | |
| using (var writer = new StreamWriter(bodyStream, new UTF8Encoding(false), leaveOpen: true)) | |
| { | |
| // ── MIME Part 1: SOAP 1.2 envelope (XOP root part) ──────────────────── | |
| // application/xop+xml declares that XOP processing is required. | |
| // The type parameter names the real media type of the logical message | |
| // (application/soap+xml for SOAP 1.2). | |
| await writer.WriteAsync($"--{boundary}\r\n"); | |
| await writer.WriteAsync("Content-Type: application/xop+xml; charset=UTF-8; " + | |
| "type=\"application/soap+xml\"\r\n"); | |
| await writer.WriteAsync("Content-Transfer-Encoding: 8bit\r\n"); | |
| await writer.WriteAsync($"Content-ID: <{rootPartId}>\r\n"); | |
| await writer.WriteAsync("\r\n"); // blank line required between headers and body | |
| await writer.WriteAsync(soapXml); | |
| await writer.WriteAsync("\r\n"); | |
| await writer.FlushAsync(); | |
| // ── MIME Parts 2…N: One part per binary attachment ───────────────────── | |
| foreach (var attachment in attachments) | |
| { | |
| // Headers for this attachment part. | |
| // Content-ID must match the cid: URI inside the corresponding | |
| // <xop:Include href="cid:contentID"/> in the SOAP envelope body above. | |
| await writer.WriteAsync($"--{boundary}\r\n"); | |
| await writer.WriteAsync($"Content-Type: {attachment.ContentType}\r\n"); | |
| await writer.WriteAsync("Content-Transfer-Encoding: binary\r\n"); | |
| await writer.WriteAsync($"Content-ID: <{attachment.ContentID}>\r\n"); | |
| await writer.WriteAsync("\r\n"); | |
| await writer.FlushAsync(); | |
| // Append the raw file bytes. binary transfer encoding means no | |
| // Base64 or quoted-printable transformation is applied, which is | |
| // the key efficiency advantage of MTOM over inline Base64 encoding. | |
| byte[] fileBytes = await File.ReadAllBytesAsync(attachment.FilePath); | |
| await bodyStream.WriteAsync(fileBytes); | |
| await writer.WriteAsync("\r\n"); | |
| await writer.FlushAsync(); | |
| } | |
| // ── Closing MIME boundary ───────────────────────────────────────────── | |
| await writer.WriteAsync($"--{boundary}--\r\n"); | |
| await writer.FlushAsync(); | |
| } | |
| bodyStream.Seek(0, SeekOrigin.Begin); | |
| // ── Step 3: Construct the HTTP request with the MTOM Content-Type ───────── | |
| // The outer Content-Type identifies the multipart structure and provides: | |
| // type – media type of the root (XOP) part | |
| // start – Content-ID of the root part (SOAP envelope) | |
| // start-info – actual SOAP media type (for SOAP 1.2 = application/soap+xml) | |
| // boundary – the MIME delimiter string used between parts | |
| using var httpClient = new HttpClient(); | |
| var content = new StreamContent(bodyStream); | |
| content.Headers.ContentType = MediaTypeHeaderValue.Parse( | |
| $"multipart/related; " + | |
| $"type=\"application/xop+xml\"; " + | |
| $"start=\"<{rootPartId}>\"; " + | |
| $"start-info=\"application/soap+xml\"; " + | |
| $"boundary=\"{boundary}\""); | |
| // SOAPAction is required by SOAP 1.1 routers; for SOAP 1.2 it is conveyed | |
| // as an action parameter in Content-Type, but adding the header ensures | |
| // compatibility with intermediaries that inspect it regardless of version. | |
| httpClient.DefaultRequestHeaders.Add("SOAPAction", $"\"{soapAction}\""); | |
| // ── Step 4: POST the MTOM message and await the HTTP response ───────────── | |
| HttpResponseMessage httpResponse = | |
| await httpClient.PostAsync(endpointUrl, content); | |
| // Raise an HttpRequestException for any non-2xx HTTP status so the caller | |
| // learns about transport-level failures immediately rather than silently | |
| // receiving a SOAP fault or empty body. | |
| httpResponse.EnsureSuccessStatusCode(); | |
| // ── Step 5: Return the response body as a raw string ────────────────────── | |
| // The response may itself be multipart/MTOM. Parse and decode it if | |
| // the service returns XOP-encoded response attachments. | |
| return await httpResponse.Content.ReadAsStringAsync(); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import java.io.ByteArrayInputStream; | |
| import java.io.InputStream; | |
| import java.io.StringWriter; | |
| import java.util.List; | |
| import javax.activation.DataHandler; | |
| import javax.activation.FileDataSource; | |
| import javax.xml.XMLConstants; | |
| import javax.xml.soap.*; | |
| import javax.xml.transform.*; | |
| import javax.xml.transform.dom.DOMSource; | |
| import javax.xml.transform.stream.StreamResult; | |
| /** | |
| * Sends a SOAP 1.2 request with multiple attachments using MTOM | |
| * (Message Transmission Optimization Mechanism / XOP packaging). | |
| * | |
| * MTOM avoids Base64-encoding binary data inline in the XML body. | |
| * Instead, each attachment is sent as a raw binary MIME part and | |
| * referenced from the SOAP body via an <xop:Include href="cid:…"/> | |
| * element. This significantly reduces message size for large files. | |
| * | |
| * The soapXml parameter must already contain the XOP placeholders, e.g.: | |
| * <FileData> | |
| * <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" | |
| * href="cid:attachment1@example.com"/> | |
| * </FileData> | |
| * | |
| * @param soapXml SOAP 1.2 envelope XML with <xop:Include> references | |
| * @param attachments List of files to attach (path, MIME type, content-ID) | |
| * @param endpointUrl Target SOAP service URL | |
| * @return SOAP response envelope as a String | |
| */ | |
| public static String sendMtomSoapRequest( | |
| String soapXml, | |
| List<AttachmentData> attachments, | |
| String endpointUrl) throws Exception { | |
| // ── Step 1: Create a SOAP 1.2 MessageFactory ────────────────────────────── | |
| // MTOM is only defined for SOAP 1.2. SOAP_1_2_PROTOCOL selects the correct | |
| // factory that uses application/soap+xml as the inner envelope content type, | |
| // which MTOM wraps with application/xop+xml. | |
| MessageFactory messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL); | |
| // ── Step 2: Parse the SOAP envelope XML into a SOAPMessage ──────────────── | |
| // The XML string is converted to a byte stream so the factory can parse it. | |
| // Each <xop:Include href="cid:…"/> in the body acts as a pointer to the | |
| // corresponding binary MIME part that will be added in Step 4. | |
| InputStream xmlStream = new ByteArrayInputStream(soapXml.getBytes("UTF-8")); | |
| SOAPMessage soapMessage = messageFactory.createMessage(null, xmlStream); | |
| // ── Step 3: Set the MTOM/XOP Content-Type on the primary MIME part ──────── | |
| // application/xop+xml with type="application/soap+xml" tells the receiver | |
| // to apply XOP processing: it must find and dereference every cid: URI in | |
| // the envelope by looking up the matching attachment MIME part. | |
| MimeHeaders mimeHeaders = soapMessage.getMimeHeaders(); | |
| mimeHeaders.setHeader("Content-Type", | |
| "application/xop+xml; charset=UTF-8; type=\"application/soap+xml\""); | |
| // ── Step 4: Add each file as a separate binary XOP MIME part ────────────── | |
| for (AttachmentData data : attachments) { | |
| // DataHandler + FileDataSource wraps the file path in a clean I/O | |
| // abstraction and ensures the SAAJ implementation reads the file lazily. | |
| // This avoids leaving open FileInputStream handles that could leak. | |
| DataHandler dataHandler = new DataHandler(new FileDataSource(data.FilePath)); | |
| AttachmentPart attachment = soapMessage.createAttachmentPart(dataHandler); | |
| // The Content-ID (angle-bracket form) must exactly match the cid: URI | |
| // in the <xop:Include href="cid:…"/> placeholder in the SOAP body. | |
| // Without this match the receiver cannot reassemble the logical message. | |
| attachment.setContentId("<" + data.ContentID + ">"); | |
| attachment.setContentType(data.ConcentType); | |
| // binary transfer encoding means the bytes are sent as-is with no | |
| // additional Base64 or quoted-printable transformation at the MIME level, | |
| // which is the whole performance benefit of MTOM over SOAP with Attachments. | |
| attachment.addMimeHeader("Content-Transfer-Encoding", "binary"); | |
| soapMessage.addAttachmentPart(attachment); | |
| } | |
| // ── Step 5: Finalise MIME boundaries and envelope headers ───────────────── | |
| // saveChanges() recomputes the multipart MIME structure, assigns boundary | |
| // separators between parts, and updates Content-Length where applicable. | |
| // It must be called before transmitting the message. | |
| soapMessage.saveChanges(); | |
| // ── Step 6: Open a SOAP connection and dispatch the request ─────────────── | |
| SOAPConnectionFactory connFactory = SOAPConnectionFactory.newInstance(); | |
| SOAPConnection connection = connFactory.createConnection(); | |
| SOAPMessage soapResponse; | |
| try { | |
| soapResponse = connection.call(soapMessage, endpointUrl); | |
| } finally { | |
| // Always close the connection in a finally block so that the underlying | |
| // HTTP socket is released even if the remote call throws an exception. | |
| connection.close(); | |
| } | |
| // ── Step 7: Serialize the response SOAP envelope to a String ────────────── | |
| org.w3c.dom.Document responseDoc = | |
| soapResponse.getSOAPPart().getEnvelope().getOwnerDocument(); | |
| TransformerFactory tf = TransformerFactory.newInstance(); | |
| // Disable external DTD and stylesheet loading to prevent XXE injection | |
| // attacks (OWASP A03:2021 – Injection / XML External Entity processing). | |
| tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); | |
| tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); | |
| StringWriter output = new StringWriter(); | |
| tf.newTransformer().transform(new DOMSource(responseDoc), new StreamResult(output)); | |
| return output.toString(); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /// <summary> | |
| /// Sends a SOAP 1.1 request with multiple attachments using SwA | |
| /// (SOAP with Attachments, W3C Note, 2000). | |
| /// | |
| /// Unlike MTOM, SwA uses plain text/xml for the SOAP envelope and references | |
| /// each binary attachment from the SOAP body with a href="cid:…" attribute. | |
| /// There are no XOP Include elements. SwA is the legacy attachment mechanism | |
| /// for SOAP 1.1 systems that predate or do not support MTOM/XOP. | |
| /// | |
| /// Wire format: | |
| /// Content-Type: multipart/related; type="text/xml"; boundary="…" | |
| /// --boundary | |
| /// Content-Type: text/xml; charset=UTF-8 | |
| /// Content-ID: <soaproot> | |
| /// [SOAP 1.1 envelope — body elements carry href="cid:…" attributes] | |
| /// --boundary | |
| /// Content-Type: application/pdf | |
| /// Content-Transfer-Encoding: binary | |
| /// Content-ID: <attachment1@example.com> | |
| /// Content-Disposition: attachment; filename="invoice.pdf" | |
| /// [raw binary file bytes] | |
| /// --boundary-- | |
| /// </summary> | |
| /// <param name="soapXml">SOAP 1.1 envelope; body elements reference attachments via href="cid:…".</param> | |
| /// <param name="attachments">Files to attach; each ContentID must match a cid: in the XML body.</param> | |
| /// <param name="endpointUrl">Target web service URL.</param> | |
| /// <param name="soapAction">SOAPAction header value identifying the SOAP operation.</param> | |
| /// <returns>Raw response body string.</returns> | |
| public static async Task<string> SendSwaSoapRequestAsync( | |
| string soapXml, | |
| IEnumerable<AttachmentData> attachments, | |
| string endpointUrl, | |
| string soapAction) | |
| { | |
| // ── Step 1: Generate a unique MIME boundary ──────────────────────────────── | |
| // The boundary appears as a line prefix to delimit MIME parts. | |
| // Using a GUID prevents any accidental collision with binary content. | |
| string boundary = "SwABoundary_" + Guid.NewGuid().ToString("N"); | |
| string rootPartId = "soaproot@swa.example.com"; | |
| // ── Step 2: Compose the multipart/related message body ──────────────────── | |
| using var bodyStream = new MemoryStream(); | |
| using (var writer = new StreamWriter(bodyStream, new UTF8Encoding(false), leaveOpen: true)) | |
| { | |
| // ── MIME Part 1: SOAP 1.1 XML envelope (primary part) ───────────────── | |
| // The Content-Type here is text/xml (not application/xop+xml) because | |
| // SwA does not use XOP. This is the key structural difference from MTOM: | |
| // the XML body is sent as regular text without any XOP optimisation. | |
| await writer.WriteAsync($"--{boundary}\r\n"); | |
| await writer.WriteAsync("Content-Type: text/xml; charset=UTF-8\r\n"); | |
| await writer.WriteAsync("Content-Transfer-Encoding: 8bit\r\n"); | |
| await writer.WriteAsync($"Content-ID: <{rootPartId}>\r\n"); | |
| await writer.WriteAsync("\r\n"); // blank line separates headers from body | |
| await writer.WriteAsync(soapXml); | |
| await writer.WriteAsync("\r\n"); | |
| await writer.FlushAsync(); | |
| // ── MIME Parts 2…N: Binary file attachments ──────────────────────────── | |
| foreach (var attachment in attachments) | |
| { | |
| // Each attachment is identified by a Content-ID that must match, | |
| // without angle brackets, the cid: value in the SOAP body attribute | |
| // e.g. <ns:Document href="cid:invoice.pdf@example.com"/> | |
| await writer.WriteAsync($"--{boundary}\r\n"); | |
| await writer.WriteAsync($"Content-Type: {attachment.ContentType}\r\n"); | |
| await writer.WriteAsync("Content-Transfer-Encoding: binary\r\n"); | |
| await writer.WriteAsync($"Content-ID: <{attachment.ContentID}>\r\n"); | |
| // Content-Disposition is optional but recommended; it provides a | |
| // filename hint for recipient agents that save or display attachments. | |
| string fileName = Path.GetFileName(attachment.FilePath); | |
| await writer.WriteAsync( | |
| $"Content-Disposition: attachment; filename=\"{fileName}\"\r\n"); | |
| await writer.WriteAsync("\r\n"); | |
| await writer.FlushAsync(); | |
| // Write the raw file bytes into the body stream. | |
| // binary transfer encoding preserves the bytes exactly as-is without | |
| // any Base64 or quoted-printable transformation at the MIME level. | |
| byte[] fileBytes = await File.ReadAllBytesAsync(attachment.FilePath); | |
| await bodyStream.WriteAsync(fileBytes); | |
| await writer.WriteAsync("\r\n"); | |
| await writer.FlushAsync(); | |
| } | |
| // ── Closing MIME boundary ───────────────────────────────────────────── | |
| await writer.WriteAsync($"--{boundary}--\r\n"); | |
| await writer.FlushAsync(); | |
| } | |
| bodyStream.Seek(0, SeekOrigin.Begin); | |
| // ── Step 3: Attach the correct Content-Type for a SwA message ───────────── | |
| // For SwA the outer Content-Type is multipart/related with type="text/xml" | |
| // (matching the primary SOAP part type, unlike MTOM which uses xop+xml). | |
| // The start parameter names the root part by its Content-ID. | |
| using var httpClient = new HttpClient(); | |
| var content = new StreamContent(bodyStream); | |
| content.Headers.ContentType = MediaTypeHeaderValue.Parse( | |
| $"multipart/related; " + | |
| $"type=\"text/xml\"; " + | |
| $"start=\"<{rootPartId}>\"; " + | |
| $"boundary=\"{boundary}\""); | |
| // SOAPAction is mandatory in SOAP 1.1 (spec section 6.1.1). | |
| // The value must be quoted and should identify the target SOAP operation URI. | |
| httpClient.DefaultRequestHeaders.Add("SOAPAction", $"\"{soapAction}\""); | |
| // ── Step 4: POST the SwA request ────────────────────────────────────────── | |
| HttpResponseMessage httpResponse = | |
| await httpClient.PostAsync(endpointUrl, content); | |
| // Throw for non-2xx so the caller is not silently handed an error page. | |
| httpResponse.EnsureSuccessStatusCode(); | |
| // ── Step 5: Return the response as a string ──────────────────────────────── | |
| return await httpResponse.Content.ReadAsStringAsync(); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import java.io.ByteArrayInputStream; | |
| import java.io.File; | |
| import java.io.FileInputStream; | |
| import java.io.InputStream; | |
| import java.io.StringWriter; | |
| import java.util.List; | |
| import javax.xml.XMLConstants; | |
| import javax.xml.soap.*; | |
| import javax.xml.transform.*; | |
| import javax.xml.transform.dom.DOMSource; | |
| import javax.xml.transform.stream.StreamResult; | |
| /** | |
| * Sends a SOAP 1.1 request with multiple attachments using SwA | |
| * (SOAP with Attachments, W3C Note, 2000). | |
| * | |
| * Unlike MTOM, SwA does not use XOP. The SOAP body references each attachment | |
| * via a plain href="cid:…" attribute, and each file is attached as a separate | |
| * MIME part in a multipart/related message. SwA is the older standard and is | |
| * supported by a wider range of legacy SOAP 1.1 services. | |
| * | |
| * Example SOAP body reference: | |
| * <ns:Document href="cid:invoice.pdf"/> | |
| * | |
| * @param soapXml SOAP 1.1 envelope XML with href="cid:…" references | |
| * @param attachments List of files to attach (path, MIME type, content-ID) | |
| * @param endpointUrl Target SOAP service URL | |
| * @return SOAP response envelope as a String | |
| */ | |
| public static String sendSwaSoapRequest( | |
| String soapXml, | |
| List<AttachmentData> attachments, | |
| String endpointUrl) throws Exception { | |
| // ── Step 1: Create a SOAP 1.1 MessageFactory ────────────────────────────── | |
| // SwA uses SOAP 1.1 (text/xml content type). SOAP_1_1_PROTOCOL guarantees | |
| // the correct envelope namespace and Content-Type for SOAP 1.1 services. | |
| MessageFactory messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL); | |
| // ── Step 2: Parse the SOAP XML into a SOAPMessage ───────────────────────── | |
| // The SOAP body elements that correspond to attachments must carry the | |
| // attribute href="cid:contentID". The contentID must equal the Content-ID | |
| // set on the matching MIME attachment part (without angle brackets). | |
| InputStream xmlStream = new ByteArrayInputStream(soapXml.getBytes("UTF-8")); | |
| SOAPMessage soapMessage = messageFactory.createMessage(null, xmlStream); | |
| // ── Step 3: Add each file as a raw binary MIME attachment part ──────────── | |
| for (AttachmentData data : attachments) { | |
| AttachmentPart attachment = soapMessage.createAttachmentPart(); | |
| // try-with-resources ensures the FileInputStream is closed immediately | |
| // after SAAJ copies the bytes into its internal buffer. | |
| // This prevents file handle leaks even if an exception is thrown. | |
| try (FileInputStream fileStream = new FileInputStream(data.FilePath)) { | |
| // setRawContent reads the stream and stores the bytes associated | |
| // with the given MIME type (e.g. "application/pdf", "image/jpeg"). | |
| attachment.setRawContent(fileStream, data.ConcentType); | |
| } | |
| // Content-ID in angle brackets per RFC 2392. The cid: URI referenced in | |
| // href="cid:…" in the SOAP body must equal this ID without the angle brackets. | |
| attachment.setContentId("<" + data.ContentID + ">"); | |
| // Content-Disposition provides a human-readable filename for clients that | |
| // save or display the attachment parts individually. | |
| attachment.addMimeHeader("Content-Disposition", | |
| "attachment; filename=\"" + new File(data.FilePath).getName() + "\""); | |
| soapMessage.addAttachmentPart(attachment); | |
| } | |
| // ── Step 4: Finalise the MIME multipart/related message structure ────────── | |
| // saveChanges() promotes the message Content-Type to multipart/related, | |
| // assigns MIME boundary delimiters between parts, and recalculates headers. | |
| // Without this call the message may be sent with an incorrect Content-Type. | |
| soapMessage.saveChanges(); | |
| // ── Step 5: Send the request over a SOAP connection ─────────────────────── | |
| SOAPConnectionFactory connFactory = SOAPConnectionFactory.newInstance(); | |
| SOAPConnection connection = connFactory.createConnection(); | |
| SOAPMessage soapResponse; | |
| try { | |
| soapResponse = connection.call(soapMessage, endpointUrl); | |
| } finally { | |
| // Release the connection unconditionally to avoid socket leaks in error paths. | |
| connection.close(); | |
| } | |
| // ── Step 6: Convert the SOAP response envelope to a String ──────────────── | |
| org.w3c.dom.Document responseDoc = | |
| soapResponse.getSOAPPart().getEnvelope().getOwnerDocument(); | |
| TransformerFactory tf = TransformerFactory.newInstance(); | |
| // Prevent XXE attacks by blocking all external DTD and stylesheet resolution. | |
| tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); | |
| tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); | |
| StringWriter output = new StringWriter(); | |
| tf.newTransformer().transform(new DOMSource(responseDoc), new StreamResult(output)); | |
| return output.toString(); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment