mirror of
https://code.rocketnine.space/tslocum/gmitohtml.git
synced 2024-11-27 17:48:14 +01:00
Add option to allow local file access
This commit is contained in:
parent
11183c0c63
commit
e2232a8dc8
5 changed files with 51 additions and 10 deletions
|
@ -1,5 +1,6 @@
|
||||||
1.0.1:
|
1.0.1:
|
||||||
- Display navigation bar in pages
|
- Display navigation bar in pages
|
||||||
|
- Add option to allow local file access
|
||||||
|
|
||||||
1.0.0:
|
1.0.0:
|
||||||
- Initial release
|
- Initial release
|
||||||
|
|
|
@ -19,6 +19,14 @@ openssl req -x509 -out localhost.crt -keyout localhost.key \
|
||||||
Files `localhost.crt` and `localhost.key` are generated. Rename these files to
|
Files `localhost.crt` and `localhost.key` are generated. Rename these files to
|
||||||
match the domain where the certificate will be used.
|
match the domain where the certificate will be used.
|
||||||
|
|
||||||
|
## Allow file:// access
|
||||||
|
|
||||||
|
By default, local files are not served by gmitohtml. When executed with the
|
||||||
|
`--allow-file` argument, local files may be accessed via `file://`.
|
||||||
|
|
||||||
|
For example, to view `/home/dioscuri/sites/gemlog/index.gmi`, navigate to
|
||||||
|
`file:///home/dioscuri/sites/gemlog/index.gmi`.
|
||||||
|
|
||||||
# Example config.yaml
|
# Example config.yaml
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
|
4
main.go
4
main.go
|
@ -33,9 +33,11 @@ func openBrowser(url string) {
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var view bool
|
var view bool
|
||||||
|
var allowFile bool
|
||||||
var daemon string
|
var daemon string
|
||||||
var configFile string
|
var configFile string
|
||||||
flag.BoolVar(&view, "view", false, "open web browser")
|
flag.BoolVar(&view, "view", false, "open web browser")
|
||||||
|
flag.BoolVar(&allowFile, "allow-file", false, "allow local file access via file://")
|
||||||
flag.StringVar(&daemon, "daemon", "", "start daemon on specified address")
|
flag.StringVar(&daemon, "daemon", "", "start daemon on specified address")
|
||||||
flag.StringVar(&configFile, "config", "", "path to configuration file")
|
flag.StringVar(&configFile, "config", "", "path to configuration file")
|
||||||
// TODO option to include response header in page
|
// TODO option to include response header in page
|
||||||
|
@ -76,7 +78,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if daemon != "" {
|
if daemon != "" {
|
||||||
err := gmitohtml.StartDaemon(daemon)
|
err := gmitohtml.StartDaemon(daemon, allowFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,11 @@ func rewriteURL(u string, loc *url.URL) string {
|
||||||
if daemonAddress != "" {
|
if daemonAddress != "" {
|
||||||
if strings.HasPrefix(u, "gemini://") {
|
if strings.HasPrefix(u, "gemini://") {
|
||||||
return "http://" + daemonAddress + "/gemini/" + u[9:]
|
return "http://" + daemonAddress + "/gemini/" + u[9:]
|
||||||
|
} else if strings.HasPrefix(u, "file://") {
|
||||||
|
if !allowFileAccess {
|
||||||
|
return "http://" + daemonAddress + "/?FileAccessNotAllowed"
|
||||||
|
}
|
||||||
|
return "http://" + daemonAddress + "/file/" + u[7:]
|
||||||
} else if strings.Contains(u, "://") {
|
} else if strings.Contains(u, "://") {
|
||||||
return u
|
return u
|
||||||
} else if loc != nil && len(u) > 0 && !strings.HasPrefix(u, "//") {
|
} else if loc != nil && len(u) > 0 && !strings.HasPrefix(u, "//") {
|
||||||
|
|
|
@ -11,13 +11,17 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var lastRequestTime = time.Now().Unix()
|
var lastRequestTime = time.Now().Unix()
|
||||||
|
|
||||||
var clientCerts = make(map[string]tls.Certificate)
|
var (
|
||||||
|
clientCerts = make(map[string]tls.Certificate)
|
||||||
|
allowFileAccess bool
|
||||||
|
)
|
||||||
|
|
||||||
// ErrInvalidCertificate is the error returned when an invalid certificate is provided.
|
// ErrInvalidCertificate is the error returned when an invalid certificate is provided.
|
||||||
var ErrInvalidCertificate = errors.New("invalid certificate")
|
var ErrInvalidCertificate = errors.New("invalid certificate")
|
||||||
|
@ -165,12 +169,17 @@ func handleRequest(writer http.ResponseWriter, request *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pathSplit := strings.Split(request.URL.Path, "/")
|
pathSplit := strings.Split(request.URL.Path, "/")
|
||||||
if len(pathSplit) < 2 || pathSplit[1] != "gemini" {
|
if len(pathSplit) < 2 || (pathSplit[1] != "gemini" && (!allowFileAccess || pathSplit[1] != "file")) {
|
||||||
writer.Write([]byte("Error: invalid protocol, only Gemini is supported"))
|
writer.Write([]byte("Error: invalid protocol, only Gemini is supported"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
u, err := url.ParseRequestURI("gemini://" + strings.Join(pathSplit[2:], "/"))
|
scheme := "gemini://"
|
||||||
|
if pathSplit[1] == "file" {
|
||||||
|
scheme = "file://"
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := url.ParseRequestURI(scheme + strings.Join(pathSplit[2:], "/"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writer.Write([]byte("Error: invalid URL"))
|
writer.Write([]byte("Error: invalid URL"))
|
||||||
return
|
return
|
||||||
|
@ -186,9 +195,24 @@ func handleRequest(writer http.ResponseWriter, request *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
header, data, err := fetch(u.String())
|
var header []byte
|
||||||
if err != nil {
|
var data []byte
|
||||||
fmt.Fprintf(writer, "Error: failed to fetch %s: %s", u, err)
|
if scheme == "gemini://" {
|
||||||
|
header, data, err = fetch(u.String())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(writer, "Error: failed to fetch %s: %s", u, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if allowFileAccess && scheme == "file://" {
|
||||||
|
header = []byte("20 text/gemini; charset=utf-8")
|
||||||
|
data, err = ioutil.ReadFile(path.Join("/", strings.Join(pathSplit[2:], "/")))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(writer, "Error: failed to read file %s: %s", u, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data = Convert(data, u.String())
|
||||||
|
} else {
|
||||||
|
writer.Write([]byte("Error: invalid URL"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,10 +243,11 @@ func handleAssets(writer http.ResponseWriter, request *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartDaemon starts the page conversion daemon.
|
// StartDaemon starts the page conversion daemon.
|
||||||
func StartDaemon(address string) error {
|
func StartDaemon(address string, allowFile bool) error {
|
||||||
loadAssets()
|
|
||||||
|
|
||||||
daemonAddress = address
|
daemonAddress = address
|
||||||
|
allowFileAccess = allowFile
|
||||||
|
|
||||||
|
loadAssets()
|
||||||
|
|
||||||
handler := http.NewServeMux()
|
handler := http.NewServeMux()
|
||||||
handler.HandleFunc("/assets/style.css", handleAssets)
|
handler.HandleFunc("/assets/style.css", handleAssets)
|
||||||
|
|
Loading…
Reference in a new issue