添加vednor和验证码接口

master
DESKTOP-4RNDQIC\29019 2019-01-29 21:57:53 +08:00
parent 2a1c947808
commit 48c5a9c552
443 changed files with 151736 additions and 25847 deletions

View File

@ -73,3 +73,10 @@ func GetMysqlConfig() *MysqlConfig{
return nil return nil
} }
} }
func GetLogConfig() *LogConfig {
if gConf.init{
return &gConf.Logs
}else{
return nil
}
}

View File

@ -76,27 +76,9 @@ func Auth(c *gin.Context) {
// @Success 200 {array} util.RespBase // @Success 200 {array} util.RespBase
// @Router /accounts [get] // @Router /accounts [get]
func SetUser(c *gin.Context){ func SetUser(c *gin.Context){
var req model.Users
var resp RespBase
resp.Msg = "操作失败"
resp.Status = 20
defer func() {
c.JSON(200,resp)
}()
e := c.BindJSON(&req)
if nil != e{
logs.Error(e.Error())
return
}
} }
func DelUser(c *gin.Context){ func DelUser(c *gin.Context){
var resp RespBase
resp.Msg = "操作失败"
resp.Status = 20
defer func() {
c.JSON(200,resp)
}()
} }
@ -118,11 +100,11 @@ func GetUser(c *gin.Context) {
if nil != e { if nil != e {
logs.Error(e.Error()) logs.Error(e.Error())
} }
delete(users,"socketToken") delete(users,"socketToken" +
"")
resp.Status = 0 resp.Status = 0
resp.Msg = "操作成功" resp.Msg = "操作成功"
resp.Data = users resp.Data = users
} }
// GetUsers godoc // GetUsers godoc
// @Summary GetUsers // @Summary GetUsers
@ -134,10 +116,6 @@ func GetUser(c *gin.Context) {
// @Param displayname query string false "name search by q" // @Param displayname query string false "name search by q"
// @Param department_id query string false "name search by q" // @Param department_id query string false "name search by q"
// @Param permission_type query string false "name search by q" // @Param permission_type query string false "name search by q"
// @Success 200 {array} util.RespBase
// @Failure 400 {object} util.RespBase
// @Failure 404 {object} util.RespBase
// @Failure 500 {object} util.RespBase
// @Router /api/users [get] // @Router /api/users [get]
func GetUsers(c *gin.Context) { func GetUsers(c *gin.Context) {
var statuscode int var statuscode int

197
controller/mail/mail.go Normal file
View File

@ -0,0 +1,197 @@
package mail
import (
"bufio"
"bytes"
"errors"
"github.com/gin-gonic/gin"
"io/ioutil"
"log"
"net/smtp"
"os"
"regexp"
"strings"
"text/template"
)
type RespJson struct {
Msg string `json:"msg"`
Data interface{} `json:"data,omitempty"`
Affected int64 `json:"affected,omitempty"`
}
func PathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsExist(err) {
return true, nil
}
return false, err
}
func GetTemplateFile(template string) ([]byte, error) {
path := "G:\\GoPath\\Email\\" + template + ".tpl"
ok, err := PathExists(path)
if !ok {
return nil, errors.New("Count not Find File " + path)
}
file, err := os.Open(path)
if err != nil {
log.Println(err.Error())
}
ret, err := ioutil.ReadAll(file)
file.Close()
return ret, nil
}
//静态文件存放地
const PATH_STATIC = "G://GoPath//Email//static//"
type ReqSendEmail struct {
From string `json:"from"`
To string `json:"to"`
Tittle string `json:"tittle"`
TempData interface{} `json:"temp_data"`
Template string `json:"template"`
Generate bool `json:"generate"`
}
func SendToMail(title, user, password, host, to, tplname string, content interface{}, mailtype string, ifgenerate bool) error {
var content_type string
var paseresult bytes.Buffer
writer := bufio.NewWriter(&paseresult)
hp := strings.Split(host, ":")
auth := smtp.PlainAuth("", user, password, hp[0])
if mailtype == "html" {
content_type = "Content-Type: text/" + mailtype + "; charset=UTF-8"
} else {
content_type = "Content-Type: text/plain" + "; charset=UTF-8"
}
//todo 获取模板文件内容
tpl, err := GetTemplateFile(tplname)
if err != nil {
log.Println(err.Error())
return err
}
//todo 渲染
tparse := template.New(tplname)
tparse, _ = tparse.Parse(string(tpl))
tparse.Execute(writer, content)
writer.Flush()
if err != nil {
log.Println(err.Error())
return err
}
msg := []byte("To: " + to + "\r\nFrom: " + user + "\r\nSubject: " + title + "\r\n" +
content_type + "\r\n\r\n" + paseresult.String() + "\r\n")
send_to := strings.Split(to, ";")
//todo 如果生成Html文件
if ifgenerate {
file, err := os.Create(PATH_STATIC + tplname + ".html")
if err != nil {
log.Println(err.Error())
}
file.WriteString(paseresult.String())
file.Close()
}
//检测是否是邮件地址
for k, _ := range send_to {
match, _ := regexp.MatchString("[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?", send_to[k])
if !match {
return errors.New("Format Error")
}
}
err = smtp.SendMail(host, auth, user, send_to, msg)
if err != nil {
return err
}
return err
}
/*
func OnSendEmailSendCloud(c *gin.Context){
var req ReqSendEmail
var resp mysqlcurd.RespJson
defer func() {
c.JSON(200, resp)
}()
e := c.Bind(&req)
if e!= nil{
log.Println(e.Error())
resp.Msg = "ParaErr"
return
}
sendcloud.UpdateApiInfo("a7458969_test_KIIqjl", "ovErXj6M8UJeiPJt")
var to = make([]map[string]string, 1)
to[0] = map[string]string{"to":"290198252@qq.com", "%url%": "http://www.baidu.com"}
var ok, err, result = sendcloud.SendTemplateMail("test_template_active", "290198252@sendcloud.org", "测试", "", "测试", to, nil)
if err != nil{
log.Print(err.Error())
resp.Msg = "Fail"
}
if !ok{
resp.Msg = "Fail"
}
resp.Msg = result
}*/
/*
{
"tittle":"运维通知",
"from":"c7458969@163.com",
"to":"290198252@qq.com",
"template":"test",
"generate":true,
"temp_data":{
"content":"f发撒旦法时代阿达是否",
"title":"运维通知2",
"topimg":"http://img2.imgtn.bdimg.com/it/u=387283908,3372540416&fm=27&gp=0.jpg",
"button1text":"客服热线",
"button1url":"http://www.baidu.com",
"button2text":"查看详情",
"button2url":"http://www.baidu.com",
"logoimg":"http://news.tom.com/dimg/2016/1027/img-1479784632271.jpg"
}
}
*/
//from: 发送人邮箱
//to:接收邮件,可以是"290198252@qq.com;29019822@qq.com;2901982@qq.com" 邮箱之间用分号隔开
//template:模板名字
//content :网页模板的参数 key-value结构
//temp_data 模板内具体要替换的变量名字 Key-value结构
//generate 是否生成静态html
func OnSendEmail(c *gin.Context) {
var req ReqSendEmail
var resp RespJson
defer func() {
c.JSON(200, resp)
}()
e := c.Bind(&req)
if e != nil {
log.Println(e.Error())
resp.Msg = "ParaErr"
return
}
user := "c7458969@163.com"
password := "caiyu123"
host := "smtp.163.com:25"
//抄送给自己
//e = SendToMail(user,password,host,req.From,req.Template,req.Content,"html")
//发送
e = SendToMail(req.Tittle, user, password, host, req.To, req.Template, req.TempData, "html", req.Generate)
if nil != e {
log.Println(e.Error())
resp.Msg = "Error"
return
}
resp.Msg = "OK"
}

39
controller/mail/upload.go Normal file
View File

@ -0,0 +1,39 @@
package mail
import (
"fmt"
"github.com/gin-gonic/gin"
"io"
"log"
"os"
)
func OnUpload(c *gin.Context) {
file, header, err := c.Request.FormFile("upload")
filename := header.Filename
fmt.Println(header.Filename)
out, err := os.Create("G://GoPath//image//" + filename + ".png")
if err != nil {
log.Fatal(err)
}
defer out.Close()
_, err = io.Copy(out, file)
if err != nil {
log.Fatal(err)
}
}
func OnDownLoad(c *gin.Context) {
file, header, err := c.Request.FormFile("upload")
filename := header.Filename
fmt.Println(header.Filename)
out, err := os.Create("G://GoPath//image//" + filename + ".png")
if err != nil {
log.Fatal(err)
}
defer out.Close()
_, err = io.Copy(out, file)
if err != nil {
log.Fatal(err)
}
}

View File

@ -3,13 +3,13 @@ package db
import ( import (
"database/sql" "database/sql"
"document/logs"
"errors" "errors"
"fmt" "fmt"
"reflect" "reflect"
"strconv" "strconv"
"sync" "sync"
"time" "time"
"user/logs"
) )
// 数据容器抽象对象定义 // 数据容器抽象对象定义

View File

@ -2,17 +2,15 @@ package db
import ( import (
"database/sql" "database/sql"
"user/config"
"fmt" "fmt"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"log" "user/config"
) )
var gDb Database var gDb Database
func Init() { func Init() {
mysqlconf := config.GetMysqlConfig() mysqlconf := config.GetMysqlConfig()
log.Println(mysqlconf)
cnn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8",mysqlconf.UserName,mysqlconf.Password, cnn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8",mysqlconf.UserName,mysqlconf.Password,
mysqlconf.Addr,mysqlconf.Db) mysqlconf.Addr,mysqlconf.Db)
_db,err := sql.Open("mysql",cnn) _db,err := sql.Open("mysql",cnn)

View File

@ -2,6 +2,7 @@ package main
import ( import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/tommy351/gin-sessions"
"log" "log"
"strconv" "strconv"
"user/controller" "user/controller"
@ -24,8 +25,12 @@ func main() {
if nil != e{ if nil != e{
log.Println(e.Error()) log.Println(e.Error())
} }
logs.Init(config.GetLogConfig().Dir,config.GetLogConfig().File,config.GetLogConfig().Level,config.GetLogConfig().SaveFile)
db.Init() db.Init()
r := gin.Default() r := gin.Default()
store := sessions.NewCookieStore([]byte("secret123"))
r.Use(sessions.Middleware("my_session", store))
{ {
/** 添加或修改用户 **/ /** 添加或修改用户 **/
r.POST("/api/user", controller.SetUser) r.POST("/api/user", controller.SetUser)

View File

@ -5,7 +5,7 @@ logs:
dir: "/var/log/user" dir: "/var/log/user"
file: "user.log" file: "user.log"
level: 1 level: 1
savefile: true savefile: false
redis: redis:
addr: 118.24.238.198 addr: 118.24.238.198
password: 6379 password: 6379

202
vendor/cloud.google.com/go/LICENSE generated vendored Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,4 +1,4 @@
// Copyright 2016 Google Inc. All Rights Reserved. // Copyright 2016 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.

View File

@ -1,11 +1,20 @@
package utils package utils
// 加入8字节 import (
"bytes"
"encoding/binary"
// "errors"
// "fmt"
// "reflect"
// "unsafe"
)
// Put8bit 加入8字节到[]byte中
func Put8bit(buf []byte, n byte) []byte { func Put8bit(buf []byte, n byte) []byte {
return append(buf, n) return append(buf, n)
} }
// 加入16字节 // Put16bit 加入16字节
func Put16bit(buf []byte, n uint16) []byte { func Put16bit(buf []byte, n uint16) []byte {
var by [2]byte var by [2]byte
@ -15,7 +24,7 @@ func Put16bit(buf []byte, n uint16) []byte {
return append(buf, by[:]...) return append(buf, by[:]...)
} }
// 加入32字节 // Put32bit 加入32字节
func Put32bit(buf []byte, n uint32) []byte { func Put32bit(buf []byte, n uint32) []byte {
var by [4]byte var by [4]byte
@ -27,7 +36,7 @@ func Put32bit(buf []byte, n uint32) []byte {
return append(buf, by[:]...) return append(buf, by[:]...)
} }
// 加入64字节 // Put64bit 加入64字节
func Put64bit(buf []byte, n uint64) []byte { func Put64bit(buf []byte, n uint64) []byte {
var by [8]byte var by [8]byte
@ -43,12 +52,12 @@ func Put64bit(buf []byte, n uint64) []byte {
return append(buf, by[:]...) return append(buf, by[:]...)
} }
// 获取8bit // Get8bit 获取8bit
func Get8bit(buf []byte, start int) byte { func Get8bit(buf []byte, start int) byte {
return buf[start] return buf[start]
} }
// 获取16bit // Get16bit 获取16bit
func Get16bit(buf []byte, start int) uint16 { func Get16bit(buf []byte, start int) uint16 {
var ret uint16 var ret uint16
@ -58,7 +67,7 @@ func Get16bit(buf []byte, start int) uint16 {
return ret return ret
} }
// 获取32big // Get32bit 获取32big
func Get32bit(buf []byte, start int) uint32 { func Get32bit(buf []byte, start int) uint32 {
var ret uint32 var ret uint32
@ -70,7 +79,7 @@ func Get32bit(buf []byte, start int) uint32 {
return ret return ret
} }
// 获取64bit // Get64bit 获取64bit
func Get64bit(buf []byte, start int) uint64 { func Get64bit(buf []byte, start int) uint64 {
var ret uint64 var ret uint64
@ -85,3 +94,114 @@ func Get64bit(buf []byte, start int) uint64 {
return ret return ret
} }
// BytesToInt 字节数组转int
func BytesToInt(b []byte) int {
buf := bytes.NewBuffer(b)
var x int
binary.Read(buf, binary.BigEndian, &x)
return int(x)
}
// IntToBytes int转字节数组
func IntToBytes(n int) []byte {
buf := bytes.NewBuffer([]byte{})
binary.Write(buf, binary.BigEndian, n)
return buf.Bytes()
}
// BytesToInt16 字节数组转int16
func BytesToInt16(b []byte) int16 {
buf := bytes.NewBuffer(b)
var x int16
binary.Read(buf, binary.BigEndian, &x)
return int16(x)
}
// Int16ToBytes int16转字节数组
func Int16ToBytes(n int16) []byte {
x := int16(n)
buf := bytes.NewBuffer([]byte{})
binary.Write(buf, binary.BigEndian, x)
return buf.Bytes()
}
// BytesToInt32 字节数组转int32
func BytesToInt32(b []byte) int32 {
buf := bytes.NewBuffer(b)
var x int32
binary.Read(buf, binary.BigEndian, &x)
return int32(x)
}
// Int32ToBytes int32转字节数组
func Int32ToBytes(n int32) []byte {
x := int32(n)
buf := bytes.NewBuffer([]byte{})
binary.Write(buf, binary.BigEndian, x)
return buf.Bytes()
}
// 字节数组转int64
func BytesToInt64(b []byte) int64 {
buf := bytes.NewBuffer(b)
var x int64
binary.Read(buf, binary.BigEndian, &x)
return int64(x)
}
// Int64ToBytes int64转字节数组
func Int64ToBytes(n int64) []byte {
buf := bytes.NewBuffer([]byte{})
binary.Write(buf, binary.BigEndian, n)
return buf.Bytes()
}
// BytesToUInt64 字节数组转uint64
func BytesToUInt64(b []byte) uint64 {
buf := bytes.NewBuffer(b)
var x uint64
binary.Read(buf, binary.BigEndian, &x)
return uint64(x)
}
// UInt64ToBytes uint64转字节数组
func UInt64ToBytes(n uint64) []byte {
buf := bytes.NewBuffer([]byte{})
binary.Write(buf, binary.BigEndian, n)
return buf.Bytes()
}
// UInt32ToBytes uint32转字节数组
func UInt32ToBytes(n uint32) []byte {
buf := bytes.NewBuffer([]byte{})
binary.Write(buf, binary.BigEndian, n)
return buf.Bytes()
}
// BytesToBool 字节数组转bool
func BytesToBool(b []byte) bool {
buf := bytes.NewBuffer(b)
var x bool
binary.Read(buf, binary.BigEndian, &x)
return x
}
// BoolToBytes bool转字节数组
func BoolToBytes(x bool) []byte {
buf := bytes.NewBuffer([]byte{})
binary.Write(buf, binary.BigEndian, x)
return buf.Bytes()
}

View File

@ -52,6 +52,9 @@ func Authcode(text string, params ...interface{}) string {
if l > 1 { if l > 1 {
key = params[1].(string) key = params[1].(string)
if key=="" {
key = "DH-Framework"
}
} }
if l > 2 { if l > 2 {
@ -169,18 +172,18 @@ func AuthcodeUrl(text string, params ...interface{}) string {
} }
} }
// JsonEncode 编码JSON // JsonEncodeWithError 编码JSON
func JsonEncode(m interface{}) string { func JsonEncodeWithError(m interface{}) (string, error) {
b, err := json.Marshal(m) b, err := json.Marshal(m)
if err != nil { if err != nil {
log.Printf("Json Encode[%#v] Error:%s", m, err.Error()) return "", err
return ""
} }
return string(b) return string(b), nil
} }
// JsonDecode 解码JSON
func JsonDecode(str string, v ...interface{}) (interface{}, error) { // JsonDecodeWithError 解码JSON
func JsonDecodeWithError(str string, v ...interface{}) (interface{}, error) {
var m interface{} var m interface{}
if len(v) > 0 { if len(v) > 0 {
m = v[0] m = v[0]
@ -196,6 +199,26 @@ func JsonDecode(str string, v ...interface{}) (interface{}, error) {
return m, nil return m, nil
} }
// JsonEncode 编码JSON
func JsonEncode(m interface{}) string {
s, err := JsonEncodeWithError(m)
if err != nil {
log.Printf("Json Encode[%#v] Error:%s", m, err.Error())
return ""
}
return s
}
// JsonDecode 解码JSON
func JsonDecode(str string, v ...interface{}) interface{} {
i, err := JsonDecodeWithError(str, v...)
if err != nil {
log.Printf("Json Decode[%s] Error:%s", str, err.Error())
return nil
}
return i
}
func Crc32(text string) string { func Crc32(text string) string {
h := crc32.NewIEEE() h := crc32.NewIEEE()
io.WriteString(h, text) io.WriteString(h, text)

View File

@ -6,6 +6,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"fmt"
) )
const ( const (
@ -16,6 +17,7 @@ const (
// ReadTextFile 读取文件 // ReadTextFile 读取文件
func ReadTextFile(path string) string { func ReadTextFile(path string) string {
fmt.Println("path:",path)
fp, err := os.Open(path) fp, err := os.Open(path)
if nil != err { if nil != err {
return "" return ""

View File

@ -4,8 +4,10 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/url"
"reflect" "reflect"
"regexp" "regexp"
"sort"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -308,6 +310,33 @@ func Long2ip(ip uint32) string {
return fmt.Sprintf("%d.%d.%d.%d", ip>>24, ip<<8>>24, ip<<16>>24, ip<<24>>24) return fmt.Sprintf("%d.%d.%d.%d", ip>>24, ip<<8>>24, ip<<16>>24, ip<<24>>24)
} }
// SignStrBuild
func MapToRawStr(data map[string]string) string {
str := ""
if len(data) > 0 {
keys := make([]string, 0)
for k, _ := range data {
if k != "sign" && k != "encode" && k != "v" {
keys = append(keys, k)
}
}
sort.Strings(keys)
//
for _, k := range keys {
if data[k] != "" {
if str == "" {
str = fmt.Sprintf("%s=%s", k, url.QueryEscape(strings.Replace(data[k], " ", "+", -1)))
} else {
str = fmt.Sprintf("%s&%s=%s", str, k, url.QueryEscape(strings.Replace(data[k], " ", "+", -1)))
}
}
}
}
return str
}
// GbkToUtf8 GBK转UTF-8 // GbkToUtf8 GBK转UTF-8
func GbkToUtf8(s []byte) ([]byte, error) { func GbkToUtf8(s []byte) ([]byte, error) {
reader := transform.NewReader(bytes.NewReader(s), simplifiedchinese.GBK.NewDecoder()) reader := transform.NewReader(bytes.NewReader(s), simplifiedchinese.GBK.NewDecoder())

View File

@ -27,7 +27,6 @@ func Get(apiUrl string, parm map[string]string, header map[string]string, isHttp
} }
apiUrl = fmt.Sprintf("%s%s", apiUrl, p) apiUrl = fmt.Sprintf("%s%s", apiUrl, p)
} }
client := &http.Client{} client := &http.Client{}
if isHttps { if isHttps {
@ -35,8 +34,10 @@ func Get(apiUrl string, parm map[string]string, header map[string]string, isHttp
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
} }
} }
reqest, _ := http.NewRequest("GET", apiUrl, nil) reqest, err := http.NewRequest("GET", apiUrl, nil)
if err != nil {
return nil, err
}
for k, v := range header { for k, v := range header {
reqest.Header.Set(k, v) reqest.Header.Set(k, v)
} }
@ -142,3 +143,43 @@ func GetRemoteIP(r *http.Request) string {
return strings.Split(addr, ":")[0] return strings.Split(addr, ":")[0]
} }
// ParseQuery 参数解析兼容部分字段有encode部分没encode的情况
func ParseQuery(query string) (m url.Values, err error) {
m = make(url.Values)
for query != "" {
key := query
if i := strings.IndexAny(key, "&"); i >= 0 {
key, query = key[:i], key[i+1:]
} else {
query = ""
}
if key == "" {
continue
}
value := ""
if i := strings.Index(key, "="); i >= 0 {
key, value = key[:i], key[i+1:]
}
key, err1 := url.QueryUnescape(key)
if err1 != nil {
if err == nil {
err = err1
}
continue
}
value1, err1 := url.QueryUnescape(value)
if err1 != nil {
if !strings.HasPrefix(err1.Error(), "invalid URL escape") {
if err == nil {
err = err1
}
continue
}
m[key] = append(m[key], value)
} else {
m[key] = append(m[key], value1)
}
}
return m, err
}

View File

@ -4,6 +4,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"net/http" "net/http"
"fmt"
) )
// buildLuaResponse构造Lua响应结果 // buildLuaResponse构造Lua响应结果
@ -52,6 +53,11 @@ func BuildLuaResponse(m interface{}) string {
vStr = "{" + Substr(vStr, 1) + "}" vStr = "{" + Substr(vStr, 1) + "}"
case string: case string:
vStr = `"` + strings.Replace(v, `"`, `\"`, -1) + `"` vStr = `"` + strings.Replace(v, `"`, `\"`, -1) + `"`
case map[string]interface{}:
for ks, vs := range v {
vStr += `,` + ks + `=` + `"`+strings.Replace(fmt.Sprint(vs), `"`, `\"`, -1)+`"`
}
vStr = "{" + Substr(vStr, 1) + "}"
default: default:
if vv, ok := v.(map[interface{}]interface{}); ok { if vv, ok := v.(map[interface{}]interface{}); ok {
vStr = BuildLuaResponse(vv) vStr = BuildLuaResponse(vv)

View File

@ -12,12 +12,28 @@ const (
regEmail = `^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$` regEmail = `^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$`
regPhone = `^((\d3)|(\d{3}\-))?13[0-9]\d{8}|14[0-9]\d{8}|15[0-9]\d{8}|17[0-9]\d{8}|18[0-9]\d{8}` regPhone = `^((\d3)|(\d{3}\-))?13[0-9]\d{8}|14[0-9]\d{8}|15[0-9]\d{8}|17[0-9]\d{8}|18[0-9]\d{8}`
regUrl = `^((https?|ftp|news|http):\/\/)?([a-z]([a-z0-9\-]*[\.。])+([a-z]{2}|aero|arpa|biz|com|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel)|(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))(\/[a-z0-9_\-\.~]+)*(\/([a-z0-9_\-\.]*)(\?[a-z0-9+_\-\.%=&]*)?)?(#[a-z][a-z0-9_]*)?$` regUrl = `^((https?|ftp|news|http):\/\/)?([a-z]([a-z0-9\-]*[\.。])+([a-z]{2}|aero|arpa|biz|com|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel)|(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))(\/[a-z0-9_\-\.~]+)*(\/([a-z0-9_\-\.]*)(\?[a-z0-9+_\-\.%=&]*)?)?(#[a-z][a-z0-9_]*)?$`
regGuid = `[a-zA-Z0-9-_]{0,40}` regGuid = `[a-zA-Z0-9-_]{1,40}`
regDescription = `^{0,64}$` regDescription = `^{0,64}$`
regOutTypeDescription = `^{0,20}$` regOutTypeDescription = `^{0,20}$`
regMac = `^{0,40}$` regMac = `^{0,40}$`
regTradeNo = `^[a-zA-Z0-9_-]{1,40}$` regTradeNo = `^[a-zA-Z0-9_-]{1,40}$`
regAttach = `^{0,127}$` regAttach = `^{0,127}$`
// LT
regID = `^[0-9]{0,11}$`
regTitle = `^[\s\S]{0,40}$`
regIntro = `^[\s\S]{0,120}$`
regHash = `^[\S]{0,160}$`
reqAuthorName = `^{0,60}$`
reqAtType = `^[1-7]{1}$`
reqActionListAtType = `^[1,3]{1}$`
regContent = `^[\s\S]{0,255}$`
reqSrcType = `^[1,2,3]{1}$`
reqCommentActionAtType = `^[1,2,6]{1}$`
reqUserActionAtType = `^[1,2,3,4]{1}$`
reqKeyword = `^.{0,40}$`
regReason = `^[\s\S]{0,140}$`
regUserSuggestTitle = `^[\s\S]{0,120}$`
) )
func CheckString(data string, pat string) bool { func CheckString(data string, pat string) bool {
@ -87,3 +103,73 @@ func CheckTradeNo(tradeNo string) bool {
func CheckAttach(attach string) bool { func CheckAttach(attach string) bool {
return CheckString(attach, regAttach) return CheckString(attach, regAttach)
} }
// 检测资源id
func CheckID(anchorId string) bool {
return CheckString(anchorId, regID)
}
// 检测资源title
func CheckTitle(title string) bool {
return CheckString(title, regTitle)
}
// 检测资源intro
func CheckIntro(intro string) bool {
return CheckString(intro, regIntro)
}
// 检测资源Hash
func CheckHash(hash string) bool {
return CheckString(hash, regHash)
}
// 检测资源AuthorName
func CheckAuthorName(authorName string) bool {
return CheckString(authorName, reqAuthorName)
}
// 检测资源atType
func CheckAtType(atType string) bool {
return CheckString(atType, reqAtType)
}
// 检测资源atType
func CheckActionListAtType(atType string) bool {
return CheckString(atType, reqActionListAtType)
}
// 检测资源atType
func CheckContent(content string) bool {
return CheckString(content, regContent)
}
// 检测资源atType
func CheckSrcType(srcType string) bool {
return CheckString(srcType, reqSrcType)
}
// 检测资源atType
func CheckCommentActionAtType(atType string) bool {
return CheckString(atType, reqCommentActionAtType)
}
// 检测资源atType
func CheckUserActionAtType(atType string) bool {
return CheckString(atType, reqUserActionAtType)
}
// 检测资源keyword
func CheckKeyword(keyword string) bool {
return CheckString(keyword, reqKeyword)
}
// 检测资源Reason
func CheckReason(reason string) bool {
return CheckString(reason, regReason)
}
// 检测资源SuggestTitle
func CheckSuggestTitle(title string) bool {
return CheckString(title, regUserSuggestTitle)
}

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"log" "log"
"math/rand" "math/rand"
"net"
"net/url" "net/url"
"reflect" "reflect"
"strconv" "strconv"
@ -355,10 +356,22 @@ func LenSyncMap(m *sync.Map) int {
return length return length
} }
// 模拟三元操作符 // Ternary 模拟三元操作符
func Ternary(b bool, trueVal, falseVal interface{}) interface{} { func Ternary(b bool, trueVal, falseVal interface{}) interface{} {
if b { if b {
return trueVal return trueVal
} }
return falseVal return falseVal
} }
// GetMacAddr 获取本地mac地址
func GetLocalMacAddr() ([]byte, error) {
// 获取本机的MAC地址
interfaces, err := net.Interfaces()
if err != nil || len(interfaces) == 0 {
return nil, err
}
return interfaces[0].HardwareAddr, nil
}

View File

@ -29,24 +29,19 @@ var driverInstanceNoProcess = &Driver{processQueryText: false}
func init() { func init() {
sql.Register("mssql", driverInstance) sql.Register("mssql", driverInstance)
sql.Register("sqlserver", driverInstanceNoProcess) sql.Register("sqlserver", driverInstanceNoProcess)
createDialer = func(p *connectParams) dialer { createDialer = func(p *connectParams) Dialer {
return tcpDialer{&net.Dialer{KeepAlive: p.keepAlive}} return netDialer{&net.Dialer{KeepAlive: p.keepAlive}}
} }
} }
// Abstract the dialer for testing and for non-TCP based connections. var createDialer func(p *connectParams) Dialer
type dialer interface {
Dial(ctx context.Context, addr string) (net.Conn, error)
}
var createDialer func(p *connectParams) dialer type netDialer struct {
type tcpDialer struct {
nd *net.Dialer nd *net.Dialer
} }
func (d tcpDialer) Dial(ctx context.Context, addr string) (net.Conn, error) { func (d netDialer) DialContext(ctx context.Context, network string, addr string) (net.Conn, error) {
return d.nd.DialContext(ctx, "tcp", addr) return d.nd.DialContext(ctx, network, addr)
} }
type Driver struct { type Driver struct {
@ -125,6 +120,21 @@ type Connector struct {
// SessionInitSQL is optional. The session will be reset even if // SessionInitSQL is optional. The session will be reset even if
// SessionInitSQL is empty. // SessionInitSQL is empty.
SessionInitSQL string SessionInitSQL string
// Dialer sets a custom dialer for all network operations.
// If Dialer is not set, normal net dialers are used.
Dialer Dialer
}
type Dialer interface {
DialContext(ctx context.Context, network string, addr string) (net.Conn, error)
}
func (c *Connector) getDialer(p *connectParams) Dialer {
if c != nil && c.Dialer != nil {
return c.Dialer
}
return createDialer(p)
} }
type Conn struct { type Conn struct {
@ -310,12 +320,12 @@ func (d *Driver) open(ctx context.Context, dsn string) (*Conn, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return d.connect(ctx, params) return d.connect(ctx, nil, params)
} }
// connect to the server, using the provided context for dialing only. // connect to the server, using the provided context for dialing only.
func (d *Driver) connect(ctx context.Context, params connectParams) (*Conn, error) { func (d *Driver) connect(ctx context.Context, c *Connector, params connectParams) (*Conn, error) {
sess, err := connect(ctx, d.log, params) sess, err := connect(ctx, c, d.log, params)
if err != nil { if err != nil {
// main server failed, try fail-over partner // main server failed, try fail-over partner
if params.failOverPartner == "" { if params.failOverPartner == "" {
@ -327,7 +337,7 @@ func (d *Driver) connect(ctx context.Context, params connectParams) (*Conn, erro
params.port = params.failOverPort params.port = params.failOverPort
} }
sess, err = connect(ctx, d.log, params) sess, err = connect(ctx, c, d.log, params)
if err != nil { if err != nil {
// fail-over partner also failed, now fail // fail-over partner also failed, now fail
return nil, err return nil, err
@ -335,6 +345,7 @@ func (d *Driver) connect(ctx context.Context, params connectParams) (*Conn, erro
} }
conn := &Conn{ conn := &Conn{
connector: c,
sess: sess, sess: sess,
transactionCtx: context.Background(), transactionCtx: context.Background(),
processQueryText: d.processQueryText, processQueryText: d.processQueryText,

View File

@ -34,10 +34,7 @@ func (c *Conn) ResetSession(ctx context.Context) error {
// Connect to the server and return a TDS connection. // Connect to the server and return a TDS connection.
func (c *Connector) Connect(ctx context.Context) (driver.Conn, error) { func (c *Connector) Connect(ctx context.Context) (driver.Conn, error) {
conn, err := c.driver.connect(ctx, c.params) conn, err := c.driver.connect(ctx, c, c.params)
if conn != nil {
conn.connector = c
}
if err == nil { if err == nil {
err = conn.ResetSession(ctx) err = conn.ResetSession(ctx)
} }

View File

@ -50,12 +50,11 @@ func parseInstances(msg []byte) map[string]map[string]string {
return results return results
} }
func getInstances(ctx context.Context, address string) (map[string]map[string]string, error) { func getInstances(ctx context.Context, d Dialer, address string) (map[string]map[string]string, error) {
maxTime := 5 * time.Second maxTime := 5 * time.Second
dialer := &net.Dialer{ ctx, cancel := context.WithTimeout(ctx, maxTime)
Timeout: maxTime, defer cancel()
} conn, err := d.DialContext(ctx, "udp", address+":1434")
conn, err := dialer.DialContext(ctx, "udp", address+":1434")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1112,7 +1111,7 @@ type auth interface {
// SQL Server AlwaysOn Availability Group Listeners are bound by DNS to a // SQL Server AlwaysOn Availability Group Listeners are bound by DNS to a
// list of IP addresses. So if there is more than one, try them all and // list of IP addresses. So if there is more than one, try them all and
// use the first one that allows a connection. // use the first one that allows a connection.
func dialConnection(ctx context.Context, p connectParams) (conn net.Conn, err error) { func dialConnection(ctx context.Context, c *Connector, p connectParams) (conn net.Conn, err error) {
var ips []net.IP var ips []net.IP
ips, err = net.LookupIP(p.host) ips, err = net.LookupIP(p.host)
if err != nil { if err != nil {
@ -1123,9 +1122,9 @@ func dialConnection(ctx context.Context, p connectParams) (conn net.Conn, err er
ips = []net.IP{ip} ips = []net.IP{ip}
} }
if len(ips) == 1 { if len(ips) == 1 {
d := createDialer(&p) d := c.getDialer(&p)
addr := net.JoinHostPort(ips[0].String(), strconv.Itoa(int(p.port))) addr := net.JoinHostPort(ips[0].String(), strconv.Itoa(int(p.port)))
conn, err = d.Dial(ctx, addr) conn, err = d.DialContext(ctx, "tcp", addr)
} else { } else {
//Try Dials in parallel to avoid waiting for timeouts. //Try Dials in parallel to avoid waiting for timeouts.
@ -1134,9 +1133,9 @@ func dialConnection(ctx context.Context, p connectParams) (conn net.Conn, err er
portStr := strconv.Itoa(int(p.port)) portStr := strconv.Itoa(int(p.port))
for _, ip := range ips { for _, ip := range ips {
go func(ip net.IP) { go func(ip net.IP) {
d := createDialer(&p) d := c.getDialer(&p)
addr := net.JoinHostPort(ip.String(), portStr) addr := net.JoinHostPort(ip.String(), portStr)
conn, err := d.Dial(ctx, addr) conn, err := d.DialContext(ctx, "tcp", addr)
if err == nil { if err == nil {
connChan <- conn connChan <- conn
} else { } else {
@ -1174,7 +1173,7 @@ func dialConnection(ctx context.Context, p connectParams) (conn net.Conn, err er
return conn, err return conn, err
} }
func connect(ctx context.Context, log optionalLogger, p connectParams) (res *tdsSession, err error) { func connect(ctx context.Context, c *Connector, log optionalLogger, p connectParams) (res *tdsSession, err error) {
dialCtx := ctx dialCtx := ctx
if p.dial_timeout > 0 { if p.dial_timeout > 0 {
var cancel func() var cancel func()
@ -1184,7 +1183,8 @@ func connect(ctx context.Context, log optionalLogger, p connectParams) (res *tds
// if instance is specified use instance resolution service // if instance is specified use instance resolution service
if p.instance != "" { if p.instance != "" {
p.instance = strings.ToUpper(p.instance) p.instance = strings.ToUpper(p.instance)
instances, err := getInstances(dialCtx, p.host) d := c.getDialer(&p)
instances, err := getInstances(dialCtx, d, p.host)
if err != nil { if err != nil {
f := "Unable to get instances from Sql Server Browser on host %v: %v" f := "Unable to get instances from Sql Server Browser on host %v: %v"
return nil, fmt.Errorf(f, p.host, err.Error()) return nil, fmt.Errorf(f, p.host, err.Error())
@ -1202,7 +1202,7 @@ func connect(ctx context.Context, log optionalLogger, p connectParams) (res *tds
} }
initiate_connection: initiate_connection:
conn, err := dialConnection(dialCtx, p) conn, err := dialConnection(dialCtx, c, p)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -116,25 +116,23 @@ func resizeHorizontal(img image.Image, width int, filter ResampleFilter) *image.
for y := range ys { for y := range ys {
src.scan(0, y, src.w, y+1, scanLine) src.scan(0, y, src.w, y+1, scanLine)
j0 := y * dst.Stride j0 := y * dst.Stride
for x := range weights { for x := 0; x < width; x++ {
var r, g, b, a float64 var r, g, b, a float64
for _, w := range weights[x] { for _, w := range weights[x] {
i := w.index * 4 i := w.index * 4
s := scanLine[i : i+4 : i+4] aw := float64(scanLine[i+3]) * w.weight
aw := float64(s[3]) * w.weight r += float64(scanLine[i+0]) * aw
r += float64(s[0]) * aw g += float64(scanLine[i+1]) * aw
g += float64(s[1]) * aw b += float64(scanLine[i+2]) * aw
b += float64(s[2]) * aw
a += aw a += aw
} }
if a != 0 { if a != 0 {
aInv := 1 / a aInv := 1 / a
j := j0 + x*4 j := j0 + x*4
d := dst.Pix[j : j+4 : j+4] dst.Pix[j+0] = clamp(r * aInv)
d[0] = clamp(r * aInv) dst.Pix[j+1] = clamp(g * aInv)
d[1] = clamp(g * aInv) dst.Pix[j+2] = clamp(b * aInv)
d[2] = clamp(b * aInv) dst.Pix[j+3] = clamp(a)
d[3] = clamp(a)
} }
} }
} }
@ -150,25 +148,23 @@ func resizeVertical(img image.Image, height int, filter ResampleFilter) *image.N
scanLine := make([]uint8, src.h*4) scanLine := make([]uint8, src.h*4)
for x := range xs { for x := range xs {
src.scan(x, 0, x+1, src.h, scanLine) src.scan(x, 0, x+1, src.h, scanLine)
for y := range weights { for y := 0; y < height; y++ {
var r, g, b, a float64 var r, g, b, a float64
for _, w := range weights[y] { for _, w := range weights[y] {
i := w.index * 4 i := w.index * 4
s := scanLine[i : i+4 : i+4] aw := float64(scanLine[i+3]) * w.weight
aw := float64(s[3]) * w.weight r += float64(scanLine[i+0]) * aw
r += float64(s[0]) * aw g += float64(scanLine[i+1]) * aw
g += float64(s[1]) * aw b += float64(scanLine[i+2]) * aw
b += float64(s[2]) * aw
a += aw a += aw
} }
if a != 0 { if a != 0 {
aInv := 1 / a aInv := 1 / a
j := y*dst.Stride + x*4 j := y*dst.Stride + x*4
d := dst.Pix[j : j+4 : j+4] dst.Pix[j+0] = clamp(r * aInv)
d[0] = clamp(r * aInv) dst.Pix[j+1] = clamp(g * aInv)
d[1] = clamp(g * aInv) dst.Pix[j+2] = clamp(b * aInv)
d[2] = clamp(b * aInv) dst.Pix[j+3] = clamp(a)
d[3] = clamp(a)
} }
} }
} }

View File

@ -33,36 +33,21 @@ func (s *scanner) scan(x1, y1, x2, y2 int, dst []uint8) {
size := (x2 - x1) * 4 size := (x2 - x1) * 4
j := 0 j := 0
i := y1*img.Stride + x1*4 i := y1*img.Stride + x1*4
if size == 4 {
for y := y1; y < y2; y++ {
d := dst[j : j+4 : j+4]
s := img.Pix[i : i+4 : i+4]
d[0] = s[0]
d[1] = s[1]
d[2] = s[2]
d[3] = s[3]
j += size
i += img.Stride
}
} else {
for y := y1; y < y2; y++ { for y := y1; y < y2; y++ {
copy(dst[j:j+size], img.Pix[i:i+size]) copy(dst[j:j+size], img.Pix[i:i+size])
j += size j += size
i += img.Stride i += img.Stride
} }
}
case *image.NRGBA64: case *image.NRGBA64:
j := 0 j := 0
for y := y1; y < y2; y++ { for y := y1; y < y2; y++ {
i := y*img.Stride + x1*8 i := y*img.Stride + x1*8
for x := x1; x < x2; x++ { for x := x1; x < x2; x++ {
s := img.Pix[i : i+8 : i+8] dst[j+0] = img.Pix[i+0]
d := dst[j : j+4 : j+4] dst[j+1] = img.Pix[i+2]
d[0] = s[0] dst[j+2] = img.Pix[i+4]
d[1] = s[2] dst[j+3] = img.Pix[i+6]
d[2] = s[4]
d[3] = s[6]
j += 4 j += 4
i += 8 i += 8
} }
@ -73,31 +58,26 @@ func (s *scanner) scan(x1, y1, x2, y2 int, dst []uint8) {
for y := y1; y < y2; y++ { for y := y1; y < y2; y++ {
i := y*img.Stride + x1*4 i := y*img.Stride + x1*4
for x := x1; x < x2; x++ { for x := x1; x < x2; x++ {
d := dst[j : j+4 : j+4]
a := img.Pix[i+3] a := img.Pix[i+3]
switch a { switch a {
case 0: case 0:
d[0] = 0 dst[j+0] = 0
d[1] = 0 dst[j+1] = 0
d[2] = 0 dst[j+2] = 0
d[3] = a
case 0xff: case 0xff:
s := img.Pix[i : i+4 : i+4] dst[j+0] = img.Pix[i+0]
d[0] = s[0] dst[j+1] = img.Pix[i+1]
d[1] = s[1] dst[j+2] = img.Pix[i+2]
d[2] = s[2]
d[3] = a
default: default:
s := img.Pix[i : i+4 : i+4] r16 := uint16(img.Pix[i+0])
r16 := uint16(s[0]) g16 := uint16(img.Pix[i+1])
g16 := uint16(s[1]) b16 := uint16(img.Pix[i+2])
b16 := uint16(s[2])
a16 := uint16(a) a16 := uint16(a)
d[0] = uint8(r16 * 0xff / a16) dst[j+0] = uint8(r16 * 0xff / a16)
d[1] = uint8(g16 * 0xff / a16) dst[j+1] = uint8(g16 * 0xff / a16)
d[2] = uint8(b16 * 0xff / a16) dst[j+2] = uint8(b16 * 0xff / a16)
d[3] = a
} }
dst[j+3] = a
j += 4 j += 4
i += 4 i += 4
} }
@ -108,28 +88,26 @@ func (s *scanner) scan(x1, y1, x2, y2 int, dst []uint8) {
for y := y1; y < y2; y++ { for y := y1; y < y2; y++ {
i := y*img.Stride + x1*8 i := y*img.Stride + x1*8
for x := x1; x < x2; x++ { for x := x1; x < x2; x++ {
s := img.Pix[i : i+8 : i+8] a := img.Pix[i+6]
d := dst[j : j+4 : j+4]
a := s[6]
switch a { switch a {
case 0: case 0:
d[0] = 0 dst[j+0] = 0
d[1] = 0 dst[j+1] = 0
d[2] = 0 dst[j+2] = 0
case 0xff: case 0xff:
d[0] = s[0] dst[j+0] = img.Pix[i+0]
d[1] = s[2] dst[j+1] = img.Pix[i+2]
d[2] = s[4] dst[j+2] = img.Pix[i+4]
default: default:
r32 := uint32(s[0])<<8 | uint32(s[1]) r32 := uint32(img.Pix[i+0])<<8 | uint32(img.Pix[i+1])
g32 := uint32(s[2])<<8 | uint32(s[3]) g32 := uint32(img.Pix[i+2])<<8 | uint32(img.Pix[i+3])
b32 := uint32(s[4])<<8 | uint32(s[5]) b32 := uint32(img.Pix[i+4])<<8 | uint32(img.Pix[i+5])
a32 := uint32(s[6])<<8 | uint32(s[7]) a32 := uint32(img.Pix[i+6])<<8 | uint32(img.Pix[i+7])
d[0] = uint8((r32 * 0xffff / a32) >> 8) dst[j+0] = uint8((r32 * 0xffff / a32) >> 8)
d[1] = uint8((g32 * 0xffff / a32) >> 8) dst[j+1] = uint8((g32 * 0xffff / a32) >> 8)
d[2] = uint8((b32 * 0xffff / a32) >> 8) dst[j+2] = uint8((b32 * 0xffff / a32) >> 8)
} }
d[3] = a dst[j+3] = a
j += 4 j += 4
i += 8 i += 8
} }
@ -141,11 +119,10 @@ func (s *scanner) scan(x1, y1, x2, y2 int, dst []uint8) {
i := y*img.Stride + x1 i := y*img.Stride + x1
for x := x1; x < x2; x++ { for x := x1; x < x2; x++ {
c := img.Pix[i] c := img.Pix[i]
d := dst[j : j+4 : j+4] dst[j+0] = c
d[0] = c dst[j+1] = c
d[1] = c dst[j+2] = c
d[2] = c dst[j+3] = 0xff
d[3] = 0xff
j += 4 j += 4
i++ i++
} }
@ -157,11 +134,10 @@ func (s *scanner) scan(x1, y1, x2, y2 int, dst []uint8) {
i := y*img.Stride + x1*2 i := y*img.Stride + x1*2
for x := x1; x < x2; x++ { for x := x1; x < x2; x++ {
c := img.Pix[i] c := img.Pix[i]
d := dst[j : j+4 : j+4] dst[j+0] = c
d[0] = c dst[j+1] = c
d[1] = c dst[j+2] = c
d[2] = c dst[j+3] = 0xff
d[3] = 0xff
j += 4 j += 4
i += 2 i += 2
} }
@ -173,61 +149,52 @@ func (s *scanner) scan(x1, y1, x2, y2 int, dst []uint8) {
x2 += img.Rect.Min.X x2 += img.Rect.Min.X
y1 += img.Rect.Min.Y y1 += img.Rect.Min.Y
y2 += img.Rect.Min.Y y2 += img.Rect.Min.Y
hy := img.Rect.Min.Y / 2
hx := img.Rect.Min.X / 2
for y := y1; y < y2; y++ { for y := y1; y < y2; y++ {
iy := (y-img.Rect.Min.Y)*img.YStride + (x1 - img.Rect.Min.X) iy := (y-img.Rect.Min.Y)*img.YStride + (x1 - img.Rect.Min.X)
var yBase int
switch img.SubsampleRatio {
case image.YCbCrSubsampleRatio444, image.YCbCrSubsampleRatio422:
yBase = (y - img.Rect.Min.Y) * img.CStride
case image.YCbCrSubsampleRatio420, image.YCbCrSubsampleRatio440:
yBase = (y/2 - hy) * img.CStride
}
for x := x1; x < x2; x++ { for x := x1; x < x2; x++ {
var ic int var ic int
switch img.SubsampleRatio { switch img.SubsampleRatio {
case image.YCbCrSubsampleRatio444, image.YCbCrSubsampleRatio440: case image.YCbCrSubsampleRatio444:
ic = yBase + (x - img.Rect.Min.X) ic = (y-img.Rect.Min.Y)*img.CStride + (x - img.Rect.Min.X)
case image.YCbCrSubsampleRatio422, image.YCbCrSubsampleRatio420: case image.YCbCrSubsampleRatio422:
ic = yBase + (x/2 - hx) ic = (y-img.Rect.Min.Y)*img.CStride + (x/2 - img.Rect.Min.X/2)
case image.YCbCrSubsampleRatio420:
ic = (y/2-img.Rect.Min.Y/2)*img.CStride + (x/2 - img.Rect.Min.X/2)
case image.YCbCrSubsampleRatio440:
ic = (y/2-img.Rect.Min.Y/2)*img.CStride + (x - img.Rect.Min.X)
default: default:
ic = img.COffset(x, y) ic = img.COffset(x, y)
} }
yy1 := int32(img.Y[iy]) * 0x10101 yy := int(img.Y[iy])
cb1 := int32(img.Cb[ic]) - 128 cb := int(img.Cb[ic]) - 128
cr1 := int32(img.Cr[ic]) - 128 cr := int(img.Cr[ic]) - 128
r := yy1 + 91881*cr1 r := (yy<<16 + 91881*cr + 1<<15) >> 16
if uint32(r)&0xff000000 == 0 { if r > 0xff {
r >>= 16 r = 0xff
} else { } else if r < 0 {
r = ^(r >> 31) r = 0
} }
g := yy1 - 22554*cb1 - 46802*cr1 g := (yy<<16 - 22554*cb - 46802*cr + 1<<15) >> 16
if uint32(g)&0xff000000 == 0 { if g > 0xff {
g >>= 16 g = 0xff
} else { } else if g < 0 {
g = ^(g >> 31) g = 0
} }
b := yy1 + 116130*cb1 b := (yy<<16 + 116130*cb + 1<<15) >> 16
if uint32(b)&0xff000000 == 0 { if b > 0xff {
b >>= 16 b = 0xff
} else { } else if b < 0 {
b = ^(b >> 31) b = 0
} }
d := dst[j : j+4 : j+4] dst[j+0] = uint8(r)
d[0] = uint8(r) dst[j+1] = uint8(g)
d[1] = uint8(g) dst[j+2] = uint8(b)
d[2] = uint8(b) dst[j+3] = 0xff
d[3] = 0xff
iy++ iy++
j += 4 j += 4
@ -240,11 +207,10 @@ func (s *scanner) scan(x1, y1, x2, y2 int, dst []uint8) {
i := y*img.Stride + x1 i := y*img.Stride + x1
for x := x1; x < x2; x++ { for x := x1; x < x2; x++ {
c := s.palette[img.Pix[i]] c := s.palette[img.Pix[i]]
d := dst[j : j+4 : j+4] dst[j+0] = c.R
d[0] = c.R dst[j+1] = c.G
d[1] = c.G dst[j+2] = c.B
d[2] = c.B dst[j+3] = c.A
d[3] = c.A
j += 4 j += 4
i++ i++
} }
@ -260,23 +226,22 @@ func (s *scanner) scan(x1, y1, x2, y2 int, dst []uint8) {
for y := y1; y < y2; y++ { for y := y1; y < y2; y++ {
for x := x1; x < x2; x++ { for x := x1; x < x2; x++ {
r16, g16, b16, a16 := s.image.At(x, y).RGBA() r16, g16, b16, a16 := s.image.At(x, y).RGBA()
d := dst[j : j+4 : j+4]
switch a16 { switch a16 {
case 0xffff: case 0xffff:
d[0] = uint8(r16 >> 8) dst[j+0] = uint8(r16 >> 8)
d[1] = uint8(g16 >> 8) dst[j+1] = uint8(g16 >> 8)
d[2] = uint8(b16 >> 8) dst[j+2] = uint8(b16 >> 8)
d[3] = 0xff dst[j+3] = 0xff
case 0: case 0:
d[0] = 0 dst[j+0] = 0
d[1] = 0 dst[j+1] = 0
d[2] = 0 dst[j+2] = 0
d[3] = 0 dst[j+3] = 0
default: default:
d[0] = uint8(((r16 * 0xffff) / a16) >> 8) dst[j+0] = uint8(((r16 * 0xffff) / a16) >> 8)
d[1] = uint8(((g16 * 0xffff) / a16) >> 8) dst[j+1] = uint8(((g16 * 0xffff) / a16) >> 8)
d[2] = uint8(((b16 * 0xffff) / a16) >> 8) dst[j+2] = uint8(((b16 * 0xffff) / a16) >> 8)
d[3] = uint8(a16 >> 8) dst[j+3] = uint8(a16 >> 8)
} }
j += 4 j += 4
} }

View File

@ -1,9 +1,7 @@
GO ?= go
GOFMT ?= gofmt "-s" GOFMT ?= gofmt "-s"
PACKAGES ?= $(shell $(GO) list ./... | grep -v /vendor/) PACKAGES ?= $(shell go list ./... | grep -v /vendor/)
VETPACKAGES ?= $(shell $(GO) list ./... | grep -v /vendor/ | grep -v /examples/) VETPACKAGES ?= $(shell go list ./... | grep -v /vendor/ | grep -v /examples/)
GOFILES := $(shell find . -name "*.go" -type f -not -path "./vendor/*") GOFILES := $(shell find . -name "*.go" -type f -not -path "./vendor/*")
TESTFOLDER := $(shell $(GO) list ./... | grep -E 'gin$$|binding$$|render$$' | grep -v examples)
all: install all: install
@ -12,19 +10,7 @@ install: deps
.PHONY: test .PHONY: test
test: test:
echo "mode: count" > coverage.out sh coverage.sh
for d in $(TESTFOLDER); do \
$(GO) test -v -covermode=count -coverprofile=profile.out $$d > tmp.out; \
cat tmp.out; \
if grep -q "^--- FAIL" tmp.out; then \
rm tmp.out; \
exit 1;\
fi; \
if [ -f profile.out ]; then \
cat profile.out | grep -v "mode:" >> coverage.out; \
rm profile.out; \
fi; \
done
.PHONY: fmt .PHONY: fmt
fmt: fmt:
@ -32,6 +18,7 @@ fmt:
.PHONY: fmt-check .PHONY: fmt-check
fmt-check: fmt-check:
# get all go files and run go fmt on them
@diff=$$($(GOFMT) -d $(GOFILES)); \ @diff=$$($(GOFMT) -d $(GOFILES)); \
if [ -n "$$diff" ]; then \ if [ -n "$$diff" ]; then \
echo "Please run 'make fmt' and commit the result:"; \ echo "Please run 'make fmt' and commit the result:"; \
@ -40,14 +27,14 @@ fmt-check:
fi; fi;
vet: vet:
$(GO) vet $(VETPACKAGES) go vet $(VETPACKAGES)
deps: deps:
@hash govendor > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ @hash govendor > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/kardianos/govendor; \ go get -u github.com/kardianos/govendor; \
fi fi
@hash embedmd > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ @hash embedmd > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/campoy/embedmd; \ go get -u github.com/campoy/embedmd; \
fi fi
embedmd: embedmd:
@ -56,26 +43,20 @@ embedmd:
.PHONY: lint .PHONY: lint
lint: lint:
@hash golint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ @hash golint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u golang.org/x/lint/golint; \ go get -u github.com/golang/lint/golint; \
fi fi
for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done; for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done;
.PHONY: misspell-check .PHONY: misspell-check
misspell-check: misspell-check:
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ @hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/client9/misspell/cmd/misspell; \ go get -u github.com/client9/misspell/cmd/misspell; \
fi fi
misspell -error $(GOFILES) misspell -error $(GOFILES)
.PHONY: misspell .PHONY: misspell
misspell: misspell:
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ @hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/client9/misspell/cmd/misspell; \ go get -u github.com/client9/misspell/cmd/misspell; \
fi fi
misspell -w $(GOFILES) misspell -w $(GOFILES)
.PHONY: tools
tools:
go install golang.org/x/lint/golint; \
go install github.com/client9/misspell/cmd/misspell; \
go install github.com/campoy/embedmd;

View File

@ -9,7 +9,6 @@
[![Join the chat at https://gitter.im/gin-gonic/gin](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gin-gonic/gin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat at https://gitter.im/gin-gonic/gin](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gin-gonic/gin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Sourcegraph](https://sourcegraph.com/github.com/gin-gonic/gin/-/badge.svg)](https://sourcegraph.com/github.com/gin-gonic/gin?badge) [![Sourcegraph](https://sourcegraph.com/github.com/gin-gonic/gin/-/badge.svg)](https://sourcegraph.com/github.com/gin-gonic/gin?badge)
[![Open Source Helpers](https://www.codetriage.com/gin-gonic/gin/badges/users.svg)](https://www.codetriage.com/gin-gonic/gin) [![Open Source Helpers](https://www.codetriage.com/gin-gonic/gin/badges/users.svg)](https://www.codetriage.com/gin-gonic/gin)
[![Release](https://img.shields.io/github/release/gin-gonic/gin.svg?style=flat-square)](https://github.com/gin-gonic/gin/releases)
Gin is a web framework written in Go (Golang). It features a martini-like API with much better performance, up to 40 times faster thanks to [httprouter](https://github.com/julienschmidt/httprouter). If you need performance and good productivity, you will love Gin. Gin is a web framework written in Go (Golang). It features a martini-like API with much better performance, up to 40 times faster thanks to [httprouter](https://github.com/julienschmidt/httprouter). If you need performance and good productivity, you will love Gin.
@ -39,10 +38,9 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi
- [Custom Validators](#custom-validators) - [Custom Validators](#custom-validators)
- [Only Bind Query String](#only-bind-query-string) - [Only Bind Query String](#only-bind-query-string)
- [Bind Query String or Post Data](#bind-query-string-or-post-data) - [Bind Query String or Post Data](#bind-query-string-or-post-data)
- [Bind Uri](#bind-uri)
- [Bind HTML checkboxes](#bind-html-checkboxes) - [Bind HTML checkboxes](#bind-html-checkboxes)
- [Multipart/Urlencoded binding](#multiparturlencoded-binding) - [Multipart/Urlencoded binding](#multiparturlencoded-binding)
- [XML, JSON, YAML and ProtoBuf rendering](#xml-json-yaml-and-protobuf-rendering) - [XML, JSON and YAML rendering](#xml-json-and-yaml-rendering)
- [JSONP rendering](#jsonp) - [JSONP rendering](#jsonp)
- [Serving static files](#serving-static-files) - [Serving static files](#serving-static-files)
- [Serving data from reader](#serving-data-from-reader) - [Serving data from reader](#serving-data-from-reader)
@ -60,10 +58,8 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi
- [Bind form-data request with custom struct](#bind-form-data-request-with-custom-struct) - [Bind form-data request with custom struct](#bind-form-data-request-with-custom-struct)
- [Try to bind body into different structs](#try-to-bind-body-into-different-structs) - [Try to bind body into different structs](#try-to-bind-body-into-different-structs)
- [http2 server push](#http2-server-push) - [http2 server push](#http2-server-push)
- [Define format for the log of routes](#define-format-for-the-log-of-routes)
- [Set and get a cookie](#set-and-get-a-cookie)
- [Testing](#testing) - [Testing](#testing)
- [Users](#users) - [Users](#users--)
## Installation ## Installation
@ -104,7 +100,7 @@ $ mkdir -p $GOPATH/src/github.com/myusername/project && cd "$_"
```sh ```sh
$ govendor init $ govendor init
$ govendor fetch github.com/gin-gonic/gin@v1.3 $ govendor fetch github.com/gin-gonic/gin@v1.2
``` ```
4. Copy a starting template inside your project 4. Copy a starting template inside your project
@ -202,7 +198,7 @@ BenchmarkVulcan_GithubAll | 5000 | 394253 | 19894
## Build with [jsoniter](https://github.com/json-iterator/go) ## Build with [jsoniter](https://github.com/json-iterator/go)
Gin uses `encoding/json` as default json package but you can change to [jsoniter](https://github.com/json-iterator/go) by build from other tags. Gin use `encoding/json` as default json package but you can change to [jsoniter](https://github.com/json-iterator/go) by build from other tags.
```sh ```sh
$ go build -tags=jsoniter . $ go build -tags=jsoniter .
@ -530,7 +526,7 @@ func main() {
### Model binding and validation ### Model binding and validation
To bind a request body into a type, use model binding. We currently support binding of JSON, XML, YAML and standard form values (foo=bar&boo=baz). To bind a request body into a type, use model binding. We currently support binding of JSON, XML and standard form values (foo=bar&boo=baz).
Gin uses [**go-playground/validator.v8**](https://github.com/go-playground/validator) for validation. Check the full docs on tags usage [here](http://godoc.org/gopkg.in/go-playground/validator.v8#hdr-Baked_In_Validators_and_Tags). Gin uses [**go-playground/validator.v8**](https://github.com/go-playground/validator) for validation. Check the full docs on tags usage [here](http://godoc.org/gopkg.in/go-playground/validator.v8#hdr-Baked_In_Validators_and_Tags).
@ -538,10 +534,10 @@ Note that you need to set the corresponding binding tag on all fields you want t
Also, Gin provides two sets of methods for binding: Also, Gin provides two sets of methods for binding:
- **Type** - Must bind - **Type** - Must bind
- **Methods** - `Bind`, `BindJSON`, `BindXML`, `BindQuery`, `BindYAML` - **Methods** - `Bind`, `BindJSON`, `BindQuery`
- **Behavior** - These methods use `MustBindWith` under the hood. If there is a binding error, the request is aborted with `c.AbortWithError(400, err).SetType(ErrorTypeBind)`. This sets the response status code to 400 and the `Content-Type` header is set to `text/plain; charset=utf-8`. Note that if you try to set the response code after this, it will result in a warning `[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422`. If you wish to have greater control over the behavior, consider using the `ShouldBind` equivalent method. - **Behavior** - These methods use `MustBindWith` under the hood. If there is a binding error, the request is aborted with `c.AbortWithError(400, err).SetType(ErrorTypeBind)`. This sets the response status code to 400 and the `Content-Type` header is set to `text/plain; charset=utf-8`. Note that if you try to set the response code after this, it will result in a warning `[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422`. If you wish to have greater control over the behavior, consider using the `ShouldBind` equivalent method.
- **Type** - Should bind - **Type** - Should bind
- **Methods** - `ShouldBind`, `ShouldBindJSON`, `ShouldBindXML`, `ShouldBindQuery`, `ShouldBindYAML` - **Methods** - `ShouldBind`, `ShouldBindJSON`, `ShouldBindQuery`
- **Behavior** - These methods use `ShouldBindWith` under the hood. If there is a binding error, the error is returned and it is the developer's responsibility to handle the request and error appropriately. - **Behavior** - These methods use `ShouldBindWith` under the hood. If there is a binding error, the error is returned and it is the developer's responsibility to handle the request and error appropriately.
When using the Bind-method, Gin tries to infer the binder depending on the Content-Type header. If you are sure what you are binding, you can use `MustBindWith` or `ShouldBindWith`. When using the Bind-method, Gin tries to infer the binder depending on the Content-Type header. If you are sure what you are binding, you can use `MustBindWith` or `ShouldBindWith`.
@ -551,8 +547,8 @@ You can also specify that specific fields are required. If a field is decorated
```go ```go
// Binding from JSON // Binding from JSON
type Login struct { type Login struct {
User string `form:"user" json:"user" xml:"user" binding:"required"` User string `form:"user" json:"user" binding:"required"`
Password string `form:"password" json:"password" xml:"password" binding:"required"` Password string `form:"password" json:"password" binding:"required"`
} }
func main() { func main() {
@ -561,55 +557,30 @@ func main() {
// Example for binding JSON ({"user": "manu", "password": "123"}) // Example for binding JSON ({"user": "manu", "password": "123"})
router.POST("/loginJSON", func(c *gin.Context) { router.POST("/loginJSON", func(c *gin.Context) {
var json Login var json Login
if err := c.ShouldBindJSON(&json); err != nil { if err := c.ShouldBindJSON(&json); err == nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) if json.User == "manu" && json.Password == "123" {
return
}
if json.User != "manu" || json.Password != "123" {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
return
}
c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
}) } else {
// Example for binding XML (
// <?xml version="1.0" encoding="UTF-8"?>
// <root>
// <user>user</user>
// <password>123</user>
// </root>)
router.POST("/loginXML", func(c *gin.Context) {
var xml Login
if err := c.ShouldBindXML(&xml); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if xml.User != "manu" || xml.Password != "123" {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
return
} }
} else {
c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
}) })
// Example for binding a HTML form (user=manu&password=123) // Example for binding a HTML form (user=manu&password=123)
router.POST("/loginForm", func(c *gin.Context) { router.POST("/loginForm", func(c *gin.Context) {
var form Login var form Login
// This will infer what binder to use depending on the content-type header. // This will infer what binder to use depending on the content-type header.
if err := c.ShouldBind(&form); err != nil { if err := c.ShouldBind(&form); err == nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) if form.User == "manu" && form.Password == "123" {
return
}
if form.User != "manu" || form.Password != "123" {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
return
}
c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
} else {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
}
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
}) })
// Listen and serve on 0.0.0.0:8080 // Listen and serve on 0.0.0.0:8080
@ -661,7 +632,6 @@ import (
"gopkg.in/go-playground/validator.v8" "gopkg.in/go-playground/validator.v8"
) )
// Booking contains binded and validated data.
type Booking struct { type Booking struct {
CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"` CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"`
CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"` CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"`
@ -709,7 +679,7 @@ $ curl "localhost:8085/bookable?check_in=2018-03-08&check_out=2018-03-09"
{"error":"Key: 'Booking.CheckIn' Error:Field validation for 'CheckIn' failed on the 'bookabledate' tag"} {"error":"Key: 'Booking.CheckIn' Error:Field validation for 'CheckIn' failed on the 'bookabledate' tag"}
``` ```
[Struct level validations](https://github.com/go-playground/validator/releases/tag/v8.7) can also be registered this way. [Struct level validations](https://github.com/go-playground/validator/releases/tag/v8.7) can also be registed this way.
See the [struct-lvl-validation example](examples/struct-lvl-validations) to learn more. See the [struct-lvl-validation example](examples/struct-lvl-validations) to learn more.
### Only Bind Query String ### Only Bind Query String
@ -755,12 +725,9 @@ See the [detail information](https://github.com/gin-gonic/gin/issues/742#issueco
```go ```go
package main package main
import ( import "log"
"log" import "github.com/gin-gonic/gin"
"time" import "time"
"github.com/gin-gonic/gin"
)
type Person struct { type Person struct {
Name string `form:"name"` Name string `form:"name"`
@ -794,40 +761,6 @@ Test it with:
$ curl -X GET "localhost:8085/testing?name=appleboy&address=xyz&birthday=1992-03-15" $ curl -X GET "localhost:8085/testing?name=appleboy&address=xyz&birthday=1992-03-15"
``` ```
### Bind Uri
See the [detail information](https://github.com/gin-gonic/gin/issues/846).
```go
package main
import "github.com/gin-gonic/gin"
type Person struct {
ID string `uri:"id" binding:"required,uuid"`
Name string `uri:"name" binding:"required"`
}
func main() {
route := gin.Default()
route.GET("/:name/:id", func(c *gin.Context) {
var person Person
if err := c.ShouldBindUri(&person); err != nil {
c.JSON(400, gin.H{"msg": err})
return
}
c.JSON(200, gin.H{"name": person.Name, "uuid": person.ID})
})
route.Run(":8088")
}
```
Test it with:
```sh
$ curl -v localhost:8088/thinkerou/987fbc97-4bed-5078-9f07-9141ba07c9f3
$ curl -v localhost:8088/thinkerou/not-uuid
```
### Bind HTML checkboxes ### Bind HTML checkboxes
See the [detail information](https://github.com/gin-gonic/gin/issues/129#issuecomment-124260092) See the [detail information](https://github.com/gin-gonic/gin/issues/129#issuecomment-124260092)
@ -859,12 +792,12 @@ form.html
<form action="/" method="POST"> <form action="/" method="POST">
<p>Check some colors</p> <p>Check some colors</p>
<label for="red">Red</label> <label for="red">Red</label>
<input type="checkbox" name="colors[]" value="red" id="red"> <input type="checkbox" name="colors[]" value="red" id="red" />
<label for="green">Green</label> <label for="green">Green</label>
<input type="checkbox" name="colors[]" value="green" id="green"> <input type="checkbox" name="colors[]" value="green" id="green" />
<label for="blue">Blue</label> <label for="blue">Blue</label>
<input type="checkbox" name="colors[]" value="blue" id="blue"> <input type="checkbox" name="colors[]" value="blue" id="blue" />
<input type="submit"> <input type="submit" />
</form> </form>
``` ```
@ -913,7 +846,7 @@ Test it with:
$ curl -v --form user=user --form password=password http://localhost:8080/login $ curl -v --form user=user --form password=password http://localhost:8080/login
``` ```
### XML, JSON, YAML and ProtoBuf rendering ### XML, JSON and YAML rendering
```go ```go
func main() { func main() {
@ -947,19 +880,6 @@ func main() {
c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
}) })
r.GET("/someProtoBuf", func(c *gin.Context) {
reps := []int64{int64(1), int64(2)}
label := "test"
// The specific definition of protobuf is written in the testdata/protoexample file.
data := &protoexample.Test{
Label: &label,
Reps: reps,
}
// Note that data becomes binary data in the response
// Will output protoexample.Test protobuf serialized data
c.ProtoBuf(http.StatusOK, data)
})
// Listen and serve on 0.0.0.0:8080 // Listen and serve on 0.0.0.0:8080
r.Run(":8080") r.Run(":8080")
} }
@ -1033,34 +953,6 @@ func main() {
} }
``` ```
#### PureJSON
Normally, JSON replaces special HTML characters with their unicode entities, e.g. `<` becomes `\u003c`. If you want to encode such characters literally, you can use PureJSON instead.
This feature is unavailable in Go 1.6 and lower.
```go
func main() {
r := gin.Default()
// Serves unicode entities
r.GET("/json", func(c *gin.Context) {
c.JSON(200, gin.H{
"html": "<b>Hello, world!</b>",
})
})
// Serves literal characters
r.GET("/purejson", func(c *gin.Context) {
c.PureJSON(200, gin.H{
"html": "<b>Hello, world!</b>",
})
})
// listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
```
### Serving static files ### Serving static files
```go ```go
@ -1195,7 +1087,7 @@ You may use custom delims
```go ```go
r := gin.Default() r := gin.Default()
r.Delims("{[{", "}]}") r.Delims("{[{", "}]}")
r.LoadHTMLGlob("/path/to/templates") r.LoadHTMLGlob("/path/to/templates"))
``` ```
#### Custom Template Funcs #### Custom Template Funcs
@ -1757,11 +1649,11 @@ type StructX struct {
} }
type StructY struct { type StructY struct {
Y StructX `form:"name_y"` // HERE have form Y StructX `form:"name_y"` // HERE hava form
} }
type StructZ struct { type StructZ struct {
Z *StructZ `form:"name_z"` // HERE have form Z *StructZ `form:"name_z"` // HERE hava form
} }
``` ```
@ -1874,78 +1766,6 @@ func main() {
} }
``` ```
### Define format for the log of routes
The default log of routes is:
```
[GIN-debug] POST /foo --> main.main.func1 (3 handlers)
[GIN-debug] GET /bar --> main.main.func2 (3 handlers)
[GIN-debug] GET /status --> main.main.func3 (3 handlers)
```
If you want to log this information in given format (e.g. JSON, key values or something else), then you can define this format with `gin.DebugPrintRouteFunc`.
In the example below, we log all routes with standard log package but you can use another log tools that suits of your needs.
```go
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) {
log.Printf("endpoint %v %v %v %v\n", httpMethod, absolutePath, handlerName, nuHandlers)
}
r.POST("/foo", func(c *gin.Context) {
c.JSON(http.StatusOK, "foo")
})
r.GET("/bar", func(c *gin.Context) {
c.JSON(http.StatusOK, "bar")
})
r.GET("/status", func(c *gin.Context) {
c.JSON(http.StatusOK, "ok")
})
// Listen and Server in http://0.0.0.0:8080
r.Run()
}
```
### Set and get a cookie
```go
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
router.GET("/cookie", func(c *gin.Context) {
cookie, err := c.Cookie("gin_cookie")
if err != nil {
cookie = "NotSet"
c.SetCookie("gin_cookie", "test", 3600, "/", "localhost", false, true)
}
fmt.Printf("Cookie value: %s \n", cookie)
})
router.Run()
}
```
## Testing ## Testing
The `net/http/httptest` package is preferable way for HTTP testing. The `net/http/httptest` package is preferable way for HTTP testing.
@ -1996,9 +1816,5 @@ func TestPingRoute(t *testing.T) {
Awesome project lists using [Gin](https://github.com/gin-gonic/gin) web framework. Awesome project lists using [Gin](https://github.com/gin-gonic/gin) web framework.
* [drone](https://github.com/drone/drone): Drone is a Continuous Delivery platform built on Docker, written in Go. * [drone](https://github.com/drone/drone): Drone is a Continuous Delivery platform built on Docker, written in Go
* [gorush](https://github.com/appleboy/gorush): A push notification server written in Go. * [gorush](https://github.com/appleboy/gorush): A push notification server written in Go.
* [fnproject](https://github.com/fnproject/fn): The container native, cloud agnostic serverless platform.
* [photoprism](https://github.com/photoprism/photoprism): Personal photo management powered by Go and Google TensorFlow.
* [krakend](https://github.com/devopsfaith/krakend): Ultra performant API Gateway with middlewares.
* [picfit](https://github.com/thoas/picfit): An image resizing server written in Go.

View File

@ -18,7 +18,6 @@ const (
MIMEPROTOBUF = "application/x-protobuf" MIMEPROTOBUF = "application/x-protobuf"
MIMEMSGPACK = "application/x-msgpack" MIMEMSGPACK = "application/x-msgpack"
MIMEMSGPACK2 = "application/msgpack" MIMEMSGPACK2 = "application/msgpack"
MIMEYAML = "application/x-yaml"
) )
// Binding describes the interface which needs to be implemented for binding the // Binding describes the interface which needs to be implemented for binding the
@ -36,16 +35,9 @@ type BindingBody interface {
BindBody([]byte, interface{}) error BindBody([]byte, interface{}) error
} }
// BindingUri adds BindUri method to Binding. BindUri is similar with Bind,
// but it read the Params.
type BindingUri interface {
Name() string
BindUri(map[string][]string, interface{}) error
}
// StructValidator is the minimal interface which needs to be implemented in // StructValidator is the minimal interface which needs to be implemented in
// order for it to be used as the validator engine for ensuring the correctness // order for it to be used as the validator engine for ensuring the correctness
// of the request. Gin provides a default implementation for this using // of the reqest. Gin provides a default implementation for this using
// https://github.com/go-playground/validator/tree/v8.18.2. // https://github.com/go-playground/validator/tree/v8.18.2.
type StructValidator interface { type StructValidator interface {
// ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right. // ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right.
@ -76,8 +68,6 @@ var (
FormMultipart = formMultipartBinding{} FormMultipart = formMultipartBinding{}
ProtoBuf = protobufBinding{} ProtoBuf = protobufBinding{}
MsgPack = msgpackBinding{} MsgPack = msgpackBinding{}
YAML = yamlBinding{}
Uri = uriBinding{}
) )
// Default returns the appropriate Binding instance based on the HTTP method // Default returns the appropriate Binding instance based on the HTTP method
@ -96,8 +86,6 @@ func Default(method, contentType string) Binding {
return ProtoBuf return ProtoBuf
case MIMEMSGPACK, MIMEMSGPACK2: case MIMEMSGPACK, MIMEMSGPACK2:
return MsgPack return MsgPack
case MIMEYAML:
return YAML
default: //case MIMEPOSTForm, MIMEMultipartPOSTForm: default: //case MIMEPOSTForm, MIMEMultipartPOSTForm:
return Form return Form
} }

View File

@ -12,15 +12,7 @@ import (
"time" "time"
) )
func mapUri(ptr interface{}, m map[string][]string) error {
return mapFormByTag(ptr, m, "uri")
}
func mapForm(ptr interface{}, form map[string][]string) error { func mapForm(ptr interface{}, form map[string][]string) error {
return mapFormByTag(ptr, form, "form")
}
func mapFormByTag(ptr interface{}, form map[string][]string, tag string) error {
typ := reflect.TypeOf(ptr).Elem() typ := reflect.TypeOf(ptr).Elem()
val := reflect.ValueOf(ptr).Elem() val := reflect.ValueOf(ptr).Elem()
for i := 0; i < typ.NumField(); i++ { for i := 0; i < typ.NumField(); i++ {
@ -31,7 +23,7 @@ func mapFormByTag(ptr interface{}, form map[string][]string, tag string) error {
} }
structFieldKind := structField.Kind() structFieldKind := structField.Kind()
inputFieldName := typeField.Tag.Get(tag) inputFieldName := typeField.Tag.Get("form")
inputFieldNameList := strings.Split(inputFieldName, ",") inputFieldNameList := strings.Split(inputFieldName, ",")
inputFieldName = inputFieldNameList[0] inputFieldName = inputFieldNameList[0]
var defaultValue string var defaultValue string
@ -82,8 +74,7 @@ func mapFormByTag(ptr interface{}, form map[string][]string, tag string) error {
} }
} }
val.Field(i).Set(slice) val.Field(i).Set(slice)
continue } else {
}
if _, isTime := structField.Interface().(time.Time); isTime { if _, isTime := structField.Interface().(time.Time); isTime {
if err := setTimeField(inputValue[0], typeField, structField); err != nil { if err := setTimeField(inputValue[0], typeField, structField); err != nil {
return err return err
@ -94,6 +85,7 @@ func mapFormByTag(ptr interface{}, form map[string][]string, tag string) error {
return err return err
} }
} }
}
return nil return nil
} }
@ -186,7 +178,7 @@ func setFloatField(val string, bitSize int, field reflect.Value) error {
func setTimeField(val string, structField reflect.StructField, value reflect.Value) error { func setTimeField(val string, structField reflect.StructField, value reflect.Value) error {
timeFormat := structField.Tag.Get("time_format") timeFormat := structField.Tag.Get("time_format")
if timeFormat == "" { if timeFormat == "" {
timeFormat = time.RFC3339 return errors.New("Blank time format")
} }
if val == "" { if val == "" {

View File

@ -6,11 +6,10 @@ package binding
import ( import (
"bytes" "bytes"
"fmt"
"io" "io"
"net/http" "net/http"
"github.com/gin-gonic/gin/internal/json" "github.com/gin-gonic/gin/json"
) )
// EnableDecoderUseNumber is used to call the UseNumber method on the JSON // EnableDecoderUseNumber is used to call the UseNumber method on the JSON
@ -25,9 +24,6 @@ func (jsonBinding) Name() string {
} }
func (jsonBinding) Bind(req *http.Request, obj interface{}) error { func (jsonBinding) Bind(req *http.Request, obj interface{}) error {
if req == nil || req.Body == nil {
return fmt.Errorf("invalid request")
}
return decodeJSON(req.Body, obj) return decodeJSON(req.Body, obj)
} }

View File

@ -29,7 +29,7 @@ func (protobufBinding) BindBody(body []byte, obj interface{}) error {
if err := proto.Unmarshal(body, obj.(proto.Message)); err != nil { if err := proto.Unmarshal(body, obj.(proto.Message)); err != nil {
return err return err
} }
// Here it's same to return validate(obj), but util now we can't add // Here it's same to return validate(obj), but util now we cann't add
// `binding:""` to the struct which automatically generate by gen-proto // `binding:""` to the struct which automatically generate by gen-proto
return nil return nil
// return validate(obj) // return validate(obj)

View File

@ -31,7 +31,6 @@ const (
MIMEPlain = binding.MIMEPlain MIMEPlain = binding.MIMEPlain
MIMEPOSTForm = binding.MIMEPOSTForm MIMEPOSTForm = binding.MIMEPOSTForm
MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm
MIMEYAML = binding.MIMEYAML
BodyBytesKey = "_gin-gonic/gin/bodybyteskey" BodyBytesKey = "_gin-gonic/gin/bodybyteskey"
) )
@ -415,6 +414,7 @@ func (c *Context) PostFormArray(key string) []string {
// a boolean value whether at least one value exists for the given key. // a boolean value whether at least one value exists for the given key.
func (c *Context) GetPostFormArray(key string) ([]string, bool) { func (c *Context) GetPostFormArray(key string) ([]string, bool) {
req := c.Request req := c.Request
req.ParseForm()
req.ParseMultipartForm(c.engine.MaxMultipartMemory) req.ParseMultipartForm(c.engine.MaxMultipartMemory)
if values := req.PostForm[key]; len(values) > 0 { if values := req.PostForm[key]; len(values) > 0 {
return values, true return values, true
@ -437,6 +437,7 @@ func (c *Context) PostFormMap(key string) map[string]string {
// whether at least one value exists for the given key. // whether at least one value exists for the given key.
func (c *Context) GetPostFormMap(key string) (map[string]string, bool) { func (c *Context) GetPostFormMap(key string) (map[string]string, bool) {
req := c.Request req := c.Request
req.ParseForm()
req.ParseMultipartForm(c.engine.MaxMultipartMemory) req.ParseMultipartForm(c.engine.MaxMultipartMemory)
dicts, exist := c.get(req.PostForm, key) dicts, exist := c.get(req.PostForm, key)
@ -464,11 +465,6 @@ func (c *Context) get(m map[string][]string, key string) (map[string]string, boo
// FormFile returns the first file for the provided form key. // FormFile returns the first file for the provided form key.
func (c *Context) FormFile(name string) (*multipart.FileHeader, error) { func (c *Context) FormFile(name string) (*multipart.FileHeader, error) {
if c.Request.MultipartForm == nil {
if err := c.Request.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil {
return nil, err
}
}
_, fh, err := c.Request.FormFile(name) _, fh, err := c.Request.FormFile(name)
return fh, err return fh, err
} }
@ -515,23 +511,13 @@ func (c *Context) BindJSON(obj interface{}) error {
return c.MustBindWith(obj, binding.JSON) return c.MustBindWith(obj, binding.JSON)
} }
// BindXML is a shortcut for c.MustBindWith(obj, binding.BindXML).
func (c *Context) BindXML(obj interface{}) error {
return c.MustBindWith(obj, binding.XML)
}
// BindQuery is a shortcut for c.MustBindWith(obj, binding.Query). // BindQuery is a shortcut for c.MustBindWith(obj, binding.Query).
func (c *Context) BindQuery(obj interface{}) error { func (c *Context) BindQuery(obj interface{}) error {
return c.MustBindWith(obj, binding.Query) return c.MustBindWith(obj, binding.Query)
} }
// BindYAML is a shortcut for c.MustBindWith(obj, binding.YAML).
func (c *Context) BindYAML(obj interface{}) error {
return c.MustBindWith(obj, binding.YAML)
}
// MustBindWith binds the passed struct pointer using the specified binding engine. // MustBindWith binds the passed struct pointer using the specified binding engine.
// It will abort the request with HTTP 400 if any error occurs. // It will abort the request with HTTP 400 if any error ocurrs.
// See the binding package. // See the binding package.
func (c *Context) MustBindWith(obj interface{}, b binding.Binding) (err error) { func (c *Context) MustBindWith(obj interface{}, b binding.Binding) (err error) {
if err = c.ShouldBindWith(obj, b); err != nil { if err = c.ShouldBindWith(obj, b); err != nil {
@ -559,30 +545,11 @@ func (c *Context) ShouldBindJSON(obj interface{}) error {
return c.ShouldBindWith(obj, binding.JSON) return c.ShouldBindWith(obj, binding.JSON)
} }
// ShouldBindXML is a shortcut for c.ShouldBindWith(obj, binding.XML).
func (c *Context) ShouldBindXML(obj interface{}) error {
return c.ShouldBindWith(obj, binding.XML)
}
// ShouldBindQuery is a shortcut for c.ShouldBindWith(obj, binding.Query). // ShouldBindQuery is a shortcut for c.ShouldBindWith(obj, binding.Query).
func (c *Context) ShouldBindQuery(obj interface{}) error { func (c *Context) ShouldBindQuery(obj interface{}) error {
return c.ShouldBindWith(obj, binding.Query) return c.ShouldBindWith(obj, binding.Query)
} }
// ShouldBindYAML is a shortcut for c.ShouldBindWith(obj, binding.YAML).
func (c *Context) ShouldBindYAML(obj interface{}) error {
return c.ShouldBindWith(obj, binding.YAML)
}
// ShouldBindUri binds the passed struct pointer using the specified binding engine.
func (c *Context) ShouldBindUri(obj interface{}) error {
m := make(map[string][]string)
for _, v := range c.Params {
m[v.Key] = []string{v.Value}
}
return binding.Uri.BindUri(m, obj)
}
// ShouldBindWith binds the passed struct pointer using the specified binding engine. // ShouldBindWith binds the passed struct pointer using the specified binding engine.
// See the binding package. // See the binding package.
func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error { func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error {
@ -594,7 +561,9 @@ func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error {
// //
// NOTE: This method reads the body before binding. So you should use // NOTE: This method reads the body before binding. So you should use
// ShouldBindWith for better performance if you need to call only once. // ShouldBindWith for better performance if you need to call only once.
func (c *Context) ShouldBindBodyWith(obj interface{}, bb binding.BindingBody) (err error) { func (c *Context) ShouldBindBodyWith(
obj interface{}, bb binding.BindingBody,
) (err error) {
var body []byte var body []byte
if cb, ok := c.Get(BodyBytesKey); ok { if cb, ok := c.Get(BodyBytesKey); ok {
if cbb, ok := cb.([]byte); ok { if cbb, ok := cb.([]byte); ok {
@ -686,9 +655,9 @@ func (c *Context) Status(code int) {
func (c *Context) Header(key, value string) { func (c *Context) Header(key, value string) {
if value == "" { if value == "" {
c.Writer.Header().Del(key) c.Writer.Header().Del(key)
return } else {
}
c.Writer.Header().Set(key, value) c.Writer.Header().Set(key, value)
}
} }
// GetHeader returns value from request headers. // GetHeader returns value from request headers.
@ -732,7 +701,6 @@ func (c *Context) Cookie(name string) (string, error) {
return val, nil return val, nil
} }
// Render writes the response headers and calls render.Render to render data.
func (c *Context) Render(code int, r render.Render) { func (c *Context) Render(code int, r render.Render) {
c.Status(code) c.Status(code)
@ -777,9 +745,9 @@ func (c *Context) JSONP(code int, obj interface{}) {
callback := c.DefaultQuery("callback", "") callback := c.DefaultQuery("callback", "")
if callback == "" { if callback == "" {
c.Render(code, render.JSON{Data: obj}) c.Render(code, render.JSON{Data: obj})
return } else {
}
c.Render(code, render.JsonpJSON{Callback: callback, Data: obj}) c.Render(code, render.JsonpJSON{Callback: callback, Data: obj})
}
} }
// JSON serializes the given struct as JSON into the response body. // JSON serializes the given struct as JSON into the response body.
@ -805,11 +773,6 @@ func (c *Context) YAML(code int, obj interface{}) {
c.Render(code, render.YAML{Data: obj}) c.Render(code, render.YAML{Data: obj})
} }
// ProtoBuf serializes the given struct as ProtoBuf into the response body.
func (c *Context) ProtoBuf(code int, obj interface{}) {
c.Render(code, render.ProtoBuf{Data: obj})
}
// String writes the given string into the response body. // String writes the given string into the response body.
func (c *Context) String(code int, format string, values ...interface{}) { func (c *Context) String(code int, format string, values ...interface{}) {
c.Render(code, render.String{Format: format, Data: values}) c.Render(code, render.String{Format: format, Data: values})
@ -855,7 +818,6 @@ func (c *Context) SSEvent(name string, message interface{}) {
}) })
} }
// Stream sends a streaming response.
func (c *Context) Stream(step func(w io.Writer) bool) { func (c *Context) Stream(step func(w io.Writer) bool) {
w := c.Writer w := c.Writer
clientGone := w.CloseNotify() clientGone := w.CloseNotify()
@ -877,7 +839,6 @@ func (c *Context) Stream(step func(w io.Writer) bool) {
/******** CONTENT NEGOTIATION *******/ /******** CONTENT NEGOTIATION *******/
/************************************/ /************************************/
// Negotiate contains all negotiations data.
type Negotiate struct { type Negotiate struct {
Offered []string Offered []string
HTMLName string HTMLName string
@ -887,7 +848,6 @@ type Negotiate struct {
Data interface{} Data interface{}
} }
// Negotiate calls different Render according acceptable Accept format.
func (c *Context) Negotiate(code int, config Negotiate) { func (c *Context) Negotiate(code int, config Negotiate) {
switch c.NegotiateFormat(config.Offered...) { switch c.NegotiateFormat(config.Offered...) {
case binding.MIMEJSON: case binding.MIMEJSON:
@ -907,7 +867,6 @@ func (c *Context) Negotiate(code int, config Negotiate) {
} }
} }
// NegotiateFormat returns an acceptable Accept format.
func (c *Context) NegotiateFormat(offered ...string) string { func (c *Context) NegotiateFormat(offered ...string) string {
assert1(len(offered) > 0, "you must provide at least one offer") assert1(len(offered) > 0, "you must provide at least one offer")
@ -927,7 +886,6 @@ func (c *Context) NegotiateFormat(offered ...string) string {
return "" return ""
} }
// SetAccepted sets Accept header data.
func (c *Context) SetAccepted(formats ...string) { func (c *Context) SetAccepted(formats ...string) {
c.Accepted = formats c.Accepted = formats
} }

13
vendor/github.com/gin-gonic/gin/coverage.sh generated vendored Normal file
View File

@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -e
echo "mode: count" > coverage.out
for d in $(go list ./... | grep -E 'gin$|binding$|render$' | grep -v 'examples'); do
go test -v -covermode=count -coverprofile=profile.out $d
if [ -f profile.out ]; then
cat profile.out | grep -v "mode:" >> coverage.out
rm profile.out
fi
done

View File

@ -6,15 +6,13 @@ package gin
import ( import (
"bytes" "bytes"
"fmt"
"html/template" "html/template"
"os" "log"
"runtime"
"strconv"
"strings"
) )
const ginSupportMinGoVer = 6 func init() {
log.SetFlags(0)
}
// IsDebugging returns true if the framework is running in debug mode. // IsDebugging returns true if the framework is running in debug mode.
// Use SetMode(gin.ReleaseMode) to disable debug mode. // Use SetMode(gin.ReleaseMode) to disable debug mode.
@ -22,18 +20,11 @@ func IsDebugging() bool {
return ginMode == debugCode return ginMode == debugCode
} }
// DebugPrintRouteFunc indicates debug log output format.
var DebugPrintRouteFunc func(httpMethod, absolutePath, handlerName string, nuHandlers int)
func debugPrintRoute(httpMethod, absolutePath string, handlers HandlersChain) { func debugPrintRoute(httpMethod, absolutePath string, handlers HandlersChain) {
if IsDebugging() { if IsDebugging() {
nuHandlers := len(handlers) nuHandlers := len(handlers)
handlerName := nameOfFunction(handlers.Last()) handlerName := nameOfFunction(handlers.Last())
if DebugPrintRouteFunc == nil {
debugPrint("%-6s %-25s --> %s (%d handlers)\n", httpMethod, absolutePath, handlerName, nuHandlers) debugPrint("%-6s %-25s --> %s (%d handlers)\n", httpMethod, absolutePath, handlerName, nuHandlers)
} else {
DebugPrintRouteFunc(httpMethod, absolutePath, handlerName, nuHandlers)
}
} }
} }
@ -51,28 +42,14 @@ func debugPrintLoadTemplate(tmpl *template.Template) {
func debugPrint(format string, values ...interface{}) { func debugPrint(format string, values ...interface{}) {
if IsDebugging() { if IsDebugging() {
if !strings.HasSuffix(format, "\n") { log.Printf("[GIN-debug] "+format, values...)
format += "\n"
} }
fmt.Fprintf(os.Stderr, "[GIN-debug] "+format, values...)
}
}
func getMinVer(v string) (uint64, error) {
first := strings.IndexByte(v, '.')
last := strings.LastIndexByte(v, '.')
if first == last {
return strconv.ParseUint(v[first+1:], 10, 64)
}
return strconv.ParseUint(v[first+1:last], 10, 64)
} }
func debugPrintWARNINGDefault() { func debugPrintWARNINGDefault() {
if v, e := getMinVer(runtime.Version()); e == nil && v <= ginSupportMinGoVer {
debugPrint(`[WARNING] Now Gin requires Go 1.6 or later and Go 1.7 will be required soon. debugPrint(`[WARNING] Now Gin requires Go 1.6 or later and Go 1.7 will be required soon.
`) `)
}
debugPrint(`[WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached. debugPrint(`[WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
`) `)

View File

@ -9,28 +9,21 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"github.com/gin-gonic/gin/internal/json" "github.com/gin-gonic/gin/json"
) )
// ErrorType is an unsigned 64-bit error code as defined in the gin spec.
type ErrorType uint64 type ErrorType uint64
const ( const (
// ErrorTypeBind is used when Context.Bind() fails. ErrorTypeBind ErrorType = 1 << 63 // used when c.Bind() fails
ErrorTypeBind ErrorType = 1 << 63 ErrorTypeRender ErrorType = 1 << 62 // used when c.Render() fails
// ErrorTypeRender is used when Context.Render() fails.
ErrorTypeRender ErrorType = 1 << 62
// ErrorTypePrivate indicates a private error.
ErrorTypePrivate ErrorType = 1 << 0 ErrorTypePrivate ErrorType = 1 << 0
// ErrorTypePublic indicates a public error.
ErrorTypePublic ErrorType = 1 << 1 ErrorTypePublic ErrorType = 1 << 1
// ErrorTypeAny indicates any other error.
ErrorTypeAny ErrorType = 1<<64 - 1 ErrorTypeAny ErrorType = 1<<64 - 1
// ErrorTypeNu indicates any other error.
ErrorTypeNu = 2 ErrorTypeNu = 2
) )
// Error represents a error's specification.
type Error struct { type Error struct {
Err error Err error
Type ErrorType Type ErrorType
@ -41,19 +34,16 @@ type errorMsgs []*Error
var _ error = &Error{} var _ error = &Error{}
// SetType sets the error's type.
func (msg *Error) SetType(flags ErrorType) *Error { func (msg *Error) SetType(flags ErrorType) *Error {
msg.Type = flags msg.Type = flags
return msg return msg
} }
// SetMeta sets the error's meta data.
func (msg *Error) SetMeta(data interface{}) *Error { func (msg *Error) SetMeta(data interface{}) *Error {
msg.Meta = data msg.Meta = data
return msg return msg
} }
// JSON creates a properly formated JSON
func (msg *Error) JSON() interface{} { func (msg *Error) JSON() interface{} {
json := H{} json := H{}
if msg.Meta != nil { if msg.Meta != nil {
@ -80,12 +70,11 @@ func (msg *Error) MarshalJSON() ([]byte, error) {
return json.Marshal(msg.JSON()) return json.Marshal(msg.JSON())
} }
// Error implements the error interface. // Error implements the error interface
func (msg Error) Error() string { func (msg Error) Error() string {
return msg.Err.Error() return msg.Err.Error()
} }
// IsType judges one error.
func (msg *Error) IsType(flags ErrorType) bool { func (msg *Error) IsType(flags ErrorType) bool {
return (msg.Type & flags) > 0 return (msg.Type & flags) > 0
} }
@ -149,7 +138,6 @@ func (a errorMsgs) JSON() interface{} {
} }
} }
// MarshalJSON implements the json.Marshaller interface.
func (a errorMsgs) MarshalJSON() ([]byte, error) { func (a errorMsgs) MarshalJSON() ([]byte, error) {
return json.Marshal(a.JSON()) return json.Marshal(a.JSON())
} }

View File

@ -5,7 +5,6 @@
package gin package gin
import ( import (
"fmt"
"html/template" "html/template"
"net" "net"
"net/http" "net/http"
@ -15,7 +14,11 @@ import (
"github.com/gin-gonic/gin/render" "github.com/gin-gonic/gin/render"
) )
const defaultMultipartMemory = 32 << 20 // 32 MB const (
// Version is Framework's version.
Version = "v1.3.0"
defaultMultipartMemory = 32 << 20 // 32 MB
)
var ( var (
default404Body = []byte("404 page not found") default404Body = []byte("404 page not found")
@ -23,10 +26,7 @@ var (
defaultAppEngine bool defaultAppEngine bool
) )
// HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context) type HandlerFunc func(*Context)
// HandlersChain defines a HandlerFunc array.
type HandlersChain []HandlerFunc type HandlersChain []HandlerFunc
// Last returns the last handler in the chain. ie. the last handler is the main own. // Last returns the last handler in the chain. ie. the last handler is the main own.
@ -37,15 +37,12 @@ func (c HandlersChain) Last() HandlerFunc {
return nil return nil
} }
// RouteInfo represents a request route's specification which contains method and path and its handler.
type RouteInfo struct { type RouteInfo struct {
Method string Method string
Path string Path string
Handler string Handler string
HandlerFunc HandlerFunc
} }
// RoutesInfo defines a RouteInfo array.
type RoutesInfo []RouteInfo type RoutesInfo []RouteInfo
// Engine is the framework's instance, it contains the muxer, middleware and configuration settings. // Engine is the framework's instance, it contains the muxer, middleware and configuration settings.
@ -158,7 +155,6 @@ func (engine *Engine) allocateContext() *Context {
return &Context{engine: engine} return &Context{engine: engine}
} }
// Delims sets template left and right delims and returns a Engine instance.
func (engine *Engine) Delims(left, right string) *Engine { func (engine *Engine) Delims(left, right string) *Engine {
engine.delims = render.Delims{Left: left, Right: right} engine.delims = render.Delims{Left: left, Right: right}
return engine return engine
@ -268,12 +264,10 @@ func (engine *Engine) Routes() (routes RoutesInfo) {
func iterate(path, method string, routes RoutesInfo, root *node) RoutesInfo { func iterate(path, method string, routes RoutesInfo, root *node) RoutesInfo {
path += root.path path += root.path
if len(root.handlers) > 0 { if len(root.handlers) > 0 {
handlerFunc := root.handlers.Last()
routes = append(routes, RouteInfo{ routes = append(routes, RouteInfo{
Method: method, Method: method,
Path: path, Path: path,
Handler: nameOfFunction(handlerFunc), Handler: nameOfFunction(root.handlers.Last()),
HandlerFunc: handlerFunc,
}) })
} }
for _, child := range root.children { for _, child := range root.children {
@ -322,23 +316,6 @@ func (engine *Engine) RunUnix(file string) (err error) {
return return
} }
// RunFd attaches the router to a http.Server and starts listening and serving HTTP requests
// through the specified file descriptor.
// Note: this method will block the calling goroutine indefinitely unless an error happens.
func (engine *Engine) RunFd(fd int) (err error) {
debugPrint("Listening and serving HTTP on fd@%d", fd)
defer func() { debugPrintError(err) }()
f := os.NewFile(uintptr(fd), fmt.Sprintf("fd@%d", fd))
listener, err := net.FileListener(f)
if err != nil {
return
}
defer listener.Close()
err = http.Serve(listener, engine)
return
}
// ServeHTTP conforms to the http.Handler interface. // ServeHTTP conforms to the http.Handler interface.
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
c := engine.pool.Get().(*Context) c := engine.pool.Get().(*Context)
@ -357,6 +334,7 @@ func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
func (engine *Engine) HandleContext(c *Context) { func (engine *Engine) HandleContext(c *Context) {
c.reset() c.reset()
engine.handleHTTPRequest(c) engine.handleHTTPRequest(c)
engine.pool.Put(c)
} }
func (engine *Engine) handleHTTPRequest(c *Context) { func (engine *Engine) handleHTTPRequest(c *Context) {

15
vendor/github.com/gin-gonic/gin/json/json.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
// Copyright 2017 Bo-Yi Wu. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
// +build !jsoniter
package json
import "encoding/json"
var (
Marshal = json.Marshal
MarshalIndent = json.MarshalIndent
NewDecoder = json.NewDecoder
)

16
vendor/github.com/gin-gonic/gin/json/jsoniter.go generated vendored Normal file
View File

@ -0,0 +1,16 @@
// Copyright 2017 Bo-Yi Wu. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
// +build jsoniter
package json
import "github.com/json-iterator/go"
var (
json = jsoniter.ConfigCompatibleWithStandardLibrary
Marshal = json.Marshal
MarshalIndent = json.MarshalIndent
NewDecoder = json.NewDecoder
)

View File

@ -17,7 +17,7 @@ import (
var ( var (
green = string([]byte{27, 91, 57, 55, 59, 52, 50, 109}) green = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
white = string([]byte{27, 91, 57, 48, 59, 52, 55, 109}) white = string([]byte{27, 91, 57, 48, 59, 52, 55, 109})
yellow = string([]byte{27, 91, 57, 48, 59, 52, 51, 109}) yellow = string([]byte{27, 91, 57, 55, 59, 52, 51, 109})
red = string([]byte{27, 91, 57, 55, 59, 52, 49, 109}) red = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
blue = string([]byte{27, 91, 57, 55, 59, 52, 52, 109}) blue = string([]byte{27, 91, 57, 55, 59, 52, 52, 109})
magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109}) magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109})
@ -53,7 +53,7 @@ func Logger() HandlerFunc {
return LoggerWithWriter(DefaultWriter) return LoggerWithWriter(DefaultWriter)
} }
// LoggerWithWriter instance a Logger middleware with the specified writer buffer. // LoggerWithWriter instance a Logger middleware with the specified writter buffer.
// Example: os.Stdout, a file opened in write mode, a socket... // Example: os.Stdout, a file opened in write mode, a socket...
func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc { func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
isTerm := true isTerm := true

View File

@ -11,15 +11,11 @@ import (
"github.com/gin-gonic/gin/binding" "github.com/gin-gonic/gin/binding"
) )
// ENV_GIN_MODE indicates environment name for gin mode.
const ENV_GIN_MODE = "GIN_MODE" const ENV_GIN_MODE = "GIN_MODE"
const ( const (
// DebugMode indicates gin mode is debug.
DebugMode = "debug" DebugMode = "debug"
// ReleaseMode indicates gin mode is release.
ReleaseMode = "release" ReleaseMode = "release"
// TestMode indicates gin mode is test.
TestMode = "test" TestMode = "test"
) )
const ( const (
@ -28,7 +24,7 @@ const (
testCode testCode
) )
// DefaultWriter is the default io.Writer used by Gin for debug output and // DefaultWriter is the default io.Writer used the Gin for debug output and
// middleware output like Logger() or Recovery(). // middleware output like Logger() or Recovery().
// Note that both Logger and Recovery provides custom ways to configure their // Note that both Logger and Recovery provides custom ways to configure their
// output io.Writer. // output io.Writer.
@ -36,8 +32,6 @@ const (
// import "github.com/mattn/go-colorable" // import "github.com/mattn/go-colorable"
// gin.DefaultWriter = colorable.NewColorableStdout() // gin.DefaultWriter = colorable.NewColorableStdout()
var DefaultWriter io.Writer = os.Stdout var DefaultWriter io.Writer = os.Stdout
// DefaultErrorWriter is the default io.Writer used by Gin to debug errors
var DefaultErrorWriter io.Writer = os.Stderr var DefaultErrorWriter io.Writer = os.Stderr
var ginMode = debugCode var ginMode = debugCode
@ -48,7 +42,6 @@ func init() {
SetMode(mode) SetMode(mode)
} }
// SetMode sets gin mode according to input string.
func SetMode(value string) { func SetMode(value string) {
switch value { switch value {
case DebugMode, "": case DebugMode, "":
@ -66,18 +59,14 @@ func SetMode(value string) {
modeName = value modeName = value
} }
// DisableBindValidation closes the default validator.
func DisableBindValidation() { func DisableBindValidation() {
binding.Validator = nil binding.Validator = nil
} }
// EnableJsonDecoderUseNumber sets true for binding.EnableDecoderUseNumberto to
// call the UseNumber method on the JSON Decoder instance.
func EnableJsonDecoderUseNumber() { func EnableJsonDecoderUseNumber() {
binding.EnableDecoderUseNumber = true binding.EnableDecoderUseNumber = true
} }
// Mode returns currently gin mode.
func Mode() string { func Mode() string {
return modeName return modeName
} }

View File

@ -10,12 +10,9 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"log" "log"
"net"
"net/http" "net/http"
"net/http/httputil" "net/http/httputil"
"os"
"runtime" "runtime"
"strings"
"time" "time"
) )
@ -40,38 +37,13 @@ func RecoveryWithWriter(out io.Writer) HandlerFunc {
return func(c *Context) { return func(c *Context) {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
// Check for a broken connection, as it is not really a
// condition that warrants a panic stack trace.
var brokenPipe bool
if ne, ok := err.(*net.OpError); ok {
if se, ok := ne.Err.(*os.SyscallError); ok {
if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
brokenPipe = true
}
}
}
if logger != nil { if logger != nil {
stack := stack(3) stack := stack(3)
httprequest, _ := httputil.DumpRequest(c.Request, false) httprequest, _ := httputil.DumpRequest(c.Request, false)
if brokenPipe { logger.Printf("[Recovery] %s panic recovered:\n%s\n%s\n%s%s", timeFormat(time.Now()), string(httprequest), err, stack, reset)
logger.Printf("%s\n%s%s", err, string(httprequest), reset)
} else if IsDebugging() {
logger.Printf("[Recovery] %s panic recovered:\n%s\n%s\n%s%s",
timeFormat(time.Now()), string(httprequest), err, stack, reset)
} else {
logger.Printf("[Recovery] %s panic recovered:\n%s\n%s%s",
timeFormat(time.Now()), err, stack, reset)
} }
}
// If the connection is dead, we can't write a status to it.
if brokenPipe {
c.Error(err.(error))
c.Abort()
} else {
c.AbortWithStatus(http.StatusInternalServerError) c.AbortWithStatus(http.StatusInternalServerError)
} }
}
}() }()
c.Next() c.Next()
} }

View File

@ -6,7 +6,6 @@ package render
import "net/http" import "net/http"
// Data contains ContentType and bytes data.
type Data struct { type Data struct {
ContentType string ContentType string
Data []byte Data []byte
@ -19,7 +18,6 @@ func (r Data) Render(w http.ResponseWriter) (err error) {
return return
} }
// WriteContentType (Data) writes custom ContentType.
func (r Data) WriteContentType(w http.ResponseWriter) { func (r Data) WriteContentType(w http.ResponseWriter) {
writeContentType(w, []string{r.ContentType}) writeContentType(w, []string{r.ContentType})
} }

View File

@ -9,27 +9,20 @@ import (
"net/http" "net/http"
) )
// Delims represents a set of Left and Right delimiters for HTML template rendering.
type Delims struct { type Delims struct {
// Left delimiter, defaults to {{.
Left string Left string
// Right delimiter, defaults to }}.
Right string Right string
} }
// HTMLRender interface is to be implemented by HTMLProduction and HTMLDebug.
type HTMLRender interface { type HTMLRender interface {
// Instance returns an HTML instance.
Instance(string, interface{}) Render Instance(string, interface{}) Render
} }
// HTMLProduction contains template reference and its delims.
type HTMLProduction struct { type HTMLProduction struct {
Template *template.Template Template *template.Template
Delims Delims Delims Delims
} }
// HTMLDebug contains template delims and pattern and function with file list.
type HTMLDebug struct { type HTMLDebug struct {
Files []string Files []string
Glob string Glob string
@ -37,7 +30,6 @@ type HTMLDebug struct {
FuncMap template.FuncMap FuncMap template.FuncMap
} }
// HTML contains template reference and its name with given interface object.
type HTML struct { type HTML struct {
Template *template.Template Template *template.Template
Name string Name string
@ -46,7 +38,6 @@ type HTML struct {
var htmlContentType = []string{"text/html; charset=utf-8"} var htmlContentType = []string{"text/html; charset=utf-8"}
// Instance (HTMLProduction) returns an HTML instance which it realizes Render interface.
func (r HTMLProduction) Instance(name string, data interface{}) Render { func (r HTMLProduction) Instance(name string, data interface{}) Render {
return HTML{ return HTML{
Template: r.Template, Template: r.Template,
@ -55,7 +46,6 @@ func (r HTMLProduction) Instance(name string, data interface{}) Render {
} }
} }
// Instance (HTMLDebug) returns an HTML instance which it realizes Render interface.
func (r HTMLDebug) Instance(name string, data interface{}) Render { func (r HTMLDebug) Instance(name string, data interface{}) Render {
return HTML{ return HTML{
Template: r.loadTemplate(), Template: r.loadTemplate(),
@ -76,7 +66,6 @@ func (r HTMLDebug) loadTemplate() *template.Template {
panic("the HTML debug render was created without files or glob pattern") panic("the HTML debug render was created without files or glob pattern")
} }
// Render (HTML) executes template and writes its result with custom ContentType for response.
func (r HTML) Render(w http.ResponseWriter) error { func (r HTML) Render(w http.ResponseWriter) error {
r.WriteContentType(w) r.WriteContentType(w)
@ -86,7 +75,6 @@ func (r HTML) Render(w http.ResponseWriter) error {
return r.Template.ExecuteTemplate(w, r.Name, r.Data) return r.Template.ExecuteTemplate(w, r.Name, r.Data)
} }
// WriteContentType (HTML) writes HTML ContentType.
func (r HTML) WriteContentType(w http.ResponseWriter) { func (r HTML) WriteContentType(w http.ResponseWriter) {
writeContentType(w, htmlContentType) writeContentType(w, htmlContentType)
} }

View File

@ -10,44 +10,37 @@ import (
"html/template" "html/template"
"net/http" "net/http"
"github.com/gin-gonic/gin/internal/json" "github.com/gin-gonic/gin/json"
) )
// JSON contains the given interface object.
type JSON struct { type JSON struct {
Data interface{} Data interface{}
} }
// IndentedJSON contains the given interface object.
type IndentedJSON struct { type IndentedJSON struct {
Data interface{} Data interface{}
} }
// SecureJSON contains the given interface object and its prefix.
type SecureJSON struct { type SecureJSON struct {
Prefix string Prefix string
Data interface{} Data interface{}
} }
// JsonpJSON contains the given interface object its callback.
type JsonpJSON struct { type JsonpJSON struct {
Callback string Callback string
Data interface{} Data interface{}
} }
// AsciiJSON contains the given interface object.
type AsciiJSON struct { type AsciiJSON struct {
Data interface{} Data interface{}
} }
// SecureJSONPrefix is a string which represents SecureJSON prefix.
type SecureJSONPrefix string type SecureJSONPrefix string
var jsonContentType = []string{"application/json; charset=utf-8"} var jsonContentType = []string{"application/json; charset=utf-8"}
var jsonpContentType = []string{"application/javascript; charset=utf-8"} var jsonpContentType = []string{"application/javascript; charset=utf-8"}
var jsonAsciiContentType = []string{"application/json"} var jsonAsciiContentType = []string{"application/json"}
// Render (JSON) writes data with custom ContentType.
func (r JSON) Render(w http.ResponseWriter) (err error) { func (r JSON) Render(w http.ResponseWriter) (err error) {
if err = WriteJSON(w, r.Data); err != nil { if err = WriteJSON(w, r.Data); err != nil {
panic(err) panic(err)
@ -55,12 +48,10 @@ func (r JSON) Render(w http.ResponseWriter) (err error) {
return return
} }
// WriteContentType (JSON) writes JSON ContentType.
func (r JSON) WriteContentType(w http.ResponseWriter) { func (r JSON) WriteContentType(w http.ResponseWriter) {
writeContentType(w, jsonContentType) writeContentType(w, jsonContentType)
} }
// WriteJSON marshals the given interface object and writes it with custom ContentType.
func WriteJSON(w http.ResponseWriter, obj interface{}) error { func WriteJSON(w http.ResponseWriter, obj interface{}) error {
writeContentType(w, jsonContentType) writeContentType(w, jsonContentType)
jsonBytes, err := json.Marshal(obj) jsonBytes, err := json.Marshal(obj)
@ -71,7 +62,6 @@ func WriteJSON(w http.ResponseWriter, obj interface{}) error {
return nil return nil
} }
// Render (IndentedJSON) marshals the given interface object and writes it with custom ContentType.
func (r IndentedJSON) Render(w http.ResponseWriter) error { func (r IndentedJSON) Render(w http.ResponseWriter) error {
r.WriteContentType(w) r.WriteContentType(w)
jsonBytes, err := json.MarshalIndent(r.Data, "", " ") jsonBytes, err := json.MarshalIndent(r.Data, "", " ")
@ -82,12 +72,10 @@ func (r IndentedJSON) Render(w http.ResponseWriter) error {
return nil return nil
} }
// WriteContentType (IndentedJSON) writes JSON ContentType.
func (r IndentedJSON) WriteContentType(w http.ResponseWriter) { func (r IndentedJSON) WriteContentType(w http.ResponseWriter) {
writeContentType(w, jsonContentType) writeContentType(w, jsonContentType)
} }
// Render (SecureJSON) marshals the given interface object and writes it with custom ContentType.
func (r SecureJSON) Render(w http.ResponseWriter) error { func (r SecureJSON) Render(w http.ResponseWriter) error {
r.WriteContentType(w) r.WriteContentType(w)
jsonBytes, err := json.Marshal(r.Data) jsonBytes, err := json.Marshal(r.Data)
@ -102,12 +90,10 @@ func (r SecureJSON) Render(w http.ResponseWriter) error {
return nil return nil
} }
// WriteContentType (SecureJSON) writes JSON ContentType.
func (r SecureJSON) WriteContentType(w http.ResponseWriter) { func (r SecureJSON) WriteContentType(w http.ResponseWriter) {
writeContentType(w, jsonContentType) writeContentType(w, jsonContentType)
} }
// Render (JsonpJSON) marshals the given interface object and writes it and its callback with custom ContentType.
func (r JsonpJSON) Render(w http.ResponseWriter) (err error) { func (r JsonpJSON) Render(w http.ResponseWriter) (err error) {
r.WriteContentType(w) r.WriteContentType(w)
ret, err := json.Marshal(r.Data) ret, err := json.Marshal(r.Data)
@ -129,12 +115,10 @@ func (r JsonpJSON) Render(w http.ResponseWriter) (err error) {
return nil return nil
} }
// WriteContentType (JsonpJSON) writes Javascript ContentType.
func (r JsonpJSON) WriteContentType(w http.ResponseWriter) { func (r JsonpJSON) WriteContentType(w http.ResponseWriter) {
writeContentType(w, jsonpContentType) writeContentType(w, jsonpContentType)
} }
// Render (AsciiJSON) marshals the given interface object and writes it with custom ContentType.
func (r AsciiJSON) Render(w http.ResponseWriter) (err error) { func (r AsciiJSON) Render(w http.ResponseWriter) (err error) {
r.WriteContentType(w) r.WriteContentType(w)
ret, err := json.Marshal(r.Data) ret, err := json.Marshal(r.Data)
@ -144,8 +128,10 @@ func (r AsciiJSON) Render(w http.ResponseWriter) (err error) {
var buffer bytes.Buffer var buffer bytes.Buffer
for _, r := range string(ret) { for _, r := range string(ret) {
cvt := string(r) cvt := ""
if r >= 128 { if r < 128 {
cvt = string(r)
} else {
cvt = fmt.Sprintf("\\u%04x", int64(r)) cvt = fmt.Sprintf("\\u%04x", int64(r))
} }
buffer.WriteString(cvt) buffer.WriteString(cvt)
@ -155,7 +141,6 @@ func (r AsciiJSON) Render(w http.ResponseWriter) (err error) {
return nil return nil
} }
// WriteContentType (AsciiJSON) writes JSON ContentType.
func (r AsciiJSON) WriteContentType(w http.ResponseWriter) { func (r AsciiJSON) WriteContentType(w http.ResponseWriter) {
writeContentType(w, jsonAsciiContentType) writeContentType(w, jsonAsciiContentType)
} }

View File

@ -10,26 +10,22 @@ import (
"github.com/ugorji/go/codec" "github.com/ugorji/go/codec"
) )
// MsgPack contains the given interface object.
type MsgPack struct { type MsgPack struct {
Data interface{} Data interface{}
} }
var msgpackContentType = []string{"application/msgpack; charset=utf-8"} var msgpackContentType = []string{"application/msgpack; charset=utf-8"}
// WriteContentType (MsgPack) writes MsgPack ContentType.
func (r MsgPack) WriteContentType(w http.ResponseWriter) { func (r MsgPack) WriteContentType(w http.ResponseWriter) {
writeContentType(w, msgpackContentType) writeContentType(w, msgpackContentType)
} }
// Render (MsgPack) encodes the given interface object and writes data with custom ContentType.
func (r MsgPack) Render(w http.ResponseWriter) error { func (r MsgPack) Render(w http.ResponseWriter) error {
return WriteMsgPack(w, r.Data) return WriteMsgPack(w, r.Data)
} }
// WriteMsgPack writes MsgPack ContentType and encodes the given interface object.
func WriteMsgPack(w http.ResponseWriter, obj interface{}) error { func WriteMsgPack(w http.ResponseWriter, obj interface{}) error {
writeContentType(w, msgpackContentType) writeContentType(w, msgpackContentType)
var mh codec.MsgpackHandle var h codec.Handle = new(codec.MsgpackHandle)
return codec.NewEncoder(w, &mh).Encode(obj) return codec.NewEncoder(w, h).Encode(obj)
} }

View File

@ -1,7 +1,3 @@
// Copyright 2018 Gin Core Team. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package render package render
import ( import (
@ -10,7 +6,6 @@ import (
"strconv" "strconv"
) )
// Reader contains the IO reader and its length, and custom ContentType and other headers.
type Reader struct { type Reader struct {
ContentType string ContentType string
ContentLength int64 ContentLength int64
@ -27,12 +22,10 @@ func (r Reader) Render(w http.ResponseWriter) (err error) {
return return
} }
// WriteContentType (Reader) writes custom ContentType.
func (r Reader) WriteContentType(w http.ResponseWriter) { func (r Reader) WriteContentType(w http.ResponseWriter) {
writeContentType(w, []string{r.ContentType}) writeContentType(w, []string{r.ContentType})
} }
// writeHeaders writes custom Header.
func (r Reader) writeHeaders(w http.ResponseWriter, headers map[string]string) { func (r Reader) writeHeaders(w http.ResponseWriter, headers map[string]string) {
header := w.Header() header := w.Header()
for k, v := range headers { for k, v := range headers {

View File

@ -9,14 +9,12 @@ import (
"net/http" "net/http"
) )
// Redirect contains the http request reference and redirects status code and location.
type Redirect struct { type Redirect struct {
Code int Code int
Request *http.Request Request *http.Request
Location string Location string
} }
// Render (Redirect) redirects the http request to new location and writes redirect response.
func (r Redirect) Render(w http.ResponseWriter) error { func (r Redirect) Render(w http.ResponseWriter) error {
// todo(thinkerou): go1.6 not support StatusPermanentRedirect(308) // todo(thinkerou): go1.6 not support StatusPermanentRedirect(308)
// when we upgrade go version we can use http.StatusPermanentRedirect // when we upgrade go version we can use http.StatusPermanentRedirect
@ -27,5 +25,4 @@ func (r Redirect) Render(w http.ResponseWriter) error {
return nil return nil
} }
// WriteContentType (Redirect) don't write any ContentType.
func (r Redirect) WriteContentType(http.ResponseWriter) {} func (r Redirect) WriteContentType(http.ResponseWriter) {}

View File

@ -6,11 +6,8 @@ package render
import "net/http" import "net/http"
// Render interface is to be implemented by JSON, XML, HTML, YAML and so on.
type Render interface { type Render interface {
// Render writes data with custom ContentType.
Render(http.ResponseWriter) error Render(http.ResponseWriter) error
// WriteContentType writes custom ContentType.
WriteContentType(w http.ResponseWriter) WriteContentType(w http.ResponseWriter)
} }
@ -30,7 +27,6 @@ var (
_ Render = MsgPack{} _ Render = MsgPack{}
_ Render = Reader{} _ Render = Reader{}
_ Render = AsciiJSON{} _ Render = AsciiJSON{}
_ Render = ProtoBuf{}
) )
func writeContentType(w http.ResponseWriter, value []string) { func writeContentType(w http.ResponseWriter, value []string) {

View File

@ -10,7 +10,6 @@ import (
"net/http" "net/http"
) )
// String contains the given interface object slice and its format.
type String struct { type String struct {
Format string Format string
Data []interface{} Data []interface{}
@ -18,23 +17,20 @@ type String struct {
var plainContentType = []string{"text/plain; charset=utf-8"} var plainContentType = []string{"text/plain; charset=utf-8"}
// Render (String) writes data with custom ContentType.
func (r String) Render(w http.ResponseWriter) error { func (r String) Render(w http.ResponseWriter) error {
WriteString(w, r.Format, r.Data) WriteString(w, r.Format, r.Data)
return nil return nil
} }
// WriteContentType (String) writes Plain ContentType.
func (r String) WriteContentType(w http.ResponseWriter) { func (r String) WriteContentType(w http.ResponseWriter) {
writeContentType(w, plainContentType) writeContentType(w, plainContentType)
} }
// WriteString writes data according to its format and write custom ContentType.
func WriteString(w http.ResponseWriter, format string, data []interface{}) { func WriteString(w http.ResponseWriter, format string, data []interface{}) {
writeContentType(w, plainContentType) writeContentType(w, plainContentType)
if len(data) > 0 { if len(data) > 0 {
fmt.Fprintf(w, format, data...) fmt.Fprintf(w, format, data...)
return } else {
}
io.WriteString(w, format) io.WriteString(w, format)
}
} }

View File

@ -9,20 +9,17 @@ import (
"net/http" "net/http"
) )
// XML contains the given interface object.
type XML struct { type XML struct {
Data interface{} Data interface{}
} }
var xmlContentType = []string{"application/xml; charset=utf-8"} var xmlContentType = []string{"application/xml; charset=utf-8"}
// Render (XML) encodes the given interface object and writes data with custom ContentType.
func (r XML) Render(w http.ResponseWriter) error { func (r XML) Render(w http.ResponseWriter) error {
r.WriteContentType(w) r.WriteContentType(w)
return xml.NewEncoder(w).Encode(r.Data) return xml.NewEncoder(w).Encode(r.Data)
} }
// WriteContentType (XML) writes XML ContentType for response.
func (r XML) WriteContentType(w http.ResponseWriter) { func (r XML) WriteContentType(w http.ResponseWriter) {
writeContentType(w, xmlContentType) writeContentType(w, xmlContentType)
} }

View File

@ -10,14 +10,12 @@ import (
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )
// YAML contains the given interface object.
type YAML struct { type YAML struct {
Data interface{} Data interface{}
} }
var yamlContentType = []string{"application/x-yaml; charset=utf-8"} var yamlContentType = []string{"application/x-yaml; charset=utf-8"}
// Render (YAML) marshals the given interface object and writes data with custom ContentType.
func (r YAML) Render(w http.ResponseWriter) error { func (r YAML) Render(w http.ResponseWriter) error {
r.WriteContentType(w) r.WriteContentType(w)
@ -30,7 +28,6 @@ func (r YAML) Render(w http.ResponseWriter) error {
return nil return nil
} }
// WriteContentType (YAML) writes YAML ContentType for response.
func (r YAML) WriteContentType(w http.ResponseWriter) { func (r YAML) WriteContentType(w http.ResponseWriter) {
writeContentType(w, yamlContentType) writeContentType(w, yamlContentType)
} }

View File

@ -11,13 +11,11 @@ import (
"strings" "strings"
) )
// IRouter defines all router handle interface includes single and group router.
type IRouter interface { type IRouter interface {
IRoutes IRoutes
Group(string, ...HandlerFunc) *RouterGroup Group(string, ...HandlerFunc) *RouterGroup
} }
// IRoutes defines all router handle interface.
type IRoutes interface { type IRoutes interface {
Use(...HandlerFunc) IRoutes Use(...HandlerFunc) IRoutes
@ -36,8 +34,8 @@ type IRoutes interface {
StaticFS(string, http.FileSystem) IRoutes StaticFS(string, http.FileSystem) IRoutes
} }
// RouterGroup is used internally to configure router, a RouterGroup is associated with // RouterGroup is used internally to configure router, a RouterGroup is associated with a prefix
// a prefix and an array of handlers (middleware). // and an array of handlers (middleware).
type RouterGroup struct { type RouterGroup struct {
Handlers HandlersChain Handlers HandlersChain
basePath string basePath string
@ -53,8 +51,8 @@ func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
return group.returnObj() return group.returnObj()
} }
// Group creates a new router group. You should add all the routes that have common middlewares or the same path prefix. // Group creates a new router group. You should add all the routes that have common middlwares or the same path prefix.
// For example, all the routes that use a common middleware for authorization could be grouped. // For example, all the routes that use a common middlware for authorization could be grouped.
func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup { func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
return &RouterGroup{ return &RouterGroup{
Handlers: group.combineHandlers(handlers), Handlers: group.combineHandlers(handlers),
@ -63,8 +61,6 @@ func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *R
} }
} }
// BasePath returns the base path of router group.
// For example, if v := router.Group("/rest/n/v1/api"), v.BasePath() is "/rest/n/v1/api".
func (group *RouterGroup) BasePath() string { func (group *RouterGroup) BasePath() string {
return group.basePath return group.basePath
} }
@ -185,22 +181,11 @@ func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) IRou
func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandlerFunc { func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandlerFunc {
absolutePath := group.calculateAbsolutePath(relativePath) absolutePath := group.calculateAbsolutePath(relativePath)
fileServer := http.StripPrefix(absolutePath, http.FileServer(fs)) fileServer := http.StripPrefix(absolutePath, http.FileServer(fs))
_, nolisting := fs.(*onlyfilesFS)
return func(c *Context) { return func(c *Context) {
if _, nolisting := fs.(*onlyfilesFS); nolisting { if nolisting {
c.Writer.WriteHeader(http.StatusNotFound) c.Writer.WriteHeader(http.StatusNotFound)
} }
file := c.Param("filepath")
// Check if file exists and/or if we have permission to access it
if _, err := fs.Open(file); err != nil {
c.Writer.WriteHeader(http.StatusNotFound)
c.handlers = group.engine.allNoRoute
// Reset index
c.index = -1
return
}
fileServer.ServeHTTP(c.Writer, c.Request) fileServer.ServeHTTP(c.Writer, c.Request)
} }
} }

View File

@ -193,16 +193,9 @@ func (n *node) addRoute(path string, handlers HandlersChain) {
} }
} }
pathSeg := path panic("path segment '" + path +
if n.nType != catchAll {
pathSeg = strings.SplitN(path, "/", 2)[0]
}
prefix := fullPath[:strings.Index(fullPath, pathSeg)] + n.path
panic("'" + pathSeg +
"' in new path '" + fullPath +
"' conflicts with existing wildcard '" + n.path + "' conflicts with existing wildcard '" + n.path +
"' in existing prefix '" + prefix + "' in path '" + fullPath + "'")
"'")
} }
c := path[0] c := path[0]

View File

@ -14,10 +14,8 @@ import (
"strings" "strings"
) )
// BindKey indicates a default bind key.
const BindKey = "_gin-gonic/gin/bindkey" const BindKey = "_gin-gonic/gin/bindkey"
// Bind is a helper function for given interface object and returns a Gin middleware.
func Bind(val interface{}) HandlerFunc { func Bind(val interface{}) HandlerFunc {
value := reflect.ValueOf(val) value := reflect.ValueOf(val)
if value.Kind() == reflect.Ptr { if value.Kind() == reflect.Ptr {
@ -35,14 +33,16 @@ func Bind(val interface{}) HandlerFunc {
} }
} }
// WrapF is a helper function for wrapping http.HandlerFunc and returns a Gin middleware. // WrapF is a helper function for wrapping http.HandlerFunc
// Returns a Gin middleware
func WrapF(f http.HandlerFunc) HandlerFunc { func WrapF(f http.HandlerFunc) HandlerFunc {
return func(c *Context) { return func(c *Context) {
f(c.Writer, c.Request) f(c.Writer, c.Request)
} }
} }
// WrapH is a helper function for wrapping http.Handler and returns a Gin middleware. // WrapH is a helper function for wrapping http.Handler
// Returns a Gin middleware
func WrapH(h http.Handler) HandlerFunc { func WrapH(h http.Handler) HandlerFunc {
return func(c *Context) { return func(c *Context) {
h.ServeHTTP(c.Writer, c.Request) h.ServeHTTP(c.Writer, c.Request)

1
vendor/github.com/gin-gonic/gin/wercker.yml generated vendored Normal file
View File

@ -0,0 +1 @@
box: wercker/default

View File

@ -35,7 +35,6 @@ Hanno Braun <mail at hannobraun.com>
Henri Yandell <flamefew at gmail.com> Henri Yandell <flamefew at gmail.com>
Hirotaka Yamamoto <ymmt2005 at gmail.com> Hirotaka Yamamoto <ymmt2005 at gmail.com>
ICHINOSE Shogo <shogo82148 at gmail.com> ICHINOSE Shogo <shogo82148 at gmail.com>
Ilia Cimpoes <ichimpoesh at gmail.com>
INADA Naoki <songofacandy at gmail.com> INADA Naoki <songofacandy at gmail.com>
Jacek Szwec <szwec.jacek at gmail.com> Jacek Szwec <szwec.jacek at gmail.com>
James Harr <james.harr at gmail.com> James Harr <james.harr at gmail.com>
@ -73,9 +72,6 @@ Shuode Li <elemount at qq.com>
Soroush Pour <me at soroushjp.com> Soroush Pour <me at soroushjp.com>
Stan Putrya <root.vagner at gmail.com> Stan Putrya <root.vagner at gmail.com>
Stanley Gunawan <gunawan.stanley at gmail.com> Stanley Gunawan <gunawan.stanley at gmail.com>
Steven Hartland <steven.hartland at multiplay.co.uk>
Thomas Wodarek <wodarekwebpage at gmail.com>
Tom Jenkinson <tom at tjenkinson.me>
Xiangyu Hu <xiangyu.hu at outlook.com> Xiangyu Hu <xiangyu.hu at outlook.com>
Xiaobing Jiang <s7v7nislands at gmail.com> Xiaobing Jiang <s7v7nislands at gmail.com>
Xiuming Chen <cc at cxm.cc> Xiuming Chen <cc at cxm.cc>
@ -91,4 +87,3 @@ Keybase Inc.
Percona LLC Percona LLC
Pivotal Inc. Pivotal Inc.
Stripe Inc. Stripe Inc.
Multiplay Ltd.

View File

@ -1,3 +1,14 @@
## Version 1.4.1 (2018-11-14)
Bugfixes:
- Fix TIME format for binary columns (#818)
- Fix handling of empty auth plugin names (#835)
- Fix caching_sha2_password with empty password (#826)
- Fix canceled context broke mysqlConn (#862)
- Fix OldAuthSwitchRequest support (#870)
- Fix Auth Response packet for cleartext password (#887)
## Version 1.4 (2018-06-03) ## Version 1.4 (2018-06-03)
Changes: Changes:

View File

@ -40,7 +40,7 @@ A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) pac
* Optional placeholder interpolation * Optional placeholder interpolation
## Requirements ## Requirements
* Go 1.8 or higher. We aim to support the 3 latest versions of Go. * Go 1.7 or higher. We aim to support the 3 latest versions of Go.
* MySQL (4.1+), MariaDB, Percona Server, Google CloudSQL or Sphinx (2.2.3+) * MySQL (4.1+), MariaDB, Percona Server, Google CloudSQL or Sphinx (2.2.3+)
--------------------------------------- ---------------------------------------

View File

@ -360,15 +360,13 @@ func (mc *mysqlConn) handleAuthResult(oldAuthData []byte, plugin string) error {
pubKey := mc.cfg.pubKey pubKey := mc.cfg.pubKey
if pubKey == nil { if pubKey == nil {
// request public key from server // request public key from server
data, err := mc.buf.takeSmallBuffer(4 + 1) data := mc.buf.takeSmallBuffer(4 + 1)
if err != nil {
return err
}
data[4] = cachingSha2PasswordRequestPublicKey data[4] = cachingSha2PasswordRequestPublicKey
mc.writePacket(data) mc.writePacket(data)
// parse public key // parse public key
if data, err = mc.readPacket(); err != nil { data, err := mc.readPacket()
if err != nil {
return err return err
} }

View File

@ -22,17 +22,17 @@ const defaultBufSize = 4096
// The buffer is similar to bufio.Reader / Writer but zero-copy-ish // The buffer is similar to bufio.Reader / Writer but zero-copy-ish
// Also highly optimized for this particular use case. // Also highly optimized for this particular use case.
type buffer struct { type buffer struct {
buf []byte // buf is a byte buffer who's length and capacity are equal. buf []byte
nc net.Conn nc net.Conn
idx int idx int
length int length int
timeout time.Duration timeout time.Duration
} }
// newBuffer allocates and returns a new buffer.
func newBuffer(nc net.Conn) buffer { func newBuffer(nc net.Conn) buffer {
var b [defaultBufSize]byte
return buffer{ return buffer{
buf: make([]byte, defaultBufSize), buf: b[:],
nc: nc, nc: nc,
} }
} }
@ -105,56 +105,43 @@ func (b *buffer) readNext(need int) ([]byte, error) {
return b.buf[offset:b.idx], nil return b.buf[offset:b.idx], nil
} }
// takeBuffer returns a buffer with the requested size. // returns a buffer with the requested size.
// If possible, a slice from the existing buffer is returned. // If possible, a slice from the existing buffer is returned.
// Otherwise a bigger buffer is made. // Otherwise a bigger buffer is made.
// Only one buffer (total) can be used at a time. // Only one buffer (total) can be used at a time.
func (b *buffer) takeBuffer(length int) ([]byte, error) { func (b *buffer) takeBuffer(length int) []byte {
if b.length > 0 { if b.length > 0 {
return nil, ErrBusyBuffer return nil
} }
// test (cheap) general case first // test (cheap) general case first
if length <= cap(b.buf) { if length <= defaultBufSize || length <= cap(b.buf) {
return b.buf[:length], nil return b.buf[:length]
} }
if length < maxPacketSize { if length < maxPacketSize {
b.buf = make([]byte, length) b.buf = make([]byte, length)
return b.buf, nil return b.buf
} }
return make([]byte, length)
// buffer is larger than we want to store.
return make([]byte, length), nil
} }
// takeSmallBuffer is shortcut which can be used if length is // shortcut which can be used if the requested buffer is guaranteed to be
// known to be smaller than defaultBufSize. // smaller than defaultBufSize
// Only one buffer (total) can be used at a time. // Only one buffer (total) can be used at a time.
func (b *buffer) takeSmallBuffer(length int) ([]byte, error) { func (b *buffer) takeSmallBuffer(length int) []byte {
if b.length > 0 { if b.length > 0 {
return nil, ErrBusyBuffer return nil
} }
return b.buf[:length], nil return b.buf[:length]
} }
// takeCompleteBuffer returns the complete existing buffer. // takeCompleteBuffer returns the complete existing buffer.
// This can be used if the necessary buffer size is unknown. // This can be used if the necessary buffer size is unknown.
// cap and len of the returned buffer will be equal.
// Only one buffer (total) can be used at a time. // Only one buffer (total) can be used at a time.
func (b *buffer) takeCompleteBuffer() ([]byte, error) { func (b *buffer) takeCompleteBuffer() []byte {
if b.length > 0 { if b.length > 0 {
return nil, ErrBusyBuffer
}
return b.buf, nil
}
// store stores buf, an updated buffer, if its suitable to do so.
func (b *buffer) store(buf []byte) error {
if b.length > 0 {
return ErrBusyBuffer
} else if cap(buf) <= maxPacketSize && cap(buf) > cap(b.buf) {
b.buf = buf[:cap(buf)]
}
return nil return nil
}
return b.buf
} }

View File

@ -9,8 +9,6 @@
package mysql package mysql
import ( import (
"context"
"database/sql"
"database/sql/driver" "database/sql/driver"
"io" "io"
"net" "net"
@ -19,6 +17,16 @@ import (
"time" "time"
) )
// a copy of context.Context for Go 1.7 and earlier
type mysqlContext interface {
Done() <-chan struct{}
Err() error
// defined in context.Context, but not used in this driver:
// Deadline() (deadline time.Time, ok bool)
// Value(key interface{}) interface{}
}
type mysqlConn struct { type mysqlConn struct {
buf buffer buf buffer
netConn net.Conn netConn net.Conn
@ -35,7 +43,7 @@ type mysqlConn struct {
// for context support (Go 1.8+) // for context support (Go 1.8+)
watching bool watching bool
watcher chan<- context.Context watcher chan<- mysqlContext
closech chan struct{} closech chan struct{}
finished chan<- struct{} finished chan<- struct{}
canceled atomicError // set non-nil if conn is canceled canceled atomicError // set non-nil if conn is canceled
@ -182,10 +190,10 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin
return "", driver.ErrSkip return "", driver.ErrSkip
} }
buf, err := mc.buf.takeCompleteBuffer() buf := mc.buf.takeCompleteBuffer()
if err != nil { if buf == nil {
// can not take the buffer. Something must be wrong with the connection // can not take the buffer. Something must be wrong with the connection
errLog.Print(err) errLog.Print(ErrBusyBuffer)
return "", ErrInvalidConn return "", ErrInvalidConn
} }
buf = buf[:0] buf = buf[:0]
@ -451,193 +459,3 @@ func (mc *mysqlConn) finish() {
case <-mc.closech: case <-mc.closech:
} }
} }
// Ping implements driver.Pinger interface
func (mc *mysqlConn) Ping(ctx context.Context) (err error) {
if mc.closed.IsSet() {
errLog.Print(ErrInvalidConn)
return driver.ErrBadConn
}
if err = mc.watchCancel(ctx); err != nil {
return
}
defer mc.finish()
if err = mc.writeCommandPacket(comPing); err != nil {
return mc.markBadConn(err)
}
return mc.readResultOK()
}
// BeginTx implements driver.ConnBeginTx interface
func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
if err := mc.watchCancel(ctx); err != nil {
return nil, err
}
defer mc.finish()
if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault {
level, err := mapIsolationLevel(opts.Isolation)
if err != nil {
return nil, err
}
err = mc.exec("SET TRANSACTION ISOLATION LEVEL " + level)
if err != nil {
return nil, err
}
}
return mc.begin(opts.ReadOnly)
}
func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
dargs, err := namedValueToValue(args)
if err != nil {
return nil, err
}
if err := mc.watchCancel(ctx); err != nil {
return nil, err
}
rows, err := mc.query(query, dargs)
if err != nil {
mc.finish()
return nil, err
}
rows.finish = mc.finish
return rows, err
}
func (mc *mysqlConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
dargs, err := namedValueToValue(args)
if err != nil {
return nil, err
}
if err := mc.watchCancel(ctx); err != nil {
return nil, err
}
defer mc.finish()
return mc.Exec(query, dargs)
}
func (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
if err := mc.watchCancel(ctx); err != nil {
return nil, err
}
stmt, err := mc.Prepare(query)
mc.finish()
if err != nil {
return nil, err
}
select {
default:
case <-ctx.Done():
stmt.Close()
return nil, ctx.Err()
}
return stmt, nil
}
func (stmt *mysqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
dargs, err := namedValueToValue(args)
if err != nil {
return nil, err
}
if err := stmt.mc.watchCancel(ctx); err != nil {
return nil, err
}
rows, err := stmt.query(dargs)
if err != nil {
stmt.mc.finish()
return nil, err
}
rows.finish = stmt.mc.finish
return rows, err
}
func (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
dargs, err := namedValueToValue(args)
if err != nil {
return nil, err
}
if err := stmt.mc.watchCancel(ctx); err != nil {
return nil, err
}
defer stmt.mc.finish()
return stmt.Exec(dargs)
}
func (mc *mysqlConn) watchCancel(ctx context.Context) error {
if mc.watching {
// Reach here if canceled,
// so the connection is already invalid
mc.cleanup()
return nil
}
// When ctx is already cancelled, don't watch it.
if err := ctx.Err(); err != nil {
return err
}
// When ctx is not cancellable, don't watch it.
if ctx.Done() == nil {
return nil
}
// When watcher is not alive, can't watch it.
if mc.watcher == nil {
return nil
}
mc.watching = true
mc.watcher <- ctx
return nil
}
func (mc *mysqlConn) startWatcher() {
watcher := make(chan context.Context, 1)
mc.watcher = watcher
finished := make(chan struct{})
mc.finished = finished
go func() {
for {
var ctx context.Context
select {
case ctx = <-watcher:
case <-mc.closech:
return
}
select {
case <-ctx.Done():
mc.cancel(ctx.Err())
case <-finished:
case <-mc.closech:
return
}
}
}()
}
func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) {
nv.Value, err = converter{}.ConvertValue(nv.Value)
return
}
// ResetSession implements driver.SessionResetter.
// (From Go 1.10)
func (mc *mysqlConn) ResetSession(ctx context.Context) error {
if mc.closed.IsSet() {
return driver.ErrBadConn
}
return nil
}

View File

@ -0,0 +1,207 @@
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
// +build go1.8
package mysql
import (
"context"
"database/sql"
"database/sql/driver"
)
// Ping implements driver.Pinger interface
func (mc *mysqlConn) Ping(ctx context.Context) (err error) {
if mc.closed.IsSet() {
errLog.Print(ErrInvalidConn)
return driver.ErrBadConn
}
if err = mc.watchCancel(ctx); err != nil {
return
}
defer mc.finish()
if err = mc.writeCommandPacket(comPing); err != nil {
return
}
return mc.readResultOK()
}
// BeginTx implements driver.ConnBeginTx interface
func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
if err := mc.watchCancel(ctx); err != nil {
return nil, err
}
defer mc.finish()
if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault {
level, err := mapIsolationLevel(opts.Isolation)
if err != nil {
return nil, err
}
err = mc.exec("SET TRANSACTION ISOLATION LEVEL " + level)
if err != nil {
return nil, err
}
}
return mc.begin(opts.ReadOnly)
}
func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
dargs, err := namedValueToValue(args)
if err != nil {
return nil, err
}
if err := mc.watchCancel(ctx); err != nil {
return nil, err
}
rows, err := mc.query(query, dargs)
if err != nil {
mc.finish()
return nil, err
}
rows.finish = mc.finish
return rows, err
}
func (mc *mysqlConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
dargs, err := namedValueToValue(args)
if err != nil {
return nil, err
}
if err := mc.watchCancel(ctx); err != nil {
return nil, err
}
defer mc.finish()
return mc.Exec(query, dargs)
}
func (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
if err := mc.watchCancel(ctx); err != nil {
return nil, err
}
stmt, err := mc.Prepare(query)
mc.finish()
if err != nil {
return nil, err
}
select {
default:
case <-ctx.Done():
stmt.Close()
return nil, ctx.Err()
}
return stmt, nil
}
func (stmt *mysqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
dargs, err := namedValueToValue(args)
if err != nil {
return nil, err
}
if err := stmt.mc.watchCancel(ctx); err != nil {
return nil, err
}
rows, err := stmt.query(dargs)
if err != nil {
stmt.mc.finish()
return nil, err
}
rows.finish = stmt.mc.finish
return rows, err
}
func (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
dargs, err := namedValueToValue(args)
if err != nil {
return nil, err
}
if err := stmt.mc.watchCancel(ctx); err != nil {
return nil, err
}
defer stmt.mc.finish()
return stmt.Exec(dargs)
}
func (mc *mysqlConn) watchCancel(ctx context.Context) error {
if mc.watching {
// Reach here if canceled,
// so the connection is already invalid
mc.cleanup()
return nil
}
// When ctx is already cancelled, don't watch it.
if err := ctx.Err(); err != nil {
return err
}
// When ctx is not cancellable, don't watch it.
if ctx.Done() == nil {
return nil
}
// When watcher is not alive, can't watch it.
if mc.watcher == nil {
return nil
}
mc.watching = true
mc.watcher <- ctx
return nil
}
func (mc *mysqlConn) startWatcher() {
watcher := make(chan mysqlContext, 1)
mc.watcher = watcher
finished := make(chan struct{})
mc.finished = finished
go func() {
for {
var ctx mysqlContext
select {
case ctx = <-watcher:
case <-mc.closech:
return
}
select {
case <-ctx.Done():
mc.cancel(ctx.Err())
case <-finished:
case <-mc.closech:
return
}
}
}()
}
func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) {
nv.Value, err = converter{}.ConvertValue(nv.Value)
return
}
// ResetSession implements driver.SessionResetter.
// (From Go 1.10)
func (mc *mysqlConn) ResetSession(ctx context.Context) error {
if mc.closed.IsSet() {
return driver.ErrBadConn
}
return nil
}

View File

@ -23,6 +23,11 @@ import (
"sync" "sync"
) )
// watcher interface is used for context support (From Go 1.8)
type watcher interface {
startWatcher()
}
// MySQLDriver is exported to make the driver directly accessible. // MySQLDriver is exported to make the driver directly accessible.
// In general the driver is used via the database/sql package. // In general the driver is used via the database/sql package.
type MySQLDriver struct{} type MySQLDriver struct{}
@ -50,7 +55,7 @@ func RegisterDial(net string, dial DialFunc) {
// Open new Connection. // Open new Connection.
// See https://github.com/go-sql-driver/mysql#dsn-data-source-name for how // See https://github.com/go-sql-driver/mysql#dsn-data-source-name for how
// the DSN string is formatted // the DSN string is formated
func (d MySQLDriver) Open(dsn string) (driver.Conn, error) { func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
var err error var err error
@ -77,10 +82,6 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
mc.netConn, err = nd.Dial(mc.cfg.Net, mc.cfg.Addr) mc.netConn, err = nd.Dial(mc.cfg.Net, mc.cfg.Addr)
} }
if err != nil { if err != nil {
if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
errLog.Print("net.Error from Dial()': ", nerr.Error())
return nil, driver.ErrBadConn
}
return nil, err return nil, err
} }
@ -95,7 +96,9 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
} }
// Call startWatcher for context support (From Go 1.8) // Call startWatcher for context support (From Go 1.8)
mc.startWatcher() if s, ok := interface{}(mc).(watcher); ok {
s.startWatcher()
}
mc.buf = newBuffer(mc.netConn) mc.buf = newBuffer(mc.netConn)

View File

@ -51,7 +51,7 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
mc.sequence++ mc.sequence++
// packets with length 0 terminate a previous packet which is a // packets with length 0 terminate a previous packet which is a
// multiple of (2^24)-1 bytes long // multiple of (2^24)1 bytes long
if pktLen == 0 { if pktLen == 0 {
// there was no previous packet // there was no previous packet
if prevData == nil { if prevData == nil {
@ -286,10 +286,10 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string
} }
// Calculate packet length and get buffer with that size // Calculate packet length and get buffer with that size
data, err := mc.buf.takeSmallBuffer(pktLen + 4) data := mc.buf.takeSmallBuffer(pktLen + 4)
if err != nil { if data == nil {
// cannot take the buffer. Something must be wrong with the connection // cannot take the buffer. Something must be wrong with the connection
errLog.Print(err) errLog.Print(ErrBusyBuffer)
return errBadConnNoWrite return errBadConnNoWrite
} }
@ -367,10 +367,10 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse
func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte) error { func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte) error {
pktLen := 4 + len(authData) pktLen := 4 + len(authData)
data, err := mc.buf.takeSmallBuffer(pktLen) data := mc.buf.takeSmallBuffer(pktLen)
if err != nil { if data == nil {
// cannot take the buffer. Something must be wrong with the connection // cannot take the buffer. Something must be wrong with the connection
errLog.Print(err) errLog.Print(ErrBusyBuffer)
return errBadConnNoWrite return errBadConnNoWrite
} }
@ -387,10 +387,10 @@ func (mc *mysqlConn) writeCommandPacket(command byte) error {
// Reset Packet Sequence // Reset Packet Sequence
mc.sequence = 0 mc.sequence = 0
data, err := mc.buf.takeSmallBuffer(4 + 1) data := mc.buf.takeSmallBuffer(4 + 1)
if err != nil { if data == nil {
// cannot take the buffer. Something must be wrong with the connection // cannot take the buffer. Something must be wrong with the connection
errLog.Print(err) errLog.Print(ErrBusyBuffer)
return errBadConnNoWrite return errBadConnNoWrite
} }
@ -406,10 +406,10 @@ func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error {
mc.sequence = 0 mc.sequence = 0
pktLen := 1 + len(arg) pktLen := 1 + len(arg)
data, err := mc.buf.takeBuffer(pktLen + 4) data := mc.buf.takeBuffer(pktLen + 4)
if err != nil { if data == nil {
// cannot take the buffer. Something must be wrong with the connection // cannot take the buffer. Something must be wrong with the connection
errLog.Print(err) errLog.Print(ErrBusyBuffer)
return errBadConnNoWrite return errBadConnNoWrite
} }
@ -427,10 +427,10 @@ func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error {
// Reset Packet Sequence // Reset Packet Sequence
mc.sequence = 0 mc.sequence = 0
data, err := mc.buf.takeSmallBuffer(4 + 1 + 4) data := mc.buf.takeSmallBuffer(4 + 1 + 4)
if err != nil { if data == nil {
// cannot take the buffer. Something must be wrong with the connection // cannot take the buffer. Something must be wrong with the connection
errLog.Print(err) errLog.Print(ErrBusyBuffer)
return errBadConnNoWrite return errBadConnNoWrite
} }
@ -883,7 +883,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
const minPktLen = 4 + 1 + 4 + 1 + 4 const minPktLen = 4 + 1 + 4 + 1 + 4
mc := stmt.mc mc := stmt.mc
// Determine threshold dynamically to avoid packet size shortage. // Determine threshould dynamically to avoid packet size shortage.
longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1) longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1)
if longDataSize < 64 { if longDataSize < 64 {
longDataSize = 64 longDataSize = 64
@ -893,17 +893,15 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
mc.sequence = 0 mc.sequence = 0
var data []byte var data []byte
var err error
if len(args) == 0 { if len(args) == 0 {
data, err = mc.buf.takeBuffer(minPktLen) data = mc.buf.takeBuffer(minPktLen)
} else { } else {
data, err = mc.buf.takeCompleteBuffer() data = mc.buf.takeCompleteBuffer()
// In this case the len(data) == cap(data) which is used to optimise the flow below.
} }
if err != nil { if data == nil {
// cannot take the buffer. Something must be wrong with the connection // cannot take the buffer. Something must be wrong with the connection
errLog.Print(err) errLog.Print(ErrBusyBuffer)
return errBadConnNoWrite return errBadConnNoWrite
} }
@ -929,7 +927,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
pos := minPktLen pos := minPktLen
var nullMask []byte var nullMask []byte
if maskLen, typesLen := (len(args)+7)/8, 1+2*len(args); pos+maskLen+typesLen >= cap(data) { if maskLen, typesLen := (len(args)+7)/8, 1+2*len(args); pos+maskLen+typesLen >= len(data) {
// buffer has to be extended but we don't know by how much so // buffer has to be extended but we don't know by how much so
// we depend on append after all data with known sizes fit. // we depend on append after all data with known sizes fit.
// We stop at that because we deal with a lot of columns here // We stop at that because we deal with a lot of columns here
@ -938,11 +936,10 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
copy(tmp[:pos], data[:pos]) copy(tmp[:pos], data[:pos])
data = tmp data = tmp
nullMask = data[pos : pos+maskLen] nullMask = data[pos : pos+maskLen]
// No need to clean nullMask as make ensures that.
pos += maskLen pos += maskLen
} else { } else {
nullMask = data[pos : pos+maskLen] nullMask = data[pos : pos+maskLen]
for i := range nullMask { for i := 0; i < maskLen; i++ {
nullMask[i] = 0 nullMask[i] = 0
} }
pos += maskLen pos += maskLen
@ -1079,10 +1076,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
// In that case we must build the data packet with the new values buffer // In that case we must build the data packet with the new values buffer
if valuesCap != cap(paramValues) { if valuesCap != cap(paramValues) {
data = append(data[:pos], paramValues...) data = append(data[:pos], paramValues...)
if err = mc.buf.store(data); err != nil { mc.buf.buf = data
errLog.Print(err)
return errBadConnNoWrite
}
} }
pos += len(paramValues) pos += len(paramValues)

View File

@ -10,10 +10,8 @@ package mysql
import ( import (
"crypto/tls" "crypto/tls"
"database/sql"
"database/sql/driver" "database/sql/driver"
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"io" "io"
"strconv" "strconv"
@ -82,7 +80,7 @@ func DeregisterTLSConfig(key string) {
func getTLSConfigClone(key string) (config *tls.Config) { func getTLSConfigClone(key string) (config *tls.Config) {
tlsConfigLock.RLock() tlsConfigLock.RLock()
if v, ok := tlsConfigRegistry[key]; ok { if v, ok := tlsConfigRegistry[key]; ok {
config = v.Clone() config = cloneTLSConfig(v)
} }
tlsConfigLock.RUnlock() tlsConfigLock.RUnlock()
return return
@ -726,30 +724,3 @@ func (ae *atomicError) Value() error {
} }
return nil return nil
} }
func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) {
dargs := make([]driver.Value, len(named))
for n, param := range named {
if len(param.Name) > 0 {
// TODO: support the use of Named Parameters #561
return nil, errors.New("mysql: driver does not support the use of Named Parameters")
}
dargs[n] = param.Value
}
return dargs, nil
}
func mapIsolationLevel(level driver.IsolationLevel) (string, error) {
switch sql.IsolationLevel(level) {
case sql.LevelRepeatableRead:
return "REPEATABLE READ", nil
case sql.LevelReadCommitted:
return "READ COMMITTED", nil
case sql.LevelReadUncommitted:
return "READ UNCOMMITTED", nil
case sql.LevelSerializable:
return "SERIALIZABLE", nil
default:
return "", fmt.Errorf("mysql: unsupported isolation level: %v", level)
}
}

40
vendor/github.com/go-sql-driver/mysql/utils_go17.go generated vendored Normal file
View File

@ -0,0 +1,40 @@
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
// +build go1.7
// +build !go1.8
package mysql
import "crypto/tls"
func cloneTLSConfig(c *tls.Config) *tls.Config {
return &tls.Config{
Rand: c.Rand,
Time: c.Time,
Certificates: c.Certificates,
NameToCertificate: c.NameToCertificate,
GetCertificate: c.GetCertificate,
RootCAs: c.RootCAs,
NextProtos: c.NextProtos,
ServerName: c.ServerName,
ClientAuth: c.ClientAuth,
ClientCAs: c.ClientCAs,
InsecureSkipVerify: c.InsecureSkipVerify,
CipherSuites: c.CipherSuites,
PreferServerCipherSuites: c.PreferServerCipherSuites,
SessionTicketsDisabled: c.SessionTicketsDisabled,
SessionTicketKey: c.SessionTicketKey,
ClientSessionCache: c.ClientSessionCache,
MinVersion: c.MinVersion,
MaxVersion: c.MaxVersion,
CurvePreferences: c.CurvePreferences,
DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
Renegotiation: c.Renegotiation,
}
}

50
vendor/github.com/go-sql-driver/mysql/utils_go18.go generated vendored Normal file
View File

@ -0,0 +1,50 @@
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
// +build go1.8
package mysql
import (
"crypto/tls"
"database/sql"
"database/sql/driver"
"errors"
"fmt"
)
func cloneTLSConfig(c *tls.Config) *tls.Config {
return c.Clone()
}
func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) {
dargs := make([]driver.Value, len(named))
for n, param := range named {
if len(param.Name) > 0 {
// TODO: support the use of Named Parameters #561
return nil, errors.New("mysql: driver does not support the use of Named Parameters")
}
dargs[n] = param.Value
}
return dargs, nil
}
func mapIsolationLevel(level driver.IsolationLevel) (string, error) {
switch sql.IsolationLevel(level) {
case sql.LevelRepeatableRead:
return "REPEATABLE READ", nil
case sql.LevelReadCommitted:
return "READ COMMITTED", nil
case sql.LevelReadUncommitted:
return "READ UNCOMMITTED", nil
case sql.LevelSerializable:
return "SERIALIZABLE", nil
default:
return "", fmt.Errorf("mysql: unsupported isolation level: %v", level)
}
}

View File

@ -186,6 +186,7 @@ func (p *Buffer) DecodeVarint() (x uint64, err error) {
if b&0x80 == 0 { if b&0x80 == 0 {
goto done goto done
} }
// x -= 0x80 << 63 // Always zero.
return 0, errOverflow return 0, errOverflow

View File

@ -246,8 +246,7 @@ func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool {
return false return false
} }
m1 := extensionAsLegacyType(e1.value) m1, m2 := e1.value, e2.value
m2 := extensionAsLegacyType(e2.value)
if m1 == nil && m2 == nil { if m1 == nil && m2 == nil {
// Both have only encoded form. // Both have only encoded form.

View File

@ -186,23 +186,7 @@ type Extension struct {
// accessed using GetExtension (or GetExtensions) desc and value // accessed using GetExtension (or GetExtensions) desc and value
// will be set. // will be set.
desc *ExtensionDesc desc *ExtensionDesc
// value is a concrete value for the extension field. Let the type of
// desc.ExtensionType be the "API type" and the type of Extension.value
// be the "storage type". The API type and storage type are the same except:
// * For scalars (except []byte), the API type uses *T,
// while the storage type uses T.
// * For repeated fields, the API type uses []T, while the storage type
// uses *[]T.
//
// The reason for the divergence is so that the storage type more naturally
// matches what is expected of when retrieving the values through the
// protobuf reflection APIs.
//
// The value may only be populated if desc is also populated.
value interface{} value interface{}
// enc is the raw bytes for the extension field.
enc []byte enc []byte
} }
@ -350,7 +334,7 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) {
// descriptors with the same field number. // descriptors with the same field number.
return nil, errors.New("proto: descriptor conflict") return nil, errors.New("proto: descriptor conflict")
} }
return extensionAsLegacyType(e.value), nil return e.value, nil
} }
if extension.ExtensionType == nil { if extension.ExtensionType == nil {
@ -365,11 +349,11 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) {
// Remember the decoded version and drop the encoded version. // Remember the decoded version and drop the encoded version.
// That way it is safe to mutate what we return. // That way it is safe to mutate what we return.
e.value = extensionAsStorageType(v) e.value = v
e.desc = extension e.desc = extension
e.enc = nil e.enc = nil
emap[extension.Field] = e emap[extension.Field] = e
return extensionAsLegacyType(e.value), nil return e.value, nil
} }
// defaultExtensionValue returns the default value for extension. // defaultExtensionValue returns the default value for extension.
@ -504,7 +488,7 @@ func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error
} }
typ := reflect.TypeOf(extension.ExtensionType) typ := reflect.TypeOf(extension.ExtensionType)
if typ != reflect.TypeOf(value) { if typ != reflect.TypeOf(value) {
return fmt.Errorf("proto: bad extension value type. got: %T, want: %T", value, extension.ExtensionType) return errors.New("proto: bad extension value type")
} }
// nil extension values need to be caught early, because the // nil extension values need to be caught early, because the
// encoder can't distinguish an ErrNil due to a nil extension // encoder can't distinguish an ErrNil due to a nil extension
@ -516,7 +500,7 @@ func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error
} }
extmap := epb.extensionsWrite() extmap := epb.extensionsWrite()
extmap[extension.Field] = Extension{desc: extension, value: extensionAsStorageType(value)} extmap[extension.Field] = Extension{desc: extension, value: value}
return nil return nil
} }
@ -557,51 +541,3 @@ func RegisterExtension(desc *ExtensionDesc) {
func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc { func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc {
return extensionMaps[reflect.TypeOf(pb).Elem()] return extensionMaps[reflect.TypeOf(pb).Elem()]
} }
// extensionAsLegacyType converts an value in the storage type as the API type.
// See Extension.value.
func extensionAsLegacyType(v interface{}) interface{} {
switch rv := reflect.ValueOf(v); rv.Kind() {
case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
// Represent primitive types as a pointer to the value.
rv2 := reflect.New(rv.Type())
rv2.Elem().Set(rv)
v = rv2.Interface()
case reflect.Ptr:
// Represent slice types as the value itself.
switch rv.Type().Elem().Kind() {
case reflect.Slice:
if rv.IsNil() {
v = reflect.Zero(rv.Type().Elem()).Interface()
} else {
v = rv.Elem().Interface()
}
}
}
return v
}
// extensionAsStorageType converts an value in the API type as the storage type.
// See Extension.value.
func extensionAsStorageType(v interface{}) interface{} {
switch rv := reflect.ValueOf(v); rv.Kind() {
case reflect.Ptr:
// Represent slice types as the value itself.
switch rv.Type().Elem().Kind() {
case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
if rv.IsNil() {
v = reflect.Zero(rv.Type().Elem()).Interface()
} else {
v = rv.Elem().Interface()
}
}
case reflect.Slice:
// Represent slice types as a pointer to the value.
if rv.Type().Elem().Kind() != reflect.Uint8 {
rv2 := reflect.New(rv.Type())
rv2.Elem().Set(rv)
v = rv2.Interface()
}
}
return v
}

View File

@ -341,6 +341,26 @@ type Message interface {
ProtoMessage() ProtoMessage()
} }
// Stats records allocation details about the protocol buffer encoders
// and decoders. Useful for tuning the library itself.
type Stats struct {
Emalloc uint64 // mallocs in encode
Dmalloc uint64 // mallocs in decode
Encode uint64 // number of encodes
Decode uint64 // number of decodes
Chit uint64 // number of cache hits
Cmiss uint64 // number of cache misses
Size uint64 // number of sizes
}
// Set to true to enable stats collection.
const collectStats = false
var stats Stats
// GetStats returns a copy of the global Stats structure.
func GetStats() Stats { return stats }
// A Buffer is a buffer manager for marshaling and unmarshaling // A Buffer is a buffer manager for marshaling and unmarshaling
// protocol buffers. It may be reused between invocations to // protocol buffers. It may be reused between invocations to
// reduce memory usage. It is not necessary to use a Buffer; // reduce memory usage. It is not necessary to use a Buffer;
@ -940,19 +960,13 @@ func isProto3Zero(v reflect.Value) bool {
return false return false
} }
const ( // ProtoPackageIsVersion2 is referenced from generated protocol buffer files
// ProtoPackageIsVersion3 is referenced from generated protocol buffer files // to assert that that code is compatible with this version of the proto package.
// to assert that that code is compatible with this version of the proto package. const ProtoPackageIsVersion2 = true
ProtoPackageIsVersion3 = true
// ProtoPackageIsVersion2 is referenced from generated protocol buffer files // ProtoPackageIsVersion1 is referenced from generated protocol buffer files
// to assert that that code is compatible with this version of the proto package. // to assert that that code is compatible with this version of the proto package.
ProtoPackageIsVersion2 = true const ProtoPackageIsVersion1 = true
// ProtoPackageIsVersion1 is referenced from generated protocol buffer files
// to assert that that code is compatible with this version of the proto package.
ProtoPackageIsVersion1 = true
)
// InternalMessageInfo is a type used internally by generated .pb.go files. // InternalMessageInfo is a type used internally by generated .pb.go files.
// This type is not intended to be used by non-generated code. // This type is not intended to be used by non-generated code.

View File

@ -36,7 +36,13 @@ package proto
*/ */
import ( import (
"bytes"
"encoding/json"
"errors" "errors"
"fmt"
"reflect"
"sort"
"sync"
) )
// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. // errNoMessageTypeID occurs when a protocol buffer does not have a message type ID.
@ -139,9 +145,46 @@ func skipVarint(buf []byte) []byte {
return buf[i+1:] return buf[i+1:]
} }
// unmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. // MarshalMessageSet encodes the extension map represented by m in the message set wire format.
// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option.
func MarshalMessageSet(exts interface{}) ([]byte, error) {
return marshalMessageSet(exts, false)
}
// marshaMessageSet implements above function, with the opt to turn on / off deterministic during Marshal.
func marshalMessageSet(exts interface{}, deterministic bool) ([]byte, error) {
switch exts := exts.(type) {
case *XXX_InternalExtensions:
var u marshalInfo
siz := u.sizeMessageSet(exts)
b := make([]byte, 0, siz)
return u.appendMessageSet(b, exts, deterministic)
case map[int32]Extension:
// This is an old-style extension map.
// Wrap it in a new-style XXX_InternalExtensions.
ie := XXX_InternalExtensions{
p: &struct {
mu sync.Mutex
extensionMap map[int32]Extension
}{
extensionMap: exts,
},
}
var u marshalInfo
siz := u.sizeMessageSet(&ie)
b := make([]byte, 0, siz)
return u.appendMessageSet(b, &ie, deterministic)
default:
return nil, errors.New("proto: not an extension map")
}
}
// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
// It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option. // It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
func unmarshalMessageSet(buf []byte, exts interface{}) error { func UnmarshalMessageSet(buf []byte, exts interface{}) error {
var m map[int32]Extension var m map[int32]Extension
switch exts := exts.(type) { switch exts := exts.(type) {
case *XXX_InternalExtensions: case *XXX_InternalExtensions:
@ -179,3 +222,93 @@ func unmarshalMessageSet(buf []byte, exts interface{}) error {
} }
return nil return nil
} }
// MarshalMessageSetJSON encodes the extension map represented by m in JSON format.
// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
func MarshalMessageSetJSON(exts interface{}) ([]byte, error) {
var m map[int32]Extension
switch exts := exts.(type) {
case *XXX_InternalExtensions:
var mu sync.Locker
m, mu = exts.extensionsRead()
if m != nil {
// Keep the extensions map locked until we're done marshaling to prevent
// races between marshaling and unmarshaling the lazily-{en,de}coded
// values.
mu.Lock()
defer mu.Unlock()
}
case map[int32]Extension:
m = exts
default:
return nil, errors.New("proto: not an extension map")
}
var b bytes.Buffer
b.WriteByte('{')
// Process the map in key order for deterministic output.
ids := make([]int32, 0, len(m))
for id := range m {
ids = append(ids, id)
}
sort.Sort(int32Slice(ids)) // int32Slice defined in text.go
for i, id := range ids {
ext := m[id]
msd, ok := messageSetMap[id]
if !ok {
// Unknown type; we can't render it, so skip it.
continue
}
if i > 0 && b.Len() > 1 {
b.WriteByte(',')
}
fmt.Fprintf(&b, `"[%s]":`, msd.name)
x := ext.value
if x == nil {
x = reflect.New(msd.t.Elem()).Interface()
if err := Unmarshal(ext.enc, x.(Message)); err != nil {
return nil, err
}
}
d, err := json.Marshal(x)
if err != nil {
return nil, err
}
b.Write(d)
}
b.WriteByte('}')
return b.Bytes(), nil
}
// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format.
// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error {
// Common-case fast path.
if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) {
return nil
}
// This is fairly tricky, and it's not clear that it is needed.
return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented")
}
// A global registry of types that can be used in a MessageSet.
var messageSetMap = make(map[int32]messageSetDesc)
type messageSetDesc struct {
t reflect.Type // pointer to struct
name string
}
// RegisterMessageSetType is called from the generated code.
func RegisterMessageSetType(m Message, fieldNum int32, name string) {
messageSetMap[fieldNum] = messageSetDesc{
t: reflect.TypeOf(m),
name: name,
}
}

View File

@ -79,13 +79,10 @@ func toPointer(i *Message) pointer {
// toAddrPointer converts an interface to a pointer that points to // toAddrPointer converts an interface to a pointer that points to
// the interface data. // the interface data.
func toAddrPointer(i *interface{}, isptr, deref bool) pointer { func toAddrPointer(i *interface{}, isptr bool) pointer {
v := reflect.ValueOf(*i) v := reflect.ValueOf(*i)
u := reflect.New(v.Type()) u := reflect.New(v.Type())
u.Elem().Set(v) u.Elem().Set(v)
if deref {
u = u.Elem()
}
return pointer{v: u} return pointer{v: u}
} }

View File

@ -85,21 +85,16 @@ func toPointer(i *Message) pointer {
// toAddrPointer converts an interface to a pointer that points to // toAddrPointer converts an interface to a pointer that points to
// the interface data. // the interface data.
func toAddrPointer(i *interface{}, isptr, deref bool) (p pointer) { func toAddrPointer(i *interface{}, isptr bool) pointer {
// Super-tricky - read or get the address of data word of interface value. // Super-tricky - read or get the address of data word of interface value.
if isptr { if isptr {
// The interface is of pointer type, thus it is a direct interface. // The interface is of pointer type, thus it is a direct interface.
// The data word is the pointer data itself. We take its address. // The data word is the pointer data itself. We take its address.
p = pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)} return pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)}
} else { }
// The interface is not of pointer type. The data word is the pointer // The interface is not of pointer type. The data word is the pointer
// to the data. // to the data.
p = pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]}
}
if deref {
p.p = *(*unsafe.Pointer)(p.p)
}
return p
} }
// valToPointer converts v to a pointer. v must be of pointer type. // valToPointer converts v to a pointer. v must be of pointer type.

View File

@ -334,6 +334,9 @@ func GetProperties(t reflect.Type) *StructProperties {
sprop, ok := propertiesMap[t] sprop, ok := propertiesMap[t]
propertiesMu.RUnlock() propertiesMu.RUnlock()
if ok { if ok {
if collectStats {
stats.Chit++
}
return sprop return sprop
} }
@ -343,20 +346,17 @@ func GetProperties(t reflect.Type) *StructProperties {
return sprop return sprop
} }
type (
oneofFuncsIface interface {
XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
}
oneofWrappersIface interface {
XXX_OneofWrappers() []interface{}
}
)
// getPropertiesLocked requires that propertiesMu is held. // getPropertiesLocked requires that propertiesMu is held.
func getPropertiesLocked(t reflect.Type) *StructProperties { func getPropertiesLocked(t reflect.Type) *StructProperties {
if prop, ok := propertiesMap[t]; ok { if prop, ok := propertiesMap[t]; ok {
if collectStats {
stats.Chit++
}
return prop return prop
} }
if collectStats {
stats.Cmiss++
}
prop := new(StructProperties) prop := new(StructProperties)
// in case of recursive protos, fill this in now. // in case of recursive protos, fill this in now.
@ -391,14 +391,13 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
// Re-order prop.order. // Re-order prop.order.
sort.Sort(prop) sort.Sort(prop)
var oots []interface{} type oneofMessage interface {
switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
case oneofFuncsIface:
_, _, _, oots = m.XXX_OneofFuncs()
case oneofWrappersIface:
oots = m.XXX_OneofWrappers()
} }
if len(oots) > 0 { if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok {
var oots []interface{}
_, _, _, oots = om.XXX_OneofFuncs()
// Interpret oneof metadata. // Interpret oneof metadata.
prop.OneofTypes = make(map[string]*OneofProperties) prop.OneofTypes = make(map[string]*OneofProperties)
for _, oot := range oots { for _, oot := range oots {

View File

@ -87,7 +87,6 @@ type marshalElemInfo struct {
sizer sizer sizer sizer
marshaler marshaler marshaler marshaler
isptr bool // elem is pointer typed, thus interface of this type is a direct interface (extension only) isptr bool // elem is pointer typed, thus interface of this type is a direct interface (extension only)
deref bool // dereference the pointer before operating on it; implies isptr
} }
var ( var (
@ -321,11 +320,8 @@ func (u *marshalInfo) computeMarshalInfo() {
// get oneof implementers // get oneof implementers
var oneofImplementers []interface{} var oneofImplementers []interface{}
switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { if m, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok {
case oneofFuncsIface:
_, _, _, oneofImplementers = m.XXX_OneofFuncs() _, _, _, oneofImplementers = m.XXX_OneofFuncs()
case oneofWrappersIface:
oneofImplementers = m.XXX_OneofWrappers()
} }
n := t.NumField() n := t.NumField()
@ -411,22 +407,13 @@ func (u *marshalInfo) getExtElemInfo(desc *ExtensionDesc) *marshalElemInfo {
panic("tag is not an integer") panic("tag is not an integer")
} }
wt := wiretype(tags[0]) wt := wiretype(tags[0])
if t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct {
t = t.Elem()
}
sizer, marshaler := typeMarshaler(t, tags, false, false) sizer, marshaler := typeMarshaler(t, tags, false, false)
var deref bool
if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 {
t = reflect.PtrTo(t)
deref = true
}
e = &marshalElemInfo{ e = &marshalElemInfo{
wiretag: uint64(tag)<<3 | wt, wiretag: uint64(tag)<<3 | wt,
tagsize: SizeVarint(uint64(tag) << 3), tagsize: SizeVarint(uint64(tag) << 3),
sizer: sizer, sizer: sizer,
marshaler: marshaler, marshaler: marshaler,
isptr: t.Kind() == reflect.Ptr, isptr: t.Kind() == reflect.Ptr,
deref: deref,
} }
// update cache // update cache
@ -461,7 +448,7 @@ func (fi *marshalFieldInfo) computeMarshalFieldInfo(f *reflect.StructField) {
func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofImplementers []interface{}) { func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofImplementers []interface{}) {
fi.field = toField(f) fi.field = toField(f)
fi.wiretag = math.MaxInt32 // Use a large tag number, make oneofs sorted at the end. This tag will not appear on the wire. fi.wiretag = 1<<31 - 1 // Use a large tag number, make oneofs sorted at the end. This tag will not appear on the wire.
fi.isPointer = true fi.isPointer = true
fi.sizer, fi.marshaler = makeOneOfMarshaler(fi, f) fi.sizer, fi.marshaler = makeOneOfMarshaler(fi, f)
fi.oneofElems = make(map[reflect.Type]*marshalElemInfo) fi.oneofElems = make(map[reflect.Type]*marshalElemInfo)
@ -489,6 +476,10 @@ func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofI
} }
} }
type oneofMessage interface {
XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
}
// wiretype returns the wire encoding of the type. // wiretype returns the wire encoding of the type.
func wiretype(encoding string) uint64 { func wiretype(encoding string) uint64 {
switch encoding { switch encoding {
@ -2319,8 +2310,8 @@ func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) {
for _, k := range m.MapKeys() { for _, k := range m.MapKeys() {
ki := k.Interface() ki := k.Interface()
vi := m.MapIndex(k).Interface() vi := m.MapIndex(k).Interface()
kaddr := toAddrPointer(&ki, false, false) // pointer to key kaddr := toAddrPointer(&ki, false) // pointer to key
vaddr := toAddrPointer(&vi, valIsPtr, false) // pointer to value vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value
siz := keySizer(kaddr, 1) + valSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1) siz := keySizer(kaddr, 1) + valSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1)
n += siz + SizeVarint(uint64(siz)) + tagsize n += siz + SizeVarint(uint64(siz)) + tagsize
} }
@ -2338,8 +2329,8 @@ func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) {
for _, k := range keys { for _, k := range keys {
ki := k.Interface() ki := k.Interface()
vi := m.MapIndex(k).Interface() vi := m.MapIndex(k).Interface()
kaddr := toAddrPointer(&ki, false, false) // pointer to key kaddr := toAddrPointer(&ki, false) // pointer to key
vaddr := toAddrPointer(&vi, valIsPtr, false) // pointer to value vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value
b = appendVarint(b, tag) b = appendVarint(b, tag)
siz := keySizer(kaddr, 1) + valCachedSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1) siz := keySizer(kaddr, 1) + valCachedSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1)
b = appendVarint(b, uint64(siz)) b = appendVarint(b, uint64(siz))
@ -2408,7 +2399,7 @@ func (u *marshalInfo) sizeExtensions(ext *XXX_InternalExtensions) int {
// the last time this function was called. // the last time this function was called.
ei := u.getExtElemInfo(e.desc) ei := u.getExtElemInfo(e.desc)
v := e.value v := e.value
p := toAddrPointer(&v, ei.isptr, ei.deref) p := toAddrPointer(&v, ei.isptr)
n += ei.sizer(p, ei.tagsize) n += ei.sizer(p, ei.tagsize)
} }
mu.Unlock() mu.Unlock()
@ -2443,7 +2434,7 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de
ei := u.getExtElemInfo(e.desc) ei := u.getExtElemInfo(e.desc)
v := e.value v := e.value
p := toAddrPointer(&v, ei.isptr, ei.deref) p := toAddrPointer(&v, ei.isptr)
b, err = ei.marshaler(b, p, ei.wiretag, deterministic) b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
if !nerr.Merge(err) { if !nerr.Merge(err) {
return b, err return b, err
@ -2474,7 +2465,7 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de
ei := u.getExtElemInfo(e.desc) ei := u.getExtElemInfo(e.desc)
v := e.value v := e.value
p := toAddrPointer(&v, ei.isptr, ei.deref) p := toAddrPointer(&v, ei.isptr)
b, err = ei.marshaler(b, p, ei.wiretag, deterministic) b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
if !nerr.Merge(err) { if !nerr.Merge(err) {
return b, err return b, err
@ -2519,7 +2510,7 @@ func (u *marshalInfo) sizeMessageSet(ext *XXX_InternalExtensions) int {
ei := u.getExtElemInfo(e.desc) ei := u.getExtElemInfo(e.desc)
v := e.value v := e.value
p := toAddrPointer(&v, ei.isptr, ei.deref) p := toAddrPointer(&v, ei.isptr)
n += ei.sizer(p, 1) // message, tag = 3 (size=1) n += ei.sizer(p, 1) // message, tag = 3 (size=1)
} }
mu.Unlock() mu.Unlock()
@ -2562,7 +2553,7 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de
ei := u.getExtElemInfo(e.desc) ei := u.getExtElemInfo(e.desc)
v := e.value v := e.value
p := toAddrPointer(&v, ei.isptr, ei.deref) p := toAddrPointer(&v, ei.isptr)
b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
if !nerr.Merge(err) { if !nerr.Merge(err) {
return b, err return b, err
@ -2600,7 +2591,7 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de
ei := u.getExtElemInfo(e.desc) ei := u.getExtElemInfo(e.desc)
v := e.value v := e.value
p := toAddrPointer(&v, ei.isptr, ei.deref) p := toAddrPointer(&v, ei.isptr)
b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
b = append(b, 1<<3|WireEndGroup) b = append(b, 1<<3|WireEndGroup)
if !nerr.Merge(err) { if !nerr.Merge(err) {
@ -2630,7 +2621,7 @@ func (u *marshalInfo) sizeV1Extensions(m map[int32]Extension) int {
ei := u.getExtElemInfo(e.desc) ei := u.getExtElemInfo(e.desc)
v := e.value v := e.value
p := toAddrPointer(&v, ei.isptr, ei.deref) p := toAddrPointer(&v, ei.isptr)
n += ei.sizer(p, ei.tagsize) n += ei.sizer(p, ei.tagsize)
} }
return n return n
@ -2665,7 +2656,7 @@ func (u *marshalInfo) appendV1Extensions(b []byte, m map[int32]Extension, determ
ei := u.getExtElemInfo(e.desc) ei := u.getExtElemInfo(e.desc)
v := e.value v := e.value
p := toAddrPointer(&v, ei.isptr, ei.deref) p := toAddrPointer(&v, ei.isptr)
b, err = ei.marshaler(b, p, ei.wiretag, deterministic) b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
if !nerr.Merge(err) { if !nerr.Merge(err) {
return b, err return b, err

View File

@ -136,7 +136,7 @@ func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error {
u.computeUnmarshalInfo() u.computeUnmarshalInfo()
} }
if u.isMessageSet { if u.isMessageSet {
return unmarshalMessageSet(b, m.offset(u.extensions).toExtensions()) return UnmarshalMessageSet(b, m.offset(u.extensions).toExtensions())
} }
var reqMask uint64 // bitmask of required fields we've seen. var reqMask uint64 // bitmask of required fields we've seen.
var errLater error var errLater error
@ -362,15 +362,13 @@ func (u *unmarshalInfo) computeUnmarshalInfo() {
} }
// Find any types associated with oneof fields. // Find any types associated with oneof fields.
var oneofImplementers []interface{} // TODO: XXX_OneofFuncs returns more info than we need. Get rid of some of it?
switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { fn := reflect.Zero(reflect.PtrTo(t)).MethodByName("XXX_OneofFuncs")
case oneofFuncsIface: if fn.IsValid() {
_, _, _, oneofImplementers = m.XXX_OneofFuncs() res := fn.Call(nil)[3] // last return value from XXX_OneofFuncs: []interface{}
case oneofWrappersIface: for i := res.Len() - 1; i >= 0; i-- {
oneofImplementers = m.XXX_OneofWrappers() v := res.Index(i) // interface{}
} tptr := reflect.ValueOf(v.Interface()).Type() // *Msg_X
for _, v := range oneofImplementers {
tptr := reflect.TypeOf(v) // *Msg_X
typ := tptr.Elem() // Msg_X typ := tptr.Elem() // Msg_X
f := typ.Field(0) // oneof implementers have one field f := typ.Field(0) // oneof implementers have one field
@ -399,11 +397,11 @@ func (u *unmarshalInfo) computeUnmarshalInfo() {
u.setTag(fieldNum, of.field, unmarshal, 0, name) u.setTag(fieldNum, of.field, unmarshal, 0, name)
} }
} }
}
} }
// Get extension ranges, if any. // Get extension ranges, if any.
fn := reflect.Zero(reflect.PtrTo(t)).MethodByName("ExtensionRangeArray") fn = reflect.Zero(reflect.PtrTo(t)).MethodByName("ExtensionRangeArray")
if fn.IsValid() { if fn.IsValid() {
if !u.extensions.IsValid() && !u.oldExtensions.IsValid() { if !u.extensions.IsValid() && !u.oldExtensions.IsValid() {
panic("a message with extensions, but no extensions field in " + t.Name()) panic("a message with extensions, but no extensions field in " + t.Name())
@ -1950,7 +1948,7 @@ func encodeVarint(b []byte, x uint64) []byte {
// If there is an error, it returns 0,0. // If there is an error, it returns 0,0.
func decodeVarint(b []byte) (uint64, int) { func decodeVarint(b []byte) (uint64, int) {
var x, y uint64 var x, y uint64
if len(b) == 0 { if len(b) <= 0 {
goto bad goto bad
} }
x = uint64(b[0]) x = uint64(b[0])

View File

@ -31,7 +31,7 @@ Let's start with an example that shows the sessions API in a nutshell:
// environmental variable, or flag (or both), and don't accidentally commit it // environmental variable, or flag (or both), and don't accidentally commit it
// alongside your code. Ensure your key is sufficiently random - i.e. use Go's // alongside your code. Ensure your key is sufficiently random - i.e. use Go's
// crypto/rand or securecookie.GenerateRandomKey(32) and persist the result. // crypto/rand or securecookie.GenerateRandomKey(32) and persist the result.
var store = sessions.NewCookieStore(os.Getenv("SESSION_KEY")) var store = sessions.NewCookieStore([]byte(os.Getenv("SESSION_KEY")))
func MyHandler(w http.ResponseWriter, r *http.Request) { func MyHandler(w http.ResponseWriter, r *http.Request) {
// Get a session. We're ignoring the error resulted from decoding an // Get a session. We're ignoring the error resulted from decoding an
@ -51,18 +51,6 @@ secret key used to authenticate the session. Inside the handler, we call
some session values in session.Values, which is a `map[interface{}]interface{}`. some session values in session.Values, which is a `map[interface{}]interface{}`.
And finally we call `session.Save()` to save the session in the response. And finally we call `session.Save()` to save the session in the response.
Important Note: If you aren't using gorilla/mux, you need to wrap your handlers
with
[`context.ClearHandler`](https://www.gorillatoolkit.org/pkg/context#ClearHandler)
or else you will leak memory! An easy way to do this is to wrap the top-level
mux when calling http.ListenAndServe:
```go
http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux))
```
The ClearHandler function is provided by the gorilla/context package.
More examples are available [on the Gorilla More examples are available [on the Gorilla
website](https://www.gorillatoolkit.org/pkg/sessions). website](https://www.gorillatoolkit.org/pkg/sessions).

View File

@ -59,14 +59,6 @@ session.Save(r, w), and either display an error message or otherwise handle it.
Save must be called before writing to the response, otherwise the session Save must be called before writing to the response, otherwise the session
cookie will not be sent to the client. cookie will not be sent to the client.
Important Note: If you aren't using gorilla/mux, you need to wrap your handlers
with context.ClearHandler as or else you will leak memory! An easy way to do this
is to wrap the top-level mux when calling http.ListenAndServe:
http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux))
The ClearHandler function is provided by the gorilla/context package.
That's all you need to know for the basic usage. Let's take a look at other That's all you need to know for the basic usage. Let's take a look at other
options, starting with flash messages. options, starting with flash messages.

View File

@ -5,12 +5,11 @@
package sessions package sessions
import ( import (
"context"
"encoding/gob" "encoding/gob"
"fmt" "fmt"
"net/http" "net/http"
"time" "time"
"github.com/gorilla/context"
) )
// Default flashes key. // Default flashes key.
@ -108,7 +107,8 @@ const registryKey contextKey = 0
// GetRegistry returns a registry instance for the current request. // GetRegistry returns a registry instance for the current request.
func GetRegistry(r *http.Request) *Registry { func GetRegistry(r *http.Request) *Registry {
registry := context.Get(r, registryKey) var ctx = r.Context()
registry := ctx.Value(registryKey)
if registry != nil { if registry != nil {
return registry.(*Registry) return registry.(*Registry)
} }
@ -116,7 +116,7 @@ func GetRegistry(r *http.Request) *Registry {
request: r, request: r,
sessions: make(map[string]sessionInfo), sessions: make(map[string]sessionInfo),
} }
context.Set(r, registryKey, newRegistry) *r = *r.WithContext(context.WithValue(ctx, registryKey, newRegistry))
return newRegistry return newRegistry
} }

21
vendor/github.com/json-iterator/go/Gopkg.lock generated vendored Normal file
View File

@ -0,0 +1,21 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/modern-go/concurrent"
packages = ["."]
revision = "e0a39a4cb4216ea8db28e22a69f4ec25610d513a"
version = "1.0.0"
[[projects]]
name = "github.com/modern-go/reflect2"
packages = ["."]
revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd"
version = "1.0.1"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "ea54a775e5a354cb015502d2e7aa4b74230fc77e894f34a838b268c25ec8eeb8"
solver-name = "gps-cdcl"
solver-version = 1

26
vendor/github.com/json-iterator/go/Gopkg.toml generated vendored Normal file
View File

@ -0,0 +1,26 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
ignored = ["github.com/davecgh/go-spew*","github.com/google/gofuzz*","github.com/stretchr/testify*"]
[[constraint]]
name = "github.com/modern-go/reflect2"
version = "1.0.1"

21
vendor/github.com/json-iterator/go/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 json-iterator
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

91
vendor/github.com/json-iterator/go/README.md generated vendored Normal file
View File

@ -0,0 +1,91 @@
[![Sourcegraph](https://sourcegraph.com/github.com/json-iterator/go/-/badge.svg)](https://sourcegraph.com/github.com/json-iterator/go?badge)
[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/json-iterator/go)
[![Build Status](https://travis-ci.org/json-iterator/go.svg?branch=master)](https://travis-ci.org/json-iterator/go)
[![codecov](https://codecov.io/gh/json-iterator/go/branch/master/graph/badge.svg)](https://codecov.io/gh/json-iterator/go)
[![rcard](https://goreportcard.com/badge/github.com/json-iterator/go)](https://goreportcard.com/report/github.com/json-iterator/go)
[![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/json-iterator/go/master/LICENSE)
[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/json-iterator/Lobby)
A high-performance 100% compatible drop-in replacement of "encoding/json"
You can also use thrift like JSON using [thrift-iterator](https://github.com/thrift-iterator/go)
```
Go开发者们请加入我们滴滴出行平台技术部 taowen@didichuxing.com
```
# Benchmark
![benchmark](http://jsoniter.com/benchmarks/go-benchmark.png)
Source code: https://github.com/json-iterator/go-benchmark/blob/master/src/github.com/json-iterator/go-benchmark/benchmark_medium_payload_test.go
Raw Result (easyjson requires static code generation)
| | ns/op | allocation bytes | allocation times |
| --- | --- | --- | --- |
| std decode | 35510 ns/op | 1960 B/op | 99 allocs/op |
| easyjson decode | 8499 ns/op | 160 B/op | 4 allocs/op |
| jsoniter decode | 5623 ns/op | 160 B/op | 3 allocs/op |
| std encode | 2213 ns/op | 712 B/op | 5 allocs/op |
| easyjson encode | 883 ns/op | 576 B/op | 3 allocs/op |
| jsoniter encode | 837 ns/op | 384 B/op | 4 allocs/op |
Always benchmark with your own workload.
The result depends heavily on the data input.
# Usage
100% compatibility with standard lib
Replace
```go
import "encoding/json"
json.Marshal(&data)
```
with
```go
import "github.com/json-iterator/go"
var json = jsoniter.ConfigCompatibleWithStandardLibrary
json.Marshal(&data)
```
Replace
```go
import "encoding/json"
json.Unmarshal(input, &data)
```
with
```go
import "github.com/json-iterator/go"
var json = jsoniter.ConfigCompatibleWithStandardLibrary
json.Unmarshal(input, &data)
```
[More documentation](http://jsoniter.com/migrate-from-go-std.html)
# How to get
```
go get github.com/json-iterator/go
```
# Contribution Welcomed !
Contributors
* [thockin](https://github.com/thockin)
* [mattn](https://github.com/mattn)
* [cch123](https://github.com/cch123)
* [Oleg Shaldybin](https://github.com/olegshaldybin)
* [Jason Toffaletti](https://github.com/toffaletti)
Report issue or pull request, or email taowen@gmail.com, or [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/json-iterator/Lobby)

150
vendor/github.com/json-iterator/go/adapter.go generated vendored Normal file
View File

@ -0,0 +1,150 @@
package jsoniter
import (
"bytes"
"io"
)
// RawMessage to make replace json with jsoniter
type RawMessage []byte
// Unmarshal adapts to json/encoding Unmarshal API
//
// Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v.
// Refer to https://godoc.org/encoding/json#Unmarshal for more information
func Unmarshal(data []byte, v interface{}) error {
return ConfigDefault.Unmarshal(data, v)
}
// UnmarshalFromString convenient method to read from string instead of []byte
func UnmarshalFromString(str string, v interface{}) error {
return ConfigDefault.UnmarshalFromString(str, v)
}
// Get quick method to get value from deeply nested JSON structure
func Get(data []byte, path ...interface{}) Any {
return ConfigDefault.Get(data, path...)
}
// Marshal adapts to json/encoding Marshal API
//
// Marshal returns the JSON encoding of v, adapts to json/encoding Marshal API
// Refer to https://godoc.org/encoding/json#Marshal for more information
func Marshal(v interface{}) ([]byte, error) {
return ConfigDefault.Marshal(v)
}
// MarshalIndent same as json.MarshalIndent. Prefix is not supported.
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
return ConfigDefault.MarshalIndent(v, prefix, indent)
}
// MarshalToString convenient method to write as string instead of []byte
func MarshalToString(v interface{}) (string, error) {
return ConfigDefault.MarshalToString(v)
}
// NewDecoder adapts to json/stream NewDecoder API.
//
// NewDecoder returns a new decoder that reads from r.
//
// Instead of a json/encoding Decoder, an Decoder is returned
// Refer to https://godoc.org/encoding/json#NewDecoder for more information
func NewDecoder(reader io.Reader) *Decoder {
return ConfigDefault.NewDecoder(reader)
}
// Decoder reads and decodes JSON values from an input stream.
// Decoder provides identical APIs with json/stream Decoder (Token() and UseNumber() are in progress)
type Decoder struct {
iter *Iterator
}
// Decode decode JSON into interface{}
func (adapter *Decoder) Decode(obj interface{}) error {
if adapter.iter.head == adapter.iter.tail && adapter.iter.reader != nil {
if !adapter.iter.loadMore() {
return io.EOF
}
}
adapter.iter.ReadVal(obj)
err := adapter.iter.Error
if err == io.EOF {
return nil
}
return adapter.iter.Error
}
// More is there more?
func (adapter *Decoder) More() bool {
iter := adapter.iter
if iter.Error != nil {
return false
}
c := iter.nextToken()
if c == 0 {
return false
}
iter.unreadByte()
return c != ']' && c != '}'
}
// Buffered remaining buffer
func (adapter *Decoder) Buffered() io.Reader {
remaining := adapter.iter.buf[adapter.iter.head:adapter.iter.tail]
return bytes.NewReader(remaining)
}
// UseNumber causes the Decoder to unmarshal a number into an interface{} as a
// Number instead of as a float64.
func (adapter *Decoder) UseNumber() {
cfg := adapter.iter.cfg.configBeforeFrozen
cfg.UseNumber = true
adapter.iter.cfg = cfg.frozeWithCacheReuse(adapter.iter.cfg.extraExtensions)
}
// DisallowUnknownFields causes the Decoder to return an error when the destination
// is a struct and the input contains object keys which do not match any
// non-ignored, exported fields in the destination.
func (adapter *Decoder) DisallowUnknownFields() {
cfg := adapter.iter.cfg.configBeforeFrozen
cfg.DisallowUnknownFields = true
adapter.iter.cfg = cfg.frozeWithCacheReuse(adapter.iter.cfg.extraExtensions)
}
// NewEncoder same as json.NewEncoder
func NewEncoder(writer io.Writer) *Encoder {
return ConfigDefault.NewEncoder(writer)
}
// Encoder same as json.Encoder
type Encoder struct {
stream *Stream
}
// Encode encode interface{} as JSON to io.Writer
func (adapter *Encoder) Encode(val interface{}) error {
adapter.stream.WriteVal(val)
adapter.stream.WriteRaw("\n")
adapter.stream.Flush()
return adapter.stream.Error
}
// SetIndent set the indention. Prefix is not supported
func (adapter *Encoder) SetIndent(prefix, indent string) {
config := adapter.stream.cfg.configBeforeFrozen
config.IndentionStep = len(indent)
adapter.stream.cfg = config.frozeWithCacheReuse(adapter.stream.cfg.extraExtensions)
}
// SetEscapeHTML escape html by default, set to false to disable
func (adapter *Encoder) SetEscapeHTML(escapeHTML bool) {
config := adapter.stream.cfg.configBeforeFrozen
config.EscapeHTML = escapeHTML
adapter.stream.cfg = config.frozeWithCacheReuse(adapter.stream.cfg.extraExtensions)
}
// Valid reports whether data is a valid JSON encoding.
func Valid(data []byte) bool {
return ConfigDefault.Valid(data)
}

321
vendor/github.com/json-iterator/go/any.go generated vendored Normal file
View File

@ -0,0 +1,321 @@
package jsoniter
import (
"errors"
"fmt"
"github.com/modern-go/reflect2"
"io"
"reflect"
"strconv"
"unsafe"
)
// Any generic object representation.
// The lazy json implementation holds []byte and parse lazily.
type Any interface {
LastError() error
ValueType() ValueType
MustBeValid() Any
ToBool() bool
ToInt() int
ToInt32() int32
ToInt64() int64
ToUint() uint
ToUint32() uint32
ToUint64() uint64
ToFloat32() float32
ToFloat64() float64
ToString() string
ToVal(val interface{})
Get(path ...interface{}) Any
Size() int
Keys() []string
GetInterface() interface{}
WriteTo(stream *Stream)
}
type baseAny struct{}
func (any *baseAny) Get(path ...interface{}) Any {
return &invalidAny{baseAny{}, fmt.Errorf("GetIndex %v from simple value", path)}
}
func (any *baseAny) Size() int {
return 0
}
func (any *baseAny) Keys() []string {
return []string{}
}
func (any *baseAny) ToVal(obj interface{}) {
panic("not implemented")
}
// WrapInt32 turn int32 into Any interface
func WrapInt32(val int32) Any {
return &int32Any{baseAny{}, val}
}
// WrapInt64 turn int64 into Any interface
func WrapInt64(val int64) Any {
return &int64Any{baseAny{}, val}
}
// WrapUint32 turn uint32 into Any interface
func WrapUint32(val uint32) Any {
return &uint32Any{baseAny{}, val}
}
// WrapUint64 turn uint64 into Any interface
func WrapUint64(val uint64) Any {
return &uint64Any{baseAny{}, val}
}
// WrapFloat64 turn float64 into Any interface
func WrapFloat64(val float64) Any {
return &floatAny{baseAny{}, val}
}
// WrapString turn string into Any interface
func WrapString(val string) Any {
return &stringAny{baseAny{}, val}
}
// Wrap turn a go object into Any interface
func Wrap(val interface{}) Any {
if val == nil {
return &nilAny{}
}
asAny, isAny := val.(Any)
if isAny {
return asAny
}
typ := reflect2.TypeOf(val)
switch typ.Kind() {
case reflect.Slice:
return wrapArray(val)
case reflect.Struct:
return wrapStruct(val)
case reflect.Map:
return wrapMap(val)
case reflect.String:
return WrapString(val.(string))
case reflect.Int:
if strconv.IntSize == 32 {
return WrapInt32(int32(val.(int)))
}
return WrapInt64(int64(val.(int)))
case reflect.Int8:
return WrapInt32(int32(val.(int8)))
case reflect.Int16:
return WrapInt32(int32(val.(int16)))
case reflect.Int32:
return WrapInt32(val.(int32))
case reflect.Int64:
return WrapInt64(val.(int64))
case reflect.Uint:
if strconv.IntSize == 32 {
return WrapUint32(uint32(val.(uint)))
}
return WrapUint64(uint64(val.(uint)))
case reflect.Uintptr:
if ptrSize == 32 {
return WrapUint32(uint32(val.(uintptr)))
}
return WrapUint64(uint64(val.(uintptr)))
case reflect.Uint8:
return WrapUint32(uint32(val.(uint8)))
case reflect.Uint16:
return WrapUint32(uint32(val.(uint16)))
case reflect.Uint32:
return WrapUint32(uint32(val.(uint32)))
case reflect.Uint64:
return WrapUint64(val.(uint64))
case reflect.Float32:
return WrapFloat64(float64(val.(float32)))
case reflect.Float64:
return WrapFloat64(val.(float64))
case reflect.Bool:
if val.(bool) == true {
return &trueAny{}
}
return &falseAny{}
}
return &invalidAny{baseAny{}, fmt.Errorf("unsupported type: %v", typ)}
}
// ReadAny read next JSON element as an Any object. It is a better json.RawMessage.
func (iter *Iterator) ReadAny() Any {
return iter.readAny()
}
func (iter *Iterator) readAny() Any {
c := iter.nextToken()
switch c {
case '"':
iter.unreadByte()
return &stringAny{baseAny{}, iter.ReadString()}
case 'n':
iter.skipThreeBytes('u', 'l', 'l') // null
return &nilAny{}
case 't':
iter.skipThreeBytes('r', 'u', 'e') // true
return &trueAny{}
case 'f':
iter.skipFourBytes('a', 'l', 's', 'e') // false
return &falseAny{}
case '{':
return iter.readObjectAny()
case '[':
return iter.readArrayAny()
case '-':
return iter.readNumberAny(false)
case 0:
return &invalidAny{baseAny{}, errors.New("input is empty")}
default:
return iter.readNumberAny(true)
}
}
func (iter *Iterator) readNumberAny(positive bool) Any {
iter.startCapture(iter.head - 1)
iter.skipNumber()
lazyBuf := iter.stopCapture()
return &numberLazyAny{baseAny{}, iter.cfg, lazyBuf, nil}
}
func (iter *Iterator) readObjectAny() Any {
iter.startCapture(iter.head - 1)
iter.skipObject()
lazyBuf := iter.stopCapture()
return &objectLazyAny{baseAny{}, iter.cfg, lazyBuf, nil}
}
func (iter *Iterator) readArrayAny() Any {
iter.startCapture(iter.head - 1)
iter.skipArray()
lazyBuf := iter.stopCapture()
return &arrayLazyAny{baseAny{}, iter.cfg, lazyBuf, nil}
}
func locateObjectField(iter *Iterator, target string) []byte {
var found []byte
iter.ReadObjectCB(func(iter *Iterator, field string) bool {
if field == target {
found = iter.SkipAndReturnBytes()
return false
}
iter.Skip()
return true
})
return found
}
func locateArrayElement(iter *Iterator, target int) []byte {
var found []byte
n := 0
iter.ReadArrayCB(func(iter *Iterator) bool {
if n == target {
found = iter.SkipAndReturnBytes()
return false
}
iter.Skip()
n++
return true
})
return found
}
func locatePath(iter *Iterator, path []interface{}) Any {
for i, pathKeyObj := range path {
switch pathKey := pathKeyObj.(type) {
case string:
valueBytes := locateObjectField(iter, pathKey)
if valueBytes == nil {
return newInvalidAny(path[i:])
}
iter.ResetBytes(valueBytes)
case int:
valueBytes := locateArrayElement(iter, pathKey)
if valueBytes == nil {
return newInvalidAny(path[i:])
}
iter.ResetBytes(valueBytes)
case int32:
if '*' == pathKey {
return iter.readAny().Get(path[i:]...)
}
return newInvalidAny(path[i:])
default:
return newInvalidAny(path[i:])
}
}
if iter.Error != nil && iter.Error != io.EOF {
return &invalidAny{baseAny{}, iter.Error}
}
return iter.readAny()
}
var anyType = reflect2.TypeOfPtr((*Any)(nil)).Elem()
func createDecoderOfAny(ctx *ctx, typ reflect2.Type) ValDecoder {
if typ == anyType {
return &directAnyCodec{}
}
if typ.Implements(anyType) {
return &anyCodec{
valType: typ,
}
}
return nil
}
func createEncoderOfAny(ctx *ctx, typ reflect2.Type) ValEncoder {
if typ == anyType {
return &directAnyCodec{}
}
if typ.Implements(anyType) {
return &anyCodec{
valType: typ,
}
}
return nil
}
type anyCodec struct {
valType reflect2.Type
}
func (codec *anyCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
panic("not implemented")
}
func (codec *anyCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
obj := codec.valType.UnsafeIndirect(ptr)
any := obj.(Any)
any.WriteTo(stream)
}
func (codec *anyCodec) IsEmpty(ptr unsafe.Pointer) bool {
obj := codec.valType.UnsafeIndirect(ptr)
any := obj.(Any)
return any.Size() == 0
}
type directAnyCodec struct {
}
func (codec *directAnyCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
*(*Any)(ptr) = iter.readAny()
}
func (codec *directAnyCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
any := *(*Any)(ptr)
any.WriteTo(stream)
}
func (codec *directAnyCodec) IsEmpty(ptr unsafe.Pointer) bool {
any := *(*Any)(ptr)
return any.Size() == 0
}

278
vendor/github.com/json-iterator/go/any_array.go generated vendored Normal file
View File

@ -0,0 +1,278 @@
package jsoniter
import (
"reflect"
"unsafe"
)
type arrayLazyAny struct {
baseAny
cfg *frozenConfig
buf []byte
err error
}
func (any *arrayLazyAny) ValueType() ValueType {
return ArrayValue
}
func (any *arrayLazyAny) MustBeValid() Any {
return any
}
func (any *arrayLazyAny) LastError() error {
return any.err
}
func (any *arrayLazyAny) ToBool() bool {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
return iter.ReadArray()
}
func (any *arrayLazyAny) ToInt() int {
if any.ToBool() {
return 1
}
return 0
}
func (any *arrayLazyAny) ToInt32() int32 {
if any.ToBool() {
return 1
}
return 0
}
func (any *arrayLazyAny) ToInt64() int64 {
if any.ToBool() {
return 1
}
return 0
}
func (any *arrayLazyAny) ToUint() uint {
if any.ToBool() {
return 1
}
return 0
}
func (any *arrayLazyAny) ToUint32() uint32 {
if any.ToBool() {
return 1
}
return 0
}
func (any *arrayLazyAny) ToUint64() uint64 {
if any.ToBool() {
return 1
}
return 0
}
func (any *arrayLazyAny) ToFloat32() float32 {
if any.ToBool() {
return 1
}
return 0
}
func (any *arrayLazyAny) ToFloat64() float64 {
if any.ToBool() {
return 1
}
return 0
}
func (any *arrayLazyAny) ToString() string {
return *(*string)(unsafe.Pointer(&any.buf))
}
func (any *arrayLazyAny) ToVal(val interface{}) {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
iter.ReadVal(val)
}
func (any *arrayLazyAny) Get(path ...interface{}) Any {
if len(path) == 0 {
return any
}
switch firstPath := path[0].(type) {
case int:
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
valueBytes := locateArrayElement(iter, firstPath)
if valueBytes == nil {
return newInvalidAny(path)
}
iter.ResetBytes(valueBytes)
return locatePath(iter, path[1:])
case int32:
if '*' == firstPath {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
arr := make([]Any, 0)
iter.ReadArrayCB(func(iter *Iterator) bool {
found := iter.readAny().Get(path[1:]...)
if found.ValueType() != InvalidValue {
arr = append(arr, found)
}
return true
})
return wrapArray(arr)
}
return newInvalidAny(path)
default:
return newInvalidAny(path)
}
}
func (any *arrayLazyAny) Size() int {
size := 0
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
iter.ReadArrayCB(func(iter *Iterator) bool {
size++
iter.Skip()
return true
})
return size
}
func (any *arrayLazyAny) WriteTo(stream *Stream) {
stream.Write(any.buf)
}
func (any *arrayLazyAny) GetInterface() interface{} {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
return iter.Read()
}
type arrayAny struct {
baseAny
val reflect.Value
}
func wrapArray(val interface{}) *arrayAny {
return &arrayAny{baseAny{}, reflect.ValueOf(val)}
}
func (any *arrayAny) ValueType() ValueType {
return ArrayValue
}
func (any *arrayAny) MustBeValid() Any {
return any
}
func (any *arrayAny) LastError() error {
return nil
}
func (any *arrayAny) ToBool() bool {
return any.val.Len() != 0
}
func (any *arrayAny) ToInt() int {
if any.val.Len() == 0 {
return 0
}
return 1
}
func (any *arrayAny) ToInt32() int32 {
if any.val.Len() == 0 {
return 0
}
return 1
}
func (any *arrayAny) ToInt64() int64 {
if any.val.Len() == 0 {
return 0
}
return 1
}
func (any *arrayAny) ToUint() uint {
if any.val.Len() == 0 {
return 0
}
return 1
}
func (any *arrayAny) ToUint32() uint32 {
if any.val.Len() == 0 {
return 0
}
return 1
}
func (any *arrayAny) ToUint64() uint64 {
if any.val.Len() == 0 {
return 0
}
return 1
}
func (any *arrayAny) ToFloat32() float32 {
if any.val.Len() == 0 {
return 0
}
return 1
}
func (any *arrayAny) ToFloat64() float64 {
if any.val.Len() == 0 {
return 0
}
return 1
}
func (any *arrayAny) ToString() string {
str, _ := MarshalToString(any.val.Interface())
return str
}
func (any *arrayAny) Get(path ...interface{}) Any {
if len(path) == 0 {
return any
}
switch firstPath := path[0].(type) {
case int:
if firstPath < 0 || firstPath >= any.val.Len() {
return newInvalidAny(path)
}
return Wrap(any.val.Index(firstPath).Interface())
case int32:
if '*' == firstPath {
mappedAll := make([]Any, 0)
for i := 0; i < any.val.Len(); i++ {
mapped := Wrap(any.val.Index(i).Interface()).Get(path[1:]...)
if mapped.ValueType() != InvalidValue {
mappedAll = append(mappedAll, mapped)
}
}
return wrapArray(mappedAll)
}
return newInvalidAny(path)
default:
return newInvalidAny(path)
}
}
func (any *arrayAny) Size() int {
return any.val.Len()
}
func (any *arrayAny) WriteTo(stream *Stream) {
stream.WriteVal(any.val)
}
func (any *arrayAny) GetInterface() interface{} {
return any.val.Interface()
}

137
vendor/github.com/json-iterator/go/any_bool.go generated vendored Normal file
View File

@ -0,0 +1,137 @@
package jsoniter
type trueAny struct {
baseAny
}
func (any *trueAny) LastError() error {
return nil
}
func (any *trueAny) ToBool() bool {
return true
}
func (any *trueAny) ToInt() int {
return 1
}
func (any *trueAny) ToInt32() int32 {
return 1
}
func (any *trueAny) ToInt64() int64 {
return 1
}
func (any *trueAny) ToUint() uint {
return 1
}
func (any *trueAny) ToUint32() uint32 {
return 1
}
func (any *trueAny) ToUint64() uint64 {
return 1
}
func (any *trueAny) ToFloat32() float32 {
return 1
}
func (any *trueAny) ToFloat64() float64 {
return 1
}
func (any *trueAny) ToString() string {
return "true"
}
func (any *trueAny) WriteTo(stream *Stream) {
stream.WriteTrue()
}
func (any *trueAny) Parse() *Iterator {
return nil
}
func (any *trueAny) GetInterface() interface{} {
return true
}
func (any *trueAny) ValueType() ValueType {
return BoolValue
}
func (any *trueAny) MustBeValid() Any {
return any
}
type falseAny struct {
baseAny
}
func (any *falseAny) LastError() error {
return nil
}
func (any *falseAny) ToBool() bool {
return false
}
func (any *falseAny) ToInt() int {
return 0
}
func (any *falseAny) ToInt32() int32 {
return 0
}
func (any *falseAny) ToInt64() int64 {
return 0
}
func (any *falseAny) ToUint() uint {
return 0
}
func (any *falseAny) ToUint32() uint32 {
return 0
}
func (any *falseAny) ToUint64() uint64 {
return 0
}
func (any *falseAny) ToFloat32() float32 {
return 0
}
func (any *falseAny) ToFloat64() float64 {
return 0
}
func (any *falseAny) ToString() string {
return "false"
}
func (any *falseAny) WriteTo(stream *Stream) {
stream.WriteFalse()
}
func (any *falseAny) Parse() *Iterator {
return nil
}
func (any *falseAny) GetInterface() interface{} {
return false
}
func (any *falseAny) ValueType() ValueType {
return BoolValue
}
func (any *falseAny) MustBeValid() Any {
return any
}

83
vendor/github.com/json-iterator/go/any_float.go generated vendored Normal file
View File

@ -0,0 +1,83 @@
package jsoniter
import (
"strconv"
)
type floatAny struct {
baseAny
val float64
}
func (any *floatAny) Parse() *Iterator {
return nil
}
func (any *floatAny) ValueType() ValueType {
return NumberValue
}
func (any *floatAny) MustBeValid() Any {
return any
}
func (any *floatAny) LastError() error {
return nil
}
func (any *floatAny) ToBool() bool {
return any.ToFloat64() != 0
}
func (any *floatAny) ToInt() int {
return int(any.val)
}
func (any *floatAny) ToInt32() int32 {
return int32(any.val)
}
func (any *floatAny) ToInt64() int64 {
return int64(any.val)
}
func (any *floatAny) ToUint() uint {
if any.val > 0 {
return uint(any.val)
}
return 0
}
func (any *floatAny) ToUint32() uint32 {
if any.val > 0 {
return uint32(any.val)
}
return 0
}
func (any *floatAny) ToUint64() uint64 {
if any.val > 0 {
return uint64(any.val)
}
return 0
}
func (any *floatAny) ToFloat32() float32 {
return float32(any.val)
}
func (any *floatAny) ToFloat64() float64 {
return any.val
}
func (any *floatAny) ToString() string {
return strconv.FormatFloat(any.val, 'E', -1, 64)
}
func (any *floatAny) WriteTo(stream *Stream) {
stream.WriteFloat64(any.val)
}
func (any *floatAny) GetInterface() interface{} {
return any.val
}

74
vendor/github.com/json-iterator/go/any_int32.go generated vendored Normal file
View File

@ -0,0 +1,74 @@
package jsoniter
import (
"strconv"
)
type int32Any struct {
baseAny
val int32
}
func (any *int32Any) LastError() error {
return nil
}
func (any *int32Any) ValueType() ValueType {
return NumberValue
}
func (any *int32Any) MustBeValid() Any {
return any
}
func (any *int32Any) ToBool() bool {
return any.val != 0
}
func (any *int32Any) ToInt() int {
return int(any.val)
}
func (any *int32Any) ToInt32() int32 {
return any.val
}
func (any *int32Any) ToInt64() int64 {
return int64(any.val)
}
func (any *int32Any) ToUint() uint {
return uint(any.val)
}
func (any *int32Any) ToUint32() uint32 {
return uint32(any.val)
}
func (any *int32Any) ToUint64() uint64 {
return uint64(any.val)
}
func (any *int32Any) ToFloat32() float32 {
return float32(any.val)
}
func (any *int32Any) ToFloat64() float64 {
return float64(any.val)
}
func (any *int32Any) ToString() string {
return strconv.FormatInt(int64(any.val), 10)
}
func (any *int32Any) WriteTo(stream *Stream) {
stream.WriteInt32(any.val)
}
func (any *int32Any) Parse() *Iterator {
return nil
}
func (any *int32Any) GetInterface() interface{} {
return any.val
}

74
vendor/github.com/json-iterator/go/any_int64.go generated vendored Normal file
View File

@ -0,0 +1,74 @@
package jsoniter
import (
"strconv"
)
type int64Any struct {
baseAny
val int64
}
func (any *int64Any) LastError() error {
return nil
}
func (any *int64Any) ValueType() ValueType {
return NumberValue
}
func (any *int64Any) MustBeValid() Any {
return any
}
func (any *int64Any) ToBool() bool {
return any.val != 0
}
func (any *int64Any) ToInt() int {
return int(any.val)
}
func (any *int64Any) ToInt32() int32 {
return int32(any.val)
}
func (any *int64Any) ToInt64() int64 {
return any.val
}
func (any *int64Any) ToUint() uint {
return uint(any.val)
}
func (any *int64Any) ToUint32() uint32 {
return uint32(any.val)
}
func (any *int64Any) ToUint64() uint64 {
return uint64(any.val)
}
func (any *int64Any) ToFloat32() float32 {
return float32(any.val)
}
func (any *int64Any) ToFloat64() float64 {
return float64(any.val)
}
func (any *int64Any) ToString() string {
return strconv.FormatInt(any.val, 10)
}
func (any *int64Any) WriteTo(stream *Stream) {
stream.WriteInt64(any.val)
}
func (any *int64Any) Parse() *Iterator {
return nil
}
func (any *int64Any) GetInterface() interface{} {
return any.val
}

82
vendor/github.com/json-iterator/go/any_invalid.go generated vendored Normal file
View File

@ -0,0 +1,82 @@
package jsoniter
import "fmt"
type invalidAny struct {
baseAny
err error
}
func newInvalidAny(path []interface{}) *invalidAny {
return &invalidAny{baseAny{}, fmt.Errorf("%v not found", path)}
}
func (any *invalidAny) LastError() error {
return any.err
}
func (any *invalidAny) ValueType() ValueType {
return InvalidValue
}
func (any *invalidAny) MustBeValid() Any {
panic(any.err)
}
func (any *invalidAny) ToBool() bool {
return false
}
func (any *invalidAny) ToInt() int {
return 0
}
func (any *invalidAny) ToInt32() int32 {
return 0
}
func (any *invalidAny) ToInt64() int64 {
return 0
}
func (any *invalidAny) ToUint() uint {
return 0
}
func (any *invalidAny) ToUint32() uint32 {
return 0
}
func (any *invalidAny) ToUint64() uint64 {
return 0
}
func (any *invalidAny) ToFloat32() float32 {
return 0
}
func (any *invalidAny) ToFloat64() float64 {
return 0
}
func (any *invalidAny) ToString() string {
return ""
}
func (any *invalidAny) WriteTo(stream *Stream) {
}
func (any *invalidAny) Get(path ...interface{}) Any {
if any.err == nil {
return &invalidAny{baseAny{}, fmt.Errorf("get %v from invalid", path)}
}
return &invalidAny{baseAny{}, fmt.Errorf("%v, get %v from invalid", any.err, path)}
}
func (any *invalidAny) Parse() *Iterator {
return nil
}
func (any *invalidAny) GetInterface() interface{} {
return nil
}

69
vendor/github.com/json-iterator/go/any_nil.go generated vendored Normal file
View File

@ -0,0 +1,69 @@
package jsoniter
type nilAny struct {
baseAny
}
func (any *nilAny) LastError() error {
return nil
}
func (any *nilAny) ValueType() ValueType {
return NilValue
}
func (any *nilAny) MustBeValid() Any {
return any
}
func (any *nilAny) ToBool() bool {
return false
}
func (any *nilAny) ToInt() int {
return 0
}
func (any *nilAny) ToInt32() int32 {
return 0
}
func (any *nilAny) ToInt64() int64 {
return 0
}
func (any *nilAny) ToUint() uint {
return 0
}
func (any *nilAny) ToUint32() uint32 {
return 0
}
func (any *nilAny) ToUint64() uint64 {
return 0
}
func (any *nilAny) ToFloat32() float32 {
return 0
}
func (any *nilAny) ToFloat64() float64 {
return 0
}
func (any *nilAny) ToString() string {
return ""
}
func (any *nilAny) WriteTo(stream *Stream) {
stream.WriteNil()
}
func (any *nilAny) Parse() *Iterator {
return nil
}
func (any *nilAny) GetInterface() interface{} {
return nil
}

123
vendor/github.com/json-iterator/go/any_number.go generated vendored Normal file
View File

@ -0,0 +1,123 @@
package jsoniter
import (
"io"
"unsafe"
)
type numberLazyAny struct {
baseAny
cfg *frozenConfig
buf []byte
err error
}
func (any *numberLazyAny) ValueType() ValueType {
return NumberValue
}
func (any *numberLazyAny) MustBeValid() Any {
return any
}
func (any *numberLazyAny) LastError() error {
return any.err
}
func (any *numberLazyAny) ToBool() bool {
return any.ToFloat64() != 0
}
func (any *numberLazyAny) ToInt() int {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
val := iter.ReadInt()
if iter.Error != nil && iter.Error != io.EOF {
any.err = iter.Error
}
return val
}
func (any *numberLazyAny) ToInt32() int32 {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
val := iter.ReadInt32()
if iter.Error != nil && iter.Error != io.EOF {
any.err = iter.Error
}
return val
}
func (any *numberLazyAny) ToInt64() int64 {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
val := iter.ReadInt64()
if iter.Error != nil && iter.Error != io.EOF {
any.err = iter.Error
}
return val
}
func (any *numberLazyAny) ToUint() uint {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
val := iter.ReadUint()
if iter.Error != nil && iter.Error != io.EOF {
any.err = iter.Error
}
return val
}
func (any *numberLazyAny) ToUint32() uint32 {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
val := iter.ReadUint32()
if iter.Error != nil && iter.Error != io.EOF {
any.err = iter.Error
}
return val
}
func (any *numberLazyAny) ToUint64() uint64 {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
val := iter.ReadUint64()
if iter.Error != nil && iter.Error != io.EOF {
any.err = iter.Error
}
return val
}
func (any *numberLazyAny) ToFloat32() float32 {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
val := iter.ReadFloat32()
if iter.Error != nil && iter.Error != io.EOF {
any.err = iter.Error
}
return val
}
func (any *numberLazyAny) ToFloat64() float64 {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
val := iter.ReadFloat64()
if iter.Error != nil && iter.Error != io.EOF {
any.err = iter.Error
}
return val
}
func (any *numberLazyAny) ToString() string {
return *(*string)(unsafe.Pointer(&any.buf))
}
func (any *numberLazyAny) WriteTo(stream *Stream) {
stream.Write(any.buf)
}
func (any *numberLazyAny) GetInterface() interface{} {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
return iter.Read()
}

374
vendor/github.com/json-iterator/go/any_object.go generated vendored Normal file
View File

@ -0,0 +1,374 @@
package jsoniter
import (
"reflect"
"unsafe"
)
type objectLazyAny struct {
baseAny
cfg *frozenConfig
buf []byte
err error
}
func (any *objectLazyAny) ValueType() ValueType {
return ObjectValue
}
func (any *objectLazyAny) MustBeValid() Any {
return any
}
func (any *objectLazyAny) LastError() error {
return any.err
}
func (any *objectLazyAny) ToBool() bool {
return true
}
func (any *objectLazyAny) ToInt() int {
return 0
}
func (any *objectLazyAny) ToInt32() int32 {
return 0
}
func (any *objectLazyAny) ToInt64() int64 {
return 0
}
func (any *objectLazyAny) ToUint() uint {
return 0
}
func (any *objectLazyAny) ToUint32() uint32 {
return 0
}
func (any *objectLazyAny) ToUint64() uint64 {
return 0
}
func (any *objectLazyAny) ToFloat32() float32 {
return 0
}
func (any *objectLazyAny) ToFloat64() float64 {
return 0
}
func (any *objectLazyAny) ToString() string {
return *(*string)(unsafe.Pointer(&any.buf))
}
func (any *objectLazyAny) ToVal(obj interface{}) {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
iter.ReadVal(obj)
}
func (any *objectLazyAny) Get(path ...interface{}) Any {
if len(path) == 0 {
return any
}
switch firstPath := path[0].(type) {
case string:
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
valueBytes := locateObjectField(iter, firstPath)
if valueBytes == nil {
return newInvalidAny(path)
}
iter.ResetBytes(valueBytes)
return locatePath(iter, path[1:])
case int32:
if '*' == firstPath {
mappedAll := map[string]Any{}
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
iter.ReadMapCB(func(iter *Iterator, field string) bool {
mapped := locatePath(iter, path[1:])
if mapped.ValueType() != InvalidValue {
mappedAll[field] = mapped
}
return true
})
return wrapMap(mappedAll)
}
return newInvalidAny(path)
default:
return newInvalidAny(path)
}
}
func (any *objectLazyAny) Keys() []string {
keys := []string{}
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
iter.ReadMapCB(func(iter *Iterator, field string) bool {
iter.Skip()
keys = append(keys, field)
return true
})
return keys
}
func (any *objectLazyAny) Size() int {
size := 0
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
iter.ReadObjectCB(func(iter *Iterator, field string) bool {
iter.Skip()
size++
return true
})
return size
}
func (any *objectLazyAny) WriteTo(stream *Stream) {
stream.Write(any.buf)
}
func (any *objectLazyAny) GetInterface() interface{} {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
return iter.Read()
}
type objectAny struct {
baseAny
err error
val reflect.Value
}
func wrapStruct(val interface{}) *objectAny {
return &objectAny{baseAny{}, nil, reflect.ValueOf(val)}
}
func (any *objectAny) ValueType() ValueType {
return ObjectValue
}
func (any *objectAny) MustBeValid() Any {
return any
}
func (any *objectAny) Parse() *Iterator {
return nil
}
func (any *objectAny) LastError() error {
return any.err
}
func (any *objectAny) ToBool() bool {
return any.val.NumField() != 0
}
func (any *objectAny) ToInt() int {
return 0
}
func (any *objectAny) ToInt32() int32 {
return 0
}
func (any *objectAny) ToInt64() int64 {
return 0
}
func (any *objectAny) ToUint() uint {
return 0
}
func (any *objectAny) ToUint32() uint32 {
return 0
}
func (any *objectAny) ToUint64() uint64 {
return 0
}
func (any *objectAny) ToFloat32() float32 {
return 0
}
func (any *objectAny) ToFloat64() float64 {
return 0
}
func (any *objectAny) ToString() string {
str, err := MarshalToString(any.val.Interface())
any.err = err
return str
}
func (any *objectAny) Get(path ...interface{}) Any {
if len(path) == 0 {
return any
}
switch firstPath := path[0].(type) {
case string:
field := any.val.FieldByName(firstPath)
if !field.IsValid() {
return newInvalidAny(path)
}
return Wrap(field.Interface())
case int32:
if '*' == firstPath {
mappedAll := map[string]Any{}
for i := 0; i < any.val.NumField(); i++ {
field := any.val.Field(i)
if field.CanInterface() {
mapped := Wrap(field.Interface()).Get(path[1:]...)
if mapped.ValueType() != InvalidValue {
mappedAll[any.val.Type().Field(i).Name] = mapped
}
}
}
return wrapMap(mappedAll)
}
return newInvalidAny(path)
default:
return newInvalidAny(path)
}
}
func (any *objectAny) Keys() []string {
keys := make([]string, 0, any.val.NumField())
for i := 0; i < any.val.NumField(); i++ {
keys = append(keys, any.val.Type().Field(i).Name)
}
return keys
}
func (any *objectAny) Size() int {
return any.val.NumField()
}
func (any *objectAny) WriteTo(stream *Stream) {
stream.WriteVal(any.val)
}
func (any *objectAny) GetInterface() interface{} {
return any.val.Interface()
}
type mapAny struct {
baseAny
err error
val reflect.Value
}
func wrapMap(val interface{}) *mapAny {
return &mapAny{baseAny{}, nil, reflect.ValueOf(val)}
}
func (any *mapAny) ValueType() ValueType {
return ObjectValue
}
func (any *mapAny) MustBeValid() Any {
return any
}
func (any *mapAny) Parse() *Iterator {
return nil
}
func (any *mapAny) LastError() error {
return any.err
}
func (any *mapAny) ToBool() bool {
return true
}
func (any *mapAny) ToInt() int {
return 0
}
func (any *mapAny) ToInt32() int32 {
return 0
}
func (any *mapAny) ToInt64() int64 {
return 0
}
func (any *mapAny) ToUint() uint {
return 0
}
func (any *mapAny) ToUint32() uint32 {
return 0
}
func (any *mapAny) ToUint64() uint64 {
return 0
}
func (any *mapAny) ToFloat32() float32 {
return 0
}
func (any *mapAny) ToFloat64() float64 {
return 0
}
func (any *mapAny) ToString() string {
str, err := MarshalToString(any.val.Interface())
any.err = err
return str
}
func (any *mapAny) Get(path ...interface{}) Any {
if len(path) == 0 {
return any
}
switch firstPath := path[0].(type) {
case int32:
if '*' == firstPath {
mappedAll := map[string]Any{}
for _, key := range any.val.MapKeys() {
keyAsStr := key.String()
element := Wrap(any.val.MapIndex(key).Interface())
mapped := element.Get(path[1:]...)
if mapped.ValueType() != InvalidValue {
mappedAll[keyAsStr] = mapped
}
}
return wrapMap(mappedAll)
}
return newInvalidAny(path)
default:
value := any.val.MapIndex(reflect.ValueOf(firstPath))
if !value.IsValid() {
return newInvalidAny(path)
}
return Wrap(value.Interface())
}
}
func (any *mapAny) Keys() []string {
keys := make([]string, 0, any.val.Len())
for _, key := range any.val.MapKeys() {
keys = append(keys, key.String())
}
return keys
}
func (any *mapAny) Size() int {
return any.val.Len()
}
func (any *mapAny) WriteTo(stream *Stream) {
stream.WriteVal(any.val)
}
func (any *mapAny) GetInterface() interface{} {
return any.val.Interface()
}

166
vendor/github.com/json-iterator/go/any_str.go generated vendored Normal file
View File

@ -0,0 +1,166 @@
package jsoniter
import (
"fmt"
"strconv"
)
type stringAny struct {
baseAny
val string
}
func (any *stringAny) Get(path ...interface{}) Any {
if len(path) == 0 {
return any
}
return &invalidAny{baseAny{}, fmt.Errorf("GetIndex %v from simple value", path)}
}
func (any *stringAny) Parse() *Iterator {
return nil
}
func (any *stringAny) ValueType() ValueType {
return StringValue
}
func (any *stringAny) MustBeValid() Any {
return any
}
func (any *stringAny) LastError() error {
return nil
}
func (any *stringAny) ToBool() bool {
str := any.ToString()
if str == "0" {
return false
}
for _, c := range str {
switch c {
case ' ', '\n', '\r', '\t':
default:
return true
}
}
return false
}
func (any *stringAny) ToInt() int {
return int(any.ToInt64())
}
func (any *stringAny) ToInt32() int32 {
return int32(any.ToInt64())
}
func (any *stringAny) ToInt64() int64 {
if any.val == "" {
return 0
}
flag := 1
startPos := 0
endPos := 0
if any.val[0] == '+' || any.val[0] == '-' {
startPos = 1
}
if any.val[0] == '-' {
flag = -1
}
for i := startPos; i < len(any.val); i++ {
if any.val[i] >= '0' && any.val[i] <= '9' {
endPos = i + 1
} else {
break
}
}
parsed, _ := strconv.ParseInt(any.val[startPos:endPos], 10, 64)
return int64(flag) * parsed
}
func (any *stringAny) ToUint() uint {
return uint(any.ToUint64())
}
func (any *stringAny) ToUint32() uint32 {
return uint32(any.ToUint64())
}
func (any *stringAny) ToUint64() uint64 {
if any.val == "" {
return 0
}
startPos := 0
endPos := 0
if any.val[0] == '-' {
return 0
}
if any.val[0] == '+' {
startPos = 1
}
for i := startPos; i < len(any.val); i++ {
if any.val[i] >= '0' && any.val[i] <= '9' {
endPos = i + 1
} else {
break
}
}
parsed, _ := strconv.ParseUint(any.val[startPos:endPos], 10, 64)
return parsed
}
func (any *stringAny) ToFloat32() float32 {
return float32(any.ToFloat64())
}
func (any *stringAny) ToFloat64() float64 {
if len(any.val) == 0 {
return 0
}
// first char invalid
if any.val[0] != '+' && any.val[0] != '-' && (any.val[0] > '9' || any.val[0] < '0') {
return 0
}
// extract valid num expression from string
// eg 123true => 123, -12.12xxa => -12.12
endPos := 1
for i := 1; i < len(any.val); i++ {
if any.val[i] == '.' || any.val[i] == 'e' || any.val[i] == 'E' || any.val[i] == '+' || any.val[i] == '-' {
endPos = i + 1
continue
}
// end position is the first char which is not digit
if any.val[i] >= '0' && any.val[i] <= '9' {
endPos = i + 1
} else {
endPos = i
break
}
}
parsed, _ := strconv.ParseFloat(any.val[:endPos], 64)
return parsed
}
func (any *stringAny) ToString() string {
return any.val
}
func (any *stringAny) WriteTo(stream *Stream) {
stream.WriteString(any.val)
}
func (any *stringAny) GetInterface() interface{} {
return any.val
}

74
vendor/github.com/json-iterator/go/any_uint32.go generated vendored Normal file
View File

@ -0,0 +1,74 @@
package jsoniter
import (
"strconv"
)
type uint32Any struct {
baseAny
val uint32
}
func (any *uint32Any) LastError() error {
return nil
}
func (any *uint32Any) ValueType() ValueType {
return NumberValue
}
func (any *uint32Any) MustBeValid() Any {
return any
}
func (any *uint32Any) ToBool() bool {
return any.val != 0
}
func (any *uint32Any) ToInt() int {
return int(any.val)
}
func (any *uint32Any) ToInt32() int32 {
return int32(any.val)
}
func (any *uint32Any) ToInt64() int64 {
return int64(any.val)
}
func (any *uint32Any) ToUint() uint {
return uint(any.val)
}
func (any *uint32Any) ToUint32() uint32 {
return any.val
}
func (any *uint32Any) ToUint64() uint64 {
return uint64(any.val)
}
func (any *uint32Any) ToFloat32() float32 {
return float32(any.val)
}
func (any *uint32Any) ToFloat64() float64 {
return float64(any.val)
}
func (any *uint32Any) ToString() string {
return strconv.FormatInt(int64(any.val), 10)
}
func (any *uint32Any) WriteTo(stream *Stream) {
stream.WriteUint32(any.val)
}
func (any *uint32Any) Parse() *Iterator {
return nil
}
func (any *uint32Any) GetInterface() interface{} {
return any.val
}

74
vendor/github.com/json-iterator/go/any_uint64.go generated vendored Normal file
View File

@ -0,0 +1,74 @@
package jsoniter
import (
"strconv"
)
type uint64Any struct {
baseAny
val uint64
}
func (any *uint64Any) LastError() error {
return nil
}
func (any *uint64Any) ValueType() ValueType {
return NumberValue
}
func (any *uint64Any) MustBeValid() Any {
return any
}
func (any *uint64Any) ToBool() bool {
return any.val != 0
}
func (any *uint64Any) ToInt() int {
return int(any.val)
}
func (any *uint64Any) ToInt32() int32 {
return int32(any.val)
}
func (any *uint64Any) ToInt64() int64 {
return int64(any.val)
}
func (any *uint64Any) ToUint() uint {
return uint(any.val)
}
func (any *uint64Any) ToUint32() uint32 {
return uint32(any.val)
}
func (any *uint64Any) ToUint64() uint64 {
return any.val
}
func (any *uint64Any) ToFloat32() float32 {
return float32(any.val)
}
func (any *uint64Any) ToFloat64() float64 {
return float64(any.val)
}
func (any *uint64Any) ToString() string {
return strconv.FormatUint(any.val, 10)
}
func (any *uint64Any) WriteTo(stream *Stream) {
stream.WriteUint64(any.val)
}
func (any *uint64Any) Parse() *Iterator {
return nil
}
func (any *uint64Any) GetInterface() interface{} {
return any.val
}

12
vendor/github.com/json-iterator/go/build.sh generated vendored Normal file
View File

@ -0,0 +1,12 @@
#!/bin/bash
set -e
set -x
if [ ! -d /tmp/build-golang/src/github.com/json-iterator ]; then
mkdir -p /tmp/build-golang/src/github.com/json-iterator
ln -s $PWD /tmp/build-golang/src/github.com/json-iterator/go
fi
export GOPATH=/tmp/build-golang
go get -u github.com/golang/dep/cmd/dep
cd /tmp/build-golang/src/github.com/json-iterator/go
exec $GOPATH/bin/dep ensure -update

375
vendor/github.com/json-iterator/go/config.go generated vendored Normal file
View File

@ -0,0 +1,375 @@
package jsoniter
import (
"encoding/json"
"io"
"reflect"
"sync"
"unsafe"
"github.com/modern-go/concurrent"
"github.com/modern-go/reflect2"
)
// Config customize how the API should behave.
// The API is created from Config by Froze.
type Config struct {
IndentionStep int
MarshalFloatWith6Digits bool
EscapeHTML bool
SortMapKeys bool
UseNumber bool
DisallowUnknownFields bool
TagKey string
OnlyTaggedField bool
ValidateJsonRawMessage bool
ObjectFieldMustBeSimpleString bool
CaseSensitive bool
}
// API the public interface of this package.
// Primary Marshal and Unmarshal.
type API interface {
IteratorPool
StreamPool
MarshalToString(v interface{}) (string, error)
Marshal(v interface{}) ([]byte, error)
MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
UnmarshalFromString(str string, v interface{}) error
Unmarshal(data []byte, v interface{}) error
Get(data []byte, path ...interface{}) Any
NewEncoder(writer io.Writer) *Encoder
NewDecoder(reader io.Reader) *Decoder
Valid(data []byte) bool
RegisterExtension(extension Extension)
DecoderOf(typ reflect2.Type) ValDecoder
EncoderOf(typ reflect2.Type) ValEncoder
}
// ConfigDefault the default API
var ConfigDefault = Config{
EscapeHTML: true,
}.Froze()
// ConfigCompatibleWithStandardLibrary tries to be 100% compatible with standard library behavior
var ConfigCompatibleWithStandardLibrary = Config{
EscapeHTML: true,
SortMapKeys: true,
ValidateJsonRawMessage: true,
}.Froze()
// ConfigFastest marshals float with only 6 digits precision
var ConfigFastest = Config{
EscapeHTML: false,
MarshalFloatWith6Digits: true, // will lose precession
ObjectFieldMustBeSimpleString: true, // do not unescape object field
}.Froze()
type frozenConfig struct {
configBeforeFrozen Config
sortMapKeys bool
indentionStep int
objectFieldMustBeSimpleString bool
onlyTaggedField bool
disallowUnknownFields bool
decoderCache *concurrent.Map
encoderCache *concurrent.Map
encoderExtension Extension
decoderExtension Extension
extraExtensions []Extension
streamPool *sync.Pool
iteratorPool *sync.Pool
caseSensitive bool
}
func (cfg *frozenConfig) initCache() {
cfg.decoderCache = concurrent.NewMap()
cfg.encoderCache = concurrent.NewMap()
}
func (cfg *frozenConfig) addDecoderToCache(cacheKey uintptr, decoder ValDecoder) {
cfg.decoderCache.Store(cacheKey, decoder)
}
func (cfg *frozenConfig) addEncoderToCache(cacheKey uintptr, encoder ValEncoder) {
cfg.encoderCache.Store(cacheKey, encoder)
}
func (cfg *frozenConfig) getDecoderFromCache(cacheKey uintptr) ValDecoder {
decoder, found := cfg.decoderCache.Load(cacheKey)
if found {
return decoder.(ValDecoder)
}
return nil
}
func (cfg *frozenConfig) getEncoderFromCache(cacheKey uintptr) ValEncoder {
encoder, found := cfg.encoderCache.Load(cacheKey)
if found {
return encoder.(ValEncoder)
}
return nil
}
var cfgCache = concurrent.NewMap()
func getFrozenConfigFromCache(cfg Config) *frozenConfig {
obj, found := cfgCache.Load(cfg)
if found {
return obj.(*frozenConfig)
}
return nil
}
func addFrozenConfigToCache(cfg Config, frozenConfig *frozenConfig) {
cfgCache.Store(cfg, frozenConfig)
}
// Froze forge API from config
func (cfg Config) Froze() API {
api := &frozenConfig{
sortMapKeys: cfg.SortMapKeys,
indentionStep: cfg.IndentionStep,
objectFieldMustBeSimpleString: cfg.ObjectFieldMustBeSimpleString,
onlyTaggedField: cfg.OnlyTaggedField,
disallowUnknownFields: cfg.DisallowUnknownFields,
caseSensitive: cfg.CaseSensitive,
}
api.streamPool = &sync.Pool{
New: func() interface{} {
return NewStream(api, nil, 512)
},
}
api.iteratorPool = &sync.Pool{
New: func() interface{} {
return NewIterator(api)
},
}
api.initCache()
encoderExtension := EncoderExtension{}
decoderExtension := DecoderExtension{}
if cfg.MarshalFloatWith6Digits {
api.marshalFloatWith6Digits(encoderExtension)
}
if cfg.EscapeHTML {
api.escapeHTML(encoderExtension)
}
if cfg.UseNumber {
api.useNumber(decoderExtension)
}
if cfg.ValidateJsonRawMessage {
api.validateJsonRawMessage(encoderExtension)
}
api.encoderExtension = encoderExtension
api.decoderExtension = decoderExtension
api.configBeforeFrozen = cfg
return api
}
func (cfg Config) frozeWithCacheReuse(extraExtensions []Extension) *frozenConfig {
api := getFrozenConfigFromCache(cfg)
if api != nil {
return api
}
api = cfg.Froze().(*frozenConfig)
for _, extension := range extraExtensions {
api.RegisterExtension(extension)
}
addFrozenConfigToCache(cfg, api)
return api
}
func (cfg *frozenConfig) validateJsonRawMessage(extension EncoderExtension) {
encoder := &funcEncoder{func(ptr unsafe.Pointer, stream *Stream) {
rawMessage := *(*json.RawMessage)(ptr)
iter := cfg.BorrowIterator([]byte(rawMessage))
iter.Read()
if iter.Error != nil {
stream.WriteRaw("null")
} else {
cfg.ReturnIterator(iter)
stream.WriteRaw(string(rawMessage))
}
}, func(ptr unsafe.Pointer) bool {
return len(*((*json.RawMessage)(ptr))) == 0
}}
extension[reflect2.TypeOfPtr((*json.RawMessage)(nil)).Elem()] = encoder
extension[reflect2.TypeOfPtr((*RawMessage)(nil)).Elem()] = encoder
}
func (cfg *frozenConfig) useNumber(extension DecoderExtension) {
extension[reflect2.TypeOfPtr((*interface{})(nil)).Elem()] = &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) {
exitingValue := *((*interface{})(ptr))
if exitingValue != nil && reflect.TypeOf(exitingValue).Kind() == reflect.Ptr {
iter.ReadVal(exitingValue)
return
}
if iter.WhatIsNext() == NumberValue {
*((*interface{})(ptr)) = json.Number(iter.readNumberAsString())
} else {
*((*interface{})(ptr)) = iter.Read()
}
}}
}
func (cfg *frozenConfig) getTagKey() string {
tagKey := cfg.configBeforeFrozen.TagKey
if tagKey == "" {
return "json"
}
return tagKey
}
func (cfg *frozenConfig) RegisterExtension(extension Extension) {
cfg.extraExtensions = append(cfg.extraExtensions, extension)
copied := cfg.configBeforeFrozen
cfg.configBeforeFrozen = copied
}
type lossyFloat32Encoder struct {
}
func (encoder *lossyFloat32Encoder) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteFloat32Lossy(*((*float32)(ptr)))
}
func (encoder *lossyFloat32Encoder) IsEmpty(ptr unsafe.Pointer) bool {
return *((*float32)(ptr)) == 0
}
type lossyFloat64Encoder struct {
}
func (encoder *lossyFloat64Encoder) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteFloat64Lossy(*((*float64)(ptr)))
}
func (encoder *lossyFloat64Encoder) IsEmpty(ptr unsafe.Pointer) bool {
return *((*float64)(ptr)) == 0
}
// EnableLossyFloatMarshalling keeps 10**(-6) precision
// for float variables for better performance.
func (cfg *frozenConfig) marshalFloatWith6Digits(extension EncoderExtension) {
// for better performance
extension[reflect2.TypeOfPtr((*float32)(nil)).Elem()] = &lossyFloat32Encoder{}
extension[reflect2.TypeOfPtr((*float64)(nil)).Elem()] = &lossyFloat64Encoder{}
}
type htmlEscapedStringEncoder struct {
}
func (encoder *htmlEscapedStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
str := *((*string)(ptr))
stream.WriteStringWithHTMLEscaped(str)
}
func (encoder *htmlEscapedStringEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return *((*string)(ptr)) == ""
}
func (cfg *frozenConfig) escapeHTML(encoderExtension EncoderExtension) {
encoderExtension[reflect2.TypeOfPtr((*string)(nil)).Elem()] = &htmlEscapedStringEncoder{}
}
func (cfg *frozenConfig) cleanDecoders() {
typeDecoders = map[string]ValDecoder{}
fieldDecoders = map[string]ValDecoder{}
*cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig))
}
func (cfg *frozenConfig) cleanEncoders() {
typeEncoders = map[string]ValEncoder{}
fieldEncoders = map[string]ValEncoder{}
*cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig))
}
func (cfg *frozenConfig) MarshalToString(v interface{}) (string, error) {
stream := cfg.BorrowStream(nil)
defer cfg.ReturnStream(stream)
stream.WriteVal(v)
if stream.Error != nil {
return "", stream.Error
}
return string(stream.Buffer()), nil
}
func (cfg *frozenConfig) Marshal(v interface{}) ([]byte, error) {
stream := cfg.BorrowStream(nil)
defer cfg.ReturnStream(stream)
stream.WriteVal(v)
if stream.Error != nil {
return nil, stream.Error
}
result := stream.Buffer()
copied := make([]byte, len(result))
copy(copied, result)
return copied, nil
}
func (cfg *frozenConfig) MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
if prefix != "" {
panic("prefix is not supported")
}
for _, r := range indent {
if r != ' ' {
panic("indent can only be space")
}
}
newCfg := cfg.configBeforeFrozen
newCfg.IndentionStep = len(indent)
return newCfg.frozeWithCacheReuse(cfg.extraExtensions).Marshal(v)
}
func (cfg *frozenConfig) UnmarshalFromString(str string, v interface{}) error {
data := []byte(str)
iter := cfg.BorrowIterator(data)
defer cfg.ReturnIterator(iter)
iter.ReadVal(v)
c := iter.nextToken()
if c == 0 {
if iter.Error == io.EOF {
return nil
}
return iter.Error
}
iter.ReportError("Unmarshal", "there are bytes left after unmarshal")
return iter.Error
}
func (cfg *frozenConfig) Get(data []byte, path ...interface{}) Any {
iter := cfg.BorrowIterator(data)
defer cfg.ReturnIterator(iter)
return locatePath(iter, path)
}
func (cfg *frozenConfig) Unmarshal(data []byte, v interface{}) error {
iter := cfg.BorrowIterator(data)
defer cfg.ReturnIterator(iter)
iter.ReadVal(v)
c := iter.nextToken()
if c == 0 {
if iter.Error == io.EOF {
return nil
}
return iter.Error
}
iter.ReportError("Unmarshal", "there are bytes left after unmarshal")
return iter.Error
}
func (cfg *frozenConfig) NewEncoder(writer io.Writer) *Encoder {
stream := NewStream(cfg, writer, 512)
return &Encoder{stream}
}
func (cfg *frozenConfig) NewDecoder(reader io.Reader) *Decoder {
iter := Parse(cfg, reader, 512)
return &Decoder{iter}
}
func (cfg *frozenConfig) Valid(data []byte) bool {
iter := cfg.BorrowIterator(data)
defer cfg.ReturnIterator(iter)
iter.Skip()
return iter.Error == nil
}

View File

@ -0,0 +1,7 @@
| json type \ dest type | bool | int | uint | float |string|
| --- | --- | --- | --- |--|--|
| number | positive => true <br/> negative => true <br/> zero => false| 23.2 => 23 <br/> -32.1 => -32| 12.1 => 12 <br/> -12.1 => 0|as normal|same as origin|
| string | empty string => false <br/> string "0" => false <br/> other strings => true | "123.32" => 123 <br/> "-123.4" => -123 <br/> "123.23xxxw" => 123 <br/> "abcde12" => 0 <br/> "-32.1" => -32| 13.2 => 13 <br/> -1.1 => 0 |12.1 => 12.1 <br/> -12.3 => -12.3<br/> 12.4xxa => 12.4 <br/> +1.1e2 =>110 |same as origin|
| bool | true => true <br/> false => false| true => 1 <br/> false => 0 | true => 1 <br/> false => 0 |true => 1 <br/>false => 0|true => "true" <br/> false => "false"|
| object | true | 0 | 0 |0|originnal json|
| array | empty array => false <br/> nonempty array => true| [] => 0 <br/> [1,2] => 1 | [] => 0 <br/> [1,2] => 1 |[] => 0<br/>[1,2] => 1|original json|

322
vendor/github.com/json-iterator/go/iter.go generated vendored Normal file
View File

@ -0,0 +1,322 @@
package jsoniter
import (
"encoding/json"
"fmt"
"io"
)
// ValueType the type for JSON element
type ValueType int
const (
// InvalidValue invalid JSON element
InvalidValue ValueType = iota
// StringValue JSON element "string"
StringValue
// NumberValue JSON element 100 or 0.10
NumberValue
// NilValue JSON element null
NilValue
// BoolValue JSON element true or false
BoolValue
// ArrayValue JSON element []
ArrayValue
// ObjectValue JSON element {}
ObjectValue
)
var hexDigits []byte
var valueTypes []ValueType
func init() {
hexDigits = make([]byte, 256)
for i := 0; i < len(hexDigits); i++ {
hexDigits[i] = 255
}
for i := '0'; i <= '9'; i++ {
hexDigits[i] = byte(i - '0')
}
for i := 'a'; i <= 'f'; i++ {
hexDigits[i] = byte((i - 'a') + 10)
}
for i := 'A'; i <= 'F'; i++ {
hexDigits[i] = byte((i - 'A') + 10)
}
valueTypes = make([]ValueType, 256)
for i := 0; i < len(valueTypes); i++ {
valueTypes[i] = InvalidValue
}
valueTypes['"'] = StringValue
valueTypes['-'] = NumberValue
valueTypes['0'] = NumberValue
valueTypes['1'] = NumberValue
valueTypes['2'] = NumberValue
valueTypes['3'] = NumberValue
valueTypes['4'] = NumberValue
valueTypes['5'] = NumberValue
valueTypes['6'] = NumberValue
valueTypes['7'] = NumberValue
valueTypes['8'] = NumberValue
valueTypes['9'] = NumberValue
valueTypes['t'] = BoolValue
valueTypes['f'] = BoolValue
valueTypes['n'] = NilValue
valueTypes['['] = ArrayValue
valueTypes['{'] = ObjectValue
}
// Iterator is a io.Reader like object, with JSON specific read functions.
// Error is not returned as return value, but stored as Error member on this iterator instance.
type Iterator struct {
cfg *frozenConfig
reader io.Reader
buf []byte
head int
tail int
captureStartedAt int
captured []byte
Error error
Attachment interface{} // open for customized decoder
}
// NewIterator creates an empty Iterator instance
func NewIterator(cfg API) *Iterator {
return &Iterator{
cfg: cfg.(*frozenConfig),
reader: nil,
buf: nil,
head: 0,
tail: 0,
}
}
// Parse creates an Iterator instance from io.Reader
func Parse(cfg API, reader io.Reader, bufSize int) *Iterator {
return &Iterator{
cfg: cfg.(*frozenConfig),
reader: reader,
buf: make([]byte, bufSize),
head: 0,
tail: 0,
}
}
// ParseBytes creates an Iterator instance from byte array
func ParseBytes(cfg API, input []byte) *Iterator {
return &Iterator{
cfg: cfg.(*frozenConfig),
reader: nil,
buf: input,
head: 0,
tail: len(input),
}
}
// ParseString creates an Iterator instance from string
func ParseString(cfg API, input string) *Iterator {
return ParseBytes(cfg, []byte(input))
}
// Pool returns a pool can provide more iterator with same configuration
func (iter *Iterator) Pool() IteratorPool {
return iter.cfg
}
// Reset reuse iterator instance by specifying another reader
func (iter *Iterator) Reset(reader io.Reader) *Iterator {
iter.reader = reader
iter.head = 0
iter.tail = 0
return iter
}
// ResetBytes reuse iterator instance by specifying another byte array as input
func (iter *Iterator) ResetBytes(input []byte) *Iterator {
iter.reader = nil
iter.buf = input
iter.head = 0
iter.tail = len(input)
return iter
}
// WhatIsNext gets ValueType of relatively next json element
func (iter *Iterator) WhatIsNext() ValueType {
valueType := valueTypes[iter.nextToken()]
iter.unreadByte()
return valueType
}
func (iter *Iterator) skipWhitespacesWithoutLoadMore() bool {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
switch c {
case ' ', '\n', '\t', '\r':
continue
}
iter.head = i
return false
}
return true
}
func (iter *Iterator) isObjectEnd() bool {
c := iter.nextToken()
if c == ',' {
return false
}
if c == '}' {
return true
}
iter.ReportError("isObjectEnd", "object ended prematurely, unexpected char "+string([]byte{c}))
return true
}
func (iter *Iterator) nextToken() byte {
// a variation of skip whitespaces, returning the next non-whitespace token
for {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
switch c {
case ' ', '\n', '\t', '\r':
continue
}
iter.head = i + 1
return c
}
if !iter.loadMore() {
return 0
}
}
}
// ReportError record a error in iterator instance with current position.
func (iter *Iterator) ReportError(operation string, msg string) {
if iter.Error != nil {
if iter.Error != io.EOF {
return
}
}
peekStart := iter.head - 10
if peekStart < 0 {
peekStart = 0
}
peekEnd := iter.head + 10
if peekEnd > iter.tail {
peekEnd = iter.tail
}
parsing := string(iter.buf[peekStart:peekEnd])
contextStart := iter.head - 50
if contextStart < 0 {
contextStart = 0
}
contextEnd := iter.head + 50
if contextEnd > iter.tail {
contextEnd = iter.tail
}
context := string(iter.buf[contextStart:contextEnd])
iter.Error = fmt.Errorf("%s: %s, error found in #%v byte of ...|%s|..., bigger context ...|%s|...",
operation, msg, iter.head-peekStart, parsing, context)
}
// CurrentBuffer gets current buffer as string for debugging purpose
func (iter *Iterator) CurrentBuffer() string {
peekStart := iter.head - 10
if peekStart < 0 {
peekStart = 0
}
return fmt.Sprintf("parsing #%v byte, around ...|%s|..., whole buffer ...|%s|...", iter.head,
string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail]))
}
func (iter *Iterator) readByte() (ret byte) {
if iter.head == iter.tail {
if iter.loadMore() {
ret = iter.buf[iter.head]
iter.head++
return ret
}
return 0
}
ret = iter.buf[iter.head]
iter.head++
return ret
}
func (iter *Iterator) loadMore() bool {
if iter.reader == nil {
if iter.Error == nil {
iter.head = iter.tail
iter.Error = io.EOF
}
return false
}
if iter.captured != nil {
iter.captured = append(iter.captured,
iter.buf[iter.captureStartedAt:iter.tail]...)
iter.captureStartedAt = 0
}
for {
n, err := iter.reader.Read(iter.buf)
if n == 0 {
if err != nil {
if iter.Error == nil {
iter.Error = err
}
return false
}
} else {
iter.head = 0
iter.tail = n
return true
}
}
}
func (iter *Iterator) unreadByte() {
if iter.Error != nil {
return
}
iter.head--
return
}
// Read read the next JSON element as generic interface{}.
func (iter *Iterator) Read() interface{} {
valueType := iter.WhatIsNext()
switch valueType {
case StringValue:
return iter.ReadString()
case NumberValue:
if iter.cfg.configBeforeFrozen.UseNumber {
return json.Number(iter.readNumberAsString())
}
return iter.ReadFloat64()
case NilValue:
iter.skipFourBytes('n', 'u', 'l', 'l')
return nil
case BoolValue:
return iter.ReadBool()
case ArrayValue:
arr := []interface{}{}
iter.ReadArrayCB(func(iter *Iterator) bool {
var elem interface{}
iter.ReadVal(&elem)
arr = append(arr, elem)
return true
})
return arr
case ObjectValue:
obj := map[string]interface{}{}
iter.ReadMapCB(func(Iter *Iterator, field string) bool {
var elem interface{}
iter.ReadVal(&elem)
obj[field] = elem
return true
})
return obj
default:
iter.ReportError("Read", fmt.Sprintf("unexpected value type: %v", valueType))
return nil
}
}

Some files were not shown because too many files have changed in this diff Show More