Skip to content

Commit

Permalink
feat(gnoweb): disable html in markdown (#2964)
Browse files Browse the repository at this point in the history
<!-- please provide a detailed description of the changes made in this
pull request. -->

In line with our vision for a HTML-free Gnoweb, this PR disables the
rendering of HTML within Markdown content. It replaces all elements
recognized as HTML tags (e.g., `<div>`, `<br>`, `<web-component>`) with
empty spaces before sending the content to the front-end. The parsing
still happens via JavaScript, but now without any HTML tags. However,
HTML tags like ``` `<div>lorem ipsum</div>` ``` can still appear within
code blocks in Markdown, as usual, but won’t be parsed/read as actual
HTML.

Additionally, this feature is controlled by the `gnoweb` boolean flag
`with-html`, which defaults to `false`.

cc @gfanton 

> [!WARNING] 
> Enabling this feature will break the design of gno.land realms (and
any other realms relying on HTML), since current layout elements like
`columns`, `stacks`, or `jumbotrons`... are built with HTML. We will
need to adopt the new design system expected with `gnoweb2.0` (or future
`gnoweb1` improvements).


### BEFORE:
![127 0 0 1_8888_
(1)](https://github.com/user-attachments/assets/04328db4-7076-4690-9727-50c33f58954d)
### AFTER:
![127 0 0 1_8888_
(2)](https://github.com/user-attachments/assets/b8d9532c-45e6-4a78-b166-2f6d0176bd10)

---
### BEFORE:
![127 0 0
1_8888_r_gnoland_pages](https://github.com/user-attachments/assets/445cbb3f-565b-42af-b794-14f9c682d4ce)
### AFTER:
![127 0 0 1_8888_r_gnoland_pages
(1)](https://github.com/user-attachments/assets/ac7131f1-c2d4-42ea-a426-66244782e910)

---------

Co-authored-by: Manfred Touron <94029+moul@users.noreply.github.com>
  • Loading branch information
alexiscolin and moul authored Oct 20, 2024
1 parent f6bd2d3 commit 93ece90
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 3 deletions.
2 changes: 1 addition & 1 deletion contribs/gnodev/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/gnolang/gno/contribs/gnodev

go 1.22
go 1.22.0

replace github.com/gnolang/gno => ../..

Expand Down
1 change: 1 addition & 0 deletions gno.land/cmd/gnoweb/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func runMain(args []string) error {
fs.StringVar(&cfg.HelpRemote, "help-remote", cfg.HelpRemote, "help page's remote addr")
fs.BoolVar(&cfg.WithAnalytics, "with-analytics", cfg.WithAnalytics, "enable privacy-first analytics")
fs.StringVar(&bindAddress, "bind", "127.0.0.1:8888", "server listening address")
fs.BoolVar(&cfg.WithHTML, "with-html", cfg.WithHTML, "Enable HTML parsing in markdown rendering")

if err := fs.Parse(args); err != nil {
return err
Expand Down
35 changes: 33 additions & 2 deletions gno.land/pkg/gnoweb/gnoweb.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"net/url"
"os"
"path/filepath"
"regexp"
"runtime"
"strings"
"time"
Expand Down Expand Up @@ -45,6 +46,7 @@ type Config struct {
HelpChainID string
HelpRemote string
WithAnalytics bool
WithHTML bool
}

func NewDefaultConfig() Config {
Expand All @@ -56,6 +58,7 @@ func NewDefaultConfig() Config {
HelpChainID: "dev",
HelpRemote: "127.0.0.1:26657",
WithAnalytics: false,
WithHTML: false,
}
}

Expand Down Expand Up @@ -109,6 +112,34 @@ func MakeApp(logger *slog.Logger, cfg Config) gotuna.App {
return app
}

var (
inlineCodePattern = regexp.MustCompile("`[^`]*`")
htmlTagPattern = regexp.MustCompile(`<\/?\w+[^>]*?>`)
)

func sanitizeContent(cfg *Config, content string) string {
if cfg.WithHTML {
return content
}

placeholders := map[string]string{}
contentWithPlaceholders := inlineCodePattern.ReplaceAllStringFunc(content, func(match string) string {
placeholder := fmt.Sprintf("__GNOMDCODE_%d__", len(placeholders))
placeholders[placeholder] = match
return placeholder
})

sanitizedContent := htmlTagPattern.ReplaceAllString(contentWithPlaceholders, "")

if len(placeholders) > 0 {
for placeholder, code := range placeholders {
sanitizedContent = strings.ReplaceAll(sanitizedContent, placeholder, code)
}
}

return sanitizedContent
}

// handlerRealmAlias is used to render official pages from realms.
// url is intended to be shorter.
// UX is intended to be more minimalistic.
Expand Down Expand Up @@ -151,7 +182,7 @@ func handlerRealmAlias(logger *slog.Logger, app gotuna.App, cfg *Config, rlmpath
tmpl.Set("RealmPath", rlmpath)
tmpl.Set("Query", querystr)
tmpl.Set("PathLinks", pathLinks)
tmpl.Set("Contents", string(res.Data))
tmpl.Set("Contents", sanitizeContent(cfg, string(res.Data)))
tmpl.Set("Config", cfg)
tmpl.Set("IsAlias", true)
tmpl.Render(w, r, "realm_render.html", "funcs.html")
Expand Down Expand Up @@ -339,7 +370,7 @@ func handleRealmRender(logger *slog.Logger, app gotuna.App, cfg *Config, w http.
tmpl.Set("RealmPath", rlmpath)
tmpl.Set("Query", querystr)
tmpl.Set("PathLinks", pathLinks)
tmpl.Set("Contents", string(res.Data))
tmpl.Set("Contents", sanitizeContent(cfg, string(res.Data)))
tmpl.Set("Config", cfg)
tmpl.Set("HasReadme", hasReadme)
tmpl.Render(w, r, "realm_render.html", "funcs.html")
Expand Down

1 comment on commit 93ece90

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Go Benchmarks'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.20.

Benchmark suite Current: 93ece90 Previous: b655cd2 Ratio
BenchmarkBinary/EmptyStruct:encode 532 ns/op 96 B/op 2 allocs/op 292.7 ns/op 96 B/op 2 allocs/op 1.82
BenchmarkBinary/EmptyStruct:encode - ns/op 532 ns/op 292.7 ns/op 1.82
BenchmarkBinary/EmptyStruct:decode 270.3 ns/op 0 B/op 0 allocs/op 143.1 ns/op 0 B/op 0 allocs/op 1.89
BenchmarkBinary/EmptyStruct:decode - ns/op 270.3 ns/op 143.1 ns/op 1.89
BenchmarkBinary/ShortArraysStruct:encode 847.7 ns/op 192 B/op 4 allocs/op 613.4 ns/op 192 B/op 4 allocs/op 1.38
BenchmarkBinary/ShortArraysStruct:encode - ns/op 847.7 ns/op 613.4 ns/op 1.38
BenchmarkBinary/ShortArraysStruct:decode 359.6 ns/op 0 B/op 0 allocs/op 232.7 ns/op 0 B/op 0 allocs/op 1.55
BenchmarkBinary/ShortArraysStruct:decode - ns/op 359.6 ns/op 232.7 ns/op 1.55
BenchmarkBinary/EmbeddedSt1:encode 5712 ns/op 2037 B/op 65 allocs/op 4629 ns/op 2037 B/op 65 allocs/op 1.23
BenchmarkBinary/EmbeddedSt1:encode - ns/op 5712 ns/op 4629 ns/op 1.23
BenchmarkBcryptGenerateFromPassword/benchmark-security-param 63791914 ns/op 5132 B/op 9 allocs/op 31995929 ns/op 5125 B/op 9 allocs/op 1.99
BenchmarkBcryptGenerateFromPassword/benchmark-security-param - ns/op 63791914 ns/op 31995929 ns/op 1.99
BenchmarkBcryptGenerateFromPassword/benchmark-security-param 127514643 ns/op 5139 B/op 9 allocs/op 31995929 ns/op 5125 B/op 9 allocs/op 3.99
BenchmarkBcryptGenerateFromPassword/benchmark-security-param - ns/op 127514643 ns/op 31995929 ns/op 3.99
BenchmarkBcryptGenerateFromPassword/benchmark-security-param 254944278 ns/op 5158 B/op 9 allocs/op 31995929 ns/op 5125 B/op 9 allocs/op 7.97
BenchmarkBcryptGenerateFromPassword/benchmark-security-param - ns/op 254944278 ns/op 31995929 ns/op 7.97
BenchmarkBcryptGenerateFromPassword/benchmark-security-param 509845083 ns/op 5196 B/op 10 allocs/op 31995929 ns/op 5125 B/op 9 allocs/op 15.93
BenchmarkBcryptGenerateFromPassword/benchmark-security-param - ns/op 509845083 ns/op 31995929 ns/op 15.93
BenchmarkBcryptGenerateFromPassword/benchmark-security-param 1019480212 ns/op 5528 B/op 13 allocs/op 31995929 ns/op 5125 B/op 9 allocs/op 31.86
BenchmarkBcryptGenerateFromPassword/benchmark-security-param - ns/op 1019480212 ns/op 31995929 ns/op 31.86
BenchmarkBcryptGenerateFromPassword/benchmark-security-param - allocs/op 13 allocs/op 9 allocs/op 1.44
BenchmarkBcryptGenerateFromPassword/benchmark-security-param 2039059936 ns/op 5528 B/op 13 allocs/op 31995929 ns/op 5125 B/op 9 allocs/op 63.73
BenchmarkBcryptGenerateFromPassword/benchmark-security-param - ns/op 2039059936 ns/op 31995929 ns/op 63.73
BenchmarkBcryptGenerateFromPassword/benchmark-security-param - allocs/op 13 allocs/op 9 allocs/op 1.44
BenchmarkSigning 84211 ns/op 1856 B/op 36 allocs/op 25701 ns/op 64 B/op 1 allocs/op 3.28
BenchmarkSigning - ns/op 84211 ns/op 25701 ns/op 3.28
BenchmarkSigning - B/op 1856 B/op 64 B/op 29
BenchmarkSigning - allocs/op 36 allocs/op 1 allocs/op 36
BenchmarkSigning 82758 ns/op 1856 B/op 36 allocs/op 25701 ns/op 64 B/op 1 allocs/op 3.22
BenchmarkSigning - ns/op 82758 ns/op 25701 ns/op 3.22
BenchmarkSigning - B/op 1856 B/op 64 B/op 29
BenchmarkSigning - allocs/op 36 allocs/op 1 allocs/op 36
BenchmarkVerification 165378 ns/op 864 B/op 19 allocs/op 61110 ns/op 0 B/op 0 allocs/op 2.71
BenchmarkVerification - ns/op 165378 ns/op 61110 ns/op 2.71
BenchmarkVerification - B/op 864 B/op 0 B/op +∞
BenchmarkVerification - allocs/op 19 allocs/op 0 allocs/op +∞
BenchmarkVerification 170292 ns/op 864 B/op 19 allocs/op 61110 ns/op 0 B/op 0 allocs/op 2.79
BenchmarkVerification - ns/op 170292 ns/op 61110 ns/op 2.79
BenchmarkVerification - B/op 864 B/op 0 B/op +∞
BenchmarkVerification - allocs/op 19 allocs/op 0 allocs/op +∞
BenchmarkRandomBytes/random 69.08 ns/op 16 B/op 1 allocs/op 33.25 ns/op 4 B/op 1 allocs/op 2.08
BenchmarkRandomBytes/random - ns/op 69.08 ns/op 33.25 ns/op 2.08
BenchmarkRandomBytes/random - B/op 16 B/op 4 B/op 4
BenchmarkRandomBytes/random 105.8 ns/op 32 B/op 1 allocs/op 33.25 ns/op 4 B/op 1 allocs/op 3.18
BenchmarkRandomBytes/random - ns/op 105.8 ns/op 33.25 ns/op 3.18
BenchmarkRandomBytes/random - B/op 32 B/op 4 B/op 8
BenchmarkRandomBytes/random 268.1 ns/op 112 B/op 1 allocs/op 33.25 ns/op 4 B/op 1 allocs/op 8.06
BenchmarkRandomBytes/random - ns/op 268.1 ns/op 33.25 ns/op 8.06
BenchmarkRandomBytes/random - B/op 112 B/op 4 B/op 28
BenchmarkRandomBytes/random 2331 ns/op 1024 B/op 1 allocs/op 33.25 ns/op 4 B/op 1 allocs/op 70.11
BenchmarkRandomBytes/random - ns/op 2331 ns/op 33.25 ns/op 70.11
BenchmarkRandomBytes/random - B/op 1024 B/op 4 B/op 256
BenchmarkSmall/boltdb-1000-100-16-40/update 1409779 ns/op 45235 B/op 382 allocs/op 974381 ns/op 37376 B/op 371 allocs/op 1.45
BenchmarkSmall/boltdb-1000-100-16-40/update - ns/op 1409779 ns/op 974381 ns/op 1.45
BenchmarkSmall/boltdb-1000-100-16-40/update - B/op 45235 B/op 37376 B/op 1.21
BenchmarkSmall/boltdb-1000-100-16-40/block - B/op 5773064 B/op 4692235 B/op 1.23
BenchmarkSmall/memdb-1000-100-16-40/block - B/op 9109826 B/op 6597573 B/op 1.38
BenchmarkSmall/memdb-1000-100-16-40/block - allocs/op 165847 allocs/op 117018 allocs/op 1.42
BenchmarkMedium/boltdb-100000-100-16-40/update - B/op 126634 B/op 102976 B/op 1.23
BenchmarkMedium/memdb-100000-100-16-40/update 1256333 ns/op 372552 B/op 7383 allocs/op 1042125 ns/op 258863 B/op 4998 allocs/op 1.21
BenchmarkMedium/memdb-100000-100-16-40/update - ns/op 1256333 ns/op 1042125 ns/op 1.21
BenchmarkMedium/memdb-100000-100-16-40/update - B/op 372552 B/op 258863 B/op 1.44
BenchmarkMedium/memdb-100000-100-16-40/update - allocs/op 7383 allocs/op 4998 allocs/op 1.48
BenchmarkLevelDBBatchSizes/goleveldb-100000-400-16-40/update - B/op 49079 B/op 38752 B/op 1.27
BenchmarkLevelDBBatchSizes/goleveldb-100000-400-16-40/update - allocs/op 588 allocs/op 453 allocs/op 1.30
BenchmarkLevelDBBatchSizes/goleveldb-100000-2000-16-40/update - allocs/op 415 allocs/op 341 allocs/op 1.22
BenchmarkLevelDBBatchSizes/goleveldb-100000-2000-16-40/block - B/op 110063516 B/op 77471570 B/op 1.42
BenchmarkLevelDBBatchSizes/goleveldb-100000-2000-16-40/block - allocs/op 1319374 allocs/op 960917 allocs/op 1.37
BenchmarkHash/ripemd160 2826 ns/op 25 B/op 1 allocs/op 700.4 ns/op 25 B/op 1 allocs/op 4.03
BenchmarkHash/ripemd160 - ns/op 2826 ns/op 700.4 ns/op 4.03
BenchmarkHash/sha2-256 522.5 ns/op 33 B/op 1 allocs/op 171.3 ns/op 33 B/op 1 allocs/op 3.05
BenchmarkHash/sha2-256 - ns/op 522.5 ns/op 171.3 ns/op 3.05
BenchmarkHash/sha3-256 1842 ns/op 33 B/op 1 allocs/op 717.4 ns/op 33 B/op 1 allocs/op 2.57
BenchmarkHash/sha3-256 - ns/op 1842 ns/op 717.4 ns/op 2.57
BenchmarkWriteSecretConnection 5768 ns/op 0 B/op 0 allocs/op 4097 ns/op 0 B/op 0 allocs/op 1.41
BenchmarkWriteSecretConnection - ns/op 5768 ns/op 4097 ns/op 1.41
BenchmarkReadSecretConnection 3351 ns/op 0 B/op 0 allocs/op 2364 ns/op 0 B/op 0 allocs/op 1.42
BenchmarkReadSecretConnection - ns/op 3351 ns/op 2364 ns/op 1.42
BenchmarkCacheStoreGetNoKeyFound - B/op 183 B/op 149 B/op 1.23

This comment was automatically generated by workflow using github-action-benchmark.

CC: @ajnavarro @thehowl @zivkovicmilos

Please sign in to comment.