Title Text

Golang HTTP server for pro

Thomas Perez

@scullwm

Meetup Golang Marseille

Thomas Perez

Lead dev backend

Go|PHP

twitter.com/scullwm

PepperReport.io 🌶

github.com/scullwm

HTTP Server for pro

HTTP Server for pro



import "net/http"

Server

ServeMux

Transport

Client

Response

Request

TLS

Flusher

HTTP2

Proxy

Push

package main


import (
	"io"
	"net/http"
)


func main() {
	http.HandleFunc("/", helloWorldHandler)
	http.ListenAndServe(":80", nil)
}


func helloWorldHandler(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "Hello world!")
}

HTTP Server for pro

Let's start

THE END!

HTTP Server for pro

HTTP Server for pro

Log ?
Advanced routing ?
Security ?
Error ?

Who need a
"hello world" application ?

HTTP Server for pro

Advanced routing

HTTP Server for pro

package main

import (
	"io"
	"net/http"
        "gorilla/mux"
)

func main() {
        r := mux.NewRouter()
        r.HandleFunc("/products/{key}", ProductHandler).Name("product").Methods("GET")
        r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
        r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
        http.Handle("/", r)
}

https://github.com/gorilla/mux

HTTP Server for pro

func(http.Handler) http.Handler

Middleware

HTTP Server for pro


func doingThings(next http.Handler) http.Handler {

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

		log.Printf("I'm doing things here, really!")
		next.ServeHTTP(w, r)

	})

}

HTTP Server for pro

func loggerHandler(h http.Handler) http.Handler {

    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

        start := time.Now()

        h.ServeHTTP(w, r)

        log.Printf("<< %s %s %v", r.Method, r.URL.Path, time.Since(start))
    })

}

Let's log response time

HTTP Server for pro

What about security?

HTTP Server for pro

There's a middleware for that

func checkAuth(h http.Handler) http.Handler {

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

		if ReadCookieHandler(r) {
			h.ServeHTTP(w, r)
		} else {
			log.Printf("Not authorized %s", 401)
		}

		h.ServeHTTP(w, r)
	})

}

HTTP Server for pro

const cookieName = "mycookiename"

var hashKey = []byte(securecookie.GenerateRandomKey(32))
var blockKey = []byte(securecookie.GenerateRandomKey(32))

var sc = securecookie.New(hashKey, blockKey)

func ReadCookie(r *http.Request) bool {

	if cookie, err := r.Cookie(cookieName); err == nil {
		value := make(map[string]string)
		if err = sc.Decode(cookieName, cookie.Value, &value); err == nil {
			return true
		}
	}

	return false
}

using securecookie and bcrypt

https://github.com/gorilla/securecookie

HTTP Server for pro

Organize theses middlewares

HTTP Server for pro

HTTP Server for pro

Before

After

Middleware1(Middleware2(Middleware3(App)))
alice.New(Middleware1, Middleware2, Middleware3).Then(App)

HTTP Server for pro

    publicChain := alice.New(loggerHandler, recoverHandler)
    
    privateChain := alice.New(loggerHandler, recoverHandler, authHandler)
    
    apiChain := alice.New(loggerHandler, recoverHandler, rateLimitHandler, jsonHandler)



    r := mux.NewRouter()
    r.HandleFunc("/products/{key}", ProductHandler)
    r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
    r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
    http.Handle("/", publicChain.then(r))


    http.Handle("/api", apiChain.Then(r))
    http.Handle("/cart", privateChain.Then(r))


    r.PathPrefix("/").Handler(http.FileServer(http.Dir("./static/")))

Chain them

HTTP Server for pro

HTTPS ?

With let's encrypt!

HTTP Server for pro

package main

import (
	"crypto/tls"
	"golang.org/x/crypto/acme/autocert"
	"io"
	"log"
	"net/http"
)

func main() {
	s := &http.Server{
		Addr: ":443",
	}

	m := autocert.Manager{
		Prompt:     autocert.AcceptTOS,
		Cache:      autocert.DirCache("/tmp/acme/"),
		HostPolicy: autocert.HostWhitelist("secure.500peppers.com"),
	}
	// Configure extra tcp/80 server for http-01 challenge:
	// https://godoc.org/golang.org/x/crypto/acme/autocert#Manager.HTTPHandler
	httpServer := &http.Server{
		Handler: m.HTTPHandler(nil),
		Addr:    ":80",
	}
	go httpServer.ListenAndServe()

	http.HandleFunc("/", helloWorldHandler)

	s.TLSConfig = &tls.Config{GetCertificate: m.GetCertificate}
	log.Fatal(s.ListenAndServeTLS("", ""))
}

HTTP Server for pro

HTTP Server for pro

Ready ?

Questions ?

Golang http server for pro

By Thomas Perez

Golang http server for pro

Meetup Golang #3

  • 1,152