commit c1dd11d072eb6abaa6f9bb22ae375c90a62b3810 Author: mithun Date: Mon Dec 5 23:26:16 2016 +0530 Fix for , in URI diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index e890844..9ba265c 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -333,8 +333,9 @@ static const PQEnvironmentOption EnvironmentOptions[] = static const char uri_designator[] = "postgresql://"; static const char short_uri_designator[] = "postgres://"; -static bool connectOptions1(PGconn *conn, const char *conninfo); -static bool connectOptions2(PGconn *conn); +static bool connectOptions1(PGconn *conn, const char *conninfo, + bool *decode_hostname); +static bool connectOptions2(PGconn *conn, bool decode_hostname); static int connectDBStart(PGconn *conn); static int connectDBComplete(PGconn *conn); static PGPing internal_ping(PGconn *conn); @@ -346,14 +347,16 @@ static void release_all_addrinfo(PGconn *conn); static void sendTerminateConn(PGconn *conn); static PQconninfoOption *conninfo_init(PQExpBuffer errorMessage); static PQconninfoOption *parse_connection_string(const char *conninfo, - PQExpBuffer errorMessage, bool use_defaults); + PQExpBuffer errorMessage, bool use_defaults, + bool *decode_hostname); static int uri_prefix_length(const char *connstr); static bool recognized_connection_string(const char *connstr); static PQconninfoOption *conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, bool use_defaults); static PQconninfoOption *conninfo_array_parse(const char *const * keywords, const char *const * values, PQExpBuffer errorMessage, - bool use_defaults, int expand_dbname); + bool use_defaults, int expand_dbname, + bool *decode_hostname); static bool conninfo_add_defaults(PQconninfoOption *options, PQExpBuffer errorMessage); static PQconninfoOption *conninfo_uri_parse(const char *uri, @@ -575,6 +578,7 @@ PQconnectStartParams(const char *const * keywords, { PGconn *conn; PQconninfoOption *connOptions; + bool decode_hostname = false; /* * Allocate memory for the conn structure @@ -588,7 +592,8 @@ PQconnectStartParams(const char *const * keywords, */ connOptions = conninfo_array_parse(keywords, values, &conn->errorMessage, - true, expand_dbname); + true, expand_dbname, + &decode_hostname); if (connOptions == NULL) { conn->status = CONNECTION_BAD; @@ -613,7 +618,7 @@ PQconnectStartParams(const char *const * keywords, /* * Compute derived options */ - if (!connectOptions2(conn)) + if (!connectOptions2(conn, decode_hostname)) return conn; /* @@ -651,6 +656,7 @@ PGconn * PQconnectStart(const char *conninfo) { PGconn *conn; + bool decode_hostname = false; /* * Allocate memory for the conn structure @@ -662,13 +668,13 @@ PQconnectStart(const char *conninfo) /* * Parse the conninfo string */ - if (!connectOptions1(conn, conninfo)) + if (!connectOptions1(conn, conninfo, &decode_hostname)) return conn; /* * Compute derived options */ - if (!connectOptions2(conn)) + if (!connectOptions2(conn, decode_hostname)) return conn; /* @@ -734,14 +740,15 @@ fillPGconn(PGconn *conn, PQconninfoOption *connOptions) * and so is conn->status). */ static bool -connectOptions1(PGconn *conn, const char *conninfo) +connectOptions1(PGconn *conn, const char *conninfo, bool *decode_hostname) { PQconninfoOption *connOptions; /* * Parse the conninfo string */ - connOptions = parse_connection_string(conninfo, &conn->errorMessage, true); + connOptions = parse_connection_string(conninfo, &conn->errorMessage, true, + decode_hostname); if (connOptions == NULL) { conn->status = CONNECTION_BAD; @@ -776,7 +783,7 @@ connectOptions1(PGconn *conn, const char *conninfo) * and so is conn->status). */ static bool -connectOptions2(PGconn *conn) +connectOptions2(PGconn *conn, bool decode_hostname) { /* * Allocate memory for details about each host to which we might possibly @@ -819,6 +826,7 @@ connectOptions2(PGconn *conn) while (1) { char *e = s; + char *currhost = NULL; /* * Search for the end of the current hostname; a comma or @@ -828,12 +836,23 @@ connectOptions2(PGconn *conn) ++e; /* Copy the hostname whose bounds we just identified. */ - conn->connhost[i].host = - (char *) malloc(sizeof(char) * (e - s + 1)); - if (conn->connhost[i].host == NULL) + currhost = (char *) malloc(sizeof(char) * (e - s + 1)); + if (currhost == NULL) goto oom_error; - memcpy(conn->connhost[i].host, s, e - s); - conn->connhost[i].host[e - s] = '\0'; + memcpy(currhost, s, e - s); + currhost[e - s] = '\0'; + if (decode_hostname) + { + conn->connhost[i].host = + conninfo_uri_decode(currhost, &conn->errorMessage); + if (conn->connhost[i].host == NULL) + { + conn->status = CONNECTION_BAD; + return false; + } + } + else + conn->connhost[i].host = currhost; /* Identify the type of host. */ conn->connhost[i].type = CHT_HOST_NAME; @@ -1125,6 +1144,7 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, const char *pwd) { PGconn *conn; + bool decode_hostname = false; /* * Allocate memory for the conn structure @@ -1139,7 +1159,7 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, */ if (dbName && recognized_connection_string(dbName)) { - if (!connectOptions1(conn, dbName)) + if (!connectOptions1(conn, dbName, &decode_hostname)) return conn; } else @@ -1148,7 +1168,7 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, * Old-style path: first, parse an empty conninfo string in order to * set up the same defaults that PQconnectdb() would use. */ - if (!connectOptions1(conn, "")) + if (!connectOptions1(conn, "", &decode_hostname)) return conn; /* Insert dbName parameter value into struct */ @@ -1168,6 +1188,7 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, */ if (pghost && pghost[0] != '\0') { + decode_hostname = false; if (conn->pghost) free(conn->pghost); conn->pghost = strdup(pghost); @@ -1223,7 +1244,7 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, /* * Compute derived options */ - if (!connectOptions2(conn)) + if (!connectOptions2(conn, decode_hostname)) return conn; /* @@ -4560,7 +4581,7 @@ PQconninfoParse(const char *conninfo, char **errmsg) initPQExpBuffer(&errorBuf); if (PQExpBufferDataBroken(errorBuf)) return NULL; /* out of memory already :-( */ - connOptions = parse_connection_string(conninfo, &errorBuf, false); + connOptions = parse_connection_string(conninfo, &errorBuf, false, NULL); if (connOptions == NULL && errmsg) *errmsg = errorBuf.data; else @@ -4613,11 +4634,15 @@ conninfo_init(PQExpBuffer errorMessage) */ static PQconninfoOption * parse_connection_string(const char *connstr, PQExpBuffer errorMessage, - bool use_defaults) + bool use_defaults, bool *decode_hostname) { /* Parse as URI if connection string matches URI prefix */ if (uri_prefix_length(connstr) != 0) + { + if (decode_hostname) + *decode_hostname = true; return conninfo_uri_parse(connstr, errorMessage, use_defaults); + } /* Parse as default otherwise */ return conninfo_parse(connstr, errorMessage, use_defaults); @@ -4846,7 +4871,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, static PQconninfoOption * conninfo_array_parse(const char *const * keywords, const char *const * values, PQExpBuffer errorMessage, bool use_defaults, - int expand_dbname) + int expand_dbname, bool *decode_hostname) { PQconninfoOption *options; PQconninfoOption *dbname_options = NULL; @@ -4872,7 +4897,9 @@ conninfo_array_parse(const char *const * keywords, const char *const * values, */ if (recognized_connection_string(pvalue)) { - dbname_options = parse_connection_string(pvalue, errorMessage, false); + dbname_options = parse_connection_string(pvalue, errorMessage, + false, + decode_hostname); if (dbname_options == NULL) return NULL; } @@ -5327,9 +5354,18 @@ conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, /* Save final values for host and port. */ if (PQExpBufferDataBroken(hostbuf) || PQExpBufferDataBroken(portbuf)) goto cleanup; + + /* + * Delay URI decoding of hostname till connectOptions2(). The ',' is + * treated as separator in case of multihost connection string. If we + * decode the escaped comma here then it becomes impossible say what ',' + * represent. Frist let us split the hostname then decode the uri. + * We can decode port immediately now, as it takes only digits to represent + * them. + */ if (hostbuf.data[0] && !conninfo_storeval(options, "host", hostbuf.data, - errorMessage, false, true)) + errorMessage, false, false)) goto cleanup; if (portbuf.data[0] && !conninfo_storeval(options, "port", portbuf.data,