lib/proxy.rb

Summary

Maintainability
A
2 hrs
Test Coverage
require "net/http"
require "enumerator"

module Peas
  class Proxy
    def call(env)
      req = Rack::Request.new(env)
      method = req.request_method.downcase
      method[0..0] = method[0..0].upcase

      uri = find_destination(req)
      return [200, {}, ["Peas has no application at this address"]] unless uri

      sub_request = Net::HTTP.const_get(method).new("#{uri.path}#{'?' if uri.query}#{uri.query}")

      if sub_request.request_body_permitted? && req.body
        sub_request.body_stream = req.body
        sub_request.content_length = req.content_length
        sub_request.content_type = req.content_type
      end

      sub_request["X-Forwarded-For"] = (req.env["X-Forwarded-For"].to_s.split(/, +/) + [req.env['REMOTE_ADDR']]).join(", ")
      sub_request["Accept-Encoding"] = req.accept_encoding
      sub_request["Referer"] = req.referer

      begin
        sub_response = Net::HTTP.start(uri.host, uri.port) do |http|
          http.request(sub_request)
        end
      rescue EOFError
        Peas::API.logger.error @random_web_pea.app.recent_logs(10)
        return [
          500,
          {},
          ["The application '#{@random_web_pea.app.name}' didn't respond. Please check the logs and try again."]
        ]
      end

      headers = {}
      sub_response.each_header do |k, v|
        headers[k] = v unless k.to_s =~ /cookie|content-length|transfer-encoding/i
      end

      [sub_response.code.to_i, headers, [sub_response.read_body]]
    end

    def find_destination(req)
      peas_part = Peas.host.split('.').first # Eg; 'peas' from 'peas.io'
      req_part = req.host.split('.').first # Eg; 'appname' from 'appname.peas.io'
      return false if peas_part == req_part # If there's no subdomain
      app_name = req_part
      app = App.where(name: app_name).first
      @random_web_pea = Pea.where(app: app).where(process_type: 'web').to_a.sample
      return false if @random_web_pea.nil?
      forwarding_address = "http://#{@random_web_pea.pod.hostname}:#{@random_web_pea.port}#{req.path}"
      Peas.logger.info "Proxying request to: #{forwarding_address}"
      URI.parse forwarding_address
    end
  end
end