From 03d1f786bf352dbaf50eb1889468cb2367692048 Mon Sep 17 00:00:00 2001 From: davefej Date: Tue, 13 Jul 2021 21:14:58 +0200 Subject: [PATCH] Support for soap attachments in response. (#1148) * Add support of MTOM attachments in response * create test for MTOM response attachment functionality * typo fix lastReponseAttachments * fix tests without mocking httpres * lint and coverage fixes * Fix getAttachment test fails on linux (LF to CRLF) * improve code coverage and minor fixes * Rename option mtomResponse to parseReponseAttachments * feat: add mtomAttachments to result * lint fix * remove accidentally re-added request package Co-authored-by: David Polidario-Maddock Co-authored-by: david.varga --- Readme.md | 3 +- package-lock.json | 29 +++++++++++ package.json | 3 ++ src/client.ts | 17 +++--- src/http.ts | 42 +++++++++++++-- src/types.ts | 14 ++++- src/utils.ts | 50 ++++++++++++++++++ test/request-response-samples-test.js | 44 +++++++++++++--- .../attachmentParts.js | 7 +++ .../request.json | 3 ++ .../request.xml | 1 + .../response.json | 1 + .../response.xml | 23 ++++++++ .../responseHttpHeader.json | 3 ++ .../soap.wsdl | 52 +++++++++++++++++++ .../wsdl_options.json | 3 ++ .../request.json | 3 ++ .../request.xml | 1 + .../response.json | 1 + .../response.xml | 9 ++++ .../soap.wsdl | 52 +++++++++++++++++++ .../wsdl_options.json | 3 ++ 22 files changed, 344 insertions(+), 20 deletions(-) create mode 100644 test/request-response-samples/getAttachments__should_handle_MTOM_response/attachmentParts.js create mode 100644 test/request-response-samples/getAttachments__should_handle_MTOM_response/request.json create mode 100644 test/request-response-samples/getAttachments__should_handle_MTOM_response/request.xml create mode 100644 test/request-response-samples/getAttachments__should_handle_MTOM_response/response.json create mode 100644 test/request-response-samples/getAttachments__should_handle_MTOM_response/response.xml create mode 100644 test/request-response-samples/getAttachments__should_handle_MTOM_response/responseHttpHeader.json create mode 100644 test/request-response-samples/getAttachments__should_handle_MTOM_response/soap.wsdl create mode 100644 test/request-response-samples/getAttachments__should_handle_MTOM_response/wsdl_options.json create mode 100644 test/request-response-samples/getAttachments__should_handle_not_MTOM_response/request.json create mode 100644 test/request-response-samples/getAttachments__should_handle_not_MTOM_response/request.xml create mode 100644 test/request-response-samples/getAttachments__should_handle_not_MTOM_response/response.json create mode 100644 test/request-response-samples/getAttachments__should_handle_not_MTOM_response/response.xml create mode 100644 test/request-response-samples/getAttachments__should_handle_not_MTOM_response/soap.wsdl create mode 100644 test/request-response-samples/getAttachments__should_handle_not_MTOM_response/wsdl_options.json diff --git a/Readme.md b/Readme.md index 7dc7fe316..db618cda3 100644 --- a/Readme.md +++ b/Readme.md @@ -151,8 +151,9 @@ The `options` argument allows you to customize the client with the following pro - namespaceArrayElements: provides support for nonstandard array semantics. If true, JSON arrays of the form `{list: [{elem: 1}, {elem: 2}]}` are marshalled into xml as `1 2`. If false, marshalls into ` 1 2 `. Default: `true`. - stream: allows using a stream to parse the XML SOAP response. Default: `false` - returnSaxStream: enables the library to return the sax stream, transferring to the end user the responsibility of parsing the XML. It can be used only in combination with *stream* argument set to `true`. Default: `false` +- parseReponseAttachments: Treat response as multipart/related response with MTOM attachment. Reach attachments on the `lastResponseAttachments` property of SoapClient. Default: `false` -Note: for versions of node >0.10.X, you may need to specify `{connection: 'keep-alive'}` in SOAP headers to avoid truncation of longer chunked responses. +Note: for versions of node >0.10.X, you may need to specify `{connection: 'keep-alive'}` in SOAP headers to avoid truncation of longer chunked responses. ### soap.listen(*server*, *path*, *services*, *wsdl*, *callback*) - create a new SOAP server that listens on *path* and provides *services*. *server* can be a [http](https://nodejs.org/api/http.html) Server or [express](http://expressjs.com/) framework based server diff --git a/package-lock.json b/package-lock.json index d7d247872..d0bf4f51b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -761,6 +761,11 @@ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", "dev": true }, + "content-type-parser": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.2.tgz", + "integrity": "sha512-lM4l4CnMEwOLHAHr/P6MEZwZFPJFtAAKgL6pogbXmVZggIqXhdB6RbBtPOTsw2FcXwYhehRGERJmRrjOiIB8pQ==" + }, "convert-source-map": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", @@ -1444,6 +1449,11 @@ "samsam": "~1.1" } }, + "formidable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz", + "integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==" + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -1667,6 +1677,20 @@ "sshpk": "^1.7.0" } }, + "httpntlm": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.7.7.tgz", + "integrity": "sha512-Pv2Rvrz8H0qv1Dne5mAdZ9JegG1uc6Vu5lwLflIY6s8RKHdZQbW39L4dYswSgqMDT0pkJILUTKjeyU0VPNRZjA==", + "requires": { + "httpreq": ">=0.4.22", + "underscore": "~1.12.1" + } + }, + "httpreq": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.5.2.tgz", + "integrity": "sha512-2Jm+x9WkExDOeFRrdBCBSpLPT5SokTcRHkunV3pjKmX/cx6av8zQ0WtHUMDrYb6O4hBFzNU6sxJEypvRUVYKnw==" + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -3558,6 +3582,11 @@ } } }, + "underscore": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", + "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" + }, "unherit": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz", diff --git a/package.json b/package.json index 4213c7cdd..ed3b57d79 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,11 @@ "dependencies": { "axios": "^0.21.1", "axios-ntlm": "^1.1.6", + "content-type-parser": "^1.0.2", "debug": "^4.3.1", + "formidable": "^1.2.2", "get-stream": "^6.0.1", + "httpntlm": "^1.5.2", "lodash": "^4.17.21", "sax": ">=0.6", "strip-bom": "^3.0.0", diff --git a/src/client.ts b/src/client.ts index 194880230..0c4496ead 100644 --- a/src/client.ts +++ b/src/client.ts @@ -11,7 +11,7 @@ import { IncomingHttpHeaders } from 'http'; import * as _ from 'lodash'; import { v4 as uuidv4 } from 'uuid'; import { HttpClient } from './http'; -import { IHeaders, IHttpClient, IOptions, ISecurity, SoapMethod, SoapMethodAsync } from './types'; +import { IHeaders, IHttpClient, IMTOMAttachments, IOptions, ISecurity, SoapMethod, SoapMethodAsync } from './types'; import { findPrefix } from './utils'; import { WSDL } from './wsdl'; import { IPort, OperationElement, ServiceElement } from './wsdl/elements'; @@ -53,6 +53,7 @@ export class Client extends EventEmitter { public lastResponse?: any; public lastResponseHeaders?: IncomingHttpHeaders; public lastElapsedTime?: number; + public lastResponseAttachments: IMTOMAttachments; private wsdl: WSDL; private httpClient: IHttpClient; @@ -230,11 +231,12 @@ export class Client extends EventEmitter { rawResponse: any, soapHeader: any, rawRequest: any, + mtomAttachments: any, ) => { if (err) { reject(err); } else { - resolve([result, rawResponse, soapHeader, rawRequest]); + resolve([result, rawResponse, soapHeader, rawRequest, mtomAttachments]); } }; method( @@ -263,8 +265,8 @@ export class Client extends EventEmitter { extraHeaders = options; options = temp; } - this._invoke(method, args, location, (error, result, rawResponse, soapHeader, rawRequest) => { - callback(error, result, rawResponse, soapHeader, rawRequest); + this._invoke(method, args, location, (error, result, rawResponse, soapHeader, rawRequest, mtomAttachments) => { + callback(error, result, rawResponse, soapHeader, rawRequest, mtomAttachments); }, options, extraHeaders); }; } @@ -314,7 +316,7 @@ export class Client extends EventEmitter { if (!output) { // one-way, no output expected - return callback(null, null, body, obj.Header, xml); + return callback(null, null, body, obj.Header, xml, response.mtomResponseAttachments); } // If it's not HTML and Soap Body is empty @@ -351,7 +353,7 @@ export class Client extends EventEmitter { }); } - callback(null, result, body, obj.Header, xml); + callback(null, result, body, obj.Header, xml, response.mtomResponseAttachments); }; const parseSync = (body, response) => { @@ -372,7 +374,7 @@ export class Client extends EventEmitter { error.response = response; error.body = body; this.emit('soapError', error, eid); - return callback(error, response, body, undefined, xml); + return callback(error, response, body, undefined, xml, response.mtomResponseAttachments); } return finish(obj, body, response); }; @@ -552,6 +554,7 @@ export class Client extends EventEmitter { if (response) { this.lastResponseHeaders = response.headers; this.lastElapsedTime = response.headers.date; + this.lastResponseAttachments = response.mtomResponseAttachments; // Added mostly for testability, but possibly useful for debugging this.lastRequestHeaders = response.config && response.config.headers; } diff --git a/src/http.ts b/src/http.ts index 1d3c0b26b..3a98aa665 100644 --- a/src/http.ts +++ b/src/http.ts @@ -5,11 +5,14 @@ import * as req from 'axios'; import { NtlmClient } from 'axios-ntlm'; +import * as contentTypeParser from 'content-type-parser'; import * as debugBuilder from 'debug'; import { ReadStream } from 'fs'; import * as url from 'url'; + import { v4 as uuidv4 } from 'uuid'; -import { IExOptions, IHeaders, IHttpClient, IOptions } from './types'; +import { IExOptions, IHeaders, IHttpClient, IMTOMAttachments, IOptions } from './types'; +import { parseMTOMResp } from './utils'; const debug = debugBuilder('node-soap'); const VERSION = require('../package.json').version; @@ -29,10 +32,13 @@ export interface IAttachment { * @constructor */ export class HttpClient implements IHttpClient { + private _request: req.AxiosInstance; + private options: IOptions; constructor(options?: IOptions) { options = options || {}; + this.options = options; this._request = options.request || req.default.create(); } @@ -166,11 +172,41 @@ export class HttpClient implements IHttpClient { }); req = ntlmReq(options); } else { + if (this.options.parseReponseAttachments) { + options.responseType = 'arraybuffer'; + options.responseEncoding = 'binary'; + } req = this._request(options); } - + const _this = this; req.then((res) => { - res.data = this.handleResponse(req, res, res.data); + let body; + if (_this.options.parseReponseAttachments) { + const isMultipartResp = res.headers['content-type'] && res.headers['content-type'].toLowerCase().indexOf('multipart/related') > -1; + if (isMultipartResp) { + let boundary; + const parsedContentType = contentTypeParser(res.headers['content-type']); + if (parsedContentType && parsedContentType.parameterList) { + boundary = ((parsedContentType.parameterList as any[]).find((item) => item.key === 'boundary') || {}).value; + } + if (!boundary) { + return callback(new Error('Missing boundary from content-type')); + } + const multipartResponse = parseMTOMResp(res.data, boundary); + + // first part is the soap response + const firstPart = multipartResponse.parts.shift(); + if (!firstPart || !firstPart.body) { + return callback(new Error('Cannot parse multipart response')); + } + body = firstPart.body.toString('utf8'); + (res as any).mtomResponseAttachments = multipartResponse; + } else { + body = res.data.toString('utf8'); + } + } + + res.data = this.handleResponse(req, res, body || res.data); callback(null, res, res.data); return res; }, (err) => { diff --git a/src/types.ts b/src/types.ts index 4a306bc76..1700a511f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -19,16 +19,17 @@ export interface IHttpClient { export type ISoapMethod = SoapMethod; export type SoapMethod = ( args: any, - callback: (err: any, result: any, rawResponse: any, soapHeader: any, rawRequest: any) => void, + callback: (err: any, result: any, rawResponse: any, soapHeader: any, rawRequest: any, mtomAttachments?: IMTOMAttachments) => void, options?: any, extraHeaders?: any, + mtomAttachments?: IMTOMAttachments, ) => void; export type SoapMethodAsync = ( args: any, options?: any, extraHeaders?: any, -) => Promise<[any, any, any, any]>; +) => Promise<[any, any, any, any, IMTOMAttachments?]>; export type ISoapServiceMethod = (args: any, callback?: (data: any) => void, headers?: any, req?: any, res?: any, sender?: any) => any; @@ -133,6 +134,8 @@ export interface IOptions extends IWsdlBaseOptions { overridePromiseSuffix?: string; /** @internal */ WSDL_CACHE?; + /** handle MTOM soapAttachments in response */ + parseReponseAttachments?: boolean; } export interface IOneWayOptions { @@ -152,3 +155,10 @@ export interface IServerOptions extends IWsdlBaseOptions { /** A boolean for controlling chunked transfer encoding in response. Some client (such as Windows 10's MDM enrollment SOAP client) is sensitive to transfer-encoding mode and can't accept chunked response. This option let user disable chunked transfer encoding for such a client. Default to true for backward compatibility. */ enableChunkedEncoding?: boolean; } + +export interface IMTOMAttachments { + parts: Array<{ + body: Buffer, + headers: { [key: string]: string }, + }>; +} diff --git a/src/utils.ts b/src/utils.ts index 8154d971d..67dd49a4f 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,7 @@ import * as crypto from 'crypto'; +import { MultipartParser } from 'formidable/lib/multipart_parser.js'; +import { IMTOMAttachments } from './types'; export function passwordDigest(nonce: string, created: string, password: string): string { // digest = base64 ( sha1 ( nonce + created + password ) ) @@ -64,3 +66,51 @@ export function xmlEscape(obj) { return obj; } + +export function parseMTOMResp(payload: Buffer, boundary: string): IMTOMAttachments { + const resp: IMTOMAttachments = { + parts: [], + }; + let headerName = ''; + let headerValue = ''; + let data: Buffer; + let partIndex = 0; + const parser = new MultipartParser(); + + parser.initWithBoundary(boundary); + parser.onPartBegin = () => { + resp.parts[partIndex] = { + body: null, + headers: {}, + }; + data = Buffer.from(''); + }; + + parser.onHeaderField = (b: Buffer, start: number, end: number) => { + headerName = b.slice(start, end).toString(); + }; + + parser.onHeaderValue = (b: Buffer, start: number, end: number) => { + headerValue = b.slice(start, end).toString(); + }; + + parser.onHeaderEnd = () => { + resp.parts[partIndex].headers[headerName.toLowerCase()] = headerValue; + }; + + parser.onHeadersEnd = () => {}; + + parser.onPartData = (b: Buffer, start: number, end: number) => { + data = Buffer.concat([data, b.slice(start, end)]); + }; + + parser.onPartEnd = () => { + resp.parts[partIndex].body = data; + partIndex++; + }; + + parser.onEnd = () => {}; + parser.write(payload); + + return resp; +} diff --git a/test/request-response-samples-test.js b/test/request-response-samples-test.js index d24e290ad..e6c1dd134 100644 --- a/test/request-response-samples-test.js +++ b/test/request-response-samples-test.js @@ -57,6 +57,11 @@ var requestContext = { assert.equal(actualRequest, expectedRequest); if(!requestContext.responseToSend)return requestContext.doneHandler(); + if(requestContext.responseHttpHeaders){ + for(const headerKey in requestContext.responseHttpHeaders ){ + res.setHeader(headerKey,requestContext.responseHttpHeaders[headerKey]); + } + } res.end(requestContext.responseToSend); requestContext.expectedRequest = null; @@ -81,6 +86,8 @@ tests.forEach(function(test){ var options = path.resolve(test, 'options.json'); var wsdlOptionsFile = path.resolve(test, 'wsdl_options.json'); var wsdlJSOptionsFile = path.resolve(test, 'wsdl_options.js'); + var responseHttpHeaders = path.resolve(test,'responseHttpHeader.json'); + var attachmentParts = path.resolve(test, "attachmentParts.js"); var wsdlOptions = {}; //headerJSON is optional @@ -120,11 +127,20 @@ tests.forEach(function(test){ else if(fs.existsSync(wsdlJSOptionsFile)) wsdlOptions = require(wsdlJSOptionsFile); else wsdlOptions = {}; - generateTest(name, methodName, wsdl, headerJSON, securityJSON, requestXML, requestJSON, responseXML, responseJSON, responseSoapHeaderJSON, wsdlOptions, options, false); - generateTest(name, methodName, wsdl, headerJSON, securityJSON, requestXML, requestJSON, responseXML, responseJSON, responseSoapHeaderJSON, wsdlOptions, options, true); + + //responseHttpHeaders + if(fs.existsSync(responseHttpHeaders)) responseHttpHeaders = require(responseHttpHeaders) + else responseHttpHeaders = null; + + //attachmentParts + if(fs.existsSync(attachmentParts)) attachmentParts = require(attachmentParts) + else attachmentParts = null; + + generateTest(name, methodName, wsdl, headerJSON, securityJSON, requestXML, requestJSON, responseXML, responseJSON, responseSoapHeaderJSON, wsdlOptions, options, responseHttpHeaders, attachmentParts, false); + generateTest(name, methodName, wsdl, headerJSON, securityJSON, requestXML, requestJSON, responseXML, responseJSON, responseSoapHeaderJSON, wsdlOptions, options, responseHttpHeaders, attachmentParts, true); }); -function generateTest(name, methodName, wsdlPath, headerJSON, securityJSON, requestXML, requestJSON, responseXML, responseJSON, responseSoapHeaderJSON, wsdlOptions, options, usePromises){ +function generateTest(name, methodName, wsdlPath, headerJSON, securityJSON, requestXML, requestJSON, responseXML, responseJSON, responseSoapHeaderJSON, wsdlOptions, options, responseHttpHeaders, attachmentParts, usePromises){ var methodCaller = cbCaller; if (usePromises) { @@ -135,8 +151,15 @@ function generateTest(name, methodName, wsdlPath, headerJSON, securityJSON, requ suite[name] = function(done){ if(requestXML) requestContext.expectedRequest = requestXML; - if(responseXML) requestContext.responseToSend = responseXML; + if (responseXML) { + if (wsdlOptions.parseReponseAttachments) {//all LF to CRLF + responseXML = responseXML.replace(/\r\n/g, "\n"); + responseXML = responseXML.replace(/\n/g, "\r\n"); + } + requestContext.responseToSend = responseXML; + } requestContext.doneHandler = done; + requestContext.responseHttpHeaders = responseHttpHeaders; soap.createClient(wsdlPath, wsdlOptions, function(err, client){ if (headerJSON) { for (var headerKey in headerJSON) { @@ -152,12 +175,12 @@ function generateTest(name, methodName, wsdlPath, headerJSON, securityJSON, requ throw new Error('method ' + methodName + ' does not exists in wsdl specified in test wsdl: ' + wsdlPath); } - methodCaller(client, methodName, requestJSON, responseJSON, responseSoapHeaderJSON, options, done); + methodCaller(client, methodName, requestJSON, responseJSON, responseSoapHeaderJSON, options, attachmentParts, done); }, 'http://localhost:'+port+'/Message/Message.dll?Handler=Default'); }; } -function cbCaller(client, methodName, requestJSON, responseJSON, responseSoapHeaderJSON, options, done){ +function cbCaller(client, methodName, requestJSON, responseJSON, responseSoapHeaderJSON, options, attachmentParts, done){ client[methodName](requestJSON, function(err, json, body, soapHeader){ if(requestJSON){ if (err) { @@ -169,14 +192,18 @@ function cbCaller(client, methodName, requestJSON, responseJSON, responseSoapHea if(responseSoapHeaderJSON){ assert.equal(JSON.stringify(soapHeader), JSON.stringify(responseSoapHeaderJSON)); } + if(client.lastResponseAttachments){ + assert.deepEqual(client.lastResponseAttachments.parts,attachmentParts) + } } } done(); }, options); } -function promiseCaller(client, methodName, requestJSON, responseJSON, responseSoapHeaderJSON, options, done){ +function promiseCaller(client, methodName, requestJSON, responseJSON, responseSoapHeaderJSON, options, attachmentParts, done){ client[methodName](requestJSON).then(function(responseArr){ + const respAttachments = client.lastResponseAttachments; var json = responseArr[0]; var body = responseArr[1]; var soapHeader = responseArr[2]; @@ -187,6 +214,9 @@ function promiseCaller(client, methodName, requestJSON, responseJSON, responseSo if(responseSoapHeaderJSON){ assert.equal(JSON.stringify(soapHeader), JSON.stringify(responseSoapHeaderJSON)); } + if(client.lastResponseAttachments){ + assert.deepEqual(client.lastResponseAttachments.parts,attachmentParts) + } } }).catch(function(err) { if(requestJSON){ diff --git a/test/request-response-samples/getAttachments__should_handle_MTOM_response/attachmentParts.js b/test/request-response-samples/getAttachments__should_handle_MTOM_response/attachmentParts.js new file mode 100644 index 000000000..53924a64d --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_MTOM_response/attachmentParts.js @@ -0,0 +1,7 @@ +module.exports = [{ + body:Buffer.from("...binary data..."), + headers:{ + "content-type": "image/tiff", + "content-transfer-encoding": "binary" + } +}]; \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_MTOM_response/request.json b/test/request-response-samples/getAttachments__should_handle_MTOM_response/request.json new file mode 100644 index 000000000..f87ce7528 --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_MTOM_response/request.json @@ -0,0 +1,3 @@ +{ + "param":"123" +} \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_MTOM_response/request.xml b/test/request-response-samples/getAttachments__should_handle_MTOM_response/request.xml new file mode 100644 index 000000000..575506abc --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_MTOM_response/request.xml @@ -0,0 +1 @@ +123 \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_MTOM_response/response.json b/test/request-response-samples/getAttachments__should_handle_MTOM_response/response.json new file mode 100644 index 000000000..643d28ef9 --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_MTOM_response/response.json @@ -0,0 +1 @@ +{"attributes":{"soapenv:encodingStyle":"http://schemas.xmlsoap.org/soap/encoding/"},"attachment1":{"attributes":{"xsi:type":"xsd:base64Binary"},"$value":"cid:1186818862128"},"attachment2":{"attributes":{"xsi:type":"xsd:base64Binary"},"$value":"cid:536857424511"}} \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_MTOM_response/response.xml b/test/request-response-samples/getAttachments__should_handle_MTOM_response/response.xml new file mode 100644 index 000000000..7c394452f --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_MTOM_response/response.xml @@ -0,0 +1,23 @@ + +--MIME_boundary +Content-Type: text/xml; charset=UTF-8 +Content-Transfer-Encoding: 8bit + + + + + + cid:1186818862128 + cid:536857424511 + + + + +--MIME_boundary +Content-Type: image/tiff +Content-Transfer-Encoding: binary + +...binary data... +--MIME_boundary-- + + diff --git a/test/request-response-samples/getAttachments__should_handle_MTOM_response/responseHttpHeader.json b/test/request-response-samples/getAttachments__should_handle_MTOM_response/responseHttpHeader.json new file mode 100644 index 000000000..d6739f69a --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_MTOM_response/responseHttpHeader.json @@ -0,0 +1,3 @@ +{ + "content-type":"Multipart/Related; boundary=MIME_boundary; type=text/xml;" +} \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_MTOM_response/soap.wsdl b/test/request-response-samples/getAttachments__should_handle_MTOM_response/soap.wsdl new file mode 100644 index 000000000..78e87dd5e --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_MTOM_response/soap.wsdl @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WSDL File for MTOMService + + + + + \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_MTOM_response/wsdl_options.json b/test/request-response-samples/getAttachments__should_handle_MTOM_response/wsdl_options.json new file mode 100644 index 000000000..88a84c3d2 --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_MTOM_response/wsdl_options.json @@ -0,0 +1,3 @@ +{ + "parseReponseAttachments":true +} \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/request.json b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/request.json new file mode 100644 index 000000000..f87ce7528 --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/request.json @@ -0,0 +1,3 @@ +{ + "param":"123" +} \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/request.xml b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/request.xml new file mode 100644 index 000000000..575506abc --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/request.xml @@ -0,0 +1 @@ +123 \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/response.json b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/response.json new file mode 100644 index 000000000..643d28ef9 --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/response.json @@ -0,0 +1 @@ +{"attributes":{"soapenv:encodingStyle":"http://schemas.xmlsoap.org/soap/encoding/"},"attachment1":{"attributes":{"xsi:type":"xsd:base64Binary"},"$value":"cid:1186818862128"},"attachment2":{"attributes":{"xsi:type":"xsd:base64Binary"},"$value":"cid:536857424511"}} \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/response.xml b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/response.xml new file mode 100644 index 000000000..01e4eb62d --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/response.xml @@ -0,0 +1,9 @@ + + + + + cid:1186818862128 + cid:536857424511 + + + \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/soap.wsdl b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/soap.wsdl new file mode 100644 index 000000000..78e87dd5e --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/soap.wsdl @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WSDL File for MTOMService + + + + + \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/wsdl_options.json b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/wsdl_options.json new file mode 100644 index 000000000..88a84c3d2 --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/wsdl_options.json @@ -0,0 +1,3 @@ +{ + "parseReponseAttachments":true +} \ No newline at end of file