The request in Parse.Object.saveAll() does not have a reverse proxy
New Issue Checklist
- [x] I am not disclosing a vulnerability.
- [x] I am not just asking a question.
- [x] I have searched through existing issues.
- [x] I can reproduce the issue with the latest versions of Parse Server and the Parse JS SDK.
Issue Description
I was wondering about the practical method behind Parse.Object.saveAll, If my Parse Server I want to redirect through Proxy ex: 192.168.1.1/api -> 192.168.1.1:4000/parse then, here is the problem.
on the parse/lib/node/ParseObject.js line:2388
return RESTController.request('POST', 'batch', {
requests: batch.map(obj => {
const params = obj._getSaveParams();
params.path = getServerUrlPath() + params.path;
return params;
})
}, options);
And here is the problem, After the above code, my input data format will be like this:
{
"requests": [
{
"method": "PUT",
"path": "/api/classes/{{className}}/{{ objectId }}",
"body": {
{{ Here is the object body}}
}
}
]
}
and then, as you can see the RESTController will send a axios POST for url -> 192.168.1.1/api/batch and then proxy server (nginx), will let the request send to the 192.168.1.1:4000/parse/batch, but in my requests body, the path only show it to /api/classes/{{className}}/{{objectId}} , it wont through the nginx setting to let the redirect change to /parse/classes/{{className}}/{{objectId}}
Steps to reproduce
//config.js
const parseUrl = process.env.PARSE_URL || 'http://192.168.1.1/api'; // the nginx will let the 192.168.1.1/api turn into 192.168.1.1:4000/parse
const appId = 'test';
const masterKey = 'test-key';
const initParse = () => {
Parse.initialize(appId, null, masterKey);
Parse.serverURL = parseUrl;
Parse.User.enableUnsafeCurrentUser();
};
const query = new Parse.Query(Tests);
const tests = await query.findAll()
tests.forEach((test) => {
test.set('name', 'something');
})
await Parse.Object.saveAll(tests); // And then show the error code 206
Actual Outcome
format : Parse Error: cannot route batch path: /api/classes/{{className}}/{{objectId}} { code: 111 }
real outcome: ParseError: cannot route batch path /api/classes/tests/6ab89f70-addf-11ed-b17e-f98dadf7fe5c at C:\Users.......\node_modules\parse\lib\node\ParseObject.js:3047:34 at processTicksAndRejections (node:internal/process/task_queues:96:5) { code: 111 }, . . .
Expected Outcome
Expected it can saveAll and the response won't fail
Environment
Nginx
location /api/ {
#proxy_redirect off;
#proxy_set_header Host $host;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET,POST,OPTIONS';
add_header Access-Control-Allow-Headers 'Content-Type, X-DP-Token, X-DP-Application-Id';
#proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://192.168.1.1:4000/parse/;
client_max_body_size 16M;
}
Server
- Parse Server version: 6.2.0
- Operating system: linux
Database
- MongoDB
Client
- Parse JS SDK version: 4.1.0
Thanks for opening this issue!
- 🚀 You can help us to fix this issue faster by opening a pull request with a failing test. See our Contribution Guide for how to make a pull request, or read our New Contributor's Guide if this is your first time contributing.
Could you please complete the issue template (I've re-added the headlines) and ensure that you follow the checklist at the top?
Could you please complete the issue template (I've re-added the headlines) and ensure that you follow the checklist at the top?
I already fix it, and very sorry about didn't follow the issue template, cause this is the first time I try to send the issue.
No worries, thanks for reporting the issue. The template just helps others to easier understand the issue.
In the steps to reproduce you are first querying tests and then saving all users. How are tests and users related?
sorry, it was tests not users. I already edited it. and also add setting code about the nginx setting. and you can check it.
Could you please correct the code and make sure it's complete?
Could you please correct the code and make sure it's complete?
I corrected it. Here are some additions, where my parse server is set on port :4000/parse on docker, so you can see above that I use an nginx as a reverse proxy to /api -> :4000/parse
Could you post the line from ParseObject.js:3047:34?
(0, _promiseUtils.when)(batchReady).then(() => {
// Kick off the batch request
return RESTController.request('POST', 'batch', {
requests: batch.map(obj => {
const params = obj._getSaveParams();
params.path = getServerUrlPath() + params.path;
return params;
})
}, options);
}).then(batchReturned.resolve, error => {
batchReturned.reject(new _ParseError.default(_ParseError.default.INCORRECT_TYPE, error.message));
});
The error show up on the batchReturned ... this line and then I see the function getServerUrlPath() how it works,
function getServerUrlPath() {
let serverUrl = _CoreManager.default.get('SERVER_URL');
if (serverUrl[serverUrl.length - 1] !== '/') {
serverUrl += '/';
}
const url = serverUrl.replace(/https?:\/\//, '');
return url.substr(url.indexOf('/'));
}
so as you can see, if my parseUrl is 'http://192.168.1.1/api' and I use a reverse proxy to make this url to redirect on the Parse Server (this is setup on the docker url: '192.168.1.1:4000/parse'), and I can see the request is sending to the url 'http://192.168.1.1/api' and then turn into the 'https://192.168.1.1:4000/parse', but the getServerUrlPath() didn't know I was trying to use reverse proxy skill, so params.path = getServerUrlPath() + params.path; it will show up like /api/classes/{className}/{objectId} and not like this /parse/classes/{className}/{objectId},
for example:
{
"requests": [
{
"method": "POST",
"path": "/api/classes/GameScore",
"body": {
"score": 1337,
"playerName": "Sean Plott"
}
},
{
"method": "POST",
"path": "/api/classes/GameScore",
"body": {
"score": 1338,
"playerName": "ZeroCool"
}
}
]
}'
request url : https://192.168.1.1/api/ -> and then proxy will send into https://192.168.1.1:4000/parse
request method: post
but the every request object's attribute 'path' won't change to /parse/....
Sorry for my english is not very good so please forgive me :( if i didn't explain clearly
Thanks for providing more details, let's see if someone in the community has an idea...