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 () {
108 // Function to add a 'connect' message listener to a http server
109 function addhttpsconnect(httpserver) {
110 httpserver.addListener(
112 function (request, socketrequest, bodyhead) {
115 stats['https-requests-initiated']++;
116 // Extract destination information
117 var res = request['url'].split(":")
118 var hostname = res[0]
119 var port = defaulthttpsport;
120 if (res[1] != null) {
124 // Setup connection to destination
125 var httpversion = request['httpVersion'];
126 var proxysocket = new net.Socket();
129 parseInt(port), hostname,
131 proxysocket.write(bodyhead);
132 socketrequest.write("HTTP/" + httpversion + " 200 Connection established\r\n\r\n");
136 // Handle the connection and data transfer between source and desitnation
137 proxysocket.on('data', function (chunk) {
138 socketrequest.write(chunk);
140 proxysocket.on('end', function () {
144 socketrequest.on('data', function (chunk) {
145 proxysocket.write(chunk);
147 socketrequest.on('end', function () {
151 proxysocket.on('error', function (err) {
152 stats['https-requests-failed']++;
154 socketrequest.write("HTTP/" + httpversion + " 500 Connection error\r\n\r\n");
157 socketrequest.on('error', function (err) {
158 stats['https-requests-failed']++;
168 // -------------------- Alive server ----------------------------------
169 // Responde with '200' and statistics for any path on the alive address
170 const alivelistener = function (req, res) {
172 res.writeHead(200, { 'Content-Type': 'application/json' });
173 res.write(JSON.stringify(stats))
177 // The alive server - for healthckeck
178 const aliveserver = http.createServer(alivelistener);
180 // The alive server - for healthckeck
181 const aliveserverhttps = https.createServer(httpsoptions, alivelistener);
183 //Handle heatlhcheck requests
184 aliveserver.listen(aliveport, () => {
185 console.log('alive server on: '+aliveport);
186 console.log(' example: curl localhost:'+aliveport)
189 //Handle heatlhcheck requests
190 aliveserverhttps.listen(aliveporthttps, () => {
191 console.log('alive server on: '+aliveporthttps);
192 console.log(' example: curl -k https://localhost:'+aliveporthttps)
195 // -------------------- Proxy server ---------------------------------
198 const proxyserver = http.createServer(httpclientrequest).listen(proxyport);
199 console.log('http/https proxy for http proxy calls on port ' + proxyport);
200 console.log(' example: curl --proxy http://localhost:8080 http://100.110.120.130:1234')
201 console.log(' example: curl -k --proxy http//localhost:8080 https://100.110.120.130:5678')
203 // handle a http proxy request - https listener
204 addhttpsconnect(proxyserver);
206 const proxyserverhttps = https.createServer(httpsoptions, httpclientrequest).listen(proxyporthttps);
207 console.log('http/https proxy for https proxy calls on port ' + proxyporthttps);
208 console.log(' example: curl --proxy-insecure --proxy https://localhost:8433 http://100.110.120.130:1234')
209 console.log(' example: curl --proxy-insecure --proxy https://localhost:8433 https://100.110.120.130:5678')
211 // handle a https proxy request - https listener
212 addhttpsconnect(proxyserverhttps);
216 //Handle ctrl c when running in interactive mode
217 process.on('SIGINT', () => {
218 console.info("Interrupted")