[Bug] `parseDatabaseUrl` removes path from URL
luchillo17 opened this issue · 12 comments
Bug Report
The parseDatabaseUrl
function completely ignores the path, these URLs are stripped from path resulting in the wrong web socket request, this happens when we use Ingress to serve the load balancer from a path deeper than the root:
neo4j://localhost/neo4j/bolt
gets transformed intolocalhost:7687
, the port change kind of makes sense since the driver assumes the default port, but the path is missing.neo4j://localhost:80/neo4j/bolt
gets transformed intolocalhost:80
which breaks because I expected the web socket request to land inws://localhost:80/neo4j/bolt
.
To be more precise what I'm doing is deploying the neo4j helm chart & then using Ingress to put the load balancer service behind a path in the cluster, it is clear in the function the query is never introduced again into the URL:
Please note that query is being passed down but the path isn't.
Location of the function: https://github.com/neo4j/neo4j-javascript-driver/blob/5.0/packages/core/src/internal/url-util.ts#L93-L108
My Environment
software name | version |
---|---|
OS | Windows 10 WSL2 Ubuntu |
Web browser | Chrome 113.0.5672.129 |
node.js | lts/gallium 16.20.0 |
npm | 8.19.4 |
yarn | 1.22.19 |
Neo4j Browser | neo4j/neo4j-browser#1922 |
Neo4j | - |
In case anyone is curious about my setup, the reason I had to use Ingress is because of a limitation on Docker Desktop on Windows, that doesn't forward the ports of the cluster to the host, however, another use case is what I mentioned, instead of a neo4j database available at root /
we could route it with Ingress and put it under a path like example.com/app1/db
.
https://gist.github.com/luchillo17/68c7496b0d5b0b9cd791c236f5924ad2
The driver connection url doesn't support paths.
Since the goal of the driver is keeping parity of functionality between different environments and languages, path in the url is not supported.
Supporting path can be handy for websockets since its api supported it. However, this feature is not supported by regular sockets.
About connection url see:
https://neo4j.com/docs/javascript-manual/current/connect-advanced/
https://neo4j.com/docs/java-manual/current/client-applications/#java-driver-connection-uris
That's a bummer, though I do lack context on the other languages like Java & Python, so basically the closest thing would be to expose the DB with an Ingress that uses a subdomain instead of a path like db.example.com:7467
right?, wonder if I can make it work with nip.io DNS proxy ips...
Yes, you should use subdomains because they will be resolve via dns.
It worked perfectly, thanks.
Nevermind, Browser works fine, but the Driver doesn't, this is what I get from the error when connecting with the driver and Apollo GraphQL
Ingress HTTP port for browser: http://neo4j.[IP].nip.io/browser/
Ingress TCP port for db connection: bolt://bolt.[IP].nip.io:80
For some reason Browser needs to use bolt://
protocol instead of neo4j://
to connect properly, but no matter what I pass to the driver in my app, I get this error:
"Neo4jError: Server responded HTTP. Make sure you are not trying to connect to the http endpoint (HTTP defaults to port 7474 whereas BOLT defaults to port 7687)",
" at new Neo4jError (webpack-internal:///(sc_server)/../../node_modules/.pnpm/neo4j-driver-core@5.9.1/node_modules/neo4j-driver-core/lib/error.js:76:16)",
" at newError (webpack-internal:///(sc_server)/../../node_modules/.pnpm/neo4j-driver-core@5.9.1/node_modules/neo4j-driver-core/lib/error.js:108:12)",
" at parseNegotiatedResponse (webpack-internal:///(sc_server)/../../node_modules/.pnpm/neo4j-driver-bolt-connection@5.9.1/node_modules/neo4j-driver-bolt-connection/lib/bolt/handshake.js:59:48)",
" at channel.onmessage (webpack-internal:///(sc_server)/../../node_modules/.pnpm/neo4j-driver-bolt-connection@5.9.1/node_modules/neo4j-driver-bolt-connection/lib/bolt/handshake.js:106:39)",
" at Socket.eval (webpack-internal:///(sc_server)/../../node_modules/.pnpm/neo4j-driver-bolt-connection@5.9.1/node_modules/neo4j-driver-bolt-connection/lib/channel/node/node-channel.js:167:26)",
" at Socket.emit (node:events:513:28)",
" at addChunk (node:internal/streams/readable:324:12)",
" at readableAddChunk (node:internal/streams/readable:297:9)",
" at Readable.push (node:internal/streams/readable:234:10)",
" at TCP.onStreamRead (node:internal/stream_base_commons:190:23)",
" at TCP.callbackTrampoline (node:internal/async_hooks:130:17)"
This error means the driver is trying to connect to a http server. The NodeJS
version of the driver doesn't make use of WebSockets
. Neo4j Browser
makes use of the javascript driver, but the driver uses websockets on the browsers.
Makes no sense to me why it works ok when using kubectl port-forward svc/neo4j-db-lb-neo4j tcp-bolt http https
but if I use Ingress to expose it, then it doesn't work
If the driver can connect properly to the port-forwarded tcp-bolt
but not to the same exposed through Ingress, either I'm configuring Ingress wrong or my Ingress implementation (nginx-ingress
) can't handle the protocol...
You can try to curl or telnet bolt://bolt.[IP].nip.io:80
, they are probably returning the http header.
Hi @luchillo17
I just want to share this draft PR with you as it might be helpful.
We are planning to release a new Helm Chart that provides a thin wrapper over the HAProxy helm chart. This will allow standard Kubernetes Ingress to work well with a Neo4j deployment.
It's not ideal as it means an extra service to manage but it seems to work well so far.