Skip to content

Instantly share code, notes, and snippets.

@calmh
Last active June 12, 2018 20:29
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save calmh/0de9efffe65986db8269955a8f7fae5f to your computer and use it in GitHub Desktop.
Save calmh/0de9efffe65986db8269955a8f7fae5f to your computer and use it in GitHub Desktop.
Toy HTTP-over-stdio thing
package main
import (
"fmt"
"io"
"net"
"net/http"
"os"
"time"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
fmt.Fprintln(w, "Hello, world")
})
listener := newRWListener(os.Stdin, os.Stdout)
http.Serve(listener, nil)
}
// rwListener implements net.Listener on top of the given reader/writer
// pair. Only a single "connection" can be open at a given time - once
// Accept() has returned a connection, further calls to Accept() will block
// until that connection has been closed or the listener is closed.
type rwListener struct {
r io.Reader
w io.Writer
stop chan struct{}
avail chan struct{}
}
func newRWListener(r io.Reader, w io.Writer) *rwListener {
l := &rwListener{
r: r,
w: w,
stop: make(chan struct{}),
avail: make(chan struct{}, 1),
}
l.avail <- struct{}{}
return l
}
func (l *rwListener) Accept() (net.Conn, error) {
select {
case <-l.avail:
return &rwConn{
r: l.r,
w: l.w,
closed: l.avail,
}, nil
case <-l.stop:
return nil, fmt.Errorf("closed")
}
}
func (l *rwListener) Addr() net.Addr {
return &rwAddr{}
}
func (l *rwListener) Close() error {
close(l.stop)
return nil
}
// rwConn is a net.Conn for a reader/writer pair. A send to the closed chan
// will happen when Close() is called.
type rwConn struct {
r io.Reader
w io.Writer
closed chan struct{}
}
func (c rwConn) RemoteAddr() net.Addr {
return rwAddr{}
}
func (c rwConn) LocalAddr() net.Addr {
return rwAddr{}
}
func (c rwConn) Close() error {
c.closed <- struct{}{}
return nil
}
func (c rwConn) Read(data []byte) (int, error) {
return c.r.Read(data)
}
func (c rwConn) Write(data []byte) (int, error) {
return c.w.Write(data)
}
func (c rwConn) SetReadDeadline(t time.Time) error { return nil }
func (c rwConn) SetWriteDeadline(t time.Time) error { return nil }
func (c rwConn) SetDeadline(t time.Time) error { return nil }
// rwAddr is a net.Addr for r/w connections
type rwAddr struct{}
func (rwAddr) String() string {
return "-"
}
func (rwAddr) Network() string {
return "rw"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment