ssrf_proxy 0.0.2

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.
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (c) 2015 Brendan Coles <bcoles@gmail.com>
4
+ # SSRF Proxy - https://github.com/bcoles/ssrf_proxy
5
+ # See the file 'LICENSE' for copying permission
6
+ #
7
+
8
+ require "ssrf_proxy/version"
9
+ require "ssrf_proxy/http"
10
+ require "ssrf_proxy/server"
11
+
12
+ module SSRFProxy
13
+
14
+ require 'logger'
15
+ require 'colorize'
16
+
17
+ end
18
+
@@ -0,0 +1,1306 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (c) 2015 Brendan Coles <bcoles@gmail.com>
4
+ # SSRF Proxy - https://github.com/bcoles/ssrf_proxy
5
+ # See the file 'LICENSE' for copying permission
6
+ #
7
+
8
+ require "ssrf_proxy"
9
+
10
+ module SSRFProxy
11
+ #
12
+ # @note SSRFProxy::HTTP
13
+ #
14
+ class HTTP
15
+ attr_accessor = :logger
16
+
17
+ # @note output status messages
18
+ def print_status(msg='')
19
+ puts '[*] '.blue + msg
20
+ end
21
+
22
+ # @note output progress messages
23
+ def print_good(msg='')
24
+ puts '[+] '.green + msg
25
+ end
26
+
27
+ # url parsing
28
+ require 'net/http'
29
+ require 'uri'
30
+ require 'cgi'
31
+
32
+ # client http request parsing
33
+ require 'webrick'
34
+ require 'stringio'
35
+
36
+ # rules
37
+ require 'digest'
38
+ require 'base64'
39
+
40
+ # ip encoding
41
+ require 'ipaddress'
42
+
43
+ # @note logger
44
+ def logger
45
+ @logger || ::Logger.new(STDOUT).tap do |log|
46
+ log.progname = 'ssrf-proxy'
47
+ log.level = ::Logger::WARN
48
+ log.datetime_format = '%Y-%m-%d %H:%M:%S '
49
+ end
50
+ end
51
+
52
+ #
53
+ # @note SSRFProxy:HTTP errors
54
+ #
55
+ module Error
56
+ # custom errors
57
+ class Error < StandardError; end
58
+ exceptions = %w(
59
+ NoUrlPlaceholder
60
+ InvalidSsrfRequest
61
+ InvalidRequestMethod
62
+ InvalidUpstreamProxy
63
+ InvalidIpEncoding
64
+ InvalidHttpRequest
65
+ InvalidUriRequest )
66
+ exceptions.each { |e| const_set(e, Class.new(Error)) }
67
+ end
68
+
69
+ #
70
+ # @note SSRFProxy::HTTP
71
+ #
72
+ # @options
73
+ # - url - String - SSRF URL with 'xxURLxx' placeholder
74
+ # - opts - Hash - SSRF and HTTP connection options:
75
+ # - 'proxy' => String
76
+ # - 'method' => String
77
+ # - 'post_data' => String
78
+ # - 'rules' => String
79
+ # - 'ip_encoding' => String
80
+ # - 'match' => Regex
81
+ # - 'strip' => String
82
+ # - 'guess_status' => Boolean
83
+ # - 'guess_mime' => Boolean
84
+ # - 'forward_cookies'=> Boolean
85
+ # - 'body_to_uri' => Boolean
86
+ # - 'auth_to_uri' => Boolean
87
+ # - 'cookie' => String
88
+ # - 'timeout' => Integer
89
+ # - 'user_agent' => String
90
+ #
91
+ def initialize(url='', opts={})
92
+ @logger = ::Logger.new(STDOUT).tap do |log|
93
+ log.progname = 'ssrf-proxy'
94
+ log.level = ::Logger::WARN
95
+ log.datetime_format = '%Y-%m-%d %H:%M:%S '
96
+ end
97
+ begin
98
+ @ssrf_url = URI::parse(url.to_s)
99
+ rescue URI::InvalidURIError
100
+ raise SSRFProxy::HTTP::Error::InvalidSsrfRequest.new,
101
+ "Invalid SSRF request specified."
102
+ end
103
+ if @ssrf_url.scheme.nil? || @ssrf_url.host.nil? || @ssrf_url.port.nil?
104
+ raise SSRFProxy::HTTP::Error::InvalidSsrfRequest.new,
105
+ "Invalid SSRF request specified."
106
+ end
107
+ if @ssrf_url.scheme !~ /\Ahttps?\z/
108
+ raise SSRFProxy::HTTP::Error::InvalidSsrfRequest.new,
109
+ "Invalid SSRF request specified. Scheme must be http(s)."
110
+ end
111
+
112
+ # SSRF options
113
+ @upstream_proxy = nil
114
+ @method = 'GET'
115
+ @post_data = ''
116
+ @ip_encoding = nil
117
+ @rules = []
118
+ @forward_cookies = false
119
+ @body_to_uri = false
120
+ @auth_to_uri = false
121
+ opts.each do |option, value|
122
+ next if value.eql?('')
123
+ case option
124
+ when 'proxy'
125
+ begin
126
+ @upstream_proxy = URI::parse(value)
127
+ rescue URI::InvalidURIError => e
128
+ raise SSRFProxy::HTTP::Error::InvalidUpstreamProxy.new,
129
+ "Invalid upstream HTTP proxy specified."
130
+ end
131
+ if @upstream_proxy.scheme !~ /\Ahttps?\z/
132
+ raise SSRFProxy::HTTP::Error::InvalidUpstreamProxy.new,
133
+ "Invalid upstream HTTP proxy specified."
134
+ end
135
+ when 'method'
136
+ if @method !~ /\A(get|post|head)+?\z/i
137
+ raise SSRFProxy::HTTP::Error::InvalidRequestMethod.new,
138
+ "Invalid SSRF request method specified. Method must be GET/POST/HEAD."
139
+ end
140
+ @method = 'GET' if value =~ /\Aget\z/i
141
+ @method = 'POST' if value =~ /\Apost\z/i
142
+ @method = 'HEAD' if value =~ /\Ahead\z/i
143
+ when 'post_data'
144
+ @post_data = value.to_s
145
+ when 'ip_encoding'
146
+ if value.to_s !~ /\A[a-z0-9]+\z/i
147
+ raise SSRFProxy::HTTP::Error::InvalidIpEncoding.new,
148
+ "Invalid IP encoding method specified."
149
+ end
150
+ @ip_encoding = value.to_s
151
+ when 'rules'
152
+ @rules = value.to_s.split(/,/)
153
+ when 'forward_cookies'
154
+ @forward_cookies = true if value
155
+ when 'body_to_uri'
156
+ @body_to_uri = true if value
157
+ when 'auth_to_uri'
158
+ @auth_to_uri = true if value
159
+ end
160
+ end
161
+ if @ssrf_url.request_uri !~ /xxURLxx/ && @post_data.to_s !~ /xxURLxx/
162
+ raise SSRFProxy::HTTP::Error::NoUrlPlaceholder.new,
163
+ "You must specify a URL placeholder with 'xxURLxx' in the SSRF request"
164
+ end
165
+
166
+ # HTTP connection options
167
+ @cookie = nil
168
+ @timeout = 10
169
+ @user_agent = 'Mozilla/5.0'
170
+ opts.each do |option, value|
171
+ next if value.eql?('')
172
+ case option
173
+ when 'cookie'
174
+ @cookie = value.to_s
175
+ when 'timeout'
176
+ @timeout = value.to_i
177
+ when 'user_agent'
178
+ @user_agent = value.to_s
179
+ end
180
+ end
181
+
182
+ # HTTP response modification options
183
+ @match_regex = "\\A(.+)\\z"
184
+ @strip = []
185
+ @guess_status = false
186
+ @guess_mime = false
187
+ opts.each do |option, value|
188
+ next if value.eql?('')
189
+ case option
190
+ when 'match'
191
+ @match_regex = value.to_s
192
+ when 'strip'
193
+ @strip = value.to_s.split(/,/)
194
+ when 'guess_status'
195
+ @guess_status = true if value
196
+ when 'guess_mime'
197
+ @guess_mime = true if value
198
+ end
199
+ end
200
+
201
+ end
202
+
203
+ #
204
+ # @note URL accessor
205
+ #
206
+ # @returns - String - SSRF URL
207
+ #
208
+ def url
209
+ @ssrf_url
210
+ end
211
+
212
+ #
213
+ # @note Host accessor
214
+ #
215
+ # @returns - String - SSRF host
216
+ #
217
+ def host
218
+ @ssrf_url.host
219
+ end
220
+
221
+ #
222
+ # @note Port accessor
223
+ #
224
+ # @returns - String - SSRF port
225
+ #
226
+ def port
227
+ @ssrf_url.port
228
+ end
229
+
230
+ #
231
+ # @note Cookie accessor
232
+ #
233
+ # @returns - String - SSRF request cookie
234
+ #
235
+ def cookie
236
+ @cookie
237
+ end
238
+
239
+ #
240
+ # @note Upstream proxy accessor
241
+ #
242
+ # @returns - String - Upstream proxy
243
+ #
244
+ def proxy
245
+ @upstream_proxy
246
+ end
247
+
248
+ #
249
+ # @note Encode IP address of a given URL
250
+ #
251
+ # @options
252
+ # - url - String - target url
253
+ # - mode - String - encoding (int, ipv6, oct, hex)
254
+ #
255
+ # @returns - String - encoded ip address
256
+ #
257
+ def encode_ip(url, mode)
258
+ return if url.nil?
259
+ new_host = nil
260
+ host = URI::parse(url.to_s.split('?').first).host.to_s
261
+ begin
262
+ ip = IPAddress.parse(host)
263
+ rescue
264
+ logger.warn("Could not parse requested host as IP address: #{host}")
265
+ return
266
+ end
267
+ case mode
268
+ when 'int'
269
+ new_host = url.to_s.gsub!(host, "#{ip.to_u32}")
270
+ when 'ipv6'
271
+ new_host = url.to_s.gsub!(host, "#{ip.to_ipv6}")
272
+ when 'oct'
273
+ new_host = url.to_s.gsub!(host, "0#{ip.to_u32.to_s(8)}")
274
+ when 'hex'
275
+ new_host = url.to_s.gsub!(host, "0x#{ip.to_u32.to_s(16)}")
276
+ else
277
+ logger.warn("Invalid IP encoding: #{mode}")
278
+ end
279
+ new_host
280
+ end
281
+
282
+ #
283
+ # @note Run a specified URL through SSRF rules
284
+ #
285
+ # @options
286
+ # - url - String - request URL
287
+ # - rules - String - comma separated list of rules
288
+ #
289
+ # @returns - String - modified request URL
290
+ #
291
+ def run_rules(url, rules)
292
+ str = url.to_s
293
+ return str if rules.nil?
294
+ rules.each do |rule|
295
+ case rule
296
+ when 'noproto'
297
+ str = str.gsub(/^https?:\/\//, '')
298
+ when 'nossl', 'http'
299
+ str = str.gsub(/^https:\/\//, 'http://')
300
+ when 'ssl', 'https'
301
+ str = str.gsub(/^http:\/\//, 'https://')
302
+ when 'base64'
303
+ str = Base64.encode64(str).chomp
304
+ when 'md4'
305
+ str = OpenSSL::Digest::MD4.hexdigest(str)
306
+ when 'md5'
307
+ md5 = Digest::MD5.new
308
+ md5.update str
309
+ str = md5.hexdigest
310
+ when 'sha1'
311
+ str = Digest::SHA1.hexdigest(str)
312
+ when 'reverse'
313
+ str = str.reverse
314
+ when 'urlencode'
315
+ str = CGI.escape(str)
316
+ when 'urldecode'
317
+ str = CGI.unescape(str)
318
+ else
319
+ logger.warn("Unknown rule: #{rule}")
320
+ end
321
+ end
322
+ str
323
+ end
324
+
325
+ #
326
+ # @note Format a HTTP request as a URL and request via SSRF
327
+ #
328
+ # @options
329
+ # - request - String - raw HTTP request
330
+ #
331
+ # @returns String - raw HTTP response headers and body
332
+ #
333
+ def send_request(request)
334
+ if request.to_s !~ /\A[A-Z]{1,20} /
335
+ logger.warn("Received malformed client HTTP request.")
336
+ return "HTTP\/1.1 501 Error\nServer: SSRF Proxy\nContent-Length: 0\n\n"
337
+ elsif request.to_s =~ /\ACONNECT ([^\s]+) .*$/
338
+ logger.warn("CONNECT tunneling is not supported: #{$1}")
339
+ return "HTTP\/1.1 501 Error\nServer: SSRF Proxy\nContent-Length: 0\n\n"
340
+ elsif request.to_s =~ /\A(DEBUG|TRACE|TRACK|OPTIONS) /
341
+ logger.warn("Client request method is not supported: #{$1}")
342
+ return "HTTP\/1.1 501 Error\nServer: SSRF Proxy\nContent-Length: 0\n\n"
343
+ end
344
+ if request.to_s !~ /\A[A-Z]{1,20} https?:\/\//
345
+ if request.to_s =~ /^Host: ([^\s]+)\r?\n/
346
+ logger.info("Using host header: #{$1}")
347
+ else
348
+ logger.warn("No host specified")
349
+ return "HTTP\/1.1 501 Error\nServer: SSRF Proxy\nContent-Length: 0\n\n"
350
+ end
351
+ end
352
+ opts = {}
353
+ begin
354
+ # change POST to GET if the request body is empty
355
+ if request.to_s =~ /\APOST /
356
+ request = request.gsub!(/\APOST /, 'GET ') if request.split(/\r?\n\r?\n/)[1].nil?
357
+ end
358
+ # parse request
359
+ req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP)
360
+ req.parse(StringIO.new(request))
361
+ if req.to_s =~ /^Upgrade: WebSocket/
362
+ logger.warn("WebSocket tunneling is not supported: #{req.host}:#{req.port}")
363
+ return "HTTP\/1.1 501 Error\nServer: SSRF Proxy\nContent-Length: 0\n\n"
364
+ end
365
+ uri = req.request_uri
366
+ raise SSRFProxy::HTTP::Error::InvalidHttpRequest if uri.nil?
367
+ rescue => e
368
+ logger.info("Received malformed client HTTP request.")
369
+ return "HTTP\/1.1 501 Error\nServer: SSRF Proxy\nContent-Length: 0\n\n"
370
+ end
371
+
372
+ # parse request body and move to uri
373
+ if @body_to_uri && !req.body.nil?
374
+ logger.debug "Parsing request body: #{req.body}"
375
+ begin
376
+ new_query = URI.decode_www_form(req.body)
377
+ if req.query_string.nil?
378
+ uri = "#{uri}?#{URI.encode_www_form(new_query)}"
379
+ else
380
+ URI.decode_www_form(req.query_string).each { |p| new_query << p }
381
+ uri = "#{uri}&#{URI.encode_www_form(new_query)}"
382
+ end
383
+ rescue
384
+ logger.warn "Could not parse request POST data"
385
+ end
386
+ end
387
+
388
+ # move basic authentication credentials to uri
389
+ if @auth_to_uri && !req.header.nil?
390
+ req.header['authorization'].each do |header|
391
+ next unless header.split(' ').first =~ /^basic$/i
392
+ begin
393
+ creds = header.split(' ')[1]
394
+ user = Base64.decode64(creds).chomp
395
+ logger.info "Using basic authentication credentials: #{user}"
396
+ uri = uri.to_s.gsub!(/:(\/\/)/, "://#{user}@")
397
+ rescue
398
+ logger.warn "Could not parse request authorization header: #{header}"
399
+ end
400
+ break
401
+ end
402
+ end
403
+
404
+ # forward client cookies
405
+ new_cookie = []
406
+ new_cookie << @cookie unless @cookie.nil?
407
+ if @forward_cookies
408
+ req.cookies.each do |c|
409
+ new_cookie << "#{c}"
410
+ end
411
+ end
412
+ unless new_cookie.empty?
413
+ opts['cookie'] = new_cookie.uniq.join('; ').to_s
414
+ logger.info "Using cookie: #{opts['cookie']}"
415
+ end
416
+ send_uri(uri, opts)
417
+ end
418
+
419
+ #
420
+ # @note Fetch a URI via SSRF
421
+ #
422
+ # @options
423
+ # - uri - URI - URI to fetch
424
+ # - opts - Hash - request options (keys: cookie)
425
+ #
426
+ # @returns String - raw HTTP response headers and body
427
+ #
428
+ def send_uri(uri, opts={})
429
+ raise SSRFProxy::HTTP::Error::InvalidUriRequest if uri.nil?
430
+
431
+ # convert ip
432
+ if @ip_encoding
433
+ encoded_url = encode_ip(uri, @ip_encoding)
434
+ uri = encoded_url unless encoded_url.nil?
435
+ end
436
+
437
+ # send request
438
+ status_msg = "Request -> #{@method}"
439
+ status_msg << " -> PROXY[#{@upstream_proxy.host}:#{@upstream_proxy.port}]" unless @upstream_proxy.nil?
440
+ status_msg << " -> SSRF[#{@ssrf_url.host}:#{@ssrf_url.port}] -> URI[#{uri}]"
441
+ print_status(status_msg)
442
+ response = send_http_request(uri, opts)
443
+ response = parse_http_response(response) unless response.class == Hash
444
+ body = response["body"]||''
445
+ headers = response["headers"]
446
+
447
+ # handle HTTP response
448
+ if response["status"] == 'fail'
449
+ status_msg = "Response <- #{response["code"]}"
450
+ status_msg << " <- PROXY[#{@upstream_proxy.host}:#{@upstream_proxy.port}]" unless @upstream_proxy.nil?
451
+ status_msg << " <- SSRF[#{@ssrf_url.host}:#{@ssrf_url.port}] <- URI[#{uri}]"
452
+ print_status(status_msg)
453
+ return "#{response['headers']}#{response['body']}"
454
+ end
455
+
456
+ # guess mime type and add content-type header
457
+ if @guess_mime
458
+ content_type = guess_mime(File.extname(uri.to_s.split('?').first))
459
+ unless content_type.nil?
460
+ logger.info "Using content-type: #{content_type}"
461
+ if headers =~ /^content\-type:.*$/i
462
+ headers.gsub!(/^content\-type:.*$/i, "Content-Type: #{content_type}")
463
+ else
464
+ headers.gsub!(/\n\n\z/, "\nContent-Type: #{content_type}\n\n")
465
+ end
466
+ end
467
+ end
468
+
469
+ # match response content
470
+ unless @match_regex.nil?
471
+ matches = body.scan(/#{@match_regex}/m)
472
+ if matches.length
473
+ body = matches.flatten.first.to_s
474
+ logger.info "Response matches pattern '#{@match_regex}'"
475
+ else
476
+ logger.warn "Response does not match pattern"
477
+ end
478
+ end
479
+
480
+ # set content length
481
+ content_length = body.to_s.length
482
+ if headers =~ /^transfer\-encoding:.*$/i
483
+ headers.gsub!(/^transfer\-encoding:.*$/i, "Content-Length: #{content_length}")
484
+ elsif headers =~ /^content\-length:.*$/i
485
+ headers.gsub!(/^content\-length:.*$/i, "Content-Length: #{content_length}")
486
+ else
487
+ headers.gsub!(/\n\n\z/, "\nContent-Length: #{content_length}\n\n")
488
+ end
489
+
490
+ # return HTTP response
491
+ logger.debug("Response:\n#{headers}#{body}")
492
+ status_msg = "Response <- #{response["code"]}"
493
+ status_msg << " <- PROXY[#{@upstream_proxy.host}:#{@upstream_proxy.port}]" unless @upstream_proxy.nil?
494
+ status_msg << " <- SSRF[#{@ssrf_url.host}:#{@ssrf_url.port}] <- URI[#{uri}]"
495
+ status_msg << " -- TITLE[#{$1}]" if body[0..1024] =~ /<title>([^<]*)<\/title>/im
496
+ status_msg << " -- SIZE[#{body.size} bytes]"
497
+ print_good(status_msg)
498
+ return "#{headers}#{body}"
499
+ end
500
+
501
+ #
502
+ # @note Send HTTP request
503
+ #
504
+ # @options
505
+ # - url - String - URI to fetch
506
+ # - opts - Hash - request options (keys: cookie)
507
+ #
508
+ # @returns Hash of HTTP response (status, code, headers, body)
509
+ #
510
+ def send_http_request(url, opts={})
511
+ # use upstream proxy
512
+ if @upstream_proxy.nil?
513
+ http = Net::HTTP.new(@ssrf_url.host, @ssrf_url.port)
514
+ else
515
+ http = Net::HTTP::Proxy(@upstream_proxy.host, @upstream_proxy.port).new(@ssrf_url.host, @ssrf_url.port)
516
+ end
517
+ # run target url through rules
518
+ target = run_rules(url, @rules)
519
+ # replace xxURLxx placeholder in SSRF HTTP GET parameters
520
+ ssrf_url = "#{@ssrf_url.path}?#{@ssrf_url.query}".gsub(/xxURLxx/, "#{target}")
521
+ # replace xxURLxx placeholder in SSRF HTTP POST parameters
522
+ post_data = @post_data.gsub(/xxURLxx/, "#{target}") unless @post_data.nil?
523
+ if @ssrf_url.scheme == 'https'
524
+ http.use_ssl = true
525
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE #PEER
526
+ end
527
+ # set socket options
528
+ http.open_timeout = @timeout
529
+ http.read_timeout = @timeout
530
+ # set request headers
531
+ headers = {}
532
+ headers['User-Agent'] = @user_agent unless @user_agent.nil?
533
+ headers['Cookie'] = opts['cookie'].to_s unless opts['cookie'].nil?
534
+ headers['Content-Type'] = 'application/x-www-form-urlencoded' if @method == 'POST'
535
+ response = {}
536
+ # send http request
537
+ begin
538
+ if @method == 'GET'
539
+ response = http.request Net::HTTP::Get.new(ssrf_url, headers.to_hash)
540
+ elsif @method == 'HEAD'
541
+ response = http.request Net::HTTP::Head.new(ssrf_url, headers.to_hash)
542
+ elsif @method == 'POST'
543
+ request = Net::HTTP::Post.new(ssrf_url, headers.to_hash)
544
+ request.body = post_data
545
+ response = http.request(request)
546
+ else
547
+ logger.info("SSRF request method not implemented - METHOD[#{@method}]")
548
+ response["status"] = 'fail'
549
+ response["code"] = 501
550
+ response["message"] = 'Error'
551
+ response["headers"] = "HTTP\/1.1 501 Error\nServer: SSRF Proxy\nContent-Length: 0\n\n"
552
+ end
553
+ rescue Timeout::Error,Errno::ETIMEDOUT
554
+ logger.warn("Connection timeout - TIMEOUT[#{@timeout}] - URI[#{url}]\n")
555
+ response["status"] = 'fail'
556
+ response["code"] = 504
557
+ response["message"] = 'Timeout'
558
+ response["headers"] = "HTTP\/1.1 504 Error\nServer: SSRF Proxy\nContent-Length: 0\n\n"
559
+ rescue => e
560
+ response["status"] = 'fail'
561
+ response["code"] = 500
562
+ response["message"] = 'Error'
563
+ response["headers"] = "HTTP\/1.1 500 Error\nServer: SSRF Proxy\nContent-Length: 0\n\n"
564
+ logger.error("Unhandled exception: #{e.message}: #{e}")
565
+ end
566
+ return response
567
+ end
568
+
569
+ #
570
+ # @note Parse HTTP response
571
+ #
572
+ # @options
573
+ # - response - Net::HTTPResponse - HTTP response object
574
+ #
575
+ # @returns - Hash - HTTP response object
576
+ #
577
+ def parse_http_response(response)
578
+ return response if response.class == Hash
579
+ result = {}
580
+ begin
581
+ result["status"] = 'complete'
582
+ result["http_version"] = response.http_version
583
+ result["code"] = response.code
584
+ result["message"] = response.message
585
+ if @guess_status
586
+ head = response.body[0..4096]
587
+ # generic page titles containing HTTP status
588
+ if head =~ />401 Unauthorized</
589
+ result["code"] = 401
590
+ result["message"] = 'Unauthorized'
591
+ elsif head =~ />403 Forbidden</
592
+ result["code"] = 403
593
+ result["message"] = 'Forbidden'
594
+ elsif head =~ />404 Not Found</
595
+ result["code"] = 404
596
+ result["message"] = 'Not Found'
597
+ elsif head =~ />500 Internal Server Error</
598
+ result["code"] = 500
599
+ result["message"] = 'Internal Server Error'
600
+ # getaddrinfo() errors
601
+ elsif head =~ /getaddrinfo: /
602
+ if head =~ /getaddrinfo: nodename nor servname provided/
603
+ result["code"] = 502
604
+ result["message"] = 'Bad Gateway'
605
+ elsif head =~ /getaddrinfo: Name or service not known/
606
+ result["code"] = 502
607
+ result["message"] = 'Bad Gateway'
608
+ end
609
+ # getnameinfo() errors
610
+ elsif head =~ /getnameinfo failed: /
611
+ result["code"] = 502
612
+ result["message"] = 'Bad Gateway'
613
+ # PHP 'failed to open stream' errors
614
+ elsif head =~ /failed to open stream: /
615
+ # HTTP request failed! HTTP/[version] [code] [message]
616
+ if head =~ /failed to open stream: HTTP request failed! HTTP\/(0\.9|1\.0|1\.1) ([\d]+) /
617
+ result["code"] = "#{$2}"
618
+ result["message"] = ''
619
+ if head =~ /failed to open stream: HTTP request failed! HTTP\/(0\.9|1\.0|1\.1) [\d]+ ([a-zA-Z ]+)/
620
+ result["message"] = "#{$2}"
621
+ end
622
+ # No route to host
623
+ elsif head =~ /failed to open stream: No route to host in/
624
+ result["code"] = 502
625
+ result["message"] = 'Bad Gateway'
626
+ # Connection refused
627
+ elsif head =~ /failed to open stream: Connection refused in/
628
+ result["code"] = 502
629
+ result["message"] = 'Bad Gateway'
630
+ # Connection timed out
631
+ elsif head =~ /failed to open stream: Connection timed out/
632
+ result["code"] = 504
633
+ result["message"] = 'Timeout'
634
+ end
635
+ # Java 'java.net.ConnectException' errors
636
+ elsif head =~ /java\.net\.ConnectException: /
637
+ # No route to host
638
+ if head =~ /java\.net\.ConnectException: No route to host/
639
+ result["code"] = 502
640
+ result["message"] = 'Bad Gateway'
641
+ # Connection refused
642
+ elsif head =~ /java\.net\.ConnectException: Connection refused/
643
+ result["code"] = 502
644
+ result["message"] = 'Bad Gateway'
645
+ # Connection timed out
646
+ elsif head =~ /java\.net\.ConnectException: Connection timed out/
647
+ result["code"] = 504
648
+ result["message"] = 'Timeout'
649
+ end
650
+ # Java 'java.net.UnknownHostException' errors
651
+ elsif head =~ /java\.net\.UnknownHostException: /
652
+ if head =~ /java\.net\.UnknownHostException: Invalid hostname/
653
+ result["code"] = 502
654
+ result["message"] = 'Bad Gateway'
655
+ end
656
+ # Python errors
657
+ elsif head =~ /\[Errno -?[\d]{1,3}\]/
658
+ if head =~ /\[Errno 113\] No route to host/
659
+ result["code"] = 502
660
+ result["message"] = 'Bad Gateway'
661
+ elsif head =~ /\[Errno -2\] Name or service not known/
662
+ result["code"] = 502
663
+ result["message"] = 'Bad Gateway'
664
+ elsif head =~ /\[Errno 111\] Connection refused/
665
+ result["code"] = 502
666
+ result["message"] = 'Bad Gateway'
667
+ elsif head =~ /\[Errno 110\] Connection timed out/
668
+ result["code"] = 504
669
+ result["message"] = 'Timeout'
670
+ end
671
+ # Ruby errors
672
+ elsif head =~ /Errno::[A-Z]+/
673
+ # Connection refused
674
+ if head =~ /Errno::ECONNREFUSED/
675
+ result["code"] = 502
676
+ result["message"] = 'Bad Gateway'
677
+ # No route to host
678
+ elsif head =~ /Errno::EHOSTUNREACH/
679
+ result["code"] = 502
680
+ result["message"] = 'Bad Gateway'
681
+ # Connection timed out
682
+ elsif head =~ /Errno::ETIMEDOUT/
683
+ result["code"] = 504
684
+ result["message"] = 'Timeout'
685
+ end
686
+ elsif head =~ /(Connection refused|No route to host) - connect\(\d\)/
687
+ # Connection refused
688
+ if head =~ /Connection refused - connect\(\d\)/
689
+ result["code"] = 502
690
+ result["message"] = 'Bad Gateway'
691
+ # No route to host
692
+ elsif head =~ /No route to host - connect\(\d\)/
693
+ result["code"] = 502
694
+ result["message"] = 'Bad Gateway'
695
+ # Connection timed out
696
+ elsif head =~ /Connection timed out - connect\(\d\)/
697
+ result["code"] = 504
698
+ result["message"] = 'Timeout'
699
+ end
700
+ end
701
+ logger.info "Using HTTP response status: #{result["code"]} #{result["message"]}"
702
+ end
703
+ result["headers"] = "HTTP\/#{result["http_version"]} #{result["code"]} #{result["message"]}\n"
704
+ response.each_header do |header_name, header_value|
705
+ if @strip.include?(header_name.downcase)
706
+ logger.info "Removed response header: #{header_name}"
707
+ next
708
+ end
709
+ result["headers"] << "#{header_name}: #{header_value}\n"
710
+ end
711
+ result["headers"] << "\n"
712
+ result["body"] = "#{response.body}" unless response.body.nil?
713
+ rescue => e
714
+ logger.info("Malformed HTTP response from server")
715
+ result["status"] = 'fail'
716
+ result["code"] = 502
717
+ result["message"] = 'Error'
718
+ result["headers"] = "HTTP\/1.1 502 Error\nServer: SSRF Proxy\nContent-Length: 0\n\n"
719
+ end
720
+ return result
721
+ end
722
+
723
+ #
724
+ # @note Guess content type based on file extension
725
+ # - List from: https://stackoverflow.com/questions/1029740/get-mime-type-from-filename-extension
726
+ #
727
+ # @options
728
+ # - ext - String - File extension [with dots] (Example: '.png')
729
+ #
730
+ # @returns String - content-type value
731
+ #
732
+ def guess_mime(ext)
733
+ content_types = %w(
734
+ 323,text/h323,
735
+ 3g2,video/3gpp2,
736
+ 3gp,video/3gpp,
737
+ 3gp2,video/3gpp2,
738
+ 3gpp,video/3gpp,
739
+ 7z,application/x-7z-compressed,
740
+ aa,audio/audible,
741
+ AAC,audio/aac,
742
+ aaf,application/octet-stream,
743
+ aax,audio/vnd.audible.aax,
744
+ ac3,audio/ac3,
745
+ aca,application/octet-stream,
746
+ accda,application/msaccess.addin,
747
+ accdb,application/msaccess,
748
+ accdc,application/msaccess.cab,
749
+ accde,application/msaccess,
750
+ accdr,application/msaccess.runtime,
751
+ accdt,application/msaccess,
752
+ accdw,application/msaccess.webapplication,
753
+ accft,application/msaccess.ftemplate,
754
+ acx,application/internet-property-stream,
755
+ AddIn,text/xml,
756
+ ade,application/msaccess,
757
+ adobebridge,application/x-bridge-url,
758
+ adp,application/msaccess,
759
+ ADT,audio/vnd.dlna.adts,
760
+ ADTS,audio/aac,
761
+ afm,application/octet-stream,
762
+ ai,application/postscript,
763
+ aif,audio/x-aiff,
764
+ aifc,audio/aiff,
765
+ aiff,audio/aiff,
766
+ air,application/vnd.adobe.air-application-installer-package+zip,
767
+ amc,application/x-mpeg,
768
+ application,application/x-ms-application,
769
+ art,image/x-jg,
770
+ asa,application/xml,
771
+ asax,application/xml,
772
+ ascx,application/xml,
773
+ asd,application/octet-stream,
774
+ asf,video/x-ms-asf,
775
+ ashx,application/xml,
776
+ asi,application/octet-stream,
777
+ asm,text/plain,
778
+ asmx,application/xml,
779
+ aspx,application/xml,
780
+ asr,video/x-ms-asf,
781
+ asx,video/x-ms-asf,
782
+ atom,application/atom+xml,
783
+ au,audio/basic,
784
+ avi,video/x-msvideo,
785
+ axs,application/olescript,
786
+ bas,text/plain,
787
+ bcpio,application/x-bcpio,
788
+ bin,application/octet-stream,
789
+ bmp,image/bmp,
790
+ c,text/plain,
791
+ cab,application/octet-stream,
792
+ caf,audio/x-caf,
793
+ calx,application/vnd.ms-office.calx,
794
+ cat,application/vnd.ms-pki.seccat,
795
+ cc,text/plain,
796
+ cd,text/plain,
797
+ cdda,audio/aiff,
798
+ cdf,application/x-cdf,
799
+ cer,application/x-x509-ca-cert,
800
+ chm,application/octet-stream,
801
+ class,application/x-java-applet,
802
+ clp,application/x-msclip,
803
+ cmx,image/x-cmx,
804
+ cnf,text/plain,
805
+ cod,image/cis-cod,
806
+ config,application/xml,
807
+ contact,text/x-ms-contact,
808
+ coverage,application/xml,
809
+ cpio,application/x-cpio,
810
+ cpp,text/plain,
811
+ crd,application/x-mscardfile,
812
+ crl,application/pkix-crl,
813
+ crt,application/x-x509-ca-cert,
814
+ cs,text/plain,
815
+ csdproj,text/plain,
816
+ csh,application/x-csh,
817
+ csproj,text/plain,
818
+ css,text/css,
819
+ csv,text/csv,
820
+ cur,application/octet-stream,
821
+ cxx,text/plain,
822
+ dat,application/octet-stream,
823
+ datasource,application/xml,
824
+ dbproj,text/plain,
825
+ dcr,application/x-director,
826
+ def,text/plain,
827
+ deploy,application/octet-stream,
828
+ der,application/x-x509-ca-cert,
829
+ dgml,application/xml,
830
+ dib,image/bmp,
831
+ dif,video/x-dv,
832
+ dir,application/x-director,
833
+ disco,text/xml,
834
+ dll,application/x-msdownload,
835
+ dll.config,text/xml,
836
+ dlm,text/dlm,
837
+ doc,application/msword,
838
+ docm,application/vnd.ms-word.document.macroEnabled.12,
839
+ docx,application/vnd.openxmlformats-officedocument.wordprocessingml.document,
840
+ dot,application/msword,
841
+ dotm,application/vnd.ms-word.template.macroEnabled.12,
842
+ dotx,application/vnd.openxmlformats-officedocument.wordprocessingml.template,
843
+ dsp,application/octet-stream,
844
+ dsw,text/plain,
845
+ dtd,text/xml,
846
+ dtsConfig,text/xml,
847
+ dv,video/x-dv,
848
+ dvi,application/x-dvi,
849
+ dwf,drawing/x-dwf,
850
+ dwp,application/octet-stream,
851
+ dxr,application/x-director,
852
+ eml,message/rfc822,
853
+ emz,application/octet-stream,
854
+ eot,application/octet-stream,
855
+ eps,application/postscript,
856
+ etl,application/etl,
857
+ etx,text/x-setext,
858
+ evy,application/envoy,
859
+ exe,application/octet-stream,
860
+ exe.config,text/xml,
861
+ fdf,application/vnd.fdf,
862
+ fif,application/fractals,
863
+ filters,Application/xml,
864
+ fla,application/octet-stream,
865
+ flr,x-world/x-vrml,
866
+ flv,video/x-flv,
867
+ fsscript,application/fsharp-script,
868
+ fsx,application/fsharp-script,
869
+ generictest,application/xml,
870
+ gif,image/gif,
871
+ group,text/x-ms-group,
872
+ gsm,audio/x-gsm,
873
+ gtar,application/x-gtar,
874
+ gz,application/x-gzip,
875
+ h,text/plain,
876
+ hdf,application/x-hdf,
877
+ hdml,text/x-hdml,
878
+ hhc,application/x-oleobject,
879
+ hhk,application/octet-stream,
880
+ hhp,application/octet-stream,
881
+ hlp,application/winhlp,
882
+ hpp,text/plain,
883
+ hqx,application/mac-binhex40,
884
+ hta,application/hta,
885
+ htc,text/x-component,
886
+ htm,text/html,
887
+ html,text/html,
888
+ htt,text/webviewhtml,
889
+ hxa,application/xml,
890
+ hxc,application/xml,
891
+ hxd,application/octet-stream,
892
+ hxe,application/xml,
893
+ hxf,application/xml,
894
+ hxh,application/octet-stream,
895
+ hxi,application/octet-stream,
896
+ hxk,application/xml,
897
+ hxq,application/octet-stream,
898
+ hxr,application/octet-stream,
899
+ hxs,application/octet-stream,
900
+ hxt,text/html,
901
+ hxv,application/xml,
902
+ hxw,application/octet-stream,
903
+ hxx,text/plain,
904
+ i,text/plain,
905
+ ico,image/x-icon,
906
+ ics,application/octet-stream,
907
+ idl,text/plain,
908
+ ief,image/ief,
909
+ iii,application/x-iphone,
910
+ inc,text/plain,
911
+ inf,application/octet-stream,
912
+ inl,text/plain,
913
+ ins,application/x-internet-signup,
914
+ ipa,application/x-itunes-ipa,
915
+ ipg,application/x-itunes-ipg,
916
+ ipproj,text/plain,
917
+ ipsw,application/x-itunes-ipsw,
918
+ iqy,text/x-ms-iqy,
919
+ isp,application/x-internet-signup,
920
+ ite,application/x-itunes-ite,
921
+ itlp,application/x-itunes-itlp,
922
+ itms,application/x-itunes-itms,
923
+ itpc,application/x-itunes-itpc,
924
+ IVF,video/x-ivf,
925
+ jar,application/java-archive,
926
+ java,application/octet-stream,
927
+ jck,application/liquidmotion,
928
+ jcz,application/liquidmotion,
929
+ jfif,image/pjpeg,
930
+ jnlp,application/x-java-jnlp-file,
931
+ jpb,application/octet-stream,
932
+ jpe,image/jpeg,
933
+ jpeg,image/jpeg,
934
+ jpg,image/jpeg,
935
+ js,application/x-javascript,
936
+ json,application/json,
937
+ jsx,text/jscript,
938
+ jsxbin,text/plain,
939
+ latex,application/x-latex,
940
+ library-ms,application/windows-library+xml,
941
+ lit,application/x-ms-reader,
942
+ loadtest,application/xml,
943
+ lpk,application/octet-stream,
944
+ lsf,video/x-la-asf,
945
+ lst,text/plain,
946
+ lsx,video/x-la-asf,
947
+ lzh,application/octet-stream,
948
+ m13,application/x-msmediaview,
949
+ m14,application/x-msmediaview,
950
+ m1v,video/mpeg,
951
+ m2t,video/vnd.dlna.mpeg-tts,
952
+ m2ts,video/vnd.dlna.mpeg-tts,
953
+ m2v,video/mpeg,
954
+ m3u,audio/x-mpegurl,
955
+ m3u8,audio/x-mpegurl,
956
+ m4a,audio/m4a,
957
+ m4b,audio/m4b,
958
+ m4p,audio/m4p,
959
+ m4r,audio/x-m4r,
960
+ m4v,video/x-m4v,
961
+ mac,image/x-macpaint,
962
+ mak,text/plain,
963
+ man,application/x-troff-man,
964
+ manifest,application/x-ms-manifest,
965
+ map,text/plain,
966
+ master,application/xml,
967
+ mda,application/msaccess,
968
+ mdb,application/x-msaccess,
969
+ mde,application/msaccess,
970
+ mdp,application/octet-stream,
971
+ me,application/x-troff-me,
972
+ mfp,application/x-shockwave-flash,
973
+ mht,message/rfc822,
974
+ mhtml,message/rfc822,
975
+ mid,audio/mid,
976
+ midi,audio/mid,
977
+ mix,application/octet-stream,
978
+ mk,text/plain,
979
+ mmf,application/x-smaf,
980
+ mno,text/xml,
981
+ mny,application/x-msmoney,
982
+ mod,video/mpeg,
983
+ mov,video/quicktime,
984
+ movie,video/x-sgi-movie,
985
+ mp2,video/mpeg,
986
+ mp2v,video/mpeg,
987
+ mp3,audio/mpeg,
988
+ mp4,video/mp4,
989
+ mp4v,video/mp4,
990
+ mpa,video/mpeg,
991
+ mpe,video/mpeg,
992
+ mpeg,video/mpeg,
993
+ mpf,application/vnd.ms-mediapackage,
994
+ mpg,video/mpeg,
995
+ mpp,application/vnd.ms-project,
996
+ mpv2,video/mpeg,
997
+ mqv,video/quicktime,
998
+ ms,application/x-troff-ms,
999
+ msi,application/octet-stream,
1000
+ mso,application/octet-stream,
1001
+ mts,video/vnd.dlna.mpeg-tts,
1002
+ mtx,application/xml,
1003
+ mvb,application/x-msmediaview,
1004
+ mvc,application/x-miva-compiled,
1005
+ mxp,application/x-mmxp,
1006
+ nc,application/x-netcdf,
1007
+ nsc,video/x-ms-asf,
1008
+ nws,message/rfc822,
1009
+ ocx,application/octet-stream,
1010
+ oda,application/oda,
1011
+ odc,text/x-ms-odc,
1012
+ odh,text/plain,
1013
+ odl,text/plain,
1014
+ odp,application/vnd.oasis.opendocument.presentation,
1015
+ ods,application/oleobject,
1016
+ odt,application/vnd.oasis.opendocument.text,
1017
+ one,application/onenote,
1018
+ onea,application/onenote,
1019
+ onepkg,application/onenote,
1020
+ onetmp,application/onenote,
1021
+ onetoc,application/onenote,
1022
+ onetoc2,application/onenote,
1023
+ orderedtest,application/xml,
1024
+ osdx,application/opensearchdescription+xml,
1025
+ p10,application/pkcs10,
1026
+ p12,application/x-pkcs12,
1027
+ p7b,application/x-pkcs7-certificates,
1028
+ p7c,application/pkcs7-mime,
1029
+ p7m,application/pkcs7-mime,
1030
+ p7r,application/x-pkcs7-certreqresp,
1031
+ p7s,application/pkcs7-signature,
1032
+ pbm,image/x-portable-bitmap,
1033
+ pcast,application/x-podcast,
1034
+ pct,image/pict,
1035
+ pcx,application/octet-stream,
1036
+ pcz,application/octet-stream,
1037
+ pdf,application/pdf,
1038
+ pfb,application/octet-stream,
1039
+ pfm,application/octet-stream,
1040
+ pfx,application/x-pkcs12,
1041
+ pgm,image/x-portable-graymap,
1042
+ pic,image/pict,
1043
+ pict,image/pict,
1044
+ pkgdef,text/plain,
1045
+ pkgundef,text/plain,
1046
+ pko,application/vnd.ms-pki.pko,
1047
+ pls,audio/scpls,
1048
+ pma,application/x-perfmon,
1049
+ pmc,application/x-perfmon,
1050
+ pml,application/x-perfmon,
1051
+ pmr,application/x-perfmon,
1052
+ pmw,application/x-perfmon,
1053
+ png,image/png,
1054
+ pnm,image/x-portable-anymap,
1055
+ pnt,image/x-macpaint,
1056
+ pntg,image/x-macpaint,
1057
+ pnz,image/png,
1058
+ pot,application/vnd.ms-powerpoint,
1059
+ potm,application/vnd.ms-powerpoint.template.macroEnabled.12,
1060
+ potx,application/vnd.openxmlformats-officedocument.presentationml.template,
1061
+ ppa,application/vnd.ms-powerpoint,
1062
+ ppam,application/vnd.ms-powerpoint.addin.macroEnabled.12,
1063
+ ppm,image/x-portable-pixmap,
1064
+ pps,application/vnd.ms-powerpoint,
1065
+ ppsm,application/vnd.ms-powerpoint.slideshow.macroEnabled.12,
1066
+ ppsx,application/vnd.openxmlformats-officedocument.presentationml.slideshow,
1067
+ ppt,application/vnd.ms-powerpoint,
1068
+ pptm,application/vnd.ms-powerpoint.presentation.macroEnabled.12,
1069
+ pptx,application/vnd.openxmlformats-officedocument.presentationml.presentation,
1070
+ prf,application/pics-rules,
1071
+ prm,application/octet-stream,
1072
+ prx,application/octet-stream,
1073
+ ps,application/postscript,
1074
+ psc1,application/PowerShell,
1075
+ psd,application/octet-stream,
1076
+ psess,application/xml,
1077
+ psm,application/octet-stream,
1078
+ psp,application/octet-stream,
1079
+ pub,application/x-mspublisher,
1080
+ pwz,application/vnd.ms-powerpoint,
1081
+ qht,text/x-html-insertion,
1082
+ qhtm,text/x-html-insertion,
1083
+ qt,video/quicktime,
1084
+ qti,image/x-quicktime,
1085
+ qtif,image/x-quicktime,
1086
+ qtl,application/x-quicktimeplayer,
1087
+ qxd,application/octet-stream,
1088
+ ra,audio/x-pn-realaudio,
1089
+ ram,audio/x-pn-realaudio,
1090
+ rar,application/octet-stream,
1091
+ ras,image/x-cmu-raster,
1092
+ rat,application/rat-file,
1093
+ rc,text/plain,
1094
+ rc2,text/plain,
1095
+ rct,text/plain,
1096
+ rdlc,application/xml,
1097
+ resx,application/xml,
1098
+ rf,image/vnd.rn-realflash,
1099
+ rgb,image/x-rgb,
1100
+ rgs,text/plain,
1101
+ rm,application/vnd.rn-realmedia,
1102
+ rmi,audio/mid,
1103
+ rmp,application/vnd.rn-rn_music_package,
1104
+ roff,application/x-troff,
1105
+ rpm,audio/x-pn-realaudio-plugin,
1106
+ rqy,text/x-ms-rqy,
1107
+ rtf,application/rtf,
1108
+ rtx,text/richtext,
1109
+ ruleset,application/xml,
1110
+ s,text/plain,
1111
+ safariextz,application/x-safari-safariextz,
1112
+ scd,application/x-msschedule,
1113
+ sct,text/scriptlet,
1114
+ sd2,audio/x-sd2,
1115
+ sdp,application/sdp,
1116
+ sea,application/octet-stream,
1117
+ searchConnector-ms,application/windows-search-connector+xml,
1118
+ setpay,application/set-payment-initiation,
1119
+ setreg,application/set-registration-initiation,
1120
+ settings,application/xml,
1121
+ sgimb,application/x-sgimb,
1122
+ sgml,text/sgml,
1123
+ sh,application/x-sh,
1124
+ shar,application/x-shar,
1125
+ shtml,text/html,
1126
+ sit,application/x-stuffit,
1127
+ sitemap,application/xml,
1128
+ skin,application/xml,
1129
+ sldm,application/vnd.ms-powerpoint.slide.macroEnabled.12,
1130
+ sldx,application/vnd.openxmlformats-officedocument.presentationml.slide,
1131
+ slk,application/vnd.ms-excel,
1132
+ sln,text/plain,
1133
+ slupkg-ms,application/x-ms-license,
1134
+ smd,audio/x-smd,
1135
+ smi,application/octet-stream,
1136
+ smx,audio/x-smd,
1137
+ smz,audio/x-smd,
1138
+ snd,audio/basic,
1139
+ snippet,application/xml,
1140
+ snp,application/octet-stream,
1141
+ sol,text/plain,
1142
+ sor,text/plain,
1143
+ spc,application/x-pkcs7-certificates,
1144
+ spl,application/futuresplash,
1145
+ src,application/x-wais-source,
1146
+ srf,text/plain,
1147
+ SSISDeploymentManifest,text/xml,
1148
+ ssm,application/streamingmedia,
1149
+ sst,application/vnd.ms-pki.certstore,
1150
+ stl,application/vnd.ms-pki.stl,
1151
+ sv4cpio,application/x-sv4cpio,
1152
+ sv4crc,application/x-sv4crc,
1153
+ svc,application/xml,
1154
+ swf,application/x-shockwave-flash,
1155
+ t,application/x-troff,
1156
+ tar,application/x-tar,
1157
+ tcl,application/x-tcl,
1158
+ testrunconfig,application/xml,
1159
+ testsettings,application/xml,
1160
+ tex,application/x-tex,
1161
+ texi,application/x-texinfo,
1162
+ texinfo,application/x-texinfo,
1163
+ tgz,application/x-compressed,
1164
+ thmx,application/vnd.ms-officetheme,
1165
+ thn,application/octet-stream,
1166
+ tif,image/tiff,
1167
+ tiff,image/tiff,
1168
+ tlh,text/plain,
1169
+ tli,text/plain,
1170
+ toc,application/octet-stream,
1171
+ tr,application/x-troff,
1172
+ trm,application/x-msterminal,
1173
+ trx,application/xml,
1174
+ ts,video/vnd.dlna.mpeg-tts,
1175
+ tsv,text/tab-separated-values,
1176
+ ttf,application/octet-stream,
1177
+ tts,video/vnd.dlna.mpeg-tts,
1178
+ txt,text/plain,
1179
+ u32,application/octet-stream,
1180
+ uls,text/iuls,
1181
+ user,text/plain,
1182
+ ustar,application/x-ustar,
1183
+ vb,text/plain,
1184
+ vbdproj,text/plain,
1185
+ vbk,video/mpeg,
1186
+ vbproj,text/plain,
1187
+ vbs,text/vbscript,
1188
+ vcf,text/x-vcard,
1189
+ vcproj,Application/xml,
1190
+ vcs,text/plain,
1191
+ vcxproj,Application/xml,
1192
+ vddproj,text/plain,
1193
+ vdp,text/plain,
1194
+ vdproj,text/plain,
1195
+ vdx,application/vnd.ms-visio.viewer,
1196
+ vml,text/xml,
1197
+ vscontent,application/xml,
1198
+ vsct,text/xml,
1199
+ vsd,application/vnd.visio,
1200
+ vsi,application/ms-vsi,
1201
+ vsix,application/vsix,
1202
+ vsixlangpack,text/xml,
1203
+ vsixmanifest,text/xml,
1204
+ vsmdi,application/xml,
1205
+ vspscc,text/plain,
1206
+ vss,application/vnd.visio,
1207
+ vsscc,text/plain,
1208
+ vssettings,text/xml,
1209
+ vssscc,text/plain,
1210
+ vst,application/vnd.visio,
1211
+ vstemplate,text/xml,
1212
+ vsto,application/x-ms-vsto,
1213
+ vsw,application/vnd.visio,
1214
+ vsx,application/vnd.visio,
1215
+ vtx,application/vnd.visio,
1216
+ wav,audio/wav,
1217
+ wave,audio/wav,
1218
+ wax,audio/x-ms-wax,
1219
+ wbk,application/msword,
1220
+ wbmp,image/vnd.wap.wbmp,
1221
+ wcm,application/vnd.ms-works,
1222
+ wdb,application/vnd.ms-works,
1223
+ wdp,image/vnd.ms-photo,
1224
+ webarchive,application/x-safari-webarchive,
1225
+ webtest,application/xml,
1226
+ wiq,application/xml,
1227
+ wiz,application/msword,
1228
+ wks,application/vnd.ms-works,
1229
+ WLMP,application/wlmoviemaker,
1230
+ wlpginstall,application/x-wlpg-detect,
1231
+ wlpginstall3,application/x-wlpg3-detect,
1232
+ wm,video/x-ms-wm,
1233
+ wma,audio/x-ms-wma,
1234
+ wmd,application/x-ms-wmd,
1235
+ wmf,application/x-msmetafile,
1236
+ wml,text/vnd.wap.wml,
1237
+ wmlc,application/vnd.wap.wmlc,
1238
+ wmls,text/vnd.wap.wmlscript,
1239
+ wmlsc,application/vnd.wap.wmlscriptc,
1240
+ wmp,video/x-ms-wmp,
1241
+ wmv,video/x-ms-wmv,
1242
+ wmx,video/x-ms-wmx,
1243
+ wmz,application/x-ms-wmz,
1244
+ wpl,application/vnd.ms-wpl,
1245
+ wps,application/vnd.ms-works,
1246
+ wri,application/x-mswrite,
1247
+ wrl,x-world/x-vrml,
1248
+ wrz,x-world/x-vrml,
1249
+ wsc,text/scriptlet,
1250
+ wsdl,text/xml,
1251
+ wvx,video/x-ms-wvx,
1252
+ x,application/directx,
1253
+ xaf,x-world/x-vrml,
1254
+ xaml,application/xaml+xml,
1255
+ xap,application/x-silverlight-app,
1256
+ xbap,application/x-ms-xbap,
1257
+ xbm,image/x-xbitmap,
1258
+ xdr,text/plain,
1259
+ xht,application/xhtml+xml,
1260
+ xhtml,application/xhtml+xml,
1261
+ xla,application/vnd.ms-excel,
1262
+ xlam,application/vnd.ms-excel.addin.macroEnabled.12,
1263
+ xlc,application/vnd.ms-excel,
1264
+ xld,application/vnd.ms-excel,
1265
+ xlk,application/vnd.ms-excel,
1266
+ xll,application/vnd.ms-excel,
1267
+ xlm,application/vnd.ms-excel,
1268
+ xls,application/vnd.ms-excel,
1269
+ xlsb,application/vnd.ms-excel.sheet.binary.macroEnabled.12,
1270
+ xlsm,application/vnd.ms-excel.sheet.macroEnabled.12,
1271
+ xlsx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,
1272
+ xlt,application/vnd.ms-excel,
1273
+ xltm,application/vnd.ms-excel.template.macroEnabled.12,
1274
+ xltx,application/vnd.openxmlformats-officedocument.spreadsheetml.template,
1275
+ xlw,application/vnd.ms-excel,
1276
+ xml,text/xml,
1277
+ xmta,application/xml,
1278
+ xof,x-world/x-vrml,
1279
+ XOML,text/plain,
1280
+ xpm,image/x-xpixmap,
1281
+ xps,application/vnd.ms-xpsdocument,
1282
+ xrm-ms,text/xml,
1283
+ xsc,application/xml,
1284
+ xsd,text/xml,
1285
+ xsf,text/xml,
1286
+ xsl,text/xml,
1287
+ xslt,text/xml,
1288
+ xsn,application/octet-stream,
1289
+ xss,application/xml,
1290
+ xtp,application/octet-stream,
1291
+ xwd,image/x-xwindowdump,
1292
+ z,application/x-compress,
1293
+ zip,application/x-zip-compressed )
1294
+ content_types.each do |type_info|
1295
+ if ext == ".#{type_info.split(',').first}"
1296
+ content_type = type_info.split(',')[1]
1297
+ return content_type
1298
+ end
1299
+ end
1300
+ nil
1301
+ end
1302
+
1303
+ private :parse_http_response,:send_http_request,:run_rules,:encode_ip,:guess_mime
1304
+
1305
+ end
1306
+ end