UNPKG

6.15 kBJavaScriptView Raw
1'use strict';
2/**
3 * This plugin accumulates data chunks from the client into an array
4 * property on the request or response, concats them on end. Then
5 * transforms the request or response based on 'accept' or 'content-type'
6 * headers.
7 *
8 * If the HTTP verb is GET and the Accept type does not match the
9 * response type, the plugin will attempt to transform it (from
10 * xml to json or vice versa).
11 *
12 * If the HTTP verb is NOT GET then the content-type is used. If the
13 * content-type is set to 'json', then an attempt is made to transform to
14 * 'xml' and vice-versa.
15 *
16 * This plugin can be disabled by sending the 'x-apigee-json2xml' http
17 * header.
18 *
19 * Users should be aware that buffering large requests or responses in
20 * memory can cause Apigee Edge Microgateway to run out of memory under
21 * high load or with a large number of concurrent requests. So this plugin
22 * should only be used when it is known that request/response bodies are small.
23 */
24
25var debug = require('debug')('plugin:json2xml');
26//library to convert json to xml
27var js2xmlparser = require("js2xmlparser");
28//library to convert xml to json
29var parseString = require("xml2js").parseString;
30var util = require("util");
31
32module.exports.init = function (config, logger, stats) {
33
34 //initialize the variables to false
35
36 //variables to control whether request and/or response transformation should take place
37 var requestXML = false;
38 var requestJSON = false;
39 var responseJSON = false;
40 var responseXML = false;
41 //use these variables to determine the content type of response sent by target server
42 var responseIsXML = false;
43 var responseIsJSON = false;
44 //flag to control whether transfornation should take place
45 var disable = false;
46
47 //method to accumulate responses
48 function accumulateResponse(res, data) {
49 debug('plugin accumulateResponse');
50 if (!res._chunks) res._chunks = [];
51 res._chunks.push(data);
52 }
53
54 //method to accumulate requests
55 function accumulateRequest(req, data) {
56 debug('plugin accumulateRequest');
57 if (disable) return;
58 if (!req._chunks) req._chunks = [];
59 req._chunks.push(data);
60 }
61
62 return {
63
64 onrequest: function(req, res, next) {
65 debug('plugin onrequest');
66 var method = req.method.toLowerCase();
67 var acceptType = req.headers['accept'];
68 var contentType = req.headers['content-type'];
69
70 if (req.headers['x-apigee-json2xml-disable']) disable = true;
71
72 debug("accept header: " + acceptType);
73 debug("content-type header: " + contentType);
74
75 //if plugin is disabled don't process headers.
76 if (!disable) {
77 if (method === "get" && acceptType.indexOf("application/xml") > -1) {
78 responseXML = true;
79 } else if (method === "get" && acceptType.indexOf("application/json") > -1) {
80 responseJSON = true;
81 } else if (method !== "get" && contentType.indexOf("application/json") > -1) {
82 requestJSON = true;
83 responseJSON = true;
84 } else if (method !== "get" && contentType.indexOf("application/xml") > -1) {
85 requestXML = true;
86 responseXML = true;
87 }
88 }
89
90 debug("requestJSON flag is " + requestJSON);
91 debug("responseJSON flag is " + responseJSON);
92
93 debug("requestXML flag is " + requestXML);
94 debug("responseXML flag is " + responseXML);
95
96 debug("plugin disabled: " + disable);
97
98 next();
99 },
100 // indicates start of target response
101 // response headers and status code should be available at this time
102 onresponse: function(req, res, next) {
103 debug('plugin onresponse');
104 //nothing to do on response
105 next();
106 },
107 //
108 ondata_request: function(req, res, data, next) {
109 debug('plugin ondata_request');
110 if (data && data.length > 0 && disable == false) accumulateRequest(req, data);
111 next(null, null);
112 },
113 //
114 //
115 ondata_response: function(req, res, data, next) {
116 debug('plugin ondata_response');
117 if (data && data.length > 0 && disable == false) accumulateResponse(res, data);
118 next(null, null);
119 },
120 //
121 onend_request: function(req, res, data, next) {
122 debug('plugin onend_request');
123 if (data && data.length > 0 && disable == false) accumulateRequest(res, data);
124 var content = null;
125 if(req._chunks && req._chunks.length) {
126 content = Buffer.concat(req._chunks);
127 }
128 delete req._chunks;
129
130 //if pugin is disabled, don't do anything
131 if (!disable) {
132 if (requestJSON) {
133 //the request needs to be transformed to xml before sending to
134 //the target server.
135
136 //set request content type.
137 req.setHeader('Content-Type', 'application/xml');
138 next(null, js2xmlparser.parse("Root",JSON.parse(content)));
139 } else if (requestXML) {
140 //set request content type.
141 req.setHeader('Content-Type', 'application/json');
142 parseString(content.toString(), function(err, js){
143 if (err) next (err);
144 next(null, JSON.stringify(js));
145 });
146 } else { //do nothing
147 next(null, content);
148 }
149 } else {
150 next(null, content);
151 }
152 },
153 //
154 onend_response: function(req, res, data, next) {
155 debug('plugin onend_request');
156 if (data && data.length > 0 && disable == false) accumulateResponse(res, data);
157
158 var contentType = res.getHeader('content-type');
159 if (contentType && contentType.indexOf("application/xml") > -1) {
160 responseIsXML = true;
161 } else if (contentType && contentType.indexOf("application/json") > -1) {
162 responseIsJSON = true;
163 }
164
165 debug("responseIsJSON flag is " + responseIsJSON);
166 debug("responseIsXML flag is" + responseIsXML);
167
168
169 var content = null;
170 if(res._chunks && res._chunks.length) {
171 content = Buffer.concat(res._chunks);
172 }
173 delete res._chunks;
174
175 //if disabled don't do anything.
176 if (!disable) {
177 if (responseXML && responseIsJSON) {
178 res.setHeader('Content-Type', 'application/xml');
179 next(null, js2xmlparser.parse("Root",JSON.parse(content)));
180 } else if (responseJSON && responseIsXML) {
181 res.setHeader('Content-Type', 'application/json');
182 parseString(content.toString(), function(err, js){
183 if (err) next (err);
184 next(null, JSON.stringify(js));
185 });
186 } else {
187 next(null, content);
188 }
189 } else {
190 next(null, content);
191 }
192 }
193 };
194}