Skip to content

Instantly share code, notes, and snippets.

@ismiyati
Last active November 11, 2019 03:38
Show Gist options
  • Select an option

  • Save ismiyati/1b91c9a2b700192fc4188764ada16b2b to your computer and use it in GitHub Desktop.

Select an option

Save ismiyati/1b91c9a2b700192fc4188764ada16b2b to your computer and use it in GitHub Desktop.
#golang . latihan uintptr : https://golang.org/pkg/builtin/#uintptr
package main
import (
"crypto/rand"
"fmt"
"net/http"
"unsafe"
"github.com/cespare/xxhash"
)
var _kode = []byte("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-")
func UInt64ToBase64(d uint64) (s [11]byte) {
copy(s[:], "+++++++++++")
i := 0
for d > 0 {
s[i] = _kode[d&63]
i++
d = d >> 6
}
return
}
var kode_ = func() (kode [123]byte) {
for i := 0; i < 123; i++ {
kode[i] = 64
}
for i := byte(48); i < 58; i++ {
kode[i] = i - 48 //'0' - '9' -> 0 - 9
}
for i := byte(97); i < 123; i++ {
kode[i] = i - 87 //'a' - 'z' -> 10 - 35
}
for i := byte(65); i < 91; i++ {
kode[i] = i - 29 //'A' - 'Z' -> 36 - 61
}
kode[95] = 62 //'_' -> 62
kode[45] = 63 //'-' -> 63
return
}()
func Base64ToUInt64(s string) (d uint64, err error) {
i := 10
for i >= 0 && s[i] == ' ' {
i--
}
for i >= 0 && s[i] < 123 {
d = d << 6
mod := kode_[s[i]]
if mod == 64 {
break
}
d = d | uint64(mod)
i--
}
if i >= 0 {
return 0, fmt.Errorf("Invalid character: '%c'", s[i])
}
return
}
func PutUint64(bfr *[8]byte, data uint64) {
for i := 0; data > 0; i++ {
(*bfr)[i] = byte(data)
data = data >> 8
}
}
func Uint64(bfr [8]byte) (ret uint64) {
for i := 7; i >= 0; i-- {
if bfr[i] == 0 {
continue
}
ret = (ret << 8) | uint64(bfr[i])
}
return
}
func HashBase64(data uint64) [11]byte {
bfr := [8]byte{}
PutUint64(&bfr, data)
return UInt64ToBase64(xxhash.Sum64(bfr[:]))
}
func HashVerify(data, hash string, s3cr3t uint64) (uint64, bool) {
v, err1 := Base64ToUInt64(data)
if err1 != nil {
return 0, true
}
bfr := [8]byte{}
PutUint64(&bfr, v^s3cr3t)
vHash, err2 := Base64ToUInt64(hash)
return v, err2 != nil && xxhash.Sum64(bfr[:]) != vHash
}
type RW struct {
http.ResponseWriter
Msg string
}
type Handler struct {
Next *http.ServeMux
S3cr3t uint64
}
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
hndlr := r.FormValue("hndlr")
hash := r.FormValue("hash")
if hndlr != "" && hash != "" {
hndlr_, rqErr := HashVerify(hndlr, hash, h.S3cr3t)
if rqErr {
http.Error(w, "bad request", http.StatusBadRequest)
return
}
hndlrPtr := (*func(http.ResponseWriter, *http.Request))(unsafe.Pointer(uintptr(hndlr_)))
(*hndlrPtr)(RW{w, "direct handler call"}, r)
} else {
h.Next.ServeHTTP(RW{w, "via routing"}, r)
}
}
func root(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.Write([]byte(`
<html>
<head></head>
<body>
<a href="javascript:GET('/page1', putResponse)">/page1</a> | <a href="javascript:GET('/page2', putResponse)">/page2</a><br>
<div id="responsePlaceHolder"></div>
<script>
var path = {
"/page1": "",
"/page2": ""
}
function GET(url, cb){
var xhr = new XMLHttpRequest()
if(!xhr){
return alert('Giving up : Cannot create an XMLHTTP instance')
}
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText)
try {
var res = JSON.parse(xhr.responseText)
path[url] = '&hndlr=' + res.hndlr +'&hash=' + res.hash
cb(res.content)
}catch(e){alert(e)}
}
}
xhr.open('GET', url + '?now=' + (new Date).getTime() + path[url])
xhr.send()
}
function putResponse(response){
responsePlaceHolder.innerHTML = 'response:<br>' + response
}
</script>
</body>
</html>
`))
}
func page1(hndlr *func(http.ResponseWriter, *http.Request), s3cr3t uint64) {
hndlrUInt64 := uint64(uintptr(unsafe.Pointer(hndlr)))
hndlrBase64 := UInt64ToBase64(hndlrUInt64) //sent to client
hndlrHash := HashBase64(hndlrUInt64 ^ s3cr3t) //sent to Client
*hndlr = func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, `{"hndlr": "%s", "hash": "%s", "content": "content for /page1<br>%s"}`, hndlrBase64, hndlrHash, w.(RW).Msg)
}
}
func page2(hndlr *func(http.ResponseWriter, *http.Request), s3cr3t uint64) {
hndlrUInt64 := uint64(uintptr(unsafe.Pointer(hndlr)))
hndlrBase64 := UInt64ToBase64(hndlrUInt64) //sent to client
hndlrHash := HashBase64(hndlrUInt64 ^ s3cr3t) //sent to Client
*hndlr = func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, `{"hndlr": "%s", "hash": "%s", "content": "content for /page2<br>%s"}`, hndlrBase64, hndlrHash, w.(RW).Msg)
}
}
func main() {
s3cr3t := func() uint64 {
bfr := [8]byte{}
rand.Read(bfr[:])
return Uint64(bfr)
}()
var page1Hndlr, page2Hndlr func(http.ResponseWriter, *http.Request)
page1(&page1Hndlr, s3cr3t)
page2(&page2Hndlr, s3cr3t)
mux := http.NewServeMux()
mux.HandleFunc("/", root)
mux.HandleFunc("/page1", page1Hndlr)
mux.HandleFunc("/page2", page2Hndlr)
http.ListenAndServe(":8080", &Handler{mux, s3cr3t})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment