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.



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

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)


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

def can_persist?
  @can_persist
end

#handle_errorObject



96
97
98
99
100
# File 'lib/thin/connection.rb', line 96

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)


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

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
# 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
  
  # 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 Object
  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 Object
  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.



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

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

#terminate_requestObject



102
103
104
105
106
107
108
109
# File 'lib/thin/connection.rb', line 102

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)


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

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.



113
114
115
# File 'lib/thin/connection.rb', line 113

def unbind
  @backend.connection_finished(self)
end