Go http无法处理没有PATH的HTTP请求

I am writing a small HTTP server that receives HTTP POSTs from some embedded devices. Unfortunately these devices send malformed POST request that contain no PATH component:

POST  HTTP/1.1
Host: 192.168.13.130:8080
Content-Length: 572
Connection: Keep-Alive

<?xml version="1.0"?>
....REST OF XML BODY

Due to this the Go http never passes the request to any of my handlers and always responds with 400 Bad Request.

Since these are embedded devices and changing the way they send the request is not an option I though maybe I could intercept the HTTP requests and if no PATH is present add one (e.g. /) to it before it passes to the SeverMux.

I tried this by creating my own CameraMux but Go always responds with 400 Bad Request even before calling the ServeHTTP() method from my custom ServeMux (see code below).

Is there a way to modify the Request object at some point before Go http responds Bad Request or there is a way to make Go accept the request even if it has no PATH?

package main

import (
  "net/http"                            
  "log"
  "os"
)

type CameraMux struct {                 
  mux *http.ServeMux                    
} 

func (handler *CameraMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  // Try to fix URL.Path here but the server never reaches this method.    
  log.Printf("URL %v
", r.URL.Path)
  handler.mux.ServeHTTP(w, r)
}

func process(path string) error {
  log.Printf("Processing %v
", path)
  // Do processing based on path and body  
  return nil
}

func main() {

  http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

    path := r.URL.Path[1:]

    log.Printf("Processing path %v
", path) 

    err := process(path)

    if err != nil {
      w.WriteHeader(http.StatusBadRequest) 
    } else {
      w.WriteHeader(http.StatusOK)
    }
  })

  err := http.ListenAndServe(":8080", &CameraMux{http.DefaultServeMux})

  if err != nil {
    log.Println(err)
    os.Exit(1)
  }

  os.Exit(0)
}

The error you are seeing occurs within the request parsing logic, which happens before ServeHTTP is called.

The HTTP request is read from the socket by the ReadRequest function from the net/http package. It will tokenize the first line of the request with an empty URL portion, but then goes on to parse the URL:

if req.URL, err = url.ParseRequestURI(rawurl); err != nil {
    return nil, err
}

Unfortunately this function will return an error for an empty URL string, which will in turn aborts the request reading process.

So it doesn't look like there is an easy way to achieve what you're after without modifying the standard library code.

I'm unsure if Go's HTTP parser will allow requests with no URI path element. If it doesn't then you're out of luck. If it does however; you could overwrite the request's path like this:

type FixPath struct {}

func (f *FixPath) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    r.RequestURI = "/dummy/path" // fix URI path
    http.DefaultServeMux.ServeHTTP(w, r) // forward the fixed request to http.DefaultServeMux
}

func main() {

    // register handlers with http.DefaultServeMux through http.Handle or http.HandleFunc, and then...

    http.ListenAndServe(":8080", &FixPath{})
}