Forum: Italian Ruby user group HTTPClient, problemi con put e delete

Posted by Marco Mastrodonato (marcomd)
on 2012-06-27 17:53
Ho testato le mie api con curl e funziona tutto, ora le devo utilizzare
con un'applicazione rails ed utilizzo la gemma in oggetto con la quale
però ho qualche problema con la richiesta put (e delete solo che di
questo non ricordo i dettagli). Get e post funzionano, col metodo
put non vengono utilizzati i parametri forniti alla chiamata:

@clnt = HTTPClient.new
res = @clnt.put("http://localhost:3001/api/v1/pippe/#{options[:id]}",
{:auth_token => @auth_token}.merge(options[:dati]))

i parametri vengono passati ma è come se put non li utilizzasse, non
arriva il token e giustamente ritorna un 401

Started PUT "/api/v1/pippe/2" for 127.0.0.1 at Wed Jun 27 17:31:23 +0200
2012
Processing by Api::V1::PippeController#update as JSON
  Parameters: {"id"=>"2"}
WARNING: Can't verify CSRF token authenticity
  User Load (0.0ms)  SELECT "users".* FROM "users" WHERE "users"."id" =
1 LIMIT 1
   (0.0ms)  begin transaction
   (0.0ms)  commit transaction
Completed 401 Unauthorized in 4ms

non ho spulciato il codice ma apparentemente sembra simile:

# File 'lib/httpclient.rb', line 595
def post(uri, body = '', extheader = {}, &block)
  request(:post, uri, nil, body, extheader, &block)
end

# File 'lib/httpclient.rb', line 600
def put(uri, body = '', extheader = {}, &block)
  request(:put, uri, nil, body, extheader, &block)
end



Qualcuno ha qualche idea?
Posted by Marco Mastrodonato (marcomd)
on 2012-06-27 18:36
E' un baco di HTTPClient:

#lib\httpclient.rb
#ho modificato il metodo create_request (riga 965)
aggiungendo questo codice:

      elsif ['DELETE', 'PUT'].include? method
        header << ['Content-Type', 'application/x-www-form-urlencoded']

ora i parametri vengono passati.
Non so se è un problema noto, io non ho trovato nulla. In questi casi si 
avvisa l'autore o si crea una patch? (non sono molto pratico)

Comunque ho risolto, ciao
Posted by Simone Carletti (weppos)
on 2012-06-27 18:49
(Received via mailing list)
Dando un veloce sguardo alla libreria che hai usato, ci sono due 
problemi
con la tua soluzione:

1. HTTPClient non accetta body per le chiamate DELETE (quindi 
quell'header
 inutile e potenzialmente errato)


  # Sends DELETE request to the specified URL.  See request for 
arguments.

  def delete(uri, *args, &block)
    request(:delete, uri, argument_to_hash(args, :header), &block)
  end

 2. Secondo l'implementazione, l'ordine dei parametri  uri, body, header

  # Sends PUT request to the specified URL.  See request for arguments.
  def put(uri, *args, &block)
    request(:put, uri, argument_to_hash(args, :body, :header), &block)
  end


Nel codice tu fai il merge del body con gli header e li passi come primo
parametro. Questo mi fa pensare che l'errore stia nel tuo uso di
HTTPClient. L'output della console pare essere d'accordo

*WARNING: Can't verify CSRF token authenticity*
 User Load (0.0ms)  SELECT "users".* FROM "users" WHERE "users"."id" =
1 LIMIT 1
  (0.0ms)  begin transaction
  (0.0ms)  commit transaction
*Completed 401 Unauthorized in 4ms*

Apparentemente, la tua richiesta non viene mai eseguita poich quella
chiamata  bloccata dall'autenticazione. Sono propenso a pensare che il 
bug
non sia in HTTPClient ma nella tua chiamata.

-- Simone


2012/6/27 Marco Mastrodonato <m.mastrodonato@gmail.com>

> Non so se  un problema noto, io non ho trovato nulla. In questi casi si
>
--
Simone Carletti
Application Developer

Site & Blog: http://www.simonecarletti.com/
LinkedIn: http://linkedin.com/in/weppos
Skype: weppos
Posted by Marco Mastrodonato (marcomd)
on 2012-06-27 19:15
Ciao Simone, in effetti ho dovuto modificare anche la chiamata del 
delete:

  def delete(uri, *args, &block)
    request(:delete, uri, argument_to_hash(args, :body, :header), 
&block)
  end

...non ho capito perchè non è stato previsto il body.

Il warning l'avevo notato ma non ho capito chi lo generava.
Ho usato la documentazione di HTTPClient anche se non è proprio 
aggiornatissima, indica l'ordine che ho usato io.

Ora devo scappare, domani controllo meglio, grazie comunque
Posted by Simone Carletti (weppos)
on 2012-06-27 19:28
(Received via mailing list)
2012/6/27 Marco Mastrodonato <m.mastrodonato@gmail.com>

> ...non ho capito perch non  stato previsto il body.


Le specifiche HTTP 1.0 n lo vietano n lo consentono. Non saprei le 1.1.
Di norma viene omesso (la maggior parte dei server HTTP lo ignora).

Mi viene da chiedere a cosa ti serva un body per cancellare una risorsa.
Quali parametri hai necessit di passare?


--
Simone Carletti
Application Developer

Site & Blog: http://www.simonecarletti.com/
LinkedIn: http://linkedin.com/in/weppos
Skype: weppos
Posted by Marco Mastrodonato (marcomd)
on 2012-06-28 09:44
Per utilizzare l'api è necessario fornire il token di autenticazione: il 
parametro che devo allegare a tutte le chiamate compresa la delete.
Posted by Simone Carletti (weppos)
on 2012-06-28 09:53
(Received via mailing list)
Non  necessario. Se vai a vedere il sorgente del modulo
RequestForgeryProtection<https://github.com/rails/rails/blob/3-2-stable/act...,
nello
specifico il metodo
verify_authenticity_token<https://github.com/rails/rails/blob/3-2-stable/act...
noterai
che dipende dal controllo


      def verified_request?

        !protect_against_forgery? || request.get? ||
          form_authenticity_token == 
params[request_forgery_protection_token] ||
          form_authenticity_token == request.headers['X-CSRF-Token']
      end

verified_request? ritorna true (quindi autorizza l'esecuzione) in 
diversi
casi, compreso nel caso in cui l'header http X-CSRF-Token sia presente e
corrisponda al token.

In altre parole,  sufficiente nelle tue chiamate API passare il token 
come
header HTTP per autorizzare la chiamata all'API, non serve simulare il
passaggio via parametro.

Quindi, almeno nel caso della DELETE, non ti serve body.

-- Simone


2012/6/28 Marco Mastrodonato <m.mastrodonato@gmail.com>

> Per utilizzare l'api  necessario fornire il token di autenticazione: il
> parametro che devo allegare a tutte le chiamate compresa la delete.
>
> --
> Posted via http://www.ruby-forum.com/.
> _______________________________________________
> Ml mailing list
> Ml@lists.ruby-it.org
> http://lists.ruby-it.org/mailman/listinfo/ml
>



--
Simone Carletti
Application Developer

Site & Blog: http://www.simonecarletti.com/
LinkedIn: http://linkedin.com/in/weppos
Skype: weppos
Posted by Marco Mastrodonato (marcomd)
on 2012-06-28 10:45
Grazie, stavo diventando matto a trovare quel warning!
Comunque non devo passare il token di rails ma quello per 
l'autenticazione in devise.
Posted by Simone Carletti (weppos)
on 2012-06-28 10:56
(Received via mailing list)
Sono quasi sicuro che anche devise accetti authenticazione via header o
querystring. :)

2012/6/28 Marco Mastrodonato <m.mastrodonato@gmail.com>

>
--
Simone Carletti
Application Developer

Site & Blog: http://www.simonecarletti.com/
LinkedIn: http://linkedin.com/in/weppos
Skype: weppos
Posted by Marco Mastrodonato (marcomd)
on 2012-06-28 12:25
Ecco, come non detto :)
Grazie
Posted by Marco Mastrodonato (marcomd)
on 2012-06-28 12:38
Simone, ho letto il tuo blog e ti ho mandato una mail, l'indirizzo con 
.name finale
Posted by Marco Mastrodonato (marcomd)
on 2012-07-16 16:24
Devise salva il token in un cookie che utilizza in automatico per cui è 
sufficiente il login dell'api e non serve più quindi passarlo come 
parametro. Con questa soluzione però deve essere fornita user e password 
per il login:

@clnt.post("#{@server}/api/users/sign_in", {"user_login[email]" => 
@user_login, "user_login[password]" => password})

E' un alternativa ma forse preferivo la precedente dove bastava fornire 
il token.

Comunque, stavo provando ad accedere con token nell'header seguendo gli 
esempi della documentazione:

https://github.com/nahi/httpclient/blob/master/sam...

puts clnt.get(target, nil, { "auth_token" => "eFRv9Jh5j6dzVxLxjQ6D" 
}).content

ma la chiamata è priva di quell'header ed infatti non funziona. Sto 
cercando di capire se sbaglio qualcosa, la sequenza di parametri della 
get coincide con l'esempio:

def get(uri, *args, &block)
  request(:get, uri, argument_to_hash(args, :query, :header, 
:follow_redirect), &block)
end
Posted by Marco Mastrodonato (marcomd)
on 2012-07-17 14:19
Sembra che devise che non supporti l'autenticazione con token su header, 
non ho indagato molto, ho risolto così:

https://gist.github.com/3129118
Posted by Marco Mastrodonato (marcomd)
on 2012-07-19 09:23
Giusto per completare il quadro, quà si parla di devise e token su 
header:
https://groups.google.com/forum/?fromgroups#!topic...
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.