2011-03-15 12:15:41 -06:00
|
|
|
// Copyright 2011 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"go/ast"
|
|
|
|
"go/token"
|
|
|
|
)
|
|
|
|
|
|
|
|
var httpserverFix = fix{
|
|
|
|
"httpserver",
|
|
|
|
httpserver,
|
2011-03-29 19:30:59 -06:00
|
|
|
`Adapt http server methods and functions to changes
|
2011-03-15 12:15:41 -06:00
|
|
|
made to the http ResponseWriter interface.
|
|
|
|
|
|
|
|
http://codereview.appspot.com/4245064 Hijacker
|
|
|
|
http://codereview.appspot.com/4239076 Header
|
|
|
|
http://codereview.appspot.com/4239077 Flusher
|
|
|
|
http://codereview.appspot.com/4248075 RemoteAddr, UsingTLS
|
|
|
|
`,
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
register(httpserverFix)
|
|
|
|
}
|
|
|
|
|
|
|
|
func httpserver(f *ast.File) bool {
|
|
|
|
if !imports(f, "http") {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
fixed := false
|
|
|
|
for _, decl := range f.Decls {
|
|
|
|
fn, ok := decl.(*ast.FuncDecl)
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
w, req, ok := isServeHTTP(fn)
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
rewrite(fn.Body, func(n interface{}) {
|
|
|
|
// Want to replace expression sometimes,
|
|
|
|
// so record pointer to it for updating below.
|
|
|
|
ptr, ok := n.(*ast.Expr)
|
|
|
|
if ok {
|
|
|
|
n = *ptr
|
|
|
|
}
|
|
|
|
|
|
|
|
// Look for w.UsingTLS() and w.Remoteaddr().
|
|
|
|
call, ok := n.(*ast.CallExpr)
|
2011-03-16 16:59:18 -06:00
|
|
|
if !ok || (len(call.Args) != 0 && len(call.Args) != 2) {
|
2011-03-15 12:15:41 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
sel, ok := call.Fun.(*ast.SelectorExpr)
|
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if !refersTo(sel.X, w) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
switch sel.Sel.String() {
|
|
|
|
case "Hijack":
|
|
|
|
// replace w with w.(http.Hijacker)
|
|
|
|
sel.X = &ast.TypeAssertExpr{
|
|
|
|
X: sel.X,
|
|
|
|
Type: ast.NewIdent("http.Hijacker"),
|
|
|
|
}
|
|
|
|
fixed = true
|
|
|
|
case "Flush":
|
|
|
|
// replace w with w.(http.Flusher)
|
|
|
|
sel.X = &ast.TypeAssertExpr{
|
|
|
|
X: sel.X,
|
|
|
|
Type: ast.NewIdent("http.Flusher"),
|
|
|
|
}
|
|
|
|
fixed = true
|
|
|
|
case "UsingTLS":
|
|
|
|
if ptr == nil {
|
|
|
|
// can only replace expression if we have pointer to it
|
|
|
|
break
|
|
|
|
}
|
|
|
|
// replace with req.TLS != nil
|
|
|
|
*ptr = &ast.BinaryExpr{
|
|
|
|
X: &ast.SelectorExpr{
|
|
|
|
X: ast.NewIdent(req.String()),
|
|
|
|
Sel: ast.NewIdent("TLS"),
|
|
|
|
},
|
|
|
|
Op: token.NEQ,
|
|
|
|
Y: ast.NewIdent("nil"),
|
|
|
|
}
|
|
|
|
fixed = true
|
|
|
|
case "RemoteAddr":
|
|
|
|
if ptr == nil {
|
|
|
|
// can only replace expression if we have pointer to it
|
|
|
|
break
|
|
|
|
}
|
|
|
|
// replace with req.RemoteAddr
|
|
|
|
*ptr = &ast.SelectorExpr{
|
|
|
|
X: ast.NewIdent(req.String()),
|
|
|
|
Sel: ast.NewIdent("RemoteAddr"),
|
|
|
|
}
|
|
|
|
fixed = true
|
2011-03-16 16:59:18 -06:00
|
|
|
case "SetHeader":
|
|
|
|
// replace w.SetHeader with w.Header().Set
|
|
|
|
// or w.Header().Del if second argument is ""
|
|
|
|
sel.X = &ast.CallExpr{
|
|
|
|
Fun: &ast.SelectorExpr{
|
|
|
|
X: ast.NewIdent(w.String()),
|
|
|
|
Sel: ast.NewIdent("Header"),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
sel.Sel = ast.NewIdent("Set")
|
|
|
|
if len(call.Args) == 2 && isEmptyString(call.Args[1]) {
|
|
|
|
sel.Sel = ast.NewIdent("Del")
|
|
|
|
call.Args = call.Args[:1]
|
|
|
|
}
|
|
|
|
fixed = true
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return fixed
|
|
|
|
}
|
|
|
|
|
|
|
|
func isServeHTTP(fn *ast.FuncDecl) (w, req *ast.Ident, ok bool) {
|
|
|
|
for _, field := range fn.Type.Params.List {
|
|
|
|
if isPkgDot(field.Type, "http", "ResponseWriter") {
|
|
|
|
w = field.Names[0]
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if isPtrPkgDot(field.Type, "http", "Request") {
|
|
|
|
req = field.Names[0]
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ok = w != nil && req != nil
|
|
|
|
return
|
|
|
|
}
|