mongo_ext 0.18.1 → 0.18.2

Sign up to get free protection for your applications and to get access to all the features.
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