mongo 1.3.0 → 1.3.1

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/README.md CHANGED
@@ -18,17 +18,18 @@ for much more:
18
18
 
19
19
  require 'rubygems'
20
20
  require 'mongo'
21
- include Mongo
22
21
 
23
- db = Connection.new.db('sample-db')
24
- coll = db.collection('test')
22
+ @conn = Mongo::Connection.new
23
+ @db = @conn['sample-db']
24
+ @coll = @db['test']
25
25
 
26
- coll.remove
26
+ @coll.remove
27
27
  3.times do |i|
28
- coll.insert({'a' => i+1})
28
+ @coll.insert({'a' => i+1})
29
29
  end
30
- puts "There are #{coll.count()} records. Here they are:"
31
- coll.find().each { |doc| puts doc.inspect }
30
+
31
+ puts "There are #{@coll.count} records. Here they are:"
32
+ @coll.find.each { |doc| puts doc.inspect }
32
33
 
33
34
  # Installation
34
35
 
@@ -1,5 +1,24 @@
1
1
  # MongoDB Ruby Driver History
2
2
 
3
+ ### 1.3.1
4
+ 2011-5-10
5
+
6
+ * Fix GridIO#gets infinite loop error (Ryan McGeary)
7
+ * Fix BSON::OrderedHash#reject! leaving keys with null values (rpt. by Ben Poweski)
8
+ * Minor semantic fix for OrderedHash#reject!
9
+ * Fix Mongo::DB to allow symbols in method traversing collection names (rpt. by Chris Griego)
10
+ * Support new server regex option "s" (dotall). This is folded in with \m in Ruby.
11
+ * Fix so that Cursor#close hits the right node when :read_secondary is enabled.
12
+ * Support maxScan, showDiskLoc, and returnKey cursor options.
13
+ * Make DB#validate_collection compatible with server v1.9.1.
14
+ * Fix so that GridIO#gets returns local md5 with md5 matches server md5 (Steve Tantra).
15
+ * Fix bug in BSON::OrderedHash that prevents YAML.load (Ian Warshak).
16
+ * Fix example from /examples.
17
+ * Ensure that we do not modify hash arguments by calling Hash#dup when appropriate.
18
+ * Ensure that JRuby deserializer preserves binary subtypes properly.
19
+ * Fix for streaming an empty file into GridFS (Daniël van de Burgt).
20
+ * Minor doc fixes.
21
+
3
22
  ### 1.3.0
4
23
  2011-4-04
5
24
 
@@ -19,7 +19,7 @@
19
19
  $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
20
20
 
21
21
  module Mongo
22
- VERSION = "1.3.0"
22
+ VERSION = "1.3.1"
23
23
  end
24
24
 
25
25
  module Mongo
@@ -91,7 +91,7 @@ module Mongo
91
91
  # Return a sub-collection of this collection by name. If 'users' is a collection, then
92
92
  # 'users.comments' is a sub-collection of users.
93
93
  #
94
- # @param [String] name
94
+ # @param [String, Symbol] name
95
95
  # the collection to return
96
96
  #
97
97
  # @raise [Mongo::InvalidNSName]
@@ -101,7 +101,8 @@ module Mongo
101
101
  # the specified sub-collection
102
102
  def [](name)
103
103
  name = "#{self.name}.#{name}"
104
- return Collection.new(name, db) if !db.strict? || db.collection_names.include?(name)
104
+ return Collection.new(name, db) if !db.strict? ||
105
+ db.collection_names.include?(name.to_s)
105
106
  raise "Collection #{name} doesn't exist. Currently in strict mode."
106
107
  end
107
108
 
@@ -147,16 +148,23 @@ module Mongo
147
148
  # @option opts [Integer] :limit maximum number of documents to return
148
149
  # @option opts [Array] :sort an array of [key, direction] pairs to sort by. Direction should
149
150
  # be specified as Mongo::ASCENDING (or :ascending / :asc) or Mongo::DESCENDING (or :descending / :desc)
150
- # @option opts [String, Array, OrderedHash] :hint hint for query optimizer, usually not necessary if using MongoDB > 1.1
151
+ # @option opts [String, Array, OrderedHash] :hint hint for query optimizer, usually not necessary if
152
+ # using MongoDB > 1.1
151
153
  # @option opts [Boolean] :snapshot (false) if true, snapshot mode will be used for this query.
152
154
  # Snapshot mode assures no duplicates are returned, or objects missed, which were preset at both the start and
153
- # end of the query's execution. For details see http://www.mongodb.org/display/DOCS/How+to+do+Snapshotting+in+the+Mongo+Database
154
- # @option opts [Boolean] :batch_size (100) the number of documents to returned by the database per GETMORE operation. A value of 0
155
- # will let the database server decide how many results to returns. This option can be ignored for most use cases.
155
+ # end of the query's execution.
156
+ # For details see http://www.mongodb.org/display/DOCS/How+to+do+Snapshotting+in+the+Mongo+Database
157
+ # @option opts [Boolean] :batch_size (100) the number of documents to returned by the database per
158
+ # GETMORE operation. A value of 0 will let the database server decide how many results to returns.
159
+ # This option can be ignored for most use cases.
156
160
  # @option opts [Boolean] :timeout (true) when +true+, the returned cursor will be subject to
157
- # the normal cursor timeout behavior of the mongod process. When +false+, the returned cursor will never timeout. Note
158
- # that disabling timeout will only work when #find is invoked with a block. This is to prevent any inadvertant failure to
159
- # close the cursor, as the cursor is explicitly closed when block code finishes.
161
+ # the normal cursor timeout behavior of the mongod process. When +false+, the returned cursor will
162
+ # never timeout. Note that disabling timeout will only work when #find is invoked with a block.
163
+ # This is to prevent any inadvertant failure to close the cursor, as the cursor is explicitly
164
+ # closed when block code finishes.
165
+ # @option opts [Integer] :max_scan (nil) Limit the number of items to scan on both collection scans and indexed queries..
166
+ # @option opts [Boolean] :show_disk_loc (false) Return the disk location of each query result (for debugging).
167
+ # @option opts [Boolean] :return_key (false) Return the index key used to obtain the result (for debugging).
160
168
  # @option opts [Block] :transformer (nil) a block for tranforming returned documents.
161
169
  # This is normally used by object mappers to convert each returned document to an instance of a class.
162
170
  #
@@ -168,6 +176,7 @@ module Mongo
168
176
  #
169
177
  # @core find find-instance_method
170
178
  def find(selector={}, opts={})
179
+ opts = opts.dup
171
180
  fields = opts.delete(:fields)
172
181
  fields = ["_id"] if fields && fields.empty?
173
182
  skip = opts.delete(:skip) || skip || 0
@@ -385,7 +394,7 @@ module Mongo
385
394
  if safe
386
395
  @connection.send_message_with_safe_check(Mongo::Constants::OP_UPDATE, message, @db.name, nil, safe)
387
396
  else
388
- @connection.send_message(Mongo::Constants::OP_UPDATE, message, nil)
397
+ @connection.send_message(Mongo::Constants::OP_UPDATE, message)
389
398
  end
390
399
  end
391
400
  end
@@ -433,8 +442,9 @@ module Mongo
433
442
  #
434
443
  # @core indexes create_index-instance_method
435
444
  def create_index(spec, opts={})
436
- opts[:dropDups] = opts.delete(:drop_dups) if opts[:drop_dups]
445
+ opts[:dropDups] = opts[:drop_dups] if opts[:drop_dups]
437
446
  field_spec = parse_index_spec(spec)
447
+ opts = opts.dup
438
448
  name = opts.delete(:name) || generate_index_name(field_spec)
439
449
  name = name.to_s if name
440
450
 
@@ -462,7 +472,7 @@ module Mongo
462
472
  now = Time.now.utc.to_i
463
473
  field_spec = parse_index_spec(spec)
464
474
 
465
- name = opts.delete(:name) || generate_index_name(field_spec)
475
+ name = opts[:name] || generate_index_name(field_spec)
466
476
  name = name.to_s if name
467
477
 
468
478
  if !@cache[name] || @cache[name] <= now
@@ -555,7 +565,7 @@ module Mongo
555
565
  def map_reduce(map, reduce, opts={})
556
566
  map = BSON::Code.new(map) unless map.is_a?(BSON::Code)
557
567
  reduce = BSON::Code.new(reduce) unless reduce.is_a?(BSON::Code)
558
- raw = opts.delete(:raw)
568
+ raw = opts[:raw]
559
569
 
560
570
  hash = BSON::OrderedHash.new
561
571
  hash['mapreduce'] = self.name
@@ -867,7 +877,7 @@ module Mongo
867
877
  if safe
868
878
  @connection.send_message_with_safe_check(Mongo::Constants::OP_INSERT, message, @db.name, nil, safe)
869
879
  else
870
- @connection.send_message(Mongo::Constants::OP_INSERT, message, nil)
880
+ @connection.send_message(Mongo::Constants::OP_INSERT, message)
871
881
  end
872
882
  end
873
883
  documents.collect { |o| o[:_id] || o['_id'] }
@@ -381,15 +381,36 @@ module Mongo
381
381
  # @param [Integer] operation a MongoDB opcode.
382
382
  # @param [BSON::ByteBuffer] message a message to send to the database.
383
383
  #
384
+ # @option opts [Symbol] :connection (:writer) The connection to which
385
+ # this message should be sent. Valid options are :writer and :reader.
386
+ #
384
387
  # @return [Integer] number of bytes sent
385
- def send_message(operation, message, log_message=nil)
388
+ def send_message(operation, message, opts={})
389
+ if opts.is_a?(String)
390
+ warn "Connection#send_message no longer takes a string log message. " +
391
+ "Logging is now handled within the Collection and Cursor classes."
392
+ opts = {}
393
+ end
394
+
395
+ connection = opts.fetch(:connection, :writer)
396
+
386
397
  begin
387
398
  add_message_headers(message, operation)
388
399
  packed_message = message.to_s
389
- socket = checkout_writer
400
+
401
+ if connection == :writer
402
+ socket = checkout_writer
403
+ else
404
+ socket = checkout_reader
405
+ end
406
+
390
407
  send_message_on_socket(packed_message, socket)
391
408
  ensure
392
- checkin_writer(socket)
409
+ if connection == :writer
410
+ checkin_writer(socket)
411
+ else
412
+ checkin_reader(socket)
413
+ end
393
414
  end
394
415
  end
395
416
 
@@ -437,7 +458,10 @@ module Mongo
437
458
  #
438
459
  # @param [Integer] operation a MongoDB opcode.
439
460
  # @param [BSON::ByteBuffer] message a message to send to the database.
461
+ # @param [String] log_message this is currently a no-op and will be removed.
440
462
  # @param [Socket] socket a socket to use in lieu of checking out a new one.
463
+ # @param [Boolean] command (false) indicate whether this is a command. If this is a command,
464
+ # the message will be sent to the primary node.
441
465
  #
442
466
  # @return [Array]
443
467
  # An array whose indexes include [0] documents returned, [1] number of document received,
@@ -41,19 +41,31 @@ module Mongo
41
41
  @connection = @db.connection
42
42
  @logger = @connection.logger
43
43
 
44
+ # Query selector
44
45
  @selector = opts[:selector] || {}
45
- @fields = convert_fields_for_query(opts[:fields])
46
- @skip = opts[:skip] || 0
47
- @limit = opts[:limit] || 0
46
+
47
+ # Special operators that form part of $query
48
48
  @order = opts[:order]
49
+ @explain = opts[:explain]
49
50
  @hint = opts[:hint]
50
51
  @snapshot = opts[:snapshot]
52
+ @max_scan = opts.fetch(:max_scan, nil)
53
+ @return_key = opts.fetch(:return_key, nil)
54
+ @show_disk_loc = opts.fetch(:show_disk_loc, nil)
55
+
56
+ # Wire-protocol settings
57
+ @fields = convert_fields_for_query(opts[:fields])
58
+ @skip = opts[:skip] || 0
59
+ @limit = opts[:limit] || 0
60
+ @tailable = opts[:tailable] || false
51
61
  @timeout = opts.fetch(:timeout, true)
52
- @explain = opts[:explain]
62
+
63
+ # Use this socket for the query
53
64
  @socket = opts[:socket]
54
- @tailable = opts[:tailable] || false
65
+
55
66
  @closed = false
56
67
  @query_run = false
68
+
57
69
  @transformer = opts[:transformer]
58
70
  batch_size(opts[:batch_size] || 0)
59
71
 
@@ -284,7 +296,7 @@ module Mongo
284
296
  message.put_int(1)
285
297
  message.put_long(@cursor_id)
286
298
  @logger.debug("MONGODB cursor.close #{@cursor_id}") if @logger
287
- @connection.send_message(Mongo::Constants::OP_KILL_CURSORS, message, nil)
299
+ @connection.send_message(Mongo::Constants::OP_KILL_CURSORS, message, :connection => :reader)
288
300
  end
289
301
  @cursor_id = 0
290
302
  @closed = true
@@ -320,7 +332,10 @@ module Mongo
320
332
  :order => @order,
321
333
  :hint => @hint,
322
334
  :snapshot => @snapshot,
323
- :timeout => @timeout }
335
+ :timeout => @timeout,
336
+ :max_scan => @max_scan,
337
+ :return_key => @return_key,
338
+ :show_disk_loc => @show_disk_loc }
324
339
  end
325
340
 
326
341
  # Clean output for inspect.
@@ -429,6 +444,9 @@ module Mongo
429
444
  spec['$hint'] = @hint if @hint && @hint.length > 0
430
445
  spec['$explain'] = true if @explain
431
446
  spec['$snapshot'] = true if @snapshot
447
+ spec['$maxscan'] = @max_scan if @max_scan
448
+ spec['$returnKey'] = true if @return_key
449
+ spec['$showDiskLoc'] = true if @show_disk_loc
432
450
  spec
433
451
  end
434
452
 
@@ -251,26 +251,28 @@ module Mongo
251
251
  # new collection. If +strict+ is true, will raise an error if
252
252
  # collection +name+ already exists.
253
253
  #
254
- # @param [String] name the name of the new collection.
254
+ # @param [String, Symbol] name the name of the new collection.
255
255
  #
256
256
  # @option opts [Boolean] :capped (False) created a capped collection.
257
257
  #
258
- # @option opts [Integer] :size (Nil) If +capped+ is +true+, specifies the maximum number of
259
- # bytes for the capped collection. If +false+, specifies the number of bytes allocated
258
+ # @option opts [Integer] :size (Nil) If +capped+ is +true+,
259
+ # specifies the maximum number of bytes for the capped collection.
260
+ # If +false+, specifies the number of bytes allocated
260
261
  # for the initial extent of the collection.
261
262
  #
262
- # @option opts [Integer] :max (Nil) If +capped+ is +true+, indicates the maximum number of records
263
- # in a capped collection.
263
+ # @option opts [Integer] :max (Nil) If +capped+ is +true+, indicates
264
+ # the maximum number of records in a capped collection.
264
265
  #
265
- # @raise [MongoDBError] raised under two conditions: either we're in +strict+ mode and the collection
266
+ # @raise [MongoDBError] raised under two conditions:
267
+ # either we're in +strict+ mode and the collection
266
268
  # already exists or collection creation fails on the server.
267
269
  #
268
270
  # @return [Mongo::Collection]
269
271
  def create_collection(name, opts={})
270
- # Does the collection already exist?
271
- if collection_names.include?(name)
272
+ if collection_names.include?(name.to_s)
272
273
  if strict?
273
- raise MongoDBError, "Collection #{name} already exists. Currently in strict mode."
274
+ raise MongoDBError, "Collection #{name} already exists. " +
275
+ "Currently in strict mode."
274
276
  else
275
277
  return Collection.new(name, self, opts)
276
278
  end
@@ -286,16 +288,19 @@ module Mongo
286
288
 
287
289
  # Get a collection by name.
288
290
  #
289
- # @param [String] name the collection name.
291
+ # @param [String, Symbol] name the collection name.
290
292
  # @param [Hash] opts any valid options that can be passed to Collection#new.
291
293
  #
292
- # @raise [MongoDBError] if collection does not already exist and we're in +strict+ mode.
294
+ # @raise [MongoDBError] if collection does not already exist and we're in
295
+ # +strict+ mode.
293
296
  #
294
297
  # @return [Mongo::Collection]
295
298
  def collection(name, opts={})
296
- if strict? && !collection_names.include?(name)
297
- raise Mongo::MongoDBError, "Collection #{name} doesn't exist. Currently in strict mode."
299
+ if strict? && !collection_names.include?(name.to_s)
300
+ raise Mongo::MongoDBError, "Collection #{name} doesn't exist. " +
301
+ "Currently in strict mode."
298
302
  else
303
+ opts = opts.dup
299
304
  opts[:safe] = opts.fetch(:safe, @safe)
300
305
  opts.merge!(:pk => @pk_factory) unless opts[:pk]
301
306
  Collection.new(name, self, opts)
@@ -305,11 +310,11 @@ module Mongo
305
310
 
306
311
  # Drop a collection by +name+.
307
312
  #
308
- # @param [String] name
313
+ # @param [String, Symbol] name
309
314
  #
310
315
  # @return [Boolean] +true+ on success or +false+ if the collection name doesn't exist.
311
316
  def drop_collection(name)
312
- return true unless collection_names.include?(name)
317
+ return true unless collection_names.include?(name.to_s)
313
318
 
314
319
  ok?(command(:drop => name))
315
320
  end
@@ -590,11 +595,16 @@ module Mongo
590
595
  # @raise [MongoDBError] if the command fails or there's a problem with the validation
591
596
  # data, or if the collection is invalid.
592
597
  def validate_collection(name)
593
- doc = command({:validate => name}, :check_response => false)
594
- raise MongoDBError, "Error with validate command: #{doc.inspect}" unless ok?(doc)
595
- result = doc['result']
596
- raise MongoDBError, "Error with validation data: #{doc.inspect}" unless result.kind_of?(String)
597
- raise MongoDBError, "Error: invalid collection #{name}: #{doc.inspect}" if result =~ /\b(exception|corrupt)\b/i
598
+ cmd = BSON::OrderedHash.new
599
+ cmd[:validate] = name
600
+ cmd[:full] = true
601
+ doc = command(cmd, :check_response => false)
602
+ if !ok?(doc)
603
+ raise MongoDBError, "Error with validate command: #{doc.inspect}"
604
+ end
605
+ if (doc.has_key?('valid') && !doc['valid']) || (doc['result'] =~ /\b(exception|corrupt)\b/i)
606
+ raise MongoDBError, "Error: invalid collection #{name}: #{doc.inspect}"
607
+ end
598
608
  doc
599
609
  end
600
610
 
@@ -65,7 +65,8 @@ module Mongo
65
65
  #
66
66
  # @return [Mongo::ObjectId] the file's id.
67
67
  def put(data, opts={})
68
- filename = opts.delete :filename
68
+ opts = opts.dup
69
+ filename = opts[:filename]
69
70
  opts.merge!(default_grid_io_opts)
70
71
  file = GridIO.new(@files, @chunks, filename, 'w', opts=opts)
71
72
  file.write(data)
@@ -93,6 +93,7 @@ module Mongo
93
93
  #
94
94
  # @return [Mongo::GridIO]
95
95
  def open(filename, mode, opts={})
96
+ opts = opts.dup
96
97
  opts.merge!(default_grid_io_opts(filename))
97
98
  del = opts.delete(:delete_old) && mode == 'w'
98
99
  file = GridIO.new(@files, @chunks, filename, mode, opts)
@@ -55,6 +55,7 @@ module Mongo
55
55
  @chunks = chunks
56
56
  @filename = filename
57
57
  @mode = mode
58
+ opts = opts.dup
58
59
  @query = opts.delete(:query) || {}
59
60
  @query_opts = opts.delete(:query_opts) || {}
60
61
  @fs_name = opts.delete(:fs_name) || Grid::DEFAULT_FS_NAME
@@ -207,43 +208,9 @@ module Mongo
207
208
  elsif separator.is_a?(Integer)
208
209
  read_length(separator)
209
210
  elsif separator.length > 1
210
- result = ''
211
- len = 0
212
- match_idx = 0
213
- match_num = separator.length - 1
214
- to_match = separator[match_idx].chr
215
- if length
216
- matcher = lambda {|idx, num| idx < num && len < length }
217
- else
218
- matcher = lambda {|idx, num| idx < num}
219
- end
220
- while matcher.call(match_idx, match_num) && char = getc
221
- result << char
222
- len += 1
223
- if char == to_match
224
- while match_idx < match_num do
225
- match_idx += 1
226
- to_match = separator[match_idx].chr
227
- char = getc
228
- result << char
229
- if char != to_match
230
- match_idx = 0
231
- to_match = separator[match_idx].chr
232
- break
233
- end
234
- end
235
- end
236
- end
237
- result
211
+ read_to_string(separator, length)
238
212
  else
239
- result = ''
240
- len = 0
241
- while char = getc
242
- result << char
243
- len += 1
244
- break if char == separator || (length ? len >= length : false)
245
- end
246
- result
213
+ read_to_character(separator, length)
247
214
  end
248
215
  end
249
216
 
@@ -284,8 +251,9 @@ module Mongo
284
251
  # @return [Mongo::GridIO] self
285
252
  def each
286
253
  return read_all unless block_given?
287
- while chunk = read(chunk_size)
254
+ while chunk = read(chunk_size)
288
255
  yield chunk
256
+ break if chunk.empty?
289
257
  end
290
258
  self
291
259
  end
@@ -316,21 +284,18 @@ module Mongo
316
284
  chunk
317
285
  end
318
286
 
319
- def last_chunk_number
320
- (@file_length / @chunk_size).to_i
321
- end
322
-
323
287
  # Read a file in its entirety.
324
288
  def read_all
325
289
  buf = ''
326
290
  if @current_chunk
327
291
  buf << @current_chunk['data'].to_s
328
- while chunk = get_chunk(@current_chunk['n'] + 1)
329
- buf << chunk['data'].to_s
330
- @current_chunk = chunk
292
+ while buf.size < @file_length
293
+ @current_chunk = get_chunk(@current_chunk['n'] + 1)
294
+ break if @current_chunk.nil?
295
+ buf << @current_chunk['data'].to_s
331
296
  end
297
+ @file_position = @file_length
332
298
  end
333
- @file_position = @file_length
334
299
  buf
335
300
  end
336
301
 
@@ -361,6 +326,48 @@ module Mongo
361
326
  buf
362
327
  end
363
328
 
329
+ def read_to_character(character="\n", length=nil)
330
+ result = ''
331
+ len = 0
332
+ while char = getc
333
+ result << char
334
+ len += 1
335
+ break if char == character || (length ? len >= length : false)
336
+ end
337
+ result.length > 0 ? result : nil
338
+ end
339
+
340
+ def read_to_string(string="\n", length=nil)
341
+ result = ''
342
+ len = 0
343
+ match_idx = 0
344
+ match_num = string.length - 1
345
+ to_match = string[match_idx].chr
346
+ if length
347
+ matcher = lambda {|idx, num| idx < num && len < length }
348
+ else
349
+ matcher = lambda {|idx, num| idx < num}
350
+ end
351
+ while matcher.call(match_idx, match_num) && char = getc
352
+ result << char
353
+ len += 1
354
+ if char == to_match
355
+ while match_idx < match_num do
356
+ match_idx += 1
357
+ to_match = string[match_idx].chr
358
+ char = getc
359
+ result << char
360
+ if char != to_match
361
+ match_idx = 0
362
+ to_match = string[match_idx].chr
363
+ break
364
+ end
365
+ end
366
+ end
367
+ end
368
+ result.length > 0 ? result : nil
369
+ end
370
+
364
371
  def cache_chunk_data
365
372
  @current_chunk_data = @current_chunk['data'].to_s
366
373
  if @current_chunk_data.respond_to?(:force_encoding)
@@ -413,6 +420,7 @@ module Mongo
413
420
 
414
421
  # Initialize the class for writing a file.
415
422
  def init_write(opts)
423
+ opts = opts.dup
416
424
  @files_id = opts.delete(:_id) || BSON::ObjectId.new
417
425
  @content_type = opts.delete(:content_type) || (defined? MIME) && get_content_type || DEFAULT_CONTENT_TYPE
418
426
  @chunk_size = opts.delete(:chunk_size) || DEFAULT_CHUNK_SIZE
@@ -455,7 +463,9 @@ module Mongo
455
463
  @server_md5 = @files.db.command(md5_command)['md5']
456
464
  if @safe
457
465
  @client_md5 = @local_md5.hexdigest
458
- if @local_md5 != @server_md5
466
+ if @local_md5 == @server_md5
467
+ @server_md5
468
+ else
459
469
  raise GridMD5Failure, "File on server failed MD5 check"
460
470
  end
461
471
  else