unless Excon.mocking?

  module Excon
    class Connection

      def initialize(url)
        @uri = URI.parse(url)
      end

      def request(params)
        begin
          params[:path] ||= ''
          unless params[:path][0..0] == '/'
            params[:path] = "/#{params[:path]}"
          end
          if params[:query] && !params[:query].empty?
            params[:path] << "?#{params[:query]}"
          end
          request = "#{params[:method]} #{params[:path]} HTTP/1.1\r\n"
          params[:headers] ||= {}
          params[:headers]['Host'] = params[:host] || @uri.host
          if params[:body] && !params[:headers]['Content-Length']
            params[:headers]['Content-Length'] = params[:body].length
          end
          for key, value in params[:headers]
            request << "#{key}: #{value}\r\n"
          end
          request << "\r\n"
          connection.write(request)

          if params[:body]
            if params[:body].is_a?(String)
              connection.write(params[:body])
            else
              while chunk = params[:body].read(CHUNK_SIZE)
                connection.write(chunk)
              end
            end
          end

          response = Excon::Response.new
          response.status = connection.readline[9..11].to_i
          while true
            data = connection.readline.chop!
            unless data.empty?
              key, value = data.split(': ')
              response.headers[key] = value
            else
              break
            end
          end

          unless params[:method] == 'HEAD'
            block = if !params[:block] || (params[:expects] && ![*params[:expects]].include?(response.status))
              response.body = ''
              lambda { |chunk| response.body << chunk }
            else
              params[:block]
            end

            if response.headers['Content-Length']
              remaining = response.headers['Content-Length'].to_i
              while remaining > 0
                block.call(connection.read([CHUNK_SIZE, remaining].min))
                remaining -= CHUNK_SIZE
              end
            elsif response.headers['Transfer-Encoding'] == 'chunked'
              while true
                chunk_size = connection.readline.chop!.to_i(16)
                chunk = connection.read(chunk_size + 2).chop! # 2 == "/r/n".length
                if chunk_size > 0
                  block.call(chunk)
                else
                  break
                end
              end
            elsif response.headers['Connection'] == 'close'
              block.call(connection.read)
              Thread.current[:_excon_connection] = nil
            end
          end
        rescue => connection_error
          Thread.current[:_excon_connection] = nil
          raise(connection_error)
        end

        if params[:expects] && ![*params[:expects]].include?(response.status)
          Thread.current[:_excon_connection] = nil
          raise(Excon::Errors.status_error(params, response))
        else
          response
        end

      rescue => request_error
        if params[:idempotent] &&
            (!request_error.is_a?(Excon::Errors::Error) || response.status != 404)
          retries_remaining ||= 4
          retries_remaining -= 1
          if retries_remaining > 0
            retry
          end
        else
          raise(request_error)
        end
      end

      private

      def connection
        if !Thread.current[:_excon_connection] || Thread.current[:_excon_connection].closed?
          Thread.current[:_excon_connection] = establish_connection
        end
        Thread.current[:_excon_connection]
      end

      def establish_connection
        connection = TCPSocket.open(@uri.host, @uri.port)

        if @uri.scheme == 'https'
          @ssl_context = OpenSSL::SSL::SSLContext.new
          @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
          connection = OpenSSL::SSL::SSLSocket.new(connection, @ssl_context)
          connection.sync_close = true
          connection.connect
        end

        connection
      end
    end
  end

else

  module Excon
    class Connection

      def initialize(url)
      end

      def request(params)
        for key in Excon.mocks.keys
          if key == params
            response = Excon.mocks[key]
            break
          end
        end
        unless response
          response = Excon::Response.new
          response.status = 404
          response.headers = { 'Content-Length' => 0 }
        end

        if params[:expects] && ![*params[:expects]].include?(response.status)
          raise(Excon::Errors.status_error(params[:expects], response.status, response))
        else
          response
        end

      rescue => request_error
        if params[:idempotent]
          retries_remaining ||= 3
          retries_remaining -= 1
          if retries_remaining > 0
            retry
          end
        else
          raise(request_error)
        end
      end

    end
  end

end