Is it possible to know what route is used in HandleFunc - go

I am using http.HandleFunc("/resource", resource.Handle) from the package net/http and I was wondering if there was a way to see what route (in this case /resource) is used to get you to resource.Handle? Or do I have to create a Mux for this?
I'd like to know this to extract the resource from the url path to do some magic with it...

Yes you can
The main points to do:
Use the DefaultServeMux used by the HandleFunc method.
Construct a fake http.Request
For Example:
package main
import (
"fmt"
"net/http"
"net/url"
)
func main() {
theUrl, err := url.Parse("/response")
if err != nil {
fmt.Println(err.Error())
return
}
http.HandleFunc("/response", func(w http.ResponseWriter, r *http.Request) {
})
handler, path := http.DefaultServeMux.Handler(&http.Request{Method: "GET", URL: theUrl})
fmt.Println(handler, path)
}
see this Go Playground

http://golang.org/pkg/net/http/#Request
Use request.URL.Path to get the path used to access the handler.

Related

Passing a URL as URL param

I have this route that was written with route params
/properties/configurations/:name/:value
and when I call with with a URL as value like that
/properties/configurations/app.url/http://test.test
it doesn't hit my Revel controller I guess because the slash confuses it. I tried when calling the Javascript request with encodeURIComponent() so it removes the slashes and other chars that are problematic but it still doesn't hit the controller and gives 404.
The problem is it is used in a public API and I cannot change it to pass this data in the body instead so I'm trying to figure out how can I make revel recognize the pattern and correctly put the values inside {name} and {value}
You just need to use one of the escape functions:
package main
import "net/url"
func main() {
s := "http://test.test"
{
t := url.PathEscape(s)
println(t == "http:%2F%2Ftest.test")
}
{
t := url.QueryEscape(s)
println(t == "http%3A%2F%2Ftest.test")
}
}
https://golang.org/pkg/net/url#PathEscape
https://golang.org/pkg/net/url#QueryEscape
If you're able to pass the URL encoded URL to your Golang server as a path variable, you can run it through url.PathUnescape(str).
If the problem is that your router isn't reaching the correct handlers because the characters in your path variable aren't matching correctly, it's possible that you've incorrectly defined that path matcher. I don't have experience with revel, but with mux (github.com/gorilla/mux) I would expect it to look like the following:
package main
import (
"net/http"
"net/url"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
r.HandleFunc("/properties/configurations/app.url/{nestedURL:.*}", myHandler)
http.ListenAndServe(":8080", r)
}
func myHandler(w http.ResponseWriter, r *http.Request){
nestedURL := mux.Vars(r)["nestedURL"]
unescapedPath, err := url.PathUnescape(nestedURL)
if err != nil {
// handle err
}
}
The above example might even work without requiring you to URL encode the nested URL (but I really do suggest you URL encode it).

How to mock many urls to return fixture content?

I'm writing some kind of a recursive parser. The simplest form is:
Take all links from first link's page body
Repeat the first step for each link
So now I want to test it. The problem is I can't figure out the best way to mock all these pages. I use http package and I already have some tests written using httptest package (via httptest.NewServer). But it seems to be no use for my task now. I guess the best way is to use http.Client with custom Transport struct, but it's lots of boilerplate and additional smelly code. Is there a more elegant way to do this?
I have used a custom Transport a couple of times for testing clients. Usually I would create some helper types and functions to cut down on boilerplate code.
Something like this could be a start.
package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
)
type roundTripFunc func(*http.Request) (*http.Response, error)
func (r roundTripFunc) RoundTrip(req *http.Request) (resp *http.Response, err error) {
return r(req)
}
func main() {
c := &http.Client{
Transport: roundTripFunc(func(req *http.Request) (resp *http.Response, err error) {
return &http.Response{
StatusCode: 200,
Body: ioutil.NopCloser(bytes.NewBufferString("test")),
}, nil
}),
}
r, _ := c.Get("/")
fmt.Printf("%#v\n", r)
io.Copy(os.Stdout, r.Body)
}
For example if your testing a JSON API client you could make a round trip helper function takes care of decoding, encoding, headers etc. In your case maybe you could make the round trip function map host header plus URL path into file fixtures paths?

golang check if javascript is enabled

this is my actual code :
package main
import (
"net/http"
"net/http/httputil"
"net/url"
)
const BaseUrl = "http://127.0.01:5000"
const ListeningPort = "80"
func main() {
// intercept call
http.HandleFunc("/test", Test)
// all other traffic pass on
http.HandleFunc("/", ProxyFunc)
http.ListenAndServe(":"+ListeningPort, nil)
}
func ProxyFunc(w http.ResponseWriter, r *http.Request) {
u, err := url.Parse(BaseUrl)
if err != nil {
w.Write([]byte(err.Error()))
return
}
proxy := httputil.NewSingleHostReverseProxy(u)
proxy.ServeHTTP(w, r)
}
func Test(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("TEST"))
}
first to accept client connexion, i want to check if browser have enabled javascript, how i can do this in my actual code ?
i want check with this method :
https://pastebin.com/ZASFQumf
It is not possible to do that in Golang since it is a server side language. I don't even think it is possible with JavaScript.
It is not something you can add/set/get from the headers.
What you are trying to do is check browser specific flags.
You might be able to find third party libraries used to manage Chrome flags or Firefox flags etc. That is your best option.

Sharing a gorilla/mux router across packages

I'm having some issues with implementing a slight MVC design with gorilla/mux.
The layout of the modules is as follows:
main.go
-- controllers
---- base.controller.go
---- example.controller.go
-- models
---- base.model.go
---- example.controller.go
All the files in controllers is in the controllers package, same with models and then the main.go is the main package.
Currently I'm just trying to get the Base Controller to be able to be shared with the main package which is working, although it's throwing some errors when trying to implement routes. The build is not throwing any errors, but the routes are not available. If I implement the Walk function in the Gorilla/Mux documentation to print out all the registered routes for the mux.Router then it gives me this error:
&{%!!(MISSING)s(*mux.Router=&{ [0xc4200901b0] map[] true
false false false}) %!!(MISSING)s(http.HandlerFunc=0xc8df0)
[%!!(MISSING)s(*mux.routeRegexp=&{/ false false true false
0xc420095360 / [] []})] %!!(MISSING)s(*mux.routeRegexpGroup=&{
0xc420016240 []}) %!!(MISSING)s(bool=true) %!!(MISSING)s(bool=false)
%!!(MISSING)s(bool=false) %!!(MISSING)s(bool=false)
%!!(MISSING)s(mux.BuildVarsFunc=)}
The reasoning for the global var V1Router *mux.Router is firstly to access it in the main package and also to create subrouters in the other controllers.
I am fairly new to Go, but I'm trying my best to learn the best practices! Any help would be greatly appreciated!
Example code below:
base.controllers.go
package controllers
import (
"fmt"
"bytes"
"net/http"
"github.com/gorilla/mux"
)
var V1Router *mux.Router
func init () {
V1Router = mux.NewRouter()
V1Router.StrictSlash(true)
V1Router.HandleFunc("/", BaseHandler)
}
// Base route to access the API Documentation.
func BaseHandler (w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello, Gophers!")
}
main.go
package main
import (
"net/http"
"log"
"github.com/projectrepo/project/models"
"github.com/projectrepo/project/controllers"
"github.com/gorilla/mux"
)
func main () {
http.Handle("/v1", controllers.V1Router)
if err := http.ListenAndServe(":8000", nil); err != nil {
log.Fatal("Serving error.")
}
}
In response to the comments, I tried this solution with the same result:
package main
import (
"net/http"
"log"
"github.com/projectrepo/project/models"
"github.com/projectrepo/project/controllers"
"github.com/gorilla/mux"
)
func main () {
r := mux.NewRouter()
r.Handle("/v1", controllers.V1Router)
if err := http.ListenAndServe(":8000", r); err != nil {
log.Fatal("Serving error.")
}
}
Gorilla mux.Router is supposed to be used to create mapping between a set of predefined rules (e.g. host, path, protocol, scheme, etc...) and it's handler (http.Handler or http.HandlerFunc). Gorilla mux can be used to replace standard server mux. If you combine gorilla/mux with built in http server mux as your original question, i.e.
func main () {
http.Handle("/v1", controllers.V1Router)
if err := http.ListenAndServe(":8000", nil); err != nil {
log.Fatal("Serving error.")
}
}
what actually happen when a client access /v1 is controllers.V1Router will be called with request path /v1 passed to V1Router1. In the controllers.V1Router, you defined that / will be handled by BaseHandler. However, since incoming request path is /v1, it won't match to your routing table. If you want to define sub routing, you can do as follows (this is what I mean in first comment):
func main () {
r := mux.NewRouter()
v1 := r.PathPrefix("/v1").Subrouter()
controllers.RegisterHandlers(v1)
if err := http.ListenAndServe(":8000", r); err != nil {
log.Fatal("Serving error.")
}
}
Then in the controllers (base.controllers.go) define
//Register handlers and it's sub router
func RegisterHandlers(r *mux.Router) {
//base handler, i.e. /v1
r.StrictSlash(true)
r.HandleFunc("/", BaseHandler)
//example sub-router, i.e. /v1/example
ex := r.PathPrefix("/example").Subrouter()
ex.HandleFunc("/", ExampleHandler)
//other handlers...
}

Golang - User of package without selector

Please, I searched this a lot and after not been able to find, I am writing and not that I didn't try to search all over first. Couldn't get the right answer. I even tried to check Revel's function and couldn't get the answer from there as well.
When I run this program I get this error for line
./test.go:11: use of package http without selector
This error points at the line below where I have written
*http
inside the struct
Confusing part is that with test and dot I even get auto complete with VIM. So I don't know why is the error. Is it that it has to be somewhat like
*(net/http)
or something like that ?
package main
import (
"fmt"
"net/http"
)
type HandleHTTP struct {
*http
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Path is %s", r.URL.Path[1:])
}
func main() {
test := HandleHTTP{}
test.http.HandleFunc("/", handler)
test.http.ListenAndServe(":8080", nil)
}
If you want to have two or more instances serving from different ports you need to spin up two, or more, server. Would something like this, perhaps, work for you?
package main
import (
"fmt"
"net/http"
)
type HandleHTTP struct {
http *http.Server
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Path is %s", r.URL.Path[1:])
}
func main() {
mux1 := http.NewServeMux()
mux1.HandleFunc("/", handler)
test1 := HandleHTTP{http:&http.Server{Addr:":8081", Handler:mux1}}
mux2 := http.NewServeMux()
mux2.HandleFunc("/", handler)
test2 := HandleHTTP{http:&http.Server{Addr:":8082", Handler:mux2}}
// run the first one in a goroutine so that the second one is executed
go test1.http.ListenAndServe()
test2.http.ListenAndServe()
}

Resources