Re: HTTP/1.1 to clients in v3.2

2010-08-16 Thread Henrik Nordström
mån 2010-08-16 klockan 14:08 -0600 skrev Alex Rousskov:

> Should we try implement what you described then? In summary:
> 
>- If the next hop is known to be 1.1, send a chunked request.
>- Otherwise, try to accumulate the full body, with a timeout.
>  Send 411 if we timed out while accumulating.
> 
> At first, the accumulation will still happen on the client side, like 
> today. Eventually, the accumulation code can be moved to the server side.

Yes.

Suggested implementaiton order:

1. Forward of chunked requests.
2. Next hop version cache, rejecting with 411 if next hop not known to
be 1.1
3. Delay 411 response condition a bit, buffering the request hoping to
be able to dechunk instead. Respond with 411 on timeout or buffer full.
4. tuning knob to selectively assume next hop is 1.1 if unknown,
enabling out of band knowledge of 1.1 capability via configuration. This
should also include tuning for selectively disabling chunked forwarding
enabling ban of broken nex-hops.
5. Option to add "Expect: 100-continue" on forwarded chunked requests
when forced 1.1, with it's requirements on delaying forwarding and
retrying without expectation if seeing a 417 in response or returning
411 if retrying is not possible at time of 417.

Note that when Expect: 100-continue is used by the client and complete
path is 1.1 then 3 should not really happen due to the client delaying
it's transmission for some considerable amount of time. Here we SHOULD
instead respond with 411 immediately to follow the 100 Continue expected
flow model, enabling client fallback to a much shorter delay.


In paralell to this it's also needed to deal with 1xx responses in an
reasonable manner, especially 100 Continue. Without these it's hard to
get the expected flow of events running.

Regards
Henrik



Re: HTTP/1.1 to clients in v3.2

2010-08-16 Thread Alex Rousskov

On 08/16/2010 01:52 PM, Henrik Nordström wrote:

mån 2010-08-16 klockan 13:30 -0600 skrev Alex Rousskov:


Since Squid is a program and not a human being, we do need to hard-code
a single default. Clearly, there will be ACLs to change the behavior,
but if no options apply, we still need to do something.

Yu have more-or-less said "no" to every option I listed :-). Correct me
if I am wrong, but I sense that option #1 (always send chunked request)
is the "least bad" default. I will try to implement that unless you stop me.


I did not say no, just the complications each proposal involves..

The correct per spec is to reject with 411 unless next hop is known to
be 1.1.

Alternatively dechunk if we have already received the full body (by
waiting a little, not sending 100 Continue)


Should we try implement what you described then? In summary:

  - If the next hop is known to be 1.1, send a chunked request.
  - Otherwise, try to accumulate the full body, with a timeout.
Send 411 if we timed out while accumulating.

At first, the accumulation will still happen on the client side, like 
today. Eventually, the accumulation code can be moved to the server side.


Is this the right path forward?

Thank you,

Alex.



An interception client is arguably more likely to know the next hop
capabilities because it thinks it is talking directly to that hop.


I would argue the opposite. It's less likely to make a correct decision
as it do not expect the proxy to be there messing with things so it
quite likely will take the response version of the proxy as an
indication of the origin server capabilities not caring to look for Via
etc..


Similarly, we are less likely to be blamed for screwing things up if we
just repeat what the intercepted client did.


Until someone slaps us with the specifications.

Regards
Henrik




Re: HTTP/1.1 to clients in v3.2

2010-08-16 Thread Henrik Nordström
mån 2010-08-16 klockan 13:30 -0600 skrev Alex Rousskov:

> Since Squid is a program and not a human being, we do need to hard-code 
> a single default. Clearly, there will be ACLs to change the behavior, 
> but if no options apply, we still need to do something.
> 
> Yu have more-or-less said "no" to every option I listed :-). Correct me 
> if I am wrong, but I sense that option #1 (always send chunked request) 
> is the "least bad" default. I will try to implement that unless you stop me.

I did not say no, just the complications each proposal involves..

The correct per spec is to reject with 411 unless next hop is known to
be 1.1.

Alternatively dechunk if we have already received the full body (by
waiting a little, not sending 100 Continue)

> An interception client is arguably more likely to know the next hop 
> capabilities because it thinks it is talking directly to that hop. 

I would argue the opposite. It's less likely to make a correct decision
as it do not expect the proxy to be there messing with things so it
quite likely will take the response version of the proxy as an
indication of the origin server capabilities not caring to look for Via
etc..

> Similarly, we are less likely to be blamed for screwing things up if we 
> just repeat what the intercepted client did.

Until someone slaps us with the specifications.

Regards
Henrik



Re: HTTP/1.1 to clients in v3.2

2010-08-16 Thread Alex Rousskov

On 08/16/2010 01:17 PM, Henrik Nordström wrote:

mån 2010-08-16 klockan 11:43 -0600 skrev Alex Rousskov:


I am revisiting this issue in hope to enable HTTP/1.1 to clients. If
Squid properly dechunks requests on the client side, what should happen
to that dechunked request on the server side? Let's start with the most
general case were we do _not_ know the origin server version and where
there are no matching ACLs to control Squid behavior.

  I see several options:

1. Always send a chunked request (because the client did so and perhaps
the client knows that the server is HTTP/1.1 and can handle a chunked
request.)


But the client doesn't really know.. it knows Squid. HTTP version,
transfer encoding etc is hop-by-hop, not end-to-end. Well, there is Via,
but not sent on 100 Continue for example.

Specs says "MUST include a valid Content-Length header field unless the
server is known to be HTTP/1.1 compliant".

But we should at least have a knob for tuning this. I don't really agree
with the specs here. As you note if the client sends chunked then in
reality it's quite likely the server supports chunked as the client most
likely have some out of band information about the server capabilities.


2. Always send dechunked request with a Content-Length field, after
buffering all the chunks and calculating content length (because we do
not know whether the server is HTTP/1.1 and can handle a chunked request).


Not really doable. Request may be huge and buffer space limited.

I am entirely fine with dechunking and converting to content-length
should we already have the data buffered. But not to use it as default
mechanism.

Limited buffering plays somewhat badly with 100 Continue. I am not very
comfortable with sending a 411 after 100 Continue even if not strictly
illegal. Very unlikely clients deal well with such situation as specs
says the 100 Continue indicates explicitly that the origin server is
willing to accept the body.


3. Always add an "Expect: 100-continue" if not already there, send the
headers, and then pick option #1 or #2, depending on the server version
if we get a 100 Continue response.


This should work out reasonably well I think, but adds a fair amount of
complexity.

If we get 100 Continue then the server is supposed to be 1.1. But MAY be
an intermediary seding 100 Continue (not strictly legal..)

If we add 100-continue then we must also retry without 100-continue if
receiving a 417. Which also means that we need to buffer the request
while it's forwarded, which risks running into the same limited
buffering issue, requiring us to send a 411 response if buffer space has
been exceeded and receiving a 417 response.


Any other options?


I don't think a single hard answer can be given. More likely a mix and
some knobs to tune to real world brokenness will be needed. But in the
short run blindly forwarding quite liekly works.


Since Squid is a program and not a human being, we do need to hard-code 
a single default. Clearly, there will be ACLs to change the behavior, 
but if no options apply, we still need to do something.


Yu have more-or-less said "no" to every option I listed :-). Correct me 
if I am wrong, but I sense that option #1 (always send chunked request) 
is the "least bad" default. I will try to implement that unless you stop me.




Should the choice depend on whether we are a direct
or interception proxy?


Not really. End result is pretty much the same, except that the client
have even less knowledge about the state of things when being
intercepted.


An interception client is arguably more likely to know the next hop 
capabilities because it thinks it is talking directly to that hop. 
Similarly, we are less likely to be blamed for screwing things up if we 
just repeat what the intercepted client did.


Thank you,

Alex.


Re: HTTP/1.1 to clients in v3.2

2010-08-16 Thread Henrik Nordström
mån 2010-08-16 klockan 11:43 -0600 skrev Alex Rousskov:

> I am revisiting this issue in hope to enable HTTP/1.1 to clients. If 
> Squid properly dechunks requests on the client side, what should happen 
> to that dechunked request on the server side? Let's start with the most 
> general case were we do _not_ know the origin server version and where 
> there are no matching ACLs to control Squid behavior.
>
>  I see several options:
> 
> 1. Always send a chunked request (because the client did so and perhaps 
> the client knows that the server is HTTP/1.1 and can handle a chunked 
> request.)

But the client doesn't really know.. it knows Squid. HTTP version,
transfer encoding etc is hop-by-hop, not end-to-end. Well, there is Via,
but not sent on 100 Continue for example.

Specs says "MUST include a valid Content-Length header field unless the
server is known to be HTTP/1.1 compliant".

But we should at least have a knob for tuning this. I don't really agree
with the specs here. As you note if the client sends chunked then in
reality it's quite likely the server supports chunked as the client most
likely have some out of band information about the server capabilities.

> 2. Always send dechunked request with a Content-Length field, after 
> buffering all the chunks and calculating content length (because we do 
> not know whether the server is HTTP/1.1 and can handle a chunked request).

Not really doable. Request may be huge and buffer space limited.

I am entirely fine with dechunking and converting to content-length
should we already have the data buffered. But not to use it as default
mechanism.

Limited buffering plays somewhat badly with 100 Continue. I am not very
comfortable with sending a 411 after 100 Continue even if not strictly
illegal. Very unlikely clients deal well with such situation as specs
says the 100 Continue indicates explicitly that the origin server is
willing to accept the body.

> 3. Always add an "Expect: 100-continue" if not already there, send the 
> headers, and then pick option #1 or #2, depending on the server version 
> if we get a 100 Continue response.

This should work out reasonably well I think, but adds a fair amount of
complexity.

If we get 100 Continue then the server is supposed to be 1.1. But MAY be
an intermediary seding 100 Continue (not strictly legal..)

If we add 100-continue then we must also retry without 100-continue if
receiving a 417. Which also means that we need to buffer the request
while it's forwarded, which risks running into the same limited
buffering issue, requiring us to send a 411 response if buffer space has
been exceeded and receiving a 417 response.

> Any other options?

I don't think a single hard answer can be given. More likely a mix and
some knobs to tune to real world brokenness will be needed. But in the
short run blindly forwarding quite liekly works.


> Should the choice depend on whether we are a direct 
> or interception proxy?

Not really. End result is pretty much the same, except that the client
have even less knowledge about the state of things when being
intercepted.

Regards
Henrik