Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions deploy/nginx/common/routes-core.conf
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
# location is chosen, because the literal locations below do not match a ';'
# and would hand it to Java. $request_uri is the path as sent: an encoded
# ';' (%3B) is part of an id, as it is to Java, and a ';' in the query string
# is the query's.
# is the query's. That holds only because Java is sent the path as sent, too
# (the /ContentService/ location below).
error_page 418 = @content_node_refuses;
if ($request_uri ~ "^/ContentService/[^?]*;") { return 418; }
location @content_node_refuses {
Expand Down Expand Up @@ -511,7 +512,14 @@ location ~ ^/gsa(/|$) { return 301 /PathwayBrowser?analysisTab=quantitative; }

location /ContentService/ {
include /etc/nginx/common/upstream-proxy.conf;
proxy_pass http://content/ContentService/;
# No URI part: Tomcat is sent the request's path as it was sent, not
# nginx's decoded copy. With one, an encoded ';' reached Java as a raw one
# and Java dropped it as a matrix parameter -- so /data/query%3Bx/R-HSA-1,
# which no node location matches, was answered by Java as node's
# /data/query/R-HSA-1: a node route answered by Java, the fallback the
# port rules out. (No braces in comments here: routes.spec.ts reads a
# location's body up to its first closing one.)
proxy_pass http://content;
# A diagram or SBML export takes minutes. Apache's default is 300s and the
# site relies on it; nginx defaults to 60 and would cut them off.
proxy_read_timeout 300s;
Expand All @@ -520,7 +528,9 @@ location /ContentService/ {

location /AnalysisService/ {
include /etc/nginx/common/upstream-proxy.conf;
proxy_pass http://analysis/AnalysisService/;
# No URI part, as for /ContentService/: the path as sent, never nginx's
# decoded copy of it.
proxy_pass http://analysis;
# An analysis over a large identifier list is not quick either.
proxy_read_timeout 300s;
proxy_send_timeout 300s;
Expand Down
19 changes: 19 additions & 0 deletions deploy/nginx/routes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,25 @@ describe('a matrix parameter', () => {
]);
});

it('reaches Java encoded, as sent, so Java cannot drop it as one', () => {
// A proxy_pass with a URI part sends nginx's decoded path: %3B arrives at
// Tomcat as ';', which it drops as a matrix parameter, and
// /data/query%3Bx/{id} -- no node location's -- is answered by Java as
// node's /data/query/{id}. Without one, Tomcat gets the path as sent;
// the AnalysisService's too.
const core = readFileSync(join(__dirname, 'common', 'routes-core.conf'), 'utf8');
for (const [service, upstream] of [
['ContentService', 'content'],
['AnalysisService', 'analysis'],
]) {
const block = new RegExp(`^location /${service}/ \\{([^}]*)\\}`, 'm').exec(core)?.[1] ?? '';
expect([service, block.match(/^\s*proxy_pass\s+[^;]*;/gm)]).toEqual([
service,
[` proxy_pass http://${upstream};`],
]);
}
});

it('is not an encoded one, nor one in the query string', async () => {
for (const url of [
'/ContentService/data/query/abridged/R-HSA-109581%3Bx',
Expand Down
Loading