Last active
November 11, 2019 03:38
-
-
Save ismiyati/1b91c9a2b700192fc4188764ada16b2b to your computer and use it in GitHub Desktop.
#golang . latihan uintptr : https://golang.org/pkg/builtin/#uintptr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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


