Gorilla sessions cookie usage with a wrapper - go

I am using a basic wrapper in a web application like this:
package main
import (
"fmt"
"log"
"net/http"
"os"
"github.com/gorilla/mux"
"github.com/gorilla/sessions"
)
const (
PORT = "8083"
)
func navbarWrapper(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "header")
h(w, r) // call original function
fmt.Fprintln(w, "footer")
}
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/cookie_write", navbarWrapper(cookie_write))
hostname, _ := os.Hostname()
log.Printf("Listening on port %s https://%s:%s/", PORT, hostname, PORT)
http.ListenAndServe(":"+PORT, r)
}
I would like to set a cookie, but it is not being sent to the browser, but is also not providing an error
var (
key = []byte("16bytestufffffff")
store = sessions.NewCookieStore(key)
)
func cookie_write(w http.ResponseWriter, r *http.Request) {
session, _ := store.Get(r, "session-name")
session.Values["authenticated"] = true
session.Values["stuff"] = "important info"
if err := session.Save(r, w); err != nil {
fmt.Println(err)
fmt.Println("error")
} else {
fmt.Println("worked?")
}
}
If I remove the wrapper, then it works fine and I can see the cookie being generated in the browser:
r.HandleFunc("/cookie_write", cookie_write)
I know I must not be saving the session correctly, but I can't figure out how to do it.

Related

Why is my GO server not displaying my HTML files in the browser?

I am doing a GO course, and whenever I run my server code, I don't get any errors but when I try to type in "localhost:8080" in the browser, I get a message saying "localhost didn’t send any data. ERR_EMPTY_RESPONS". I have the same exact code as the course, except I am using HTML and not TMPL. Why isn't my HTML displaying in the browser?
package main
import (
"fmt"
"html/template"
"net/http"
)
const portNumber = ":8080"
func Home(w http.ResponseWriter, r *http.Request) {
renderTemplate(w, "home.html")
}
func About(w http.ResponseWriter, r *http.Request) {
}
func renderTemplate(w http.ResponseWriter, html string) {
parsedTemplate, _ := template.ParseFiles("./templates" + html)
err := parsedTemplate.Execute(w, nil)
if err != nil {
fmt.Println("error parsing template:", err)
return
}
}
func main() {
http.HandleFunc("/", Home)
http.HandleFunc("/about", About)
fmt.Println(fmt.Sprintf("Starting App on port %s", portNumber))
_ = http.ListenAndServe(portNumber, nil)
}
The ParseFiles method takes a path. You're missing the / after "./templates". So it should be:
parsedTemplate, _ := template.ParseFiles("./templates/" + html)

How to simulate multiple different HTTP responses using Go's httptest?

I have created some Go functions that make HTTP GET calls to services that are out there on the internet and parse the results.
I am now working on writing test-cases for these functions.
In my test cases, I'm using the go package httptest to simulate calls to these external services. Below is my code. Error checking is purposefully removed for brevity. Here is the go-playground.
package main
import (
"fmt"
"io"
"context"
"net/http"
"net/http/httptest"
)
func handlerResponse() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"A":"B"}`))
})
}
func buildMyRequest(ctx context.Context, url string) *http.Request {
request, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
return request
}
func myPrint(response *http.Response) {
b := make([]byte, 60000)
for {
_, err := response.Body.Read(b)
if err == io.EOF {
break
}
}
fmt.Println(string(b))
}
func main() {
srv := httptest.NewServer(handlerResponse())
client := http.Client{}
myResponse1, _ := client.Do(buildMyRequest(context.Background(), srv.URL))
fmt.Println("myResponse1:")
myPrint(myResponse1)
myResponse2, _ := client.Do(buildMyRequest(context.Background(), srv.URL))
fmt.Println("myResponse2:")
myPrint(myResponse2)
}
This is the output it produces:
myResponse1:
{"A":"B"}
myResponse2:
{"A":"B"}
As you can see, I have created some dummy HTTP response data {"A":"B"} and when you send an HTTP request to srv.URL, it actually hits an ephemeral HTTP server which responds with the dummy data. Cool!
When you send the second HTTP request to srv.URL, it again responds with the same dummy data. But this is where my problem arises. I want the ephemeral HTTP server to return some different data the second time {"C":"D"} and third time {"E":"F"} it receives a request.
How can I change the first line of the main() function so that the server responds with my desired data on subsequent HTTP calls?
you could use a hack like follows ( playground : here)
package main
import (
"fmt"
"io"
"context"
"net/http"
"net/http/httptest"
"sync"
)
type responseWriter struct{
resp map[int]string
count int
lock *sync.Mutex
}
func NewResponseWriter()*responseWriter{
r := new(responseWriter)
r.lock = new(sync.Mutex)
r.resp = map[int]string{
0: `{"E":"F"}`,
1: `{"A":"B"}`,
2: `{"C":"D"}`,
}
r.count = 0
return r
}
func (r *responseWriter)GetResp()string{
r.lock.Lock()
defer r.lock.Unlock()
r.count ++
return r.resp[r.count%3]
}
func handlerResponse(rr *responseWriter) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(rr.GetResp()))
})
}
func buildMyRequest(ctx context.Context, url string) *http.Request {
request, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
return request
}
func myPrint(response *http.Response) {
b := make([]byte, 60000)
for {
_, err := response.Body.Read(b)
if err == io.EOF {
break
}
}
fmt.Println(string(b))
}
func main() {
rr := NewResponseWriter()
srv := httptest.NewServer(handlerResponse(rr))
client := http.Client{}
myResponse1, err := client.Do(buildMyRequest(context.Background(), srv.URL))
if err != nil{
fmt.Println(err)
return
}
defer myResponse1.Body.Close()
fmt.Println("myResponse1:")
myPrint(myResponse1)
myResponse2, err := client.Do(buildMyRequest(context.Background(), srv.URL))
if err != nil{
fmt.Println(err)
return
}
defer myResponse2.Body.Close()
fmt.Println("myResponse2:")
myPrint(myResponse2)
}

How to stop showing target URL in ReverseProxy in Golang using NewSingleHostReverseProxy()?

I am trying to have a reverse proxy in Golang, but I am unable to stop target ip from showing in browser ie. it is simply redirecting to wikipedia (target) rather than showing doing reverseproxy.
Can anyone tell what I am doing wrong?
package main
import (
"net/http"
"net/http/httputil"
"net/url"
"github.com/gorilla/mux"
)
func main() {
target := "https://www.wikipedia.org"
remote, err := url.Parse(target)
if err != nil {
panic(err)
}
proxy := httputil.NewSingleHostReverseProxy(remote)
r := mux.NewRouter()
r.HandleFunc("/forward/{rest:.*}", handler(remote, proxy))
http.ListenAndServe(":8080", r)
}
func handler(ur *url.URL, p *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
r.URL.Host = ur.Host
r.URL.Scheme = ur.Scheme
r.Host = ur.Host
r.URL.Path = mux.Vars(r)["rest"]
p.ServeHTTP(w, r)
}
}

golang http server send r.URL.Path over socket

I have a http server, and I want to send the r.URL.Path text to a client using a socket
I get a error: undefined: conn in conn.Write
This is becauase conn is defined in another function
What I have tried:
package main
import (
"net"
"io"
"net/http"
)
ln, _ := net.Listen("tcp", ":8081")
conn, _ := ln.Accept()
func hello(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "Hello world!")
conn.Write([]byte(r.URL.Path + "\n")) //Here I'm attemping to send it
}
func main() {
http.HandleFunc("/", hello)
http.ListenAndServe(":8000", nil)
}
Your problem is actually in the way you try to declare variables.
If you want your conn to be on global scope, use var
package main
import (
"io"
"net/http"
"net"
)
var ln, _ = net.Listen("tcp", ":8081")
var conn, _ = ln.Accept()
func hello(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "Hello world!")
conn.Write([]byte(r.URL.Path + "\n")) //Here I'm attemping to send it
}
func main() {
http.HandleFunc("/", hello)
http.ListenAndServe(":8000", nil)
}

Understanding mux router in golang

here is my code trying to display a base64 image it worked before using mux.
I've used http handlefunc before using mux, here i want to use mux and get the value of key.
package main
import (
"fmt"
"net/http"
"strconv"
base64 "encoding/base64"
"log"
"io"
"io/ioutil"
"os"
"github.com/gorilla/mux"
)
var (
Trace *log.Logger
Info *log.Logger
Warning *log.Logger
Error *log.Logger
)
func Init(
traceHandle io.Writer,
infoHandle io.Writer,
warningHandle io.Writer,
errorHandle io.Writer) {
Trace = log.New(traceHandle,
"TRACE: ",
log.Ldate|log.Ltime|log.Lshortfile)
Info = log.New(infoHandle,
"INFO: ",
log.Ldate|log.Ltime|log.Lshortfile)
Warning = log.New(warningHandle,
"WARNING: ",
log.Ldate|log.Ltime|log.Lshortfile)
Error = log.New(errorHandle,
"ERROR: ",
log.Ldate|log.Ltime|log.Lshortfile)
}
func get_info(r *http.Request){
fmt.Println(r.RemoteAddr)
fmt.Println(r.Header.Get("x-forwarded-for"))
fmt.Println(r.UserAgent())
fmt.Println(r.Referer())
}
func pix(w http.ResponseWriter, r *http.Request) {
Info.Println("Hi there, I love %s!", r.URL.Path[1:])
vars := mux.Vars(r)
key := vars["key"]
Info.Println("key", key)
var cookie *http.Cookie
cookie , err := r.Cookie("csrftoken")
if (err != nil ){
fmt.Printf("error")
fmt.Println(err)
}
get_info(r)
fmt.Printf(cookie.Value)
w.Header().Set("Content-Type", "image/jpeg")
p, err := base64.StdEncoding.DecodeString("iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAADMUlEQVRYw+2YTUgUYRjHZzOJIoNA+rrUyYNIRQgRHaLo4qFDBEGeunSxS9TFU0QEnhIh6IvokrUzO2uamRmbG6XmR/mVaKZpZVbYvvO143zszsxOz+yahNm+785sITEP72F3Z+adH8/zf5+PpagwtxKXj+Vj+Vg+lo/lY+W+WI4KpddKwWIQFUSF97nNLcLGZt75SiOHchEXfskDVmYjlowpiEoei3UT2ljcFJOpOd169C1Z2SuvgsdpB7cgzB16EV/byGM2xDIVPxQujKmBDF/2m2l0vFvmEin7N2v8kiiPiOeGlGHRvP1RdxA9eYtGR7pk2Pf6lI7RCoP2RaWkZWe3fsFc18hvesAHPGEFUc24ltnx3kyiCJwfRMs6dTXLdSIjO9Osal18qzKfE5V9coDxhlU7qS3uOyiaB55JDtkS2TKoLCLaOLPS4b02pQdCHiUfRKf653/d2kjZN6f10jYxI2EnrGk5H+2WsVi6ZZ8fVSmGQKaYyyFuR6ugmUtVrJo2C7HokeGq8447sYpOPBbo3XFzKC95626sZlz905sUM9XLGbXvtKtTOhZrQDApkhNNkiAOPo/viojh2YSZsj1aF2eQ5n2stuomNQjiiGQanrFufdCXP8gu8tbhjridJ6saVPKExXJrwlwfb3pnAg2Ut0tEBZFI8gza81Tik15DCDIoINQ7aQdBo90RMfrdwNaWLFY9opJGkBQrhCA/HXspQ8W1XHkN6vfWFiGH9ouwhdpJUFuy2JX3eg6uyqENpNHZYcUd02jcLMI2WO67UwZVv1G1HLMq3L83KuEbLPdY7IL2L42p0MMQiuzkq/ncwucOi6qPbWkWoPfCUsENpweUnP1EmE4XGhgagT72RyXolkSCHBbTU3By3fgJj8VyJW3CmSHl8oTWMJuYUUizVvtcsuyJ6J4J663CMLevXar/lJgnKNSgbphzKjriTn5i0F8eX9ODXnEzf6JHvjGtv+aNGdWCOEKnJRmpr5oFVQV8WTWglIKHMlPhv5uqQ1xGYfB5fRMPo+n2VmFbi7ChiS9oWBhZvXrI01TNLg7yPxt51v9rxMfysXwsH8vH+g+wfgDUr+5LcyNV4AAAAABJRU5ErkJggg==")
if err != nil {
http.Error(w, "internal error", 500)
return
}
w.Header().Set("Content-Length", strconv.Itoa(len(p))) //len(dec)
w.Write(p)
}
func main() {
Init(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr)
Info.Println("1")
r := mux.NewRouter()
Info.Println("2")
r.HandleFunc("/pix/{key}/pixel.gif", pix)
err := http.ListenAndServe(":9080", nil)
Info.Println("3")
if err != nil {
fmt.Println(err)
}
}
It seems that when i call http://localhost:9080/pix/2/pixel.gif
it doesn't call pix.
the url for calling it seems correct
any idea why ?
regards and thanks
It appears that you are not assigning r to anything, you should add the following at the end of your main:
http.Handle("/", r)

Resources