mongo_ext 0.18.1 → 0.18.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile CHANGED
@@ -1,3 +1,4 @@
1
+ # -*- mode: ruby; -*-
1
2
  require 'rubygems'
2
3
  require 'rubygems/specification'
3
4
  require 'fileutils'
@@ -12,9 +13,6 @@ require 'rbconfig'
12
13
  include Config
13
14
  ENV['TEST_MODE'] = 'TRUE'
14
15
 
15
- gem_command = "gem"
16
- gem_command = "gem1.9" if $0.match(/1\.9$/) # use gem1.9 if we used rake1.9
17
-
18
16
  desc "Test the MongoDB Ruby driver."
19
17
  task :test do
20
18
  puts "\nThis option has changed."
@@ -95,20 +93,16 @@ namespace :gem do
95
93
 
96
94
  desc "Install the gem locally"
97
95
  task :install do
98
- sh <<EOS
99
- #{gem_command} build mongo-ruby-driver.gemspec &&
100
- #{gem_command} install mongo-*.gem &&
101
- rm mongo-*.gem
102
- EOS
96
+ sh "gem build mongo-ruby-driver.gemspec"
97
+ sh "gem install mongo-*.gem"
98
+ sh "rm mongo-*.gem"
103
99
  end
104
100
 
105
101
  desc "Install the optional c extensions"
106
102
  task :install_extensions do
107
- sh <<EOS
108
- #{gem_command} build mongo-extensions.gemspec &&
109
- #{gem_command} install mongo_ext-*.gem &&
110
- rm mongo_ext-*.gem
111
- EOS
103
+ sh "gem build mongo-extensions.gemspec"
104
+ sh "gem install mongo_ext-*.gem"
105
+ sh "rm mongo_ext-*.gem"
112
106
  end
113
107
 
114
108
  end
@@ -51,7 +51,7 @@
51
51
 
52
52
  #define SAFE_WRITE_AT_POS(buffer, position, data, size) \
53
53
  if (buffer_write_at_position((buffer), (position), (data), (size)) != 0) \
54
- rb_raise(rb_eNoMemError, "failed to allocate memory in buffer.c")
54
+ rb_raise(rb_eRuntimeError, "invalid write at position in buffer.c")
55
55
 
56
56
  #define MAX_HOSTNAME_LENGTH 256
57
57
 
@@ -64,6 +64,7 @@ static VALUE RegexpOfHolding;
64
64
  static VALUE OrderedHash;
65
65
  static VALUE InvalidName;
66
66
  static VALUE InvalidStringEncoding;
67
+ static VALUE InvalidDocument;
67
68
  static VALUE DigestMD5;
68
69
 
69
70
  #if HAVE_RUBY_ENCODING_H
@@ -71,15 +72,26 @@ static VALUE DigestMD5;
71
72
  #define STR_NEW(p,n) rb_enc_str_new((p), (n), rb_utf8_encoding())
72
73
  /* MUST call TO_UTF8 before calling write_utf8. */
73
74
  #define TO_UTF8(string) rb_str_export_to_enc((string), rb_utf8_encoding())
74
- static void write_utf8(buffer_t buffer, VALUE string) {
75
+ static void write_utf8(buffer_t buffer, VALUE string, char check_null) {
76
+ result_t status = check_string(RSTRING_PTR(string), RSTRING_LEN(string),
77
+ 0, check_null);
78
+ if (status == HAS_NULL) {
79
+ buffer_free(buffer);
80
+ rb_raise(InvalidDocument, "Key names / regex patterns must not contain the NULL byte");
81
+ }
75
82
  SAFE_WRITE(buffer, RSTRING_PTR(string), RSTRING_LEN(string));
76
83
  }
77
84
  #else
78
85
  #define STR_NEW(p,n) rb_str_new((p), (n))
79
86
  /* MUST call TO_UTF8 before calling write_utf8. */
80
87
  #define TO_UTF8(string) (string)
81
- static void write_utf8(buffer_t buffer, VALUE string) {
82
- if (!is_legal_utf8_string(RSTRING_PTR(string), RSTRING_LEN(string))) {
88
+ static void write_utf8(buffer_t buffer, VALUE string, char check_null) {
89
+ result_t status = check_string(RSTRING_PTR(string), RSTRING_LEN(string),
90
+ 1, check_null);
91
+ if (status == HAS_NULL) {
92
+ buffer_free(buffer);
93
+ rb_raise(InvalidDocument, "Key names / regex patterns must not contain the NULL byte");
94
+ } else if (status == NOT_UTF_8) {
83
95
  buffer_free(buffer);
84
96
  rb_raise(InvalidStringEncoding, "String not valid UTF-8");
85
97
  }
@@ -100,7 +112,9 @@ static void write_utf8(buffer_t buffer, VALUE string) {
100
112
 
101
113
  /* TODO we ought to check that the malloc or asprintf was successful
102
114
  * and raise an exception if not. */
103
- #ifdef _MSC_VER
115
+ /* TODO maybe we can use something more portable like vsnprintf instead
116
+ * of this hack. And share it with the Python extension ;) */
117
+ #ifndef HAVE_ASPRINTF
104
118
  #define INT2STRING(buffer, i) \
105
119
  { \
106
120
  int vslength = _scprintf("%d", i) + 1; \
@@ -112,9 +126,8 @@ static void write_utf8(buffer_t buffer, VALUE string) {
112
126
  #endif
113
127
 
114
128
  // this sucks too.
115
- #ifndef RREGEXP_SRC_PTR
116
- #define RREGEXP_SRC_PTR(r) RREGEXP(r)->str
117
- #define RREGEXP_SRC_LEN(r) RREGEXP(r)->len
129
+ #ifndef RREGEXP_SRC
130
+ #define RREGEXP_SRC(r) rb_str_new(RREGEXP((r))->str, RREGEXP((r))->len)
118
131
  #endif
119
132
 
120
133
  static char zero = 0;
@@ -135,7 +148,7 @@ static VALUE pack_extra(buffer_t buffer, VALUE check_keys) {
135
148
  static void write_name_and_type(buffer_t buffer, VALUE name, char type) {
136
149
  SAFE_WRITE(buffer, &type, 1);
137
150
  name = TO_UTF8(name);
138
- write_utf8(buffer, name);
151
+ write_utf8(buffer, name, 1);
139
152
  SAFE_WRITE(buffer, &zero, 1);
140
153
  }
141
154
 
@@ -285,7 +298,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
285
298
  value = TO_UTF8(value);
286
299
  length = RSTRING_LEN(value) + 1;
287
300
  SAFE_WRITE(buffer, (char*)&length, 4);
288
- write_utf8(buffer, value);
301
+ write_utf8(buffer, value, 0);
289
302
  SAFE_WRITE(buffer, &zero, 1);
290
303
  break;
291
304
  }
@@ -356,6 +369,9 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
356
369
  SAFE_WRITE_AT_POS(buffer, length_location, (const char*)&obj_length, 4);
357
370
  break;
358
371
  }
372
+ buffer_free(buffer);
373
+ rb_raise(InvalidDocument, "Unsupported type for BSON (%d)", TYPE(value));
374
+ break;
359
375
  }
360
376
  case T_DATA:
361
377
  {
@@ -371,14 +387,14 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
371
387
  }
372
388
  case T_REGEXP:
373
389
  {
374
- int length = RREGEXP_SRC_LEN(value);
375
- char* pattern = (char*)RREGEXP_SRC_PTR(value);
390
+ VALUE pattern = RREGEXP_SRC(value);
376
391
  long flags = RREGEXP(value)->ptr->options;
377
392
  VALUE has_extra;
378
393
 
379
394
  write_name_and_type(buffer, key, 0x0B);
380
395
 
381
- SAFE_WRITE(buffer, pattern, length);
396
+ pattern = TO_UTF8(pattern);
397
+ write_utf8(buffer, pattern, 1);
382
398
  SAFE_WRITE(buffer, &zero, 1);
383
399
 
384
400
  if (flags & IGNORECASE) {
@@ -408,7 +424,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
408
424
  default:
409
425
  {
410
426
  buffer_free(buffer);
411
- rb_raise(rb_eTypeError, "no c encoder for this type yet (%d)", TYPE(value));
427
+ rb_raise(InvalidDocument, "Unsupported type for BSON (%d)", TYPE(value));
412
428
  break;
413
429
  }
414
430
  }
@@ -455,6 +471,13 @@ static void write_doc(buffer_t buffer, VALUE hash, VALUE check_keys) {
455
471
  // write null byte and fill in length
456
472
  SAFE_WRITE(buffer, &zero, 1);
457
473
  length = buffer_get_position(buffer) - start_position;
474
+
475
+ // make sure that length doesn't exceed 4MB
476
+ if (length > 4 * 1024 * 1024) {
477
+ buffer_free(buffer);
478
+ rb_raise(InvalidDocument, "Document too large: BSON documents are limited to 4MB.");
479
+ return;
480
+ }
458
481
  SAFE_WRITE_AT_POS(buffer, length_location, &length, 4);
459
482
  }
460
483
 
@@ -489,8 +512,8 @@ static VALUE get_value(const char* buffer, int* position, int type) {
489
512
  case 13:
490
513
  {
491
514
  int value_length;
515
+ value_length = *(int*)(buffer + *position) - 1;
492
516
  *position += 4;
493
- value_length = strlen(buffer + *position);
494
517
  value = STR_NEW(buffer + *position, value_length);
495
518
  *position += value_length + 1;
496
519
  break;
@@ -500,10 +523,11 @@ static VALUE get_value(const char* buffer, int* position, int type) {
500
523
  int size;
501
524
  memcpy(&size, buffer + *position, 4);
502
525
  if (strcmp(buffer + *position + 5, "$ref") == 0) { // DBRef
503
- int offset = *position + 14;
526
+ int offset = *position + 10;
504
527
  VALUE argv[2];
505
- int collection_length = strlen(buffer + offset);
528
+ int collection_length = *(int*)(buffer + offset) - 1;
506
529
  char id_type;
530
+ offset += 4;
507
531
 
508
532
  argv[0] = STR_NEW(buffer + offset, collection_length);
509
533
  offset += collection_length + 1;
@@ -629,8 +653,8 @@ static VALUE get_value(const char* buffer, int* position, int type) {
629
653
  {
630
654
  int collection_length;
631
655
  VALUE collection, str, oid, id, argv[2];
656
+ collection_length = *(int*)(buffer + *position) - 1;
632
657
  *position += 4;
633
- collection_length = strlen(buffer + *position);
634
658
  collection = STR_NEW(buffer + *position, collection_length);
635
659
  *position += collection_length + 1;
636
660
 
@@ -656,8 +680,9 @@ static VALUE get_value(const char* buffer, int* position, int type) {
656
680
  {
657
681
  int code_length, scope_size;
658
682
  VALUE code, scope, argv[2];
659
- *position += 8;
660
- code_length = strlen(buffer + *position);
683
+ *position += 4;
684
+ code_length = *(int*)(buffer + *position) - 1;
685
+ *position += 4;
661
686
  code = STR_NEW(buffer + *position, code_length);
662
687
  *position += code_length + 1;
663
688
 
@@ -799,6 +824,7 @@ void Init_cbson() {
799
824
  rb_require("mongo/errors");
800
825
  InvalidName = rb_const_get(mongo, rb_intern("InvalidName"));
801
826
  InvalidStringEncoding = rb_const_get(mongo, rb_intern("InvalidStringEncoding"));
827
+ InvalidDocument = rb_const_get(mongo, rb_intern("InvalidDocument"));
802
828
  rb_require("mongo/util/ordered_hash");
803
829
  OrderedHash = rb_const_get(rb_cObject, rb_intern("OrderedHash"));
804
830
 
@@ -14,8 +14,10 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
+ #include "encoding_helpers.h"
18
+
17
19
  /*
18
- * Copyright 2001 Unicode, Inc.
20
+ * Portions Copyright 2001 Unicode, Inc.
19
21
  *
20
22
  * Disclaimer
21
23
  *
@@ -85,23 +87,32 @@ static unsigned char isLegalUTF8(const unsigned char* source, int length) {
85
87
  return 1;
86
88
  }
87
89
 
88
- /* --------------------------------------------------------------------- */
89
-
90
- /*
91
- * Return whether a string containing UTF-8 is legal.
92
- */
93
- unsigned char is_legal_utf8_string(const unsigned char* string, const int length) {
90
+ result_t check_string(const unsigned char* string, const int length,
91
+ const char check_utf8, const char check_null) {
94
92
  int position = 0;
93
+ /* By default we go character by character. Will be different for checking
94
+ * UTF-8 */
95
+ int sequence_length = 1;
96
+
97
+ if (!check_utf8 && !check_null) {
98
+ return VALID;
99
+ }
95
100
 
96
101
  while (position < length) {
97
- int sequence_length = trailingBytesForUTF8[*(string + position)] + 1;
98
- if ((position + sequence_length) > length) {
99
- return 0;
102
+ if (check_null && *(string + position) == 0) {
103
+ return HAS_NULL;
100
104
  }
101
- if (!isLegalUTF8(string + position, sequence_length)) {
102
- return 0;
105
+ if (check_utf8) {
106
+ sequence_length = trailingBytesForUTF8[*(string + position)] + 1;
107
+ if ((position + sequence_length) > length) {
108
+ return NOT_UTF_8;
109
+ }
110
+ if (!isLegalUTF8(string + position, sequence_length)) {
111
+ return NOT_UTF_8;
112
+ }
103
113
  }
104
114
  position += sequence_length;
105
115
  }
106
- return 1;
116
+
117
+ return VALID;
107
118
  }
@@ -17,6 +17,13 @@
17
17
  #ifndef ENCODING_HELPERS_H
18
18
  #define ENCODING_HELPERS_H
19
19
 
20
- unsigned char is_legal_utf8_string(const unsigned char* string, const int length);
20
+ typedef enum {
21
+ VALID,
22
+ NOT_UTF_8,
23
+ HAS_NULL
24
+ } result_t;
25
+
26
+ result_t check_string(const unsigned char* string, const int length,
27
+ const char check_utf8, const char check_null);
21
28
 
22
29
  #endif
@@ -1,5 +1,7 @@
1
1
  require 'mkmf'
2
2
 
3
+ have_func("asprintf")
4
+
3
5
  have_header("ruby/st.h") || have_header("st.h")
4
6
  have_header("ruby/regex.h") || have_header("regex.h")
5
7
  have_header("ruby/encoding.h")
@@ -14,4 +14,4 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- #define VERSION "0.18.1"
17
+ #define VERSION "0.18.2"
@@ -1,5 +1,5 @@
1
1
  require 'lib/mongo'
2
- VERSION_HEADER = File.open(File.join(File.dirname(__FILE__), 'ext', 'cbson', 'version.h'), "r")
2
+ VERSION_HEADER = File.open(File.join(File.dirname(__FILE__), 'ext', 'cbson', 'version.h'), "r")
3
3
  VERSION = VERSION_HEADER.read.scan(/VERSION\s+"(\d+\.\d+(\.\d+)?)\"/)[0][0]
4
4
  Gem::Specification.new do |s|
5
5
  s.name = 'mongo_ext'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongo_ext
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.1
4
+ version: 0.18.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Dirolf
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-05 00:00:00 -05:00
12
+ date: 2009-12-29 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -33,6 +33,8 @@ files:
33
33
  - ext/cbson/version.h
34
34
  has_rdoc: false
35
35
  homepage: http://www.mongodb.org
36
+ licenses: []
37
+
36
38
  post_install_message:
37
39
  rdoc_options: []
38
40
 
@@ -53,9 +55,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
53
55
  requirements: []
54
56
 
55
57
  rubyforge_project:
56
- rubygems_version: 1.3.1
58
+ rubygems_version: 1.3.5
57
59
  signing_key:
58
- specification_version: 2
60
+ specification_version: 3
59
61
  summary: C extensions for the MongoDB Ruby driver
60
62
  test_files: []
61
63