Use more buffered I/O

This commit is contained in:
adnano 2020-09-24 19:22:35 -04:00
parent 3980cfd28f
commit 4b27a736ac
2 changed files with 36 additions and 36 deletions

View File

@ -25,7 +25,7 @@ func main() {
config.Certificates = append(config.Certificates, cert) config.Certificates = append(config.Certificates, cert)
config.ClientAuth = tls.RequestClientCert config.ClientAuth = tls.RequestClientCert
mux := &gemini.Mux{} mux := &gemini.ServeMux{}
mux.HandleFunc("/", func(rw gemini.ResponseWriter, req *gemini.Request) { mux.HandleFunc("/", func(rw gemini.ResponseWriter, req *gemini.Request) {
log.Printf("Request from %s for %s with certificates %v", req.RemoteAddr.String(), req.URL.String(), req.TLS.PeerCertificates) log.Printf("Request from %s for %s with certificates %v", req.RemoteAddr.String(), req.URL.String(), req.TLS.PeerCertificates)
rw.WriteHeader(gemini.StatusSuccess, "text/gemini") rw.WriteHeader(gemini.StatusSuccess, "text/gemini")

View File

@ -5,7 +5,6 @@ import (
"bufio" "bufio"
"crypto/tls" "crypto/tls"
"errors" "errors"
"io"
"io/ioutil" "io/ioutil"
"log" "log"
"net" "net"
@ -159,12 +158,10 @@ type Response struct {
Meta string Meta string
// Body contains the response body. // Body contains the response body.
// Body is only used by the server for successful responses.
Body []byte Body []byte
// TLS contains information about the TLS connection on which the response // TLS contains information about the TLS connection on which the response
// was received. // was received.
// This field is ignored by the server.
TLS tls.ConnectionState TLS tls.ConnectionState
} }
@ -194,8 +191,8 @@ func Get(url string) (*Response, error) {
return Do(req) return Do(req)
} }
// ProxyRequest requests the provided URL from the provided host. // ProxyGet requests the provided URL from the provided host.
func ProxyRequest(host, url string) (*Response, error) { func ProxyGet(host, url string) (*Response, error) {
req, err := NewProxyRequest(host, url) req, err := NewProxyRequest(host, url)
if err != nil { if err != nil {
return nil, err return nil, err
@ -254,7 +251,7 @@ func Do(req *Request) (*Response, error) {
// Trim carriage return // Trim carriage return
meta = meta[:len(meta)-1] meta = meta[:len(meta)-1]
// Ensure meta is less than 1024 bytes // Ensure meta is less than or equal to 1024 bytes
if len(meta) > 1024 { if len(meta) > 1024 {
return nil, ErrProtocol return nil, ErrProtocol
} }
@ -371,26 +368,39 @@ func (r *response) Write(b []byte) (int, error) {
} }
// respond responds to a connection. // respond responds to a connection.
func (s *Server) respond(rw net.Conn) { func (s *Server) respond(conn net.Conn) {
resp := newResponse(rw) r := bufio.NewReader(conn)
if rawurl, err := readLine(rw); err != nil { rw := newResponse(conn)
resp.WriteHeader(StatusBadRequest, "Bad request") // Read requested URL
} else if len(rawurl) > 1024 { rawurl, err := r.ReadString('\r')
resp.WriteHeader(StatusBadRequest, "Requested URL exceeds 1024 bytes") if err != nil {
return
}
// Trim carriage return
rawurl = rawurl[:len(rawurl)-1]
// Read terminating line feed
if b, err := r.ReadByte(); err != nil {
return
} else if b != '\n' {
rw.WriteHeader(StatusBadRequest, "Bad request")
}
if len(rawurl) > 1024 {
rw.WriteHeader(StatusBadRequest, "Requested URL exceeds 1024 bytes")
} else if url, err := url.Parse(rawurl); err != nil || url.User != nil { } else if url, err := url.Parse(rawurl); err != nil || url.User != nil {
// Note that we return an error if User is specified in the URL. // Note that we return an error status if User is specified in the URL
resp.WriteHeader(StatusBadRequest, "Requested URL is invalid") rw.WriteHeader(StatusBadRequest, "Requested URL is invalid")
} else { } else {
// Gather information about the request // Gather information about the request
req := &Request{ req := &Request{
URL: url, URL: url,
RemoteAddr: rw.RemoteAddr(), RemoteAddr: conn.RemoteAddr(),
TLS: rw.(*tls.Conn).ConnectionState(), TLS: conn.(*tls.Conn).ConnectionState(),
} }
s.Handler.Serve(resp, req) s.Handler.Serve(rw, req)
} }
resp.w.Flush() rw.w.Flush()
rw.Close() conn.Close()
} }
// A Handler responds to a Gemini request. // A Handler responds to a Gemini request.
@ -399,11 +409,11 @@ type Handler interface {
Serve(ResponseWriter, *Request) Serve(ResponseWriter, *Request)
} }
// Mux is a Gemini request multiplexer. // ServeMux is a Gemini request multiplexer.
// It matches the URL of each incoming request against a list of registered // It matches the URL of each incoming request against a list of registered
// patterns and calls the handler for the pattern that most closesly matches // patterns and calls the handler for the pattern that most closesly matches
// the URL. // the URL.
type Mux struct { type ServeMux struct {
entries []muxEntry entries []muxEntry
} }
@ -414,7 +424,7 @@ type muxEntry struct {
handler Handler handler Handler
} }
func (m *Mux) match(url *url.URL) Handler { func (m *ServeMux) match(url *url.URL) Handler {
for _, e := range m.entries { for _, e := range m.entries {
if (e.scheme == "" || url.Scheme == e.scheme) && if (e.scheme == "" || url.Scheme == e.scheme) &&
(e.host == "" || url.Host == e.host) && (e.host == "" || url.Host == e.host) &&
@ -426,7 +436,7 @@ func (m *Mux) match(url *url.URL) Handler {
} }
// Handle registers a Handler for the given pattern. // Handle registers a Handler for the given pattern.
func (m *Mux) Handle(pattern string, handler Handler) { func (m *ServeMux) Handle(pattern string, handler Handler) {
url, err := url.Parse(pattern) url, err := url.Parse(pattern)
if err != nil { if err != nil {
panic(err) panic(err)
@ -440,13 +450,13 @@ func (m *Mux) Handle(pattern string, handler Handler) {
} }
// HandleFunc registers a HandlerFunc for the given pattern. // HandleFunc registers a HandlerFunc for the given pattern.
func (m *Mux) HandleFunc(pattern string, handlerFunc func(ResponseWriter, *Request)) { func (m *ServeMux) HandleFunc(pattern string, handlerFunc func(ResponseWriter, *Request)) {
handler := HandlerFunc(handlerFunc) handler := HandlerFunc(handlerFunc)
m.Handle(pattern, handler) m.Handle(pattern, handler)
} }
// Serve responds to the request with the appropriate handler. // Serve responds to the request with the appropriate handler.
func (m *Mux) Serve(rw ResponseWriter, req *Request) { func (m *ServeMux) Serve(rw ResponseWriter, req *Request) {
h := m.match(req.URL) h := m.match(req.URL)
if h == nil { if h == nil {
rw.WriteHeader(StatusNotFound, "Not found") rw.WriteHeader(StatusNotFound, "Not found")
@ -461,13 +471,3 @@ type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) Serve(rw ResponseWriter, req *Request) { func (f HandlerFunc) Serve(rw ResponseWriter, req *Request) {
f(rw, req) f(rw, req)
} }
// readLine reads a line.
func readLine(r io.Reader) (string, error) {
scanner := bufio.NewScanner(r)
scanner.Scan()
if err := scanner.Err(); err != nil {
return "", err
}
return scanner.Text(), nil
}