ronin-support-web 0.1.0.rc1
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.
- checksums.yaml +7 -0
- data/.document +4 -0
- data/.github/workflows/ruby.yml +47 -0
- data/.gitignore +13 -0
- data/.rspec +1 -0
- data/.rubocop.yml +19 -0
- data/.ruby-version +1 -0
- data/.yardopts +1 -0
- data/COPYING.txt +165 -0
- data/ChangeLog.md +10 -0
- data/Gemfile +36 -0
- data/README.md +321 -0
- data/Rakefile +31 -0
- data/gemspec.yml +31 -0
- data/lib/ronin/support/web/agent/mixin.rb +361 -0
- data/lib/ronin/support/web/agent.rb +1386 -0
- data/lib/ronin/support/web/html/mixin.rb +115 -0
- data/lib/ronin/support/web/html.rb +116 -0
- data/lib/ronin/support/web/mixin.rb +40 -0
- data/lib/ronin/support/web/version.rb +28 -0
- data/lib/ronin/support/web/websocket/client.rb +129 -0
- data/lib/ronin/support/web/websocket/mixin.rb +888 -0
- data/lib/ronin/support/web/websocket/server.rb +212 -0
- data/lib/ronin/support/web/websocket/socket.rb +185 -0
- data/lib/ronin/support/web/websocket/url_methods.rb +91 -0
- data/lib/ronin/support/web/websocket.rb +360 -0
- data/lib/ronin/support/web/xml/mixin.rb +111 -0
- data/lib/ronin/support/web/xml.rb +110 -0
- data/lib/ronin/support/web.rb +43 -0
- data/ronin-support-web.gemspec +62 -0
- metadata +150 -0
@@ -0,0 +1,1386 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-support-web - A web support library for ronin-rb.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2023-2024 Hal Brodigan (postmodern.mod3@gmail.com)
|
6
|
+
#
|
7
|
+
# ronin-support-web is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# ronin-support-web is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with ronin-support-web. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'ronin/support/network/http'
|
22
|
+
|
23
|
+
require 'addressable/uri'
|
24
|
+
require 'nokogiri'
|
25
|
+
require 'json'
|
26
|
+
|
27
|
+
module Ronin
|
28
|
+
module Support
|
29
|
+
module Web
|
30
|
+
#
|
31
|
+
# Web Agent represents a stripped-down web browser, which can request
|
32
|
+
# URLs, follow redirects, and parse responses.
|
33
|
+
#
|
34
|
+
# ## Features
|
35
|
+
#
|
36
|
+
# * Automatically follows redirects.
|
37
|
+
# * Provides low-level HTTP methods.
|
38
|
+
# * Provides high-level methods for requesting and parsing HTML, XML, or
|
39
|
+
# JSON.
|
40
|
+
# * Maintains a persistent connection pool.
|
41
|
+
#
|
42
|
+
# ## Anti-Features
|
43
|
+
#
|
44
|
+
# * Does not cache files or write to the disk.
|
45
|
+
# * Does not evaluate JavaScript.
|
46
|
+
#
|
47
|
+
class Agent
|
48
|
+
|
49
|
+
#
|
50
|
+
# Base-class for all {Agent} exceptions.
|
51
|
+
#
|
52
|
+
class Error < RuntimeError
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Indicates that too many redirects were encountered in succession.
|
57
|
+
#
|
58
|
+
class TooManyRedirects < Error
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Indicates that the response does not have a compatible or expected
|
63
|
+
# `Content-Type` header.
|
64
|
+
#
|
65
|
+
class ContentTypeError < Error
|
66
|
+
end
|
67
|
+
|
68
|
+
# The proxy to send requests through.
|
69
|
+
#
|
70
|
+
# @return [URI::HTTP, Addressable::URI, nil]
|
71
|
+
attr_reader :proxy
|
72
|
+
|
73
|
+
# The `User-Agent` header value.
|
74
|
+
#
|
75
|
+
# @return [String, nil]
|
76
|
+
attr_reader :user_agent
|
77
|
+
|
78
|
+
# Maximum number of redirects to follow.
|
79
|
+
#
|
80
|
+
# @return [Integer]
|
81
|
+
attr_reader :max_redirects
|
82
|
+
|
83
|
+
#
|
84
|
+
# Initializes the Web agent.
|
85
|
+
#
|
86
|
+
# @param [String, URI::HTTP, Addressable::URI, nil] proxy
|
87
|
+
# The optional proxy to send requests through.
|
88
|
+
#
|
89
|
+
# @param [String, :random, :chrome, :chrome_linux, :chrome_macos, :chrome_windows, :chrome_iphone, :chrome_ipad, :chrome_android, :firefox, :firefox_linux, :firefox_macos, :firefox_windows, :firefox_iphone, :firefox_ipad, :firefox_android, :safari, :safari_macos, :safari_iphone, :safari_ipad, :edge, :linux, :macos, :windows, :iphone, :ipad, :android, nil] user_agent
|
90
|
+
# The default `User-Agent` string to add to each request.
|
91
|
+
#
|
92
|
+
# @param [Boolean, Hash{Symbol => Object}, nil] ssl
|
93
|
+
# Additional SSL/TLS configuration.
|
94
|
+
#
|
95
|
+
# @option ssl [String, nil] :ca_bundle
|
96
|
+
# The path to the CA bundle directory or file.
|
97
|
+
#
|
98
|
+
# @option ssl [OpenSSL::X509::Store, nil] :cert_store
|
99
|
+
# The certificate store to use for the SSL/TLS connection.
|
100
|
+
#
|
101
|
+
# @option ssl [Array<(name, version, bits, alg_bits)>, nil] :ciphers
|
102
|
+
# The accepted ciphers to use for the SSL/TLS connection.
|
103
|
+
#
|
104
|
+
# @option ssl [Integer, nil] :timeout
|
105
|
+
# The connection timeout limit.
|
106
|
+
#
|
107
|
+
# @option ssl [1, 1.1, 1.2, Symbol, nil] :version
|
108
|
+
# The desired SSL/TLS version.
|
109
|
+
#
|
110
|
+
# @option ssl [1, 1.1, 1.2, Symbol, nil] :min_version
|
111
|
+
# The minimum SSL/TLS version.
|
112
|
+
#
|
113
|
+
# @option ssl [1, 1.1, 1.2, Symbol, nil] :max_version
|
114
|
+
# The maximum SSL/TLS version.
|
115
|
+
#
|
116
|
+
# @option ssl [Proc, nil] :verify_callback
|
117
|
+
# The callback to use when verifying the server's certificate.
|
118
|
+
#
|
119
|
+
# @option ssl [Integer, nil] :verify_depth
|
120
|
+
# The verification depth limit.
|
121
|
+
#
|
122
|
+
# @option ssl [:none, :peer, :fail_if_no_peer_cert, true, false, Integer, nil] :verify
|
123
|
+
# The verification mode.
|
124
|
+
#
|
125
|
+
# @option ssl [Boolean, nil] :verify_hostname
|
126
|
+
# Indicates whether to verify the server's hostname.
|
127
|
+
#
|
128
|
+
def initialize(follow_redirects: true,
|
129
|
+
max_redirects: 20,
|
130
|
+
# HTTP options
|
131
|
+
proxy: Support::Network::HTTP.proxy,
|
132
|
+
ssl: nil,
|
133
|
+
user_agent: Support::Network::HTTP.user_agent)
|
134
|
+
@follow_redirects = follow_redirects
|
135
|
+
@max_redirects = max_redirects
|
136
|
+
|
137
|
+
# HTTP options
|
138
|
+
@proxy = proxy
|
139
|
+
@ssl = ssl
|
140
|
+
@user_agent = user_agent
|
141
|
+
|
142
|
+
@sessions = {}
|
143
|
+
end
|
144
|
+
|
145
|
+
#
|
146
|
+
# Indicates whether redirects will automatically be followed.
|
147
|
+
#
|
148
|
+
# @return [Boolean]
|
149
|
+
#
|
150
|
+
def follow_redirects?
|
151
|
+
@follow_redirects
|
152
|
+
end
|
153
|
+
|
154
|
+
#
|
155
|
+
# @!macro request_kwargs
|
156
|
+
# @option kwargs [String, nil] :query
|
157
|
+
# The query-string to append to the request path.
|
158
|
+
#
|
159
|
+
# @option kwargs [Hash, nil] :query_params
|
160
|
+
# The query-params to append to the request path.
|
161
|
+
#
|
162
|
+
# @option kwargs [String, nil] :user
|
163
|
+
# The user to authenticate as.
|
164
|
+
#
|
165
|
+
# @option kwargs [String, nil] :password
|
166
|
+
# The password to authenticate with.
|
167
|
+
#
|
168
|
+
# @option kwargs [Hash{Symbol,String => String}, nil] :headers
|
169
|
+
# Additional HTTP headers to use for the request.
|
170
|
+
#
|
171
|
+
# @option kwargs [String, :text, :xml, :html, :json, nil] :content_type
|
172
|
+
# The `Content-Type` header value for the request.
|
173
|
+
# If a Symbol is given it will be resolved to a common MIME type:
|
174
|
+
# * `:text` - `text/plain`
|
175
|
+
# * `:xml` - `text/xml`
|
176
|
+
# * `:html` - `text/html`
|
177
|
+
# * `:json` - `application/json`
|
178
|
+
#
|
179
|
+
# @option kwargs [String, :text, :xml, :html, :json, nil] :accept
|
180
|
+
# The `Accept` header value for the request.
|
181
|
+
# If a Symbol is given it will be resolved to a common MIME type:
|
182
|
+
# * `:text` - `text/plain`
|
183
|
+
# * `:xml` - `text/xml`
|
184
|
+
# * `:html` - `text/html`
|
185
|
+
# * `:json` - `application/json`
|
186
|
+
#
|
187
|
+
# @option kwargs [String, Hash{String => String}, Ronin::Support::Network::HTTP::Cookie, nil] :cookie
|
188
|
+
# Additional `Cookie` header.
|
189
|
+
# * If a `Hash` is given, it will be converted to a `String` using
|
190
|
+
# [Ronin::Support::Network::HTTP::Cookie](https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP/Cookie.html).
|
191
|
+
# * If the cookie value is empty, the `Cookie` header will not be
|
192
|
+
# set.
|
193
|
+
#
|
194
|
+
# @option kwargs [String, nil] :body
|
195
|
+
# The body of the request.
|
196
|
+
#
|
197
|
+
# @option kwargs [Hash, String, nil] :form_data
|
198
|
+
# The form data that may be sent in the body of the request.
|
199
|
+
#
|
200
|
+
# @option kwargs [#to_json, nil] :json
|
201
|
+
# The JSON data that will be sent in the body of the request.
|
202
|
+
# Will also default the `Content-Type` header to
|
203
|
+
# `application/json`, unless already set.
|
204
|
+
#
|
205
|
+
|
206
|
+
#
|
207
|
+
# Performs and arbitrary HTTP request.
|
208
|
+
#
|
209
|
+
# @param [Symbol, String] method
|
210
|
+
# The HTTP method to use for the request.
|
211
|
+
#
|
212
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
213
|
+
# The URL to create the HTTP request for.
|
214
|
+
#
|
215
|
+
# @!macro request_kwargs
|
216
|
+
#
|
217
|
+
# @yield [response]
|
218
|
+
# If a block is given it will be passed the received HTTP response.
|
219
|
+
#
|
220
|
+
# @yieldparam [Net::HTTPResponse] response
|
221
|
+
# The received HTTP response object.
|
222
|
+
#
|
223
|
+
# @return [Net::HTTPResponse]
|
224
|
+
# The HTTP response object.
|
225
|
+
#
|
226
|
+
# @raise [ArgumentError]
|
227
|
+
# The `:method` option did not match a known `Net::HTTP` request
|
228
|
+
# class.
|
229
|
+
#
|
230
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#request-instance_method
|
231
|
+
#
|
232
|
+
# @api public
|
233
|
+
#
|
234
|
+
def http_request(method,url,**kwargs,&block)
|
235
|
+
uri = normalize_url(url)
|
236
|
+
|
237
|
+
session_for(uri).request(
|
238
|
+
method, uri.request_uri, user: uri.user,
|
239
|
+
password: uri.password,
|
240
|
+
**kwargs, &block
|
241
|
+
)
|
242
|
+
end
|
243
|
+
|
244
|
+
#
|
245
|
+
# Sends an arbitrary HTTP request and returns the response status.
|
246
|
+
#
|
247
|
+
# @param [Symbol, String] method
|
248
|
+
# The HTTP method to use for the request.
|
249
|
+
#
|
250
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
251
|
+
# The URL to create the HTTP request for.
|
252
|
+
#
|
253
|
+
# @!macro request_kwargs
|
254
|
+
#
|
255
|
+
# @return [Integer]
|
256
|
+
# The status code of the response.
|
257
|
+
#
|
258
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#response_status-instance_method
|
259
|
+
#
|
260
|
+
# @api public
|
261
|
+
#
|
262
|
+
def http_response_status(method=:head,url,**kwargs)
|
263
|
+
uri = normalize_url(url)
|
264
|
+
|
265
|
+
session_for(uri).response_status(
|
266
|
+
method, uri.request_uri, user: uri.user,
|
267
|
+
password: uri.password,
|
268
|
+
**kwargs
|
269
|
+
)
|
270
|
+
end
|
271
|
+
|
272
|
+
#
|
273
|
+
# Sends a HTTP request and determines if the response status was 200.
|
274
|
+
#
|
275
|
+
# @param [Symbol, String] method
|
276
|
+
# The HTTP method to use for the request.
|
277
|
+
#
|
278
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
279
|
+
# The URL to create the HTTP request for.
|
280
|
+
#
|
281
|
+
# @!macro request_kwargs
|
282
|
+
#
|
283
|
+
# @return [Boolean]
|
284
|
+
# Indicates that the response status was 200.
|
285
|
+
#
|
286
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#ok%3F-instance_method
|
287
|
+
#
|
288
|
+
# @api public
|
289
|
+
#
|
290
|
+
def http_ok?(method=:head,url,**kwargs)
|
291
|
+
uri = normalize_url(url)
|
292
|
+
|
293
|
+
session_for(uri).ok?(
|
294
|
+
method, uri.request_uri, user: uri.user,
|
295
|
+
password: uri.password,
|
296
|
+
**kwargs
|
297
|
+
)
|
298
|
+
end
|
299
|
+
|
300
|
+
#
|
301
|
+
# Sends an arbitrary HTTP request and returns the response headers.
|
302
|
+
#
|
303
|
+
# @param [Symbol, String] method
|
304
|
+
# The HTTP method to use for the request.
|
305
|
+
#
|
306
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
307
|
+
# The URL to create the HTTP request for.
|
308
|
+
#
|
309
|
+
# @!macro request_kwargs
|
310
|
+
#
|
311
|
+
# @return [Hash{String => String}]
|
312
|
+
# The response headers.
|
313
|
+
#
|
314
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#response_headers-instance_method
|
315
|
+
#
|
316
|
+
# @api public
|
317
|
+
#
|
318
|
+
def http_response_headers(method=:head,url,**kwargs)
|
319
|
+
uri = normalize_url(url)
|
320
|
+
|
321
|
+
session_for(uri).response_headers(
|
322
|
+
method, uri.request_uri, user: uri.user,
|
323
|
+
password: uri.password,
|
324
|
+
**kwargs
|
325
|
+
)
|
326
|
+
end
|
327
|
+
|
328
|
+
#
|
329
|
+
# Sends an HTTP request and returns the `Server` header.
|
330
|
+
#
|
331
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
332
|
+
# The URL to create the HTTP request for.
|
333
|
+
#
|
334
|
+
# @!macro request_kwargs
|
335
|
+
#
|
336
|
+
# @return [String, nil]
|
337
|
+
# The `Server` header.
|
338
|
+
#
|
339
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#server_header-instance_method
|
340
|
+
#
|
341
|
+
# @api public
|
342
|
+
#
|
343
|
+
def http_server_header(url,**kwargs)
|
344
|
+
uri = normalize_url(url)
|
345
|
+
|
346
|
+
session_for(uri).server_header(
|
347
|
+
user: uri.user,
|
348
|
+
password: uri.password,
|
349
|
+
path: uri.request_uri,
|
350
|
+
**kwargs
|
351
|
+
)
|
352
|
+
end
|
353
|
+
|
354
|
+
#
|
355
|
+
# Sends an HTTP request and returns the `X-Powered-By` header.
|
356
|
+
#
|
357
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
358
|
+
# The URL to create the HTTP request for.
|
359
|
+
#
|
360
|
+
# @!macro request_kwargs
|
361
|
+
#
|
362
|
+
# @return [String, nil]
|
363
|
+
# The `X-Powered-By` header.
|
364
|
+
#
|
365
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#powered_by_header-instance_method
|
366
|
+
#
|
367
|
+
# @api public
|
368
|
+
#
|
369
|
+
def http_powered_by_header(url,**kwargs)
|
370
|
+
uri = normalize_url(url)
|
371
|
+
|
372
|
+
session_for(uri).powered_by_header(
|
373
|
+
user: uri.user,
|
374
|
+
password: uri.password,
|
375
|
+
path: uri.request_uri,
|
376
|
+
**kwargs
|
377
|
+
)
|
378
|
+
end
|
379
|
+
|
380
|
+
#
|
381
|
+
# Sends an arbitrary HTTP request and returns the response body.
|
382
|
+
#
|
383
|
+
# @param [Symbol, String] method
|
384
|
+
# The HTTP method to use for the request.
|
385
|
+
#
|
386
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
387
|
+
# The URL to create the HTTP request for.
|
388
|
+
#
|
389
|
+
# @!macro request_kwargs
|
390
|
+
#
|
391
|
+
# @return [String]
|
392
|
+
# The response body.
|
393
|
+
#
|
394
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#response_body-instance_method
|
395
|
+
#
|
396
|
+
# @api public
|
397
|
+
#
|
398
|
+
def http_response_body(method=:get,url,**kwargs)
|
399
|
+
uri = normalize_url(url)
|
400
|
+
|
401
|
+
session_for(uri).response_body(
|
402
|
+
method, uri.request_uri, user: uri.user,
|
403
|
+
password: uri.password,
|
404
|
+
**kwargs
|
405
|
+
)
|
406
|
+
end
|
407
|
+
|
408
|
+
#
|
409
|
+
# Performs a `COPY` request for the given URI.
|
410
|
+
#
|
411
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
412
|
+
# The URL to create the HTTP request for.
|
413
|
+
#
|
414
|
+
# @!macro request_kwargs
|
415
|
+
#
|
416
|
+
# @yield [response]
|
417
|
+
# If a block is given it will be passed the received HTTP response.
|
418
|
+
#
|
419
|
+
# @yieldparam [Net::HTTPResponse] response
|
420
|
+
# The received HTTP response object.
|
421
|
+
#
|
422
|
+
# @return [Net::HTTPResponse]
|
423
|
+
# The HTTP response object.
|
424
|
+
#
|
425
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#copy-instance_method
|
426
|
+
#
|
427
|
+
# @api public
|
428
|
+
#
|
429
|
+
def http_copy(url,**kwargs,&block)
|
430
|
+
uri = normalize_url(url)
|
431
|
+
|
432
|
+
session_for(uri).copy(
|
433
|
+
uri.request_uri, user: uri.user,
|
434
|
+
password: uri.password,
|
435
|
+
**kwargs, &block
|
436
|
+
)
|
437
|
+
end
|
438
|
+
|
439
|
+
#
|
440
|
+
# Performs a `DELETE` request for the given URI.
|
441
|
+
#
|
442
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
443
|
+
# The URL to create the HTTP request for.
|
444
|
+
#
|
445
|
+
# @!macro request_kwargs
|
446
|
+
#
|
447
|
+
# @yield [response]
|
448
|
+
# If a block is given it will be passed the received HTTP response.
|
449
|
+
#
|
450
|
+
# @yieldparam [Net::HTTPResponse] response
|
451
|
+
# The received HTTP response object.
|
452
|
+
#
|
453
|
+
# @return [Net::HTTPResponse]
|
454
|
+
# The HTTP response object.
|
455
|
+
#
|
456
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#delete-instance_method
|
457
|
+
#
|
458
|
+
# @api public
|
459
|
+
#
|
460
|
+
def http_delete(url,**kwargs,&block)
|
461
|
+
uri = normalize_url(url)
|
462
|
+
|
463
|
+
session_for(uri).delete(
|
464
|
+
uri.request_uri, user: uri.user,
|
465
|
+
password: uri.password,
|
466
|
+
**kwargs, &block
|
467
|
+
)
|
468
|
+
end
|
469
|
+
|
470
|
+
#
|
471
|
+
# Performs a `GET` request for the given URI.
|
472
|
+
#
|
473
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
474
|
+
# The URL to create the HTTP request for.
|
475
|
+
#
|
476
|
+
# @!macro request_kwargs
|
477
|
+
#
|
478
|
+
# @yield [response]
|
479
|
+
# If a block is given it will be passed the received HTTP response.
|
480
|
+
#
|
481
|
+
# @yieldparam [Net::HTTPResponse] response
|
482
|
+
# The received HTTP response object.
|
483
|
+
#
|
484
|
+
# @return [Net::HTTPResponse]
|
485
|
+
# The HTTP response object.
|
486
|
+
#
|
487
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#get-instance_method
|
488
|
+
#
|
489
|
+
# @api public
|
490
|
+
#
|
491
|
+
def http_get(url,**kwargs,&block)
|
492
|
+
uri = normalize_url(url)
|
493
|
+
|
494
|
+
session_for(uri).get(
|
495
|
+
uri.request_uri, user: uri.user,
|
496
|
+
password: uri.password,
|
497
|
+
**kwargs, &block
|
498
|
+
)
|
499
|
+
end
|
500
|
+
|
501
|
+
#
|
502
|
+
# Performs a `GET` request for the given URI and returns the response
|
503
|
+
# headers.
|
504
|
+
#
|
505
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
506
|
+
# The URL to create the HTTP request for.
|
507
|
+
#
|
508
|
+
# @!macro request_kwargs
|
509
|
+
#
|
510
|
+
# @return [Hash{String => String}]
|
511
|
+
# The response headers.
|
512
|
+
#
|
513
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#get_headers-instance_method
|
514
|
+
#
|
515
|
+
# @api public
|
516
|
+
#
|
517
|
+
def http_get_headers(url,**kwargs)
|
518
|
+
uri = normalize_url(url)
|
519
|
+
|
520
|
+
session_for(uri).get_headers(
|
521
|
+
uri.request_uri, user: uri.user,
|
522
|
+
password: uri.password,
|
523
|
+
**kwargs
|
524
|
+
)
|
525
|
+
end
|
526
|
+
|
527
|
+
#
|
528
|
+
# Sends an HTTP request and returns the parsed `Set-Cookie`
|
529
|
+
# header(s).
|
530
|
+
#
|
531
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
532
|
+
# The URL to create the HTTP request for.
|
533
|
+
#
|
534
|
+
# @!macro request_kwargs
|
535
|
+
#
|
536
|
+
# @return [Array<SetCookie>, nil]
|
537
|
+
# The parsed `SetCookie` header(s).
|
538
|
+
#
|
539
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#get_cookies-instance_method
|
540
|
+
#
|
541
|
+
# @api public
|
542
|
+
#
|
543
|
+
def http_get_cookies(url,**kwargs)
|
544
|
+
uri = normalize_url(url)
|
545
|
+
|
546
|
+
session_for(uri).get_cookies(
|
547
|
+
uri.request_uri, user: uri.user,
|
548
|
+
password: uri.password,
|
549
|
+
**kwargs
|
550
|
+
)
|
551
|
+
end
|
552
|
+
|
553
|
+
#
|
554
|
+
# Performs a `GET` request for the given URI and returns the response
|
555
|
+
# body.
|
556
|
+
#
|
557
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
558
|
+
# The URL to create the HTTP request for.
|
559
|
+
#
|
560
|
+
# @!macro request_kwargs
|
561
|
+
#
|
562
|
+
# @return [String]
|
563
|
+
# The response body.
|
564
|
+
#
|
565
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#get_body-instance_method
|
566
|
+
#
|
567
|
+
# @api public
|
568
|
+
#
|
569
|
+
def http_get_body(url,**kwargs)
|
570
|
+
uri = normalize_url(url)
|
571
|
+
|
572
|
+
session_for(uri).get_body(
|
573
|
+
uri.request_uri, user: uri.user,
|
574
|
+
password: uri.password,
|
575
|
+
**kwargs
|
576
|
+
)
|
577
|
+
end
|
578
|
+
|
579
|
+
#
|
580
|
+
# Performs a `HEAD` request for the given URI.
|
581
|
+
#
|
582
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
583
|
+
# The URL to create the HTTP request for.
|
584
|
+
#
|
585
|
+
# @!macro request_kwargs
|
586
|
+
#
|
587
|
+
# @yield [response]
|
588
|
+
# If a block is given it will be passed the received HTTP response.
|
589
|
+
#
|
590
|
+
# @yieldparam [Net::HTTPResponse] response
|
591
|
+
# The received HTTP response object.
|
592
|
+
#
|
593
|
+
# @return [Net::HTTPResponse]
|
594
|
+
# The HTTP response object.
|
595
|
+
#
|
596
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#head-instance_method
|
597
|
+
#
|
598
|
+
# @api public
|
599
|
+
#
|
600
|
+
def http_head(url,**kwargs,&block)
|
601
|
+
uri = normalize_url(url)
|
602
|
+
|
603
|
+
session_for(uri).head(
|
604
|
+
uri.request_uri, user: uri.user,
|
605
|
+
password: uri.password,
|
606
|
+
**kwargs, &block
|
607
|
+
)
|
608
|
+
end
|
609
|
+
|
610
|
+
#
|
611
|
+
# Performs a `LOCK` request for the given URI.
|
612
|
+
#
|
613
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
614
|
+
# The URL to create the HTTP request for.
|
615
|
+
#
|
616
|
+
# @!macro request_kwargs
|
617
|
+
#
|
618
|
+
# @yield [response]
|
619
|
+
# If a block is given it will be passed the received HTTP response.
|
620
|
+
#
|
621
|
+
# @yieldparam [Net::HTTPResponse] response
|
622
|
+
# The received HTTP response object.
|
623
|
+
#
|
624
|
+
# @return [Net::HTTPResponse]
|
625
|
+
# The HTTP response object.
|
626
|
+
#
|
627
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#lock-instance_method
|
628
|
+
#
|
629
|
+
# @api public
|
630
|
+
#
|
631
|
+
def http_lock(url,**kwargs,&block)
|
632
|
+
uri = normalize_url(url)
|
633
|
+
|
634
|
+
session_for(uri).lock(
|
635
|
+
uri.request_uri, user: uri.user,
|
636
|
+
password: uri.password,
|
637
|
+
**kwargs, &block
|
638
|
+
)
|
639
|
+
end
|
640
|
+
|
641
|
+
#
|
642
|
+
# Performs a `MKCOL` request for the given URI.
|
643
|
+
#
|
644
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
645
|
+
# The URL to create the HTTP request for.
|
646
|
+
#
|
647
|
+
# @!macro request_kwargs
|
648
|
+
#
|
649
|
+
# @yield [response]
|
650
|
+
# If a block is given it will be passed the received HTTP response.
|
651
|
+
#
|
652
|
+
# @yieldparam [Net::HTTPResponse] response
|
653
|
+
# The received HTTP response object.
|
654
|
+
#
|
655
|
+
# @return [Net::HTTPResponse]
|
656
|
+
# The HTTP response object.
|
657
|
+
#
|
658
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#mkcol-instance_method
|
659
|
+
#
|
660
|
+
# @api public
|
661
|
+
#
|
662
|
+
def http_mkcol(url,**kwargs,&block)
|
663
|
+
uri = normalize_url(url)
|
664
|
+
|
665
|
+
session_for(uri).mkcol(
|
666
|
+
uri.request_uri, user: uri.user,
|
667
|
+
password: uri.password,
|
668
|
+
**kwargs, &block
|
669
|
+
)
|
670
|
+
end
|
671
|
+
|
672
|
+
#
|
673
|
+
# Performs a `MOVE` request for the given URI.
|
674
|
+
#
|
675
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
676
|
+
# The URL to create the HTTP request for.
|
677
|
+
#
|
678
|
+
# @!macro request_kwargs
|
679
|
+
#
|
680
|
+
# @yield [response]
|
681
|
+
# If a block is given it will be passed the received HTTP response.
|
682
|
+
#
|
683
|
+
# @yieldparam [Net::HTTPResponse] response
|
684
|
+
# The received HTTP response object.
|
685
|
+
#
|
686
|
+
# @return [Net::HTTPResponse]
|
687
|
+
# The HTTP response object.
|
688
|
+
#
|
689
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#move-instance_method
|
690
|
+
#
|
691
|
+
# @api public
|
692
|
+
#
|
693
|
+
def http_move(url,**kwargs,&block)
|
694
|
+
uri = normalize_url(url)
|
695
|
+
|
696
|
+
session_for(uri).move(
|
697
|
+
uri.request_uri, user: uri.user,
|
698
|
+
password: uri.password,
|
699
|
+
**kwargs, &block
|
700
|
+
)
|
701
|
+
end
|
702
|
+
|
703
|
+
#
|
704
|
+
# Performs a `OPTIONS` request for the given URI.
|
705
|
+
#
|
706
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
707
|
+
# The URL to create the HTTP request for.
|
708
|
+
#
|
709
|
+
# @!macro request_kwargs
|
710
|
+
#
|
711
|
+
# @yield [response]
|
712
|
+
# If a block is given it will be passed the received HTTP response.
|
713
|
+
#
|
714
|
+
# @yieldparam [Net::HTTPResponse] response
|
715
|
+
# The received HTTP response object.
|
716
|
+
#
|
717
|
+
# @return [Net::HTTPResponse]
|
718
|
+
# The HTTP response object.
|
719
|
+
#
|
720
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#options-instance_method
|
721
|
+
#
|
722
|
+
# @api public
|
723
|
+
#
|
724
|
+
def http_options(url,**kwargs,&block)
|
725
|
+
uri = normalize_url(url)
|
726
|
+
|
727
|
+
session_for(uri).options(
|
728
|
+
uri.request_uri, user: uri.user,
|
729
|
+
password: uri.password,
|
730
|
+
**kwargs, &block
|
731
|
+
)
|
732
|
+
end
|
733
|
+
|
734
|
+
#
|
735
|
+
# Performs a `OPTIONS` HTTP request for the given URI and parses the
|
736
|
+
# `Allow` response header.
|
737
|
+
#
|
738
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
739
|
+
# The URL to create the HTTP request for.
|
740
|
+
#
|
741
|
+
# @!macro request_kwargs
|
742
|
+
#
|
743
|
+
# @return [Array<Symbol>]
|
744
|
+
# The allowed HTTP request methods for the given URL.
|
745
|
+
#
|
746
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#allowed_methods-instance_method
|
747
|
+
#
|
748
|
+
# @api public
|
749
|
+
#
|
750
|
+
def http_allowed_methods(url,**kwargs)
|
751
|
+
uri = normalize_url(url)
|
752
|
+
|
753
|
+
session_for(uri).allowed_methods(
|
754
|
+
uri.request_uri, user: uri.user,
|
755
|
+
password: uri.password,
|
756
|
+
**kwargs
|
757
|
+
)
|
758
|
+
end
|
759
|
+
|
760
|
+
#
|
761
|
+
# Performs a `PATCH` request for the given URI.
|
762
|
+
#
|
763
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
764
|
+
# The URL to create the HTTP request for.
|
765
|
+
#
|
766
|
+
# @!macro request_kwargs
|
767
|
+
#
|
768
|
+
# @yield [response]
|
769
|
+
# If a block is given it will be passed the received HTTP response.
|
770
|
+
#
|
771
|
+
# @yieldparam [Net::HTTPResponse] response
|
772
|
+
# The received HTTP response object.
|
773
|
+
#
|
774
|
+
# @return [Net::HTTPResponse]
|
775
|
+
# The HTTP response object.
|
776
|
+
#
|
777
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#patch-instance_method
|
778
|
+
#
|
779
|
+
# @api public
|
780
|
+
#
|
781
|
+
def http_patch(url,**kwargs,&block)
|
782
|
+
uri = normalize_url(url)
|
783
|
+
|
784
|
+
session_for(uri).patch(
|
785
|
+
uri.request_uri, user: uri.user,
|
786
|
+
password: uri.password,
|
787
|
+
**kwargs, &block
|
788
|
+
)
|
789
|
+
end
|
790
|
+
|
791
|
+
#
|
792
|
+
# Performs a `POST` request for the given URI.
|
793
|
+
#
|
794
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
795
|
+
# The URL to create the HTTP request for.
|
796
|
+
#
|
797
|
+
# @!macro request_kwargs
|
798
|
+
#
|
799
|
+
# @yield [response]
|
800
|
+
# If a block is given it will be passed the received HTTP response.
|
801
|
+
#
|
802
|
+
# @yieldparam [Net::HTTPResponse] response
|
803
|
+
# The received HTTP response object.
|
804
|
+
#
|
805
|
+
# @return [Net::HTTPResponse]
|
806
|
+
# The HTTP response object.
|
807
|
+
#
|
808
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#post-instance_method
|
809
|
+
#
|
810
|
+
# @api public
|
811
|
+
#
|
812
|
+
def http_post(url,**kwargs,&block)
|
813
|
+
uri = normalize_url(url)
|
814
|
+
|
815
|
+
session_for(uri).post(
|
816
|
+
uri.request_uri, user: uri.user,
|
817
|
+
password: uri.password,
|
818
|
+
**kwargs, &block
|
819
|
+
)
|
820
|
+
end
|
821
|
+
|
822
|
+
#
|
823
|
+
# Performs a `POST` request on the given URI and returns the response
|
824
|
+
# headers.
|
825
|
+
#
|
826
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
827
|
+
# The URL to create the HTTP request for.
|
828
|
+
#
|
829
|
+
# @!macro request_kwargs
|
830
|
+
#
|
831
|
+
# @return [Hash{String => String}]
|
832
|
+
# The response headers.
|
833
|
+
#
|
834
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#post_headers-instance_method
|
835
|
+
#
|
836
|
+
# @api public
|
837
|
+
#
|
838
|
+
def http_post_headers(url,**kwargs)
|
839
|
+
uri = normalize_url(url)
|
840
|
+
|
841
|
+
session_for(uri).post_headers(
|
842
|
+
uri.request_uri, user: uri.user,
|
843
|
+
password: uri.password,
|
844
|
+
**kwargs
|
845
|
+
)
|
846
|
+
end
|
847
|
+
|
848
|
+
#
|
849
|
+
# Performs a `POST` request for the given URI and returns the
|
850
|
+
# response body.
|
851
|
+
#
|
852
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
853
|
+
# The URL to create the HTTP request for.
|
854
|
+
#
|
855
|
+
# @!macro request_kwargs
|
856
|
+
#
|
857
|
+
# @return [String]
|
858
|
+
# The response body.
|
859
|
+
#
|
860
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#post_body-instance_method
|
861
|
+
#
|
862
|
+
# @api public
|
863
|
+
#
|
864
|
+
def http_post_body(url,**kwargs)
|
865
|
+
uri = normalize_url(url)
|
866
|
+
|
867
|
+
session_for(uri).post_body(
|
868
|
+
uri.request_uri, user: uri.user,
|
869
|
+
password: uri.password,
|
870
|
+
**kwargs
|
871
|
+
)
|
872
|
+
end
|
873
|
+
|
874
|
+
#
|
875
|
+
# Performs a `PROPFIND` request for the given URI.
|
876
|
+
#
|
877
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
878
|
+
# The URL to create the HTTP request for.
|
879
|
+
#
|
880
|
+
# @!macro request_kwargs
|
881
|
+
#
|
882
|
+
# @yield [response]
|
883
|
+
# If a block is given it will be passed the received HTTP response.
|
884
|
+
#
|
885
|
+
# @yieldparam [Net::HTTPResponse] response
|
886
|
+
# The received HTTP response object.
|
887
|
+
#
|
888
|
+
# @return [Net::HTTPResponse]
|
889
|
+
# The HTTP response object.
|
890
|
+
#
|
891
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#propfind-instance_method
|
892
|
+
#
|
893
|
+
# @api public
|
894
|
+
#
|
895
|
+
def http_propfind(url,**kwargs,&block)
|
896
|
+
uri = normalize_url(url)
|
897
|
+
|
898
|
+
session_for(uri).propfind(
|
899
|
+
uri.request_uri, user: uri.user,
|
900
|
+
password: uri.password,
|
901
|
+
**kwargs, &block
|
902
|
+
)
|
903
|
+
end
|
904
|
+
|
905
|
+
alias http_prop_find http_propfind
|
906
|
+
|
907
|
+
#
|
908
|
+
# Performs a `PROPPATCH` request for the given URI.
|
909
|
+
#
|
910
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
911
|
+
# The URL to create the HTTP request for.
|
912
|
+
#
|
913
|
+
# @!macro request_kwargs
|
914
|
+
#
|
915
|
+
# @yield [response]
|
916
|
+
# If a block is given it will be passed the received HTTP response.
|
917
|
+
#
|
918
|
+
# @yieldparam [Net::HTTPResponse] response
|
919
|
+
# The received HTTP response object.
|
920
|
+
#
|
921
|
+
# @return [Net::HTTPResponse]
|
922
|
+
# The HTTP response object.
|
923
|
+
#
|
924
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#proppatch-instance_method
|
925
|
+
#
|
926
|
+
# @api public
|
927
|
+
#
|
928
|
+
def http_proppatch(url,**kwargs,&block)
|
929
|
+
uri = normalize_url(url)
|
930
|
+
|
931
|
+
session_for(uri).proppatch(
|
932
|
+
uri.request_uri, user: uri.user,
|
933
|
+
password: uri.password,
|
934
|
+
**kwargs, &block
|
935
|
+
)
|
936
|
+
end
|
937
|
+
|
938
|
+
alias http_prop_patch http_proppatch
|
939
|
+
|
940
|
+
#
|
941
|
+
# Performs a `PUT` request for the given URI.
|
942
|
+
#
|
943
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
944
|
+
# The URL to create the HTTP request for.
|
945
|
+
#
|
946
|
+
# @!macro request_kwargs
|
947
|
+
#
|
948
|
+
# @yield [response]
|
949
|
+
# If a block is given it will be passed the received HTTP response.
|
950
|
+
#
|
951
|
+
# @yieldparam [Net::HTTPResponse] response
|
952
|
+
# The received HTTP response object.
|
953
|
+
#
|
954
|
+
# @return [Net::HTTPResponse]
|
955
|
+
# The HTTP response object.
|
956
|
+
#
|
957
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#put-instance_method
|
958
|
+
#
|
959
|
+
# @api public
|
960
|
+
#
|
961
|
+
def http_put(url,**kwargs,&block)
|
962
|
+
uri = normalize_url(url)
|
963
|
+
|
964
|
+
session_for(uri).put(
|
965
|
+
uri.request_uri, user: uri.user,
|
966
|
+
password: uri.password,
|
967
|
+
**kwargs, &block
|
968
|
+
)
|
969
|
+
end
|
970
|
+
|
971
|
+
#
|
972
|
+
# Performs a `TRACE` request for the given URI.
|
973
|
+
#
|
974
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
975
|
+
# The URL to create the HTTP request for.
|
976
|
+
#
|
977
|
+
# @!macro request_kwargs
|
978
|
+
#
|
979
|
+
# @yield [response]
|
980
|
+
# If a block is given it will be passed the received HTTP response.
|
981
|
+
#
|
982
|
+
# @yieldparam [Net::HTTPResponse] response
|
983
|
+
# The received HTTP response object.
|
984
|
+
#
|
985
|
+
# @return [Net::HTTPResponse]
|
986
|
+
# The HTTP response object.
|
987
|
+
#
|
988
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#trace-instance_method
|
989
|
+
#
|
990
|
+
# @api public
|
991
|
+
#
|
992
|
+
def http_trace(url,**kwargs,&block)
|
993
|
+
uri = normalize_url(url)
|
994
|
+
|
995
|
+
session_for(uri).trace(
|
996
|
+
uri.request_uri, user: uri.user,
|
997
|
+
password: uri.password,
|
998
|
+
**kwargs, &block
|
999
|
+
)
|
1000
|
+
end
|
1001
|
+
|
1002
|
+
#
|
1003
|
+
# Performs a `UNLOCK` request for the given URI.
|
1004
|
+
#
|
1005
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
1006
|
+
# The URL to create the HTTP request for.
|
1007
|
+
#
|
1008
|
+
# @!macro request_kwargs
|
1009
|
+
#
|
1010
|
+
# @yield [response]
|
1011
|
+
# If a block is given it will be passed the received HTTP response.
|
1012
|
+
#
|
1013
|
+
# @yieldparam [Net::HTTPResponse] response
|
1014
|
+
# The received HTTP response object.
|
1015
|
+
#
|
1016
|
+
# @return [Net::HTTPResponse]
|
1017
|
+
# The HTTP response object.
|
1018
|
+
#
|
1019
|
+
# @see https://ronin-rb.dev/docs/ronin-support/Ronin/Support/Network/HTTP.html#unlock-instance_method
|
1020
|
+
#
|
1021
|
+
# @api public
|
1022
|
+
#
|
1023
|
+
def http_unlock(url,**kwargs,&block)
|
1024
|
+
uri = normalize_url(url)
|
1025
|
+
|
1026
|
+
session_for(uri).unlock(
|
1027
|
+
uri.request_uri, user: uri.user,
|
1028
|
+
password: uri.password,
|
1029
|
+
**kwargs, &block
|
1030
|
+
)
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
#
|
1034
|
+
# Gets a URL and returns the response.
|
1035
|
+
#
|
1036
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
1037
|
+
# The URL to create the HTTP GET request for.
|
1038
|
+
#
|
1039
|
+
# @!macro request_kwargs
|
1040
|
+
#
|
1041
|
+
# @yield [response]
|
1042
|
+
# If a block is given it will be passed the received HTTP response.
|
1043
|
+
#
|
1044
|
+
# @yieldparam [Net::HTTPResponse] response
|
1045
|
+
# The received HTTP response object.
|
1046
|
+
#
|
1047
|
+
# @return [Net::HTTPResponse]
|
1048
|
+
# The HTTP response object.
|
1049
|
+
#
|
1050
|
+
# @raise [TooManyRedirects]
|
1051
|
+
# Maximum number of redirects reached.
|
1052
|
+
#
|
1053
|
+
# @note This method will follow redirects by default.
|
1054
|
+
#
|
1055
|
+
# @example
|
1056
|
+
# response = agent.get('https://example.com/')
|
1057
|
+
# # => #<Net::HTTPResponse:...>
|
1058
|
+
#
|
1059
|
+
def get(url, follow_redirects: @follow_redirects,
|
1060
|
+
max_redirects: @max_redirects,
|
1061
|
+
**kwargs)
|
1062
|
+
response = http_get(url,**kwargs)
|
1063
|
+
|
1064
|
+
if follow_redirects && response.kind_of?(Net::HTTPRedirection)
|
1065
|
+
redirect_count = 0
|
1066
|
+
|
1067
|
+
while response.kind_of?(Net::HTTPRedirection)
|
1068
|
+
if redirect_count >= max_redirects
|
1069
|
+
raise(TooManyRedirects,"maximum number of redirects reached: #{url.inspect}")
|
1070
|
+
end
|
1071
|
+
|
1072
|
+
location = response['Location']
|
1073
|
+
response = http_get(location)
|
1074
|
+
|
1075
|
+
redirect_count += 1
|
1076
|
+
end
|
1077
|
+
end
|
1078
|
+
|
1079
|
+
yield response if block_given?
|
1080
|
+
return response
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
#
|
1084
|
+
# Gets the URL and returns the parsed HTML.
|
1085
|
+
#
|
1086
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
1087
|
+
# The URL to create the HTTP GET request for.
|
1088
|
+
#
|
1089
|
+
# @!macro request_kwargs
|
1090
|
+
#
|
1091
|
+
# @return [Nokogiri::HTML::Document]
|
1092
|
+
# The parsed HTML response.
|
1093
|
+
#
|
1094
|
+
# @raise [ContentTypeError]
|
1095
|
+
# Did not receive a response with a `Content-Type` of `text/html`.
|
1096
|
+
#
|
1097
|
+
# @raise [TooManyRedirects]
|
1098
|
+
# Maximum number of redirects reached.
|
1099
|
+
#
|
1100
|
+
# @note This method will follow redirects by default.
|
1101
|
+
#
|
1102
|
+
# @example
|
1103
|
+
# doc = agent.get_html('https://example.com/page.html')
|
1104
|
+
# # => #<Nokogiri::HTML::Document:...>
|
1105
|
+
#
|
1106
|
+
def get_html(url,**kwargs)
|
1107
|
+
response = get(url,**kwargs)
|
1108
|
+
|
1109
|
+
unless response.content_type.include?('text/html')
|
1110
|
+
raise(ContentTypeError,"response 'Content-Type' was not 'text/html': #{response.content_type.inspect}")
|
1111
|
+
end
|
1112
|
+
|
1113
|
+
return Nokogiri::HTML(response.body)
|
1114
|
+
end
|
1115
|
+
|
1116
|
+
#
|
1117
|
+
# Gets the URL and returns the parsed XML.
|
1118
|
+
#
|
1119
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
1120
|
+
# The URL to create the HTTP GET request for.
|
1121
|
+
#
|
1122
|
+
# @!macro request_kwargs
|
1123
|
+
#
|
1124
|
+
# @return [Nokogiri::XML::Document]
|
1125
|
+
# The parsed XML response.
|
1126
|
+
#
|
1127
|
+
# @raise [ContentTypeError]
|
1128
|
+
# Did not receive a response with a `Content-Type` of `text/xml`.
|
1129
|
+
#
|
1130
|
+
# @raise [TooManyRedirects]
|
1131
|
+
# Maximum number of redirects reached.
|
1132
|
+
#
|
1133
|
+
# @note This method will follow redirects by default.
|
1134
|
+
#
|
1135
|
+
# @example
|
1136
|
+
# doc = agent.get_xml('https://example.com/data.xml')
|
1137
|
+
# # => #<Nokogiri::XML::Document:...>
|
1138
|
+
#
|
1139
|
+
def get_xml(url,**kwargs)
|
1140
|
+
response = get(url,**kwargs)
|
1141
|
+
|
1142
|
+
unless response.content_type.include?('text/xml')
|
1143
|
+
raise(ContentTypeError,"response 'Content-Type' was not 'text/xml': #{response.content_type.inspect}")
|
1144
|
+
end
|
1145
|
+
|
1146
|
+
return Nokogiri::XML(response.body)
|
1147
|
+
end
|
1148
|
+
|
1149
|
+
#
|
1150
|
+
# Gets the URL and returns the parsed JSON.
|
1151
|
+
#
|
1152
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
1153
|
+
# The URL to create the HTTP GET request for.
|
1154
|
+
#
|
1155
|
+
# @!macro request_kwargs
|
1156
|
+
#
|
1157
|
+
# @return [Hash{String => Object}, Array]
|
1158
|
+
# The parsed JSON.
|
1159
|
+
#
|
1160
|
+
# @raise [ContentTypeError]
|
1161
|
+
# Did not receive a response with a `Content-Type` of
|
1162
|
+
# `application/json`.
|
1163
|
+
#
|
1164
|
+
# @raise [TooManyRedirects]
|
1165
|
+
# Maximum number of redirects reached.
|
1166
|
+
#
|
1167
|
+
# @note This method will follow redirects by default.
|
1168
|
+
#
|
1169
|
+
# @example
|
1170
|
+
# json = agent.get_json('https://example.com/data.json')
|
1171
|
+
# # => {...}
|
1172
|
+
#
|
1173
|
+
def get_json(url,**kwargs)
|
1174
|
+
response = get(url,**kwargs)
|
1175
|
+
|
1176
|
+
unless response.content_type.include?('application/json')
|
1177
|
+
raise(ContentTypeError,"response 'Content-Type' was not 'application/json': #{response.content_type.inspect}")
|
1178
|
+
end
|
1179
|
+
|
1180
|
+
return ::JSON.parse(response.body)
|
1181
|
+
end
|
1182
|
+
|
1183
|
+
#
|
1184
|
+
# Performs an HTTP POST to the URL.
|
1185
|
+
#
|
1186
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
1187
|
+
# The URL to create the HTTP GET request for.
|
1188
|
+
#
|
1189
|
+
# @!macro request_kwargs
|
1190
|
+
#
|
1191
|
+
# @yield [response]
|
1192
|
+
# If a block is given it will be passed the received HTTP response.
|
1193
|
+
#
|
1194
|
+
# @yieldparam [Net::HTTPResponse] response
|
1195
|
+
# The received HTTP response object.
|
1196
|
+
#
|
1197
|
+
# @return [Net::HTTPResponse]
|
1198
|
+
# The HTTP response object.
|
1199
|
+
#
|
1200
|
+
# @raise [TooManyRedirects]
|
1201
|
+
# Maximum number of redirects reached.
|
1202
|
+
#
|
1203
|
+
# @note
|
1204
|
+
# If the response is an HTTP redirect, then {#get} will be called to
|
1205
|
+
# follow any redirects.
|
1206
|
+
#
|
1207
|
+
# @example
|
1208
|
+
# response = agent.post('https://example.com/form', form_data: {'foo' => 'bar'})
|
1209
|
+
# # => #<Net::HTTPResponse:...>
|
1210
|
+
#
|
1211
|
+
def post(url, follow_redirects: @follow_redirects,
|
1212
|
+
max_redirects: @max_redirects,
|
1213
|
+
**kwargs)
|
1214
|
+
response = http_post(url,**kwargs)
|
1215
|
+
|
1216
|
+
if follow_redirects && response.kind_of?(Net::HTTPRedirection)
|
1217
|
+
location = response['Location']
|
1218
|
+
|
1219
|
+
response = begin
|
1220
|
+
get(location, follow_redirects: follow_redirects,
|
1221
|
+
max_redirects: max_redirects - 1)
|
1222
|
+
rescue TooManyRedirects
|
1223
|
+
raise(TooManyRedirects,"maximum number of redirects reached: #{url.inspect}")
|
1224
|
+
end
|
1225
|
+
end
|
1226
|
+
|
1227
|
+
yield response if block_given?
|
1228
|
+
return response
|
1229
|
+
end
|
1230
|
+
|
1231
|
+
#
|
1232
|
+
# Performs an HTTP POST to the URL and parses the HTML response.
|
1233
|
+
#
|
1234
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
1235
|
+
# The URL to create the HTTP POST request for.
|
1236
|
+
#
|
1237
|
+
# @!macro request_kwargs
|
1238
|
+
#
|
1239
|
+
# @return [Nokogiri::HTML::Document]
|
1240
|
+
# The parsed HTML response.
|
1241
|
+
#
|
1242
|
+
# @raise [TooManyRedirects]
|
1243
|
+
# Maximum number of redirects reached.
|
1244
|
+
#
|
1245
|
+
# @raise [ContentTypeError]
|
1246
|
+
# Did not receive a response with a `Content-Type` of
|
1247
|
+
# `text/html`.
|
1248
|
+
#
|
1249
|
+
# @note
|
1250
|
+
# If the response is an HTTP redirect, then {#get} will be called to
|
1251
|
+
# follow any redirects.
|
1252
|
+
#
|
1253
|
+
# @example Send a POST request and parses the HTML response:
|
1254
|
+
# doc = agent.post_html 'https://example.com/form', form_data: {foo: 'bar'})
|
1255
|
+
# # => #<Nokogiri::HTML::Document:...>
|
1256
|
+
#
|
1257
|
+
def post_html(url,**kwargs)
|
1258
|
+
response = post(url,**kwargs)
|
1259
|
+
|
1260
|
+
unless response.content_type.include?('text/html')
|
1261
|
+
raise(ContentTypeError,"response 'Content-Type' was not 'text/html': #{response.content_type.inspect}")
|
1262
|
+
end
|
1263
|
+
|
1264
|
+
return Nokogiri::HTML(response.body)
|
1265
|
+
end
|
1266
|
+
|
1267
|
+
#
|
1268
|
+
# Performs an HTTP POST to the URL and parses the XML response.
|
1269
|
+
#
|
1270
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
1271
|
+
# The URL to create the HTTP POST request for.
|
1272
|
+
#
|
1273
|
+
# @!macro request_kwargs
|
1274
|
+
#
|
1275
|
+
# @return [Nokogiri::XML::Document]
|
1276
|
+
# The parsed XML response.
|
1277
|
+
#
|
1278
|
+
# @raise [TooManyRedirects]
|
1279
|
+
# Maximum number of redirects reached.
|
1280
|
+
#
|
1281
|
+
# @raise [ContentTypeError]
|
1282
|
+
# Did not receive a response with a `Content-Type` of
|
1283
|
+
# `text/xml`.
|
1284
|
+
#
|
1285
|
+
# @note
|
1286
|
+
# If the response is an HTTP redirect, then {#get} will be called to
|
1287
|
+
# follow any redirects.
|
1288
|
+
#
|
1289
|
+
# @example Send a POST request to the form and parses the XML response:
|
1290
|
+
# doc = agent.post_xml 'https://example.com/form', form_data: {foo: 'bar'}
|
1291
|
+
# # => #<Nokogiri::XML::Document:...>
|
1292
|
+
#
|
1293
|
+
def post_xml(url,**kwargs)
|
1294
|
+
response = post(url,**kwargs)
|
1295
|
+
|
1296
|
+
unless response.content_type.include?('text/xml')
|
1297
|
+
raise(ContentTypeError,"response 'Content-Type' was not 'application/json': #{response.content_type.inspect}")
|
1298
|
+
end
|
1299
|
+
|
1300
|
+
return Nokogiri::XML(response.body)
|
1301
|
+
end
|
1302
|
+
|
1303
|
+
#
|
1304
|
+
# Performs an HTTP POST to the URL and parses the JSON response.
|
1305
|
+
#
|
1306
|
+
# @param [URI::HTTP, Addressable::URI, String] url
|
1307
|
+
# The URL to create the HTTP POST request for.
|
1308
|
+
#
|
1309
|
+
# @!macro request_kwargs
|
1310
|
+
#
|
1311
|
+
# @return [Hash{String => Object}, Array]
|
1312
|
+
# The parses JSON response.
|
1313
|
+
#
|
1314
|
+
# @raise [TooManyRedirects]
|
1315
|
+
# Maximum number of redirects reached.
|
1316
|
+
#
|
1317
|
+
# @raise [ContentTypeError]
|
1318
|
+
# Did not receive a response with a `Content-Type` of
|
1319
|
+
# `application/json`.
|
1320
|
+
#
|
1321
|
+
# @note
|
1322
|
+
# If the response is an HTTP redirect, then {#get} will be called to
|
1323
|
+
# follow any redirects.
|
1324
|
+
#
|
1325
|
+
# @example Send a POST request to the form and parse the JSON response:
|
1326
|
+
# json = agent.post_json 'https://example.com/form', form_data: {foo: 'bar'}
|
1327
|
+
# # => {...}
|
1328
|
+
#
|
1329
|
+
# @example Send a POST request containing JSON and parse the JSON response:
|
1330
|
+
# json = agent.post_json 'https://example.com/api/end-point', json: {foo: 'bar'}
|
1331
|
+
# # => {...}
|
1332
|
+
#
|
1333
|
+
def post_json(url,**kwargs)
|
1334
|
+
response = post(url,**kwargs)
|
1335
|
+
|
1336
|
+
unless response.content_type.include?('application/json')
|
1337
|
+
raise(ContentTypeError,"response 'Content-Type' was not 'application/json': #{response.content_type.inspect}")
|
1338
|
+
end
|
1339
|
+
|
1340
|
+
return ::JSON.parse(response.body)
|
1341
|
+
end
|
1342
|
+
|
1343
|
+
private
|
1344
|
+
|
1345
|
+
#
|
1346
|
+
# Normalizes a URL.
|
1347
|
+
#
|
1348
|
+
# @param [URI::HTTP, Addressable::URI, String, Object] url
|
1349
|
+
# The URL or URI to normalize.
|
1350
|
+
#
|
1351
|
+
# @return [URI::HTTP, Addressable::URI]
|
1352
|
+
# The parsed URL.
|
1353
|
+
#
|
1354
|
+
def normalize_url(url)
|
1355
|
+
case url
|
1356
|
+
when URI::HTTP, Addressable::URI then url
|
1357
|
+
when String then Addressable::URI.parse(url)
|
1358
|
+
else
|
1359
|
+
raise(ArgumentError,"url must be a URI::HTTP, Addressable::URI, or a String: #{url.inspect}")
|
1360
|
+
end
|
1361
|
+
end
|
1362
|
+
|
1363
|
+
#
|
1364
|
+
# Fetches an existing HTTP session or creates a new one for the given
|
1365
|
+
# URI.
|
1366
|
+
#
|
1367
|
+
# @param [URI::HTTP] uri
|
1368
|
+
# The URL to retrieve or create an HTTP session for.
|
1369
|
+
#
|
1370
|
+
# @return [Ronin::Support::Network::HTTP]
|
1371
|
+
# The HTTP session.
|
1372
|
+
#
|
1373
|
+
def session_for(uri)
|
1374
|
+
key = [uri.scheme, uri.host, uri.port]
|
1375
|
+
|
1376
|
+
@sessions[key] ||= Support::Network::HTTP.connect_uri(
|
1377
|
+
uri, proxy: @proxy,
|
1378
|
+
ssl: (@ssl if uri.scheme == 'https'),
|
1379
|
+
user_agent: @user_agent
|
1380
|
+
)
|
1381
|
+
end
|
1382
|
+
|
1383
|
+
end
|
1384
|
+
end
|
1385
|
+
end
|
1386
|
+
end
|