9 Commits
v0.2.2 ... main

Author SHA1 Message Date
4985bf0bc8 Add link to ogirinal in readme 2023-05-26 00:45:08 -04:00
f6d3c47816 Export TLS & remove conn in request struct
This makes it possible to fully create another request outside of this module
(which Hnakra will need) and has better parity with net/http.
2023-05-26 00:38:12 -04:00
24d70951c9 Change package URL in go.mod 2023-05-26 00:37:56 -04:00
b436ec8cb5 Change import paths 2023-05-25 18:45:53 -04:00
54f7209f13 Update readme 2023-05-25 18:27:52 -04:00
Adnan Maolood
b0f27c6f74 fs: Prevent invalid directory links
A file with a name like "gemini:example" would previously result in the
following invalid link:

    => gemini:example gemini:example

Fix by prepending a "./" before each filename, so that the resulting
link looks like:

    => ./gemini:example gemini:example
2022-05-07 13:54:56 -04:00
Yujiri
8c0af18617 Fix parsing of list item lines
According to section 5.5.2 of the Gemini specification (v0.16.1), the
space is mandatory.
2022-03-15 11:07:04 -04:00
Adnan Maolood
353416685a doc: Fix Mux documentation 2022-02-16 12:01:55 -05:00
Adnan Maolood
0ceec22705 readme: Update Gemini specification version 2021-12-18 12:51:04 -05:00
13 changed files with 30 additions and 52 deletions

View File

@@ -1,16 +1,18 @@
# go-gemini # go-gemini
[![godocs.io](https://godocs.io/git.sr.ht/~adnano/go-gemini?status.svg)](https://godocs.io/git.sr.ht/~adnano/go-gemini) [![builds.sr.ht status](https://builds.sr.ht/~adnano/go-gemini.svg)](https://builds.sr.ht/~adnano/go-gemini?) This repository is a fork of [go-gemini](https://godocs.io/git.sr.ht/~adnano/go-gemini)
implementing better parity with net/http and some tweaks required for use in
[Hnakra](https://git.tebibyte.media/sashakoshka/hnakra).
Package gemini implements the [Gemini protocol](https://gemini.circumlunar.space) Package gemini implements the [Gemini protocol](https://gemini.circumlunar.space)
in Go. It provides an API similar to that of net/http to facilitate the in Go. It provides an API similar to that of net/http to facilitate the
development of Gemini clients and servers. development of Gemini clients and servers.
Compatible with version v0.14.3 of the Gemini specification. Compatible with version v0.16.0 of the Gemini specification.
## Usage ## Usage
import "git.sr.ht/~adnano/go-gemini" import "git.tebibyte.media/sashakoshka/go-gemini"
Note that some filesystem-related functionality is only available on Go 1.16 Note that some filesystem-related functionality is only available on Go 1.16
or later as it relies on the io/fs package. or later as it relies on the io/fs package.
@@ -22,12 +24,6 @@ To run an example:
go run examples/server.go go run examples/server.go
## Contributing
Send patches and questions to [~adnano/go-gemini-devel](https://lists.sr.ht/~adnano/go-gemini-devel).
Subscribe to release announcements on [~adnano/go-gemini-announce](https://lists.sr.ht/~adnano/go-gemini-announce).
## License ## License
go-gemini is licensed under the terms of the MIT license (see LICENSE). go-gemini is licensed under the terms of the MIT license (see LICENSE).

6
doc.go
View File

@@ -30,7 +30,7 @@ Servers should be configured with certificates:
server.GetCertificate = certificates.Get server.GetCertificate = certificates.Get
Mux is a Gemini request multiplexer. Mux is a Gemini request multiplexer.
Mux can handle requests for multiple hosts and schemes. Mux can handle requests for multiple hosts and paths.
mux := &gemini.Mux{} mux := &gemini.Mux{}
mux.HandleFunc("example.com", func(ctx context.Context, w gemini.ResponseWriter, r *gemini.Request) { mux.HandleFunc("example.com", func(ctx context.Context, w gemini.ResponseWriter, r *gemini.Request) {
@@ -39,8 +39,8 @@ Mux can handle requests for multiple hosts and schemes.
mux.HandleFunc("example.org/about.gmi", func(ctx context.Context, w gemini.ResponseWriter, r *gemini.Request) { mux.HandleFunc("example.org/about.gmi", func(ctx context.Context, w gemini.ResponseWriter, r *gemini.Request) {
fmt.Fprint(w, "About example.org") fmt.Fprint(w, "About example.org")
}) })
mux.HandleFunc("http://example.net", func(ctx context.Context, w gemini.ResponseWriter, r *gemini.Request) { mux.HandleFunc("/images/", func(ctx context.Context, w gemini.ResponseWriter, r *gemini.Request) {
fmt.Fprint(w, "Proxied content from http://example.net") w.WriteHeader(gemini.StatusGone, "Gone forever")
}) })
server.Handler = mux server.Handler = mux

View File

@@ -10,8 +10,8 @@ import (
"log" "log"
"time" "time"
"git.sr.ht/~adnano/go-gemini" "git.tebibyte.media/sashakoshka/go-gemini"
"git.sr.ht/~adnano/go-gemini/certificate" "git.tebibyte.media/sashakoshka/go-gemini/certificate"
) )
type User struct { type User struct {
@@ -52,7 +52,7 @@ func fingerprint(cert *x509.Certificate) string {
} }
func profile(ctx context.Context, w gemini.ResponseWriter, r *gemini.Request) { func profile(ctx context.Context, w gemini.ResponseWriter, r *gemini.Request) {
tls := r.TLS() tls := r.TLS
if len(tls.PeerCertificates) == 0 { if len(tls.PeerCertificates) == 0 {
w.WriteHeader(gemini.StatusCertificateRequired, "Certificate required") w.WriteHeader(gemini.StatusCertificateRequired, "Certificate required")
return return
@@ -68,7 +68,7 @@ func profile(ctx context.Context, w gemini.ResponseWriter, r *gemini.Request) {
} }
func changeUsername(ctx context.Context, w gemini.ResponseWriter, r *gemini.Request) { func changeUsername(ctx context.Context, w gemini.ResponseWriter, r *gemini.Request) {
tls := r.TLS() tls := r.TLS
if len(tls.PeerCertificates) == 0 { if len(tls.PeerCertificates) == 0 {
w.WriteHeader(gemini.StatusCertificateRequired, "Certificate required") w.WriteHeader(gemini.StatusCertificateRequired, "Certificate required")
return return

View File

@@ -11,7 +11,7 @@ import (
"os" "os"
"time" "time"
"git.sr.ht/~adnano/go-gemini/certificate" "git.tebibyte.media/sashakoshka/go-gemini/certificate"
) )
func main() { func main() {

View File

@@ -16,8 +16,8 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"git.sr.ht/~adnano/go-gemini" "git.tebibyte.media/sashakoshka/go-gemini"
"git.sr.ht/~adnano/go-gemini/tofu" "git.tebibyte.media/sashakoshka/go-gemini/tofu"
) )
var ( var (

View File

@@ -10,7 +10,7 @@ import (
"io" "io"
"os" "os"
"git.sr.ht/~adnano/go-gemini" "git.tebibyte.media/sashakoshka/go-gemini"
) )
func main() { func main() {

View File

@@ -11,8 +11,8 @@ import (
"os/signal" "os/signal"
"time" "time"
"git.sr.ht/~adnano/go-gemini" "git.tebibyte.media/sashakoshka/go-gemini"
"git.sr.ht/~adnano/go-gemini/certificate" "git.tebibyte.media/sashakoshka/go-gemini/certificate"
) )
func main() { func main() {

View File

@@ -10,8 +10,8 @@ import (
"log" "log"
"time" "time"
"git.sr.ht/~adnano/go-gemini" "git.tebibyte.media/sashakoshka/go-gemini"
"git.sr.ht/~adnano/go-gemini/certificate" "git.tebibyte.media/sashakoshka/go-gemini/certificate"
) )
func main() { func main() {

2
fs.go
View File

@@ -169,7 +169,7 @@ func dirList(w ResponseWriter, f fs.File) {
} }
link := LineLink{ link := LineLink{
Name: name, Name: name,
URL: (&url.URL{Path: name}).EscapedPath(), URL: "./" + url.PathEscape(name),
} }
fmt.Fprintln(w, link.String()) fmt.Fprintln(w, link.String())
} }

2
go.mod
View File

@@ -1,4 +1,4 @@
module git.sr.ht/~adnano/go-gemini module git.tebibyte.media/sashakoshka/go-gemini
go 1.15 go 1.15

View File

@@ -4,7 +4,6 @@ import (
"bufio" "bufio"
"crypto/tls" "crypto/tls"
"io" "io"
"net"
"net/url" "net/url"
) )
@@ -28,8 +27,7 @@ type Request struct {
// This field is ignored by the Gemini server. // This field is ignored by the Gemini server.
Certificate *tls.Certificate Certificate *tls.Certificate
conn net.Conn TLS *tls.ConnectionState
tls *tls.ConnectionState
} }
// NewRequest returns a new request. // NewRequest returns a new request.
@@ -98,30 +96,11 @@ func (r *Request) WriteTo(w io.Writer) (int64, error) {
return wrote, bw.Flush() return wrote, bw.Flush()
} }
// Conn returns the network connection on which the request was received.
// Conn returns nil for client requests.
func (r *Request) Conn() net.Conn {
return r.conn
}
// TLS returns information about the TLS connection on which the
// request was received.
// TLS returns nil for client requests.
func (r *Request) TLS() *tls.ConnectionState {
if r.tls == nil {
if tlsConn, ok := r.conn.(*tls.Conn); ok {
state := tlsConn.ConnectionState()
r.tls = &state
}
}
return r.tls
}
// ServerName returns the value of the TLS Server Name Indication extension // ServerName returns the value of the TLS Server Name Indication extension
// sent by the client. // sent by the client.
// ServerName returns an empty string for client requests. // ServerName returns an empty string for client requests.
func (r *Request) ServerName() string { func (r *Request) ServerName() string {
if tls := r.TLS(); tls != nil { if tls := r.TLS; tls != nil {
return tls.ServerName return tls.ServerName
} }
return "" return ""

View File

@@ -371,7 +371,10 @@ func (srv *Server) goServeConn(ctx context.Context, conn net.Conn) error {
w.WriteHeader(StatusBadRequest, "Bad request") w.WriteHeader(StatusBadRequest, "Bad request")
return w.Flush() return w.Flush()
} }
req.conn = conn if tlsConn, ok := conn.(*tls.Conn); ok {
state := tlsConn.ConnectionState()
req.TLS = &state
}
h := srv.Handler h := srv.Handler
if h == nil { if h == nil {

View File

@@ -125,8 +125,8 @@ func ParseLines(r io.Reader, handler func(Line)) error {
name = strings.TrimLeft(name, spacetab) name = strings.TrimLeft(name, spacetab)
line = LineLink{url, name} line = LineLink{url, name}
} }
} else if strings.HasPrefix(text, "*") { } else if strings.HasPrefix(text, "* ") {
text = text[1:] text = text[2:]
text = strings.TrimLeft(text, spacetab) text = strings.TrimLeft(text, spacetab)
line = LineListItem(text) line = LineListItem(text)
} else if strings.HasPrefix(text, "###") { } else if strings.HasPrefix(text, "###") {