How Database Credentials Are URL-Encoded in the Connection String
The junjiem/dify-plugin-tools-dbquery plugin uses urllib.parse.quote_plus in the DbUtil.get_url method to percent-encode usernames, passwords, and hostnames before constructing the SQLAlchemy connection URL.
The dify-plugin-tools-dbquery repository provides secure database query capabilities for the Dify platform. When handling user-provided credentials that may contain URL-reserved characters—such as @, :, /, or spaces—the plugin must sanitize these values to prevent connection string parsing failures. This is accomplished through systematic encoding within the utility class before the final URL is assembled.
The Encoding Mechanism in DbUtil.get_url
The core implementation resides in db_query/tools/db_util.py (and identically in db_query_pre_auth/tools/db_util.py). The DbUtil class exposes the get_url method, which orchestrates the safety transformation of credential components.
Step 1: Percent-Encoding with quote_plus
Each credential component is passed through urllib.parse.quote_plus (imported as parse) to convert illegal URL characters into their percent-encoded equivalents. According to lines 54–56 in db_query/tools/db_util.py, the plugin encodes the username, password, and host individually:
parsed_username = parse.quote_plus(self.username) # → URL‑encoded user
parsed_password = parse.quote_plus(self.password) # → URL‑encoded password
parsed_host = parse.quote_plus(self.host) # → URL‑encoded host
This ensures that special characters like spaces become %20, @ becomes %40, and / becomes %2F, preventing them from being misinterpreted as URL delimiters.
Step 2: URL Construction
After encoding, the sanitized components are interpolated into the driver-specific scheme at line 57:
url = f"{self.get_driver_name()}://{parsed_username}:{parsed_password}@{parsed_host}"
The colon between username and password and the @ symbol before the host are now safe literal characters because the credential values themselves contain no unencoded reserved symbols.
Driver Mapping and Optional Components
The get_driver_name method (lines 38–48 in the same file) maps the generic db_type parameter to SQLAlchemy-compatible driver strings. Port numbers, database names, and additional query parameters are appended after the host segment, though these numeric and path components typically do not require the same encoding treatment as credentials.
Practical Code Examples
PostgreSQL with Special Characters
The following example demonstrates encoding of spaces, @, !, and / characters:
from db_query.tools.db_util import DbUtil
db = DbUtil(
db_type="postgresql",
username="my user", # contains a space
password="pa@ss!", # contains @ and !
host="my/host", # contains a slash
port="5432",
database="mydb"
)
print(db.get_url())
# Output:
# postgresql+psycopg2://my%20user:pa%40ss%21@my%2Fhost:5432/mydb
MySQL with Colons and Slashes
This example shows how : and / within passwords are handled:
db_mysql = DbUtil(
db_type="mysql",
username="root",
password="p@ss:w/ord", # colon and slash need encoding
host="127.0.0.1",
port="3306",
database="testdb"
)
print(db_mysql.get_url())
# Output:
# mysql+pymysql://root:p%40ss%3Aw%2Ford@127.0.0.1:3306/testdb
Summary
- The
DbUtil.get_urlmethod indb_query/tools/db_util.pyhandles all credential encoding for the plugin urllib.parse.quote_pluspercent-encodes the username, password, and host before URL assembly- This prevents authentication failures caused by URL-reserved characters like
@,:,/, and whitespace - The driver name mapping (lines 38–48) ensures the encoded credentials are wrapped in the correct SQLAlchemy protocol scheme
- Both the standard
db_queryanddb_query_pre_authvariants implement identical encoding logic for consistency
Frequently Asked Questions
Why does the plugin use quote_plus instead of quote?
quote_plus encodes spaces as plus signs (+) rather than %20, following the application/x-www-form-urlencoded standard. While SQLAlchemy accepts both encodings, quote_plus ensures broader compatibility with database drivers that expect traditional form encoding for credential components, particularly in connection string query parameters.
Which specific fields get URL-encoded in the connection string?
According to the source code at lines 54–56 of db_query/tools/db_util.py, the plugin explicitly encodes three fields: self.username, self.password, and self.host. The port number and database name are appended without additional encoding, as they occupy positions in the URL structure where reserved characters are less likely to cause parsing ambiguity.
What happens if my password contains a percent sign?
A literal % character in your password is encoded as %25 by quote_plus. This double-encoding ensures that SQLAlchemy's URL parser interprets the original percent sign as data rather than the beginning of an escape sequence, preventing authentication errors when connecting with passwords containing percent symbols.
Where is the driver name mapping defined?
The get_driver_name method between lines 38–48 in db_query/tools/db_util.py provides the translation logic. It maps generic database types (e.g., "postgresql", "mysql") to specific driver strings (e.g., "postgresql+psycopg2", "mysql+pymysql"), ensuring the encoded credentials are injected into a valid SQLAlchemy-compatible connection scheme.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →