54 lines
1.6 KiB
Ruby
54 lines
1.6 KiB
Ruby
require 'socket'
|
|
require 'uri'
|
|
require 'json'
|
|
|
|
#
|
|
# minimal http server for DataPipeline::RestStorage tests, one request per connection
|
|
# server = TestHttpServer.new { |req| [200, { 'items' => [] }] }
|
|
# req: { method:, path:, query:, headers:, body: } -> [status, hash/array or string, optional headers]
|
|
#
|
|
class TestHttpServer
|
|
attr_reader :requests
|
|
|
|
def initialize(&handler)
|
|
@handler = handler
|
|
@requests = []
|
|
@server = TCPServer.new('127.0.0.1', 0)
|
|
@thread = Thread.new { loop { serve(@server.accept) } }
|
|
end
|
|
|
|
def url = "http://127.0.0.1:#{@server.addr[1]}"
|
|
|
|
def stop
|
|
@thread.kill
|
|
@server.close
|
|
end
|
|
|
|
private
|
|
|
|
def serve client
|
|
method, target = client.gets.to_s.split
|
|
return unless method
|
|
|
|
headers = {}
|
|
while (line = client.gets) && line != "\r\n"
|
|
key, value = line.split(':', 2)
|
|
headers[key.downcase] = value.strip
|
|
end
|
|
body = headers['content-length'] ? client.read(headers['content-length'].to_i) : ''
|
|
path, query = target.split('?', 2)
|
|
request = { method:, path:, query: URI.decode_www_form(query.to_s).to_h, headers:, body: }
|
|
@requests << request
|
|
|
|
status, payload, extra = @handler.call(request)
|
|
text = payload.is_a?(String) ? payload : JSON.generate(payload)
|
|
extra = Hash(extra).map { |key, value| "#{key}: #{value}\r\n" }.join
|
|
client.write "HTTP/1.1 #{status} X\r\nContent-Type: application/json\r\n#{extra}" \
|
|
"Content-Length: #{text.bytesize}\r\nConnection: close\r\n\r\n#{text}"
|
|
rescue StandardError => e
|
|
warn "TestHttpServer: #{e.class}: #{e.message}"
|
|
ensure
|
|
client.close
|
|
end
|
|
end
|