1 // ============LICENSE_START===============================================
2 // Copyright (C) 2021 Nordix Foundation. All rights reserved.
3 // ========================================================================
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 // ============LICENSE_END=================================================
17 // Basic http/https proxy
18 // Call the the proxy on 8080/8433 for http/https
19 // The destination (proxied) protocol may be http or https
20 // Proxy healthcheck on 8081/8434 for http/https - answers with statistics in json
22 const http = require('http');
23 const net = require('net');
24 const urlp = require('url');
25 const process = require('process')
26 const https = require('https');
27 const fs = require('fs');
29 // Proxy server port for http
30 const proxyport = 8080;
31 // Proxy server port for https
32 const proxyporthttps = 8433;
33 // Proyx server alive check, port for http
34 const aliveport = 8081;
35 // Proyx server alive check, port for https
36 const aliveporthttps = 8434;
38 // Default https destination port
39 const defaulthttpsport = "443";
41 // Certs etc for https
42 const httpsoptions = {
43 key: fs.readFileSync('cert/key.crt'),
44 cert: fs.readFileSync('cert/cert.crt'),
45 passphrase: fs.readFileSync('cert/pass', 'utf8')
49 'http-requests-initiated': 0,
50 'http-requests-failed': 0,
51 'https-requests-initiated': 0,
52 'https-requests-failed': 0
55 // handle a http proxy request
56 function httpclientrequest(clientrequest, clientresponse) {
57 stats['http-requests-initiated']++;
59 if (clientrequest.url == "/" ) {
60 console.log("Catch bad url in http request: "+clientrequest.url)
64 // Extract destination information
65 const clientrequesturl = new URL(clientrequest.url);
67 var proxyrequestoptions = {
68 'host': clientrequesturl.hostname,
69 'port': clientrequesturl.port,
70 'method': clientrequest.method,
71 'path': clientrequesturl.pathname+clientrequesturl.search,
72 'agent': clientrequest.agent,
73 'auth': clientrequest.auth,
74 'headers': clientrequest.headers
77 // Setup connection to destination
78 var proxyrequest = http.request(
80 function (proxyresponse) {
81 clientresponse.writeHead(proxyresponse.statusCode, proxyresponse.headers);
82 proxyresponse.on('data', function (chunk) {
83 clientresponse.write(chunk);
85 proxyresponse.on('end', function () {
92 // Handle the connection and data transfer between source and desitnation
93 proxyrequest.on('error', function (error) {
94 clientresponse.writeHead(500);
95 stats['http-requests-failed']++;
97 clientresponse.write("<h1>500 Error</h1>\r\n" + "<p>Error was <pre>" + error + "</pre></p>\r\n" + "</body></html>\r\n");
100 clientrequest.addListener('data', function (chunk) {
101 proxyrequest.write(chunk);
103 clientrequest.addListener('end', function () {
110 // -------------------- Alive server ----------------------------------
111 // Responde with '200' and statistics for any path on the alive address
112 const alivelistener = function (req, res) {
114 res.writeHead(200, { 'Content-Type': 'application/json' });
115 res.write(JSON.stringify(stats))
119 // The alive server - for healthckeck
120 const aliveserver = http.createServer(alivelistener);
122 // The alive server - for healthckeck
123 const aliveserverhttps = https.createServer(httpsoptions, alivelistener);
125 //Handle heatlhcheck requests
126 aliveserver.listen(aliveport, () => {
127 console.log('alive server on: '+aliveport);
128 console.log(' example: curl localhost: '+aliveport)
131 //Handle heatlhcheck requests
132 aliveserverhttps.listen(aliveporthttps, () => {
133 console.log('alive server on: '+aliveporthttps);
134 console.log(' example: curl -k https://localhost: '+aliveporthttps)
137 // -------------------- Proxy server ---------------------------------
140 const proxyserver = http.createServer(httpclientrequest).listen(proxyport);
141 console.log('http/https proxy for http proxy calls on port ' + proxyport);
142 console.log(' example: curl --proxy localhost:8080 http://pms:1234')
143 console.log(' example: curl -k --proxy localhost:8080 https://pms:5678')
145 const proxyserverhttps = https.createServer(httpsoptions, httpclientrequest).listen(proxyporthttps);
146 console.log('http/https proxy for https proxy calls on port ' + proxyporthttps);
147 console.log(' example: curl --proxy-insecure localhost:8433 http://pms:1234')
148 console.log(' example: curl --proxy-insecure localhost:8433 https://pms:5678')
149 console.log(' note: proxy shall not specify https')
151 // handle a http proxy request - https listener
152 proxyserver.addListener(
154 function (request, socketrequest, bodyhead) {
157 stats['https-requests-initiated']++;
158 // Extract destination information
159 var res = request['url'].split(":")
160 var hostname = res[0]
161 var port = defaulthttpsport;
162 if (res[1] != null) {
166 // Setup connection to destination
167 var httpversion = request['httpVersion'];
168 var proxysocket = new net.Socket();
171 parseInt(port), hostname,
173 proxysocket.write(bodyhead);
174 socketrequest.write("HTTP/" + httpversion + " 200 Connection established\r\n\r\n");
178 // Handle the connection and data transfer between source and desitnation
179 proxysocket.on('data', function (chunk) {
180 socketrequest.write(chunk);
182 proxysocket.on('end', function () {
186 socketrequest.on('data', function (chunk) {
187 proxysocket.write(chunk);
189 socketrequest.on('end', function () {
193 proxysocket.on('error', function (err) {
194 stats['https-requests-failed']++;
196 socketrequest.write("HTTP/" + httpversion + " 500 Connection error\r\n\r\n");
199 socketrequest.on('error', function (err) {
200 stats['https-requests-failed']++;
208 //Handle ctrl c when running in interactive mode
209 process.on('SIGINT', () => {
210 console.info("Interrupted")