On Tue, Jan 26, 2010 at 17:34, Mark Stosberg <m...@summersault.com> wrote:
>
> In 2008 there was some discussion about an option to preserve the
> ordering of HTTP headers. Part of that thread is quoted below.
>
> The idea resurfaced in another form with the release of
> HTTP::Headers::Fast, which provided a method to get back the the
> headers unsorted. However, the motivation was different there--
> performance-- and the implementation as different as well. It returns
> headers in essentially random order instead the order in which which
> they were created or transmitted.
>
> I took an interest in the issue of HTTP header ordering and researched
> what several other Perl modules do in regards to this as well as Ruby's
> Rack. I published the result on my blog:
>
> http://mark.stosberg.com/blog/2010/01/generating-http-headers-sorted-or-unsorted.html
>
> The summary is that I support the option for unsorted headers in
> HTTP::Headers. Michael Greb made a good case for it, and the
> possibility for a performance improvement is attractive too.

I would prefer if there was a way to make the sorted headers as fast
as unsorted headers :-)

I still would like to see support for the ordering of headers
preserved at some point.

Instead of introducing the 'as_string_without_sort' method could we
achieve the same effect with a 'order' argument to 'as_string'?  Could
take values like 'sorted'/'original'/'dontcare'.

--Gisle


> On Sun, 7 Sep 2008 15:53:46 +0200
> "Gisle Aas" <gi...@aas.no> wrote:
>
>> On Sun, Sep 7, 2008 at 1:49 PM, Michael Greb <mg...@linode.com> wrote:
>> > On Sep 5, 2008, at 7:23 PM, Gisle Aas wrote:
>> >>
>> >> True; and in this case we need to define what happens when fields are
>> >> modified with 'push', 'set' or 'init' and 'remove' as that's the API
>> >> that modify stuff.  Let me suggest the following definition of the
>> >> behaviour:
>> >>
>> >> - 'push' always append the field at the end of all headers.  multiple
>> >> occurrences of a field name do not have to be consecutive.
>> >>
>> >> - 'init' either does nothing or it works like 'push'.
>> >>
>> >> - 'remove' will always remove all concurrences of a field.
>> >>
>> >> - 'set' will work like 'push' if no other occurrence of the field exists.
>> >>
>> >> - 'set' will update the first occurrence if the field exists (and
>> >> remove all other occurrences).  if multiple field values is provided
>> >> with 'set' they are basically all injected at the location of the
>> >> first existing value.
>> >
>> >
>> > On Sep 6, 2008 at 2:57 AM, Gisle Aas wrong:
>> >>
>> >> I think it makes sense to be able to enable them separately.
>> >> Suggested interface:
>> >>
>> >>  $h->scan(\&cb, original_order => 1, original_case => 1);
>> >>  $h->as_string(eol => "\n", original_order => 1, original_case => 1);'
>> >
>> > The attached patch uses the interface above and works towards the behavior
>> > outlined in the first message.  Due to the headers being stored as a hash,
>> > pushing does not currently preserve previous values, second and subsequent
>> > pushes of the same header will overwrite the previous value.  Supporting
>> > this would require a change in how the headers are stored within the 
>> > module.
>> >  Your thoughts?
>>
>> I think it's better to just use your original approach and just keep
>> the representation like used to be with the addition of an array that
>> records the original field names and their order.  This should lead to
>> a smaller patch as the only thing that need to change is the code that
>> sets headers and the scan method.  I also like header lockups to be
>> efficient and the representation compact.
>>
>> > Server: Fool/1.0
>> > content-encoding: gzip
>> > Content-Type: text/plain; charset="UTF-8"
>> > Content-Encoding: base64
>> > Date: Fri Sep  5 10:24:37 CEST 2008
>> >
>> > Would be stored as (assuming push_header):
>>
>> My suggestion would be:
>>
>> bless {
>>     "content-encoding" => ["\n gzip", "base64"],
>>     "content-type" => "text/plain; charset=\"UTF-8\"",
>>     "date" => "Fri Sep  5 10:24:37 CEST 2008",
>>     "server" => "Fool/1.0",
>>     "::original_fields" => [
>>         "Server",
>>         "content-encoding",
>>         "Content-Type",
>>         "Content-Encoding",
>>         "Date",
>>     ],
>> }, "HTTP::Headers";
>>
>> The invariant that needs to hold is that there is the same number of
>> elements in {"::original_fields"} as there are values for all the
>> others keys.
>>
>> Pushing a value is trivial; only change from what we have now is
>> appending the original field name to {"::original_fields"}.
>>
>> The only state modification operation that becomes more complex is
>> setting of a value header value.  It has to:
>>
>>   - update the values in the hash as before
>>   - locate the first occurence of the field name in
>> {"::original_fields"}  => $idx
>>   - remove all other occurrences of the field name
>>   - splice(@{"::original_fields"}, $idx, 1, ($orig_field_name) x
>> $numbers_of_values_set);
>>
>> When 'scan' wants to iterate over the original headers it would have
>> to keep an index into the values array for each field that repeat.
>>
>> An more compact representation could be to store {"::original_fields"}
>> as a ":"-separated string; but we can think about that optimization
>> later.
>>
>> --Gisle
>>
>
>
> --
>  . . . . . . . . . . . . . . . . . . . . . . . . . . .
>   Mark Stosberg            Principal Developer
>   m...@summersault.com     Summersault, LLC
>   765-939-9301 ext 202     database driven websites
>  . . . . . http://www.summersault.com/ . . . . . . . .
>
>
>

Reply via email to