Class: Thin::Connection

Inherits:
EventMachine::Connection
  • Object
show all
Includes:
Logging
Defined in:
lib/thin/connection.rb

Overview

Connection between the server and client. This class is instanciated by EventMachine on each new connection that is opened.

Direct Known Subclasses

SwiftiplyConnection, UnixConnection

Constant Summary collapse

CONTENT_LENGTH =
'Content-Length'.freeze
TRANSFER_ENCODING =
'Transfer-Encoding'.freeze
CHUNKED_REGEXP =
/\bchunked\b/i.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Logging

#debug, debug, debug?, #log, log, #log_error, log_error, #silent, #silent=, silent?, #trace, trace, trace?

Instance Attribute Details

#appObject

Rack application (adapter) served by this connection.



15
16
17
# File 'lib/thin/connection.rb', line 15

def app
  @app
end

#backendObject

Backend to the server



18
19
20
# File 'lib/thin/connection.rb', line 18

def backend
  @backend
end

#requestObject

Current request served by the connection



21
22
23
# File 'lib/thin/connection.rb', line 21

def request
  @request
end

#responseObject

Next response sent through the connection



24
25
26
# File 'lib/thin/connection.rb', line 24

def response
  @response
end

#threaded=(value) ⇒ Object (writeonly)

Calling the application in a threaded allowing concurrent processing of requests.



28
29
30
# File 'lib/thin/connection.rb', line 28

def threaded=(value)
  @threaded = value
end

Instance Method Details

#can_persist!Object

Allows this connection to be persistent.



124
125
126
# File 'lib/thin/connection.rb', line 124

def can_persist!
  @can_persist = true
end

#can_persist?Boolean

Return true if this connection is allowed to stay open and be persistent.

Returns:

  • (Boolean)


129
130
131
# File 'lib/thin/connection.rb', line 129

def can_persist?
  @can_persist
end

#handle_errorObject

Logs catched exception and closes the connection.



98
99
100
101
102
# File 'lib/thin/connection.rb', line 98

def handle_error
  log "!! Unexpected error while processing request: #{$!.message}"
  log_error
  close_connection rescue nil
end

#persistent?Boolean

Return true if the connection must be left open and ready to be reused for another request.

Returns:

  • (Boolean)


135
136
137
# File 'lib/thin/connection.rb', line 135

def persistent?
  @can_persist && @response.persistent?
end

#post_initObject

Get the connection ready to process a request.



31
32
33
34
# File 'lib/thin/connection.rb', line 31

def post_init
  @request  = Request.new
  @response = Response.new
end

#post_process(result) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/thin/connection.rb', line 70

def post_process(result)
  return unless result

  # Set the Content-Length header if possible
  set_content_length(result) if need_content_length?(result)

  @response.status, @response.headers, @response.body = result

  log "!! Rack application returned nil body. Probably you wanted it to be an empty string?" if @response.body.nil?
  # Make the response persistent if requested by the client
  @response.persistent! if @request.persistent?

  # Send the response
  @response.each do |chunk|
    trace { chunk }
    send_data chunk
  end

  # If no more request on that same connection, we close it.
  close_connection_after_writing unless persistent?

rescue Exception
  handle_error
ensure
  terminate_request
end

#pre_processObject



58
59
60
61
62
63
64
65
66
67
68
# File 'lib/thin/connection.rb', line 58

def pre_process
  # Add client info to the request env
  @request.remote_address = remote_address

  # Process the request calling the Rack adapter
  @app.call(@request.env)
rescue Exception
  handle_error
  terminate_request
  nil # Signal to post_process that the request could not be processed
end

#processObject

Called when all data was received and the request is ready to be processed.



48
49
50
51
52
53
54
55
56
# File 'lib/thin/connection.rb', line 48

def process
  if threaded?
    @request.threaded = true
    EventMachine.defer(method(:pre_process), method(:post_process))
  else
    @request.threaded = false
    post_process(pre_process)
  end
end

#receive_data(data) ⇒ Object

Called when data is received from the client.



37
38
39
40
41
42
43
44
# File 'lib/thin/connection.rb', line 37

def receive_data(data)
  trace { data }
  process if @request.parse(data)
rescue InvalidRequest => e
  log "!! Invalid request"
  log_error e
  close_connection
end

#remote_addressObject

IP Address of the remote client.



147
148
149
150
151
152
# File 'lib/thin/connection.rb', line 147

def remote_address
  @request.forwarded_for || socket_address
rescue Exception
  log_error
  nil
end

#terminate_requestObject

Does request and response cleanup (closes open IO streams and deletes created temporary files). Re-initializes response and request if client supports persistent connection.



108
109
110
111
112
113
114
115
# File 'lib/thin/connection.rb', line 108

def terminate_request
  @request.close  rescue nil
  @response.close rescue nil

  # Prepare the connection for another request if the client
  # supports HTTP pipelining (persistent connection).
  post_init if persistent?
end

#threaded?Boolean

true if app.call will be called inside a thread. You can set all requests as threaded setting Connection#threaded=true or on a per-request case returning true in app.deferred?.

Returns:

  • (Boolean)


142
143
144
# File 'lib/thin/connection.rb', line 142

def threaded?
  @threaded || (@app.respond_to?(:deferred?) && @app.deferred?(@request.env))
end

#unbindObject

Called when the connection is unbinded from the socket and can no longer be used to process requests.



119
120
121
# File 'lib/thin/connection.rb', line 119

def unbind
  @backend.connection_finished(self)
end