Ruby Forum Italian Ruby user group > Net::HTTP get

Posted by Catiana Trisolini (catiana)
on 21.07.2008 11:47
Ciao a tutti,
avrei bosigno di porvi un quesito.

Ho creato un programmino con Qt-ruby che fa la copia in locale di alcuni
file presenti su un server remoto.

La richiesta HTTP la faccio così:

resp=Net::HTTP.get(URI.parse('http://' + url + ':' + port + path))

dove url, port e path sono variabili settate in precedenza.

Una volta effettuati tutti i controlli sulla presenza o meno della
cartella di destinazione, eseguo la scrittura del file.

fileExport = File.new(dir + "/CVIn" + @countDir.to_s + "/" +
nameFile,"wb")
fileExport.write(resp)
fileExport.close

Però succede che mentre sta cercando di eseguire la get mi dà questo
genere di errore:

c:/ruby/lib/ruby/1.8/net/protocol.rb:84:in `<<': failed to allocate
memory (NoMe
moryError)
        from c:/ruby/lib/ruby/1.8/net/protocol.rb:84:in `read'
        from c:/ruby/lib/ruby/1.8/net/http.rb:2209:in `read_body_0'
        from c:/ruby/lib/ruby/1.8/net/http.rb:2170:in `read_body'
        from c:/ruby/lib/ruby/1.8/net/http.rb:2195:in `body'
        from c:/ruby/lib/ruby/1.8/net/http.rb:2134:in `reading_body'
        from c:/ruby/lib/ruby/1.8/net/http.rb:1049:in `request'
        from c:/ruby/lib/ruby/1.8/net/http.rb:945:in `request_get'
        from c:/ruby/lib/ruby/1.8/net/http.rb:380:in `get_response'
         ... 8 levels...
        from c:/ruby/lib/ruby/site_ruby/1.8/Qt/qtruby4.rb:241:in
`qt_metacall'
        from c:/ruby/lib/ruby/site_ruby/1.8/Qt/qtruby4.rb:241:in
`method_missing
'
        from c:/ruby/lib/ruby/site_ruby/1.8/Qt/qtruby4.rb:241:in `exec'
        from Export_main.rb:35

Io credo che l'errore sia legato al fatto che cerca di portare tutto in
RAM.

Qualcuno sa dirmi di più?
Qualcuno sa indicarmi un'alternativa?
Spero che la mia richiesta non resti inascoltata...

Grazie mille a tutti, anticipatamente

Catiana
Posted by Simone Scalabrino (intersimone999)
on 21.07.2008 12:45
Catiana Trisolini wrote:
> Ciao a tutti,
> avrei bosigno di porvi un quesito.
> 
> Ho creato un programmino con Qt-ruby che fa la copia in locale di alcuni
> file presenti su un server remoto.
> 
> La richiesta HTTP la faccio così:
> 
> resp=Net::HTTP.get(URI.parse('http://' + url + ':' + port + path))
> 
> dove url, port e path sono variabili settate in precedenza.
> 
> Una volta effettuati tutti i controlli sulla presenza o meno della
> cartella di destinazione, eseguo la scrittura del file.
> 
> fileExport = File.new(dir + "/CVIn" + @countDir.to_s + "/" +
> nameFile,"wb")
> fileExport.write(resp)
> fileExport.close
> 
> Però succede che mentre sta cercando di eseguire la get mi dà questo
> genere di errore:
> 
> c:/ruby/lib/ruby/1.8/net/protocol.rb:84:in `<<': failed to allocate
> memory (NoMe
> moryError)
>         from c:/ruby/lib/ruby/1.8/net/protocol.rb:84:in `read'
>         from c:/ruby/lib/ruby/1.8/net/http.rb:2209:in `read_body_0'
>         from c:/ruby/lib/ruby/1.8/net/http.rb:2170:in `read_body'
>         from c:/ruby/lib/ruby/1.8/net/http.rb:2195:in `body'
>         from c:/ruby/lib/ruby/1.8/net/http.rb:2134:in `reading_body'
>         from c:/ruby/lib/ruby/1.8/net/http.rb:1049:in `request'
>         from c:/ruby/lib/ruby/1.8/net/http.rb:945:in `request_get'
>         from c:/ruby/lib/ruby/1.8/net/http.rb:380:in `get_response'
>          ... 8 levels...
>         from c:/ruby/lib/ruby/site_ruby/1.8/Qt/qtruby4.rb:241:in
> `qt_metacall'
>         from c:/ruby/lib/ruby/site_ruby/1.8/Qt/qtruby4.rb:241:in
> `method_missing
> '
>         from c:/ruby/lib/ruby/site_ruby/1.8/Qt/qtruby4.rb:241:in `exec'
>         from Export_main.rb:35
> 
> Io credo che l'errore sia legato al fatto che cerca di portare tutto in
> RAM.
> 
> Qualcuno sa dirmi di più?
> Qualcuno sa indicarmi un'alternativa?
> Spero che la mia richiesta non resti inascoltata...
> 
> Grazie mille a tutti, anticipatamente
> 
> Catiana

Potresti anche fare un socket che legge piano piano il contenuto. Ad 
esempio:

path = "/"#Il percorso del documento sul server
nomefile = "result.txt" #Il nome del file in locale
server = "www.x.com" #Il nome del server (senza http:// nè il resto del 
percorso)
port = 80 #La porta del server

File.open(nomefile,"wb") {|f|} #Crea il file vuoto
sock = TCPSocket.new(server,port) #Si collega al server
sock.puts "GET #{path} HTTP/1.1\r\n" #Esegue una richiesta di tipo GET.
while select([sock],[],[],1.5)[0][0] == sock #Verifica che il socket sia 
pronto e che il file non sia finito
  export = File.open(nomefile, "a+") {|file| #Riapre il file in modalità 
Append
    file.write sock.recv(1024) #Scrive 1KB appena letto dal socket
  } #Chiude il file
end

Prova se funziona, in teoria non dovrebbe dare più errori come 
NoMemoryError (prendendo solo 1KB alla volta). Poi in base alla 
grandezza della ram e del file, puoi modificare il "1024" in recv.
Posted by Catiana Trisolini (catiana)
on 21.07.2008 14:57
> Potresti anche fare un socket che legge piano piano il contenuto. Ad 
> esempio:
> 
> path = "/"#Il percorso del documento sul server
> nomefile = "result.txt" #Il nome del file in locale
> server = "www.x.com" #Il nome del server (senza http:// nè il resto del 
> percorso)
> port = 80 #La porta del server
> 
> File.open(nomefile,"wb") {|f|} #Crea il file vuoto
> sock = TCPSocket.new(server,port) #Si collega al server
> sock.puts "GET #{path} HTTP/1.1\r\n" #Esegue una richiesta di tipo GET.
> while select([sock],[],[],1.5)[0][0] == sock #Verifica che il socket sia 
> pronto e che il file non sia finito
>   export = File.open(nomefile, "a+") {|file| #Riapre il file in modalità 
> Append
>     file.write sock.recv(1024) #Scrive 1KB appena letto dal socket
>   } #Chiude il file
> end
> 
> Prova se funziona, in teoria non dovrebbe dare più errori come 
> NoMemoryError (prendendo solo 1KB alla volta). Poi in base alla 
> grandezza della ram e del file, puoi modificare il "1024" in recv.


Ciao Simone,
prima di tutto grazie per aver risposto.

Mi dà però un'altro genere di errore:

undefined method `[]' for nil:NilClass

credo che il punto in cui si fermi sia questo:
while select([sock],[],[],1.5)[0][0] == sock

Grazie tante.
Catiana
Posted by Simone Scalabrino (intersimone999)
on 21.07.2008 16:04
Catiana Trisolini wrote:
>> Potresti anche fare un socket che legge piano piano il contenuto. Ad 
>> esempio:
>> 
>> path = "/"#Il percorso del documento sul server
>> nomefile = "result.txt" #Il nome del file in locale
>> server = "www.x.com" #Il nome del server (senza http:// nè il resto del 
>> percorso)
>> port = 80 #La porta del server
>> 
>> File.open(nomefile,"wb") {|f|} #Crea il file vuoto
>> sock = TCPSocket.new(server,port) #Si collega al server
>> sock.puts "GET #{path} HTTP/1.1\r\n" #Esegue una richiesta di tipo GET.
>> while select([sock],[],[],1.5)[0][0] == sock #Verifica che il socket sia 
>> pronto e che il file non sia finito
>>   export = File.open(nomefile, "a+") {|file| #Riapre il file in modalità 
>> Append
>>     file.write sock.recv(1024) #Scrive 1KB appena letto dal socket
>>   } #Chiude il file
>> end
>> 
>> Prova se funziona, in teoria non dovrebbe dare più errori come 
>> NoMemoryError (prendendo solo 1KB alla volta). Poi in base alla 
>> grandezza della ram e del file, puoi modificare il "1024" in recv.
> 
> 
> Ciao Simone,
> prima di tutto grazie per aver risposto.
> 
> Mi dà però un'altro genere di errore:
> 
> undefined method `[]' for nil:NilClass
> 
> credo che il punto in cui si fermi sia questo:
> while select([sock],[],[],1.5)[0][0] == sock
> 
> Grazie tante.
> Catiana

Vero, hai ragione. Infatti select ritorna "nil" se non va a buon fine. 
Quindi bisogna farlo separatamente:

risultato = true
while risultato
  ... (tutto quello di prima)
  risultato = select([sock],[],[],1.5)
  risultato = (risultato[0][0] == sock) if risultato != nil
end

Prova ora, spero che non dia altri errori.
Posted by Catiana Trisolini (catiana)
on 21.07.2008 16:48
> 
> Vero, hai ragione. Infatti select ritorna "nil" se non va a buon fine. 
> Quindi bisogna farlo separatamente:
> 
> risultato = true
> while risultato
>   ... (tutto quello di prima)
>   risultato = select([sock],[],[],1.5)
>   risultato = (risultato[0][0] == sock) if risultato != nil
> end
> 
> Prova ora, spero che non dia altri errori.

Ciao Simone,
credo ci sia ancora qualcosa che non va.
Mi spiego:

il codice, correggimi se sbaglio dovrebbe essere così:

path = @pathChildrennomefile = @em_mw.cmbDirectory.currentText + "/CVIn" 
+
                                                @countDir.to_s + "/" + 
nameFile
server = "10.0.0.1"
port = 9200
File.open(nomefile,"wb") {|f|} #Crea il file vuoto
risultato = true
sock = TCPSocket.new(server,port) #Si collega al server
sock.puts "GET #{path} HTTP/1.1\r\n" #Esegue una richiesta di tipo GET
while risultato
  export = File.open(nomefile, "a+") {|file|
    file.write(sock.recv(1024))
  } #Chiude il file
  risultato = select([sock],[],[],1.5)
  risultato = (risultato[0][0] == sock) if risultato != nil
end

Ora se provo a stampare a video sock.puts "GET #{path} HTTP/1.1\r\n
ciò che ho è nil; infatti il programmino sembra bloccarsi ma non genera 
errori.

Grazie mille per la tua disponibilità, davvero.

Catiana
Posted by Simone Scalabrino (intersimone999)
on 22.07.2008 00:09
> Ciao Simone,
> credo ci sia ancora qualcosa che non va.
> Mi spiego:
> 
> il codice, correggimi se sbaglio dovrebbe essere così:
> 
> path = @pathChildrennomefile = @em_mw.cmbDirectory.currentText + "/CVIn" 
> +
>                                                 @countDir.to_s + "/" + 
> nameFile
> server = "10.0.0.1"
> port = 9200
> File.open(nomefile,"wb") {|f|} #Crea il file vuoto
> risultato = true
> sock = TCPSocket.new(server,port) #Si collega al server
> sock.puts "GET #{path} HTTP/1.1\r\n" #Esegue una richiesta di tipo GET
> while risultato
>   export = File.open(nomefile, "a+") {|file|
>     file.write(sock.recv(1024))
>   } #Chiude il file
>   risultato = select([sock],[],[],1.5)
>   risultato = (risultato[0][0] == sock) if risultato != nil
> end
> 
> Ora se provo a stampare a video sock.puts "GET #{path} HTTP/1.1\r\n
> ciò che ho è nil; infatti il programmino sembra bloccarsi ma non genera 
> errori.
> 
> Grazie mille per la tua disponibilità, davvero.
> 
> Catiana

Sì, effettivamente ora che lo provo vedo che non funziona. Era sbagliata 
la richesta GET. Ecco la versione testata. Ancora ci dovrò lavorare un 
po', perché (provando con un file exe) non fa proprio un lavoro 
eccellente, però se si tratta di scaricare qualcosa di meno "preciso", 
va bene.


path = "/"#Il percorso del documento sul server
nomefile = "result.txt" #Il nome del file in locale
server = "www.google.it" #Il nome del server (senza http:// nè il resto 
del percorso)
port = 80 #La porta del server

File.open(nomefile,"wb") {|f|} #Crea il file vuoto
sock = TCPSocket.new(server,port) #Si collega al server
sock.puts "GET #{path} HTTP/1.1\r\nHost: #{server}\r\n\r\n" #Esegue una 
richiesta di tipo GET.
sock.recv(1024) #Riceve gli header non necessari
times = 0 #Serve a eliminare dal file la grandezza in byte dei dati che 
il server invia
loop do
  written = ""
  export = File.open(nomefile, "a+") {|file| #Riapre il file in modalità 
Append
    written=sock.recv(1024) #Scrive 1KB appena letto dal socket (senza 
scrivere gli header)
  if times == 0
    spltn = written.split("\r\n")
    file.write spltn[1,spltn.size-1].join("\r\n")
  else
    file.write written
  end
  } #Chiude il file
  if written.delete("\r\n") == "" or written.delete("\r\n") == "0"
  break
  end
  times += 1
end
Posted by Catiana Trisolini (catiana)
on 22.07.2008 12:53
> path = "/"#Il percorso del documento sul server
> nomefile = "result.txt" #Il nome del file in locale
> server = "www.google.it" #Il nome del server (senza http:// nè il resto 
> del percorso)
> port = 80 #La porta del server
> 
> File.open(nomefile,"wb") {|f|} #Crea il file vuoto
> sock = TCPSocket.new(server,port) #Si collega al server
> sock.puts "GET #{path} HTTP/1.1\r\nHost: #{server}\r\n\r\n" #Esegue una 
> richiesta di tipo GET.
> sock.recv(1024) #Riceve gli header non necessari
> times = 0 #Serve a eliminare dal file la grandezza in byte dei dati che 
> il server invia
> loop do
>   written = ""
>   export = File.open(nomefile, "a+") {|file| #Riapre il file in modalità 
> Append
>     written=sock.recv(1024) #Scrive 1KB appena letto dal socket (senza 
> scrivere gli header)
>   if times == 0
>     spltn = written.split("\r\n")
>     file.write spltn[1,spltn.size-1].join("\r\n")
>   else
>     file.write written
>   end
>   } #Chiude il file
>   if written.delete("\r\n") == "" or written.delete("\r\n") == "0"
>   break
>   end
>   times += 1
> end

Grazie mille Simone, ora funziona.
Non so davvero come ringraziarti!!
Sei stato gentilissimo.

Grazie ancora.

Catiana