Module: PhusionPassenger::Utils

Extended by:
Utils
Included in:
AnalyticsLogger, MessageClient, RequestHandler, RequestHandler::ThreadHandler, Utils
Defined in:
lib/phusion_passenger/utils.rb,
lib/phusion_passenger/utils/json.rb,
lib/phusion_passenger/utils/tmpio.rb,
lib/phusion_passenger/utils/tmpdir.rb,
lib/phusion_passenger/utils/tee_input.rb,
lib/phusion_passenger/utils/ansi_colors.rb,
lib/phusion_passenger/utils/hosts_file_parser.rb,
lib/phusion_passenger/utils/unseekable_socket.rb,
lib/phusion_passenger/utils/file_system_watcher.rb

Overview

Utility functions.

Defined Under Namespace

Modules: AnsiColors Classes: FileSystemWatcher, GeneratorTest, HostsFileParser, JSON, ParserTest, TeeInput, TmpIO, UnseekableSocket

Constant Summary collapse

NULL =
"\0".freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(klass) ⇒ Object



37
38
39
40
41
42
43
# File 'lib/phusion_passenger/utils.rb', line 37

def self.included(klass)
	# When included into another class, make sure that Utils
	# methods are made private.
	public_instance_methods(false).each do |method_name|
		klass.send(:private, method_name)
	end
end

.mktmpdir(prefix_suffix = nil, tmpdir = nil) ⇒ Object

Like Dir.mktmpdir, but creates shorter filenames.



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/phusion_passenger/utils/tmpio.rb', line 34

def self.mktmpdir(prefix_suffix=nil, tmpdir=nil)
  case prefix_suffix
  when nil
    prefix = "d"
    suffix = ""
  when String
    prefix = prefix_suffix
    suffix = ""
  when Array
    prefix = prefix_suffix[0]
    suffix = prefix_suffix[1]
  else
    raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}"
  end
  tmpdir ||= Dir.tmpdir
  begin
    path = "#{tmpdir}/#{prefix}#{rand(0x100000000).to_s(36)}"
    path << suffix
    Dir.mkdir(path, 0700)
  rescue Errno::EEXIST
    retry
  end

  if block_given?
    begin
      yield path
    ensure
      FileUtils.remove_entry_secure path
    end
  else
    path
  end
end

Instance Method Details

#connect_to_server(address) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/phusion_passenger/utils.rb', line 93

def connect_to_server(address)
	case get_socket_address_type(address)
	when :unix
		return UNIXSocket.new(address.sub(/^unix:/, ''))
	when :tcp
		host, port = address.sub(%r{^tcp://}, '').split(':', 2)
		port = port.to_i
		return TCPSocket.new(host, port)
	else
		raise ArgumentError, "Unknown socket address type for '#{address}'."
	end
end

#generate_random_id(method) ⇒ Object

Generate a long, cryptographically secure random ID string, which is also a valid filename.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/phusion_passenger/utils.rb', line 47

def generate_random_id(method)
	data = File.open("/dev/urandom", "rb") do |f|
		f.read(64)
	end
	case method
	when :base64
		data = [data].pack('m')
		data.gsub!("\n", '')
		data.gsub!("+", '')
		data.gsub!("/", '')
		data.gsub!(/==$/, '')
		return data
	when :hex
		return data.unpack('H*')[0]
	else
		raise ArgumentError, "Invalid method #{method.inspect}"
	end
end

#get_socket_address_type(address) ⇒ Object



83
84
85
86
87
88
89
90
91
# File 'lib/phusion_passenger/utils.rb', line 83

def get_socket_address_type(address)
	if address =~ %r{^unix:.}
		return :unix
	elsif address =~ %r{^tcp://.}
		return :tcp
	else
		return :unknown
	end
end

#global_backtrace_reportObject

Returns a string which reports the backtraces for all threads, or if that’s not supported the backtrace for the current thread.



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/phusion_passenger/utils.rb', line 146

def global_backtrace_report
	if Kernel.respond_to?(:caller_for_all_threads)
		all_thread_stacks = caller_for_all_threads
	elsif Thread.respond_to?(:list) && Thread.public_method_defined?(:backtrace)
		all_thread_stacks = {}
		Thread.list.each do |thread|
			all_thread_stacks[thread] = thread.backtrace
		end
	end

	output = "========== Process #{Process.pid}: backtrace dump ==========\n"
	if all_thread_stacks
		all_thread_stacks.each_pair do |thread, stack|
			if thread_name = thread[:name]
				thread_name = "(#{thread_name})"
			end
			output << ("-" * 60) << "\n"
			output << "# Thread: #{thread.inspect}#{thread_name}, "
			if thread == Thread.main
				output << "[main thread], "
			end
			if thread == Thread.current
				output << "[current thread], "
			end
			output << "alive = #{thread.alive?}\n"
			output << ("-" * 60) << "\n"
			output << "    " << stack.join("\n    ")
			output << "\n\n"
		end
	else
		output << ("-" * 60) << "\n"
		output << "# Current thread: #{Thread.current.inspect}\n"
		output << ("-" * 60) << "\n"
		output << "    " << caller.join("\n    ")
	end
	return output
end

#install_options_as_ivars(object, options, *keys) ⇒ Object



138
139
140
141
142
# File 'lib/phusion_passenger/utils.rb', line 138

def install_options_as_ivars(object, options, *keys)
	keys.each do |key|
		object.instance_variable_set("@#{key}", options[key])
	end
end

#local_socket_address?(address) ⇒ Boolean

Returns:

  • (Boolean)


106
107
108
109
110
111
112
113
114
115
116
# File 'lib/phusion_passenger/utils.rb', line 106

def local_socket_address?(address)
	case get_socket_address_type(address)
	when :unix
		return true
	when :tcp
		host, port = address.sub(%r{^tcp://}, '').split(':', 2)
		return host == "127.0.0.1" || host == "::1" || host == "localhost"
	else
		raise ArgumentError, "Unknown socket address type for '#{address}'."
	end
end

Print the given exception, including the stack trace, to STDERR.

current_location is a string which describes where the code is currently at. Usually the current class name will be enough.



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

def print_exception(current_location, exception, destination = nil)
	if !exception.is_a?(SystemExit)
		data = exception.backtrace_string(current_location)
		if defined?(DebugLogging) && self.is_a?(DebugLogging)
			error(data)
		else
			destination ||= STDERR
			destination.puts(data)
			destination.flush if destination.respond_to?(:flush)
		end
	end
end

#process_is_alive?(pid) ⇒ Boolean

Checks whether the given process exists.

Returns:

  • (Boolean)


119
120
121
122
123
124
125
126
127
128
# File 'lib/phusion_passenger/utils.rb', line 119

def process_is_alive?(pid)
	begin
		Process.kill(0, pid)
		return true
	rescue Errno::ESRCH
		return false
	rescue SystemCallError => e
		return true
	end
end

#require_option(hash, key) ⇒ Object



130
131
132
133
134
135
136
# File 'lib/phusion_passenger/utils.rb', line 130

def require_option(hash, key)
	if hash.has_key?(key)
		return hash[key]
	else
		raise ArgumentError, "Option #{key.inspect} required"
	end
end

#split_by_null_into_hash(data) ⇒ Object

Split the given string into an hash. Keys and values are obtained by splitting the string using the null character as the delimitor.



187
188
189
# File 'lib/phusion_passenger/utils.rb', line 187

def split_by_null_into_hash(data)
	return PhusionPassenger::NativeSupport.split_by_null_into_hash(data)
end