Skip to content

Commit 06d608b

Browse files
committed
Merge pull request #624
2 parents 223d1b9 + ce328f1 commit 06d608b

21 files changed

+1053
-177
lines changed

php_phongo.c

Lines changed: 189 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,42 @@ static mongoc_uri_t *php_phongo_make_uri(const char *uri_string, bson_t *options
927927
return uri;
928928
} /* }}} */
929929

930+
static const char *php_phongo_bson_type_to_string(bson_type_t type) /* {{{ */
931+
{
932+
switch (type) {
933+
case BSON_TYPE_EOD: return "EOD";
934+
case BSON_TYPE_DOUBLE: return "double";
935+
case BSON_TYPE_UTF8: return "string";
936+
case BSON_TYPE_DOCUMENT: return "document";
937+
case BSON_TYPE_ARRAY: return "array";
938+
case BSON_TYPE_BINARY: return "Binary";
939+
case BSON_TYPE_UNDEFINED: return "undefined";
940+
case BSON_TYPE_OID: return "ObjectID";
941+
case BSON_TYPE_BOOL: return "boolean";
942+
case BSON_TYPE_DATE_TIME: return "UTCDateTime";
943+
case BSON_TYPE_NULL: return "null";
944+
case BSON_TYPE_REGEX: return "Regex";
945+
case BSON_TYPE_DBPOINTER: return "DBPointer";
946+
case BSON_TYPE_CODE: return "Javascript";
947+
case BSON_TYPE_SYMBOL: return "symbol";
948+
case BSON_TYPE_CODEWSCOPE: return "Javascript with scope";
949+
case BSON_TYPE_INT32: return "32-bit integer";
950+
case BSON_TYPE_TIMESTAMP: return "Timestamp";
951+
case BSON_TYPE_INT64: return "64-bit integer";
952+
case BSON_TYPE_DECIMAL128: return "Decimal128";
953+
case BSON_TYPE_MAXKEY: return "MaxKey";
954+
case BSON_TYPE_MINKEY: return "MinKey";
955+
default: return "unknown";
956+
}
957+
} /* }}} */
958+
959+
#define PHONGO_URI_INVALID_TYPE(iter, expected) \
960+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, \
961+
"Expected %s for \"%s\" URI option, %s given", \
962+
(expected), \
963+
bson_iter_key(&(iter)), \
964+
php_phongo_bson_type_to_string(bson_iter_type(&(iter))))
965+
930966
static bool php_phongo_apply_options_to_uri(mongoc_uri_t *uri, bson_t *options TSRMLS_DC) /* {{{ */
931967
{
932968
bson_iter_t iter;
@@ -949,12 +985,14 @@ static bool php_phongo_apply_options_to_uri(mongoc_uri_t *uri, bson_t *options T
949985
!strcasecmp(key, MONGOC_URI_SAFE) ||
950986
!strcasecmp(key, MONGOC_URI_SLAVEOK) ||
951987
!strcasecmp(key, MONGOC_URI_W) ||
952-
!strcasecmp(key, MONGOC_URI_WTIMEOUTMS) ||
953-
!strcasecmp(key, MONGOC_URI_APPNAME)) {
988+
!strcasecmp(key, MONGOC_URI_WTIMEOUTMS)) {
954989
continue;
955990
}
956991

957992
if (mongoc_uri_option_is_bool(key)) {
993+
/* The option's type is not validated because bson_iter_as_bool() is
994+
* used to cast the value to a boolean. Validation may be introduced
995+
* in PHPC-990. */
958996
if (!mongoc_uri_set_option_as_bool(uri, key, bson_iter_as_bool(&iter))) {
959997
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Failed to parse \"%s\" URI option", key);
960998
return false;
@@ -963,7 +1001,12 @@ static bool php_phongo_apply_options_to_uri(mongoc_uri_t *uri, bson_t *options T
9631001
continue;
9641002
}
9651003

966-
if (mongoc_uri_option_is_int32(key) && BSON_ITER_HOLDS_INT32(&iter)) {
1004+
if (mongoc_uri_option_is_int32(key)) {
1005+
if (!BSON_ITER_HOLDS_INT32(&iter)) {
1006+
PHONGO_URI_INVALID_TYPE(iter, "32-bit integer");
1007+
return false;
1008+
}
1009+
9671010
if (!mongoc_uri_set_option_as_int32(uri, key, bson_iter_int32(&iter))) {
9681011
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Failed to parse \"%s\" URI option", key);
9691012
return false;
@@ -972,60 +1015,93 @@ static bool php_phongo_apply_options_to_uri(mongoc_uri_t *uri, bson_t *options T
9721015
continue;
9731016
}
9741017

975-
if (mongoc_uri_option_is_utf8(key) && BSON_ITER_HOLDS_UTF8(&iter)) {
1018+
if (mongoc_uri_option_is_utf8(key)) {
1019+
if (!BSON_ITER_HOLDS_UTF8(&iter)) {
1020+
PHONGO_URI_INVALID_TYPE(iter, "string");
1021+
return false;
1022+
}
1023+
9761024
if (!mongoc_uri_set_option_as_utf8(uri, key, bson_iter_utf8(&iter, NULL))) {
977-
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Failed to parse \"%s\" URI option", key);
1025+
/* Assignment uses mongoc_uri_set_appname() for the "appname"
1026+
* option, which validates length in addition to UTF-8 encoding.
1027+
* For BC, we report the invalid string to the user. */
1028+
if (!strcasecmp(key, MONGOC_URI_APPNAME)) {
1029+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Invalid appname value: '%s'", bson_iter_utf8(&iter, NULL));
1030+
} else {
1031+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Failed to parse \"%s\" URI option", key);
1032+
}
9781033
return false;
9791034
}
9801035

9811036
continue;
9821037
}
9831038

984-
if (BSON_ITER_HOLDS_UTF8(&iter)) {
985-
const char *value = bson_iter_utf8(&iter, NULL);
986-
987-
if (!strcasecmp(key, "username")) {
988-
if (!mongoc_uri_set_username(uri, value)) {
989-
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Failed to parse \"%s\" URI option", key);
990-
return false;
991-
}
1039+
if (!strcasecmp(key, "username")) {
1040+
if (!BSON_ITER_HOLDS_UTF8(&iter)) {
1041+
PHONGO_URI_INVALID_TYPE(iter, "string");
1042+
return false;
1043+
}
9921044

993-
continue;
1045+
if (!mongoc_uri_set_username(uri, bson_iter_utf8(&iter, NULL))) {
1046+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Failed to parse \"%s\" URI option", key);
1047+
return false;
9941048
}
9951049

996-
if (!strcasecmp(key, "password")) {
997-
if (!mongoc_uri_set_password(uri, value)) {
998-
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Failed to parse \"%s\" URI option", key);
999-
return false;
1000-
}
1050+
continue;
1051+
}
10011052

1002-
continue;
1053+
if (!strcasecmp(key, "password")) {
1054+
if (!BSON_ITER_HOLDS_UTF8(&iter)) {
1055+
PHONGO_URI_INVALID_TYPE(iter, "string");
1056+
return false;
10031057
}
10041058

1005-
if (!strcasecmp(key, MONGOC_URI_AUTHMECHANISM)) {
1006-
if (!mongoc_uri_set_auth_mechanism(uri, value)) {
1007-
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Failed to parse \"%s\" URI option", key);
1008-
return false;
1009-
}
1059+
if (!mongoc_uri_set_password(uri, bson_iter_utf8(&iter, NULL))) {
1060+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Failed to parse \"%s\" URI option", key);
1061+
return false;
1062+
}
10101063

1011-
continue;
1064+
continue;
1065+
}
1066+
1067+
if (!strcasecmp(key, MONGOC_URI_AUTHMECHANISM)) {
1068+
if (!BSON_ITER_HOLDS_UTF8(&iter)) {
1069+
PHONGO_URI_INVALID_TYPE(iter, "string");
1070+
return false;
10121071
}
10131072

1014-
if (!strcasecmp(key, MONGOC_URI_AUTHSOURCE)) {
1015-
if (!mongoc_uri_set_auth_source(uri, value)) {
1016-
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Failed to parse \"%s\" URI option", key);
1017-
return false;
1018-
}
1073+
if (!mongoc_uri_set_auth_mechanism(uri, bson_iter_utf8(&iter, NULL))) {
1074+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Failed to parse \"%s\" URI option", key);
1075+
return false;
1076+
}
10191077

1020-
continue;
1078+
continue;
1079+
}
1080+
1081+
if (!strcasecmp(key, MONGOC_URI_AUTHSOURCE)) {
1082+
if (!BSON_ITER_HOLDS_UTF8(&iter)) {
1083+
PHONGO_URI_INVALID_TYPE(iter, "string");
1084+
return false;
10211085
}
1086+
1087+
if (!mongoc_uri_set_auth_source(uri, bson_iter_utf8(&iter, NULL))) {
1088+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Failed to parse \"%s\" URI option", key);
1089+
return false;
1090+
}
1091+
1092+
continue;
10221093
}
10231094

1024-
if (BSON_ITER_HOLDS_DOCUMENT(&iter) && !strcasecmp(key, MONGOC_URI_AUTHMECHANISMPROPERTIES)) {
1095+
if (!strcasecmp(key, MONGOC_URI_AUTHMECHANISMPROPERTIES)) {
10251096
bson_t properties;
10261097
uint32_t len;
10271098
const uint8_t *data;
10281099

1100+
if (!BSON_ITER_HOLDS_DOCUMENT(&iter)) {
1101+
PHONGO_URI_INVALID_TYPE(iter, "array or object");
1102+
return false;
1103+
}
1104+
10291105
bson_iter_document(&iter, &len, &data);
10301106

10311107
if (!bson_init_static(&properties, data, len)) {
@@ -1062,16 +1138,21 @@ static bool php_phongo_apply_rc_options_to_uri(mongoc_uri_t *uri, bson_t *option
10621138
return true;
10631139
}
10641140

1065-
if (!bson_iter_init_find_case(&iter, options, "readconcernlevel")) {
1141+
if (!bson_iter_init_find_case(&iter, options, MONGOC_URI_READCONCERNLEVEL)) {
10661142
return true;
10671143
}
10681144

10691145
new_rc = mongoc_read_concern_copy(old_rc);
10701146

1071-
if (bson_iter_init_find_case(&iter, options, "readconcernlevel") && BSON_ITER_HOLDS_UTF8(&iter)) {
1072-
const char *str = bson_iter_utf8(&iter, NULL);
1147+
if (bson_iter_init_find_case(&iter, options, MONGOC_URI_READCONCERNLEVEL)) {
1148+
if (!BSON_ITER_HOLDS_UTF8(&iter)) {
1149+
PHONGO_URI_INVALID_TYPE(iter, "string");
1150+
mongoc_read_concern_destroy(new_rc);
10731151

1074-
mongoc_read_concern_set_level(new_rc, str);
1152+
return false;
1153+
}
1154+
1155+
mongoc_read_concern_set_level(new_rc, bson_iter_utf8(&iter, NULL));
10751156
}
10761157

10771158
mongoc_uri_set_read_concern(uri, new_rc);
@@ -1107,12 +1188,30 @@ static bool php_phongo_apply_rp_options_to_uri(mongoc_uri_t *uri, bson_t *option
11071188

11081189
new_rp = mongoc_read_prefs_copy(old_rp);
11091190

1110-
if (bson_iter_init_find_case(&iter, options, MONGOC_URI_SLAVEOK) && BSON_ITER_HOLDS_BOOL(&iter) && bson_iter_bool(&iter)) {
1111-
mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_SECONDARY_PREFERRED);
1191+
if (bson_iter_init_find_case(&iter, options, MONGOC_URI_SLAVEOK)) {
1192+
if (!BSON_ITER_HOLDS_BOOL(&iter)) {
1193+
PHONGO_URI_INVALID_TYPE(iter, "boolean");
1194+
mongoc_read_prefs_destroy(new_rp);
1195+
1196+
return false;
1197+
}
1198+
1199+
if (bson_iter_bool(&iter)) {
1200+
mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_SECONDARY_PREFERRED);
1201+
}
11121202
}
11131203

1114-
if (bson_iter_init_find_case(&iter, options, MONGOC_URI_READPREFERENCE) && BSON_ITER_HOLDS_UTF8(&iter)) {
1115-
const char *str = bson_iter_utf8(&iter, NULL);
1204+
if (bson_iter_init_find_case(&iter, options, MONGOC_URI_READPREFERENCE)) {
1205+
const char *str;
1206+
1207+
if (!BSON_ITER_HOLDS_UTF8(&iter)) {
1208+
PHONGO_URI_INVALID_TYPE(iter, "string");
1209+
mongoc_read_prefs_destroy(new_rp);
1210+
1211+
return false;
1212+
}
1213+
1214+
str = bson_iter_utf8(&iter, NULL);
11161215

11171216
if (0 == strcasecmp("primary", str)) {
11181217
mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_PRIMARY);
@@ -1125,18 +1224,25 @@ static bool php_phongo_apply_rp_options_to_uri(mongoc_uri_t *uri, bson_t *option
11251224
} else if (0 == strcasecmp("nearest", str)) {
11261225
mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_NEAREST);
11271226
} else {
1128-
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Unsupported readPreference value: '%s'", str);
1227+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Unsupported %s value: '%s'", bson_iter_key(&iter), str);
11291228
mongoc_read_prefs_destroy(new_rp);
11301229

11311230
return false;
11321231
}
11331232
}
11341233

1135-
if (bson_iter_init_find_case(&iter, options, MONGOC_URI_READPREFERENCETAGS) && BSON_ITER_HOLDS_ARRAY(&iter)) {
1234+
if (bson_iter_init_find_case(&iter, options, MONGOC_URI_READPREFERENCETAGS)) {
11361235
bson_t tags;
11371236
uint32_t len;
11381237
const uint8_t *data;
11391238

1239+
if (!BSON_ITER_HOLDS_ARRAY(&iter)) {
1240+
PHONGO_URI_INVALID_TYPE(iter, "array");
1241+
mongoc_read_prefs_destroy(new_rp);
1242+
1243+
return false;
1244+
}
1245+
11401246
bson_iter_array(&iter, &len, &data);
11411247

11421248
if (!bson_init_static(&tags, data, len)) {
@@ -1166,8 +1272,17 @@ static bool php_phongo_apply_rp_options_to_uri(mongoc_uri_t *uri, bson_t *option
11661272

11671273
/* Handle maxStalenessSeconds, and make sure it is not combined with primary
11681274
* readPreference */
1169-
if (bson_iter_init_find_case(&iter, options, MONGOC_URI_MAXSTALENESSSECONDS) && BSON_ITER_HOLDS_INT(&iter)) {
1170-
int64_t max_staleness_seconds = bson_iter_as_int64(&iter);
1275+
if (bson_iter_init_find_case(&iter, options, MONGOC_URI_MAXSTALENESSSECONDS)) {
1276+
int64_t max_staleness_seconds;
1277+
1278+
if (!BSON_ITER_HOLDS_INT(&iter)) {
1279+
PHONGO_URI_INVALID_TYPE(iter, "integer");
1280+
mongoc_read_prefs_destroy(new_rp);
1281+
1282+
return false;
1283+
}
1284+
1285+
max_staleness_seconds = bson_iter_as_int64(&iter);
11711286

11721287
if (max_staleness_seconds != MONGOC_NO_MAX_STALENESS) {
11731288

@@ -1240,15 +1355,36 @@ static bool php_phongo_apply_wc_options_to_uri(mongoc_uri_t *uri, bson_t *option
12401355

12411356
new_wc = mongoc_write_concern_copy(old_wc);
12421357

1243-
if (bson_iter_init_find_case(&iter, options, MONGOC_URI_SAFE) && BSON_ITER_HOLDS_BOOL(&iter)) {
1358+
if (bson_iter_init_find_case(&iter, options, MONGOC_URI_SAFE)) {
1359+
if (!BSON_ITER_HOLDS_BOOL(&iter)) {
1360+
PHONGO_URI_INVALID_TYPE(iter, "boolean");
1361+
mongoc_write_concern_destroy(new_wc);
1362+
1363+
return false;
1364+
}
1365+
12441366
mongoc_write_concern_set_w(new_wc, bson_iter_bool(&iter) ? 1 : MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED);
12451367
}
12461368

1247-
if (bson_iter_init_find_case(&iter, options, MONGOC_URI_WTIMEOUTMS) && BSON_ITER_HOLDS_INT32(&iter)) {
1369+
if (bson_iter_init_find_case(&iter, options, MONGOC_URI_WTIMEOUTMS)) {
1370+
if (!BSON_ITER_HOLDS_INT32(&iter)) {
1371+
PHONGO_URI_INVALID_TYPE(iter, "32-bit integer");
1372+
mongoc_write_concern_destroy(new_wc);
1373+
1374+
return false;
1375+
}
1376+
12481377
wtimeoutms = bson_iter_int32(&iter);
12491378
}
12501379

1251-
if (bson_iter_init_find_case(&iter, options, MONGOC_URI_JOURNAL) && BSON_ITER_HOLDS_BOOL(&iter)) {
1380+
if (bson_iter_init_find_case(&iter, options, MONGOC_URI_JOURNAL)) {
1381+
if (!BSON_ITER_HOLDS_BOOL(&iter)) {
1382+
PHONGO_URI_INVALID_TYPE(iter, "boolean");
1383+
mongoc_write_concern_destroy(new_wc);
1384+
1385+
return false;
1386+
}
1387+
12521388
mongoc_write_concern_set_journal(new_wc, bson_iter_bool(&iter));
12531389
}
12541390

@@ -1280,6 +1416,11 @@ static bool php_phongo_apply_wc_options_to_uri(mongoc_uri_t *uri, bson_t *option
12801416
} else {
12811417
mongoc_write_concern_set_wtag(new_wc, str);
12821418
}
1419+
} else {
1420+
PHONGO_URI_INVALID_TYPE(iter, "32-bit integer or string");
1421+
mongoc_write_concern_destroy(new_wc);
1422+
1423+
return false;
12831424
}
12841425
}
12851426

@@ -1770,7 +1911,6 @@ void phongo_manager_init(php_phongo_manager_t *manager, const char *uri_string,
17701911
size_t hash_len = 0;
17711912
bson_t bson_options = BSON_INITIALIZER;
17721913
mongoc_uri_t *uri = NULL;
1773-
bson_iter_t iter;
17741914
#ifdef MONGOC_ENABLE_SSL
17751915
mongoc_ssl_opt_t *ssl_opt = NULL;
17761916
#endif
@@ -1807,15 +1947,6 @@ void phongo_manager_init(php_phongo_manager_t *manager, const char *uri_string,
18071947
goto cleanup;
18081948
}
18091949

1810-
if (bson_iter_init_find_case(&iter, &bson_options, MONGOC_URI_APPNAME) && BSON_ITER_HOLDS_UTF8(&iter)) {
1811-
const char *str = bson_iter_utf8(&iter, NULL);
1812-
1813-
if (!mongoc_uri_set_appname(uri, str)) {
1814-
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Invalid appname value: '%s'", str);
1815-
goto cleanup;
1816-
}
1817-
}
1818-
18191950
#ifdef MONGOC_ENABLE_SSL
18201951
/* Construct SSL options even if SSL is not enabled so that exceptions can
18211952
* be thrown for unsupported driver options. */

0 commit comments

Comments
 (0)