Skip to content

Instantly share code, notes, and snippets.

@teknoraver
Last active March 21, 2024 11:48
Show Gist options
  • Save teknoraver/5ffacb8757330715bcbcc90e6d46ac74 to your computer and use it in GitHub Desktop.
Save teknoraver/5ffacb8757330715bcbcc90e6d46ac74 to your computer and use it in GitHub Desktop.
HTTP over Unix domain sockets in golang
package main
import (
"context"
"flag"
"fmt"
"io"
"net"
"net/http"
"os"
"strings"
)
func main() {
post := flag.String("d", "", "data to POST")
help := flag.Bool("h", false, "usage help")
flag.Parse()
if *help || len(flag.Args()) != 2 {
fmt.Fprintln(os.Stderr, "usage:", os.Args[0], "[-d data] /path.socket /uri")
flag.PrintDefaults()
os.Exit(0)
}
fmt.Println("Unix HTTP client")
httpc := http.Client{
Transport: &http.Transport{
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial("unix", flag.Args()[0])
},
},
}
var response *http.Response
var err error
if len(*post) == 0 {
response, err = httpc.Get("http://unix" + flag.Args()[1])
} else {
response, err = httpc.Post("http://unix"+flag.Args()[1], "application/octet-stream", strings.NewReader(*post))
}
if err != nil {
panic(err)
}
io.Copy(os.Stdout, response.Body)
}
package main
import (
"fmt"
"net"
"net/http"
"os"
)
func main() {
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "usage:", os.Args[0], "/path.sock [wwwroot]")
return
}
fmt.Println("Unix HTTP server")
root := "."
if len(os.Args) > 2 {
root = os.Args[2]
}
os.Remove(os.Args[1])
server := http.Server{
Handler: http.FileServer(http.Dir(root)),
}
unixListener, err := net.Listen("unix", os.Args[1])
if err != nil {
panic(err)
}
server.Serve(unixListener)
}
@DeadlySurgeon
Copy link

Thanks!

To preserve the context, I would recommend:

				DialContext: func(ctx context.Context, _, addr string) (net.Conn, error) {
					dialer := net.Dialer{} // don't know why we need a struct to use DialContext()
					return dialer.DialContext(ctx, "unix", flag.Args()[0])
				},

I know this is like, 3 years late, but you need to store it as a variable because DialContext belongs to (*Dialer) not (Dialer). When you assign it a local value, it can be referenced as *Dialer. A way around this, is to do this:

return (&net.Dialer{}).DialContext(ctx, "unix", flags.Args()[0])

@alexec
Copy link

alexec commented Sep 15, 2021

I like this. Might be worthwhile mentioning the benefits.

@fthrslntgy
Copy link

Thanks a lot!

Are you sure you can handle the response? response.Body is always empty in my code but I can detect errors or responses at my socket application.

@vinifrancosilva
Copy link

Thank you!

Helped a lot here!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment