Response does not implement http.Hijacker - go

I'm using Go and trying to implement WebSocket in my project. while implementing this. I get "WebSocket: response does not implement HTTP.Hijacker" error. I'm new to this technology. Can anyone help me resolve this?
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
func HandleConnections(w http.ResponseWriter, r *http.Request) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("err", err)
return
}
log.Println("hello client")
}

The application is using "middleware" that wraps the net/http server's ResponseWriter implementation. The middleware wrapper does not implement the Hijacker interface.
There are two fixes for the problem:
Remove the offending middleware.
Implement the Hijacker interface on the middleware wrapper by delegating through to the underlying response. The method implementation will look something like this:
func (w *wrapper) Hijack() (net.Conn, *bufio.ReadWriter, error) {
h, ok := w.underlyingResponseWriter.(http.Hijacker)
if !ok {
return nil, nil, errors.New("hijack not supported")
}
return h.Hijack()
}
If you don't know what the response writer wrapper is, add a statement to print the type from the handler:
func HandleConnections(w http.ResponseWriter, r *http.Request) {
fmt.Printf("w's type is %T\n", w)
...

To cite the docs on http.Hijacker:
~$ go doc http.Hijacker
package http // import "net/http"
type Hijacker interface {
// Hijack lets the caller take over the connection.
// After a call to Hijack the HTTP server library
// will not do anything else with the connection.
//
// It becomes the caller's responsibility to manage
// and close the connection.
//
// The returned net.Conn may have read or write deadlines
// already set, depending on the configuration of the
// Server. It is the caller's responsibility to set
// or clear those deadlines as needed.
//
// The returned bufio.Reader may contain unprocessed buffered
// data from the client.
//
// After a call to Hijack, the original Request.Body must not
// be used. The original Request's Context remains valid and
// is not canceled until the Request's ServeHTTP method
// returns.
Hijack() (net.Conn, *bufio.ReadWriter, error)
}
The Hijacker interface is implemented by ResponseWriters that allow an
HTTP handler to take over the connection.
The default ResponseWriter for HTTP/1.x connections supports Hijacker,
but HTTP/2 connections intentionally do not.
ResponseWriter wrappers may also not support Hijacker.
Handlers should always test for this ability at runtime.
So, I see several possibilities for your problem to happen:
You're trying to turn an HTTP/2 connection to a Websocket.
You're using some "middleware" which wraps whatever object the stock net/http package passes to your handler as net/http.ResponseWriter with something which does not bother to implement the proper Hijack method to support the net/http.Hijacker interface.

Related

How to get http.ResponseWriter and http.Request in Revel controller

I am trying to implement an oauth server and the package I am using needs the complete http.ResponseWriter and http.Request types.
c.Response does not contain all the methods that http.ResponseWriter does and c.Request gives error incompatible type.
How do I get http.ResponseWriter and http.Request in a Revel controller?
type client struct {
ClientId string
ClientSecret string
}
type App struct {
*revel.Controller
}
func (c App) TokenRequest() {
r := c.Request
w := c.Response
body, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(err)
}
log.Println(string(body))
var cli client
err = json.Unmarshal(body, &cli)
if err != nil {
panic(err)
}
log.Println(cli.ClientId)
err = OauthSrv.HandleTokenRequest(w, r)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
Warning
I am generally not fond of frameworks like Revel in Go, for reasons that I hope demonstrate themselves on this page. My first recommendation would be that you examine closely what you are actually getting out of Revel that merits the use of such a heavy abstraction layer, and if it's really that valuable, you may want to ask questions going in the other direction, such as how one might make OauthSrv work within Revel's customized ecosystem.
Using a Revel controller as a ResponseWriter
For something to be an http.ResponseWriter, it just needs to have these methods.
Header
You need a method named Header() that returns an http.Header, which you can build out of any map[string][]string. Revel provides similar functionality, but through several layers of abstraction. You will need to unravel them:
c.Response is a *Response, so it has a field named Out containing an OutResponse.
An OutResponse has a Header() method—but it doesn't return an http.Header. Instead, it returns a *RevelHeader.
A *RevelHeader has a GetAll(key string) []string method—which is very similar to the API already provided by the built-in map type, but isn't exactly the same. So, you will need to copy the returned values into a new map every time Header() is called, in order to fully satisfy the function signature requirements.
Also, GetAll() requires you to know the key name you are interested in, and *RevelHeader on its own does not provide a way to look up which keys are available. For now we can rely on the fact that the current implementation only has one field, a ServerHeader that does provide a GetKeys() []string method.
Putting all this together, we can build our Header method:
func (rrw RevelResponseWrapper) Header() http.Header {
revelHeader := rrw.Response.Out.Header()
keys := revelHeader.Server.GetKeys()
headerMap := make(map[string][]string)
for _, key := range keys {
headerMap[key] = revelHeader.GetAll(key)
}
return http.Header(headerMap)
}
Write and WriteHeader
You would use similar anti-patterns to expose rrw.Write([]byte) (int, error) so that it calls through to c.Response.Out.Write(data []byte) (int, error), and rrw.WriteHeader(int) error so that it calls c.Response.WriteHeader(int, string). Depending on what is considered appropriate for the framework, either panic on errors or fail silently, since their API doesn't expect WriteHeader errors to be handle-able.
Getting an http.Request from Revel
Unfortunately, the http.Request type is a struct, so you can't just simulate it. You basically have two options: reconstruct it using the net/http package from all the properties you are able to access, or hope that the *revel.Request you have is secretly an http.Request under the hood. In the latter case, you can use a type assertion:
revelReq, ok := c.Request.In.(*revel.GoRequest)
if !ok {
// handle this somehow
}
r := revelReq.Original

Passing along data with request [duplicate]

I am designing my handlers to return a http.Handler. Here's the design of my handlers:
func Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
})
}
My middleware is designed to accept an http.Handler and then call the handler once the middleware has finished performing its operations. Here's the design of my middleware:
func Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Middleware operations
next.ServeHTTP(w, r)
})
}
Considering the design of my middleware and handlers, what is the proper way of passing information from the middleware to the handler? The information that I am trying to pass from my middleware to the handlers is a JSON web token parsed from the request body. If I do not pass the parsed JWT to the handler, then I will need to parse the JWT again in my handlers. Parsing the request body for a JWT in both the middleware and handler seems wasteful. Just in case this information is relevant, I am using the standard net/http library with gorilla mux.
Since you're already using Gorilla take a look at the context package.
(This is nice if you don't want to change your method signatures.)
import (
"github.com/gorilla/context"
)
...
func Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Middleware operations
// Parse body/get token.
context.Set(r, "token", token)
next.ServeHTTP(w, r)
})
}
...
func Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := context.Get(r, "token")
})
}
Update
The Gorilla context package is now in maintenance mode
per the repo:
Note gorilla/context, having been born well before context.Context existed, does not play well with the shallow copying of the request that http.Request.WithContext (added to net/http Go 1.7 onwards) performs.
Using gorilla/context may lead to memory leaks under those conditions, as the pointers to each http.Request become "islanded" and will not be cleaned up when the response is sent.
You should use the http.Request.Context() feature in Go 1.7.
The proper way to pass request scoped data would now be the context package in the standard library.
https://golang.org/pkg/context/
You can access it with request.Context on an http.Request.
A first approach, similar to the question, is in codemodus/chain by Daved.
Package chain aids the composition of Handler wrapper chains that carry request-scoped data.
It uses the notion of Context, coupled with a Context handler:
func ctxHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
// ...
if s, ok := getMyString(ctx); ok {
// s = "Send this down the line."
}
// ...
}
Another approach: You can have a look at "Custom Handlers and Avoiding Globals in Go Web Applications", by Matt Silverlock (elithrar). (full example here)
The idea is to define ServeHTTP on a type which include the relevant context.
// We've turned our original appHandler into a struct with two fields:
// - A function type similar to our original handler type (but that now takes an *appContext)
// - An embedded field of type *appContext
type appHandler struct {
*appContext
h func(*appContext, http.ResponseWriter, *http.Request) (int, error)
}
// Our ServeHTTP method is mostly the same, and also has the ability to
// access our *appContext's fields (templates, loggers, etc.) as well.
func (ah appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Updated to pass ah.appContext as a parameter to our handler type.
status, err := ah.h(ah.appContext, w, r)
if err != nil {
log.Printf("HTTP %d: %q", status, err)
switch status {
case http.StatusNotFound:
http.NotFound(w, r)
// And if we wanted a friendlier error page, we can
// now leverage our context instance - e.g.
// err := ah.renderTemplate(w, "http_404.tmpl", nil)
case http.StatusInternalServerError:
http.Error(w, http.StatusText(status), status)
default:
http.Error(w, http.StatusText(status), status)
}
}
}
In the appContext struct, you would put any data you want to pass around.

Dealing with middleware that requires access to the database in Go

I am having an issue with creating a middleware that will be chained to other routes and requires access to the database and am not sure how to approach this problem.
I store all of my app context, including the database in a struct called AppContext. I want to create a function handler that looks something like this:
func SomeHandler(appC *AppContext, next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
// Access the database using appC.db
// Logic that requires access to the database.
next.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}
}
In main.go, I have tried:
someHandler := middleware.SomeHandler(&appC)
However, I get the error not enough arguments in call to middleware.SomeHandler. What would be the best way to approach this problem?
The error you're getting is due to not providing the second argument, next http.Handler.
In the case of how to go about the middleware, I recommend taking a look at the implementation of the http.ServeMux https://golang.org/src/net/http/server.go?s=57308:57433#L1890 it essentially does what you're trying to do (and then some) for routing though. So using a http.Handler struct might be more easy here than using a Handler function, this way the Handler(s) you'd have as the next http.Handler argument in your function are just a field within the struct that the parent handler can call from within its ServeHTTP().
So to wrap up my point, you might want to use a struct that implements the http.Handler interface. That way it can have child handlers and the DB access. That way you don't have to keep passing this AppContext either.
I'd not do a premature setup of the context. It is specifically there to be request scoped.
I'd rather create a small and dedicated middleware for passing a database session out of the pool into the context and retrieve said session created for the request in the main handler.
func DBSession(sess *mgo.Session, next http.Handler) http.Handler {
return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
// Create a new session for the scope of the request
s := sess.Copy()
// Make it close when exiting scope
defer s.Close()
// Add the new session (actually a pointer to it)
// acessible via the name "_sess"
ctx = context.WithValue(r.Context(), "_sess", s)
// execute the next handler
next(w, r.WithContext(ctx))
})
}
Now you can use this middleware in you main.go
package main
import (
"net/http"
"gopkg.in/mgo.v2"
)
func sayHello(w http.ResponseWriter, r *http.Request) http.Handler{
return http.HandlerFunc(
func (w http.ResponseWriter, r *http.Request) {
s := r.Context().Value("_sess").(*mgo.Session)
// Do something with your database here.
}
)
}
func main() {
// Ignoring err for brevity
sess, _ := mgo.Dial("localhost:27017")
// Magic happens here: the sayHello Handler is wrapped in the
// DBSession middleware, which makes the session available
// as context param _sess and closes the session after sayHello
// executed. No clutter in your controller for setting up and tearing down
// the session, no way you can forget to close it.
http.Handle("/", middleware.DBSession(sess, sayHello))
}

Update: Send the origin header with js websockets

I've been playing around with gorilla-websocket in Go, and as I implemented the basic echo example, I logged an error after deploying the server,
Origin is not found
Websocket version != 13
I found a way to bypass this by making the function that checks the origin always return true
var wsUpgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
But it doesn't feel right. Therefore, I am looking for a way to fix that issue.
Update: After having another look at the issue it seems like I'm actually looking to add the origin header to the client implementation which is the javascript websocket implementation
#benjic
Im connecting to the websocket via a javascript html5 application that isn't hosted on the same server but is run locally by me via chrome
So how do I do that.
Reading through the Gorilla WebSocket Documentation indicates that when a nil value is provided for the CheckOrigin field of an Upgrader type a safe default is used. The default checks the Origin field of the incoming request with the Host header value to confirm they are equal before allowing the request. The documentation indicates that browsers do not enforce cross origin validity and it is the responsibility of the server application to enforce. You can see exactly how this is done in the source code for the Gorilla library.
The documentation and source indicate an Upgrade function in the websocket package that acts as a factory for your example code above. The factory function takes a custom buffer size and overrides the CheckOrigin to always return true. Instead of creating a custom Upgrader you can use this factory function in the HttpHandler to upgrade your connections.
func webSocketHandler(w http.ResponseWriter, r *http.Request) {
conn, err := websocket.Upgrade(w, r, nil, 1024, 1024)
defer conn.Close()
if err != nil {
http.Error(w, err, http.StatusInternalServerError)
return
}
conn.WriteMessage(websocket.TextMessage, []byte("Hello, world!"))
}
Deploy your html to a server, e.g nginx or just use node to start. Then it will get a hostname & port in browser.
Then allow that address when create Upgrader , e.g:
var origins = []string{ "http://127.0.0.1:18081", "http://localhost:18081", "http://example.com"}
var _ = websocket.Upgrader{
// Resolve cross-domain problems
CheckOrigin: func(r *http.Request) bool {
var origin = r.Header.Get("origin")
for _, allowOrigin := range origins {
if origin == allowOrigin {
return true
}
}
return false
}}

How can I pass data from middleware to handlers?

I am designing my handlers to return a http.Handler. Here's the design of my handlers:
func Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
})
}
My middleware is designed to accept an http.Handler and then call the handler once the middleware has finished performing its operations. Here's the design of my middleware:
func Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Middleware operations
next.ServeHTTP(w, r)
})
}
Considering the design of my middleware and handlers, what is the proper way of passing information from the middleware to the handler? The information that I am trying to pass from my middleware to the handlers is a JSON web token parsed from the request body. If I do not pass the parsed JWT to the handler, then I will need to parse the JWT again in my handlers. Parsing the request body for a JWT in both the middleware and handler seems wasteful. Just in case this information is relevant, I am using the standard net/http library with gorilla mux.
Since you're already using Gorilla take a look at the context package.
(This is nice if you don't want to change your method signatures.)
import (
"github.com/gorilla/context"
)
...
func Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Middleware operations
// Parse body/get token.
context.Set(r, "token", token)
next.ServeHTTP(w, r)
})
}
...
func Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := context.Get(r, "token")
})
}
Update
The Gorilla context package is now in maintenance mode
per the repo:
Note gorilla/context, having been born well before context.Context existed, does not play well with the shallow copying of the request that http.Request.WithContext (added to net/http Go 1.7 onwards) performs.
Using gorilla/context may lead to memory leaks under those conditions, as the pointers to each http.Request become "islanded" and will not be cleaned up when the response is sent.
You should use the http.Request.Context() feature in Go 1.7.
The proper way to pass request scoped data would now be the context package in the standard library.
https://golang.org/pkg/context/
You can access it with request.Context on an http.Request.
A first approach, similar to the question, is in codemodus/chain by Daved.
Package chain aids the composition of Handler wrapper chains that carry request-scoped data.
It uses the notion of Context, coupled with a Context handler:
func ctxHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
// ...
if s, ok := getMyString(ctx); ok {
// s = "Send this down the line."
}
// ...
}
Another approach: You can have a look at "Custom Handlers and Avoiding Globals in Go Web Applications", by Matt Silverlock (elithrar). (full example here)
The idea is to define ServeHTTP on a type which include the relevant context.
// We've turned our original appHandler into a struct with two fields:
// - A function type similar to our original handler type (but that now takes an *appContext)
// - An embedded field of type *appContext
type appHandler struct {
*appContext
h func(*appContext, http.ResponseWriter, *http.Request) (int, error)
}
// Our ServeHTTP method is mostly the same, and also has the ability to
// access our *appContext's fields (templates, loggers, etc.) as well.
func (ah appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Updated to pass ah.appContext as a parameter to our handler type.
status, err := ah.h(ah.appContext, w, r)
if err != nil {
log.Printf("HTTP %d: %q", status, err)
switch status {
case http.StatusNotFound:
http.NotFound(w, r)
// And if we wanted a friendlier error page, we can
// now leverage our context instance - e.g.
// err := ah.renderTemplate(w, "http_404.tmpl", nil)
case http.StatusInternalServerError:
http.Error(w, http.StatusText(status), status)
default:
http.Error(w, http.StatusText(status), status)
}
}
}
In the appContext struct, you would put any data you want to pass around.

Resources