Class: ConnectionTester

Inherits:
Object
  • Object
show all
Includes:
Diaspora::Logging
Defined in:
lib/connection_tester.rb

Defined Under Namespace

Classes: AddressFailure, DNSFailure, Failure, HTTPFailure, NetFailure, NodeInfoFailure, Result, SSLFailure

Constant Summary collapse

NODEINFO_SCHEMA =
"http://nodeinfo.diaspora.software/ns/schema/1.0"
NODEINFO_FRAGMENT =
"/.well-known/nodeinfo"

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(url, result = Result.new) ⇒ ConnectionTester

Returns a new instance of ConnectionTester.

Raises:


70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/connection_tester.rb', line 70

def initialize(url, result=Result.new)
  @url ||= url
  @result ||= result
  @uri ||= URI.parse(@url)
  raise AddressFailure,
        "invalid protocol: '#{@uri.scheme.upcase}'" unless http_uri?(@uri)
rescue AddressFailure => e
  raise e
rescue URI::InvalidURIError => e
  raise AddressFailure, e.message
rescue StandardError => e
  unexpected_error(e)
end

Class Method Details

.check(url) ⇒ Result

Test the reachability of a server by the given HTTP/S URL. In the first step, a DNS query is performed to check whether the given name even resolves correctly. The second step is to send a HTTP request and look at the returned status code or any returned errors. This function isn't intended to check for the availability of a specific page, instead a GET request is sent to the root directory of the server. In the third step an attempt is made to determine the software version used on the server, via the nodeinfo page.

Parameters:

Returns:

  • (Result)

    result object containing information about the server and to what point the connection was successful


27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/connection_tester.rb', line 27

def check(url)
  result = Result.new

  begin
    ct = ConnectionTester.new(url, result)

    # test DNS resolving
    ct.resolve

    # test HTTP request
    ct.request

    # test for the diaspora* version
    ct.nodeinfo

  rescue Failure => e
    result_from_failure(result, e)
  end

  result.freeze
end

Instance Method Details

#nodeinfoObject

Try to find out the version of the other servers software. Assuming the server speaks nodeinfo

Raises:

  • (NodeInfoFailure)

    if the document can't be fetched or the attempt to parse it failed


128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/connection_tester.rb', line 128

def nodeinfo
  with_http_connection do |http|
    ni_resp = http.get(NODEINFO_FRAGMENT)
    nd_resp = http.get(find_nodeinfo_url(ni_resp.body))
    find_software_version(nd_resp.body)
  end
rescue NodeInfoFailure => e
  raise e
rescue JSON::Schema::ValidationError, JSON::Schema::SchemaError => e
  raise NodeInfoFailure, "#{e.class}: #{e.message}"
rescue Faraday::ResourceNotFound, JSON::JSONError => e
  raise NodeInfoFailure, e.message[0..255].encode(Encoding.default_external, undef: :replace)
rescue StandardError => e
  unexpected_error(e)
end

#requestInteger

Perform a HTTP GET request to determine the following information

  • is the host reachable

  • is port 80/443 open

  • is the SSL certificate valid (only on HTTPS)

  • does the server return a successful HTTP status code

  • is there a reasonable amount of redirects (3 by default)

  • is there a /.well-known/host-meta (this is needed to work, this can be replaced with a mandatory NodeInfo later)

(can't do a HEAD request, since that's not a defined route in the app)

Returns:

  • (Integer)

    HTTP status code

Raises:


105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/connection_tester.rb', line 105

def request
  with_http_connection do |http|
    capture_response_time { http.get("/") }
    response = http.get("/.well-known/host-meta")
    handle_http_response(response)
  end
rescue HTTPFailure => e
  raise e
rescue Faraday::ConnectionFailed, Faraday::TimeoutError => e
  raise NetFailure, e.message
rescue Faraday::SSLError => e
  raise SSLFailure, e.message
rescue ArgumentError, FaradayMiddleware::RedirectLimitReached, Faraday::ClientError => e
  raise HTTPFailure, e.message
rescue StandardError => e
  unexpected_error(e)
end

#resolveObject

Perform the DNS query, the IP address will be stored in the result

Raises:

  • (DNSFailure)

    caused by a failure to resolve or a timeout


86
87
88
89
90
91
92
# File 'lib/connection_tester.rb', line 86

def resolve
  @result.ip = IPSocket.getaddress(@uri.host)
rescue SocketError => e
  raise DNSFailure, "'#{@uri.host}' - #{e.message}"
rescue StandardError => e
  unexpected_error(e)
end