@@ -927,6 +927,42 @@ static mongoc_uri_t *php_phongo_make_uri(const char *uri_string, bson_t *options
927
927
return uri ;
928
928
} /* }}} */
929
929
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
+
930
966
static bool php_phongo_apply_options_to_uri (mongoc_uri_t * uri , bson_t * options TSRMLS_DC ) /* {{{ */
931
967
{
932
968
bson_iter_t iter ;
@@ -949,12 +985,14 @@ static bool php_phongo_apply_options_to_uri(mongoc_uri_t *uri, bson_t *options T
949
985
!strcasecmp (key , MONGOC_URI_SAFE ) ||
950
986
!strcasecmp (key , MONGOC_URI_SLAVEOK ) ||
951
987
!strcasecmp (key , MONGOC_URI_W ) ||
952
- !strcasecmp (key , MONGOC_URI_WTIMEOUTMS ) ||
953
- !strcasecmp (key , MONGOC_URI_APPNAME )) {
988
+ !strcasecmp (key , MONGOC_URI_WTIMEOUTMS )) {
954
989
continue ;
955
990
}
956
991
957
992
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. */
958
996
if (!mongoc_uri_set_option_as_bool (uri , key , bson_iter_as_bool (& iter ))) {
959
997
phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Failed to parse \"%s\" URI option" , key );
960
998
return false;
@@ -963,7 +1001,12 @@ static bool php_phongo_apply_options_to_uri(mongoc_uri_t *uri, bson_t *options T
963
1001
continue ;
964
1002
}
965
1003
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
+
967
1010
if (!mongoc_uri_set_option_as_int32 (uri , key , bson_iter_int32 (& iter ))) {
968
1011
phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Failed to parse \"%s\" URI option" , key );
969
1012
return false;
@@ -972,60 +1015,93 @@ static bool php_phongo_apply_options_to_uri(mongoc_uri_t *uri, bson_t *options T
972
1015
continue ;
973
1016
}
974
1017
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
+
976
1024
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
+ }
978
1033
return false;
979
1034
}
980
1035
981
1036
continue ;
982
1037
}
983
1038
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
+ }
992
1044
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;
994
1048
}
995
1049
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
+ }
1001
1052
1002
- continue ;
1053
+ if (!strcasecmp (key , "password" )) {
1054
+ if (!BSON_ITER_HOLDS_UTF8 (& iter )) {
1055
+ PHONGO_URI_INVALID_TYPE (iter , "string" );
1056
+ return false;
1003
1057
}
1004
1058
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
+ }
1010
1063
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;
1012
1071
}
1013
1072
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
+ }
1019
1077
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;
1021
1085
}
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 ;
1022
1093
}
1023
1094
1024
- if (BSON_ITER_HOLDS_DOCUMENT ( & iter ) && !strcasecmp (key , MONGOC_URI_AUTHMECHANISMPROPERTIES )) {
1095
+ if (!strcasecmp (key , MONGOC_URI_AUTHMECHANISMPROPERTIES )) {
1025
1096
bson_t properties ;
1026
1097
uint32_t len ;
1027
1098
const uint8_t * data ;
1028
1099
1100
+ if (!BSON_ITER_HOLDS_DOCUMENT (& iter )) {
1101
+ PHONGO_URI_INVALID_TYPE (iter , "array or object" );
1102
+ return false;
1103
+ }
1104
+
1029
1105
bson_iter_document (& iter , & len , & data );
1030
1106
1031
1107
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
1062
1138
return true;
1063
1139
}
1064
1140
1065
- if (!bson_iter_init_find_case (& iter , options , "readconcernlevel" )) {
1141
+ if (!bson_iter_init_find_case (& iter , options , MONGOC_URI_READCONCERNLEVEL )) {
1066
1142
return true;
1067
1143
}
1068
1144
1069
1145
new_rc = mongoc_read_concern_copy (old_rc );
1070
1146
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 );
1073
1151
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 ));
1075
1156
}
1076
1157
1077
1158
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
1107
1188
1108
1189
new_rp = mongoc_read_prefs_copy (old_rp );
1109
1190
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
+ }
1112
1202
}
1113
1203
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 );
1116
1215
1117
1216
if (0 == strcasecmp ("primary" , str )) {
1118
1217
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
1125
1224
} else if (0 == strcasecmp ("nearest" , str )) {
1126
1225
mongoc_read_prefs_set_mode (new_rp , MONGOC_READ_NEAREST );
1127
1226
} 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 );
1129
1228
mongoc_read_prefs_destroy (new_rp );
1130
1229
1131
1230
return false;
1132
1231
}
1133
1232
}
1134
1233
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 )) {
1136
1235
bson_t tags ;
1137
1236
uint32_t len ;
1138
1237
const uint8_t * data ;
1139
1238
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
+
1140
1246
bson_iter_array (& iter , & len , & data );
1141
1247
1142
1248
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
1166
1272
1167
1273
/* Handle maxStalenessSeconds, and make sure it is not combined with primary
1168
1274
* 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 );
1171
1286
1172
1287
if (max_staleness_seconds != MONGOC_NO_MAX_STALENESS ) {
1173
1288
@@ -1240,15 +1355,36 @@ static bool php_phongo_apply_wc_options_to_uri(mongoc_uri_t *uri, bson_t *option
1240
1355
1241
1356
new_wc = mongoc_write_concern_copy (old_wc );
1242
1357
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
+
1244
1366
mongoc_write_concern_set_w (new_wc , bson_iter_bool (& iter ) ? 1 : MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED );
1245
1367
}
1246
1368
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
+
1248
1377
wtimeoutms = bson_iter_int32 (& iter );
1249
1378
}
1250
1379
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
+
1252
1388
mongoc_write_concern_set_journal (new_wc , bson_iter_bool (& iter ));
1253
1389
}
1254
1390
@@ -1280,6 +1416,11 @@ static bool php_phongo_apply_wc_options_to_uri(mongoc_uri_t *uri, bson_t *option
1280
1416
} else {
1281
1417
mongoc_write_concern_set_wtag (new_wc , str );
1282
1418
}
1419
+ } else {
1420
+ PHONGO_URI_INVALID_TYPE (iter , "32-bit integer or string" );
1421
+ mongoc_write_concern_destroy (new_wc );
1422
+
1423
+ return false;
1283
1424
}
1284
1425
}
1285
1426
@@ -1770,7 +1911,6 @@ void phongo_manager_init(php_phongo_manager_t *manager, const char *uri_string,
1770
1911
size_t hash_len = 0 ;
1771
1912
bson_t bson_options = BSON_INITIALIZER ;
1772
1913
mongoc_uri_t * uri = NULL ;
1773
- bson_iter_t iter ;
1774
1914
#ifdef MONGOC_ENABLE_SSL
1775
1915
mongoc_ssl_opt_t * ssl_opt = NULL ;
1776
1916
#endif
@@ -1807,15 +1947,6 @@ void phongo_manager_init(php_phongo_manager_t *manager, const char *uri_string,
1807
1947
goto cleanup ;
1808
1948
}
1809
1949
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
-
1819
1950
#ifdef MONGOC_ENABLE_SSL
1820
1951
/* Construct SSL options even if SSL is not enabled so that exceptions can
1821
1952
* be thrown for unsupported driver options. */
0 commit comments