• # Dans le même style en Ruby

    Posté par . En réponse au journal Sleipnir : proxy quick & dirty pour bien coder. Évalué à 4.

    Super idée, j'utilisais déjà un petit proxy Ruby écrit par Torsten Becker https://gist.github.com/74107 pour de sombres histoires d'ouvertures de flux qui ne passaient pas derrière un VPN … j'y ai donc ajouté la possibilité de remplacer un fichier "serveur" par un fichier local au proxy.

    L'utilisation est simple, il suffit de préciser le répertoire où sont stockés les fichiers à remplacer à la volée (par défaut /tmp). Dès que le client fait une demande (par exemple /styles/mon_style.css), si un fichier portant le même nom existe dans le répertoire local (exemple /tmp/mon_style.css) c'est ce dernier qui sera renvoyé. Du coup c'est un peu moins modulable que ton code, mais c'est facilement adaptable pour des besoins plus pointus.

    Le code fonctionne sur une installation "minimale" (pas de gems à installer) de Ruby (1.9 testé, mais doit fonctionner en 1.8).

    Le code :

    #!/usr/bin/env ruby
    # Proxy with local file replacement based on Torsten Becker <torsten.becker@gmail.com> ruby proxy https://gist.github.com/74107
    require 'socket'
    require 'uri'
    class Proxy
     def run port, local_path
     @local_path=local_path
     puts "Start proxy on port #{port}. Local file must be stored in #{local_path}."
     begin
     # Start our server to handle connections (will raise things on errors)
     @socket = TCPServer.new port
     # Handle every request in another thread
     loop do
     s = @socket.accept
     Thread.new s, &method(:handle_request)
     end
     # CTRL-C
     rescue Interrupt
     puts 'Got Interrupt..'
     # Ensure that we release the socket on errors
     ensure
     if @socket
     @socket.close
     puts 'Socked closed..'
     end
     puts 'Quitting.'
     end
     end
     def handle_request to_client
     request_line = to_client.readline
     verb = request_line[/^\w+/]
     url = request_line[/^\w+\s+(\S+)/, 1]
     version = request_line[/HTTP\/(1\.\d)\s*$/, 1]
     uri = URI::parse url
     # Show what got requested
     puts((" %4s "%verb) + url)
     filename=uri.path.split('/')[-1];
     to_server = TCPSocket.new(uri.host, (uri.port.nil? ? 80 : uri.port))
     to_server.write("#{verb}#{uri.path}?#{uri.query} HTTP/#{version}\r\n")
     content_len = 0
     loop do
     line = to_client.readline
     if line =~ /^Content-Length:\s+(\d+)\s*$/
     content_len = 1ドル.to_i
     end
     # Strip proxy headers
     if line =~ /^proxy/i
     next
     elsif line.strip.empty?
     to_server.write("Connection: close\r\n\r\n")
     if content_len >= 0
     to_server.write(to_client.read(content_len))
     end
     break
     else
     to_server.write(line)
     end
     end
     if FileTest.exists?(@local_path+filename) 
     to_server.close
     puts "Get file #{filename} from local directory #{@local_path}"
     to_server=File.new(@local_path+filename, "r") 
     end
     buff = ""
     loop do
     to_server.read(4048, buff)
     to_client.write(buff)
     break if buff.size < 4048
     end
     # Close the sockets
     to_client.close
     to_server.close
     end
    end
    def usage
     puts 'Usage: proxy.rb [port] [directory with local files]'
     exit 1
    end
    # Get parameters and start the server
    port=8008
    path="/tmp";
    ARGV.each do 
     |arg|
     if FileTest.directory?(arg) then path=arg
     elsif arg="-h" then usage
     elsif arg=~/^\d+/ then port=arg.to_i
     else usage 
     end
    end
    Proxy.new.run port, path