Merge branch 'develop'
This commit is contained in:
commit
5ee355ed77
30 changed files with 474 additions and 72 deletions
15
Godeps/Godeps.json
generated
15
Godeps/Godeps.json
generated
|
@ -4,27 +4,27 @@
|
||||||
"Deps": [
|
"Deps": [
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/chihaya/bencode",
|
"ImportPath": "github.com/chihaya/bencode",
|
||||||
"Rev": "1df51811f3440202aa39df93596654319ea5ff57"
|
"Rev": "e60878f635e1a61315c413492e133dd39769b1d1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/golang/glog",
|
"ImportPath": "github.com/golang/glog",
|
||||||
"Rev": "d1c4472bf2efd3826f2b5bdcc02d8416798d678c"
|
"Rev": "44145f04b68cf362d9c4df2182967c2275eaefed"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/julienschmidt/httprouter",
|
"ImportPath": "github.com/julienschmidt/httprouter",
|
||||||
"Rev": "46807412fe50aaceb73bb57061c2230fd26a1640"
|
"Rev": "00ce1c6a267162792c367acc43b1681a884e1872"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/pushrax/faststats",
|
"ImportPath": "github.com/pushrax/faststats",
|
||||||
"Rev": "4c069408629f728eb3fe856f0966508492393a90"
|
"Rev": "0fc2c5e41a187240ffaa09320eea7df9f8071388"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/pushrax/flatjson",
|
"ImportPath": "github.com/pushrax/flatjson",
|
||||||
"Rev": "cce9ff039f0bec46d67ed9ab4ce846b8355c94bb"
|
"Rev": "86044f1c998d49053e13293029414ddb63f3a422"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/stretchr/graceful",
|
"ImportPath": "github.com/stretchr/graceful",
|
||||||
"Rev": "0b67b304c1354aa3d1b2c4353a630ee0f589c34f"
|
"Rev": "8e780ba3fe3d3e7ab15fc52e3d60a996587181dc"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/stretchr/pat/stop",
|
"ImportPath": "github.com/stretchr/pat/stop",
|
||||||
|
@ -32,8 +32,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/net/netutil",
|
"ImportPath": "golang.org/x/net/netutil",
|
||||||
"Comment": "null-204",
|
"Rev": "c84eff7014eba178f68bd4c05b86780efe0fbf35"
|
||||||
"Rev": "8fd8d3a0313cb59e495106ac76df5da29381fa24"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
2
Godeps/_workspace/src/github.com/chihaya/bencode/LICENSE
generated
vendored
2
Godeps/_workspace/src/github.com/chihaya/bencode/LICENSE
generated
vendored
|
@ -1,6 +1,6 @@
|
||||||
bencode is released under a BSD 2-Clause license, reproduced below.
|
bencode is released under a BSD 2-Clause license, reproduced below.
|
||||||
|
|
||||||
Copyright (c) 2014, The Chihaya Authors
|
Copyright (c) 2015, The Chihaya Authors
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
|
2
Godeps/_workspace/src/github.com/chihaya/bencode/bencode.go
generated
vendored
2
Godeps/_workspace/src/github.com/chihaya/bencode/bencode.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The Chihaya Authors. All rights reserved.
|
// Copyright 2015 The Chihaya Authors. All rights reserved.
|
||||||
// Use of this source code is governed by the BSD 2-Clause license,
|
// Use of this source code is governed by the BSD 2-Clause license,
|
||||||
// which can be found in the LICENSE file.
|
// which can be found in the LICENSE file.
|
||||||
|
|
||||||
|
|
2
Godeps/_workspace/src/github.com/chihaya/bencode/decoder.go
generated
vendored
2
Godeps/_workspace/src/github.com/chihaya/bencode/decoder.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The Chihaya Authors. All rights reserved.
|
// Copyright 2015 The Chihaya Authors. All rights reserved.
|
||||||
// Use of this source code is governed by the BSD 2-Clause license,
|
// Use of this source code is governed by the BSD 2-Clause license,
|
||||||
// which can be found in the LICENSE file.
|
// which can be found in the LICENSE file.
|
||||||
|
|
||||||
|
|
2
Godeps/_workspace/src/github.com/chihaya/bencode/decoder_test.go
generated
vendored
2
Godeps/_workspace/src/github.com/chihaya/bencode/decoder_test.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The Chihaya Authors. All rights reserved.
|
// Copyright 2015 The Chihaya Authors. All rights reserved.
|
||||||
// Use of this source code is governed by the BSD 2-Clause license,
|
// Use of this source code is governed by the BSD 2-Clause license,
|
||||||
// which can be found in the LICENSE file.
|
// which can be found in the LICENSE file.
|
||||||
|
|
||||||
|
|
2
Godeps/_workspace/src/github.com/chihaya/bencode/encoder.go
generated
vendored
2
Godeps/_workspace/src/github.com/chihaya/bencode/encoder.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The Chihaya Authors. All rights reserved.
|
// Copyright 2015 The Chihaya Authors. All rights reserved.
|
||||||
// Use of this source code is governed by the BSD 2-Clause license,
|
// Use of this source code is governed by the BSD 2-Clause license,
|
||||||
// which can be found in the LICENSE file.
|
// which can be found in the LICENSE file.
|
||||||
|
|
||||||
|
|
2
Godeps/_workspace/src/github.com/chihaya/bencode/encoder_test.go
generated
vendored
2
Godeps/_workspace/src/github.com/chihaya/bencode/encoder_test.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The Chihaya Authors. All rights reserved.
|
// Copyright 2015 The Chihaya Authors. All rights reserved.
|
||||||
// Use of this source code is governed by the BSD 2-Clause license,
|
// Use of this source code is governed by the BSD 2-Clause license,
|
||||||
// which can be found in the LICENSE file.
|
// which can be found in the LICENSE file.
|
||||||
|
|
||||||
|
|
193
Godeps/_workspace/src/github.com/golang/glog/glog.go
generated
vendored
193
Godeps/_workspace/src/github.com/golang/glog/glog.go
generated
vendored
|
@ -77,6 +77,7 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
stdLog "log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -93,6 +94,9 @@ import (
|
||||||
// the corresponding constants in C++.
|
// the corresponding constants in C++.
|
||||||
type severity int32 // sync/atomic int32
|
type severity int32 // sync/atomic int32
|
||||||
|
|
||||||
|
// These constants identify the log levels in order of increasing severity.
|
||||||
|
// A message written to a high-severity log file is also written to each
|
||||||
|
// lower-severity log file.
|
||||||
const (
|
const (
|
||||||
infoLog severity = iota
|
infoLog severity = iota
|
||||||
warningLog
|
warningLog
|
||||||
|
@ -311,7 +315,7 @@ func (m *moduleSpec) Set(value string) error {
|
||||||
// isLiteral reports whether the pattern is a literal string, that is, has no metacharacters
|
// isLiteral reports whether the pattern is a literal string, that is, has no metacharacters
|
||||||
// that require filepath.Match to be called to match the pattern.
|
// that require filepath.Match to be called to match the pattern.
|
||||||
func isLiteral(pattern string) bool {
|
func isLiteral(pattern string) bool {
|
||||||
return !strings.ContainsAny(pattern, `*?[]\`)
|
return !strings.ContainsAny(pattern, `\*?[]`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// traceLocation represents the setting of the -log_backtrace_at flag.
|
// traceLocation represents the setting of the -log_backtrace_at flag.
|
||||||
|
@ -466,7 +470,7 @@ func (l *loggingT) setVState(verbosity Level, filter []modulePat, setFilter bool
|
||||||
// Turn verbosity off so V will not fire while we are in transition.
|
// Turn verbosity off so V will not fire while we are in transition.
|
||||||
logging.verbosity.set(0)
|
logging.verbosity.set(0)
|
||||||
// Ditto for filter length.
|
// Ditto for filter length.
|
||||||
logging.filterLength = 0
|
atomic.StoreInt32(&logging.filterLength, 0)
|
||||||
|
|
||||||
// Set the new filters and wipe the pc->Level map if the filter has changed.
|
// Set the new filters and wipe the pc->Level map if the filter has changed.
|
||||||
if setFilter {
|
if setFilter {
|
||||||
|
@ -513,7 +517,8 @@ var timeNow = time.Now // Stubbed out for testing.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
header formats a log header as defined by the C++ implementation.
|
header formats a log header as defined by the C++ implementation.
|
||||||
It returns a buffer containing the formatted header.
|
It returns a buffer containing the formatted header and the user's file and line number.
|
||||||
|
The depth specifies how many stack frames above lives the source line to be identified in the log message.
|
||||||
|
|
||||||
Log lines have this form:
|
Log lines have this form:
|
||||||
Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
|
Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
|
||||||
|
@ -527,10 +532,8 @@ where the fields are defined as follows:
|
||||||
line The line number
|
line The line number
|
||||||
msg The user-supplied message
|
msg The user-supplied message
|
||||||
*/
|
*/
|
||||||
func (l *loggingT) header(s severity) *buffer {
|
func (l *loggingT) header(s severity, depth int) (*buffer, string, int) {
|
||||||
// Lmmdd hh:mm:ss.uuuuuu threadid file:line]
|
_, file, line, ok := runtime.Caller(3 + depth)
|
||||||
now := timeNow()
|
|
||||||
_, file, line, ok := runtime.Caller(3) // It's always the same number of frames to the user's call.
|
|
||||||
if !ok {
|
if !ok {
|
||||||
file = "???"
|
file = "???"
|
||||||
line = 1
|
line = 1
|
||||||
|
@ -540,6 +543,12 @@ func (l *loggingT) header(s severity) *buffer {
|
||||||
file = file[slash+1:]
|
file = file[slash+1:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return l.formatHeader(s, file, line), file, line
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatHeader formats a log header using the provided file name and line number.
|
||||||
|
func (l *loggingT) formatHeader(s severity, file string, line int) *buffer {
|
||||||
|
now := timeNow()
|
||||||
if line < 0 {
|
if line < 0 {
|
||||||
line = 0 // not a real line number, but acceptable to someDigits
|
line = 0 // not a real line number, but acceptable to someDigits
|
||||||
}
|
}
|
||||||
|
@ -552,6 +561,7 @@ func (l *loggingT) header(s severity) *buffer {
|
||||||
// It's worth about 3X. Fprintf is hard.
|
// It's worth about 3X. Fprintf is hard.
|
||||||
_, month, day := now.Date()
|
_, month, day := now.Date()
|
||||||
hour, minute, second := now.Clock()
|
hour, minute, second := now.Clock()
|
||||||
|
// Lmmdd hh:mm:ss.uuuuuu threadid file:line]
|
||||||
buf.tmp[0] = severityChar[s]
|
buf.tmp[0] = severityChar[s]
|
||||||
buf.twoDigits(1, int(month))
|
buf.twoDigits(1, int(month))
|
||||||
buf.twoDigits(3, day)
|
buf.twoDigits(3, day)
|
||||||
|
@ -562,11 +572,11 @@ func (l *loggingT) header(s severity) *buffer {
|
||||||
buf.tmp[11] = ':'
|
buf.tmp[11] = ':'
|
||||||
buf.twoDigits(12, second)
|
buf.twoDigits(12, second)
|
||||||
buf.tmp[14] = '.'
|
buf.tmp[14] = '.'
|
||||||
buf.nDigits(6, 15, now.Nanosecond()/1000)
|
buf.nDigits(6, 15, now.Nanosecond()/1000, '0')
|
||||||
buf.tmp[21] = ' '
|
buf.tmp[21] = ' '
|
||||||
buf.nDigits(5, 22, pid) // TODO: should be TID
|
buf.nDigits(7, 22, pid, ' ') // TODO: should be TID
|
||||||
buf.tmp[27] = ' '
|
buf.tmp[29] = ' '
|
||||||
buf.Write(buf.tmp[:28])
|
buf.Write(buf.tmp[:30])
|
||||||
buf.WriteString(file)
|
buf.WriteString(file)
|
||||||
buf.tmp[0] = ':'
|
buf.tmp[0] = ':'
|
||||||
n := buf.someDigits(1, line)
|
n := buf.someDigits(1, line)
|
||||||
|
@ -587,12 +597,18 @@ func (buf *buffer) twoDigits(i, d int) {
|
||||||
buf.tmp[i] = digits[d%10]
|
buf.tmp[i] = digits[d%10]
|
||||||
}
|
}
|
||||||
|
|
||||||
// nDigits formats a zero-prefixed n-digit integer at buf.tmp[i].
|
// nDigits formats an n-digit integer at buf.tmp[i],
|
||||||
func (buf *buffer) nDigits(n, i, d int) {
|
// padding with pad on the left.
|
||||||
for j := n - 1; j >= 0; j-- {
|
// It assumes d >= 0.
|
||||||
|
func (buf *buffer) nDigits(n, i, d int, pad byte) {
|
||||||
|
j := n - 1
|
||||||
|
for ; j >= 0 && d > 0; j-- {
|
||||||
buf.tmp[i+j] = digits[d%10]
|
buf.tmp[i+j] = digits[d%10]
|
||||||
d /= 10
|
d /= 10
|
||||||
}
|
}
|
||||||
|
for ; j >= 0; j-- {
|
||||||
|
buf.tmp[i+j] = pad
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// someDigits formats a zero-prefixed variable-width integer at buf.tmp[i].
|
// someDigits formats a zero-prefixed variable-width integer at buf.tmp[i].
|
||||||
|
@ -612,35 +628,50 @@ func (buf *buffer) someDigits(i, d int) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *loggingT) println(s severity, args ...interface{}) {
|
func (l *loggingT) println(s severity, args ...interface{}) {
|
||||||
buf := l.header(s)
|
buf, file, line := l.header(s, 0)
|
||||||
fmt.Fprintln(buf, args...)
|
fmt.Fprintln(buf, args...)
|
||||||
l.output(s, buf)
|
l.output(s, buf, file, line, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *loggingT) print(s severity, args ...interface{}) {
|
func (l *loggingT) print(s severity, args ...interface{}) {
|
||||||
buf := l.header(s)
|
l.printDepth(s, 1, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *loggingT) printDepth(s severity, depth int, args ...interface{}) {
|
||||||
|
buf, file, line := l.header(s, depth)
|
||||||
fmt.Fprint(buf, args...)
|
fmt.Fprint(buf, args...)
|
||||||
if buf.Bytes()[buf.Len()-1] != '\n' {
|
if buf.Bytes()[buf.Len()-1] != '\n' {
|
||||||
buf.WriteByte('\n')
|
buf.WriteByte('\n')
|
||||||
}
|
}
|
||||||
l.output(s, buf)
|
l.output(s, buf, file, line, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *loggingT) printf(s severity, format string, args ...interface{}) {
|
func (l *loggingT) printf(s severity, format string, args ...interface{}) {
|
||||||
buf := l.header(s)
|
buf, file, line := l.header(s, 0)
|
||||||
fmt.Fprintf(buf, format, args...)
|
fmt.Fprintf(buf, format, args...)
|
||||||
if buf.Bytes()[buf.Len()-1] != '\n' {
|
if buf.Bytes()[buf.Len()-1] != '\n' {
|
||||||
buf.WriteByte('\n')
|
buf.WriteByte('\n')
|
||||||
}
|
}
|
||||||
l.output(s, buf)
|
l.output(s, buf, file, line, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// printWithFileLine behaves like print but uses the provided file and line number. If
|
||||||
|
// alsoLogToStderr is true, the log message always appears on standard error; it
|
||||||
|
// will also appear in the log file unless --logtostderr is set.
|
||||||
|
func (l *loggingT) printWithFileLine(s severity, file string, line int, alsoToStderr bool, args ...interface{}) {
|
||||||
|
buf := l.formatHeader(s, file, line)
|
||||||
|
fmt.Fprint(buf, args...)
|
||||||
|
if buf.Bytes()[buf.Len()-1] != '\n' {
|
||||||
|
buf.WriteByte('\n')
|
||||||
|
}
|
||||||
|
l.output(s, buf, file, line, alsoToStderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// output writes the data to the log files and releases the buffer.
|
// output writes the data to the log files and releases the buffer.
|
||||||
func (l *loggingT) output(s severity, buf *buffer) {
|
func (l *loggingT) output(s severity, buf *buffer, file string, line int, alsoToStderr bool) {
|
||||||
l.mu.Lock()
|
l.mu.Lock()
|
||||||
if l.traceLocation.isSet() {
|
if l.traceLocation.isSet() {
|
||||||
_, file, line, ok := runtime.Caller(3) // It's always the same number of frames to the user's call (same as header).
|
if l.traceLocation.match(file, line) {
|
||||||
if ok && l.traceLocation.match(file, line) {
|
|
||||||
buf.Write(stacks(false))
|
buf.Write(stacks(false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -648,7 +679,7 @@ func (l *loggingT) output(s severity, buf *buffer) {
|
||||||
if l.toStderr {
|
if l.toStderr {
|
||||||
os.Stderr.Write(data)
|
os.Stderr.Write(data)
|
||||||
} else {
|
} else {
|
||||||
if l.alsoToStderr || s >= l.stderrThreshold.get() {
|
if alsoToStderr || l.alsoToStderr || s >= l.stderrThreshold.get() {
|
||||||
os.Stderr.Write(data)
|
os.Stderr.Write(data)
|
||||||
}
|
}
|
||||||
if l.file[s] == nil {
|
if l.file[s] == nil {
|
||||||
|
@ -672,7 +703,16 @@ func (l *loggingT) output(s severity, buf *buffer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if s == fatalLog {
|
if s == fatalLog {
|
||||||
// Make sure we see the trace for the current goroutine on standard error.
|
// If we got here via Exit rather than Fatal, print no stacks.
|
||||||
|
if atomic.LoadUint32(&fatalNoStacks) > 0 {
|
||||||
|
l.mu.Unlock()
|
||||||
|
timeoutFlush(10 * time.Second)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
// Dump all goroutine stacks before exiting.
|
||||||
|
// First, make sure we see the trace for the current goroutine on standard error.
|
||||||
|
// If -logtostderr has been specified, the loop below will do that anyway
|
||||||
|
// as the first stack in the full dump.
|
||||||
if !l.toStderr {
|
if !l.toStderr {
|
||||||
os.Stderr.Write(stacks(false))
|
os.Stderr.Write(stacks(false))
|
||||||
}
|
}
|
||||||
|
@ -861,6 +901,54 @@ func (l *loggingT) flushAll() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CopyStandardLogTo arranges for messages written to the Go "log" package's
|
||||||
|
// default logs to also appear in the Google logs for the named and lower
|
||||||
|
// severities. Subsequent changes to the standard log's default output location
|
||||||
|
// or format may break this behavior.
|
||||||
|
//
|
||||||
|
// Valid names are "INFO", "WARNING", "ERROR", and "FATAL". If the name is not
|
||||||
|
// recognized, CopyStandardLogTo panics.
|
||||||
|
func CopyStandardLogTo(name string) {
|
||||||
|
sev, ok := severityByName(name)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("log.CopyStandardLogTo(%q): unrecognized severity name", name))
|
||||||
|
}
|
||||||
|
// Set a log format that captures the user's file and line:
|
||||||
|
// d.go:23: message
|
||||||
|
stdLog.SetFlags(stdLog.Lshortfile)
|
||||||
|
stdLog.SetOutput(logBridge(sev))
|
||||||
|
}
|
||||||
|
|
||||||
|
// logBridge provides the Write method that enables CopyStandardLogTo to connect
|
||||||
|
// Go's standard logs to the logs provided by this package.
|
||||||
|
type logBridge severity
|
||||||
|
|
||||||
|
// Write parses the standard logging line and passes its components to the
|
||||||
|
// logger for severity(lb).
|
||||||
|
func (lb logBridge) Write(b []byte) (n int, err error) {
|
||||||
|
var (
|
||||||
|
file = "???"
|
||||||
|
line = 1
|
||||||
|
text string
|
||||||
|
)
|
||||||
|
// Split "d.go:23: message" into "d.go", "23", and "message".
|
||||||
|
if parts := bytes.SplitN(b, []byte{':'}, 3); len(parts) != 3 || len(parts[0]) < 1 || len(parts[2]) < 1 {
|
||||||
|
text = fmt.Sprintf("bad log format: %s", b)
|
||||||
|
} else {
|
||||||
|
file = string(parts[0])
|
||||||
|
text = string(parts[2][1:]) // skip leading space
|
||||||
|
line, err = strconv.Atoi(string(parts[1]))
|
||||||
|
if err != nil {
|
||||||
|
text = fmt.Sprintf("bad line number: %s", b)
|
||||||
|
line = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// printWithFileLine with alsoToStderr=true, so standard log messages
|
||||||
|
// always appear on standard error.
|
||||||
|
logging.printWithFileLine(severity(lb), file, line, true, text)
|
||||||
|
return len(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
// setV computes and remembers the V level for a given PC
|
// setV computes and remembers the V level for a given PC
|
||||||
// when vmodule is enabled.
|
// when vmodule is enabled.
|
||||||
// File pattern matching takes the basename of the file, stripped
|
// File pattern matching takes the basename of the file, stripped
|
||||||
|
@ -964,6 +1052,12 @@ func Info(args ...interface{}) {
|
||||||
logging.print(infoLog, args...)
|
logging.print(infoLog, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InfoDepth acts as Info but uses depth to determine which call frame to log.
|
||||||
|
// InfoDepth(0, "msg") is the same as Info("msg").
|
||||||
|
func InfoDepth(depth int, args ...interface{}) {
|
||||||
|
logging.printDepth(infoLog, depth, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Infoln logs to the INFO log.
|
// Infoln logs to the INFO log.
|
||||||
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
|
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
|
||||||
func Infoln(args ...interface{}) {
|
func Infoln(args ...interface{}) {
|
||||||
|
@ -982,6 +1076,12 @@ func Warning(args ...interface{}) {
|
||||||
logging.print(warningLog, args...)
|
logging.print(warningLog, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WarningDepth acts as Warning but uses depth to determine which call frame to log.
|
||||||
|
// WarningDepth(0, "msg") is the same as Warning("msg").
|
||||||
|
func WarningDepth(depth int, args ...interface{}) {
|
||||||
|
logging.printDepth(warningLog, depth, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Warningln logs to the WARNING and INFO logs.
|
// Warningln logs to the WARNING and INFO logs.
|
||||||
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
|
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
|
||||||
func Warningln(args ...interface{}) {
|
func Warningln(args ...interface{}) {
|
||||||
|
@ -1000,6 +1100,12 @@ func Error(args ...interface{}) {
|
||||||
logging.print(errorLog, args...)
|
logging.print(errorLog, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrorDepth acts as Error but uses depth to determine which call frame to log.
|
||||||
|
// ErrorDepth(0, "msg") is the same as Error("msg").
|
||||||
|
func ErrorDepth(depth int, args ...interface{}) {
|
||||||
|
logging.printDepth(errorLog, depth, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Errorln logs to the ERROR, WARNING, and INFO logs.
|
// Errorln logs to the ERROR, WARNING, and INFO logs.
|
||||||
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
|
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
|
||||||
func Errorln(args ...interface{}) {
|
func Errorln(args ...interface{}) {
|
||||||
|
@ -1019,6 +1125,12 @@ func Fatal(args ...interface{}) {
|
||||||
logging.print(fatalLog, args...)
|
logging.print(fatalLog, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FatalDepth acts as Fatal but uses depth to determine which call frame to log.
|
||||||
|
// FatalDepth(0, "msg") is the same as Fatal("msg").
|
||||||
|
func FatalDepth(depth int, args ...interface{}) {
|
||||||
|
logging.printDepth(fatalLog, depth, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Fatalln logs to the FATAL, ERROR, WARNING, and INFO logs,
|
// Fatalln logs to the FATAL, ERROR, WARNING, and INFO logs,
|
||||||
// including a stack trace of all running goroutines, then calls os.Exit(255).
|
// including a stack trace of all running goroutines, then calls os.Exit(255).
|
||||||
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
|
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
|
||||||
|
@ -1032,3 +1144,34 @@ func Fatalln(args ...interface{}) {
|
||||||
func Fatalf(format string, args ...interface{}) {
|
func Fatalf(format string, args ...interface{}) {
|
||||||
logging.printf(fatalLog, format, args...)
|
logging.printf(fatalLog, format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fatalNoStacks is non-zero if we are to exit without dumping goroutine stacks.
|
||||||
|
// It allows Exit and relatives to use the Fatal logs.
|
||||||
|
var fatalNoStacks uint32
|
||||||
|
|
||||||
|
// Exit logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
|
||||||
|
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
|
||||||
|
func Exit(args ...interface{}) {
|
||||||
|
atomic.StoreUint32(&fatalNoStacks, 1)
|
||||||
|
logging.print(fatalLog, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExitDepth acts as Exit but uses depth to determine which call frame to log.
|
||||||
|
// ExitDepth(0, "msg") is the same as Exit("msg").
|
||||||
|
func ExitDepth(depth int, args ...interface{}) {
|
||||||
|
atomic.StoreUint32(&fatalNoStacks, 1)
|
||||||
|
logging.printDepth(fatalLog, depth, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exitln logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
|
||||||
|
func Exitln(args ...interface{}) {
|
||||||
|
atomic.StoreUint32(&fatalNoStacks, 1)
|
||||||
|
logging.println(fatalLog, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exitf logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
|
||||||
|
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
|
||||||
|
func Exitf(format string, args ...interface{}) {
|
||||||
|
atomic.StoreUint32(&fatalNoStacks, 1)
|
||||||
|
logging.printf(fatalLog, format, args...)
|
||||||
|
}
|
||||||
|
|
92
Godeps/_workspace/src/github.com/golang/glog/glog_test.go
generated
vendored
92
Godeps/_workspace/src/github.com/golang/glog/glog_test.go
generated
vendored
|
@ -19,8 +19,10 @@ package glog
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
stdLog "log"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -96,20 +98,99 @@ func TestInfo(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInfoDepth(t *testing.T) {
|
||||||
|
setFlags()
|
||||||
|
defer logging.swap(logging.newBuffers())
|
||||||
|
|
||||||
|
f := func() { InfoDepth(1, "depth-test1") }
|
||||||
|
|
||||||
|
// The next three lines must stay together
|
||||||
|
_, _, wantLine, _ := runtime.Caller(0)
|
||||||
|
InfoDepth(0, "depth-test0")
|
||||||
|
f()
|
||||||
|
|
||||||
|
msgs := strings.Split(strings.TrimSuffix(contents(infoLog), "\n"), "\n")
|
||||||
|
if len(msgs) != 2 {
|
||||||
|
t.Fatalf("Got %d lines, expected 2", len(msgs))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, m := range msgs {
|
||||||
|
if !strings.HasPrefix(m, "I") {
|
||||||
|
t.Errorf("InfoDepth[%d] has wrong character: %q", i, m)
|
||||||
|
}
|
||||||
|
w := fmt.Sprintf("depth-test%d", i)
|
||||||
|
if !strings.Contains(m, w) {
|
||||||
|
t.Errorf("InfoDepth[%d] missing %q: %q", i, w, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// pull out the line number (between : and ])
|
||||||
|
msg := m[strings.LastIndex(m, ":")+1:]
|
||||||
|
x := strings.Index(msg, "]")
|
||||||
|
if x < 0 {
|
||||||
|
t.Errorf("InfoDepth[%d]: missing ']': %q", i, m)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
line, err := strconv.Atoi(msg[:x])
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("InfoDepth[%d]: bad line number: %q", i, m)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
wantLine++
|
||||||
|
if wantLine != line {
|
||||||
|
t.Errorf("InfoDepth[%d]: got line %d, want %d", i, line, wantLine)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
CopyStandardLogTo("INFO")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that CopyStandardLogTo panics on bad input.
|
||||||
|
func TestCopyStandardLogToPanic(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
if s, ok := recover().(string); !ok || !strings.Contains(s, "LOG") {
|
||||||
|
t.Errorf(`CopyStandardLogTo("LOG") should have panicked: %v`, s)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
CopyStandardLogTo("LOG")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that using the standard log package logs to INFO.
|
||||||
|
func TestStandardLog(t *testing.T) {
|
||||||
|
setFlags()
|
||||||
|
defer logging.swap(logging.newBuffers())
|
||||||
|
stdLog.Print("test")
|
||||||
|
if !contains(infoLog, "I", t) {
|
||||||
|
t.Errorf("Info has wrong character: %q", contents(infoLog))
|
||||||
|
}
|
||||||
|
if !contains(infoLog, "test", t) {
|
||||||
|
t.Error("Info failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Test that the header has the correct format.
|
// Test that the header has the correct format.
|
||||||
func TestHeader(t *testing.T) {
|
func TestHeader(t *testing.T) {
|
||||||
setFlags()
|
setFlags()
|
||||||
defer logging.swap(logging.newBuffers())
|
defer logging.swap(logging.newBuffers())
|
||||||
defer func(previous func() time.Time) { timeNow = previous }(timeNow)
|
defer func(previous func() time.Time) { timeNow = previous }(timeNow)
|
||||||
timeNow = func() time.Time {
|
timeNow = func() time.Time {
|
||||||
return time.Date(2006, 1, 2, 15, 4, 5, .678901e9, time.Local)
|
return time.Date(2006, 1, 2, 15, 4, 5, .067890e9, time.Local)
|
||||||
}
|
}
|
||||||
|
pid = 1234
|
||||||
Info("test")
|
Info("test")
|
||||||
var line, pid int
|
var line int
|
||||||
n, err := fmt.Sscanf(contents(infoLog), "I0102 15:04:05.678901 %d glog_test.go:%d] test\n", &pid, &line)
|
format := "I0102 15:04:05.067890 1234 glog_test.go:%d] test\n"
|
||||||
if n != 2 || err != nil {
|
n, err := fmt.Sscanf(contents(infoLog), format, &line)
|
||||||
|
if n != 1 || err != nil {
|
||||||
t.Errorf("log format error: %d elements, error %s:\n%s", n, err, contents(infoLog))
|
t.Errorf("log format error: %d elements, error %s:\n%s", n, err, contents(infoLog))
|
||||||
}
|
}
|
||||||
|
// Scanf treats multiple spaces as equivalent to a single space,
|
||||||
|
// so check for correct space-padding also.
|
||||||
|
want := fmt.Sprintf(format, line)
|
||||||
|
if contents(infoLog) != want {
|
||||||
|
t.Errorf("log format error: got:\n\t%q\nwant:\t%q", contents(infoLog), want)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that an Error log goes to Warning and Info.
|
// Test that an Error log goes to Warning and Info.
|
||||||
|
@ -328,6 +409,7 @@ func TestLogBacktraceAt(t *testing.T) {
|
||||||
|
|
||||||
func BenchmarkHeader(b *testing.B) {
|
func BenchmarkHeader(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
logging.putBuffer(logging.header(infoLog))
|
buf, _, _ := logging.header(infoLog, 0)
|
||||||
|
logging.putBuffer(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1
Godeps/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml
generated
vendored
1
Godeps/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml
generated
vendored
|
@ -3,4 +3,5 @@ go:
|
||||||
- 1.1
|
- 1.1
|
||||||
- 1.2
|
- 1.2
|
||||||
- 1.3
|
- 1.3
|
||||||
|
- 1.4
|
||||||
- tip
|
- tip
|
||||||
|
|
83
Godeps/_workspace/src/github.com/julienschmidt/httprouter/README.md
generated
vendored
83
Godeps/_workspace/src/github.com/julienschmidt/httprouter/README.md
generated
vendored
|
@ -189,8 +189,9 @@ for example the [Gorilla handlers](http://www.gorillatoolkit.org/pkg/handlers).
|
||||||
Or you could [just write your own](http://justinas.org/writing-http-middleware-in-go/),
|
Or you could [just write your own](http://justinas.org/writing-http-middleware-in-go/),
|
||||||
it's very easy!
|
it's very easy!
|
||||||
|
|
||||||
Alternatively, you could try [a framework building upon HttpRouter](#web-frameworks-building-upon-httprouter).
|
Alternatively, you could try [a framework building upon HttpRouter](#web-frameworks--co-based-on-httprouter).
|
||||||
|
|
||||||
|
### Multi-domain / Sub-domains
|
||||||
Here is a quick example: Does your server serve multiple domains / hosts?
|
Here is a quick example: Does your server serve multiple domains / hosts?
|
||||||
You want to use sub-domains?
|
You want to use sub-domains?
|
||||||
Define a router per host!
|
Define a router per host!
|
||||||
|
@ -228,7 +229,85 @@ func main() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Web Frameworks building upon HttpRouter
|
### Basic Authentication
|
||||||
|
Another quick example: Basic Authentification (RFC 2617) for handles:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
"net/http"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BasicAuth(h httprouter.Handle, user, pass []byte) httprouter.Handle {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||||
|
const basicAuthPrefix string = "Basic "
|
||||||
|
|
||||||
|
// Get the Basic Authentication credentials
|
||||||
|
auth := r.Header.Get("Authorization")
|
||||||
|
if strings.HasPrefix(auth, basicAuthPrefix) {
|
||||||
|
// Check credentials
|
||||||
|
payload, err := base64.StdEncoding.DecodeString(auth[len(basicAuthPrefix):])
|
||||||
|
if err == nil {
|
||||||
|
pair := bytes.SplitN(payload, []byte(":"), 2)
|
||||||
|
if len(pair) == 2 && bytes.Equal(pair[0], user) && bytes.Equal(pair[1], pass) {
|
||||||
|
// Delegate request to the given handle
|
||||||
|
h(w, r, ps)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request Basic Authentication otherwise
|
||||||
|
w.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
|
||||||
|
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||||
|
fmt.Fprint(w, "Not protected!\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Protected(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||||
|
fmt.Fprint(w, "Protected!\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
user := []byte("gordon")
|
||||||
|
pass := []byte("secret!")
|
||||||
|
|
||||||
|
router := httprouter.New()
|
||||||
|
router.GET("/", Index)
|
||||||
|
router.GET("/protected/", BasicAuth(Protected, user, pass))
|
||||||
|
|
||||||
|
log.Fatal(http.ListenAndServe(":8080", router))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Chaining with the NotFound handler
|
||||||
|
|
||||||
|
**NOTE: It might be required to set [Router.HandleMethodNotAllowed](http://godoc.org/github.com/julienschmidt/httprouter#Router.HandleMethodNotAllowed) to `false` to avoid problems.**
|
||||||
|
|
||||||
|
You can use another [http.HandlerFunc](http://golang.org/pkg/net/http/#HandlerFunc), for example another router, to handle requests which could not be matched by this router by using the [Router.NotFound](http://godoc.org/github.com/julienschmidt/httprouter#Router.NotFound) handler. This allows chaining.
|
||||||
|
|
||||||
|
### Static files
|
||||||
|
The `NotFound` handler can for example be used to serve static files from the root path `/` (like an index.html file along with other assets):
|
||||||
|
```go
|
||||||
|
// Serve static files from the ./public directory
|
||||||
|
router.NotFound = http.FileServer(http.Dir("public")).ServeHTTP
|
||||||
|
```
|
||||||
|
|
||||||
|
But this approach sidesteps the strict core rules of this router to avoid routing problems. A cleaner approach is to use a distinct sub-path for serving files, like `/static/*filepath` or `/files/*filepath`.
|
||||||
|
|
||||||
|
## Web Frameworks & Co based on HttpRouter
|
||||||
If the HttpRouter is a bit too minimalistic for you, you might try one of the following more high-level 3rd-party web frameworks building upon the HttpRouter package:
|
If the HttpRouter is a bit too minimalistic for you, you might try one of the following more high-level 3rd-party web frameworks building upon the HttpRouter package:
|
||||||
* [Gin](https://github.com/gin-gonic/gin): Features a martini-like API with much better performance
|
* [Gin](https://github.com/gin-gonic/gin): Features a martini-like API with much better performance
|
||||||
* [Hikaru](https://github.com/najeira/hikaru): Supports standalone and Google AppEngine
|
* [Hikaru](https://github.com/najeira/hikaru): Supports standalone and Google AppEngine
|
||||||
|
* [Hitch](https://github.com/nbio/hitch): Hitch ties httprouter, [httpcontext](https://github.com/nbio/httpcontext), and middleware up in a bow
|
||||||
|
* [Neko](https://github.com/rocwong/neko): A lightweight web application framework for Golang
|
||||||
|
|
44
Godeps/_workspace/src/github.com/julienschmidt/httprouter/router.go
generated
vendored
44
Godeps/_workspace/src/github.com/julienschmidt/httprouter/router.go
generated
vendored
|
@ -123,13 +123,21 @@ type Router struct {
|
||||||
// handle is registered for it.
|
// handle is registered for it.
|
||||||
// First superfluous path elements like ../ or // are removed.
|
// First superfluous path elements like ../ or // are removed.
|
||||||
// Afterwards the router does a case-insensitive lookup of the cleaned path.
|
// Afterwards the router does a case-insensitive lookup of the cleaned path.
|
||||||
// If a handle can be found for this route, the router makes a redirection
|
// If a handle can be found for this route, the router makes a redirection
|
||||||
// to the corrected path with status code 301 for GET requests and 307 for
|
// to the corrected path with status code 301 for GET requests and 307 for
|
||||||
// all other request methods.
|
// all other request methods.
|
||||||
// For example /FOO and /..//Foo could be redirected to /foo.
|
// For example /FOO and /..//Foo could be redirected to /foo.
|
||||||
// RedirectTrailingSlash is independent of this option.
|
// RedirectTrailingSlash is independent of this option.
|
||||||
RedirectFixedPath bool
|
RedirectFixedPath bool
|
||||||
|
|
||||||
|
// If enabled, the router checks if another method is allowed for the
|
||||||
|
// current route, if the current request can not be routed.
|
||||||
|
// If this is the case, the request is answered with 'Method Not Allowed'
|
||||||
|
// and HTTP status code 405.
|
||||||
|
// If no other Method is allowed, the request is delegated to the NotFound
|
||||||
|
// handler.
|
||||||
|
HandleMethodNotAllowed bool
|
||||||
|
|
||||||
// Configurable http.HandlerFunc which is called when no matching route is
|
// Configurable http.HandlerFunc which is called when no matching route is
|
||||||
// found. If it is not set, http.NotFound is used.
|
// found. If it is not set, http.NotFound is used.
|
||||||
NotFound http.HandlerFunc
|
NotFound http.HandlerFunc
|
||||||
|
@ -149,8 +157,9 @@ var _ http.Handler = New()
|
||||||
// Path auto-correction, including trailing slashes, is enabled by default.
|
// Path auto-correction, including trailing slashes, is enabled by default.
|
||||||
func New() *Router {
|
func New() *Router {
|
||||||
return &Router{
|
return &Router{
|
||||||
RedirectTrailingSlash: true,
|
RedirectTrailingSlash: true,
|
||||||
RedirectFixedPath: true,
|
RedirectFixedPath: true,
|
||||||
|
HandleMethodNotAllowed: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,6 +168,11 @@ func (r *Router) GET(path string, handle Handle) {
|
||||||
r.Handle("GET", path, handle)
|
r.Handle("GET", path, handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HEAD is a shortcut for router.Handle("HEAD", path, handle)
|
||||||
|
func (r *Router) HEAD(path string, handle Handle) {
|
||||||
|
r.Handle("HEAD", path, handle)
|
||||||
|
}
|
||||||
|
|
||||||
// POST is a shortcut for router.Handle("POST", path, handle)
|
// POST is a shortcut for router.Handle("POST", path, handle)
|
||||||
func (r *Router) POST(path string, handle Handle) {
|
func (r *Router) POST(path string, handle Handle) {
|
||||||
r.Handle("POST", path, handle)
|
r.Handle("POST", path, handle)
|
||||||
|
@ -256,6 +270,9 @@ func (r *Router) recv(w http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
// Lookup allows the manual lookup of a method + path combo.
|
// Lookup allows the manual lookup of a method + path combo.
|
||||||
// This is e.g. useful to build a framework around this router.
|
// This is e.g. useful to build a framework around this router.
|
||||||
|
// If the path was found, it returns the handle function and the path parameter
|
||||||
|
// values. Otherwise the third return value indicates whether a redirection to
|
||||||
|
// the same path with an extra / without the trailing slash should be performed.
|
||||||
func (r *Router) Lookup(method, path string) (Handle, Params, bool) {
|
func (r *Router) Lookup(method, path string) (Handle, Params, bool) {
|
||||||
if root := r.trees[method]; root != nil {
|
if root := r.trees[method]; root != nil {
|
||||||
return root.getValue(path)
|
return root.getValue(path)
|
||||||
|
@ -284,7 +301,7 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if tsr && r.RedirectTrailingSlash {
|
if tsr && r.RedirectTrailingSlash {
|
||||||
if path[len(path)-1] == '/' {
|
if len(path) > 1 && path[len(path)-1] == '/' {
|
||||||
req.URL.Path = path[:len(path)-1]
|
req.URL.Path = path[:len(path)-1]
|
||||||
} else {
|
} else {
|
||||||
req.URL.Path = path + "/"
|
req.URL.Path = path + "/"
|
||||||
|
@ -308,6 +325,25 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle 405
|
||||||
|
if r.HandleMethodNotAllowed {
|
||||||
|
for method := range r.trees {
|
||||||
|
// Skip the requested method - we already tried this one
|
||||||
|
if method == req.Method {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
handle, _, _ := r.trees[method].getValue(req.URL.Path)
|
||||||
|
if handle != nil {
|
||||||
|
http.Error(w,
|
||||||
|
http.StatusText(http.StatusMethodNotAllowed),
|
||||||
|
http.StatusMethodNotAllowed,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle 404
|
// Handle 404
|
||||||
if r.NotFound != nil {
|
if r.NotFound != nil {
|
||||||
r.NotFound(w, req)
|
r.NotFound(w, req)
|
||||||
|
|
28
Godeps/_workspace/src/github.com/julienschmidt/httprouter/router_test.go
generated
vendored
28
Godeps/_workspace/src/github.com/julienschmidt/httprouter/router_test.go
generated
vendored
|
@ -76,7 +76,7 @@ func (h handlerStruct) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRouterAPI(t *testing.T) {
|
func TestRouterAPI(t *testing.T) {
|
||||||
var get, post, put, patch, delete, handler, handlerFunc bool
|
var get, head, post, put, patch, delete, handler, handlerFunc bool
|
||||||
|
|
||||||
httpHandler := handlerStruct{&handler}
|
httpHandler := handlerStruct{&handler}
|
||||||
|
|
||||||
|
@ -84,6 +84,9 @@ func TestRouterAPI(t *testing.T) {
|
||||||
router.GET("/GET", func(w http.ResponseWriter, r *http.Request, _ Params) {
|
router.GET("/GET", func(w http.ResponseWriter, r *http.Request, _ Params) {
|
||||||
get = true
|
get = true
|
||||||
})
|
})
|
||||||
|
router.HEAD("/GET", func(w http.ResponseWriter, r *http.Request, _ Params) {
|
||||||
|
head = true
|
||||||
|
})
|
||||||
router.POST("/POST", func(w http.ResponseWriter, r *http.Request, _ Params) {
|
router.POST("/POST", func(w http.ResponseWriter, r *http.Request, _ Params) {
|
||||||
post = true
|
post = true
|
||||||
})
|
})
|
||||||
|
@ -109,6 +112,12 @@ func TestRouterAPI(t *testing.T) {
|
||||||
t.Error("routing GET failed")
|
t.Error("routing GET failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r, _ = http.NewRequest("HEAD", "/GET", nil)
|
||||||
|
router.ServeHTTP(w, r)
|
||||||
|
if !head {
|
||||||
|
t.Error("routing HEAD failed")
|
||||||
|
}
|
||||||
|
|
||||||
r, _ = http.NewRequest("POST", "/POST", nil)
|
r, _ = http.NewRequest("POST", "/POST", nil)
|
||||||
router.ServeHTTP(w, r)
|
router.ServeHTTP(w, r)
|
||||||
if !post {
|
if !post {
|
||||||
|
@ -156,12 +165,28 @@ func TestRouterRoot(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRouterNotAllowed(t *testing.T) {
|
||||||
|
handlerFunc := func(_ http.ResponseWriter, _ *http.Request, _ Params) {}
|
||||||
|
|
||||||
|
router := New()
|
||||||
|
router.POST("/path", handlerFunc)
|
||||||
|
|
||||||
|
// Test not allowed
|
||||||
|
r, _ := http.NewRequest("GET", "/path", nil)
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
router.ServeHTTP(w, r)
|
||||||
|
if !(w.Code == http.StatusMethodNotAllowed) {
|
||||||
|
t.Errorf("NotAllowed handling route %s failed: Code=%d, Header=%v", w.Code, w.Header())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRouterNotFound(t *testing.T) {
|
func TestRouterNotFound(t *testing.T) {
|
||||||
handlerFunc := func(_ http.ResponseWriter, _ *http.Request, _ Params) {}
|
handlerFunc := func(_ http.ResponseWriter, _ *http.Request, _ Params) {}
|
||||||
|
|
||||||
router := New()
|
router := New()
|
||||||
router.GET("/path", handlerFunc)
|
router.GET("/path", handlerFunc)
|
||||||
router.GET("/dir/", handlerFunc)
|
router.GET("/dir/", handlerFunc)
|
||||||
|
router.GET("/", handlerFunc)
|
||||||
|
|
||||||
testRoutes := []struct {
|
testRoutes := []struct {
|
||||||
route string
|
route string
|
||||||
|
@ -170,6 +195,7 @@ func TestRouterNotFound(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{"/path/", 301, "map[Location:[/path]]"}, // TSR -/
|
{"/path/", 301, "map[Location:[/path]]"}, // TSR -/
|
||||||
{"/dir", 301, "map[Location:[/dir/]]"}, // TSR +/
|
{"/dir", 301, "map[Location:[/dir/]]"}, // TSR +/
|
||||||
|
{"", 301, "map[Location:[/]]"}, // TSR +/
|
||||||
{"/PATH", 301, "map[Location:[/path]]"}, // Fixed Case
|
{"/PATH", 301, "map[Location:[/path]]"}, // Fixed Case
|
||||||
{"/DIR/", 301, "map[Location:[/dir/]]"}, // Fixed Case
|
{"/DIR/", 301, "map[Location:[/dir/]]"}, // Fixed Case
|
||||||
{"/PATH/", 301, "map[Location:[/path]]"}, // Fixed Case -/
|
{"/PATH/", 301, "map[Location:[/path]]"}, // Fixed Case -/
|
||||||
|
|
4
Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree.go
generated
vendored
4
Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree.go
generated
vendored
|
@ -379,7 +379,7 @@ walk: // Outer loop for walking the tree
|
||||||
return
|
return
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic("Unknown node type")
|
panic("Invalid node type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if path == n.path {
|
} else if path == n.path {
|
||||||
|
@ -490,7 +490,7 @@ func (n *node) findCaseInsensitivePath(path string, fixTrailingSlash bool) (ciPa
|
||||||
return append(ciPath, path...), true
|
return append(ciPath, path...), true
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic("Unknown node type")
|
panic("Invalid node type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
25
Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go
generated
vendored
25
Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go
generated
vendored
|
@ -557,3 +557,28 @@ func TestTreeFindCaseInsensitivePath(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTreeInvalidNodeType(t *testing.T) {
|
||||||
|
tree := &node{}
|
||||||
|
tree.addRoute("/", fakeHandler("/"))
|
||||||
|
tree.addRoute("/:page", fakeHandler("/:page"))
|
||||||
|
|
||||||
|
// set invalid node type
|
||||||
|
tree.children[0].nType = 42
|
||||||
|
|
||||||
|
// normal lookup
|
||||||
|
recv := catchPanic(func() {
|
||||||
|
tree.getValue("/test")
|
||||||
|
})
|
||||||
|
if rs, ok := recv.(string); !ok || rs != "Invalid node type" {
|
||||||
|
t.Fatalf(`Expected panic "Invalid node type", got "%v"`, recv)
|
||||||
|
}
|
||||||
|
|
||||||
|
// case-insensitive lookup
|
||||||
|
recv = catchPanic(func() {
|
||||||
|
tree.findCaseInsensitivePath("/test", true)
|
||||||
|
})
|
||||||
|
if rs, ok := recv.(string); !ok || rs != "Invalid node type" {
|
||||||
|
t.Fatalf(`Expected panic "Invalid node type", got "%v"`, recv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
2
Godeps/_workspace/src/github.com/pushrax/faststats/LICENSE
generated
vendored
2
Godeps/_workspace/src/github.com/pushrax/faststats/LICENSE
generated
vendored
|
@ -1,6 +1,6 @@
|
||||||
faststats is released under a BSD 2-Clause license, reproduced below.
|
faststats is released under a BSD 2-Clause license, reproduced below.
|
||||||
|
|
||||||
Copyright (c) 2014, The faststats Authors
|
Copyright (c) 2015, The faststats Authors
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification,
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
|
2
Godeps/_workspace/src/github.com/pushrax/faststats/faststats.go
generated
vendored
2
Godeps/_workspace/src/github.com/pushrax/faststats/faststats.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The faststats Authors. All rights reserved.
|
// Copyright 2015 The faststats Authors. All rights reserved.
|
||||||
// Use of this source code is governed by the BSD 2-Clause license,
|
// Use of this source code is governed by the BSD 2-Clause license,
|
||||||
// which can be found in the LICENSE file.
|
// which can be found in the LICENSE file.
|
||||||
|
|
||||||
|
|
2
Godeps/_workspace/src/github.com/pushrax/faststats/json.go
generated
vendored
2
Godeps/_workspace/src/github.com/pushrax/faststats/json.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The faststats Authors. All rights reserved.
|
// Copyright 2015 The faststats Authors. All rights reserved.
|
||||||
// Use of this source code is governed by the BSD 2-Clause license,
|
// Use of this source code is governed by the BSD 2-Clause license,
|
||||||
// which can be found in the LICENSE file.
|
// which can be found in the LICENSE file.
|
||||||
|
|
||||||
|
|
2
Godeps/_workspace/src/github.com/pushrax/faststats/percentile.go
generated
vendored
2
Godeps/_workspace/src/github.com/pushrax/faststats/percentile.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The faststats Authors. All rights reserved.
|
// Copyright 2015 The faststats Authors. All rights reserved.
|
||||||
// Use of this source code is governed by the BSD 2-Clause license,
|
// Use of this source code is governed by the BSD 2-Clause license,
|
||||||
// which can be found in the LICENSE file.
|
// which can be found in the LICENSE file.
|
||||||
|
|
||||||
|
|
2
Godeps/_workspace/src/github.com/pushrax/faststats/percentile_test.go
generated
vendored
2
Godeps/_workspace/src/github.com/pushrax/faststats/percentile_test.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The faststats Authors. All rights reserved.
|
// Copyright 2015 The faststats Authors. All rights reserved.
|
||||||
// Use of this source code is governed by the BSD 2-Clause license,
|
// Use of this source code is governed by the BSD 2-Clause license,
|
||||||
// which can be found in the LICENSE file.
|
// which can be found in the LICENSE file.
|
||||||
|
|
||||||
|
|
2
Godeps/_workspace/src/github.com/pushrax/faststats/util.go
generated
vendored
2
Godeps/_workspace/src/github.com/pushrax/faststats/util.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The faststats Authors. All rights reserved.
|
// Copyright 2015 The faststats Authors. All rights reserved.
|
||||||
// Use of this source code is governed by the BSD 2-Clause license,
|
// Use of this source code is governed by the BSD 2-Clause license,
|
||||||
// which can be found in the LICENSE file.
|
// which can be found in the LICENSE file.
|
||||||
|
|
||||||
|
|
4
Godeps/_workspace/src/github.com/pushrax/flatjson/LICENSE
generated
vendored
4
Godeps/_workspace/src/github.com/pushrax/flatjson/LICENSE
generated
vendored
|
@ -1,6 +1,6 @@
|
||||||
Chihaya is released under a BSD 2-Clause license, reproduced below.
|
flatjson is released under a BSD 2-Clause license, reproduced below.
|
||||||
|
|
||||||
Copyright (c) 2014, The Chihaya Authors
|
Copyright (c) 2015, The flatjson Authors
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification,
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
|
2
Godeps/_workspace/src/github.com/pushrax/flatjson/README.md
generated
vendored
2
Godeps/_workspace/src/github.com/pushrax/flatjson/README.md
generated
vendored
|
@ -7,7 +7,7 @@ Example use case:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"Connections" {
|
"Connections": {
|
||||||
"Open": 2,
|
"Open": 2,
|
||||||
"Accepted": 4
|
"Accepted": 4
|
||||||
},
|
},
|
||||||
|
|
2
Godeps/_workspace/src/github.com/pushrax/flatjson/flatjson.go
generated
vendored
2
Godeps/_workspace/src/github.com/pushrax/flatjson/flatjson.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The flatjson Authors. All rights reserved.
|
// Copyright 2015 The flatjson Authors. All rights reserved.
|
||||||
// Use of this source code is governed by the BSD 2-Clause license,
|
// Use of this source code is governed by the BSD 2-Clause license,
|
||||||
// which can be found in the LICENSE file.
|
// which can be found in the LICENSE file.
|
||||||
|
|
||||||
|
|
9
Godeps/_workspace/src/github.com/pushrax/flatjson/flatjson_test.go
generated
vendored
9
Godeps/_workspace/src/github.com/pushrax/flatjson/flatjson_test.go
generated
vendored
|
@ -14,14 +14,11 @@ type Child struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBasicFlatten(t *testing.T) {
|
func TestBasicFlatten(t *testing.T) {
|
||||||
val := &struct {
|
val := &Child{10, "str"}
|
||||||
A int
|
|
||||||
B string
|
|
||||||
}{10, "str"}
|
|
||||||
|
|
||||||
expected := flatjson.Map{
|
expected := flatjson.Map{
|
||||||
"A": 10.0, // JSON numbers are all float64.
|
"CC": 10.0, // JSON numbers are all float64.
|
||||||
"B": "str",
|
"CD": "str",
|
||||||
}
|
}
|
||||||
|
|
||||||
testFlattening(t, val, expected)
|
testFlattening(t, val, expected)
|
||||||
|
|
9
Godeps/_workspace/src/github.com/stretchr/graceful/graceful.go
generated
vendored
9
Godeps/_workspace/src/github.com/stretchr/graceful/graceful.go
generated
vendored
|
@ -12,7 +12,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/pat/stop"
|
"github.com/stretchr/pat/stop"
|
||||||
"code.google.com/p/go.net/netutil"
|
"golang.org/x/net/netutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Server wraps an http.Server with graceful connection handling.
|
// Server wraps an http.Server with graceful connection handling.
|
||||||
|
@ -115,8 +115,13 @@ func (srv *Server) ListenAndServe() error {
|
||||||
// timeout is the duration to wait until killing active requests and stopping the server.
|
// timeout is the duration to wait until killing active requests and stopping the server.
|
||||||
// If timeout is 0, the server never times out. It waits for all active requests to finish.
|
// If timeout is 0, the server never times out. It waits for all active requests to finish.
|
||||||
func ListenAndServeTLS(server *http.Server, certFile, keyFile string, timeout time.Duration) error {
|
func ListenAndServeTLS(server *http.Server, certFile, keyFile string, timeout time.Duration) error {
|
||||||
// Create the listener ourselves so we can control its lifetime
|
|
||||||
srv := &Server{Timeout: timeout, Server: server}
|
srv := &Server{Timeout: timeout, Server: server}
|
||||||
|
return srv.ListenAndServeTLS(certFile, keyFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListenAndServeTLS is equivalent to http.Server.ListenAndServeTLS with graceful shutdown enabled.
|
||||||
|
func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
|
||||||
|
// Create the listener ourselves so we can control its lifetime
|
||||||
addr := srv.Addr
|
addr := srv.Addr
|
||||||
if addr == "" {
|
if addr == "" {
|
||||||
addr = ":https"
|
addr = ":https"
|
||||||
|
|
2
Godeps/_workspace/src/golang.org/x/net/netutil/listen.go
generated
vendored
2
Godeps/_workspace/src/golang.org/x/net/netutil/listen.go
generated
vendored
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
// Package netutil provides network utility functions, complementing the more
|
// Package netutil provides network utility functions, complementing the more
|
||||||
// common ones in the net package.
|
// common ones in the net package.
|
||||||
package netutil
|
package netutil // import "golang.org/x/net/netutil"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
"real_ip_header": "",
|
"real_ip_header": "",
|
||||||
"respect_af": false,
|
"respect_af": false,
|
||||||
"client_whitelist_enabled": false,
|
"client_whitelist_enabled": false,
|
||||||
|
"client_whitelist": ["OP1011"],
|
||||||
"http_listen_addr": ":6881",
|
"http_listen_addr": ":6881",
|
||||||
"http_request_timeout": "10s",
|
"http_request_timeout": "10s",
|
||||||
"http_read_timeout": "10s",
|
"http_read_timeout": "10s",
|
||||||
|
|
|
@ -83,6 +83,7 @@ func newRouter(s *Server) *httprouter.Router {
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.config.ClientWhitelistEnabled {
|
if s.config.ClientWhitelistEnabled {
|
||||||
|
r.GET("/clients/:clientID", makeHandler(s.getClient))
|
||||||
r.PUT("/clients/:clientID", makeHandler(s.putClient))
|
r.PUT("/clients/:clientID", makeHandler(s.putClient))
|
||||||
r.DELETE("/clients/:clientID", makeHandler(s.delClient))
|
r.DELETE("/clients/:clientID", makeHandler(s.delClient))
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,6 +178,13 @@ func (s *Server) delUser(w http.ResponseWriter, r *http.Request, p httprouter.Pa
|
||||||
return http.StatusOK, nil
|
return http.StatusOK, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) getClient(w http.ResponseWriter, r *http.Request, p httprouter.Params) (int, error) {
|
||||||
|
if err := s.tracker.ClientApproved(p.ByName("clientID")); err != nil {
|
||||||
|
return http.StatusNotFound, err
|
||||||
|
}
|
||||||
|
return http.StatusOK, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) putClient(w http.ResponseWriter, r *http.Request, p httprouter.Params) (int, error) {
|
func (s *Server) putClient(w http.ResponseWriter, r *http.Request, p httprouter.Params) (int, error) {
|
||||||
s.tracker.PutClient(p.ByName("clientID"))
|
s.tracker.PutClient(p.ByName("clientID"))
|
||||||
return http.StatusOK, nil
|
return http.StatusOK, nil
|
||||||
|
|
Loading…
Reference in a new issue