Module: Nut::Handler

Extended by:
RxIO::IOFilters::BinDelim
Defined in:
lib/nut/handler.rb

Overview

Service Handler Module

Constant Summary collapse

SUPPORTED_VERSION =

Only handle HTTP/1.1 Requests

'http/1.1'

Class Method Summary collapse

Class Method Details

.assemble_process_req(creq, msg) ⇒ Object

Assemble & Process Request Assembles and processes HTTP Requests from individual data lines.

Parameters:

  • creq (Hash)

    Client Request Context

  • msg (String)

    The message received from the Client (including newline)



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/nut/handler.rb', line 113

def self.assemble_process_req creq, msg

  # Register Request Line
  creq[:lines] << msg

  # Build Request Line
  Request.build_req_line creq, msg

  # Check Version
  raise "Unsupported HTTP Version [#{creq[:version]}]" unless creq[:version].downcase == SUPPORTED_VERSION

  # Build Headers
  Request.build_header creq, msg

  # Build Request Body
  Request.build_req_body creq, msg

  # Process Request when Complete
  process_req creq[:client]
end

.ensure_creq(client) ⇒ Object

Ensure Client Request Hash Ensures existence of Client Request Hash inside Client Context.

Parameters:

  • client (Hash)

    An RxIO Client Hash



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/nut/handler.rb', line 83

def self.ensure_creq client

  # Ensure Client Request Structure is available
  client[:nut] ||= {}
  client[:nut][:req] ||= {

    # Request Lines (full request, including headers)
    lines: [],

    # Request Headers
    headz: {},

    # Full Request Line (including verb, URI and version)
    req_l: nil,

    # Full Request Body (just the body though, no headers)
    req_b: '',

    # Chunk Info (for Chunked Transfer-Encoding)
    chunk: {},

    # Client
    client: client
  }
end

.handle_msg(client, msg) ⇒ Object

Handle Message RxIO Service Interface Callback - Triggered each time a message is received from a Client.

Parameters:

  • client (Hash)

    An RxIO Client Hash

  • msg (String)

    The message received from the Client



48
49
50
51
52
# File 'lib/nut/handler.rb', line 48

def self.handle_msg client, msg

  # Pass Full Message to Request Builder (including Message Delimiter)
  handle_req_dline client, msg + @msg_delim
end

.handle_req_dline(client, msg) ⇒ Object

Handle Request Data Line Ensures availability of a Client Request Context before passing Assembling & Processing.

Parameters:

  • client (Hash)

    An RxIO Client Hash

  • msg (String)

    The message received from the Client (including newline)



71
72
73
74
75
76
77
78
# File 'lib/nut/handler.rb', line 71

def self.handle_req_dline client, msg

  # Ensure & Acquire Client Request Context
  creq = ensure_creq client

  # Assemble & Process
  assemble_process_req creq, msg unless creq[:body_complete]
end

.on_drop(client) ⇒ Object

On Drop RxIO Service Interface Callback - Triggered each time a Client disconnects.

Parameters:

  • client (Hash)

    An RxIO Client Hash



40
41
42
# File 'lib/nut/handler.rb', line 40

def self.on_drop client
  # NoOp
end

.on_join(client) ⇒ Object

On Join RxIO Service Interface Callback - Triggered each time a Client connects.

Parameters:

  • client (Hash)

    An RxIO Client Hash



33
34
35
# File 'lib/nut/handler.rb', line 33

def self.on_join client
  # NoOp
end

.process_req(client) ⇒ Object

Process Request for Client Constructs a complete Request Hash from a Client Request Context and passes it to the Request Handler Module’s handle_req method.

Parameters:

  • client (Hash)

    An RxIO Client Hash



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/nut/handler.rb', line 137

def self.process_req client

  # Check Request Body Complete
  return unless client[:nut][:req][:body_complete]

  # Pull Request Hash & Complete
  creq = client[:nut].delete :req
  uri = URI.parse creq[:uri]
  request = {
    peer: client[:peer].dclone,
    verb: creq[:verb].downcase.to_sym,
    uri: uri,
    body: creq[:req_b],
    ctype: creq[:ctype],
    params: Hash[*(CGI.parse(uri.query || '').inject([]) { |a, e| a + [e.first, (e.last.size == 1) ? e.last.first : e.last] })].sym_keys,
    headers: creq[:headz].dclone
  }

  # Pull all Request Details
  Request.extract_req_data request

  # Prepare Response
  response = { body: '' }

  # Pass to Request Handler
  client[:serv].request_handler.handle request, response

  # Respond to Client
  serve_response client, response
end

.serve_response(client, response) ⇒ Object

Serve Response Sends out an HTTP Response to the Client.

Parameters:

  • response (Hash)

    Response Hash



171
172
173
174
175
# File 'lib/nut/handler.rb', line 171

def self.serve_response client, response

  # Send out Response String
  write client, Response.build_response(response)
end

.subprocess_input(client) ⇒ Object

Sub-Process Input RxIO Service Interface Callback - Triggered each time a chunk of data is received from a Client. Some Content-Length-based Requests may not end with a CRLF - this pulls in any left-over data directly from the RxIO Input Buffer.

Parameters:

  • client (Hash)

    Client Hash



58
59
60
61
62
63
64
65
# File 'lib/nut/handler.rb', line 58

def self.subprocess_input client

  # Acquire Client Request Context Hash
  creq = client[:nut].try(:[], :req) || {}

  # Pull any left-overs from Input Buffer for Content-Length Requests
  handle_req_dline client, creq[:client][:ibuf].slice!(0, creq[:client][:ibuf].bytesize) if Request.is_content_len? creq
end