Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
go
Commits
fd9a5d22
Commit
fd9a5d22
authored
Sep 29, 2010
by
Stephen Ma
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
http: revised http Handler interface
R=rsc CC=golang-dev
https://golang.org/cl/1993043
parent
ffdb855b
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
343 additions
and
313 deletions
+343
-313
src/cmd/godoc/codewalk.go
src/cmd/godoc/codewalk.go
+21
-21
src/cmd/godoc/godoc.go
src/cmd/godoc/godoc.go
+41
-41
src/cmd/godoc/main.go
src/cmd/godoc/main.go
+12
-12
src/pkg/expvar/expvar.go
src/pkg/expvar/expvar.go
+6
-6
src/pkg/http/fs.go
src/pkg/http/fs.go
+23
-23
src/pkg/http/pprof/pprof.go
src/pkg/http/pprof/pprof.go
+13
-13
src/pkg/http/server.go
src/pkg/http/server.go
+198
-174
src/pkg/http/status.go
src/pkg/http/status.go
+6
-0
src/pkg/rpc/debug.go
src/pkg/rpc/debug.go
+3
-3
src/pkg/rpc/server.go
src/pkg/rpc/server.go
+6
-6
src/pkg/websocket/server.go
src/pkg/websocket/server.go
+14
-14
No files found.
src/cmd/godoc/codewalk.go
View file @
fd9a5d22
...
@@ -31,26 +31,26 @@ import (
...
@@ -31,26 +31,26 @@ import (
// Handler for /doc/codewalk/ and below.
// Handler for /doc/codewalk/ and below.
func
codewalk
(
c
*
http
.
Conn
,
r
*
http
.
Request
)
{
func
codewalk
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
relpath
:=
r
.
URL
.
Path
[
len
(
"/doc/codewalk/"
)
:
]
relpath
:=
r
.
URL
.
Path
[
len
(
"/doc/codewalk/"
)
:
]
abspath
:=
absolutePath
(
r
.
URL
.
Path
[
1
:
],
*
goroot
)
abspath
:=
absolutePath
(
r
.
URL
.
Path
[
1
:
],
*
goroot
)
r
.
ParseForm
()
r
.
ParseForm
()
if
f
:=
r
.
FormValue
(
"fileprint"
);
f
!=
""
{
if
f
:=
r
.
FormValue
(
"fileprint"
);
f
!=
""
{
codewalkFileprint
(
c
,
r
,
f
)
codewalkFileprint
(
w
,
r
,
f
)
return
return
}
}
// If directory exists, serve list of code walks.
// If directory exists, serve list of code walks.
dir
,
err
:=
os
.
Lstat
(
abspath
)
dir
,
err
:=
os
.
Lstat
(
abspath
)
if
err
==
nil
&&
dir
.
IsDirectory
()
{
if
err
==
nil
&&
dir
.
IsDirectory
()
{
codewalkDir
(
c
,
r
,
relpath
,
abspath
)
codewalkDir
(
w
,
r
,
relpath
,
abspath
)
return
return
}
}
// If file exists, serve using standard file server.
// If file exists, serve using standard file server.
if
err
==
nil
{
if
err
==
nil
{
serveFile
(
c
,
r
)
serveFile
(
w
,
r
)
return
return
}
}
...
@@ -59,17 +59,17 @@ func codewalk(c *http.Conn, r *http.Request) {
...
@@ -59,17 +59,17 @@ func codewalk(c *http.Conn, r *http.Request) {
cw
,
err
:=
loadCodewalk
(
abspath
+
".xml"
)
cw
,
err
:=
loadCodewalk
(
abspath
+
".xml"
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Stderr
(
err
)
log
.
Stderr
(
err
)
serveError
(
c
,
r
,
relpath
,
err
)
serveError
(
w
,
r
,
relpath
,
err
)
return
return
}
}
// Canonicalize the path and redirect if changed
// Canonicalize the path and redirect if changed
if
redirect
(
c
,
r
)
{
if
redirect
(
w
,
r
)
{
return
return
}
}
b
:=
applyTemplate
(
codewalkHTML
,
"codewalk"
,
cw
)
b
:=
applyTemplate
(
codewalkHTML
,
"codewalk"
,
cw
)
servePage
(
c
,
"Codewalk: "
+
cw
.
Title
,
""
,
""
,
b
)
servePage
(
w
,
"Codewalk: "
+
cw
.
Title
,
""
,
""
,
b
)
}
}
...
@@ -178,7 +178,7 @@ func loadCodewalk(file string) (*Codewalk, os.Error) {
...
@@ -178,7 +178,7 @@ func loadCodewalk(file string) (*Codewalk, os.Error) {
// codewalkDir serves the codewalk directory listing.
// codewalkDir serves the codewalk directory listing.
// It scans the directory for subdirectories or files named *.xml
// It scans the directory for subdirectories or files named *.xml
// and prepares a table.
// and prepares a table.
func
codewalkDir
(
c
*
http
.
Conn
,
r
*
http
.
Request
,
relpath
,
abspath
string
)
{
func
codewalkDir
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
,
relpath
,
abspath
string
)
{
type
elem
struct
{
type
elem
struct
{
Name
string
Name
string
Title
string
Title
string
...
@@ -187,7 +187,7 @@ func codewalkDir(c *http.Conn, r *http.Request, relpath, abspath string) {
...
@@ -187,7 +187,7 @@ func codewalkDir(c *http.Conn, r *http.Request, relpath, abspath string) {
dir
,
err
:=
ioutil
.
ReadDir
(
abspath
)
dir
,
err
:=
ioutil
.
ReadDir
(
abspath
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Stderr
(
err
)
log
.
Stderr
(
err
)
serveError
(
c
,
r
,
relpath
,
err
)
serveError
(
w
,
r
,
relpath
,
err
)
return
return
}
}
var
v
vector
.
Vector
var
v
vector
.
Vector
...
@@ -204,7 +204,7 @@ func codewalkDir(c *http.Conn, r *http.Request, relpath, abspath string) {
...
@@ -204,7 +204,7 @@ func codewalkDir(c *http.Conn, r *http.Request, relpath, abspath string) {
}
}
b
:=
applyTemplate
(
codewalkdirHTML
,
"codewalkdir"
,
v
)
b
:=
applyTemplate
(
codewalkdirHTML
,
"codewalkdir"
,
v
)
servePage
(
c
,
"Codewalks"
,
""
,
""
,
b
)
servePage
(
w
,
"Codewalks"
,
""
,
""
,
b
)
}
}
...
@@ -214,12 +214,12 @@ func codewalkDir(c *http.Conn, r *http.Request, relpath, abspath string) {
...
@@ -214,12 +214,12 @@ func codewalkDir(c *http.Conn, r *http.Request, relpath, abspath string) {
// in the response. This format is used for the middle window pane
// in the response. This format is used for the middle window pane
// of the codewalk pages. It is a separate iframe and does not get
// of the codewalk pages. It is a separate iframe and does not get
// the usual godoc HTML wrapper.
// the usual godoc HTML wrapper.
func
codewalkFileprint
(
c
*
http
.
Conn
,
r
*
http
.
Request
,
f
string
)
{
func
codewalkFileprint
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
,
f
string
)
{
abspath
:=
absolutePath
(
f
,
*
goroot
)
abspath
:=
absolutePath
(
f
,
*
goroot
)
data
,
err
:=
ioutil
.
ReadFile
(
abspath
)
data
,
err
:=
ioutil
.
ReadFile
(
abspath
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Stderr
(
err
)
log
.
Stderr
(
err
)
serveError
(
c
,
r
,
f
,
err
)
serveError
(
w
,
r
,
f
,
err
)
return
return
}
}
lo
,
_
:=
strconv
.
Atoi
(
r
.
FormValue
(
"lo"
))
lo
,
_
:=
strconv
.
Atoi
(
r
.
FormValue
(
"lo"
))
...
@@ -243,17 +243,17 @@ func codewalkFileprint(c *http.Conn, r *http.Request, f string) {
...
@@ -243,17 +243,17 @@ func codewalkFileprint(c *http.Conn, r *http.Request, f string) {
}
}
}
}
io
.
WriteString
(
c
,
`<style type="text/css">@import "/doc/codewalk/codewalk.css";</style><pre>`
)
io
.
WriteString
(
w
,
`<style type="text/css">@import "/doc/codewalk/codewalk.css";</style><pre>`
)
template
.
HTMLEscape
(
c
,
data
[
0
:
mark
])
template
.
HTMLEscape
(
w
,
data
[
0
:
mark
])
io
.
WriteString
(
c
,
"<a name='mark'></a>"
)
io
.
WriteString
(
w
,
"<a name='mark'></a>"
)
template
.
HTMLEscape
(
c
,
data
[
mark
:
lo
])
template
.
HTMLEscape
(
w
,
data
[
mark
:
lo
])
if
lo
<
hi
{
if
lo
<
hi
{
io
.
WriteString
(
c
,
"<div class='codewalkhighlight'>"
)
io
.
WriteString
(
w
,
"<div class='codewalkhighlight'>"
)
template
.
HTMLEscape
(
c
,
data
[
lo
:
hi
])
template
.
HTMLEscape
(
w
,
data
[
lo
:
hi
])
io
.
WriteString
(
c
,
"</div>"
)
io
.
WriteString
(
w
,
"</div>"
)
}
}
template
.
HTMLEscape
(
c
,
data
[
hi
:
])
template
.
HTMLEscape
(
w
,
data
[
hi
:
])
io
.
WriteString
(
c
,
"</pre>"
)
io
.
WriteString
(
w
,
"</pre>"
)
}
}
...
...
src/cmd/godoc/godoc.go
View file @
fd9a5d22
...
@@ -792,7 +792,7 @@ func readTemplates() {
...
@@ -792,7 +792,7 @@ func readTemplates() {
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Generic HTML wrapper
// Generic HTML wrapper
func
servePage
(
c
*
http
.
Conn
,
title
,
subtitle
,
query
string
,
content
[]
byte
)
{
func
servePage
(
w
http
.
ResponseWriter
,
title
,
subtitle
,
query
string
,
content
[]
byte
)
{
type
Data
struct
{
type
Data
struct
{
Title
string
Title
string
Subtitle
string
Subtitle
string
...
@@ -813,15 +813,15 @@ func servePage(c *http.Conn, title, subtitle, query string, content []byte) {
...
@@ -813,15 +813,15 @@ func servePage(c *http.Conn, title, subtitle, query string, content []byte) {
Content
:
content
,
Content
:
content
,
}
}
if
err
:=
godocHTML
.
Execute
(
&
d
,
c
);
err
!=
nil
{
if
err
:=
godocHTML
.
Execute
(
&
d
,
w
);
err
!=
nil
{
log
.
Stderrf
(
"godocHTML.Execute: %s"
,
err
)
log
.
Stderrf
(
"godocHTML.Execute: %s"
,
err
)
}
}
}
}
func
serveText
(
c
*
http
.
Conn
,
text
[]
byte
)
{
func
serveText
(
w
http
.
ResponseWriter
,
text
[]
byte
)
{
c
.
SetHeader
(
"Content-Type"
,
"text/plain; charset=utf-8"
)
w
.
SetHeader
(
"Content-Type"
,
"text/plain; charset=utf-8"
)
c
.
Write
(
text
)
w
.
Write
(
text
)
}
}
...
@@ -844,19 +844,19 @@ func extractString(src []byte, rx *regexp.Regexp) (s string) {
...
@@ -844,19 +844,19 @@ func extractString(src []byte, rx *regexp.Regexp) (s string) {
}
}
func
serveHTMLDoc
(
c
*
http
.
Conn
,
r
*
http
.
Request
,
abspath
,
relpath
string
)
{
func
serveHTMLDoc
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
,
abspath
,
relpath
string
)
{
// get HTML body contents
// get HTML body contents
src
,
err
:=
ioutil
.
ReadFile
(
abspath
)
src
,
err
:=
ioutil
.
ReadFile
(
abspath
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Stderrf
(
"ioutil.ReadFile: %s"
,
err
)
log
.
Stderrf
(
"ioutil.ReadFile: %s"
,
err
)
serveError
(
c
,
r
,
relpath
,
err
)
serveError
(
w
,
r
,
relpath
,
err
)
return
return
}
}
// if it begins with "<!DOCTYPE " assume it is standalone
// if it begins with "<!DOCTYPE " assume it is standalone
// html that doesn't need the template wrapping.
// html that doesn't need the template wrapping.
if
bytes
.
HasPrefix
(
src
,
[]
byte
(
"<!DOCTYPE "
))
{
if
bytes
.
HasPrefix
(
src
,
[]
byte
(
"<!DOCTYPE "
))
{
c
.
Write
(
src
)
w
.
Write
(
src
)
return
return
}
}
...
@@ -875,7 +875,7 @@ func serveHTMLDoc(c *http.Conn, r *http.Request, abspath, relpath string) {
...
@@ -875,7 +875,7 @@ func serveHTMLDoc(c *http.Conn, r *http.Request, abspath, relpath string) {
}
}
subtitle
:=
extractString
(
src
,
subtitleRx
)
subtitle
:=
extractString
(
src
,
subtitleRx
)
servePage
(
c
,
title
,
subtitle
,
""
,
src
)
servePage
(
w
,
title
,
subtitle
,
""
,
src
)
}
}
...
@@ -888,11 +888,11 @@ func applyTemplate(t *template.Template, name string, data interface{}) []byte {
...
@@ -888,11 +888,11 @@ func applyTemplate(t *template.Template, name string, data interface{}) []byte {
}
}
func
serveGoSource
(
c
*
http
.
Conn
,
r
*
http
.
Request
,
abspath
,
relpath
string
)
{
func
serveGoSource
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
,
abspath
,
relpath
string
)
{
file
,
err
:=
parser
.
ParseFile
(
abspath
,
nil
,
parser
.
ParseComments
)
file
,
err
:=
parser
.
ParseFile
(
abspath
,
nil
,
parser
.
ParseComments
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Stderrf
(
"parser.ParseFile: %s"
,
err
)
log
.
Stderrf
(
"parser.ParseFile: %s"
,
err
)
serveError
(
c
,
r
,
relpath
,
err
)
serveError
(
w
,
r
,
relpath
,
err
)
return
return
}
}
...
@@ -911,13 +911,13 @@ func serveGoSource(c *http.Conn, r *http.Request, abspath, relpath string) {
...
@@ -911,13 +911,13 @@ func serveGoSource(c *http.Conn, r *http.Request, abspath, relpath string) {
info
:=
&
SourceInfo
{
styler
.
idList
(),
buf
.
Bytes
()}
info
:=
&
SourceInfo
{
styler
.
idList
(),
buf
.
Bytes
()}
contents
:=
applyTemplate
(
sourceHTML
,
"sourceHTML"
,
info
)
contents
:=
applyTemplate
(
sourceHTML
,
"sourceHTML"
,
info
)
servePage
(
c
,
"Source file "
+
relpath
,
""
,
""
,
contents
)
servePage
(
w
,
"Source file "
+
relpath
,
""
,
""
,
contents
)
}
}
func
redirect
(
c
*
http
.
Conn
,
r
*
http
.
Request
)
(
redirected
bool
)
{
func
redirect
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
(
redirected
bool
)
{
if
canonical
:=
pathutil
.
Clean
(
r
.
URL
.
Path
)
+
"/"
;
r
.
URL
.
Path
!=
canonical
{
if
canonical
:=
pathutil
.
Clean
(
r
.
URL
.
Path
)
+
"/"
;
r
.
URL
.
Path
!=
canonical
{
http
.
Redirect
(
c
,
canonical
,
http
.
StatusMovedPermanently
)
http
.
Redirect
(
w
,
r
,
canonical
,
http
.
StatusMovedPermanently
)
redirected
=
true
redirected
=
true
}
}
return
return
...
@@ -971,11 +971,11 @@ func isTextFile(path string) bool {
...
@@ -971,11 +971,11 @@ func isTextFile(path string) bool {
}
}
func
serveTextFile
(
c
*
http
.
Conn
,
r
*
http
.
Request
,
abspath
,
relpath
string
)
{
func
serveTextFile
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
,
abspath
,
relpath
string
)
{
src
,
err
:=
ioutil
.
ReadFile
(
abspath
)
src
,
err
:=
ioutil
.
ReadFile
(
abspath
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Stderrf
(
"ioutil.ReadFile: %s"
,
err
)
log
.
Stderrf
(
"ioutil.ReadFile: %s"
,
err
)
serveError
(
c
,
r
,
relpath
,
err
)
serveError
(
w
,
r
,
relpath
,
err
)
return
return
}
}
...
@@ -984,19 +984,19 @@ func serveTextFile(c *http.Conn, r *http.Request, abspath, relpath string) {
...
@@ -984,19 +984,19 @@ func serveTextFile(c *http.Conn, r *http.Request, abspath, relpath string) {
template
.
HTMLEscape
(
&
buf
,
src
)
template
.
HTMLEscape
(
&
buf
,
src
)
fmt
.
Fprintln
(
&
buf
,
"</pre>"
)
fmt
.
Fprintln
(
&
buf
,
"</pre>"
)
servePage
(
c
,
"Text file "
+
relpath
,
""
,
""
,
buf
.
Bytes
())
servePage
(
w
,
"Text file "
+
relpath
,
""
,
""
,
buf
.
Bytes
())
}
}
func
serveDirectory
(
c
*
http
.
Conn
,
r
*
http
.
Request
,
abspath
,
relpath
string
)
{
func
serveDirectory
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
,
abspath
,
relpath
string
)
{
if
redirect
(
c
,
r
)
{
if
redirect
(
w
,
r
)
{
return
return
}
}
list
,
err
:=
ioutil
.
ReadDir
(
abspath
)
list
,
err
:=
ioutil
.
ReadDir
(
abspath
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Stderrf
(
"ioutil.ReadDir: %s"
,
err
)
log
.
Stderrf
(
"ioutil.ReadDir: %s"
,
err
)
serveError
(
c
,
r
,
relpath
,
err
)
serveError
(
w
,
r
,
relpath
,
err
)
return
return
}
}
...
@@ -1007,23 +1007,23 @@ func serveDirectory(c *http.Conn, r *http.Request, abspath, relpath string) {
...
@@ -1007,23 +1007,23 @@ func serveDirectory(c *http.Conn, r *http.Request, abspath, relpath string) {
}
}
contents
:=
applyTemplate
(
dirlistHTML
,
"dirlistHTML"
,
list
)
contents
:=
applyTemplate
(
dirlistHTML
,
"dirlistHTML"
,
list
)
servePage
(
c
,
"Directory "
+
relpath
,
""
,
""
,
contents
)
servePage
(
w
,
"Directory "
+
relpath
,
""
,
""
,
contents
)
}
}
func
serveFile
(
c
*
http
.
Conn
,
r
*
http
.
Request
)
{
func
serveFile
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
relpath
:=
r
.
URL
.
Path
[
1
:
]
// serveFile URL paths start with '/'
relpath
:=
r
.
URL
.
Path
[
1
:
]
// serveFile URL paths start with '/'
abspath
:=
absolutePath
(
relpath
,
*
goroot
)
abspath
:=
absolutePath
(
relpath
,
*
goroot
)
// 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
r
.
URL
.
Path
{
switch
r
.
URL
.
Path
{
case
"/"
:
case
"/"
:
serveHTMLDoc
(
c
,
r
,
pathutil
.
Join
(
*
goroot
,
"doc/root.html"
),
"doc/root.html"
)
serveHTMLDoc
(
w
,
r
,
pathutil
.
Join
(
*
goroot
,
"doc/root.html"
),
"doc/root.html"
)
return
return
case
"/doc/root.html"
:
case
"/doc/root.html"
:
// hide landing page from its real name
// hide landing page from its real name
http
.
Redirect
(
c
,
"/"
,
http
.
StatusMovedPermanently
)
http
.
Redirect
(
w
,
r
,
"/"
,
http
.
StatusMovedPermanently
)
return
return
}
}
...
@@ -1032,42 +1032,42 @@ func serveFile(c *http.Conn, r *http.Request) {
...
@@ -1032,42 +1032,42 @@ func serveFile(c *http.Conn, r *http.Request) {
if
strings
.
HasSuffix
(
abspath
,
"/index.html"
)
{
if
strings
.
HasSuffix
(
abspath
,
"/index.html"
)
{
// We'll show index.html for the directory.
// We'll show index.html for the directory.
// Use the dir/ version as canonical instead of dir/index.html.
// Use the dir/ version as canonical instead of dir/index.html.
http
.
Redirect
(
c
,
r
.
URL
.
Path
[
0
:
len
(
r
.
URL
.
Path
)
-
len
(
"index.html"
)],
http
.
StatusMovedPermanently
)
http
.
Redirect
(
w
,
r
,
r
.
URL
.
Path
[
0
:
len
(
r
.
URL
.
Path
)
-
len
(
"index.html"
)],
http
.
StatusMovedPermanently
)
return
return
}
}
serveHTMLDoc
(
c
,
r
,
abspath
,
relpath
)
serveHTMLDoc
(
w
,
r
,
abspath
,
relpath
)
return
return
case
".go"
:
case
".go"
:
serveGoSource
(
c
,
r
,
abspath
,
relpath
)
serveGoSource
(
w
,
r
,
abspath
,
relpath
)
return
return
}
}
dir
,
err
:=
os
.
Lstat
(
abspath
)
dir
,
err
:=
os
.
Lstat
(
abspath
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Stderr
(
err
)
log
.
Stderr
(
err
)
serveError
(
c
,
r
,
relpath
,
err
)
serveError
(
w
,
r
,
relpath
,
err
)
return
return
}
}
if
dir
!=
nil
&&
dir
.
IsDirectory
()
{
if
dir
!=
nil
&&
dir
.
IsDirectory
()
{
if
redirect
(
c
,
r
)
{
if
redirect
(
w
,
r
)
{
return
return
}
}
if
index
:=
abspath
+
"/index.html"
;
isTextFile
(
index
)
{
if
index
:=
abspath
+
"/index.html"
;
isTextFile
(
index
)
{
serveHTMLDoc
(
c
,
r
,
index
,
relativePath
(
index
))
serveHTMLDoc
(
w
,
r
,
index
,
relativePath
(
index
))
return
return
}
}
serveDirectory
(
c
,
r
,
abspath
,
relpath
)
serveDirectory
(
w
,
r
,
abspath
,
relpath
)
return
return
}
}
if
isTextFile
(
abspath
)
{
if
isTextFile
(
abspath
)
{
serveTextFile
(
c
,
r
,
abspath
,
relpath
)
serveTextFile
(
w
,
r
,
abspath
,
relpath
)
return
return
}
}
fileServer
.
ServeHTTP
(
c
,
r
)
fileServer
.
ServeHTTP
(
w
,
r
)
}
}
...
@@ -1243,8 +1243,8 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
...
@@ -1243,8 +1243,8 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
}
}
func
(
h
*
httpHandler
)
ServeHTTP
(
c
*
http
.
Conn
,
r
*
http
.
Request
)
{
func
(
h
*
httpHandler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
if
redirect
(
c
,
r
)
{
if
redirect
(
w
,
r
)
{
return
return
}
}
...
@@ -1257,13 +1257,13 @@ func (h *httpHandler) ServeHTTP(c *http.Conn, r *http.Request) {
...
@@ -1257,13 +1257,13 @@ func (h *httpHandler) ServeHTTP(c *http.Conn, r *http.Request) {
info
:=
h
.
getPageInfo
(
abspath
,
relpath
,
r
.
FormValue
(
"p"
),
mode
)
info
:=
h
.
getPageInfo
(
abspath
,
relpath
,
r
.
FormValue
(
"p"
),
mode
)
if
info
.
Err
!=
nil
{
if
info
.
Err
!=
nil
{
log
.
Stderr
(
info
.
Err
)
log
.
Stderr
(
info
.
Err
)
serveError
(
c
,
r
,
relpath
,
info
.
Err
)
serveError
(
w
,
r
,
relpath
,
info
.
Err
)
return
return
}
}
if
r
.
FormValue
(
"f"
)
==
"text"
{
if
r
.
FormValue
(
"f"
)
==
"text"
{
contents
:=
applyTemplate
(
packageText
,
"packageText"
,
info
)
contents
:=
applyTemplate
(
packageText
,
"packageText"
,
info
)
serveText
(
c
,
contents
)
serveText
(
w
,
contents
)
return
return
}
}
...
@@ -1290,7 +1290,7 @@ func (h *httpHandler) ServeHTTP(c *http.Conn, r *http.Request) {
...
@@ -1290,7 +1290,7 @@ func (h *httpHandler) ServeHTTP(c *http.Conn, r *http.Request) {
}
}
contents
:=
applyTemplate
(
packageHTML
,
"packageHTML"
,
info
)
contents
:=
applyTemplate
(
packageHTML
,
"packageHTML"
,
info
)
servePage
(
c
,
title
,
subtitle
,
""
,
contents
)
servePage
(
w
,
title
,
subtitle
,
""
,
contents
)
}
}
...
@@ -1319,13 +1319,13 @@ func lookup(query string) (result SearchResult) {
...
@@ -1319,13 +1319,13 @@ func lookup(query string) (result SearchResult) {
}
}
func
search
(
c
*
http
.
Conn
,
r
*
http
.
Request
)
{
func
search
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
query
:=
strings
.
TrimSpace
(
r
.
FormValue
(
"q"
))
query
:=
strings
.
TrimSpace
(
r
.
FormValue
(
"q"
))
result
:=
lookup
(
query
)
result
:=
lookup
(
query
)
if
r
.
FormValue
(
"f"
)
==
"text"
{
if
r
.
FormValue
(
"f"
)
==
"text"
{
contents
:=
applyTemplate
(
searchText
,
"searchText"
,
result
)
contents
:=
applyTemplate
(
searchText
,
"searchText"
,
result
)
serveText
(
c
,
contents
)
serveText
(
w
,
contents
)
return
return
}
}
...
@@ -1337,7 +1337,7 @@ func search(c *http.Conn, r *http.Request) {
...
@@ -1337,7 +1337,7 @@ func search(c *http.Conn, r *http.Request) {
}
}
contents
:=
applyTemplate
(
searchHTML
,
"searchHTML"
,
result
)
contents
:=
applyTemplate
(
searchHTML
,
"searchHTML"
,
result
)
servePage
(
c
,
title
,
""
,
query
,
contents
)
servePage
(
w
,
title
,
""
,
query
,
contents
)
}
}
...
...
src/cmd/godoc/main.go
View file @
fd9a5d22
...
@@ -64,14 +64,14 @@ var (
...
@@ -64,14 +64,14 @@ var (
)
)
func
serveError
(
c
*
http
.
Conn
,
r
*
http
.
Request
,
relpath
string
,
err
os
.
Error
)
{
func
serveError
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
,
relpath
string
,
err
os
.
Error
)
{
contents
:=
applyTemplate
(
errorHTML
,
"errorHTML"
,
err
)
// err may contain an absolute path!
contents
:=
applyTemplate
(
errorHTML
,
"errorHTML"
,
err
)
// err may contain an absolute path!
c
.
WriteHeader
(
http
.
StatusNotFound
)
w
.
WriteHeader
(
http
.
StatusNotFound
)
servePage
(
c
,
"File "
+
relpath
,
""
,
""
,
contents
)
servePage
(
w
,
"File "
+
relpath
,
""
,
""
,
contents
)
}
}
func
exec
(
c
*
http
.
Conn
,
args
[]
string
)
(
status
int
)
{
func
exec
(
rw
http
.
ResponseWriter
,
args
[]
string
)
(
status
int
)
{
r
,
w
,
err
:=
os
.
Pipe
()
r
,
w
,
err
:=
os
.
Pipe
()
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Stderrf
(
"os.Pipe(): %v
\n
"
,
err
)
log
.
Stderrf
(
"os.Pipe(): %v
\n
"
,
err
)
...
@@ -109,18 +109,18 @@ func exec(c *http.Conn, args []string) (status int) {
...
@@ -109,18 +109,18 @@ func exec(c *http.Conn, args []string) (status int) {
if
*
verbose
{
if
*
verbose
{
os
.
Stderr
.
Write
(
buf
.
Bytes
())
os
.
Stderr
.
Write
(
buf
.
Bytes
())
}
}
if
c
!=
nil
{
if
rw
!=
nil
{
c
.
SetHeader
(
"content-type"
,
"text/plain; charset=utf-8"
)
rw
.
SetHeader
(
"content-type"
,
"text/plain; charset=utf-8"
)
c
.
Write
(
buf
.
Bytes
())
rw
.
Write
(
buf
.
Bytes
())
}
}
return
return
}
}
func
dosync
(
c
*
http
.
Conn
,
r
*
http
.
Request
)
{
func
dosync
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
args
:=
[]
string
{
"/bin/sh"
,
"-c"
,
*
syncCmd
}
args
:=
[]
string
{
"/bin/sh"
,
"-c"
,
*
syncCmd
}
switch
exec
(
c
,
args
)
{
switch
exec
(
w
,
args
)
{
case
0
:
case
0
:
// sync succeeded and some files have changed;
// sync succeeded and some files have changed;
// update package tree.
// update package tree.
...
@@ -150,9 +150,9 @@ func usage() {
...
@@ -150,9 +150,9 @@ func usage() {
func
loggingHandler
(
h
http
.
Handler
)
http
.
Handler
{
func
loggingHandler
(
h
http
.
Handler
)
http
.
Handler
{
return
http
.
HandlerFunc
(
func
(
c
*
http
.
Conn
,
req
*
http
.
Request
)
{
return
http
.
HandlerFunc
(
func
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
log
.
Stderrf
(
"%s
\t
%s"
,
c
.
RemoteAddr
,
req
.
URL
)
log
.
Stderrf
(
"%s
\t
%s"
,
w
.
RemoteAddr
()
,
req
.
URL
)
h
.
ServeHTTP
(
c
,
req
)
h
.
ServeHTTP
(
w
,
req
)
})
})
}
}
...
...
src/pkg/expvar/expvar.go
View file @
fd9a5d22
...
@@ -210,18 +210,18 @@ func Iter() <-chan KeyValue {
...
@@ -210,18 +210,18 @@ func Iter() <-chan KeyValue {
return
c
return
c
}
}
func
expvarHandler
(
c
*
http
.
Conn
,
req
*
http
.
Request
)
{
func
expvarHandler
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
c
.
SetHeader
(
"content-type"
,
"application/json; charset=utf-8"
)
w
.
SetHeader
(
"content-type"
,
"application/json; charset=utf-8"
)
fmt
.
Fprintf
(
c
,
"{
\n
"
)
fmt
.
Fprintf
(
w
,
"{
\n
"
)
first
:=
true
first
:=
true
for
name
,
value
:=
range
vars
{
for
name
,
value
:=
range
vars
{
if
!
first
{
if
!
first
{
fmt
.
Fprintf
(
c
,
",
\n
"
)
fmt
.
Fprintf
(
w
,
",
\n
"
)
}
}
first
=
false
first
=
false
fmt
.
Fprintf
(
c
,
"%q: %s"
,
name
,
value
)
fmt
.
Fprintf
(
w
,
"%q: %s"
,
name
,
value
)
}
}
fmt
.
Fprintf
(
c
,
"
\n
}
\n
"
)
fmt
.
Fprintf
(
w
,
"
\n
}
\n
"
)
}
}
func
memstats
()
string
{
func
memstats
()
string
{
...
...
src/pkg/http/fs.go
View file @
fd9a5d22
...
@@ -43,8 +43,8 @@ func isText(b []byte) bool {
...
@@ -43,8 +43,8 @@ func isText(b []byte) bool {
return
true
return
true
}
}
func
dirList
(
c
*
Conn
,
f
*
os
.
File
)
{
func
dirList
(
w
ResponseWriter
,
f
*
os
.
File
)
{
fmt
.
Fprintf
(
c
,
"<pre>
\n
"
)
fmt
.
Fprintf
(
w
,
"<pre>
\n
"
)
for
{
for
{
dirs
,
err
:=
f
.
Readdir
(
100
)
dirs
,
err
:=
f
.
Readdir
(
100
)
if
err
!=
nil
||
len
(
dirs
)
==
0
{
if
err
!=
nil
||
len
(
dirs
)
==
0
{
...
@@ -56,25 +56,25 @@ func dirList(c *Conn, f *os.File) {
...
@@ -56,25 +56,25 @@ func dirList(c *Conn, f *os.File) {
name
+=
"/"
name
+=
"/"
}
}
// TODO htmlescape
// TODO htmlescape
fmt
.
Fprintf
(
c
,
"<a href=
\"
%s
\"
>%s</a>
\n
"
,
name
,
name
)
fmt
.
Fprintf
(
w
,
"<a href=
\"
%s
\"
>%s</a>
\n
"
,
name
,
name
)
}
}
}
}
fmt
.
Fprintf
(
c
,
"</pre>
\n
"
)
fmt
.
Fprintf
(
w
,
"</pre>
\n
"
)
}
}
func
serveFile
(
c
*
Conn
,
r
*
Request
,
name
string
,
redirect
bool
)
{
func
serveFile
(
w
ResponseWriter
,
r
*
Request
,
name
string
,
redirect
bool
)
{
const
indexPage
=
"/index.html"
const
indexPage
=
"/index.html"
// redirect .../index.html to .../
// redirect .../index.html to .../
if
strings
.
HasSuffix
(
r
.
URL
.
Path
,
indexPage
)
{
if
strings
.
HasSuffix
(
r
.
URL
.
Path
,
indexPage
)
{
Redirect
(
c
,
r
.
URL
.
Path
[
0
:
len
(
r
.
URL
.
Path
)
-
len
(
indexPage
)
+
1
],
StatusMovedPermanently
)
Redirect
(
w
,
r
,
r
.
URL
.
Path
[
0
:
len
(
r
.
URL
.
Path
)
-
len
(
indexPage
)
+
1
],
StatusMovedPermanently
)
return
return
}
}
f
,
err
:=
os
.
Open
(
name
,
os
.
O_RDONLY
,
0
)
f
,
err
:=
os
.
Open
(
name
,
os
.
O_RDONLY
,
0
)
if
err
!=
nil
{
if
err
!=
nil
{
// TODO expose actual error?
// TODO expose actual error?
NotFound
(
c
,
r
)
NotFound
(
w
,
r
)
return
return
}
}
defer
f
.
Close
()
defer
f
.
Close
()
...
@@ -82,7 +82,7 @@ func serveFile(c *Conn, r *Request, name string, redirect bool) {
...
@@ -82,7 +82,7 @@ func serveFile(c *Conn, r *Request, name string, redirect bool) {
d
,
err1
:=
f
.
Stat
()
d
,
err1
:=
f
.
Stat
()
if
err1
!=
nil
{
if
err1
!=
nil
{
// TODO expose actual error?
// TODO expose actual error?
NotFound
(
c
,
r
)
NotFound
(
w
,
r
)
return
return
}
}
...
@@ -92,22 +92,22 @@ func serveFile(c *Conn, r *Request, name string, redirect bool) {
...
@@ -92,22 +92,22 @@ func serveFile(c *Conn, r *Request, name string, redirect bool) {
url
:=
r
.
URL
.
Path
url
:=
r
.
URL
.
Path
if
d
.
IsDirectory
()
{
if
d
.
IsDirectory
()
{
if
url
[
len
(
url
)
-
1
]
!=
'/'
{
if
url
[
len
(
url
)
-
1
]
!=
'/'
{
Redirect
(
c
,
url
+
"/"
,
StatusMovedPermanently
)
Redirect
(
w
,
r
,
url
+
"/"
,
StatusMovedPermanently
)
return
return
}
}
}
else
{
}
else
{
if
url
[
len
(
url
)
-
1
]
==
'/'
{
if
url
[
len
(
url
)
-
1
]
==
'/'
{
Redirect
(
c
,
url
[
0
:
len
(
url
)
-
1
],
StatusMovedPermanently
)
Redirect
(
w
,
r
,
url
[
0
:
len
(
url
)
-
1
],
StatusMovedPermanently
)
return
return
}
}
}
}
}
}
if
t
,
_
:=
time
.
Parse
(
TimeFormat
,
r
.
Header
[
"If-Modified-Since"
]);
t
!=
nil
&&
d
.
Mtime_ns
/
1e9
<=
t
.
Seconds
()
{
if
t
,
_
:=
time
.
Parse
(
TimeFormat
,
r
.
Header
[
"If-Modified-Since"
]);
t
!=
nil
&&
d
.
Mtime_ns
/
1e9
<=
t
.
Seconds
()
{
c
.
WriteHeader
(
StatusNotModified
)
w
.
WriteHeader
(
StatusNotModified
)
return
return
}
}
c
.
SetHeader
(
"Last-Modified"
,
time
.
SecondsToUTC
(
d
.
Mtime_ns
/
1e9
)
.
Format
(
TimeFormat
))
w
.
SetHeader
(
"Last-Modified"
,
time
.
SecondsToUTC
(
d
.
Mtime_ns
/
1e9
)
.
Format
(
TimeFormat
))
// use contents of index.html for directory, if present
// use contents of index.html for directory, if present
if
d
.
IsDirectory
()
{
if
d
.
IsDirectory
()
{
...
@@ -125,7 +125,7 @@ func serveFile(c *Conn, r *Request, name string, redirect bool) {
...
@@ -125,7 +125,7 @@ func serveFile(c *Conn, r *Request, name string, redirect bool) {
}
}
if
d
.
IsDirectory
()
{
if
d
.
IsDirectory
()
{
dirList
(
c
,
f
)
dirList
(
w
,
f
)
return
return
}
}
...
@@ -133,25 +133,25 @@ func serveFile(c *Conn, r *Request, name string, redirect bool) {
...
@@ -133,25 +133,25 @@ func serveFile(c *Conn, r *Request, name string, redirect bool) {
// use extension to find content type.
// use extension to find content type.
ext
:=
path
.
Ext
(
name
)
ext
:=
path
.
Ext
(
name
)
if
ctype
:=
mime
.
TypeByExtension
(
ext
);
ctype
!=
""
{
if
ctype
:=
mime
.
TypeByExtension
(
ext
);
ctype
!=
""
{
c
.
SetHeader
(
"Content-Type"
,
ctype
)
w
.
SetHeader
(
"Content-Type"
,
ctype
)
}
else
{
}
else
{
// read first chunk to decide between utf-8 text and binary
// read first chunk to decide between utf-8 text and binary
var
buf
[
1024
]
byte
var
buf
[
1024
]
byte
n
,
_
:=
io
.
ReadFull
(
f
,
buf
[
0
:
])
n
,
_
:=
io
.
ReadFull
(
f
,
buf
[
0
:
])
b
:=
buf
[
0
:
n
]
b
:=
buf
[
0
:
n
]
if
isText
(
b
)
{
if
isText
(
b
)
{
c
.
SetHeader
(
"Content-Type"
,
"text-plain; charset=utf-8"
)
w
.
SetHeader
(
"Content-Type"
,
"text-plain; charset=utf-8"
)
}
else
{
}
else
{
c
.
SetHeader
(
"Content-Type"
,
"application/octet-stream"
)
// generic binary
w
.
SetHeader
(
"Content-Type"
,
"application/octet-stream"
)
// generic binary
}
}
c
.
Write
(
b
)
w
.
Write
(
b
)
}
}
io
.
Copy
(
c
,
f
)
io
.
Copy
(
w
,
f
)
}
}
// ServeFile replies to the request with the contents of the named file or directory.
// ServeFile replies to the request with the contents of the named file or directory.
func
ServeFile
(
c
*
Conn
,
r
*
Request
,
name
string
)
{
func
ServeFile
(
w
ResponseWriter
,
r
*
Request
,
name
string
)
{
serveFile
(
c
,
r
,
name
,
false
)
serveFile
(
w
,
r
,
name
,
false
)
}
}
type
fileHandler
struct
{
type
fileHandler
struct
{
...
@@ -165,12 +165,12 @@ type fileHandler struct {
...
@@ -165,12 +165,12 @@ type fileHandler struct {
// looking up the file name in the file system.
// looking up the file name in the file system.
func
FileServer
(
root
,
prefix
string
)
Handler
{
return
&
fileHandler
{
root
,
prefix
}
}
func
FileServer
(
root
,
prefix
string
)
Handler
{
return
&
fileHandler
{
root
,
prefix
}
}
func
(
f
*
fileHandler
)
ServeHTTP
(
c
*
Conn
,
r
*
Request
)
{
func
(
f
*
fileHandler
)
ServeHTTP
(
w
ResponseWriter
,
r
*
Request
)
{
path
:=
r
.
URL
.
Path
path
:=
r
.
URL
.
Path
if
!
strings
.
HasPrefix
(
path
,
f
.
prefix
)
{
if
!
strings
.
HasPrefix
(
path
,
f
.
prefix
)
{
NotFound
(
c
,
r
)
NotFound
(
w
,
r
)
return
return
}
}
path
=
path
[
len
(
f
.
prefix
)
:
]
path
=
path
[
len
(
f
.
prefix
)
:
]
serveFile
(
c
,
r
,
f
.
root
+
"/"
+
path
,
true
)
serveFile
(
w
,
r
,
f
.
root
+
"/"
+
path
,
true
)
}
}
src/pkg/http/pprof/pprof.go
View file @
fd9a5d22
...
@@ -40,28 +40,28 @@ func init() {
...
@@ -40,28 +40,28 @@ func init() {
// Cmdline responds with the running program's
// Cmdline responds with the running program's
// command line, with arguments separated by NUL bytes.
// command line, with arguments separated by NUL bytes.
// The package initialization registers it as /debug/pprof/cmdline.
// The package initialization registers it as /debug/pprof/cmdline.
func
Cmdline
(
c
*
http
.
Conn
,
r
*
http
.
Request
)
{
func
Cmdline
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
c
.
SetHeader
(
"content-type"
,
"text/plain; charset=utf-8"
)
w
.
SetHeader
(
"content-type"
,
"text/plain; charset=utf-8"
)
fmt
.
Fprintf
(
c
,
strings
.
Join
(
os
.
Args
,
"
\x00
"
))
fmt
.
Fprintf
(
w
,
strings
.
Join
(
os
.
Args
,
"
\x00
"
))
}
}
// Heap responds with the pprof-formatted heap profile.
// Heap responds with the pprof-formatted heap profile.
// The package initialization registers it as /debug/pprof/heap.
// The package initialization registers it as /debug/pprof/heap.
func
Heap
(
c
*
http
.
Conn
,
r
*
http
.
Request
)
{
func
Heap
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
c
.
SetHeader
(
"content-type"
,
"text/plain; charset=utf-8"
)
w
.
SetHeader
(
"content-type"
,
"text/plain; charset=utf-8"
)
pprof
.
WriteHeapProfile
(
c
)
pprof
.
WriteHeapProfile
(
w
)
}
}
// Symbol looks up the program counters listed in the request,
// Symbol looks up the program counters listed in the request,
// responding with a table mapping program counters to function names.
// responding with a table mapping program counters to function names.
// The package initialization registers it as /debug/pprof/symbol.
// The package initialization registers it as /debug/pprof/symbol.
func
Symbol
(
c
*
http
.
Conn
,
r
*
http
.
Request
)
{
func
Symbol
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
c
.
SetHeader
(
"content-type"
,
"text/plain; charset=utf-8"
)
w
.
SetHeader
(
"content-type"
,
"text/plain; charset=utf-8"
)
// We don't know how many symbols we have, but we
// We don't know how many symbols we have, but we
// do have symbol information. Pprof only cares whether
// do have symbol information. Pprof only cares whether
// this number is 0 (no symbols available) or > 0.
// this number is 0 (no symbols available) or > 0.
fmt
.
Fprintf
(
c
,
"num_symbols: 1
\n
"
)
fmt
.
Fprintf
(
w
,
"num_symbols: 1
\n
"
)
var
b
*
bufio
.
Reader
var
b
*
bufio
.
Reader
if
r
.
Method
==
"POST"
{
if
r
.
Method
==
"POST"
{
...
@@ -71,15 +71,15 @@ func Symbol(c *http.Conn, r *http.Request) {
...
@@ -71,15 +71,15 @@ func Symbol(c *http.Conn, r *http.Request) {
}
}
for
{
for
{
w
,
err
:=
b
.
ReadSlice
(
'+'
)
w
ord
,
err
:=
b
.
ReadSlice
(
'+'
)
if
err
==
nil
{
if
err
==
nil
{
w
=
w
[
0
:
len
(
w
)
-
1
]
// trim +
w
ord
=
word
[
0
:
len
(
word
)
-
1
]
// trim +
}
}
pc
,
_
:=
strconv
.
Btoui64
(
string
(
w
),
0
)
pc
,
_
:=
strconv
.
Btoui64
(
string
(
w
ord
),
0
)
if
pc
!=
0
{
if
pc
!=
0
{
f
:=
runtime
.
FuncForPC
(
uintptr
(
pc
))
f
:=
runtime
.
FuncForPC
(
uintptr
(
pc
))
if
f
!=
nil
{
if
f
!=
nil
{
fmt
.
Fprintf
(
c
,
"%#x %s
\n
"
,
pc
,
f
.
Name
())
fmt
.
Fprintf
(
w
,
"%#x %s
\n
"
,
pc
,
f
.
Name
())
}
}
}
}
...
...
src/pkg/http/server.go
View file @
fd9a5d22
...
@@ -37,32 +37,78 @@ var (
...
@@ -37,32 +37,78 @@ var (
// registered to serve a particular path or subtree
// registered to serve a particular path or subtree
// in the HTTP server.
// in the HTTP server.
//
//
// ServeHTTP should write reply headers and data to the
Conn
// ServeHTTP should write reply headers and data to the
ResponseWriter
// and then return. Returning signals that the request is finished
// and then return. Returning signals that the request is finished
// and that the HTTP server can move on to the next request on
// and that the HTTP server can move on to the next request on
// the connection.
// the connection.
type
Handler
interface
{
type
Handler
interface
{
ServeHTTP
(
*
Conn
,
*
Request
)
ServeHTTP
(
ResponseWriter
,
*
Request
)
}
}
// A Conn represents the server side of a single active HTTP connection.
// A ResponseWriter interface is used by an HTTP handler to
type
Conn
struct
{
// construct an HTTP response.
RemoteAddr
string
// network address of remote side
type
ResponseWriter
interface
{
Req
*
Request
// current HTTP request
// RemoteAddr returns the address of the client that sent the current request
RemoteAddr
()
string
rwc
io
.
ReadWriteCloser
// i/o connection
buf
*
bufio
.
ReadWriter
// buffered rwc
// UsingTLS returns true if the client is connected using TLS
handler
Handler
// request handler
UsingTLS
()
bool
hijacked
bool
// connection has been hijacked by handler
// SetHeader sets a header line in the eventual response.
// state for the current reply
// For example, SetHeader("Content-Type", "text/html; charset=utf-8")
// will result in the header line
//
// Content-Type: text/html; charset=utf-8
//
// being sent. UTF-8 encoded HTML is the default setting for
// Content-Type in this library, so users need not make that
// particular call. Calls to SetHeader after WriteHeader (or Write)
// are ignored.
SetHeader
(
string
,
string
)
// Write writes the data to the connection as part of an HTTP reply.
// If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
// before writing the data.
Write
([]
byte
)
(
int
,
os
.
Error
)
// WriteHeader sends an HTTP response header with status code.
// If WriteHeader is not called explicitly, the first call to Write
// will trigger an implicit WriteHeader(http.StatusOK).
// Thus explicit calls to WriteHeader are mainly used to
// send error codes.
WriteHeader
(
int
)
// Flush sends any buffered data to the client.
Flush
()
// Hijack lets the caller take over the connection.
// After a call to Hijack(), the HTTP server library
// will not do anything else with the connection.
// It becomes the caller's responsibility to manage
// and close the connection.
Hijack
()
(
io
.
ReadWriteCloser
,
*
bufio
.
ReadWriter
,
os
.
Error
)
}
// A conn represents the server side of an HTTP connection.
type
conn
struct
{
remoteAddr
string
// network address of remote side
handler
Handler
// request handler
rwc
io
.
ReadWriteCloser
// i/o connection
buf
*
bufio
.
ReadWriter
// buffered rwc
hijacked
bool
// connection has been hijacked by handler
usingTLS
bool
// a flag indicating connection over TLS
}
// A response represents the server side of an HTTP response.
type
response
struct
{
conn
*
conn
req
*
Request
// request for this response
chunking
bool
// using chunked transfer encoding for reply body
chunking
bool
// using chunked transfer encoding for reply body
wroteHeader
bool
// reply header has been written
wroteHeader
bool
// reply header has been written
wroteContinue
bool
// 100 Continue response was written
wroteContinue
bool
// 100 Continue response was written
header
map
[
string
]
string
// reply header parameters
header
map
[
string
]
string
// reply header parameters
written
int64
// number of bytes written in body
written
int64
// number of bytes written in body
status
int
// status code passed to WriteHeader
status
int
// status code passed to WriteHeader
usingTLS
bool
// a flag indicating connection over TLS
// close connection after this reply. set on request and
// close connection after this reply. set on request and
// updated after response from handler if there's a
// updated after response from handler if there's a
...
@@ -72,11 +118,9 @@ type Conn struct {
...
@@ -72,11 +118,9 @@ type Conn struct {
}
}
// Create new connection from rwc.
// Create new connection from rwc.
func
newConn
(
rwc
net
.
Conn
,
handler
Handler
)
(
c
*
Conn
,
err
os
.
Error
)
{
func
newConn
(
rwc
net
.
Conn
,
handler
Handler
)
(
c
*
conn
,
err
os
.
Error
)
{
c
=
new
(
Conn
)
c
=
new
(
conn
)
if
a
:=
rwc
.
RemoteAddr
();
a
!=
nil
{
c
.
remoteAddr
=
rwc
.
RemoteAddr
()
.
String
()
c
.
RemoteAddr
=
a
.
String
()
}
c
.
handler
=
handler
c
.
handler
=
handler
c
.
rwc
=
rwc
c
.
rwc
=
rwc
_
,
c
.
usingTLS
=
rwc
.
(
*
tls
.
Conn
)
_
,
c
.
usingTLS
=
rwc
.
(
*
tls
.
Conn
)
...
@@ -89,17 +133,15 @@ func newConn(rwc net.Conn, handler Handler) (c *Conn, err os.Error) {
...
@@ -89,17 +133,15 @@ func newConn(rwc net.Conn, handler Handler) (c *Conn, err os.Error) {
// wrapper around io.ReaderCloser which on first read, sends an
// wrapper around io.ReaderCloser which on first read, sends an
// HTTP/1.1 100 Continue header
// HTTP/1.1 100 Continue header
type
expectContinueReader
struct
{
type
expectContinueReader
struct
{
conn
*
Conn
resp
*
response
readCloser
io
.
ReadCloser
readCloser
io
.
ReadCloser
}
}
func
(
ecr
*
expectContinueReader
)
Read
(
p
[]
byte
)
(
n
int
,
err
os
.
Error
)
{
func
(
ecr
*
expectContinueReader
)
Read
(
p
[]
byte
)
(
n
int
,
err
os
.
Error
)
{
if
!
ecr
.
conn
.
wroteContinue
&&
!
ecr
.
conn
.
hijacked
{
if
!
ecr
.
resp
.
wroteContinue
&&
!
ecr
.
resp
.
conn
.
hijacked
{
ecr
.
conn
.
wroteContinue
=
true
ecr
.
resp
.
wroteContinue
=
true
if
ecr
.
conn
.
Req
.
ProtoAtLeast
(
1
,
1
)
{
io
.
WriteString
(
ecr
.
resp
.
conn
.
buf
,
"HTTP/1.1 100 Continue
\r\n\r\n
"
)
io
.
WriteString
(
ecr
.
conn
.
buf
,
"HTTP/1.1 100 Continue
\r\n\r\n
"
)
ecr
.
resp
.
conn
.
buf
.
Flush
()
ecr
.
conn
.
buf
.
Flush
()
}
}
}
return
ecr
.
readCloser
.
Read
(
p
)
return
ecr
.
readCloser
.
Read
(
p
)
}
}
...
@@ -115,92 +157,80 @@ func (ecr *expectContinueReader) Close() os.Error {
...
@@ -115,92 +157,80 @@ func (ecr *expectContinueReader) Close() os.Error {
const
TimeFormat
=
"Mon, 02 Jan 2006 15:04:05 GMT"
const
TimeFormat
=
"Mon, 02 Jan 2006 15:04:05 GMT"
// Read next request from connection.
// Read next request from connection.
func
(
c
*
Conn
)
readRequest
()
(
req
*
Request
,
err
os
.
Error
)
{
func
(
c
*
conn
)
readRequest
()
(
w
*
response
,
err
os
.
Error
)
{
if
c
.
hijacked
{
if
c
.
hijacked
{
return
nil
,
ErrHijacked
return
nil
,
ErrHijacked
}
}
var
req
*
Request
if
req
,
err
=
ReadRequest
(
c
.
buf
.
Reader
);
err
!=
nil
{
if
req
,
err
=
ReadRequest
(
c
.
buf
.
Reader
);
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
// Reset per-request connection state.
w
=
new
(
response
)
c
.
header
=
make
(
map
[
string
]
string
)
w
.
conn
=
c
c
.
wroteHeader
=
false
w
.
req
=
req
c
.
wroteContinue
=
false
w
.
header
=
make
(
map
[
string
]
string
)
c
.
Req
=
req
// Expect 100 Continue support
// Expect 100 Continue support
if
req
.
expectsContinue
()
{
if
req
.
expectsContinue
()
&&
req
.
ProtoAtLeast
(
1
,
1
)
{
// Wrap the Body reader with one that replies on the connection
// Wrap the Body reader with one that replies on the connection
req
.
Body
=
&
expectContinueReader
{
readCloser
:
req
.
Body
,
conn
:
c
}
req
.
Body
=
&
expectContinueReader
{
readCloser
:
req
.
Body
,
resp
:
w
}
}
}
// Default output is HTML encoded in UTF-8.
// Default output is HTML encoded in UTF-8.
c
.
SetHeader
(
"Content-Type"
,
"text/html; charset=utf-8"
)
w
.
SetHeader
(
"Content-Type"
,
"text/html; charset=utf-8"
)
c
.
SetHeader
(
"Date"
,
time
.
UTC
()
.
Format
(
TimeFormat
))
w
.
SetHeader
(
"Date"
,
time
.
UTC
()
.
Format
(
TimeFormat
))
if
req
.
ProtoAtLeast
(
1
,
1
)
{
if
req
.
ProtoAtLeast
(
1
,
1
)
{
// HTTP/1.1 or greater: use chunked transfer encoding
// HTTP/1.1 or greater: use chunked transfer encoding
// to avoid closing the connection at EOF.
// to avoid closing the connection at EOF.
c
.
chunking
=
true
w
.
chunking
=
true
c
.
SetHeader
(
"Transfer-Encoding"
,
"chunked"
)
w
.
SetHeader
(
"Transfer-Encoding"
,
"chunked"
)
}
else
{
}
else
{
// HTTP version < 1.1: cannot do chunked transfer
// HTTP version < 1.1: cannot do chunked transfer
// encoding, so signal EOF by closing connection.
// encoding, so signal EOF by closing connection.
// Will be overridden if the HTTP handler ends up
// Will be overridden if the HTTP handler ends up
// writing a Content-Length and the client requested
// writing a Content-Length and the client requested
// "Connection: keep-alive"
// "Connection: keep-alive"
c
.
closeAfterReply
=
true
w
.
closeAfterReply
=
true
c
.
chunking
=
false
}
}
return
req
,
nil
return
w
,
nil
}
}
// UsingTLS
returns true if the connection uses transport layer security (TLS).
// UsingTLS
implements the ResponseWriter.UsingTLS
func
(
c
*
Conn
)
UsingTLS
()
bool
{
func
(
w
*
response
)
UsingTLS
()
bool
{
return
c
.
usingTLS
return
w
.
conn
.
usingTLS
}
}
// SetHeader sets a header line in the eventual reply.
// RemoteAddr implements the ResponseWriter.RemoteAddr method
// For example, SetHeader("Content-Type", "text/html; charset=utf-8")
func
(
w
*
response
)
RemoteAddr
()
string
{
return
w
.
conn
.
remoteAddr
}
// will result in the header line
//
// SetHeader implements the ResponseWriter.SetHeader method
// Content-Type: text/html; charset=utf-8
func
(
w
*
response
)
SetHeader
(
hdr
,
val
string
)
{
w
.
header
[
CanonicalHeaderKey
(
hdr
)]
=
val
}
//
// being sent. UTF-8 encoded HTML is the default setting for
// WriteHeader implements the ResponseWriter.WriteHeader method
// Content-Type in this library, so users need not make that
func
(
w
*
response
)
WriteHeader
(
code
int
)
{
// particular call. Calls to SetHeader after WriteHeader (or Write)
if
w
.
conn
.
hijacked
{
// are ignored.
log
.
Stderr
(
"http: response.WriteHeader on hijacked connection"
)
func
(
c
*
Conn
)
SetHeader
(
hdr
,
val
string
)
{
c
.
header
[
CanonicalHeaderKey
(
hdr
)]
=
val
}
// WriteHeader sends an HTTP response header with status code.
// If WriteHeader is not called explicitly, the first call to Write
// will trigger an implicit WriteHeader(http.StatusOK).
// Thus explicit calls to WriteHeader are mainly used to
// send error codes.
func
(
c
*
Conn
)
WriteHeader
(
code
int
)
{
if
c
.
hijacked
{
log
.
Stderr
(
"http: Conn.WriteHeader on hijacked connection"
)
return
return
}
}
if
c
.
wroteHeader
{
if
w
.
wroteHeader
{
log
.
Stderr
(
"http: multiple
Conn
.WriteHeader calls"
)
log
.
Stderr
(
"http: multiple
response
.WriteHeader calls"
)
return
return
}
}
c
.
wroteHeader
=
true
w
.
wroteHeader
=
true
c
.
status
=
code
w
.
status
=
code
if
code
==
StatusNotModified
{
if
code
==
StatusNotModified
{
// Must not have body.
// Must not have body.
c
.
header
[
"Content-Type"
]
=
""
,
false
w
.
header
[
"Content-Type"
]
=
""
,
false
c
.
header
[
"Transfer-Encoding"
]
=
""
,
false
w
.
header
[
"Transfer-Encoding"
]
=
""
,
false
}
}
c
.
written
=
0
if
!
w
.
req
.
ProtoAtLeast
(
1
,
0
)
{
if
!
c
.
Req
.
ProtoAtLeast
(
1
,
0
)
{
return
return
}
}
proto
:=
"HTTP/1.0"
proto
:=
"HTTP/1.0"
if
c
.
R
eq
.
ProtoAtLeast
(
1
,
1
)
{
if
w
.
r
eq
.
ProtoAtLeast
(
1
,
1
)
{
proto
=
"HTTP/1.1"
proto
=
"HTTP/1.1"
}
}
codestring
:=
strconv
.
Itoa
(
code
)
codestring
:=
strconv
.
Itoa
(
code
)
...
@@ -208,57 +238,55 @@ func (c *Conn) WriteHeader(code int) {
...
@@ -208,57 +238,55 @@ func (c *Conn) WriteHeader(code int) {
if
!
ok
{
if
!
ok
{
text
=
"status code "
+
codestring
text
=
"status code "
+
codestring
}
}
io
.
WriteString
(
c
.
buf
,
proto
+
" "
+
codestring
+
" "
+
text
+
"
\r\n
"
)
io
.
WriteString
(
w
.
conn
.
buf
,
proto
+
" "
+
codestring
+
" "
+
text
+
"
\r\n
"
)
for
k
,
v
:=
range
c
.
header
{
for
k
,
v
:=
range
w
.
header
{
io
.
WriteString
(
c
.
buf
,
k
+
": "
+
v
+
"
\r\n
"
)
io
.
WriteString
(
w
.
conn
.
buf
,
k
+
": "
+
v
+
"
\r\n
"
)
}
}
io
.
WriteString
(
c
.
buf
,
"
\r\n
"
)
io
.
WriteString
(
w
.
conn
.
buf
,
"
\r\n
"
)
}
}
// Write writes the data to the connection as part of an HTTP reply.
// Write implements the ResponseWriter.Write method
// If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
func
(
w
*
response
)
Write
(
data
[]
byte
)
(
n
int
,
err
os
.
Error
)
{
// before writing the data.
if
w
.
conn
.
hijacked
{
func
(
c
*
Conn
)
Write
(
data
[]
byte
)
(
n
int
,
err
os
.
Error
)
{
log
.
Stderr
(
"http: response.Write on hijacked connection"
)
if
c
.
hijacked
{
log
.
Stderr
(
"http: Conn.Write on hijacked connection"
)
return
0
,
ErrHijacked
return
0
,
ErrHijacked
}
}
if
!
c
.
wroteHeader
{
if
!
w
.
wroteHeader
{
if
c
.
R
eq
.
wantsHttp10KeepAlive
()
{
if
w
.
r
eq
.
wantsHttp10KeepAlive
()
{
_
,
hasLength
:=
c
.
header
[
"Content-Length"
]
_
,
hasLength
:=
w
.
header
[
"Content-Length"
]
if
hasLength
{
if
hasLength
{
_
,
connectionHeaderSet
:=
c
.
header
[
"Connection"
]
_
,
connectionHeaderSet
:=
w
.
header
[
"Connection"
]
if
!
connectionHeaderSet
{
if
!
connectionHeaderSet
{
c
.
header
[
"Connection"
]
=
"keep-alive"
w
.
header
[
"Connection"
]
=
"keep-alive"
}
}
}
}
}
}
c
.
WriteHeader
(
StatusOK
)
w
.
WriteHeader
(
StatusOK
)
}
}
if
len
(
data
)
==
0
{
if
len
(
data
)
==
0
{
return
0
,
nil
return
0
,
nil
}
}
if
c
.
status
==
StatusNotModified
{
if
w
.
status
==
StatusNotModified
{
// Must not have body.
// Must not have body.
return
0
,
ErrBodyNotAllowed
return
0
,
ErrBodyNotAllowed
}
}
c
.
written
+=
int64
(
len
(
data
))
// ignoring errors, for errorKludge
w
.
written
+=
int64
(
len
(
data
))
// ignoring errors, for errorKludge
// TODO(rsc): if chunking happened after the buffering,
// TODO(rsc): if chunking happened after the buffering,
// then there would be fewer chunk headers.
// then there would be fewer chunk headers.
// On the other hand, it would make hijacking more difficult.
// On the other hand, it would make hijacking more difficult.
if
c
.
chunking
{
if
w
.
chunking
{
fmt
.
Fprintf
(
c
.
buf
,
"%x
\r\n
"
,
len
(
data
))
// TODO(rsc): use strconv not fmt
fmt
.
Fprintf
(
w
.
conn
.
buf
,
"%x
\r\n
"
,
len
(
data
))
// TODO(rsc): use strconv not fmt
}
}
n
,
err
=
c
.
buf
.
Write
(
data
)
n
,
err
=
w
.
conn
.
buf
.
Write
(
data
)
if
err
==
nil
&&
c
.
chunking
{
if
err
==
nil
&&
w
.
chunking
{
if
n
!=
len
(
data
)
{
if
n
!=
len
(
data
)
{
err
=
io
.
ErrShortWrite
err
=
io
.
ErrShortWrite
}
}
if
err
==
nil
{
if
err
==
nil
{
io
.
WriteString
(
c
.
buf
,
"
\r\n
"
)
io
.
WriteString
(
w
.
conn
.
buf
,
"
\r\n
"
)
}
}
}
}
...
@@ -272,22 +300,22 @@ func (c *Conn) Write(data []byte) (n int, err os.Error) {
...
@@ -272,22 +300,22 @@ func (c *Conn) Write(data []byte) (n int, err os.Error) {
// long enough. The minimum lengths used in those
// long enough. The minimum lengths used in those
// browsers are in the 256-512 range.
// browsers are in the 256-512 range.
// Pad to 1024 bytes.
// Pad to 1024 bytes.
func
errorKludge
(
c
*
Conn
,
req
*
Request
)
{
func
errorKludge
(
w
*
response
)
{
const
min
=
1024
const
min
=
1024
// Is this an error?
// Is this an error?
if
kind
:=
c
.
status
/
100
;
kind
!=
4
&&
kind
!=
5
{
if
kind
:=
w
.
status
/
100
;
kind
!=
4
&&
kind
!=
5
{
return
return
}
}
// Did the handler supply any info? Enough?
// Did the handler supply any info? Enough?
if
c
.
written
==
0
||
c
.
written
>=
min
{
if
w
.
written
==
0
||
w
.
written
>=
min
{
return
return
}
}
// Is it a broken browser?
// Is it a broken browser?
var
msg
string
var
msg
string
switch
agent
:=
req
.
UserAgent
;
{
switch
agent
:=
w
.
req
.
UserAgent
;
{
case
strings
.
Index
(
agent
,
"MSIE"
)
>=
0
:
case
strings
.
Index
(
agent
,
"MSIE"
)
>=
0
:
msg
=
"Internet Explorer"
msg
=
"Internet Explorer"
case
strings
.
Index
(
agent
,
"Chrome/"
)
>=
0
:
case
strings
.
Index
(
agent
,
"Chrome/"
)
>=
0
:
...
@@ -298,53 +326,53 @@ func errorKludge(c *Conn, req *Request) {
...
@@ -298,53 +326,53 @@ func errorKludge(c *Conn, req *Request) {
msg
+=
" would ignore this error page if this text weren't here.
\n
"
msg
+=
" would ignore this error page if this text weren't here.
\n
"
// Is it text? ("Content-Type" is always in the map)
// Is it text? ("Content-Type" is always in the map)
baseType
:=
strings
.
Split
(
c
.
header
[
"Content-Type"
],
";"
,
2
)[
0
]
baseType
:=
strings
.
Split
(
w
.
header
[
"Content-Type"
],
";"
,
2
)[
0
]
switch
baseType
{
switch
baseType
{
case
"text/html"
:
case
"text/html"
:
io
.
WriteString
(
c
,
"<!-- "
)
io
.
WriteString
(
w
,
"<!-- "
)
for
c
.
written
<
min
{
for
w
.
written
<
min
{
io
.
WriteString
(
c
,
msg
)
io
.
WriteString
(
w
,
msg
)
}
}
io
.
WriteString
(
c
,
" -->"
)
io
.
WriteString
(
w
,
" -->"
)
case
"text/plain"
:
case
"text/plain"
:
io
.
WriteString
(
c
,
"
\n
"
)
io
.
WriteString
(
w
,
"
\n
"
)
for
c
.
written
<
min
{
for
w
.
written
<
min
{
io
.
WriteString
(
c
,
msg
)
io
.
WriteString
(
w
,
msg
)
}
}
}
}
}
}
func
(
c
*
Conn
)
finishRequest
()
{
func
(
w
*
response
)
finishRequest
()
{
// If this was an HTTP/1.0 request with keep-alive and we sent a Content-Length
// If this was an HTTP/1.0 request with keep-alive and we sent a Content-Length
// back, we can make this a keep-alive response ...
// back, we can make this a keep-alive response ...
if
c
.
R
eq
.
wantsHttp10KeepAlive
()
{
if
w
.
r
eq
.
wantsHttp10KeepAlive
()
{
_
,
sentLength
:=
c
.
header
[
"Content-Length"
]
_
,
sentLength
:=
w
.
header
[
"Content-Length"
]
if
sentLength
&&
c
.
header
[
"Connection"
]
==
"keep-alive"
{
if
sentLength
&&
w
.
header
[
"Connection"
]
==
"keep-alive"
{
c
.
closeAfterReply
=
false
w
.
closeAfterReply
=
false
}
}
}
}
if
!
c
.
wroteHeader
{
if
!
w
.
wroteHeader
{
c
.
WriteHeader
(
StatusOK
)
w
.
WriteHeader
(
StatusOK
)
}
}
errorKludge
(
c
,
c
.
Req
)
errorKludge
(
w
)
if
c
.
chunking
{
if
w
.
chunking
{
io
.
WriteString
(
c
.
buf
,
"0
\r\n
"
)
io
.
WriteString
(
w
.
conn
.
buf
,
"0
\r\n
"
)
// trailer key/value pairs, followed by blank line
// trailer key/value pairs, followed by blank line
io
.
WriteString
(
c
.
buf
,
"
\r\n
"
)
io
.
WriteString
(
w
.
conn
.
buf
,
"
\r\n
"
)
}
}
c
.
buf
.
Flush
()
w
.
conn
.
buf
.
Flush
()
}
}
// Flush
sends any buffered data to the client
.
// Flush
implements the ResponseWriter.Flush method
.
func
(
c
*
Conn
)
Flush
()
{
func
(
w
*
response
)
Flush
()
{
if
!
c
.
wroteHeader
{
if
!
w
.
wroteHeader
{
c
.
WriteHeader
(
StatusOK
)
w
.
WriteHeader
(
StatusOK
)
}
}
c
.
buf
.
Flush
()
w
.
conn
.
buf
.
Flush
()
}
}
// Close the connection.
// Close the connection.
func
(
c
*
C
onn
)
close
()
{
func
(
c
*
c
onn
)
close
()
{
if
c
.
buf
!=
nil
{
if
c
.
buf
!=
nil
{
c
.
buf
.
Flush
()
c
.
buf
.
Flush
()
c
.
buf
=
nil
c
.
buf
=
nil
...
@@ -356,9 +384,9 @@ func (c *Conn) close() {
...
@@ -356,9 +384,9 @@ func (c *Conn) close() {
}
}
// Serve a new connection.
// Serve a new connection.
func
(
c
*
C
onn
)
serve
()
{
func
(
c
*
c
onn
)
serve
()
{
for
{
for
{
req
,
err
:=
c
.
readRequest
()
w
,
err
:=
c
.
readRequest
()
if
err
!=
nil
{
if
err
!=
nil
{
break
break
}
}
...
@@ -367,32 +395,28 @@ func (c *Conn) serve() {
...
@@ -367,32 +395,28 @@ func (c *Conn) serve() {
// so we might as well run the handler in this goroutine.
// so we might as well run the handler in this goroutine.
// [*] Not strictly true: HTTP pipelining. We could let them all process
// [*] Not strictly true: HTTP pipelining. We could let them all process
// in parallel even if their responses need to be serialized.
// in parallel even if their responses need to be serialized.
c
.
handler
.
ServeHTTP
(
c
,
req
)
c
.
handler
.
ServeHTTP
(
w
,
w
.
req
)
if
c
.
hijacked
{
if
c
.
hijacked
{
return
return
}
}
c
.
finishRequest
()
w
.
finishRequest
()
if
c
.
closeAfterReply
{
if
w
.
closeAfterReply
{
break
break
}
}
}
}
c
.
close
()
c
.
close
()
}
}
// Hijack lets the caller take over the connection.
// Hijack impements the ResponseWriter.Hijack method.
// After a call to c.Hijack(), the HTTP server library
func
(
w
*
response
)
Hijack
()
(
rwc
io
.
ReadWriteCloser
,
buf
*
bufio
.
ReadWriter
,
err
os
.
Error
)
{
// will not do anything else with the connection.
if
w
.
conn
.
hijacked
{
// It becomes the caller's responsibility to manage
// and close the connection.
func
(
c
*
Conn
)
Hijack
()
(
rwc
io
.
ReadWriteCloser
,
buf
*
bufio
.
ReadWriter
,
err
os
.
Error
)
{
if
c
.
hijacked
{
return
nil
,
nil
,
ErrHijacked
return
nil
,
nil
,
ErrHijacked
}
}
c
.
hijacked
=
true
w
.
conn
.
hijacked
=
true
rwc
=
c
.
rwc
rwc
=
w
.
conn
.
rwc
buf
=
c
.
buf
buf
=
w
.
conn
.
buf
c
.
rwc
=
nil
w
.
conn
.
rwc
=
nil
c
.
buf
=
nil
w
.
conn
.
buf
=
nil
return
return
}
}
...
@@ -400,24 +424,24 @@ func (c *Conn) Hijack() (rwc io.ReadWriteCloser, buf *bufio.ReadWriter, err os.E
...
@@ -400,24 +424,24 @@ func (c *Conn) Hijack() (rwc io.ReadWriteCloser, buf *bufio.ReadWriter, err os.E
// ordinary functions as HTTP handlers. If f is a function
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// with the appropriate signature, HandlerFunc(f) is a
// Handler object that calls f.
// Handler object that calls f.
type
HandlerFunc
func
(
*
Conn
,
*
Request
)
type
HandlerFunc
func
(
ResponseWriter
,
*
Request
)
// ServeHTTP calls f(c, req).
// ServeHTTP calls f(c, req).
func
(
f
HandlerFunc
)
ServeHTTP
(
c
*
Conn
,
req
*
Request
)
{
func
(
f
HandlerFunc
)
ServeHTTP
(
w
ResponseWriter
,
r
*
Request
)
{
f
(
c
,
req
)
f
(
w
,
r
)
}
}
// Helper handlers
// Helper handlers
// Error replies to the request with the specified error message and HTTP code.
// Error replies to the request with the specified error message and HTTP code.
func
Error
(
c
*
Conn
,
error
string
,
code
int
)
{
func
Error
(
w
ResponseWriter
,
error
string
,
code
int
)
{
c
.
SetHeader
(
"Content-Type"
,
"text/plain; charset=utf-8"
)
w
.
SetHeader
(
"Content-Type"
,
"text/plain; charset=utf-8"
)
c
.
WriteHeader
(
code
)
w
.
WriteHeader
(
code
)
fmt
.
Fprintln
(
c
,
error
)
fmt
.
Fprintln
(
w
,
error
)
}
}
// NotFound replies to the request with an HTTP 404 not found error.
// NotFound replies to the request with an HTTP 404 not found error.
func
NotFound
(
c
*
Conn
,
req
*
Request
)
{
Error
(
c
,
"404 page not found"
,
StatusNotFound
)
}
func
NotFound
(
w
ResponseWriter
,
r
*
Request
)
{
Error
(
w
,
"404 page not found"
,
StatusNotFound
)
}
// NotFoundHandler returns a simple request handler
// NotFoundHandler returns a simple request handler
// that replies to each request with a ``404 page not found'' reply.
// that replies to each request with a ``404 page not found'' reply.
...
@@ -425,11 +449,11 @@ func NotFoundHandler() Handler { return HandlerFunc(NotFound) }
...
@@ -425,11 +449,11 @@ func NotFoundHandler() Handler { return HandlerFunc(NotFound) }
// Redirect replies to the request with a redirect to url,
// Redirect replies to the request with a redirect to url,
// which may be a path relative to the request path.
// which may be a path relative to the request path.
func
Redirect
(
c
*
Conn
,
url
string
,
code
int
)
{
func
Redirect
(
w
ResponseWriter
,
r
*
Request
,
url
string
,
code
int
)
{
// RFC2616 recommends that a short note "SHOULD" be included in the
// RFC2616 recommends that a short note "SHOULD" be included in the
// response because older user agents may not understand 301/307.
// response because older user agents may not understand 301/307.
note
:=
"<a href=
\"
%v
\"
>"
+
statusText
[
code
]
+
"</a>.
\n
"
note
:=
"<a href=
\"
%v
\"
>"
+
statusText
[
code
]
+
"</a>.
\n
"
if
c
.
Req
.
Method
==
"POST"
{
if
r
.
Method
==
"POST"
{
note
=
""
note
=
""
}
}
...
@@ -454,7 +478,7 @@ func Redirect(c *Conn, url string, code int) {
...
@@ -454,7 +478,7 @@ func Redirect(c *Conn, url string, code int) {
// Because of this problem, no one pays attention
// Because of this problem, no one pays attention
// to the RFC; they all send back just a new path.
// to the RFC; they all send back just a new path.
// So do we.
// So do we.
oldpath
:=
c
.
Req
.
URL
.
Path
oldpath
:=
r
.
URL
.
Path
if
oldpath
==
""
{
// should not happen, but avoid a crash if it does
if
oldpath
==
""
{
// should not happen, but avoid a crash if it does
oldpath
=
"/"
oldpath
=
"/"
}
}
...
@@ -475,9 +499,9 @@ func Redirect(c *Conn, url string, code int) {
...
@@ -475,9 +499,9 @@ func Redirect(c *Conn, url string, code int) {
}
}
finish
:
finish
:
c
.
SetHeader
(
"Location"
,
url
)
w
.
SetHeader
(
"Location"
,
url
)
c
.
WriteHeader
(
code
)
w
.
WriteHeader
(
code
)
fmt
.
Fprintf
(
c
,
note
,
url
)
fmt
.
Fprintf
(
w
,
note
,
url
)
}
}
// Redirect to a fixed URL
// Redirect to a fixed URL
...
@@ -486,8 +510,8 @@ type redirectHandler struct {
...
@@ -486,8 +510,8 @@ type redirectHandler struct {
code
int
code
int
}
}
func
(
rh
*
redirectHandler
)
ServeHTTP
(
c
*
Conn
,
req
*
Request
)
{
func
(
rh
*
redirectHandler
)
ServeHTTP
(
w
ResponseWriter
,
r
*
Request
)
{
Redirect
(
c
,
rh
.
url
,
rh
.
code
)
Redirect
(
w
,
r
,
rh
.
url
,
rh
.
code
)
}
}
// RedirectHandler returns a request handler that redirects
// RedirectHandler returns a request handler that redirects
...
@@ -563,11 +587,11 @@ func cleanPath(p string) string {
...
@@ -563,11 +587,11 @@ func cleanPath(p string) string {
// ServeHTTP dispatches the request to the handler whose
// ServeHTTP dispatches the request to the handler whose
// pattern most closely matches the request URL.
// pattern most closely matches the request URL.
func
(
mux
*
ServeMux
)
ServeHTTP
(
c
*
Conn
,
req
*
Request
)
{
func
(
mux
*
ServeMux
)
ServeHTTP
(
w
ResponseWriter
,
r
*
Request
)
{
// Clean path to canonical form and redirect.
// Clean path to canonical form and redirect.
if
p
:=
cleanPath
(
r
eq
.
URL
.
Path
);
p
!=
req
.
URL
.
Path
{
if
p
:=
cleanPath
(
r
.
URL
.
Path
);
p
!=
r
.
URL
.
Path
{
c
.
SetHeader
(
"Location"
,
p
)
w
.
SetHeader
(
"Location"
,
p
)
c
.
WriteHeader
(
StatusMovedPermanently
)
w
.
WriteHeader
(
StatusMovedPermanently
)
return
return
}
}
...
@@ -575,7 +599,7 @@ func (mux *ServeMux) ServeHTTP(c *Conn, req *Request) {
...
@@ -575,7 +599,7 @@ func (mux *ServeMux) ServeHTTP(c *Conn, req *Request) {
var
h
Handler
var
h
Handler
var
n
=
0
var
n
=
0
for
k
,
v
:=
range
mux
.
m
{
for
k
,
v
:=
range
mux
.
m
{
if
!
pathMatch
(
k
,
r
eq
.
URL
.
Path
)
{
if
!
pathMatch
(
k
,
r
.
URL
.
Path
)
{
continue
continue
}
}
if
h
==
nil
||
len
(
k
)
>
n
{
if
h
==
nil
||
len
(
k
)
>
n
{
...
@@ -586,7 +610,7 @@ func (mux *ServeMux) ServeHTTP(c *Conn, req *Request) {
...
@@ -586,7 +610,7 @@ func (mux *ServeMux) ServeHTTP(c *Conn, req *Request) {
if
h
==
nil
{
if
h
==
nil
{
h
=
NotFoundHandler
()
h
=
NotFoundHandler
()
}
}
h
.
ServeHTTP
(
c
,
req
)
h
.
ServeHTTP
(
w
,
r
)
}
}
// Handle registers the handler for the given pattern.
// Handle registers the handler for the given pattern.
...
@@ -606,7 +630,7 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) {
...
@@ -606,7 +630,7 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) {
}
}
// HandleFunc registers the handler function for the given pattern.
// HandleFunc registers the handler function for the given pattern.
func
(
mux
*
ServeMux
)
HandleFunc
(
pattern
string
,
handler
func
(
*
Conn
,
*
Request
))
{
func
(
mux
*
ServeMux
)
HandleFunc
(
pattern
string
,
handler
func
(
ResponseWriter
,
*
Request
))
{
mux
.
Handle
(
pattern
,
HandlerFunc
(
handler
))
mux
.
Handle
(
pattern
,
HandlerFunc
(
handler
))
}
}
...
@@ -616,7 +640,7 @@ func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, h
...
@@ -616,7 +640,7 @@ func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, h
// HandleFunc registers the handler function for the given pattern
// HandleFunc registers the handler function for the given pattern
// in the DefaultServeMux.
// in the DefaultServeMux.
func
HandleFunc
(
pattern
string
,
handler
func
(
*
Conn
,
*
Request
))
{
func
HandleFunc
(
pattern
string
,
handler
func
(
ResponseWriter
,
*
Request
))
{
DefaultServeMux
.
HandleFunc
(
pattern
,
handler
)
DefaultServeMux
.
HandleFunc
(
pattern
,
handler
)
}
}
...
@@ -658,8 +682,8 @@ func Serve(l net.Listener, handler Handler) os.Error {
...
@@ -658,8 +682,8 @@ func Serve(l net.Listener, handler Handler) os.Error {
// )
// )
//
//
// // hello world, the web server
// // hello world, the web server
// func HelloServer(
c *http.Conn
, req *http.Request) {
// func HelloServer(
w http.ResponseWriter
, req *http.Request) {
// io.WriteString(
c
, "hello, world!\n")
// io.WriteString(
w
, "hello, world!\n")
// }
// }
//
//
// func main() {
// func main() {
...
@@ -690,9 +714,9 @@ func ListenAndServe(addr string, handler Handler) os.Error {
...
@@ -690,9 +714,9 @@ func ListenAndServe(addr string, handler Handler) os.Error {
// "log"
// "log"
// )
// )
//
//
// func handler(
conn *http.Conn
, req *http.Request) {
// func handler(
w http.ResponseWriter
, req *http.Request) {
//
conn
.SetHeader("Content-Type", "text/plain")
//
w
.SetHeader("Content-Type", "text/plain")
//
conn
.Write([]byte("This is an example server.\n"))
//
w
.Write([]byte("This is an example server.\n"))
// }
// }
//
//
// func main() {
// func main() {
...
...
src/pkg/http/status.go
View file @
fd9a5d22
...
@@ -98,3 +98,9 @@ var statusText = map[int]string{
...
@@ -98,3 +98,9 @@ var statusText = map[int]string{
StatusGatewayTimeout
:
"Gateway Timeout"
,
StatusGatewayTimeout
:
"Gateway Timeout"
,
StatusHTTPVersionNotSupported
:
"HTTP Version Not Supported"
,
StatusHTTPVersionNotSupported
:
"HTTP Version Not Supported"
,
}
}
// StatusText returns a text for the HTTP status code. It returns the empty
// string if the code is unknown.
func
StatusText
(
code
int
)
string
{
return
statusText
[
code
]
}
src/pkg/rpc/debug.go
View file @
fd9a5d22
...
@@ -62,7 +62,7 @@ func (m methodArray) Less(i, j int) bool { return m[i].name < m[j].name }
...
@@ -62,7 +62,7 @@ func (m methodArray) Less(i, j int) bool { return m[i].name < m[j].name }
func
(
m
methodArray
)
Swap
(
i
,
j
int
)
{
m
[
i
],
m
[
j
]
=
m
[
j
],
m
[
i
]
}
func
(
m
methodArray
)
Swap
(
i
,
j
int
)
{
m
[
i
],
m
[
j
]
=
m
[
j
],
m
[
i
]
}
// Runs at /debug/rpc
// Runs at /debug/rpc
func
debugHTTP
(
c
*
http
.
Conn
,
req
*
http
.
Request
)
{
func
debugHTTP
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
// Build a sorted version of the data.
// Build a sorted version of the data.
var
services
=
make
(
serviceArray
,
len
(
server
.
serviceMap
))
var
services
=
make
(
serviceArray
,
len
(
server
.
serviceMap
))
i
:=
0
i
:=
0
...
@@ -79,8 +79,8 @@ func debugHTTP(c *http.Conn, req *http.Request) {
...
@@ -79,8 +79,8 @@ func debugHTTP(c *http.Conn, req *http.Request) {
}
}
server
.
Unlock
()
server
.
Unlock
()
sort
.
Sort
(
services
)
sort
.
Sort
(
services
)
err
:=
debug
.
Execute
(
services
,
c
)
err
:=
debug
.
Execute
(
services
,
w
)
if
err
!=
nil
{
if
err
!=
nil
{
fmt
.
Fprintln
(
c
,
"rpc: error executing template:"
,
err
.
String
())
fmt
.
Fprintln
(
w
,
"rpc: error executing template:"
,
err
.
String
())
}
}
}
}
src/pkg/rpc/server.go
View file @
fd9a5d22
...
@@ -445,16 +445,16 @@ var rpcPath string = "/_goRPC_"
...
@@ -445,16 +445,16 @@ var rpcPath string = "/_goRPC_"
var
debugPath
string
=
"/debug/rpc"
var
debugPath
string
=
"/debug/rpc"
var
connected
=
"200 Connected to Go RPC"
var
connected
=
"200 Connected to Go RPC"
func
serveHTTP
(
c
*
http
.
Conn
,
req
*
http
.
Request
)
{
func
serveHTTP
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
if
req
.
Method
!=
"CONNECT"
{
if
req
.
Method
!=
"CONNECT"
{
c
.
SetHeader
(
"Content-Type"
,
"text/plain; charset=utf-8"
)
w
.
SetHeader
(
"Content-Type"
,
"text/plain; charset=utf-8"
)
c
.
WriteHeader
(
http
.
StatusMethodNotAllowed
)
w
.
WriteHeader
(
http
.
StatusMethodNotAllowed
)
io
.
WriteString
(
c
,
"405 must CONNECT to "
+
rpcPath
+
"
\n
"
)
io
.
WriteString
(
w
,
"405 must CONNECT to "
+
rpcPath
+
"
\n
"
)
return
return
}
}
conn
,
_
,
err
:=
c
.
Hijack
()
conn
,
_
,
err
:=
w
.
Hijack
()
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Stderr
(
"rpc hijacking "
,
c
.
RemoteAddr
,
": "
,
err
.
String
())
log
.
Stderr
(
"rpc hijacking "
,
w
.
RemoteAddr
()
,
": "
,
err
.
String
())
return
return
}
}
io
.
WriteString
(
conn
,
"HTTP/1.0 "
+
connected
+
"
\n\n
"
)
io
.
WriteString
(
conn
,
"HTTP/1.0 "
+
connected
+
"
\n\n
"
)
...
...
src/pkg/websocket/server.go
View file @
fd9a5d22
...
@@ -57,8 +57,8 @@ func getKeyNumber(s string) (r uint32) {
...
@@ -57,8 +57,8 @@ func getKeyNumber(s string) (r uint32) {
}
}
// ServeHTTP implements the http.Handler interface for a Web Socket
// ServeHTTP implements the http.Handler interface for a Web Socket
func
(
f
Handler
)
ServeHTTP
(
c
*
http
.
Conn
,
req
*
http
.
Request
)
{
func
(
f
Handler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
rwc
,
buf
,
err
:=
c
.
Hijack
()
rwc
,
buf
,
err
:=
w
.
Hijack
()
if
err
!=
nil
{
if
err
!=
nil
{
panic
(
"Hijack failed: "
+
err
.
String
())
panic
(
"Hijack failed: "
+
err
.
String
())
return
return
...
@@ -98,7 +98,7 @@ func (f Handler) ServeHTTP(c *http.Conn, req *http.Request) {
...
@@ -98,7 +98,7 @@ func (f Handler) ServeHTTP(c *http.Conn, req *http.Request) {
}
}
var
location
string
var
location
string
if
c
.
UsingTLS
()
{
if
w
.
UsingTLS
()
{
location
=
"wss://"
+
req
.
Host
+
req
.
URL
.
RawPath
location
=
"wss://"
+
req
.
Host
+
req
.
URL
.
RawPath
}
else
{
}
else
{
location
=
"ws://"
+
req
.
Host
+
req
.
URL
.
RawPath
location
=
"ws://"
+
req
.
Host
+
req
.
URL
.
RawPath
...
@@ -161,30 +161,30 @@ Draft75Handler is an interface to a WebSocket based on the
...
@@ -161,30 +161,30 @@ Draft75Handler is an interface to a WebSocket based on the
type
Draft75Handler
func
(
*
Conn
)
type
Draft75Handler
func
(
*
Conn
)
// ServeHTTP implements the http.Handler interface for a Web Socket.
// ServeHTTP implements the http.Handler interface for a Web Socket.
func
(
f
Draft75Handler
)
ServeHTTP
(
c
*
http
.
Conn
,
req
*
http
.
Request
)
{
func
(
f
Draft75Handler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
if
req
.
Method
!=
"GET"
||
req
.
Proto
!=
"HTTP/1.1"
{
if
req
.
Method
!=
"GET"
||
req
.
Proto
!=
"HTTP/1.1"
{
c
.
WriteHeader
(
http
.
StatusBadRequest
)
w
.
WriteHeader
(
http
.
StatusBadRequest
)
io
.
WriteString
(
c
,
"Unexpected request"
)
io
.
WriteString
(
w
,
"Unexpected request"
)
return
return
}
}
if
req
.
Header
[
"Upgrade"
]
!=
"WebSocket"
{
if
req
.
Header
[
"Upgrade"
]
!=
"WebSocket"
{
c
.
WriteHeader
(
http
.
StatusBadRequest
)
w
.
WriteHeader
(
http
.
StatusBadRequest
)
io
.
WriteString
(
c
,
"missing Upgrade: WebSocket header"
)
io
.
WriteString
(
w
,
"missing Upgrade: WebSocket header"
)
return
return
}
}
if
req
.
Header
[
"Connection"
]
!=
"Upgrade"
{
if
req
.
Header
[
"Connection"
]
!=
"Upgrade"
{
c
.
WriteHeader
(
http
.
StatusBadRequest
)
w
.
WriteHeader
(
http
.
StatusBadRequest
)
io
.
WriteString
(
c
,
"missing Connection: Upgrade header"
)
io
.
WriteString
(
w
,
"missing Connection: Upgrade header"
)
return
return
}
}
origin
,
found
:=
req
.
Header
[
"Origin"
]
origin
,
found
:=
req
.
Header
[
"Origin"
]
if
!
found
{
if
!
found
{
c
.
WriteHeader
(
http
.
StatusBadRequest
)
w
.
WriteHeader
(
http
.
StatusBadRequest
)
io
.
WriteString
(
c
,
"missing Origin header"
)
io
.
WriteString
(
w
,
"missing Origin header"
)
return
return
}
}
rwc
,
buf
,
err
:=
c
.
Hijack
()
rwc
,
buf
,
err
:=
w
.
Hijack
()
if
err
!=
nil
{
if
err
!=
nil
{
panic
(
"Hijack failed: "
+
err
.
String
())
panic
(
"Hijack failed: "
+
err
.
String
())
return
return
...
@@ -192,7 +192,7 @@ func (f Draft75Handler) ServeHTTP(c *http.Conn, req *http.Request) {
...
@@ -192,7 +192,7 @@ func (f Draft75Handler) ServeHTTP(c *http.Conn, req *http.Request) {
defer
rwc
.
Close
()
defer
rwc
.
Close
()
var
location
string
var
location
string
if
c
.
UsingTLS
()
{
if
w
.
UsingTLS
()
{
location
=
"wss://"
+
req
.
Host
+
req
.
URL
.
RawPath
location
=
"wss://"
+
req
.
Host
+
req
.
URL
.
RawPath
}
else
{
}
else
{
location
=
"ws://"
+
req
.
Host
+
req
.
URL
.
RawPath
location
=
"ws://"
+
req
.
Host
+
req
.
URL
.
RawPath
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment