2012-01-14 4 views
3

У меня есть требование отправить HTTP-заголовок в конкретный случай символов. Я знаю, что это противоречит RFC, но у меня есть требование.Как сохранить случай с http.get?

http.get, похоже, изменяет регистр словарей, который я предоставляю. Как я могу сохранить характерный случай?

+0

Часто требования (по крайней мере, частично) спорно. И если ваше «требование» - нарушить спецификацию HTTP, вам следует обсудить ад с вашего клиента. Вещи ** будут ** по пути, и вам будет трудно адаптироваться к каждому новому компоненту, который вы вводите. Это включает в себя такие вещи, как прокси, loadbalancers, брандмауэры и веб-серверы. Все эти люди должны будут работать с вашими изменениями, чего очень трудно добиться в каждом случае. Вы должны попытаться найти другое решение или вы будете страдать от боли навсегда :) –

+0

Мне нужно взаимодействовать с сторонней системой, которая нарушает работу rfc. Не так много. –

+1

[FIX ALL THE SYSTEMS] (http://i.stack.imgur.com/UXBEb.jpg) –

ответ

13

Основываясь на ответ Дровосека о том, что библиотека Net::HTTP звонит #downcase на ключе пользовательского заголовка (и все ключи заголовков), вот некоторые дополнительные опции, которые не обезьяна патча всего Net::HTTP.

Вы можете попробовать это:

custom_header_key = "X-miXEd-cASe" 
def custom_header_key.downcase 
    self 
end 

Чтобы избежать очистки кэша метод, либо сохранить результат выше в уровне класса постоянной:

custom_header_key = "X-miXEd-cASe" 
def custom_header_key.downcase 
    self 
end 
CUSTOM_HEADER_KEY = custom_header_key 

или подкласс Струнный чтобы переопределить конкретное поведение:

class StringWithIdentityDowncase < String 
    def downcase 
    self 
    end 
end 

custom_header_key = StringWithIdentityDowncase.new("X-miXEd-cASe") 
+0

+1 Я не думал об отключении метода 'downcase', но это то, что в принципе это делает. Это дает мне право голоса. У патчей обезьян слишком много запаха кода. –

+1

Я советую шляпу вам, сэр! Одна нота: мне пришлось переопределить метод «capizeize» таким же образом, как и метод downcase для его работы. – codingFoo

2

Mine - это один из способов сделать это, но я рекомендую это делать, поскольку @yfeldblum рекомендует, просто короткое замыкание downcase для клавиш заголовка, которые должны иметь свой случай влево.


В нескольких местах в Net :: HTTP :: HTTPHeader заголовки получить сложенном строчные, используя downcase.

Я думаю, что это довольно решительно изменить это поведение, но это сделает это. Добавьте это в свой источник, и он переопределит методы в модуле HTTPHeader, в которых есть downcase.

module HTTPHeader 

    def initialize_http_header(initheader) 
    @header = {} 
    return unless initheader 
    initheader.each do |key, value| 
     warn "net/http: warning: duplicated HTTP header: #{key}" if key?(key) and $VERBOSE 
     @header[key] = [value.strip] 
    end 
    end 

    def [](key) 
    a = @header[key] or return nil 
    a.join(', ') 
    end 

    def []=(key, val) 
    unless val 
     @header.delete key 
     return val 
    end 
    @header[key] = [val] 
    end 

    def add_field(key, val) 
    if @header.key?(key) 
     @header[key].push val 
    else 
     @header[key] = [val] 
    end 
    end 

    def get_fields(key) 
    return nil unless @header[key] 
    @header[key].dup 
    end 

    def fetch(key, *args, &block) #:yield: +key+ 
    a = @header.fetch(key, *args, &block) 
    a.kind_of?(Array) ? a.join(', ') : a 
    end 

    # Removes a header field. 
    def delete(key) 
    @header.delete(key) 
    end 

    # true if +key+ header exists. 
    def key?(key) 
    @header.key?(key) 
    end 

    def tokens(vals) 
    return [] unless vals 
    vals.map {|v| v.split(',') }.flatten\ 
    .reject {|str| str.strip.empty? }\ 
    .map {|tok| tok.strip } 
    end 

end 

Я думаю, что это грубый способ передвижения, но ничего более элегантного не пришло в голову.

Хотя это должно устранить проблему для любых библиотек Ruby с использованием Net :: HTTP, это, вероятно, не удастся для любых камней, использующих Curl или libcurl.

5

Принятый ответ не работает. Честно говоря, я сомневаюсь, что это когда-либо было, так как казалось, что это должно было бы также переопределить split and capitalize, я следил за этим методом назад за несколько коммитов, это было как минимум с 2004 года.

Вот мое решение, в ответ чтобы this закрытый вопрос:

require 'net/http' 

class Net::HTTP::ImmutableHeaderKey 
    attr_reader :key 

    def initialize(key) 
    @key = key 
    end 

    def downcase 
    self 
    end 

    def capitalize 
    self 
    end 

    def split(*) 
    [self] 
    end 

    def hash 
    key.hash 
    end 

    def eql?(other) 
    key.eql? other.key.eql? 
    end 

    def to_s 
    key 
    end 
end 

Теперь вы должны быть уверены, чтобы всегда использовать экземпляры этого класса в качестве ключей.

request   = Net::HTTP::Get.new('/') 
user_key   = Net::HTTP::ImmutableHeaderKey.new("user") 
request[user_key] = "James" 

require 'stringio' 
StringIO.new.tap do |output| 
    request.exec output, 'ver', 'path' 
    puts output.string 
end 

# >> GET path HTTP/ver 
# >> Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3 
# >> Accept: */* 
# >> User-Agent: Ruby 
# >> user: James 
# >> 
+0

Ты мой герой! –

+0

FWIW, это не работает на Ruby .2.3. Его действительно близко, см. Https://github.com/jnunemaker/httparty/issues/406 –

0

Все это падает в сеть/generic_request # write_header. Вы можете обезьяна патч код

# 'net/generic_request' line 319 
def write_header(sock, ver, path) 
    customheaders = { 
    "My-Custom-Header" => "MY-CUSTOM-HEADER", 
    "Another-Custom-Header" => "aNoThErCuStOmHeAdEr" 
    } 
    buf = "#{@method} #{path} HTTP/#{ver}\r\n" 
    each_capitalized do |k,v| 
    customheaders.key?(k) ? kk = customheaders[k] : kk = k 
    buf << "#{kk}: #{v}\r\n" 
    end 
    buf << "\r\n" 
    sock.write buf 
end 

и вам не нужно переписывать весь чистый/HTTP/заголовок, чистый/generic_request и сеть/HTTP цепь. Это не лучшее решение, но это самый простой из них, я думаю, и есть наименьшее количество исправлений обезьян.

Надеюсь, это поможет.Ответ

1

Джошуа щека является большим, но это делает в работе больше в Рубине 2.3

Эта модификация исправить это:

class Net::HTTP::ImmutableHeaderKey 
    ... 

    def to_s 
    caller.first.match(/capitalize/) ? self : @key 
    end 
end 
Смежные вопросы