Esempio n. 1
0
char *
mongoc_uri_unescape (const char *escaped_string)
{
   bson_unichar_t c;
   bson_string_t *str;
   unsigned int hex = 0;
   const char *ptr;
   const char *end;
   size_t len;

   BSON_ASSERT (escaped_string);

   len = strlen(escaped_string);

   /*
    * Double check that this is a UTF-8 valid string. Bail out if necessary.
    */
   if (!bson_utf8_validate(escaped_string, len, false)) {
      MONGOC_WARNING("%s(): escaped_string contains invalid UTF-8",
                     BSON_FUNC);
      return NULL;
   }

   ptr = escaped_string;
   end = ptr + len;
   str = bson_string_new(NULL);

   for (; *ptr; ptr = bson_utf8_next_char(ptr)) {
      c = bson_utf8_get_char(ptr);
      switch (c) {
      case '%':
         if (((end - ptr) < 2) ||
             !isxdigit(ptr[1]) ||
             !isxdigit(ptr[2]) ||
#ifdef _MSC_VER
             (1 != sscanf_s(&ptr[1], "%02x", &hex)) ||
#else
             (1 != sscanf(&ptr[1], "%02x", &hex)) ||
#endif
             !isprint(hex)) {
            bson_string_free(str, true);
            return NULL;
         }
         bson_string_append_c(str, hex);
         ptr += 2;
         break;
      default:
         bson_string_append_unichar(str, c);
         break;
      }
   }

   return bson_string_free(str, false);
}
/* Uses old way of querying system.namespaces. */
mongoc_cursor_t *
_mongoc_database_find_collections_legacy (mongoc_database_t *database,
                                          const bson_t      *filter,
                                          bson_error_t      *error)
{
   mongoc_collection_t *col;
   mongoc_cursor_t *cursor = NULL;
   mongoc_read_prefs_t *read_prefs;
   uint32_t dbname_len;
   bson_t legacy_filter;
   bson_iter_t iter;
   const char *col_filter;
   bson_t q = BSON_INITIALIZER;
   mongoc_database_find_collections_legacy_ctx_t *ctx;

   BSON_ASSERT (database);

   col = mongoc_client_get_collection (database->client,
                                       database->name,
                                       "system.namespaces");

   BSON_ASSERT (col);

   dbname_len = (uint32_t)strlen (database->name);

   ctx = bson_malloc (sizeof (*ctx));

   ctx->dbname = database->name;
   ctx->dbname_len = dbname_len;

   /* Filtering on name needs to be handled differently for old servers. */
   if (filter && bson_iter_init_find (&iter, filter, "name")) {
      bson_string_t *buf;
      /* on legacy servers, this must be a string (i.e. not a regex) */
      if (!BSON_ITER_HOLDS_UTF8 (&iter)) {
         bson_set_error (error,
                         MONGOC_ERROR_NAMESPACE,
                         MONGOC_ERROR_NAMESPACE_INVALID_FILTER_TYPE,
                         "On legacy servers, a filter on name can only be a string.");
         goto cleanup_filter;
      }
      BSON_ASSERT (BSON_ITER_HOLDS_UTF8 (&iter));
      col_filter = bson_iter_utf8 (&iter, NULL);
      bson_init (&legacy_filter);
      bson_copy_to_excluding_noinit (filter, &legacy_filter, "name", NULL);
      /* We must db-qualify filters on name. */
      buf = bson_string_new (database->name);
      bson_string_append_c (buf, '.');
      bson_string_append (buf, col_filter);
      BSON_APPEND_UTF8 (&legacy_filter, "name", buf->str);
      bson_string_free (buf, true);
      filter = &legacy_filter;
   }

   read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY);

   cursor = mongoc_collection_find (col, MONGOC_QUERY_NONE, 0, 0, 0,
                                    filter ? filter : &q, NULL, read_prefs);

   _mongoc_cursor_transform_init (
      cursor,
      _mongoc_database_find_collections_legacy_filter,
      _mongoc_database_find_collections_legacy_mutate,
      &bson_free,
      ctx);

   mongoc_read_prefs_destroy (read_prefs);

 cleanup_filter:
   mongoc_collection_destroy (col);

   return cursor;
}
/* Uses old way of querying system.namespaces. */
bson_t *
_mongoc_database_get_collection_info_legacy (mongoc_database_t *database,
                                             const bson_t      *filter,
                                             bson_error_t      *error)
{
   mongoc_collection_t *col;
   mongoc_cursor_t *cursor;
   mongoc_read_prefs_t *read_prefs;
   uint32_t dbname_len;
   const bson_t *doc;
   bson_t legacy_filter;
   bson_iter_t iter;
   const char *name;
   const char *col_filter;
   bson_t q = BSON_INITIALIZER;
   bson_t *ret = NULL;
   bson_t col_array = BSON_INITIALIZER;
   const char *key;
   char keystr[16];
   uint32_t n_cols = 0;

   BSON_ASSERT (database);

   col = mongoc_client_get_collection (database->client,
                                       database->name,
                                       "system.namespaces");

   BSON_ASSERT (col);

   dbname_len = (uint32_t)strlen (database->name);

   /* Filtering on name needs to be handled differently for old servers. */
   if (filter && bson_iter_init_find (&iter, filter, "name")) {
      /* on legacy servers, this must be a string (i.e. not a regex) */
      if (!BSON_ITER_HOLDS_UTF8 (&iter)) {
         bson_set_error (error,
                         MONGOC_ERROR_NAMESPACE,
                         MONGOC_ERROR_NAMESPACE_INVALID_FILTER_TYPE,
                         "On legacy servers, a filter on name can only be a string.");
         goto cleanup_filter;
      }
      BSON_ASSERT (BSON_ITER_HOLDS_UTF8 (&iter));
      col_filter = bson_iter_utf8 (&iter, NULL);
      bson_init (&legacy_filter);
      bson_copy_to_excluding_noinit (filter, &legacy_filter, "name", NULL);
      /* We must db-qualify filters on name. */
      bson_string_t *buf = bson_string_new (database->name);
      bson_string_append_c (buf, '.');
      bson_string_append (buf, col_filter);
      BSON_APPEND_UTF8 (&legacy_filter, "name", buf->str);
      bson_string_free (buf, true);
      filter = &legacy_filter;
   }

   read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY);

   cursor = mongoc_collection_find (col, MONGOC_QUERY_NONE, 0, 0, 0,
                                    filter ? filter : &q, NULL, read_prefs);

   ret = bson_new();

   BSON_APPEND_ARRAY_BEGIN (ret, "collections", &col_array);

   while (mongoc_cursor_more (cursor) &&
          !mongoc_cursor_error (cursor, error)) {
      if (mongoc_cursor_next (cursor, &doc)) {
         /* 2 gotchas here.
          * 1. need to ignore any system collections (prefixed with $)
          * 2. need to remove the database name from the collection so that clients
          *    don't need to specialize their logic for old versions of the server.
          */
         if (bson_iter_init_find (&iter, doc, "name") &&
             BSON_ITER_HOLDS_UTF8 (&iter) &&
             (name = bson_iter_utf8 (&iter, NULL)) &&
             !strchr (name, '$') &&
             (0 == strncmp (name, database->name, dbname_len))) {
            bson_t nprefix_col = BSON_INITIALIZER;
            bson_copy_to_excluding_noinit (doc, &nprefix_col, "name", NULL);
            BSON_APPEND_UTF8 (&nprefix_col, "name", name + (dbname_len + 1));  /* +1 for the '.' */
            /* need to construct a key for this array element. */
            bson_uint32_to_string(n_cols, &key, keystr, sizeof (keystr));
            BSON_APPEND_DOCUMENT (&col_array, key, &nprefix_col);
            ++n_cols;
         }
      }
   }

   bson_append_array_end (ret, &col_array);

   mongoc_cursor_destroy (cursor);
   mongoc_read_prefs_destroy (read_prefs);
 cleanup_filter:
   mongoc_collection_destroy (col);
   return ret;
}