Handle comma-seperated Connection header #39

Merged
merged 1 commit into from Jun 11, 2014

Conversation

Projects
None yet
9 participants
@BrianMMcClain
Contributor

BrianMMcClain commented May 8, 2014

Specifically in the case of Firefox where the client sends multiple values in a comma-seperated format for the Connection header (ie. "Connection: keep-alive, Upgrade"). This was preventing Firefox (tested on v28) from properly connecting to servies which provide a websocket endpoint, while other browsers (ie. Chrome) were able to connect.

Reference: http://tools.ietf.org/html/rfc2616#section-4.2

Quote:

Multiple message-header fields with the same field-name MAY be
present in a message if and only if the entire field-value for that
header field is defined as a comma-separated list [i.e., #(values)].
It MUST be possible to combine the multiple header fields into one
"field-name: field-value" pair, without changing the semantics of the
message, by appending each subsequent field-value to the first, each
separated by a comma. The order in which header fields with the same
field-name are received is therefore significant to the
interpretation of the combined field value, and thus a proxy MUST NOT
change the order of these field values when a message is forwarded.

@cf-gitbot

This comment has been minimized.

Show comment
Hide comment
@cf-gitbot

cf-gitbot May 8, 2014

Collaborator

We have created an issue in Pivotal Tracker to manage this. You can view the current status of your issue at: https://www.pivotaltracker.com/story/show/70982344. This repo is managed by the 'Runtime' team.

Collaborator

cf-gitbot commented May 8, 2014

We have created an issue in Pivotal Tracker to manage this. You can view the current status of your issue at: https://www.pivotaltracker.com/story/show/70982344. This repo is managed by the 'Runtime' team.

@BrianMMcClain BrianMMcClain referenced this pull request May 8, 2014

Closed

Websocket issue #37

@adamstegman

This comment has been minimized.

Show comment
Hide comment
@adamstegman

adamstegman May 9, 2014

@BrianMMcClain Could you add a test for this? Looks like there's an existing test for a value of just "Upgrade", so a comma-separated test would be good.

@MarkKropf @shalako This looks like a good change. Should we move this to your icebox?

Thanks,
CF Community Pair (@adamstegman @mbhave)

@BrianMMcClain Could you add a test for this? Looks like there's an existing test for a value of just "Upgrade", so a comma-separated test would be good.

@MarkKropf @shalako This looks like a good change. Should we move this to your icebox?

Thanks,
CF Community Pair (@adamstegman @mbhave)

@BrianMMcClain

This comment has been minimized.

Show comment
Hide comment
@BrianMMcClain

BrianMMcClain May 9, 2014

Contributor

@adamstegman, absolutely. I'm admittedly a Go novice, but I'll take a look at existing tests and see what I can add and update the PR. Thanks!

Contributor

BrianMMcClain commented May 9, 2014

@adamstegman, absolutely. I'm admittedly a Go novice, but I'll take a look at existing tests and see what I can add and update the PR. Thanks!

@BrianMMcClain

This comment has been minimized.

Show comment
Hide comment
@BrianMMcClain

BrianMMcClain May 10, 2014

Contributor

@adamstegman, please see the additional commit. Apologies is this is improper or not even covering the right thing, I referred to a previous commit in which the Connection header was made case-insentive to check out which test to duplicate and modify, and figured this was the best route. Then again, this is also the bug that drove me to finally learn Go, so I'm only working off of what I've learned in the past 24 hours :)

If this isn't a proper test, let me know and I'll go back to the drawing board and try again. Thanks!

Contributor

BrianMMcClain commented May 10, 2014

@adamstegman, please see the additional commit. Apologies is this is improper or not even covering the right thing, I referred to a previous commit in which the Connection header was made case-insentive to check out which test to duplicate and modify, and figured this was the best route. Then again, this is also the bug that drove me to finally learn Go, so I'm only working off of what I've learned in the past 24 hours :)

If this isn't a proper test, let me know and I'll go back to the drawing board and try again. Thanks!

@mbhave

This comment has been minimized.

Show comment
Hide comment
@mbhave

mbhave May 12, 2014

@MarkKropf @hiremaga This looks fine at first glance. Can we move this to your icebox?

Thanks,
CF Community Pair (@stupakov, @mbhave)

mbhave commented May 12, 2014

@MarkKropf @hiremaga This looks fine at first glance. Can we move this to your icebox?

Thanks,
CF Community Pair (@stupakov, @mbhave)

@emalm

This comment has been minimized.

Show comment
Hide comment
@emalm

emalm May 13, 2014

Member

@BrianMMcClain, thanks for noticing this issue and working to resolve it! The Runtime team has recently started work on an epic to improve the capabilities and robustness of the gorouter. While it looks like the changes planned in this epic wouldn't collide with your fix to this issue (although @fraenkel would know best), we'll probably wait to pull this in until after that work is done.

Also, as part of that epic, we are planning to convert all the tests to use the Ginkgo testing framework, so it might be better to write the test for this functionality in Ginkgo after that conversion goes in. We'd be happy to help you with that as well.

Thanks,
Eric

cc: @MarkKropf @hiremaga

Member

emalm commented May 13, 2014

@BrianMMcClain, thanks for noticing this issue and working to resolve it! The Runtime team has recently started work on an epic to improve the capabilities and robustness of the gorouter. While it looks like the changes planned in this epic wouldn't collide with your fix to this issue (although @fraenkel would know best), we'll probably wait to pull this in until after that work is done.

Also, as part of that epic, we are planning to convert all the tests to use the Ginkgo testing framework, so it might be better to write the test for this functionality in Ginkgo after that conversion goes in. We'd be happy to help you with that as well.

Thanks,
Eric

cc: @MarkKropf @hiremaga

@BrianMMcClain

This comment has been minimized.

Show comment
Hide comment
@BrianMMcClain

BrianMMcClain May 13, 2014

Contributor

@ematpl, thanks for the update. It certainly makes sense to wait until the epic is completed until this is merged in, we can just hot-patch our Gorouters in the meantime.

As this is the PR that drove me to learn Go, that gives me some time to read into Ginkgo as well :)

Any word on when this is expected to be completed? I can either keep an eye out for it, or if anyone can drop a comment in this PR, I can take any actions needed on my end.

Thanks!
Brian

Contributor

BrianMMcClain commented May 13, 2014

@ematpl, thanks for the update. It certainly makes sense to wait until the epic is completed until this is merged in, we can just hot-patch our Gorouters in the meantime.

As this is the PR that drove me to learn Go, that gives me some time to read into Ginkgo as well :)

Any word on when this is expected to be completed? I can either keep an eye out for it, or if anyone can drop a comment in this PR, I can take any actions needed on my end.

Thanks!
Brian

@hiremaga

This comment has been minimized.

Show comment
Hide comment
@hiremaga

hiremaga May 13, 2014

Contributor

We're hoping to work on the epic this week while @fraenkel is in SF. At a
very least, I think we'd want to merge his switch to Gingko before making
any changes to GoRouter.

I think the other stories in the epic are unlikely to conflict with this
change. Does that sound right @fraenkel?

On Monday, May 12, 2014, Brian McClain notifications@github.com wrote:

@ematpl https://github.com/ematpl, thanks for the update. It certainly
makes sense to wait until the epic is completed until this is merged in, we
can just hot-patch our Gorouters in the meantime.

As this is the PR that drove me to learn Go, that gives me some time to
read into Ginkgo as well :)

Any word on when this is expected to be completed? I can either keep an
eye out for it, or if anyone can drop a comment in this PR, I can take any
actions needed on my end.

Thanks!
Brian


Reply to this email directly or view it on GitHubhttps://github.com/cloudfoundry/gorouter/pull/39#issuecomment-42911370
.

Contributor

hiremaga commented May 13, 2014

We're hoping to work on the epic this week while @fraenkel is in SF. At a
very least, I think we'd want to merge his switch to Gingko before making
any changes to GoRouter.

I think the other stories in the epic are unlikely to conflict with this
change. Does that sound right @fraenkel?

On Monday, May 12, 2014, Brian McClain notifications@github.com wrote:

@ematpl https://github.com/ematpl, thanks for the update. It certainly
makes sense to wait until the epic is completed until this is merged in, we
can just hot-patch our Gorouters in the meantime.

As this is the PR that drove me to learn Go, that gives me some time to
read into Ginkgo as well :)

Any word on when this is expected to be completed? I can either keep an
eye out for it, or if anyone can drop a comment in this PR, I can take any
actions needed on my end.

Thanks!
Brian


Reply to this email directly or view it on GitHubhttps://github.com/cloudfoundry/gorouter/pull/39#issuecomment-42911370
.

@fraenkel

This comment has been minimized.

Show comment
Hide comment
@fraenkel

fraenkel May 13, 2014

Contributor

The code change will not be affected, but the test cases will definitely not work once the switch to Ginkgo occurs.

On a separate note, the actual change is not quite correct. I will add comments directly in the code for that.

Contributor

fraenkel commented May 13, 2014

The code change will not be affected, but the test cases will definitely not work once the switch to Ginkgo occurs.

On a separate note, the actual change is not quite correct. I will add comments directly in the code for that.

@MarkKropf

This comment has been minimized.

Show comment
Hide comment
@MarkKropf

MarkKropf May 13, 2014

Member

Ok, looks like this will need to be resubmitted with @fraenkel 's input. @hiremaga assuming this gets updated, I'll look to schedule this after the router track.

Member

MarkKropf commented May 13, 2014

Ok, looks like this will need to be resubmitted with @fraenkel 's input. @hiremaga assuming this gets updated, I'll look to schedule this after the router track.

@hiremaga

This comment has been minimized.

Show comment
Hide comment
@hiremaga

hiremaga May 22, 2014

Contributor

Closing this PR based on the conversations we've had here.

Contributor

hiremaga commented May 22, 2014

Closing this PR based on the conversations we've had here.

@hiremaga hiremaga closed this May 22, 2014

@fraenkel

This comment has been minimized.

Show comment
Hide comment
@fraenkel

fraenkel May 23, 2014

Contributor

Why was this closed? We just need an updated PR.

Contributor

fraenkel commented May 23, 2014

Why was this closed? We just need an updated PR.

@hiremaga

This comment has been minimized.

Show comment
Hide comment
@hiremaga

hiremaga May 23, 2014

Contributor

I don't believe its mergeable in its current state. A new PR that
references this one is probably fine. Would that work?

On Thursday, May 22, 2014, Michael Fraenkel notifications@github.com
wrote:

Why was this closed? We just need an updated PR.


Reply to this email directly or view it on GitHubhttps://github.com/cloudfoundry/gorouter/pull/39#issuecomment-43959258
.

Contributor

hiremaga commented May 23, 2014

I don't believe its mergeable in its current state. A new PR that
references this one is probably fine. Would that work?

On Thursday, May 22, 2014, Michael Fraenkel notifications@github.com
wrote:

Why was this closed? We just need an updated PR.


Reply to this email directly or view it on GitHubhttps://github.com/cloudfoundry/gorouter/pull/39#issuecomment-43959258
.

@fraenkel

This comment has been minimized.

Show comment
Hide comment
@fraenkel

fraenkel May 23, 2014

Contributor

Sure... Usually I would just update the existing PR, but a new one works. They can get started on it now since the area of code affected will not change and the switch to Ginkgo/Gomega is completed.

Contributor

fraenkel commented May 23, 2014

Sure... Usually I would just update the existing PR, but a new one works. They can get started on it now since the area of code affected will not change and the switch to Ginkgo/Gomega is completed.

@hiremaga hiremaga reopened this May 23, 2014

@hiremaga

This comment has been minimized.

Show comment
Hide comment
@hiremaga

hiremaga May 23, 2014

Contributor

I've re-opened it. I'll leave it to @BrianMMcClain to decide if he'd like to recycle this one or start a new one :)

Contributor

hiremaga commented May 23, 2014

I've re-opened it. I'll leave it to @BrianMMcClain to decide if he'd like to recycle this one or start a new one :)

@BrianMMcClain

This comment has been minimized.

Show comment
Hide comment
@BrianMMcClain

BrianMMcClain May 27, 2014

Contributor

For the record, I havn't forgotten about this either :) I'm just trying to do my due diligence being a newbie in Go and take @fraenkel's comments into a proper solution. I'm shooting to have an updated PR this week.

Contributor

BrianMMcClain commented May 27, 2014

For the record, I havn't forgotten about this either :) I'm just trying to do my due diligence being a newbie in Go and take @fraenkel's comments into a proper solution. I'm shooting to have an updated PR this week.

@maxbrunsfeld

This comment has been minimized.

Show comment
Hide comment
@maxbrunsfeld

maxbrunsfeld May 27, 2014

A corollary to @fraenkel's comment-
In your test, rather than using req.Header.Set("Connection", "keep-alive, Upgrade") to set multiple header values, you may want to use the Header.Add method.

A corollary to @fraenkel's comment-
In your test, rather than using req.Header.Set("Connection", "keep-alive, Upgrade") to set multiple header values, you may want to use the Header.Add method.

@BrianMMcClain

This comment has been minimized.

Show comment
Hide comment
@BrianMMcClain

BrianMMcClain May 29, 2014

Contributor

@fraenkel, @maxbrunsfeld, just to keep everyone updated (and to document the thread), I was having a bit of odd behavior with the req.Header.Add and accessing the headers as a map and using CanonicalHeaderKey for the key. I've actually opened a thread in the golang-nuts mailing list which goes into detail which can be found here: https://groups.google.com/forum/#!topic/golang-nuts/WwoXG45Fqn0

But in short, accessing the Header map directly only returns a single string still when processing requests from Firefox (ie. "keep-alive, Upgrade"), rather than an array of values. Also, using Header.Add results in strange behavior as well, where the header is actually written twice. It's stored correctly in the Header map (as in, an array of values), but I believe the issue is when it's written to the wire, it results in the following:

GET / HTTP/1.1
Host: localhost:4567
User-Agent: Go 1.1 package http
Connection: keep-alive
Connection: Upgrade
Upgrade: websocket
Accept-Encoding: gzip

The Go net/http package parses this correctly, but no other server-side software I've tested does (ie. Sinatra/thin). This is either an issue or a misunderstanding on my part (probably more likely than a bug in Go), rather than the Gorouter, so I'll await a response in that thread.

  • Brian
Contributor

BrianMMcClain commented May 29, 2014

@fraenkel, @maxbrunsfeld, just to keep everyone updated (and to document the thread), I was having a bit of odd behavior with the req.Header.Add and accessing the headers as a map and using CanonicalHeaderKey for the key. I've actually opened a thread in the golang-nuts mailing list which goes into detail which can be found here: https://groups.google.com/forum/#!topic/golang-nuts/WwoXG45Fqn0

But in short, accessing the Header map directly only returns a single string still when processing requests from Firefox (ie. "keep-alive, Upgrade"), rather than an array of values. Also, using Header.Add results in strange behavior as well, where the header is actually written twice. It's stored correctly in the Header map (as in, an array of values), but I believe the issue is when it's written to the wire, it results in the following:

GET / HTTP/1.1
Host: localhost:4567
User-Agent: Go 1.1 package http
Connection: keep-alive
Connection: Upgrade
Upgrade: websocket
Accept-Encoding: gzip

The Go net/http package parses this correctly, but no other server-side software I've tested does (ie. Sinatra/thin). This is either an issue or a misunderstanding on my part (probably more likely than a bug in Go), rather than the Gorouter, so I'll await a response in that thread.

  • Brian
@fraenkel

This comment has been minimized.

Show comment
Hide comment
@fraenkel

fraenkel May 29, 2014

Contributor

What are you seeing is valid by the HTTP spec.
See http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-26#section-3.2.2

A field that is comma delimited can be specified with multiple header fields.

Contributor

fraenkel commented May 29, 2014

What are you seeing is valid by the HTTP spec.
See http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-26#section-3.2.2

A field that is comma delimited can be specified with multiple header fields.

@BrianMMcClain

This comment has been minimized.

Show comment
Hide comment
@BrianMMcClain

BrianMMcClain May 29, 2014

Contributor

Hm, I see. So would the acceptable logic be:

  1. Access the Header map via request.Header[http.CanonicalHeaderKey("Connection")]
  2. Iterate over each result (To cover the case of multiple filed-names
  3. Downcase and split each result on a comma
  4. Iterate over each value of the split
  5. If "upgrade" is found, return the value of the Upgrade header
  6. Otherwise, return an empty string

And perhaps the tests could cover both cases of a single or multiple headers sharing the same field-name?

Sorry if I'm coming off a bit daft, figured confirming a proper solution with you guys and then implementing would be easier on everyone :)

Contributor

BrianMMcClain commented May 29, 2014

Hm, I see. So would the acceptable logic be:

  1. Access the Header map via request.Header[http.CanonicalHeaderKey("Connection")]
  2. Iterate over each result (To cover the case of multiple filed-names
  3. Downcase and split each result on a comma
  4. Iterate over each value of the split
  5. If "upgrade" is found, return the value of the Upgrade header
  6. Otherwise, return an empty string

And perhaps the tests could cover both cases of a single or multiple headers sharing the same field-name?

Sorry if I'm coming off a bit daft, figured confirming a proper solution with you guys and then implementing would be easier on everyone :)

@fraenkel

This comment has been minimized.

Show comment
Hide comment
@fraenkel

fraenkel May 29, 2014

Contributor

Its a bit easier than you think.

  1. Access the Header map via request.Header[http.CanonicalHeaderKey("Connection")]
  2. Iterate over each string
  3. Downcase the string
  4. If "upgrade" is found, return the value of the Upgrade header
  5. Otherwise, return an empty string

Technically upgrade needs to be "Upgrade" as per RFC 6455. That would allow us to skip step 3.

Contributor

fraenkel commented May 29, 2014

Its a bit easier than you think.

  1. Access the Header map via request.Header[http.CanonicalHeaderKey("Connection")]
  2. Iterate over each string
  3. Downcase the string
  4. If "upgrade" is found, return the value of the Upgrade header
  5. Otherwise, return an empty string

Technically upgrade needs to be "Upgrade" as per RFC 6455. That would allow us to skip step 3.

Handle comma-seperated and multiple Connection headers
Specifically in the case of Firefox where the client sends multiple values in a comma-seperated format for the Connection header (ie. "Connection: keep-alive, Upgrade"). This was preventing Firefox (tested on v28) from properly connecting to servies which provide a websocket endpoint, while other browsers (ie. Chrome) were able to connect.

Reference: http://tools.ietf.org/html/rfc2616#section-4.2

Quote:

 Multiple message-header fields with the same field-name MAY be
   present in a message if and only if the entire field-value for that
   header field is defined as a comma-separated list [i.e., #(values)].
   It MUST be possible to combine the multiple header fields into one
   "field-name: field-value" pair, without changing the semantics of the
   message, by appending each subsequent field-value to the first, each
   separated by a comma. The order in which header fields with the same
   field-name are received is therefore significant to the
   interpretation of the combined field value, and thus a proxy MUST NOT
   change the order of these field values when a message is forwarded.
@BrianMMcClain

This comment has been minimized.

Show comment
Hide comment
@BrianMMcClain

BrianMMcClain Jun 9, 2014

Contributor

Rebased, reimplemented and retested. I was probably over-thinking how to interpret how you wanted the implementation , @fraenkel, but as the two Connection header maps are either:

["keep-alive, Upgrade"] (Single Connection header sent as comma-separated string)

or

["keep-alive", "Upgrade"] (multiple Connection headers sent)

I think this is what you were looking for. I've also updated my tests based on @maxbrunsfeld's commends to use Header.Add instead of Header.Set

Apologies on the delay getting this in, was preparing for the CF Summit :)

Contributor

BrianMMcClain commented Jun 9, 2014

Rebased, reimplemented and retested. I was probably over-thinking how to interpret how you wanted the implementation , @fraenkel, but as the two Connection header maps are either:

["keep-alive, Upgrade"] (Single Connection header sent as comma-separated string)

or

["keep-alive", "Upgrade"] (multiple Connection headers sent)

I think this is what you were looking for. I've also updated my tests based on @maxbrunsfeld's commends to use Header.Add instead of Header.Set

Apologies on the delay getting this in, was preparing for the CF Summit :)

@fraenkel

This comment has been minimized.

Show comment
Hide comment
@fraenkel

fraenkel Jun 10, 2014

Contributor

The code looks good.
However, your test for multiple Headers doesn't do what I believe you were trying to do. It will append the values together as one header. The only way to do what you want is to manually write the request.

Contributor

fraenkel commented Jun 10, 2014

The code looks good.
However, your test for multiple Headers doesn't do what I believe you were trying to do. It will append the values together as one header. The only way to do what you want is to manually write the request.

@BrianMMcClain

This comment has been minimized.

Show comment
Hide comment
@BrianMMcClain

BrianMMcClain Jun 10, 2014

Contributor

@fraenkel, is that the case? At least on go1.2.2, I believe Go is sending it as multiple Connection headers, in a test client, the following code:

package main

import (
  "fmt"
  "net/http"
  "io/ioutil"
  "net/http/httputil"
)
func main() {

  client := &http.Client{}
  req, _ := http.NewRequest("GET", "http://localhost:8080", nil)
  req.Header.Add("Connection", "keep-alive")
  req.Header.Add("Connection", "Upgrade")
  req.Header.Add("Upgrade", "websocket")

  dump, _ := httputil.DumpRequestOut(req, false)
  fmt.Println(string(dump))

  res, _ := client.Do(req)

  body, _ := ioutil.ReadAll(res.Body)
  res.Body.Close()
  fmt.Printf("%s", body)
}

Is showing the following output:

GET / HTTP/1.1
Host: localhost:8080
User-Agent: Go 1.1 package http
Connection: keep-alive
Connection: Upgrade
Upgrade: websocket
Accept-Encoding: gzip


Hello World!

To ensure this is actually the case, checking out the data in Wireshark produces the following which is what's actually being sent over the wire:

No.     Time           Source                Destination           Protocol Length Info
    133 76.912331000   127.0.0.1             127.0.0.1             HTTP     217    GET / HTTP/1.1

Frame 133: 217 bytes on wire (1736 bits), 217 bytes captured (1736 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1 (127.0.0.1), Dst: 127.0.0.1 (127.0.0.1)
Transmission Control Protocol, Src Port: 49386 (49386), Dst Port: http-alt (8080), Seq: 1, Ack: 1, Len: 161
Hypertext Transfer Protocol
    GET / HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): GET / HTTP/1.1\r\n]
        Request Method: GET
        Request URI: /
        Request Version: HTTP/1.1
    Host: localhost:8080\r\n
    User-Agent: Go 1.1 package http\r\n
    Connection: keep-alive\r\n
    Connection: Upgrade\r\n
    Upgrade: websocket\r\n
    Accept-Encoding: gzip\r\n
    \r\n
    [Full request URI: http://localhost:8080/]
    [HTTP request 1/1]
    [Response in frame: 135]

Apologies for probably another dumb question (my specialty :) ), just wanted to make sure I was understanding this properly.

Thanks!
Brian

Contributor

BrianMMcClain commented Jun 10, 2014

@fraenkel, is that the case? At least on go1.2.2, I believe Go is sending it as multiple Connection headers, in a test client, the following code:

package main

import (
  "fmt"
  "net/http"
  "io/ioutil"
  "net/http/httputil"
)
func main() {

  client := &http.Client{}
  req, _ := http.NewRequest("GET", "http://localhost:8080", nil)
  req.Header.Add("Connection", "keep-alive")
  req.Header.Add("Connection", "Upgrade")
  req.Header.Add("Upgrade", "websocket")

  dump, _ := httputil.DumpRequestOut(req, false)
  fmt.Println(string(dump))

  res, _ := client.Do(req)

  body, _ := ioutil.ReadAll(res.Body)
  res.Body.Close()
  fmt.Printf("%s", body)
}

Is showing the following output:

GET / HTTP/1.1
Host: localhost:8080
User-Agent: Go 1.1 package http
Connection: keep-alive
Connection: Upgrade
Upgrade: websocket
Accept-Encoding: gzip


Hello World!

To ensure this is actually the case, checking out the data in Wireshark produces the following which is what's actually being sent over the wire:

No.     Time           Source                Destination           Protocol Length Info
    133 76.912331000   127.0.0.1             127.0.0.1             HTTP     217    GET / HTTP/1.1

Frame 133: 217 bytes on wire (1736 bits), 217 bytes captured (1736 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1 (127.0.0.1), Dst: 127.0.0.1 (127.0.0.1)
Transmission Control Protocol, Src Port: 49386 (49386), Dst Port: http-alt (8080), Seq: 1, Ack: 1, Len: 161
Hypertext Transfer Protocol
    GET / HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): GET / HTTP/1.1\r\n]
        Request Method: GET
        Request URI: /
        Request Version: HTTP/1.1
    Host: localhost:8080\r\n
    User-Agent: Go 1.1 package http\r\n
    Connection: keep-alive\r\n
    Connection: Upgrade\r\n
    Upgrade: websocket\r\n
    Accept-Encoding: gzip\r\n
    \r\n
    [Full request URI: http://localhost:8080/]
    [HTTP request 1/1]
    [Response in frame: 135]

Apologies for probably another dumb question (my specialty :) ), just wanted to make sure I was understanding this properly.

Thanks!
Brian

@fraenkel fraenkel merged commit bdfcbc3 into cloudfoundry:master Jun 11, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment