mirror of
https://github.com/golang/go
synced 2024-11-25 07:37:57 -07:00
- better support for text files: show them nicely formatted
instead of serving them raw - path-related cleanups R=rsc http://go/go-review/1026021
This commit is contained in:
parent
7ee3f3ddd1
commit
89d0e2dbe3
@ -23,6 +23,7 @@ import (
|
|||||||
"sync";
|
"sync";
|
||||||
"template";
|
"template";
|
||||||
"time";
|
"time";
|
||||||
|
"utf8";
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -626,9 +627,8 @@ func commentText(src []byte) (text string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func serveHtmlDoc(c *http.Conn, r *http.Request, filename string) {
|
func serveHtmlDoc(c *http.Conn, r *http.Request, path string) {
|
||||||
// get HTML body contents
|
// get HTML body contents
|
||||||
path := pathutil.Join(goroot, filename);
|
|
||||||
src, err := io.ReadFile(path);
|
src, err := io.ReadFile(path);
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Stderrf("%v", err);
|
log.Stderrf("%v", err);
|
||||||
@ -658,8 +658,7 @@ func serveParseErrors(c *http.Conn, errors *parseErrors) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func serveGoSource(c *http.Conn, filename string, styler printer.Styler) {
|
func serveGoSource(c *http.Conn, r *http.Request, path string, styler printer.Styler) {
|
||||||
path := pathutil.Join(goroot, filename);
|
|
||||||
prog, errors := parse(path, parser.ParseComments);
|
prog, errors := parse(path, parser.ParseComments);
|
||||||
if errors != nil {
|
if errors != nil {
|
||||||
serveParseErrors(c, errors);
|
serveParseErrors(c, errors);
|
||||||
@ -671,7 +670,7 @@ func serveGoSource(c *http.Conn, filename string, styler printer.Styler) {
|
|||||||
writeNode(&buf, prog, true, styler);
|
writeNode(&buf, prog, true, styler);
|
||||||
fmt.Fprintln(&buf, "</pre>");
|
fmt.Fprintln(&buf, "</pre>");
|
||||||
|
|
||||||
servePage(c, "Source file " + filename, "", buf.Bytes());
|
servePage(c, "Source file " + r.Url.Path, "", buf.Bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -684,12 +683,72 @@ func redirect(c *http.Conn, r *http.Request) (redirected bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func serveDirectory(c *http.Conn, r *http.Request) {
|
// TODO(gri): Should have a mapping from extension to handler, eventually.
|
||||||
|
|
||||||
|
// textExt[x] is true if the extension x indicates a text file, and false otherwise.
|
||||||
|
var textExt = map[string]bool{
|
||||||
|
".css": false, // must be served raw
|
||||||
|
".js": false, // must be served raw
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func isTextFile(path string) bool {
|
||||||
|
// if the extension is known, use it for decision making
|
||||||
|
if isText, found := textExt[pathutil.Ext(path)]; found {
|
||||||
|
return isText;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the extension is not known; read an initial chunk of
|
||||||
|
// file and check if it looks like correct UTF-8; if it
|
||||||
|
// does, it's probably a text file
|
||||||
|
f, err := os.Open(path, os.O_RDONLY, 0);
|
||||||
|
if err != nil {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf [1024]byte;
|
||||||
|
n, err := f.Read(&buf);
|
||||||
|
if err != nil {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s := string(buf[0:n]);
|
||||||
|
n -= utf8.UTFMax; // make sure there's enough bytes for a complete unicode char
|
||||||
|
for i, c := range s {
|
||||||
|
if i > n {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' {
|
||||||
|
// decoding error or control character - not a text file
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// likely a text file
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func serveTextFile(c *http.Conn, r *http.Request, path string) {
|
||||||
|
src, err := io.ReadFile(path);
|
||||||
|
if err != nil {
|
||||||
|
log.Stderrf("serveTextFile: %s", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer;
|
||||||
|
fmt.Fprintln(&buf, "<pre>");
|
||||||
|
template.HtmlEscape(&buf, src);
|
||||||
|
fmt.Fprintln(&buf, "</pre>");
|
||||||
|
|
||||||
|
servePage(c, "Text file " + path, "", buf.Bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func serveDirectory(c *http.Conn, r *http.Request, path string) {
|
||||||
if redirect(c, r) {
|
if redirect(c, r) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
path := pathutil.Join(".", r.Url.Path);
|
|
||||||
list, err := io.ReadDir(path);
|
list, err := io.ReadDir(path);
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.NotFound(c, r);
|
http.NotFound(c, r);
|
||||||
@ -708,37 +767,45 @@ func serveDirectory(c *http.Conn, r *http.Request) {
|
|||||||
var fileServer = http.FileServer(".", "")
|
var fileServer = http.FileServer(".", "")
|
||||||
|
|
||||||
func serveFile(c *http.Conn, r *http.Request) {
|
func serveFile(c *http.Conn, r *http.Request) {
|
||||||
path := r.Url.Path;
|
path := pathutil.Join(".", r.Url.Path);
|
||||||
|
|
||||||
// pick off special cases and hand the rest to the standard file server
|
// pick off special cases and hand the rest to the standard file server
|
||||||
switch ext := pathutil.Ext(path); {
|
switch ext := pathutil.Ext(path); {
|
||||||
case path == "/":
|
case r.Url.Path == "/":
|
||||||
serveHtmlDoc(c, r, "doc/root.html");
|
serveHtmlDoc(c, r, "doc/root.html");
|
||||||
|
return;
|
||||||
|
|
||||||
case r.Url.Path == "/doc/root.html":
|
case r.Url.Path == "/doc/root.html":
|
||||||
// hide landing page from its real name
|
// hide landing page from its real name
|
||||||
http.NotFound(c, r);
|
http.NotFound(c, r);
|
||||||
|
return;
|
||||||
|
|
||||||
case ext == ".html":
|
case ext == ".html":
|
||||||
serveHtmlDoc(c, r, path);
|
serveHtmlDoc(c, r, path);
|
||||||
|
return;
|
||||||
|
|
||||||
case ext == ".go":
|
case ext == ".go":
|
||||||
serveGoSource(c, path, &Styler{highlight: r.FormValue("h")});
|
serveGoSource(c, r, path, &Styler{highlight: r.FormValue("h")});
|
||||||
|
return;
|
||||||
default:
|
|
||||||
dir, err := os.Lstat(pathutil.Join(".", path));
|
|
||||||
if err != nil {
|
|
||||||
http.NotFound(c, r);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if dir != nil && dir.IsDirectory() {
|
|
||||||
serveDirectory(c, r);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fileServer.ServeHTTP(c, r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dir, err := os.Lstat(path);
|
||||||
|
if err != nil {
|
||||||
|
http.NotFound(c, r);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if dir != nil && dir.IsDirectory() {
|
||||||
|
serveDirectory(c, r, path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if isTextFile(path) {
|
||||||
|
serveTextFile(c, r, path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileServer.ServeHTTP(c, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user