Esempio n. 1
0
bool
mongoc_uri_set_option_as_bool (mongoc_uri_t *uri,
                               const char   *option,
                               bool          value)
{
   const bson_t *options;
   bson_iter_t iter;

   BSON_ASSERT (option);

   if (!mongoc_uri_option_is_bool (option)) {
      return false;
   }

   if ((options = mongoc_uri_get_options (uri)) &&
         bson_iter_init_find_case (&iter, options, option)) {
      if (BSON_ITER_HOLDS_BOOL (&iter)) {
         bson_iter_overwrite_bool (&iter, value);
         return true;
      } else {
         return false;
      }
   }
   bson_append_bool(&uri->options, option, -1, value);
   return true;

}
Esempio n. 2
0
void
_mongoc_sasl_set_properties (mongoc_sasl_t *sasl, const mongoc_uri_t *uri)
{
   const bson_t *options;
   bson_iter_t iter;
   bson_t properties;
   const char *service_name = NULL;
   bool canonicalize = false;

   _mongoc_sasl_set_pass(sasl, mongoc_uri_get_password(uri));
   _mongoc_sasl_set_user(sasl, mongoc_uri_get_username(uri));

   options = mongoc_uri_get_options (uri);

   if (!mongoc_uri_get_mechanism_properties (uri, &properties)) {
      bson_init (&properties);
   }

   if (bson_iter_init_find_case (
          &iter, options, MONGOC_URI_GSSAPISERVICENAME) &&
       BSON_ITER_HOLDS_UTF8 (&iter)) {
      service_name = bson_iter_utf8 (&iter, NULL);
   }

   if (bson_iter_init_find_case (&iter, &properties, "SERVICE_NAME") &&
       BSON_ITER_HOLDS_UTF8 (&iter)) {
      /* newer "authMechanismProperties" URI syntax takes precedence */
      service_name = bson_iter_utf8 (&iter, NULL);
   }

   _mongoc_sasl_set_service_name (sasl, service_name);

   /*
    * Driver Authentication Spec: "Drivers MAY allow the user to request
    * canonicalization of the hostname. This might be required when the hosts
    * report different hostnames than what is used in the kerberos database.
    * The default is "false".
    *
    * Some underlying GSSAPI layers will do this for us, but can be disabled in
    * their config (krb.conf).
    *
    * See CDRIVER-323 for more information.
    */
   if (bson_iter_init_find_case (
          &iter, options, MONGOC_URI_CANONICALIZEHOSTNAME) &&
       BSON_ITER_HOLDS_BOOL (&iter)) {
      canonicalize = bson_iter_bool (&iter);
   }

   if (bson_iter_init_find_case (
          &iter, &properties, "CANONICALIZE_HOST_NAME") &&
       BSON_ITER_HOLDS_UTF8 (&iter)) {
      /* newer "authMechanismProperties" URI syntax takes precedence */
      canonicalize = !strcasecmp (bson_iter_utf8 (&iter, NULL), "true");
   }

   sasl->canonicalize_host_name = canonicalize;

   bson_destroy (&properties);
}
mongoc_client_pool_t *
mongoc_client_pool_new (const mongoc_uri_t *uri)
{
   mongoc_topology_t *topology;
   mongoc_client_pool_t *pool;
   const bson_t *b;
   bson_iter_t iter;

   ENTRY;

   BSON_ASSERT (uri);

#ifndef MONGOC_ENABLE_SSL
   if (mongoc_uri_get_ssl (uri)) {
      MONGOC_ERROR ("Can't create SSL client pool,"
                    " SSL not enabled in this build.");
      return NULL;
   }
#endif

   pool = (mongoc_client_pool_t *)bson_malloc0(sizeof *pool);
   mongoc_mutex_init(&pool->mutex);
   _mongoc_queue_init(&pool->queue);
   pool->uri = mongoc_uri_copy(uri);
   pool->min_pool_size = 0;
   pool->max_pool_size = 100;
   pool->size = 0;
   pool->topology_scanner_started = false;

   topology = mongoc_topology_new(uri, false);
   pool->topology = topology;

   mongoc_client_metadata_init (&pool->topology->scanner->ismaster_metadata);

   pool->error_api_version = MONGOC_ERROR_API_VERSION_LEGACY;

   b = mongoc_uri_get_options(pool->uri);

   if (bson_iter_init_find_case(&iter, b, "minpoolsize")) {
      if (BSON_ITER_HOLDS_INT32(&iter)) {
         pool->min_pool_size = BSON_MAX(0, bson_iter_int32(&iter));
      }
   }

   if (bson_iter_init_find_case(&iter, b, "maxpoolsize")) {
      if (BSON_ITER_HOLDS_INT32(&iter)) {
         pool->max_pool_size = BSON_MAX(1, bson_iter_int32(&iter));
      }
   }

   mongoc_counter_client_pools_active_inc();

   RETURN(pool);
}
mongoc_client_t *
mongoc_client_new (const char *uri_string)
{
   const mongoc_write_concern_t *write_concern;
   mongoc_client_t *client;
   mongoc_uri_t *uri;
   const bson_t *options;
   bson_iter_t iter;
   bool has_ssl = false;

   if (!uri_string) {
      uri_string = "mongodb://127.0.0.1/";
   }

   if (!(uri = mongoc_uri_new(uri_string))) {
      return NULL;
   }

   options = mongoc_uri_get_options (uri);

   if (bson_iter_init_find (&iter, options, "ssl") &&
       BSON_ITER_HOLDS_BOOL (&iter) &&
       bson_iter_bool (&iter)) {
      has_ssl = true;
   }

   client = bson_malloc0(sizeof *client);
   client->uri = uri;
   client->request_id = rand ();
   client->initiator = mongoc_client_default_stream_initiator;
   client->initiator_data = client;

   write_concern = mongoc_uri_get_write_concern (uri);
   client->write_concern = mongoc_write_concern_copy (write_concern);

   client->read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY);

   _mongoc_cluster_init (&client->cluster, client->uri, client);

#ifdef MONGOC_ENABLE_SSL
   if (has_ssl) {
      mongoc_client_set_ssl_opts (client, mongoc_ssl_opt_get_default ());
   }
#endif

   mongoc_counter_clients_active_inc ();

   return client;
}
Esempio n. 5
0
const char*
mongoc_uri_get_option_as_utf8 (const mongoc_uri_t *uri, const char *option,
                               const char *fallback)
{
   const bson_t *options;
   bson_iter_t iter;

   if ((options = mongoc_uri_get_options (uri)) &&
       bson_iter_init_find_case (&iter, options, option) &&
       BSON_ITER_HOLDS_UTF8 (&iter)) {
      return bson_iter_utf8 (&iter, NULL);
   }

   return fallback;
}
Esempio n. 6
0
bool
mongoc_uri_get_option_as_bool (const mongoc_uri_t *uri, const char *option,
                               bool fallback)
{
   const bson_t *options;
   bson_iter_t iter;

   if ((options = mongoc_uri_get_options (uri)) &&
       bson_iter_init_find_case (&iter, options, option) &&
       BSON_ITER_HOLDS_BOOL (&iter)) {
      return bson_iter_bool (&iter);
   }

   return fallback;
}
Esempio n. 7
0
int32_t
mongoc_uri_get_option_as_int32(const mongoc_uri_t *uri, const char *option,
                               int32_t fallback)
{
   const bson_t *options;
   bson_iter_t iter;
   int32_t retval = fallback;

   if ((options = mongoc_uri_get_options (uri)) &&
        bson_iter_init_find_case (&iter, options, option) &&
        BSON_ITER_HOLDS_INT32 (&iter)) {

      if (!(retval = bson_iter_int32(&iter))) {
         retval = fallback;
      }
   }

   return retval;
}
Esempio n. 8
0
mongoc_client_t *
_mongoc_client_new_from_uri (const mongoc_uri_t *uri, mongoc_topology_t *topology)
{
   mongoc_client_t *client;
   const mongoc_read_prefs_t *read_prefs;
   const mongoc_write_concern_t *write_concern;
#ifdef MONGOC_ENABLE_SSL
   const bson_t *options;
   bson_iter_t iter;
#endif

   BSON_ASSERT (uri);

   client = (mongoc_client_t *)bson_malloc0(sizeof *client);
   client->uri = mongoc_uri_copy (uri);
   client->request_id = rand ();
   client->initiator = mongoc_client_default_stream_initiator;
   client->initiator_data = client;
   client->topology = topology;

   write_concern = mongoc_uri_get_write_concern (client->uri);
   client->write_concern = mongoc_write_concern_copy (write_concern);

   read_prefs = mongoc_uri_get_read_prefs_t (client->uri);
   client->read_prefs = mongoc_read_prefs_copy (read_prefs);

   mongoc_cluster_init (&client->cluster, client->uri, client);

#ifdef MONGOC_ENABLE_SSL
   options = mongoc_uri_get_options (client->uri);

   if (bson_iter_init_find (&iter, options, "ssl") &&
       BSON_ITER_HOLDS_BOOL (&iter) &&
       bson_iter_bool (&iter)) {
         mongoc_client_set_ssl_opts (client, mongoc_ssl_opt_get_default ());
   }
#endif

   mongoc_counter_clients_active_inc ();

   return client;
}
mongoc_client_pool_t *
mongoc_client_pool_new (const mongoc_uri_t *uri)
{
   mongoc_topology_t *topology;
   mongoc_client_pool_t *pool;
   const bson_t *b;
   bson_iter_t iter;

   ENTRY;

   BSON_ASSERT (uri);

   pool = (mongoc_client_pool_t *)bson_malloc0(sizeof *pool);
   mongoc_mutex_init(&pool->mutex);
   _mongoc_queue_init(&pool->queue);
   pool->uri = mongoc_uri_copy(uri);
   pool->min_pool_size = 0;
   pool->max_pool_size = 100;
   pool->size = 0;

   topology = mongoc_topology_new(uri, false);
   pool->topology = topology;

   b = mongoc_uri_get_options(pool->uri);

   if (bson_iter_init_find_case(&iter, b, "minpoolsize")) {
      if (BSON_ITER_HOLDS_INT32(&iter)) {
         pool->min_pool_size = BSON_MAX(0, bson_iter_int32(&iter));
      }
   }

   if (bson_iter_init_find_case(&iter, b, "maxpoolsize")) {
      if (BSON_ITER_HOLDS_INT32(&iter)) {
         pool->max_pool_size = BSON_MAX(1, bson_iter_int32(&iter));
      }
   }

   mongoc_counter_client_pools_active_inc();

   RETURN(pool);
}
Esempio n. 10
0
static mongoc_stream_t *
mongoc_client_connect_tcp (const mongoc_uri_t       *uri,
                           const mongoc_host_list_t *host,
                           bson_error_t             *error)
{
   mongoc_socket_t *sock = NULL;
   struct addrinfo hints;
   struct addrinfo *result, *rp;
   int32_t connecttimeoutms = MONGOC_DEFAULT_CONNECTTIMEOUTMS;
   int64_t expire_at;
   const bson_t *options;
   bson_iter_t iter;
   char portstr [8];
   int s;

   ENTRY;

   bson_return_val_if_fail (uri, NULL);
   bson_return_val_if_fail (host, NULL);

   if ((options = mongoc_uri_get_options (uri)) &&
       bson_iter_init_find (&iter, options, "connecttimeoutms") &&
       BSON_ITER_HOLDS_INT32 (&iter)) {
      if (!(connecttimeoutms = bson_iter_int32(&iter))) {
         connecttimeoutms = MONGOC_DEFAULT_CONNECTTIMEOUTMS;
      }
   }

   BSON_ASSERT (connecttimeoutms);
   expire_at = bson_get_monotonic_time () + (connecttimeoutms * 1000L);

   bson_snprintf (portstr, sizeof portstr, "%hu", host->port);

   memset (&hints, 0, sizeof hints);
   hints.ai_family = host->family;
   hints.ai_socktype = SOCK_STREAM;
   hints.ai_flags = 0;
   hints.ai_protocol = 0;

   s = getaddrinfo (host->host, portstr, &hints, &result);

   if (s != 0) {
      mongoc_counter_dns_failure_inc ();
      bson_set_error(error,
                     MONGOC_ERROR_STREAM,
                     MONGOC_ERROR_STREAM_NAME_RESOLUTION,
                     "Failed to resolve %s",
                     host->host);
      RETURN (NULL);
   }

   mongoc_counter_dns_success_inc ();

   for (rp = result; rp; rp = rp->ai_next) {
      /*
       * Create a new non-blocking socket.
       */
      if (!(sock = mongoc_socket_new (rp->ai_family,
                                      rp->ai_socktype,
                                      rp->ai_protocol))) {
         continue;
      }

      /*
       * Try to connect to the peer.
       */
      if (0 != mongoc_socket_connect (sock,
                                      rp->ai_addr,
                                      (socklen_t)rp->ai_addrlen,
                                      expire_at)) {
         char errmsg_buf[32];
         const char * errmsg;

         errmsg = bson_strerror_r (mongoc_socket_errno (sock), errmsg_buf, sizeof errmsg_buf);
         MONGOC_WARNING ("Failed to connect, error: %d, %s\n",
                         mongoc_socket_errno(sock),
                         errmsg);
         mongoc_socket_destroy (sock);
         sock = NULL;
         continue;
      }

      break;
   }

   if (!sock) {
      bson_set_error (error,
                      MONGOC_ERROR_STREAM,
                      MONGOC_ERROR_STREAM_CONNECT,
                      "Failed to connect to target host: %s",
                      host->host_and_port);
      freeaddrinfo (result);
      RETURN (NULL);
   }

   freeaddrinfo (result);

   return mongoc_stream_socket_new (sock);
}
Esempio n. 11
0
static mongoc_stream_t *
mongoc_client_default_stream_initiator (const mongoc_uri_t       *uri,
                                        const mongoc_host_list_t *host,
                                        void                     *user_data,
                                        bson_error_t             *error)
{
   mongoc_stream_t *base_stream = NULL;
#ifdef MONGOC_ENABLE_SSL
   mongoc_client_t *client = user_data;
   const bson_t *options;
   bson_iter_t iter;
   const char *mechanism;
#endif

   bson_return_val_if_fail (uri, NULL);
   bson_return_val_if_fail (host, NULL);

#ifndef MONGOC_ENABLE_SSL
   if (mongoc_uri_get_ssl (uri)) {
      bson_set_error (error,
                      MONGOC_ERROR_CLIENT,
                      MONGOC_ERROR_CLIENT_NO_ACCEPTABLE_PEER,
                      "SSL is not enabled in this build of mongo-c-driver.");
      return NULL;
   }
#endif


   switch (host->family) {
#if defined(AF_INET6)
   case AF_INET6:
#endif
   case AF_INET:
      base_stream = mongoc_client_connect_tcp (uri, host, error);
      break;
   case AF_UNIX:
      base_stream = mongoc_client_connect_unix (uri, host, error);
      break;
   default:
      bson_set_error (error,
                      MONGOC_ERROR_STREAM,
                      MONGOC_ERROR_STREAM_INVALID_TYPE,
                      "Invalid address family: 0x%02x", host->family);
      break;
   }

#ifdef MONGOC_ENABLE_SSL
   if (base_stream) {
      options = mongoc_uri_get_options (uri);
      mechanism = mongoc_uri_get_auth_mechanism (uri);

      if ((bson_iter_init_find_case (&iter, options, "ssl") &&
           bson_iter_as_bool (&iter)) ||
          (mechanism && (0 == strcmp (mechanism, "MONGODB-X509")))) {
         base_stream = mongoc_stream_tls_new (base_stream, &client->ssl_opts,
                                              true);

         if (!base_stream) {
            bson_set_error (error,
                            MONGOC_ERROR_STREAM,
                            MONGOC_ERROR_STREAM_SOCKET,
                            "Failed initialize TLS state.");
            return NULL;
         }

         if (!mongoc_stream_tls_do_handshake (base_stream, -1) ||
             !mongoc_stream_tls_check_cert (base_stream, host->host)) {
            bson_set_error (error,
                            MONGOC_ERROR_STREAM,
                            MONGOC_ERROR_STREAM_SOCKET,
                            "Failed to handshake and validate TLS certificate.");
            mongoc_stream_destroy (base_stream);
            base_stream = NULL;
            return NULL;
         }
      }
   }
#endif

   return base_stream ? mongoc_stream_buffered_new (base_stream, 1024) : NULL;
}
Esempio n. 12
0
static void
test_mongoc_uri_new (void)
{
   const mongoc_host_list_t *hosts;
   const bson_t *options;
   const bson_t *credentials;
   bson_t properties;
   mongoc_uri_t *uri;
   bson_iter_t iter;
   bson_iter_t child;

   /* bad uris */
   ASSERT(!mongoc_uri_new("mongodb://"));
   ASSERT(!mongoc_uri_new("mongodb://::"));
   ASSERT(!mongoc_uri_new("mongodb://*****:*****@localhost:27017/foo/?authSource=abcd");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_username(uri), "christian");
   ASSERT_CMPSTR(mongoc_uri_get_password(uri), "secret");
   ASSERT_CMPSTR(mongoc_uri_get_auth_source(uri), "abcd");
   mongoc_uri_destroy(uri);

   /* should use the default auth source and mechanism */
   uri = mongoc_uri_new("mongodb://*****:*****@localhost:27017");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_auth_source(uri), "admin");
   ASSERT(!mongoc_uri_get_auth_mechanism(uri));
   mongoc_uri_destroy(uri);

   /* should use the db when no authSource is specified */
   uri = mongoc_uri_new("mongodb://*****:*****@localhost/foo");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_auth_source(uri), "foo");
   mongoc_uri_destroy(uri);

   /* should recognize an empty password */
   uri = mongoc_uri_new("mongodb://samantha:@localhost");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_username(uri), "samantha");
   ASSERT_CMPSTR(mongoc_uri_get_password(uri), "");
   mongoc_uri_destroy(uri);

   /* should recognize no password */
   uri = mongoc_uri_new("mongodb://christian@localhost:27017");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_username(uri), "christian");
   ASSERT(!mongoc_uri_get_password(uri));
   mongoc_uri_destroy(uri);

   /* should recognize a url escaped character in the username */
   uri = mongoc_uri_new("mongodb://christian%40realm:pwd@localhost:27017");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_username(uri), "christian@realm");
   mongoc_uri_destroy(uri);

   /* while you shouldn't do this, lets test for it */
   uri = mongoc_uri_new("mongodb://christian%40realm@localhost:27017/db%2ename");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_database(uri), "db.name");
   mongoc_uri_destroy(uri);
   uri = mongoc_uri_new("mongodb://christian%40realm@localhost:27017/db%2Ename");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_database(uri), "db.name");
   mongoc_uri_destroy(uri);

   uri = mongoc_uri_new("mongodb://christian%40realm@localhost:27017/?abcd=%20");
   ASSERT(uri);
   options = mongoc_uri_get_options(uri);
   ASSERT(options);
   ASSERT(bson_iter_init_find(&iter, options, "abcd"));
   ASSERT(BSON_ITER_HOLDS_UTF8(&iter));
   ASSERT_CMPSTR(bson_iter_utf8(&iter, NULL), " ");
   mongoc_uri_destroy(uri);

   uri = mongoc_uri_new("mongodb://christian%40realm@[::6]:27017/?abcd=%20");
   ASSERT(uri);
   options = mongoc_uri_get_options(uri);
   ASSERT(options);
   ASSERT(bson_iter_init_find(&iter, options, "abcd"));
   ASSERT(BSON_ITER_HOLDS_UTF8(&iter));
   ASSERT_CMPSTR(bson_iter_utf8(&iter, NULL), " ");
   mongoc_uri_destroy(uri);

   /* GSSAPI-specific options */

   /* should recognize the GSSAPI mechanism, and use $external as source */
   uri = mongoc_uri_new("mongodb://user%40DOMAIN.COM:password@localhost/?authMechanism=GSSAPI");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_auth_mechanism(uri), "GSSAPI");
   /*ASSERT_CMPSTR(mongoc_uri_get_auth_source(uri), "$external");*/
   mongoc_uri_destroy(uri);

   /* use $external as source when db is specified */
   uri = mongoc_uri_new("mongodb://user%40DOMAIN.COM:password@localhost/foo/?authMechanism=GSSAPI");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_auth_source(uri), "$external");
   mongoc_uri_destroy(uri);

   /* should not accept authSource other than $external */
   ASSERT(!mongoc_uri_new("mongodb://user%40DOMAIN.COM:password@localhost/foo/?authMechanism=GSSAPI&authSource=bar"));

   /* should accept authMechanismProperties */
   uri = mongoc_uri_new("mongodb://user%40DOMAIN.COM:password@localhost/?authMechanism=GSSAPI"
                        "&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:true");
   ASSERT(uri);
   credentials = mongoc_uri_get_credentials(uri);
   ASSERT(credentials);
   ASSERT(mongoc_uri_get_mechanism_properties(uri, &properties));
   assert (bson_iter_init_find_case (&iter, &properties, "SERVICE_NAME") &&
           BSON_ITER_HOLDS_UTF8 (&iter) &&
           (0 == strcmp (bson_iter_utf8 (&iter, NULL), "other")));
   assert (bson_iter_init_find_case (&iter, &properties, "CANONICALIZE_HOST_NAME") &&
           BSON_ITER_HOLDS_UTF8 (&iter) &&
           (0 == strcmp (bson_iter_utf8 (&iter, NULL), "true")));
   mongoc_uri_destroy(uri);

   /* reverse order of arguments to ensure parsing still succeeds */
   uri = mongoc_uri_new("mongodb://user@localhost/"
                        "?authMechanismProperties=SERVICE_NAME:other"
                        "&authMechanism=GSSAPI");
   ASSERT(uri);
   mongoc_uri_destroy(uri);

   /* deprecated gssapiServiceName option */
   uri = mongoc_uri_new("mongodb://christian%40realm.cc@localhost:27017/?authMechanism=GSSAPI&gssapiServiceName=blah");
   ASSERT(uri);
   options = mongoc_uri_get_options(uri);
   ASSERT(options);
   assert (0 == strcmp (mongoc_uri_get_auth_mechanism (uri), "GSSAPI"));
   assert (0 == strcmp (mongoc_uri_get_username (uri), "*****@*****.**"));
   assert (bson_iter_init_find_case (&iter, options, "gssapiServiceName") &&
           BSON_ITER_HOLDS_UTF8 (&iter) &&
           (0 == strcmp (bson_iter_utf8 (&iter, NULL), "blah")));
   mongoc_uri_destroy(uri);

   /* MONGODB-CR */

   /* should recognize this mechanism */
   uri = mongoc_uri_new("mongodb://user@localhost/?authMechanism=MONGODB-CR");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_auth_mechanism(uri), "MONGODB-CR");
   mongoc_uri_destroy(uri);

   /* X509 */

   /* should recognize this mechanism, and use $external as the source */
   uri = mongoc_uri_new("mongodb://user@localhost/?authMechanism=MONGODB-X509");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_auth_mechanism(uri), "MONGODB-X509");
   /*ASSERT_CMPSTR(mongoc_uri_get_auth_source(uri), "$external");*/
   mongoc_uri_destroy(uri);

   /* use $external as source when db is specified */
   uri = mongoc_uri_new("mongodb://CN%3DmyName%2COU%3DmyOrgUnit%2CO%3DmyOrg%2CL%3DmyLocality"
                        "%2CST%3DmyState%2CC%3DmyCountry@localhost/foo/?authMechanism=MONGODB-X509");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_auth_source(uri), "$external");
   mongoc_uri_destroy(uri);

   /* should not accept authSource other than $external */
   ASSERT(!mongoc_uri_new("mongodb://CN%3DmyName%2COU%3DmyOrgUnit%2CO%3DmyOrg%2CL%3DmyLocality"
                          "%2CST%3DmyState%2CC%3DmyCountry@localhost/foo/?authMechanism=MONGODB-X509&authSource=bar"));

   /* should recognize the encoded username */
   uri = mongoc_uri_new("mongodb://CN%3DmyName%2COU%3DmyOrgUnit%2CO%3DmyOrg%2CL%3DmyLocality"
                        "%2CST%3DmyState%2CC%3DmyCountry@localhost/?authMechanism=MONGODB-X509");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_username(uri), "CN=myName,OU=myOrgUnit,O=myOrg,L=myLocality,ST=myState,C=myCountry");
   mongoc_uri_destroy(uri);

   /* PLAIN */

   /* should recognize this mechanism */
   uri = mongoc_uri_new("mongodb://user@localhost/?authMechanism=PLAIN");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_auth_mechanism(uri), "PLAIN");
   mongoc_uri_destroy(uri);

   /* SCRAM-SHA1 */

   /* should recognize this mechanism */
   uri = mongoc_uri_new("mongodb://user@localhost/?authMechanism=SCRAM-SHA1");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_auth_mechanism(uri), "SCRAM-SHA1");
   mongoc_uri_destroy(uri);
}
static void
test_mongoc_uri_new (void)
{
   const mongoc_host_list_t *hosts;
   const bson_t *options;
   mongoc_uri_t *uri;
   bson_iter_t iter;
   bson_iter_t child;

   ASSERT(!mongoc_uri_new("mongodb://"));
   ASSERT(!mongoc_uri_new("mongodb://::"));
   ASSERT(!mongoc_uri_new("mongodb://*****:*****@localhost:27017?authSource=abcd");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_username(uri), "christian");
   ASSERT_CMPSTR(mongoc_uri_get_password(uri), "secret");
   ASSERT_CMPSTR(mongoc_uri_get_auth_source(uri), "abcd");
   mongoc_uri_destroy(uri);

   uri = mongoc_uri_new("mongodb://*****:*****@localhost:27017");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_auth_source(uri), "admin");
   mongoc_uri_destroy(uri);

   uri = mongoc_uri_new("mongodb://christian@localhost:27017");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_username(uri), "christian");
   mongoc_uri_destroy(uri);

   uri = mongoc_uri_new("mongodb://christian%40realm@localhost:27017");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_username(uri), "christian@realm");
   mongoc_uri_destroy(uri);

   /* while you shouldn't do this, lets test for it */
   uri = mongoc_uri_new("mongodb://christian%40realm@localhost:27017/db%2ename");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_database(uri), "db.name");
   mongoc_uri_destroy(uri);
   uri = mongoc_uri_new("mongodb://christian%40realm@localhost:27017/db%2Ename");
   ASSERT(uri);
   ASSERT_CMPSTR(mongoc_uri_get_database(uri), "db.name");
   mongoc_uri_destroy(uri);

   uri = mongoc_uri_new("mongodb://christian%40realm@localhost:27017/?abcd=%20");
   ASSERT(uri);
   options = mongoc_uri_get_options(uri);
   ASSERT(options);
   ASSERT(bson_iter_init_find(&iter, options, "abcd"));
   ASSERT(BSON_ITER_HOLDS_UTF8(&iter));
   ASSERT_CMPSTR(bson_iter_utf8(&iter, NULL), " ");
   mongoc_uri_destroy(uri);

   uri = mongoc_uri_new("mongodb://christian%40realm.cc@localhost:27017/?authmechanism=GSSAPI&gssapiservicename=blah");
   ASSERT(uri);
   options = mongoc_uri_get_options(uri);
   ASSERT(options);
   assert (0 == strcmp (mongoc_uri_get_auth_mechanism (uri), "GSSAPI"));
   assert (0 == strcmp (mongoc_uri_get_username (uri), "*****@*****.**"));
   assert (bson_iter_init_find_case (&iter, options, "gssapiservicename") &&
           BSON_ITER_HOLDS_UTF8 (&iter) &&
           (0 == strcmp (bson_iter_utf8 (&iter, NULL), "blah")));
   mongoc_uri_destroy(uri);

   uri = mongoc_uri_new("mongodb://christian%40realm@[::6]:27017/?abcd=%20");
   ASSERT(uri);
   options = mongoc_uri_get_options(uri);
   ASSERT(options);
   ASSERT(bson_iter_init_find(&iter, options, "abcd"));
   ASSERT(BSON_ITER_HOLDS_UTF8(&iter));
   ASSERT_CMPSTR(bson_iter_utf8(&iter, NULL), " ");
   mongoc_uri_destroy(uri);
}