Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Staging API] To Use Staging Server or not to use staging server #15517

Merged
merged 10 commits into from
Mar 6, 2023
9 changes: 9 additions & 0 deletions config/proxyConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* These are the base API root used to send requests to the proxy.
* We only specify for staging URLs as API requests are sent to the production
* servers by default.
*/
module.exports = {
STAGING: '/staging-',
STAGING_SECURE: '/staging-secure-',
};
2 changes: 2 additions & 0 deletions config/webpack/webpack.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ module.exports = (env = {}) => portfinder.getPortPromise({port: BASE_PORT})
: {
proxy: {
'/api': 'http://[::1]:9000',
'/staging-api': 'http://[::1]:9000',
'/staging-secure-api': 'http://[::1]:9000',
'/chat-attachments': 'http://[::1]:9000',
},
};
Expand Down
1 change: 1 addition & 0 deletions src/CONFIG.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,5 @@ export default {
DEV_PORT: process.env.PORT || 8080,
E2E_TESTING: lodashGet(Config, 'E2E_TESTING', 'false') === 'true',
SEND_CRASH_REPORTS: lodashGet(Config, 'SEND_CRASH_REPORTS', 'false') === 'true',
IS_USING_WEB_PROXY: getPlatform() === 'web' && useWebProxy,
};
15 changes: 9 additions & 6 deletions src/libs/HttpUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import CONFIG from '../CONFIG';
import CONST from '../CONST';
import ONYXKEYS from '../ONYXKEYS';
import HttpsError from './Errors/HttpsError';
import shouldUseStagingServer from './shouldUseStagingServer';
import getPlatform from './getPlatform';
import proxyConfig from '../../config/proxyConfig';

// Desktop and web use staging config too so we we should default to staging API endpoint if on those platforms
const shouldDefaultToStaging = _.contains([CONST.PLATFORM.WEB, CONST.PLATFORM.DESKTOP], getPlatform());
Comment on lines 10 to 12
Copy link
Contributor

@kidroca kidroca Mar 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be the reason you're hitting staging @mountiny

The default should always be false now be false unless we're on staging

let stagingServerToggleState = false;
let shouldUseStagingServer = false;
Onyx.connect({
key: ONYXKEYS.USER,
callback: val => stagingServerToggleState = lodashGet(val, 'shouldUseStagingServer', shouldDefaultToStaging),
callback: val => shouldUseStagingServer = lodashGet(val, 'shouldUseStagingServer', shouldDefaultToStaging),
});

let shouldFailAllRequests = false;
Expand Down Expand Up @@ -109,10 +109,13 @@ function xhr(command, data, type = CONST.NETWORK.METHOD.POST, shouldUseSecure =

let apiRoot = shouldUseSecure ? CONFIG.EXPENSIFY.SECURE_EXPENSIFY_URL : CONFIG.EXPENSIFY.URL_API_ROOT;

if (shouldUseStagingServer(stagingServerToggleState)) {
apiRoot = shouldUseSecure ? CONFIG.EXPENSIFY.STAGING_SECURE_EXPENSIFY_URL : CONFIG.EXPENSIFY.STAGING_EXPENSIFY_URL;
if (shouldUseStagingServer) {
if (CONFIG.IS_USING_WEB_PROXY) {
apiRoot = shouldUseSecure ? proxyConfig.STAGING_SECURE : proxyConfig.STAGING;
} else {
apiRoot = shouldUseSecure ? CONFIG.EXPENSIFY.STAGING_SECURE_EXPENSIFY_URL : CONFIG.EXPENSIFY.STAGING_EXPENSIFY_URL;
}
}

return processHTTPRequest(`${apiRoot}api?command=${command}`, type, formData, data.canCancel);
}

Expand Down
13 changes: 0 additions & 13 deletions src/libs/shouldUseStagingServer/index.js

This file was deleted.

13 changes: 0 additions & 13 deletions src/libs/shouldUseStagingServer/index.native.js

This file was deleted.

50 changes: 39 additions & 11 deletions web/proxy.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
const http = require('http');
const https = require('https');
const proxyConfig = require('../config/proxyConfig');
require('dotenv').config();

if (process.env.USE_WEB_PROXY === 'false') {
process.stdout.write('Skipping proxy as USE_WEB_PROXY was set to false.\n');
process.exit();
}

let host = 'www.expensify.com';

// If we are testing against the staging API then we must use the correct host here or nothing with work.
if (/staging/.test(process.env.EXPENSIFY_URL)) {
host = 'staging.expensify.com';
}
const host = new URL(process.env.EXPENSIFY_URL || 'https://www.expensify.com').hostname;
const stagingHost = new URL(process.env.STAGING_EXPENSIFY_URL || 'https://staging.expensify.com').hostname;
const stagingSecureHost = new URL(process.env.STAGING_SECURE_EXPENSIFY_URL || 'https://staging-secure.expensify.com').hostname;

// eslint-disable-next-line no-console
console.log(`Creating proxy with host: ${host}`);
console.log(`Creating proxy with host: ${host} for production API and ${stagingHost} for staging API`);

/**
* Local proxy server that hits the production endpoint
Expand All @@ -24,13 +21,44 @@ console.log(`Creating proxy with host: ${host}`);
* environment that has no local API.
*/
const server = http.createServer((request, response) => {
let hostname = host;
let requestPath = request.url;

// Regex not declared globally to avoid internal regex pointer reset for each request.
const apiRegex = /(\/staging.*)api/g;
Prince-Mendiratta marked this conversation as resolved.
Show resolved Hide resolved

/**
* We only match staging api root to redirect requests to the staging server if the request
* is an API call, except chat attachments. By default, requests are sent to the prod server.
* For example,
* /api?command=OpenReport => request sent to production server
* /staging-api?command=OpenReport => request sent to staging server
* /staging-secure-api?command=OpenReport => request sent to secure staging server
* /chat-attachments/46545... => request sent to production server
*/
const apiRootMatch = apiRegex.exec(requestPath);

// Switch host only if API call, not on chat attachments.
if (apiRootMatch) {
const apiRoot = apiRootMatch[1];

// apiRoot can only be staging or secure staging
hostname = apiRoot === proxyConfig.STAGING_SECURE ? stagingSecureHost : stagingHost;

/**
* Replace the mapping url with the actual path.
* This is done because the staging api root is only intended for the proxy,
* the actual server request must use the /api path.
*/
requestPath = request.url.replace(apiRoot, '/');
Prince-Mendiratta marked this conversation as resolved.
Show resolved Hide resolved
}
const proxyRequest = https.request({
hostname: host,
hostname,
method: 'POST',
path: request.url,
path: requestPath,
headers: {
...request.headers,
host,
host: hostname,
'user-agent': request.headers['user-agent'].concat(' Development-NewDot/1.0'),
},
port: 443,
Expand Down