2010-04-25 2 views
3

Bien que la spécification HTTP indique que les en-têtes ne respectent pas la casse; Paypal, avec sa nouvelle API de paiements adaptatifs, exige que ses en-têtes soient sensibles à la casse. En utilisant l'extension paypal adaptative pour ActiveMerchant (http://github.com/lamp/paypal_adaptive_gateway), il semble que bien que les en-têtes soient définis en majuscules, ils sont envoyés en casse mixte.Préservation des cas dans les en-têtes HTTP avec Ruby's Net: HTTP

Voici le code qui envoie la requête HTTP:

headers = { 
    "X-PAYPAL-REQUEST-DATA-FORMAT" => "XML", 
    "X-PAYPAL-RESPONSE-DATA-FORMAT" => "JSON", 
    "X-PAYPAL-SECURITY-USERID" => @config[:login], 
    "X-PAYPAL-SECURITY-PASSWORD" => @config[:password], 
    "X-PAYPAL-SECURITY-SIGNATURE" => @config[:signature], 
    "X-PAYPAL-APPLICATION-ID" => @config[:appid] 
} 
build_url action 

request = Net::HTTP::Post.new(@url.path) 

request.body = @xml 
headers.each_pair { |k,v| request[k] = v } 
request.content_type = 'text/xml' 

proxy = Net::HTTP::Proxy("127.0.0.1", "60723") 

server = proxy.new(@url.host, 443) 
server.use_ssl = true 

server.start { |http| http.request(request) }.body 

(i ajouté la ligne proxy afin que je puisse voir ce qui se passait avec Charles - http://www.charlesproxy.com/)

Quand je regarde la demande têtes dans charles, voici ce que je vois:

X-Paypal-Application-Id ... 
X-Paypal-Security-Password... 
X-Paypal-Security-Signature ... 
X-Paypal-Security-Userid ... 
X-Paypal-Request-Data-Format XML 
X-Paypal-Response-Data-Format JSON 
Accept */* 
Content-Type text/xml 
Content-Length 522 
Host svcs.sandbox.paypal.com 

J'ai vérifié que ce n'est pas Charles fait la conversion de cas en exécutant une requête similaire en utilisant curl. Dans ce test, le boîtier a été conservé.

Répondre

2

La RFC spécifie que les clés d'en-tête sont case-insensitive, donc malheureusement, vous semblez avoir atteint une exigence ennuyante avec l'API PayPal.

Net :: HTTP est ce qui change le cas, même si je suis surpris qu'ils ne sont pas tous s'en minuscule:

# File net/http.rb, line 1160 
    def []=(key, val) 
     unless val 
     @header.delete key.downcase 
     return val 
     end 
     @header[key.downcase] = [val] 
    end 

« définit le champ d'en-tête correspondant à la clé de la casse. »

Comme ce qui précède est une classe simple, il pourrait être patché par un singe. Je penserai plus loin pour une meilleure solution.

+0

ouais, singe-patcher est une option, mais vous auriez à singe-patch beaucoup plus que le [] = méthode ... à tout le moins, [ ] et write_header devraient aussi être corrigés (ce dernier est l'endroit où les en-têtes sont capitalisés lors de la sortie). – emh

+1

Voir la réponse à cette question: http://stackoverflow.com/questions/8864627/how-do-i-preserve-case-with-http-get – codingFoo

+1

Le vrai coupable est Net :: HTTPHeader # capitaliser –

1

Utilisez le code suivant pour forcer les en-têtes sensibles à la casse.

class CaseSensitivePost < Net::HTTP::Post 
    def initialize_http_header(headers) 
    @header = {} 
    headers.each{|k,v| @header[k.to_s] = [v] } 
    end 

    def [](name) 
    @header[name.to_s] 
    end 

    def []=(name, val) 
    if val 
     @header[name.to_s] = [val] 
    else 
     @header.delete(name.to_s) 
    end 
    end 

    def capitalize(name) 
    name 
    end 
end 

Exemple d'utilisation:

post = CaseSensitivePost.new(url, {myCasedHeader: '1'}) 
post.body = body 
http = Net::HTTP.new(host, port) 
http.request(post)