mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-03 20:27:35 +03:00
GOPATH is a list of paths, similar to PATH. If someone does have a list set, the tests will try to use the full list as a path prefix to load the certificates, which won't work. But even handling GOPATH as a list does not solve the issue of what certificate or error_codes.go file to load, since the code might not be under the first one it finds. Instead, use the runtime functionality to get the filename of the path of the project at compilation time and perform the lookups relative to that, which guarantees that we're loading the files from the path of the code that is running.
160 lines
3.9 KiB
Go
160 lines
3.9 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"log"
|
|
"mime/multipart"
|
|
"net/http"
|
|
"path"
|
|
"runtime"
|
|
"strings"
|
|
"sync"
|
|
|
|
_ "net/http/pprof"
|
|
|
|
"github.com/lucas-clemente/quic-go/h2quic"
|
|
"github.com/lucas-clemente/quic-go/utils"
|
|
)
|
|
|
|
type binds []string
|
|
|
|
func (b binds) String() string {
|
|
return strings.Join(b, ",")
|
|
}
|
|
|
|
func (b *binds) Set(v string) error {
|
|
*b = strings.Split(v, ",")
|
|
return nil
|
|
}
|
|
|
|
// Size is needed by the /demo/upload handler to determine the size of the uploaded file
|
|
type Size interface {
|
|
Size() int64
|
|
}
|
|
|
|
func init() {
|
|
http.HandleFunc("/demo/tile", func(w http.ResponseWriter, r *http.Request) {
|
|
// Small 40x40 png
|
|
w.Write([]byte{
|
|
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
|
|
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28,
|
|
0x01, 0x03, 0x00, 0x00, 0x00, 0xb6, 0x30, 0x2a, 0x2e, 0x00, 0x00, 0x00,
|
|
0x03, 0x50, 0x4c, 0x54, 0x45, 0x5a, 0xc3, 0x5a, 0xad, 0x38, 0xaa, 0xdb,
|
|
0x00, 0x00, 0x00, 0x0b, 0x49, 0x44, 0x41, 0x54, 0x78, 0x01, 0x63, 0x18,
|
|
0x61, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x01, 0xe2, 0xb8, 0x75, 0x22, 0x00,
|
|
0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
|
|
})
|
|
})
|
|
|
|
http.HandleFunc("/demo/tiles", func(w http.ResponseWriter, r *http.Request) {
|
|
io.WriteString(w, "<html><head><style>img{width:40px;height:40px;}</style></head><body>")
|
|
for i := 0; i < 200; i++ {
|
|
fmt.Fprintf(w, `<img src="/demo/tile?cachebust=%d">`, i)
|
|
}
|
|
io.WriteString(w, "</body></html>")
|
|
})
|
|
|
|
http.HandleFunc("/demo/echo", func(w http.ResponseWriter, r *http.Request) {
|
|
body, err := ioutil.ReadAll(r.Body)
|
|
if err != nil {
|
|
fmt.Printf("error reading body while handling /echo: %s\n", err.Error())
|
|
}
|
|
w.Write(body)
|
|
})
|
|
|
|
// accept file uploads and return the MD5 of the uploaded file
|
|
// maximum accepted file size is 1 GB
|
|
http.HandleFunc("/demo/upload", func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == http.MethodPost {
|
|
var err error
|
|
err = r.ParseMultipartForm(1 << 30) // 1 GB
|
|
if err == nil {
|
|
var file multipart.File
|
|
file, _, err = r.FormFile("uploadfile")
|
|
if err == nil {
|
|
var size int64
|
|
if sizeInterface, ok := file.(Size); ok {
|
|
size = sizeInterface.Size()
|
|
b := make([]byte, size)
|
|
file.Read(b)
|
|
md5 := md5.Sum(b)
|
|
fmt.Fprintf(w, "%x", md5)
|
|
return
|
|
}
|
|
err = errors.New("Couldn't get uploaded file size.")
|
|
}
|
|
}
|
|
if err != nil {
|
|
utils.Infof("Error receiving upload: %#v", err)
|
|
}
|
|
}
|
|
io.WriteString(w, `<html><body><form action="/demo/upload" method="post" enctype="multipart/form-data">
|
|
<input type="file" name="uploadfile"><br>
|
|
<input type="submit">
|
|
</form></body></html>`)
|
|
})
|
|
}
|
|
|
|
func getBuildDir() string {
|
|
_, filename, _, ok := runtime.Caller(0)
|
|
if !ok {
|
|
panic("Failed to get current frame")
|
|
}
|
|
|
|
return path.Dir(filename)
|
|
}
|
|
|
|
func main() {
|
|
// defer profile.Start().Stop()
|
|
go func() {
|
|
log.Println(http.ListenAndServe("localhost:6060", nil))
|
|
}()
|
|
// runtime.SetBlockProfileRate(1)
|
|
|
|
verbose := flag.Bool("v", false, "verbose")
|
|
bs := binds{}
|
|
flag.Var(&bs, "bind", "bind to")
|
|
certPath := flag.String("certpath", getBuildDir(), "certificate directory")
|
|
www := flag.String("www", "/var/www", "www data")
|
|
tcp := flag.Bool("tcp", false, "also listen on TCP")
|
|
flag.Parse()
|
|
|
|
if *verbose {
|
|
utils.SetLogLevel(utils.LogLevelDebug)
|
|
} else {
|
|
utils.SetLogLevel(utils.LogLevelInfo)
|
|
}
|
|
|
|
certFile := *certPath + "/fullchain.pem"
|
|
keyFile := *certPath + "/privkey.pem"
|
|
|
|
http.Handle("/", http.FileServer(http.Dir(*www)))
|
|
|
|
if len(bs) == 0 {
|
|
bs = binds{"localhost:6121"}
|
|
}
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(len(bs))
|
|
for _, b := range bs {
|
|
bCap := b
|
|
go func() {
|
|
var err error
|
|
if *tcp {
|
|
err = h2quic.ListenAndServe(bCap, certFile, keyFile, nil)
|
|
} else {
|
|
err = h2quic.ListenAndServeQUIC(bCap, certFile, keyFile, nil)
|
|
}
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
wg.Done()
|
|
}()
|
|
}
|
|
wg.Wait()
|
|
}
|