How to enable OPTIONS requests globally?

I am using HTTP handlers in 1.22, however, OPTIONS requests are automatically being rejected and a 405 sent to the client. For this reason, I am unable to call any POST endpoints from my SPA application. Is there a way to automatically allow OPTIONS requests globally without using third party tools/libraries?

I do it this way:

	switch r.Method {
	case "GET":
		Read(w, r)
	case "DELETE":
		Delete(w, r)
	case "POST":
		Create(w, r)
	case "PUT":
		Update(w, r)
	case "OPTIONS":
		// bugfix (handshake)
	default:
		Read(w, r)
	}

You should be able to just use something like this:

func newAppMux() *http.ServeMux {
	router := http.NewServeMux()
	// Global options handler
	router.HandleFunc("OPTIONS /", handleOptions)
	return router
}

func handleOptions(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Origin", "https://myapp.com")
	w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
	w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, Authorization")
	w.WriteHeader(http.StatusOK)
}

A note about “/” in the pattern. From the docs:

The special wildcard {$} matches only the end of the URL. For example, the pattern “/{$}” matches only the path “/”, whereas the pattern “/” matches every path.

So that matches every path for that method (“OPTIONS”). For further reading on CORS and understanding of what headers you might want to set, check this out.

1 Like

You can enable CORS (Cross-Origin Resource Sharing) for all requests using modules like mod_headers or mod_rewrite .

There is no need to declare a global OPTIONS handler for CORS, though; and rather than implementing CORS by hand, which is error-prone, I’d recommend using a dedicated library. Here is an example:

package main

import (
  "io"
  "log"
  "net/http"

  "github.com/jub0bs/cors"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("GET /hello", handleHello) // note: not configured for CORS

  // create CORS middleware
  corsMw, err := cors.NewMiddleware(cors.Config{
    Origins:        []string{"https://example.com"},
    Methods:        []string{http.MethodGet, http.MethodPost},
    RequestHeaders: []string{"Authorization"},
  })
  if err != nil {
    log.Fatal(err)
  }
  corsMw.SetDebug(true) // turn debug mode on (optional)

  api := http.NewServeMux()
  api.HandleFunc("GET /users", handleUsersGet)
  api.HandleFunc("POST /users", handleUsersPost)
  mux.Handle("/api/", http.StripPrefix("/api", corsMw.Wrap(api))) // note: method-less pattern here

  log.Fatal(http.ListenAndServe(":8080", mux))
}

func handleHello(w http.ResponseWriter, _ *http.Request) {
  io.WriteString(w, "Hello, World!")
}

func handleUsersGet(w http.ResponseWriter, _ *http.Request) {
  // omitted
}

func handleUsersPost(w http.ResponseWriter, _ *http.Request) {
  // omitted
}

Enabling OPTIONS requests globally typically involves configuring your web server to respond to OPTIONS requests for all resources. Here’s how you can achieve this for popular web servers:

Apache: You can enable OPTIONS requests globally in Apache by adding the following lines to your .htaccess file or Apache configuration:

apache

Copy code

<LimitExcept GET POST>
    Require all granted
</LimitExcept>

This configuration allows all HTTP methods except GET and POST, including OPTIONS.

Nginx: In Nginx, you can enable OPTIONS requests globally by adding the following configuration inside your server block:

nginx

Copy code

location / {
    if ($request_method = OPTIONS ) {
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, HEAD";
        add_header Access-Control-Allow-Headers "Authorization, Origin, X-Requested-With, Content-Type, Accept";
        add_header Content-Length 0;
        return 200;
    }
}

This configuration responds with appropriate CORS headers for OPTIONS requests.

IIS (Internet Information Services): In IIS, you can enable OPTIONS requests globally by adding the following configuration to your web.config file:

xml

Copy code

<system.webServer>
    <httpProtocol>
        <customHeaders>
            <add name="Access-Control-Allow-Origin" value="*" />
            <add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS, HEAD" />
            <add name="Access-Control-Allow-Headers" value="Authorization, Origin, X-Requested-With, Content-Type, Accept" />
        </customHeaders>
    </httpProtocol>
</system.webServer>

This configuration adds CORS headers to the response for OPTIONS requests.

After making these changes, your web server should respond to OPTIONS requests with appropriate CORS headers, allowing cross-origin requests to your resources. Make sure to test your configuration to ensure it behaves as expected. Additionally, consider the security implications of allowing OPTIONS requests globally and adjust your configuration accordingly.