<p>It seems like the methods of Ruby's Net::HTTP are all or nothing when it comes to reading the body of a web page. How can I read, say, the just the first 100 bytes of the body? </p>

<p>I am trying to read from a content server that returns a short error message in the body of the response if the file requested isn't available. I need to read enough of the body to determine whether the file is there. The files are huge, so I don't want to get the whole body just to check if the file is available.</p>

[{'answer_id': 82564, 'author': 'user9385', 'author_id': 9385, 'author_profile': 'https://Stackoverflow.com/users/9385', 'pm_score': -1, 'selected': False, 'text': "<p>You can't.  But why do you need to?  Surely if the page just says that the file isn't available then it won't be a huge page (i.e. by definition, the file won't be there)?</p>\n"}, {'answer_id': 82579, 'author': 'Jean', 'author_id': 7898, 'author_profile': 'https://Stackoverflow.com/users/7898', 'pm_score': 2, 'selected': False, 'text': "<p>Are you sure the content server only returns a short error page?</p>\n\n<p>Doesn't it also set the <code>HTTPResponse</code> to something appropriate like 404. In which case you can trap the <code>HTTPClientError</code> derived exception (most likely <code>HTTPNotFound</code>) which is raised when accessing <code>Net::HTTP.value()</code>. </p>\n\n<p>If you get an error then your file wasn't there if you get 200 the file is starting to download and you can close the connection.</p>\n"}, {'answer_id': 82663, 'author': 'Nathan de Vries', 'author_id': 11109, 'author_profile': 'https://Stackoverflow.com/users/11109', 'pm_score': 2, 'selected': False, 'text': "<p>To read the body of an HTTP request in chunks, you'll need to use <code>Net::HTTPResponse#read_body</code> like this:</p>\n\n<pre><code>http.request_get('/large_resource') do |response|\n  response.read_body do |segment|\n    print segment\n  end\nend\n</code></pre>\n"}, {'answer_id': 82711, 'author': 'Ian Dickinson', 'author_id': 6716, 'author_profile': 'https://Stackoverflow.com/users/6716', 'pm_score': 4, 'selected': False, 'text': '<p>Shouldn\'t you just use an HTTP <code>HEAD</code> request (Ruby <code>Net::HTTP::Head</code> method) to see if the resource is there, and only proceed if you get a 2xx or 3xx response? This presumes your server is configured to return a 4xx error code if the document is not available. I would argue this was the correct solution. </p>\n\n<p>An alternative is to request the HTTP head and look at the <code>content-length</code> header value in the result: if your server is correctly configured, you should easily be able to tell the difference in length between a short message and a long document. Another alternative: set the <code>content-range</code> header field in the request (which again assumes that the server is behaving correctly WRT the HTTP spec).</p>\n\n<p>I don\'t think that solving the problem in the client <em>after</em> you\'ve sent the GET request is the way to go: by that time, the network has done the heavy lifting, and you won\'t really save any wasted resources.</p>\n\n<p>Reference: <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html" rel="nofollow noreferrer" title="http method headers">http header definitions</a></p>\n'}, {'answer_id': 84008, 'author': 'Roman', 'author_id': 12695, 'author_profile': 'https://Stackoverflow.com/users/12695', 'pm_score': 2, 'selected': False, 'text': '<p>I wanted to do this once, and the only thing that I could think of is monkey patching the <code>Net::HTTP#read_body</code> and <code>Net::HTTP#read_body_0</code> methods to accept a length parameter, and then in the former just pass the length parameter to the <code>read_body_0</code> method, where you can read only as much as length bytes.</p>\n'}, {'answer_id': 8597488, 'author': 'Dustin Frazier', 'author_id': 1072414, 'author_profile': 'https://Stackoverflow.com/users/1072414', 'pm_score': 4, 'selected': False, 'text': '<p>This is an old thread, but the question of how to read only a portion of a file via HTTP in Ruby is still a mostly unanswered one according to my research. Here\'s a solution I came up with by monkey-patching Net::HTTP a bit:</p>\n\n<pre><code>require \'net/http\'\n\n# provide access to the actual socket\nclass Net::HTTPResponse\n  attr_reader :socket\nend\n\nuri = URI("http://www.example.com/path/to/file")\nbegin\n  Net::HTTP.start(uri.host, uri.port) do |http|\n    request = Net::HTTP::Get.new(uri.request_uri)\n    # calling request with a block prevents body from being read\n    http.request(request) do |response|\n      # do whatever limited reading you want to do with the socket\n      x = response.socket.read(100);\n      # be sure to call finish before exiting the block\n      http.finish\n    end\n  end\nrescue IOError\n  # ignore\nend\n</code></pre>\n\n<p>The rescue catches the IOError that\'s thrown when you call HTTP.finish prematurely.</p>\n\n<p>FYI, the socket within the <code>HTTPResponse</code> object isn\'t a true <code>IO</code> object (it\'s an internal class called <code>BufferedIO</code>), but it\'s pretty easy to monkey-patch that, too, to mimic the <code>IO</code> methods you need. For example, another library I was using (exifr) needed the <code>readchar</code> method, which was easy to add:</p>\n\n<pre><code>class Net::BufferedIO\n  def readchar\n    read(1)[0].ord\n  end\nend\n</code></pre>\n'}]
['https://Stackoverflow.com/questions/82349', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/3298/']