HTTPClient, problemi con put e delete

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?

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

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

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

  1. 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 M. [email protected]

Non so se un problema noto, io non ho trovato nulla. In questi casi si


Simone C.
Application Developer

Site & Blog: http://www.simonecarletti.com/
LinkedIn: http://linkedin.com/in/weppos
Skype: weppos

2012/6/27 Marco M. [email protected]

…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 C.
Application Developer

Site & Blog: http://www.simonecarletti.com/
LinkedIn: http://linkedin.com/in/weppos
Skype: weppos

Per utilizzare l’api è necessario fornire il token di autenticazione: il
parametro che devo allegare a tutte le chiamate compresa la delete.

Grazie, stavo diventando matto a trovare quel warning!
Comunque non devo passare il token di rails ma quello per
l’autenticazione in devise.

Non necessario. Se vai a vedere il sorgente del modulo
RequestForgeryProtectionhttps://github.com/rails/rails/blob/3-2-stable/actionpack/lib/action_controller/metal/request_forgery_protection.rb,
nello
specifico il metodo
verify_authenticity_tokenhttps://github.com/rails/rails/blob/3-2-stable/actionpack/lib/action_controller/metal/request_forgery_protection.rb#L75
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 M. [email protected]

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
[email protected]
http://lists.ruby-it.org/mailman/listinfo/ml


Simone C.
Application Developer

Site & Blog: http://www.simonecarletti.com/
LinkedIn: http://linkedin.com/in/weppos
Skype: weppos

Sono quasi sicuro che anche devise accetti authenticazione via header o
querystring. :slight_smile:

2012/6/28 Marco M. [email protected]


Simone C.
Application Developer

Site & Blog: http://www.simonecarletti.com/
LinkedIn: http://linkedin.com/in/weppos
Skype: weppos

Ecco, come non detto :slight_smile:
Grazie

Simone, ho letto il tuo blog e ti ho mandato una mail, l’indirizzo con
.name finale

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:

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

Sembra che devise che non supporti l’autenticazione con token su header,
non ho indagato molto, ho risolto così:

Giusto per completare il quadro, quà si parla di devise e token su
header:
https://groups.google.com/forum/?fromgroups#!topic/plataformatec-devise/o3Gqgl0yUZo