CORS Boilerplate in Go

10/15/2017

Edit: Since this writing, rs/cors has been identified as the easiest and best way to do CORS in Go.

/*
 * Boilerplate for handling CORS preflighted requests.
 * https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests
 */
package main

import (
	"fmt"
	"log"
	"net/http"
	"strings"
)

// Define length of time results of preflight
// can be cached
// https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Access-Control-Max-Age
var MaxAge = "60"

// Define all allowed methods here.
var AllowedMethods = map[string]bool{
	"GET":  true,
	"POST": true,
}

// Define all allowed headers here.
var AllowedHeaders = map[string]bool{
	"XPING": true,
}

// Define all allowed origins here.
// Can be wildcard ("*") or exactly ONE URI (e.g. "www.nhatqbui.com")
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
var AllowedOrigins = "*"

func getKeys(m map[string]bool) []string {
	keys := make([]string, 0, len(m))
	for k := range m {
		keys = append(keys, k)
	}
	return keys
}

// Example method handling preflight requests and normal requests.
func handleAjaxHello(w http.ResponseWriter, r *http.Request) {
	if r.Method == "OPTIONS" {
		// Handle pre-flight here.
		// Note: We begin by manually checking the headers of the preflight.
		//       We can actually respond with the information communicated
		//       in the response headers and the browser should handle
		//       whether the subsequent is carried out. Here, we are being
		//       very explicit and checking the headers ourselves.

		// Pre-flight will indicate the method of the actual request.
		// Check that the method is a member of the set of allowed methods.
		reqMethod, ok := r.Header["Access-Control-Request-Method"]
		if !ok {
			// Handle unspecified methods here
			// In this example, we don't do anything and return.
			return
		}

		hasMethod := false
		for _, method := range reqMethod {
			if AllowedMethods[method] {
				hasMethod = true
				break
			}
		}
		if !hasMethod {
			// Handle incorrect methods here
			// In this example, we don't do anything and return.
			return
		}

		// Check that subsequent request will have appropriate headers.
		// This one is more nuanced. You should consider:
		//   - should the request contain ALL allowed headers?
		//   - or should the request headers be allowed headers
		//     (but not necessarily containing all allowed headers)
		// Here, we just check that the request headers are allowed headers.
		// Whether it has-all-necessary-headers is not checked.
		reqHeaders, ok := r.Header["Access-Control-Request-Headers"]
		if !ok {
			// Handle unspecified methods here.
			// In this example, we don't do anything and return.
			return
		}
		for _, headers := range reqHeaders {
			for _, header := range strings.Split(headers, ",") {
				if !AllowedHeaders[header] {
					// Handle incorrect headers here
					// In this example, we don't do anything and return.
					return
				}
			}
		}

		// We arrived here, the preflight has passed our checks
		// And the subsequent request will be valid.
		w.Header().Set("Access-Control-Allow-Origin", AllowedOrigins)
		w.Header().Set("Access-Control-Allow-Methods", strings.Join(getKeys(AllowedMethods), ","))
		w.Header().Set("Access-Control-Allow-Headers", strings.Join(getKeys(AllowedHeaders), ","))
		w.Header().Set("Access-Control-Max-Age", MaxAge)
	} else if r.Method == "POST" {
		var jsonStr = []byte(fmt.Sprintf(`{"data":"PONG"}`))
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.Write(jsonStr)
	}
}

func main() {
	http.HandleFunc("/ajax/hello", handleAjaxHello)

	err := http.ListenAndServeTLS(":8080", "./certs/testing.crt", "./certs/testing.key", nil)
	if err != nil {
		log.Fatal("ListenAndServer: ", err)
	}
}

Python Protobuf 'syntax' Error

08/20/2017

A common error somebody may encounter using Python protobufs on common Linux distros is:

TypeError: __init__() got an unexpected keyword argument 'syntax'

This is most likely due to the fact that a lot of OSs have an outdated version of the Python protobuf package. Typically a user may acquire protobuf tools from the OS package manager like

sudo apt-get install protobuf-compiler
sudo apt-get install python-protobuf

The protobuf compiler will compile a version of the protobuf which has a syntax the python-protobuf, the package that allows you to do import google.protobuf, doesn’t understand. Specifically, all objects will be passed a syntax field to their __init__ function. Update Python protobuf by visiting the repo and getting the latest version.

Ducktyping + Python Protobuf

08/18/2017

Given a compiled Python protobuf as follows:

message Person {
    optional string email = 1;
}

Don’t use duck typing to see if an optional field has been set!

Though the value is known to be unset, accessing the value always returns a default value! (Source. See optional field description.)

import Person_pb2

person = Person()

if person.email:
    print('Oh wow you totally have an email!')
    print('It is: '.format(person.email))
else:
    print('I got nothing')

> Oh wow you totally have an email!

> It is:

Use the compiled protobuf’s data member functions to check existance:

if person.HasField('email'):
    # do stuff

It’s not very clear you need to do it like this…

REST Example

08/17/2017

Not RESTful

REST interface: “Do something and let me know when you’re done.”

Resource: “K.”

Resource: “Hey, I’m done.”

REST interface: “K.”

RESTful

REST interface: “Do something.”

Resource: “K.”

REST interface: “Are you done?”

Resource: “No.”

REST interface: “Are you done?”

Resource: “No.”

REST interface: “Are you done?”

Resource: “No.”

REST interface: “Are you done?”

Resource: “No.”

Portrait Mode

07/10/2017

Portrait Mode