Last active
June 12, 2018 20:29
-
-
Save calmh/0de9efffe65986db8269955a8f7fae5f to your computer and use it in GitHub Desktop.
Toy HTTP-over-stdio thing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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