Sorry to resurrect a month old thread, but I just implemented bullet #2
with this patch.
I need to disable the automatic 100-continue behavior so that my handler
can reply with a 40X status before the client read the 100-contine and
starts sending data.
On Saturday, September 17, 2016 at 12:08:29 AM UTC-4, David Anderson wrote:
>
> Tricky one. A couple of options spring to mind, none of them amazingly
> good:
>
> - Use a GCE Network LB instead of HTTP LB. You can bring the TCP
> sessions straight to your web servers, with load-balancing done
> per-TCP-session rather than per-HTTP-request.
> - Build your web server using a modified Go stdlib codebase that
> removes this conditional block:
> https://golang.org/src/net/http/server.go#L1562 . If you do this, I
> suggest also filing a bug against Go to evaluate whether "don't do
> automatic Continue support" should be added as a Server knob.
> - Stick the Go web servers behind a non-Go proxy layer (e.g. nginx)
> that strips out the "Expect: 100-continue" header before forwarding to the
> Go server. Run one nginx per Go server, on the same machines (or in the
> same Kubernetes pods if using GKE), so that the system properties look the
> same from the POV of the upstream load-balancer (same number of backends,
> same arrangement...).
> - Wait for GCE to support 100-Continue. Given that 100-Continue is
> almost non-existent on the web, personally I wouldn't hold my breath, I
> suspect it's a low-priority item.
> - You say your clients can't be modified... Can't they? I've never
> heard of browsers using 100-Continue unprompted, so if it is just
> chrome/firefox/IE, what are you doing that's causing them to use
> 100-Continue? Or are they some other client software like Mercurial?
>
> - Dave
>
> On Fri, Sep 16, 2016 at 10:00 AM, Ian Rose <[email protected]
> <javascript:>> wrote:
>
>> Howdy,
>>
>> I'm currently running a group of Go web servers behind an HTTP(s) load
>> balancer on Google Compute Engine. Unfortunately I have learned that GCE
>> load balancers do not support the "Expect: 100-continue" header [1]. From
>> my experiments, it appears that it isn't actually the request header that
>> causes the problem, but instead is the server's "100 Continue" response
>> that the load balancer dies on. Specifically, the load balancer responds
>> with a 502 to the client.
>>
>> Any suggestions on how to deal with this? We don't control our clients
>> (they are just "browsers across the internet") so solving things on that
>> side isn't possible. After digging through the net/http code a bit, my
>> best thought is to hijack the connection, which (I think) will prevent a
>> "100 Continue" status from being sent. I'm concerned, however, that this
>> won't work in all cases - for example http2 connections are not hijackable (
>> https://github.com/golang/go/issues/15312).
>>
>> Is there a better path forward?
>>
>> Thanks,
>> Ian
>>
>> [1] https://code.google.com/p/google-compute-engine/issues/detail?id=298
>> (also see "notes and restrictions" here:
>> https://cloud.google.com/compute/docs/load-balancing/http/)
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "golang-nuts" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to [email protected] <javascript:>.
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>
--
You received this message because you are subscribed to the Google Groups
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.
diff --git a/src/net/http/server.go b/src/net/http/server.go
index 51a66c3..6c01228 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -1679,14 +1679,16 @@ func (c *conn) serve(ctx context.Context) {
// Expect 100 Continue support
req := w.req
- if req.expectsContinue() {
- if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 {
- // Wrap the Body reader with one that replies on the connection
- req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
+ if !c.server.NoAuto100Continue {
+ if req.expectsContinue() {
+ if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 {
+ // Wrap the Body reader with one that replies on the connection
+ req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
+ }
+ } else if req.Header.get("Expect") != "" {
+ w.sendExpectationFailed()
+ return
}
- } else if req.Header.get("Expect") != "" {
- w.sendExpectationFailed()
- return
}
c.curReq.Store(w)
@@ -2246,6 +2248,11 @@ type Server struct {
// standard logger.
ErrorLog *log.Logger
+ // NoAuto100Continue disabled the default behavior of the
+ // server to automatically reply with a 100-continue response
+ // before invoking a handler.
+ NoAuto100Continue bool
+
disableKeepAlives int32 // accessed atomically.
nextProtoOnce sync.Once // guards setupHTTP2_* init
nextProtoErr error // result of http2.ConfigureServer if used