Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/net/http: panic when route ends with '/' #36275

Closed
AlexDvorak opened this issue Dec 24, 2019 · 5 comments
Closed

x/net/http: panic when route ends with '/' #36275

AlexDvorak opened this issue Dec 24, 2019 · 5 comments

Comments

@AlexDvorak
Copy link

What version of Go are you using (go version)?

$ go version
go version go1.13.5 linux/amd64

Does this issue reproduce with the latest release?

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/alex/.cache/go-build"
GOENV="/home/alex/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/alex/programming/random_projs/go_projects"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/lib/go-1.13"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go-1.13/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build953592629=/tmp/go-build -gno-record-gcc-switches"

What did you do?

package main

import (
  "fmt"
  "io/ioutil"
  "net/http"
)

type Page struct {
  Title string
  Body  []byte
}

func loadPage(title string) (*Page, error) {
  filename := "./static/" + title + ".html"
  body, err := ioutil.ReadFile(filename)
  if err != nil {
    return nil, err
  }
  return &Page{Title: title, Body: body}, nil
}

func loadStatic(w http.ResponseWriter, r *http.Request){
  fmt.Println("[REQ] " + r.URL.Path);
  title := r.URL.Path[len("/static/"):]
  p, _ := loadPage(title)
  fmt.Fprintf(w, "<header>%s</header>%s", p.Title, p.Body);
}

func main() {
  fmt.Println("Starting Server");
  http.HandleFunc("/static/", loadStatic);
  http.ListenAndServe(":8000", nil);
}

and then I ran

curl 'localhost:8000/static/'

which resulted in this response from the server

$ go run smth.go
2019/12/24 13:44:04 http: panic serving [::1]:58890: runtime error: invalid memory address or nil pointer dereference
goroutine 19 [running]:
net/http.(*conn).serve.func1(0xc0000aaaa0)
        /usr/lib/go-1.13/src/net/http/server.go:1767 +0x139
panic(0x6a7040, 0x92b390)
        /usr/lib/go-1.13/src/runtime/panic.go:679 +0x1b2
main.loadStatic(0x7668a0, 0xc0000e20e0, 0xc000106000)
        /home/alex/programming/random_projs/go_projects/src/IMS/smth.go:29 +0x128
net/http.HandlerFunc.ServeHTTP(0x717370, 0x7668a0, 0xc0000e20e0, 0xc000106000)
        /usr/lib/go-1.13/src/net/http/server.go:2007 +0x44
net/http.(*ServeMux).ServeHTTP(0x937980, 0x7668a0, 0xc0000e20e0, 0xc000106000)
        /usr/lib/go-1.13/src/net/http/server.go:2387 +0x1bd
net/http.serverHandler.ServeHTTP(0xc0000e2000, 0x7668a0, 0xc0000e20e0, 0xc000106000)
        /usr/lib/go-1.13/src/net/http/server.go:2802 +0xa4
net/http.(*conn).serve(0xc0000aaaa0, 0x766e20, 0xc0000bc2c0)
        /usr/lib/go-1.13/src/net/http/server.go:1890 +0x875
created by net/http.(*Server).Serve
        /usr/lib/go-1.13/src/net/http/server.go:2928 +0x384

this example works properly when the route is "/static" and returns a 404 Page not found

What did you expect to see?

I expected to see a 404 Page not found response when I ran curl 'localhost:8000/static/'

What did you see instead?

instead, /usr/lib/go-1.13/src/net/http/server.go failed on line 1767 with the above message
here are the lines surrounding it:

   7 func (c *conn) serve(ctx context.Context) {
   6   c.remoteAddr = c.rwc.RemoteAddr().String()
   5   ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr())
   4   defer func() {
   3     if err := recover(); err != nil && err != ErrAbortHandler {
   2       const size = 64 << 10
   1       buf := make([]byte, size)
1767       buf = buf[:runtime.Stack(buf, false)]
   1       c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf)
   2     }
   3     if !c.hijacked() {
   4       c.close()
   5       c.setState(c.rwc, StateClosed)
   6     }
@gopherbot gopherbot added this to the Unreleased milestone Dec 24, 2019
@AlexDvorak
Copy link
Author

AlexDvorak commented Dec 24, 2019

Here's a play.golang.org link, though it fails for another reason
https://play.golang.org/p/p5plUyS-pYx

Starting Server
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [sync.Cond.Wait]:
runtime.goparkunlock(...)
	/usr/local/go/src/runtime/proc.go:310
sync.runtime_notifyListWait(0x8407f0, 0x0)
	/usr/local/go/src/runtime/sema.go:510 +0x120
sync.(*Cond).Wait(0x8407e8, 0x8407e0)
	/usr/local/go/src/sync/cond.go:56 +0xe0
syscall.(*queue).waitRead(0x8407e0, 0x1, 0x0, 0x0, 0x8001e0, 0x3a348c, 0x864c84, 0x0)
	/usr/local/go/src/syscall/net_nacl.go:292 +0xe0
syscall.(*msgq).read(0x8407e0, 0x327960, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
	/usr/local/go/src/syscall/net_nacl.go:409 +0xc0
syscall.(*netFile).accept(0x8321c0, 0x0, 0x8321c0, 0x0, 0x0, 0x4fac, 0x70, 0x334c60)
	/usr/local/go/src/syscall/net_nacl.go:571 +0x40
syscall.Accept(0x3, 0x0, 0xff800000, 0x7ff, 0x56400, 0x4fac, 0xc2a544b4, 0x8505a8)
	/usr/local/go/src/syscall/net_nacl.go:799 +0xa0
internal/poll.accept(0x3, 0x4f01, 0x1, 0x83ea40, 0x2, 0x2, 0x8, 0x0, 0x2, 0x0)
	/usr/local/go/src/internal/poll/sys_cloexec.go:24 +0x40
internal/poll.(*FD).Accept(0x8505a0, 0x4fac, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
	/usr/local/go/src/internal/poll/fd_unix.go:377 +0x140
net.(*netFD).accept(0x8505a0, 0x864e18, 0x57ea60, 0x4fac, 0xfefc0008, 0x0)
	/usr/local/go/src/net/fd_unix.go:238 +0x40
net.(*TCPListener).accept(0x83e9e0, 0x4fac, 0x20, 0x345f60, 0x83c101, 0x0)
	/usr/local/go/src/net/tcpsock_posix.go:139 +0x40
net.(*TCPListener).Accept(0x83e9e0, 0x0, 0x83ea80, 0x4fac, 0x323000, 0x574358)
	/usr/local/go/src/net/tcpsock.go:261 +0x40
net/http.(*Server).Serve(0x852480, 0x3ebfd0, 0x83e9e0, 0x5, 0x0, 0x0)
	/usr/local/go/src/net/http/server.go:2896 +0x2e0
net/http.(*Server).ListenAndServe(0x852480, 0x35eced, 0x852480, 0x3e9ef0)
	/usr/local/go/src/net/http/server.go:2825 +0xe0
net/http.ListenAndServe(...)
	/usr/local/go/src/net/http/server.go:3081
main.main()
	/tmp/sandbox044273064/prog.go:33 +0x140

Program exited: status 2.

@seankhliao
Copy link
Member

r.URL.Path[len("/static/"):]: your slice starts after the end, ie, out of bounds

@ghost
Copy link

ghost commented Dec 25, 2019

You've got a nil pointer, p. Always check the errors.

p, _ := loadPage(title)
fmt.Fprintf(w, "<header>%s</header>%s", p.Title, p.Body);

@AlexDvorak
Copy link
Author

AlexDvorak commented Dec 25, 2019

ah sorry about that, thank you all

@DGKSK8LIFE
Copy link

told ya it wasn't a bug @AlexDvorak

@golang golang locked and limited conversation to collaborators Jan 2, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants