Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/anemone/http.rb
Views: 11766
require 'net/https'1require 'anemone/page'2require 'anemone/cookie_store'34module Anemone5class HTTP6# Maximum number of redirects to follow on each get_response7REDIRECT_LIMIT = 589# CookieStore for this HTTP client10attr_reader :cookie_store1112def initialize(opts = {})13@connections = {}14@opts = opts15@cookie_store = CookieStore.new(@opts[:cookies])16end1718#19# Fetch a single Page from the response of an HTTP request to *url*.20# Just gets the final destination page.21#22def fetch_page(url, referer = nil, depth = nil)23fetch_pages(url, referer, depth).last24end2526#27# Create new Pages from the response of an HTTP request to *url*,28# including redirects29#30def fetch_pages(url, referer = nil, depth = nil)31begin32url = URI(url) unless url.is_a?(URI)33pages = []34get(url, referer) do |response, code, location, redirect_to, response_time|35pages << Page.new(location, :body => response.body.dup,36:code => code,37:headers => response.to_hash,38:referer => referer,39:depth => depth,40:redirect_to => redirect_to,41:response_time => response_time)42end4344return pages45rescue => e46if verbose?47puts e.inspect48puts e.backtrace49end50return [Page.new(url, :error => e)]51end52end5354#55# The maximum number of redirects to follow56#57def redirect_limit58@opts[:redirect_limit] || REDIRECT_LIMIT59end6061#62# The user-agent string which will be sent with each request,63# or nil if no such option is set64#65def user_agent66@opts[:user_agent]67end6869#70# Does this HTTP client accept cookies from the server?71#72def accept_cookies?73@opts[:accept_cookies]74end7576private7778#79# Retrieve HTTP responses for *url*, including redirects.80# Yields the response object, response code, and URI location81# for each response.82#83def get(url, referer = nil)84limit = redirect_limit85loc = url86begin87# if redirected to a relative url, merge it with the host of the original88# request url89loc = url.merge(loc) if loc.relative?9091response, response_time = get_response(loc, referer)92code = Integer(response.code)93redirect_to = response.is_a?(Net::HTTPRedirection) ? URI(response['location']).normalize : nil94yield response, code, loc, redirect_to, response_time95limit -= 196end while (loc = redirect_to) && allowed?(redirect_to, url) && limit > 097end9899#100# Get an HTTPResponse for *url*, sending the appropriate User-Agent string101#102# MODIFIED: Change get_response to allow fine tuning of the HTTP request before103# it is sent to the remote system.104#105def get_response(url, referer = nil)106full_path = url.query.nil? ? url.path : "#{url.path}?#{url.query}"107108opts = {}109opts['User-Agent'] = user_agent if user_agent110opts['Referer'] = referer.to_s if referer111opts['Cookie'] = @cookie_store.to_s unless @cookie_store.empty? || (!accept_cookies? && @opts[:cookies].nil?)112113if @opts[:http_basic_auth]114opts['Authorization'] = "Basic " + @opts[:http_basic_auth]115end116117if not @opts[:inject_headers].nil?118@opts[:inject_headers].each do |hdr|119k,v = hdr.split(':', 2)120opts[k] = v121end122end123124retries = 0125begin126start = Time.now()127response = nil128if @opts[:request_factory]129response = @opts[:request_factory].call(connection(url), full_path, opts)130else131response = connection(url).get(full_path, opts)132end133finish = Time.now()134response_time = ((finish - start) * 1000).round135@cookie_store.merge!(response['Set-Cookie']) if accept_cookies?136return response, response_time137rescue EOFError138refresh_connection(url)139retries += 1140retry unless retries > (@opts[:retry_limit] || 3)141end142end143144def connection(url)145@connections[url.host] ||= {}146147if conn = @connections[url.host][url.port]148return conn149end150151refresh_connection url152end153154#155# MODIFIED: Change refresh_connection to allow a HTTP factory to be used to156# create the Net::HTTP object. This allows much more granular157# control over the requests.158#159def refresh_connection(url)160http = nil161if @opts[:http_factory]162http = @opts[:http_factory].call(url)163else164http = Net::HTTP.new(url.host, url.port)165if url.scheme == 'https'166http.use_ssl = true167http.verify_mode = OpenSSL::SSL::VERIFY_NONE168end169end170@connections[url.host][url.port] = http.start171end172173def verbose?174@opts[:verbose]175end176177#178# Allowed to connect to the requested url?179#180def allowed?(to_url, from_url)181to_url.host.nil? || (to_url.host == from_url.host)182end183184end185end186187188