net.http.inflate_by_default.patch

Eric Hodel, 05/25/2012 09:15 AM

Download (7.28 KB)

View differences:

lib/net/http/response.rb (working copy)
275 275

  
276 276
  private
277 277

  
278
  ##
279
  # Checks for a supported Content-Encoding header and returns the Inflate
280
  # wrapper for this response's socket when zlib is present.  If the
281
  # Content-Encoding is unsupported or zlib is missing the plain socket is
282
  # returned.
283

  
284
  def inflater # :nodoc:
285
    return @socket unless Net::HTTP::HAVE_ZLIB
286

  
287
    case self['content-encoding']
288
    when 'deflate', 'gzip', 'x-gzip' then
289
      self.delete 'content-encoding'
290

  
291
      Inflater.new @socket
292
    when 'none', 'identity' then
293
      self.delete 'content-encoding'
294

  
295
      @socket
296
    else
297
      @socket
298
    end
299
  end
300

  
278 301
  def read_body_0(dest)
279 302
    if chunked?
280
      read_chunked dest
303
      read_chunked dest, inflater
281 304
      return
282 305
    end
306

  
307
    @socket = inflater
308

  
283 309
    clen = content_length()
284 310
    if clen
285 311
      @socket.read clen, dest, true   # ignore EOF
......
291 317
      return
292 318
    end
293 319
    @socket.read_all dest
320
  ensure
321
    @socket.finish if Inflater === @socket
294 322
  end
295 323

  
296
  def read_chunked(dest)
324
  def read_chunked(dest, inflater)
297 325
    len = nil
298 326
    total = 0
299 327
    while true
......
303 331
      len = hexlen.hex
304 332
      break if len == 0
305 333
      begin
306
        @socket.read len, dest
334
        inflater.read len, dest
307 335
      ensure
308 336
        total += len
309 337
        @socket.read 2   # \r\n
......
319 347
  end
320 348

  
321 349
  def procdest(dest, block)
322
    raise ArgumentError, 'both arg and block given for HTTP method' \
323
        if dest and block
350
    raise ArgumentError, 'both arg and block given for HTTP method' if
351
      dest and block
324 352
    if block
325 353
      Net::ReadAdapter.new(block)
326 354
    else
......
328 356
    end
329 357
  end
330 358

  
359
  ##
360
  # Inflater is a wrapper around Net::BufferedIO that transparently inflates
361
  # zlib and gzip streams.
362

  
363
  class Inflater # :nodoc:
364

  
365
    ##
366
    # Creates a new Inflater wrapping +socket+
367

  
368
    def initialize socket
369
      @socket = socket
370
      # zlib with automatic gzip detection
371
      @inflate = Zlib::Inflate.new(32 + Zlib::MAX_WBITS)
372
    end
373

  
374
    ##
375
    # Reads +clen+ bytes from the socket, inflates them, then writes them to
376
    # +dest+.  +ignore_eof+ is passed down to Net::BufferedIO#read
377

  
378
    def read clen, dest, ignore_eof = false
379
      temp_dest = ''
380

  
381
      @socket.read clen, temp_dest, ignore_eof
382

  
383
      dest << @inflate.inflate(temp_dest)
384
    end
385

  
386
    ##
387
    # Reads the rest of the socket, inflates it, then writes it to +dest+.
388

  
389
    def read_all dest
390
      temp_dest = ''
391
      
392
      @socket.read_all temp_dest
393

  
394
      dest << @inflate.inflate(temp_dest)
395
    end
396

  
397
    ##
398
    # Finishes the inflate stream.
399

  
400
    def finish
401
      @inflate.finish
402
    end
403

  
404
  end
405

  
331 406
end
332 407

  
lib/net/http.rb (working copy)
590 590
      @use_ssl = false
591 591
      @ssl_context = nil
592 592
      @enable_post_connection_check = true
593
      @compression = nil
594 593
      @sspi_enabled = false
595 594
      SSL_IVNAMES.each do |ivname|
596 595
        instance_variable_set ivname, nil
......
1034 1033
          initheader = initheader.merge({
1035 1034
            "accept-encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
1036 1035
          })
1037
          @compression = true
1038 1036
        end
1039 1037
      end
1040 1038
      request(Get.new(path, initheader)) {|r|
1041
        if r.key?("content-encoding") and @compression
1042
          @compression = nil # Clear it till next set.
1043
          the_body = r.read_body dest, &block
1044
          case r["content-encoding"]
1045
          when "gzip"
1046
            r.body= Zlib::GzipReader.new(StringIO.new(the_body), encoding: "ASCII-8BIT").read
1047
            r.delete("content-encoding")
1048
          when "deflate"
1049
            r.body= Zlib::Inflate.inflate(the_body);
1050
            r.delete("content-encoding")
1051
          when "identity"
1052
            ; # nothing needed
1053
          else
1054
            ; # Don't do anything dramatic, unless we need to later
1055
          end
1056
        else
1057
          r.read_body dest, &block
1058
        end
1039
        r.read_body dest, &block
1059 1040
        res = r
1060 1041
      }
1061 1042
      res
test/net/http/test_httpresponse.rb (working copy)
4 4

  
5 5
class HTTPResponseTest < Test::Unit::TestCase
6 6
  def test_singleline_header
7
    io = dummy_io(<<EOS.gsub(/\n/, "\r\n"))
7
    io = dummy_io(<<EOS)
8 8
HTTP/1.1 200 OK
9 9
Content-Length: 5
10 10
Connection: close
......
17 17
  end
18 18

  
19 19
  def test_multiline_header
20
    io = dummy_io(<<EOS.gsub(/\n/, "\r\n"))
20
    io = dummy_io(<<EOS)
21 21
HTTP/1.1 200 OK
22 22
X-Foo: XXX
23 23
   YYY
......
32 32
    assert_equal('XXX YYY', res.header['x-bar'])
33 33
  end
34 34

  
35
  def test_read_body
36
    io = dummy_io(<<EOS)
37
HTTP/1.1 200 OK
38
Connection: close
39
Content-Length: 5
40

  
41
hello
42
EOS
43

  
44
    res = Net::HTTPResponse.read_new(io)
45

  
46
    body = nil
47

  
48
    res.reading_body io, true do
49
      body = res.read_body
50
    end
51

  
52
    assert_equal 'hello', body
53
  end
54

  
55
  def test_read_body_block
56
    io = dummy_io(<<EOS)
57
HTTP/1.1 200 OK
58
Connection: close
59
Content-Length: 5
60

  
61
hello
62
EOS
63

  
64
    res = Net::HTTPResponse.read_new(io)
65

  
66
    body = ''
67

  
68
    res.reading_body io, true do
69
      res.read_body do |chunk|
70
        body << chunk
71
      end
72
    end
73

  
74
    assert_equal 'hello', body
75
  end
76

  
77
  def test_read_body_content_encoding_deflate
78
    io = dummy_io(<<EOS)
79
HTTP/1.1 200 OK
80
Connection: close
81
Content-Encoding: deflate
82
Content-Length: 13
83

  
84
x\x9C\xCBH\xCD\xC9\xC9\a\x00\x06,\x02\x15
85
EOS
86

  
87
    res = Net::HTTPResponse.read_new(io)
88

  
89
    body = nil
90

  
91
    res.reading_body io, true do
92
      body = res.read_body
93
    end
94

  
95
    assert_equal 'hello', body
96
  end
97

  
98
  def test_read_body_content_encoding_deflate_chunked
99
    io = dummy_io(<<EOS)
100
HTTP/1.1 200 OK
101
Connection: close
102
Content-Encoding: deflate
103
Transfer-Encoding: chunked
104

  
105
6
106
x\x9C\xCBH\xCD\xC9
107
7
108
\xC9\a\x00\x06,\x02\x15
109
0
110

  
111
EOS
112

  
113
    res = Net::HTTPResponse.read_new(io)
114

  
115
    body = nil
116

  
117
    res.reading_body io, true do
118
      body = res.read_body
119
    end
120

  
121
    assert_equal 'hello', body
122
  end
123

  
124
  def test_read_body_content_encoding_deflate_no_length
125
    io = dummy_io(<<EOS)
126
HTTP/1.1 200 OK
127
Connection: close
128
Content-Encoding: deflate
129

  
130
x\x9C\xCBH\xCD\xC9\xC9\a\x00\x06,\x02\x15
131
EOS
132

  
133
    res = Net::HTTPResponse.read_new(io)
134

  
135
    body = nil
136

  
137
    res.reading_body io, true do
138
      body = res.read_body
139
    end
140

  
141
    assert_equal 'hello', body
142
  end
143

  
144
  def test_read_body_string
145
    io = dummy_io(<<EOS)
146
HTTP/1.1 200 OK
147
Connection: close
148
Content-Length: 5
149

  
150
hello
151
EOS
152

  
153
    res = Net::HTTPResponse.read_new(io)
154

  
155
    body = ''
156

  
157
    res.reading_body io, true do
158
      res.read_body body
159
    end
160

  
161
    assert_equal 'hello', body
162
  end
163

  
35 164
private
36 165

  
37 166
  def dummy_io(str)
167
    str = str.gsub(/\n/, "\r\n")
168

  
38 169
    Net::BufferedIO.new(StringIO.new(str))
39 170
  end
40 171
end