Merge branch 'gin-gonic:master' into merge_json_render_write

This commit is contained in:
mstmdev 2022-06-30 20:12:23 +08:00 committed by GitHub
commit 501fc1e523
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
90 changed files with 1053 additions and 383 deletions

View File

@ -37,7 +37,7 @@ jobs:
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v1 uses: github/codeql-action/init@v2
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file. # If you wish to specify custom queries, you can do so here or in a config file.
@ -46,4 +46,4 @@ jobs:
# queries: ./path/to/local/query, your-org/your-repo/queries@main # queries: ./path/to/local/query, your-org/your-repo/queries@main
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1 uses: github/codeql-action/analyze@v2

View File

@ -13,13 +13,13 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Setup go - name: Setup go
uses: actions/setup-go@v2 uses: actions/setup-go@v3
with: with:
go-version: '^1.16' go-version: '^1.16'
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Setup golangci-lint - name: Setup golangci-lint
uses: golangci/golangci-lint-action@v3.1.0 uses: golangci/golangci-lint-action@v3.2.0
with: with:
version: v1.45.0 version: v1.45.0
args: --verbose args: --verbose
@ -28,7 +28,7 @@ jobs:
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, macos-latest] os: [ubuntu-latest, macos-latest]
go: [1.14, 1.15, 1.16, 1.17, 1.18] go: [1.15, 1.16, 1.17, 1.18]
test-tags: ['', nomsgpack] test-tags: ['', nomsgpack]
include: include:
- os: ubuntu-latest - os: ubuntu-latest
@ -43,7 +43,7 @@ jobs:
GOPROXY: https://proxy.golang.org GOPROXY: https://proxy.golang.org
steps: steps:
- name: Set up Go ${{ matrix.go }} - name: Set up Go ${{ matrix.go }}
uses: actions/setup-go@v2 uses: actions/setup-go@v3
with: with:
go-version: ${{ matrix.go }} go-version: ${{ matrix.go }}
@ -65,7 +65,7 @@ jobs:
run: make test run: make test
- name: Upload coverage to Codecov - name: Upload coverage to Codecov
uses: codecov/codecov-action@v2 uses: codecov/codecov-action@v3
with: with:
flags: ${{ matrix.os }},go-${{ matrix.go }},${{ matrix.test-tags }} flags: ${{ matrix.os }},go-${{ matrix.go }},${{ matrix.test-tags }}
notification-gitter: notification-gitter:

34
.github/workflows/goreleaser.yml vendored Normal file
View File

@ -0,0 +1,34 @@
name: Goreleaser
on:
push:
tags:
- '*'
permissions:
contents: write
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
-
name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.17
-
name: Run GoReleaser
uses: goreleaser/goreleaser-action@v3
with:
# either 'goreleaser' (default) or 'goreleaser-pro'
distribution: goreleaser
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

57
.goreleaser.yaml Normal file
View File

@ -0,0 +1,57 @@
project_name: gin
builds:
-
# If true, skip the build.
# Useful for library projects.
# Default is false
skip: true
changelog:
# Set it to true if you wish to skip the changelog generation.
# This may result in an empty release notes on GitHub/GitLab/Gitea.
skip: false
# Changelog generation implementation to use.
#
# Valid options are:
# - `git`: uses `git log`;
# - `github`: uses the compare GitHub API, appending the author login to the changelog.
# - `gitlab`: uses the compare GitLab API, appending the author name and email to the changelog.
# - `github-native`: uses the GitHub release notes generation API, disables the groups feature.
#
# Defaults to `git`.
use: git
# Sorts the changelog by the commit's messages.
# Could either be asc, desc or empty
# Default is empty
sort: asc
# Group commits messages by given regex and title.
# Order value defines the order of the groups.
# Proving no regex means all commits will be grouped under the default group.
# Groups are disabled when using github-native, as it already groups things by itself.
#
# Default is no groups.
groups:
- title: Features
regexp: "^.*feat[(\\w)]*:+.*$"
order: 0
- title: 'Bug fixes'
regexp: "^.*fix[(\\w)]*:+.*$"
order: 1
- title: 'Enhancements'
regexp: "^.*chore[(\\w)]*:+.*$"
order: 2
- title: Others
order: 999
filters:
# Commit messages matching the regexp listed here will be removed from
# the changelog
# Default is empty
exclude:
- '^docs'
- 'CICD'
- typo

View File

@ -2,237 +2,405 @@ List of all the awesome people working to make Gin the best Web Framework in Go.
## gin 1.x series authors ## gin 1.x series authors
**Gin Core Team:** Bo-Yi Wu (@appleboy), 田欧 (@thinkerou), Javier Provecho (@javierprovecho) **Gin Core Team:** Bo-Yi Wu (@appleboy), thinkerou (@thinkerou), Javier Provecho (@javierprovecho)
## gin 0.x series authors ## gin 0.x series authors
**Maintainers:** Manu Martinez-Almeida (@manucorporat), Javier Provecho (@javierprovecho) **Maintainers:** Manu Martinez-Almeida (@manucorporat), Javier Provecho (@javierprovecho)
------
People and companies, who have contributed, in alphabetical order. People and companies, who have contributed, in alphabetical order.
**@858806258 (杰哥)** - 178inaba <178inaba@users.noreply.github.com>
- Fix typo in example - A. F <hello@clivern.com>
- ABHISHEK SONI <abhishek.rocks26@gmail.com>
- Abhishek Chanda <achanda@users.noreply.github.com>
**@achedeuzot (Klemen Sever)** - Abner Chen <houjunchen@gmail.com>
- Fix newline debug printing - AcoNCodes <acongame@gmail.com>
- Adam Dratwinski <adam.dratwinski@gmail.com>
- Adam Mckaig <adam.mckaig@gmail.com>
**@adammck (Adam Mckaig)** - Adam Zielinski <MusicAdam@users.noreply.github.com>
- Add MIT license - Adonis <donileo@gmail.com>
- Alan Wang <azzwacb9001@126.com>
- Albin Gilles <gilles.albin@gmail.com>
**@AlexanderChen1989 (Alexander)** - Aleksandr Didenko <aa.didenko@yandex.ru>
- Typos in README - Alessandro (Ale) Segala <43508+ItalyPaleAle@users.noreply.github.com>
- Alex <AWulkan@users.noreply.github.com>
- Alexander <alexanderchenmh@gmail.com>
**@alexanderdidenko (Aleksandr Didenko)** - Alexander Lokhman <alex.lokhman@gmail.com>
- Add support multipart/form-data - Alexander Melentyev <55826637+alexander-melentyev@users.noreply.github.com>
- Alexander Nyquist <nyquist.alexander@gmail.com>
- Allen Ren <kulong0105@gmail.com>
**@alexandernyquist (Alexander Nyquist)** - AllinGo <tanhp@outlook.com>
- Using template.Must to fix multiple return issue - Ammar Bandukwala <ammar@ammar.io>
- ★ Added support for OPTIONS verb - An Xiao (Luffy) <hac@zju.edu.cn>
- ★ Setting response headers before calling WriteHeader - Andre Dublin <81dublin@gmail.com>
- Improved documentation for model binding - Andrew Szeto <github@jabagawee.com>
- ★ Added Content.Redirect() - Andrey Abramov <andreyabramov.aaa@gmail.com>
- ★ Added tons of Unit tests - Andrey Nering <andrey.nering@gmail.com>
- Andrey Smirnov <Smirnov.Andrey@gmail.com>
- Andrii Bubis <firstrow@gmail.com>
**@austinheap (Austin Heap)** - André Bazaglia <bazaglia@users.noreply.github.com>
- Added travis CI integration - Andy Pan <panjf2000@gmail.com>
- Antoine GIRARD <sapk@users.noreply.github.com>
- Anup Kumar Panwar <1anuppanwar@gmail.com>
**@andredublin (Andre Dublin)** - Aravinth Sundaram <gosh.aravind@gmail.com>
- Fix typo in comment - Artem <horechek@gmail.com>
- Ashwani <ashwanisharma686@gmail.com>
- Aurelien Regat-Barrel <arb@cyberkarma.net>
**@bredov (Ludwig Valda Vasquez)** - Austin Heap <me@austinheap.com>
- Fix html templating in debug mode - Barnabus <jbampton@users.noreply.github.com>
- Bo-Yi Wu <appleboy.tw@gmail.com>
- Boris Borshevsky <BorisBorshevsky@gmail.com>
**@bluele (Jun Kimura)** - Boyi Wu <p581581@gmail.com>
- Fixes code examples in README - BradyBromley <51128276+BradyBromley@users.noreply.github.com>
- Brendan Fosberry <brendan@shopkeep.com>
- Brian Wigginton <brianwigginton@gmail.com>
**@chad-russell** - Carlos Eduardo <carlosedp@gmail.com>
- ★ Support for serializing gin.H into XML - Chad Russell <chaddouglasrussell@gmail.com>
- Charles <cxjava@gmail.com>
- Christian Muehlhaeuser <muesli@gmail.com>
**@dickeyxxx (Jeff Dickey)** - Christian Persson <saser@live.se>
- Typos in README - Christopher Harrington <ironiridis@gmail.com>
- Add example about serving static files - Damon Zhao <yijun.zhao@outlook.com>
- Dan Markham <dmarkham@gmail.com>
- Dang Nguyen <hoangdang.me@gmail.com>
**@donileo (Adonis)** - Daniel Krom <kromdan@gmail.com>
- Add NoMethod handler - Daniel M. Lambea <dmlambea@gmail.com>
- Danieliu <liudanking@gmail.com>
- David Irvine <aviddiviner@gmail.com>
**@dutchcoders (DutchCoders)** - David Zhang <crispgm@gmail.com>
- ★ Fix security bug that allows client to spoof ip - Davor Kapsa <dvrkps@users.noreply.github.com>
- Fix typo. r.HTMLTemplates -> SetHTMLTemplate - DeathKing <DeathKing@users.noreply.github.com>
- Dennis Cho <47404603+forest747@users.noreply.github.com>
- Dmitry Dorogin <dmirogin@ya.ru>
**@el3ctro- (Joshua Loper)** - Dmitry Kutakov <vkd.castle@gmail.com>
- Fix typo in example - Dmitry Sedykh <dmitrys@d3h.local>
- Don2Quixote <35610661+Don2Quixote@users.noreply.github.com>
- Donn Pebe <iam@donnpebe.com>
**@ethankan (Ethan Kan)** - Dustin Decker <dustindecker@protonmail.com>
- Unsigned integers in binding - Eason Lin <easonlin404@gmail.com>
- Edward Betts <edward@4angle.com>
- Egor Seredin <4819888+agmt@users.noreply.github.com>
**(Evgeny Persienko)** - Emmanuel Goh <emmanuel@visenze.com>
- Validate sub structures - Equim <sayaka@ekyu.moe>
- Eren A. Akyol <eren@redmc.me>
- Eric_Lee <xplzv@126.com>
**@frankbille (Frank Bille)** - Erik Bender <erik.bender@develerik.dev>
- Add support for HTTP Realm Auth - Ethan Kan <ethankan@neoplot.com>
- Evgeny Persienko <e.persienko@office.ngs.ru>
- Faisal Alam <ifaisalalam@gmail.com>
**@fmd (Fareed Dudhia)** - Fareed Dudhia <fareeddudhia@googlemail.com>
- Fix typo. SetHTTPTemplate -> SetHTMLTemplate - Filip Figiel <figiel.filip@gmail.com>
- Florian Polster <couchpolster@icqmail.com>
- Frank Bille <github@frankbille.dk>
**@ironiridis (Christopher Harrington)** - Franz Bettag <franz@bett.ag>
- Remove old reference - Ganlv <ganlvtech@users.noreply.github.com>
- Gaozhen Ying <yinggaozhen@hotmail.com>
- George Gabolaev <gabolaev98@gmail.com>
**@jammie-stackhouse (Jamie Stackhouse)** - George Kirilenko <necryin@users.noreply.github.com>
- Add more shortcuts for router methods - Georges Varouchas <georges.varouchas@gmail.com>
- Gordon Tyler <gordon@doxxx.net>
- Harindu Perera <harinduenator@gmail.com>
**@jasonrhansen** - Helios <674876158@qq.com>
- Fix spelling and grammar errors in documentation - Henry Kwan <piengeng@users.noreply.github.com>
- Henry Yee <henry@yearning.io>
- Himanshu Mishra <OrkoHunter@users.noreply.github.com>
**@JasonSoft (Jason Lee)** - Hiroyuki Tanaka <h.tanaka.0325@gmail.com>
- Fix typo in comment - Ibraheem Ahmed <ibrah1440@gmail.com>
- Ignacio Galindo <joiggama@gmail.com>
- Igor H. Vieira <zignd.igor@gmail.com>
**@jincheng9 (Jincheng Zhang)** - Ildar1111 <54001462+Ildar1111@users.noreply.github.com>
- ★ support TSR when wildcard follows named param - Iskander (Alex) Sharipov <iskander.sharipov@intel.com>
- Fix errors and typos in comments - Ismail Gjevori <isgjevori@protonmail.com>
- Ivan Chen <allenivan@gmail.com>
- JINNOUCHI Yasushi <delphinus@remora.cx>
**@joiggama (Ignacio Galindo)** - James Pettyjohn <japettyjohn@users.noreply.github.com>
- Add utf-8 charset header on renders - Jamie Stackhouse <jamie.stackhouse@redspace.com>
- Jason Lee <jawc@hotmail.com>
- Javier Provecho <j.provecho@dartekstudios.com>
**@julienschmidt (Julien Schmidt)** - Javier Provecho <javier.provecho@bq.com>
- gofmt the code examples - Javier Provecho <javiertitan@gmail.com>
- Javier Provecho Fernandez <j.provecho@dartekstudios.com>
- Javier Provecho Fernandez <javiertitan@gmail.com>
**@kelcecil (Kel Cecil)** - Jean-Christophe Lebreton <jclebreton@gmail.com>
- Fix readme typo - Jeff <laojianzi1994@gmail.com>
- Jeremy Loy <jeremy.b.loy@icloud.com>
- Jim Filippou <p3160253@aueb.gr>
**@kyledinh (Kyle Dinh)** - Jimmy Pettersson <jimmy@expertmaker.com>
- Adds RunTLS() - John Bampton <jbampton@users.noreply.github.com>
- Johnny Dallas <johnnydallas0308@gmail.com>
- Johnny Dallas <theonlyjohnny@theonlyjohnny.sh>
**@LinusU (Linus Unnebäck)** - Jonathan (JC) Chen <jc@dijonkitchen.org>
- Small fixes in README - Josep Jesus Bigorra Algaba <42377845+averageflow@users.noreply.github.com>
- Josh Horowitz <joshua.m.horowitz@gmail.com>
- Joshua Loper <josh.el3@gmail.com>
**@loongmxbt (Saint Asky)** - Julien Schmidt <github@julienschmidt.com>
- Fix typo in example - Jun Kimura <jksmphone@gmail.com>
- Justin Beckwith <justin.beckwith@gmail.com>
- Justin Israel <justinisrael@gmail.com>
**@lucas-clemente (Lucas Clemente)** - Justin Mayhew <mayhew@live.ca>
- ★ work around path.Join removing trailing slashes from routes - Jérôme Laforge <jerome-laforge@users.noreply.github.com>
- Kacper Bąk <56700396+53jk1@users.noreply.github.com>
- Kamron Batman <kamronbatman@users.noreply.github.com>
**@mattn (Yasuhiro Matsumoto)** - Kane Rogers <kane@cleanstream.com.au>
- Improve color logger - Kaushik Neelichetty <kaushikneelichetty6132@gmail.com>
- Keiji Yoshida <yoshida.keiji.84@gmail.com>
- Kel Cecil <kel.cecil@listhub.com>
**@mdigger (Dmitry Sedykh)** - Kevin Mulvey <kmulvey@linux.com>
- Fixes Form binding when content-type is x-www-form-urlencoded - Kevin Zhu <ipandtcp@gmail.com>
- No repeat call c.Writer.Status() in gin.Logger - Kirill Motkov <motkov.kirill@gmail.com>
- Fixes Content-Type for json render - Klemen Sever <ksever@student.42.fr>
- Kristoffer A. Iversen <kristoffer.a.iversen@gmail.com>
- Krzysztof Szafrański <k.p.szafranski@gmail.com>
**@mirzac (Mirza Ceric)** - Kumar McMillan <kumar.mcmillan@gmail.com>
- Fix debug printing - Kyle Mcgill <email@kylescottmcgill.com>
- Lanco <35420416+lancoLiu@users.noreply.github.com>
- Levi Olson <olson.levi@gmail.com>
**@mopemope (Yutaka Matsubara)** - Lin Kao-Yuan <mosdeo@gmail.com>
- ★ Adds Godep support (Dependencies Manager) - Linus Unnebäck <linus@folkdatorn.se>
- Fix variadic parameter in the flexible render API - Lucas Clemente <lucas@clemente.io>
- Fix Corrupted plain render - Ludwig Valda Vasquez <bredov@gmail.com>
- Add Pluggable View Renderer Example - Luis GG <lggomez@users.noreply.github.com>
- MW Lim <williamchange@gmail.com>
- Maksimov Sergey <konjoot@gmail.com>
**@msemenistyi (Mykyta Semenistyi)** - Manjusaka <lizheao940510@gmail.com>
- update Readme.md. Add code to String method - Manu MA <manu.mtza@gmail.com>
- Manu MA <manu.valladolid@gmail.com>
- Manu Mtz-Almeida <manu.valladolid@gmail.com>
**@msoedov (Sasha Myasoedov)** - Manu Mtz.-Almeida <manu.valladolid@gmail.com>
- ★ Adds tons of unit tests. - Manuel Alonso <manuelalonso@invisionapp.com>
- Mara Kim <hacker.root@gmail.com>
- Mario Kostelac <mario@intercom.io>
**@ngerakines (Nick Gerakines)** - Martin Karlsch <martin@karlsch.com>
- ★ Improves API, c.GET() doesn't panic - Matt Newberry <mnewberry@opentable.com>
- Adds MustGet() method - Matt Williams <gh@mattyw.net>
- Matthieu MOREL <mmorel-35@users.noreply.github.com>
- Max Hilbrunner <mhilbrunner@users.noreply.github.com>
**@r8k (Rajiv Kilaparti)** - Maxime Soulé <btik-git@scoubidou.com>
- Fix Port usage in README. - MetalBreaker <johnymichelson@gmail.com>
- Michael Puncel <mpuncel@squareup.com>
- MichaelDeSteven <51652084+MichaelDeSteven@users.noreply.github.com>
**@rayrod2030 (Ray Rodriguez)** - Mike <38686456+icy4ever@users.noreply.github.com>
- Fix typo in example - Mike Stipicevic <mst@ableton.com>
- Miki Tebeka <miki.tebeka@gmail.com>
- Miles <MilesLin@users.noreply.github.com>
**@rns** - Mirza Ceric <mirza.ceric@b2match.com>
- Fix typo in example - Mykyta Semenistyi <nikeiwe@gmail.com>
- Naoki Takano <honten@tinkermode.com>
- Ngalim Siregar <ngalim.siregar@gmail.com>
**@RobAWilkinson (Robert Wilkinson)** - Ni Hao <supernihaooo@qq.com>
- Add example of forms and params - Nick Gerakines <nick@gerakines.net>
- Nikifor Seryakov <nikandfor@gmail.com>
- Notealot <714804968@qq.com>
**@rogierlommers (Rogier Lommers)** - Olivier Mengué <dolmen@cpan.org>
- Add updated static serve example - Olivier Robardet <orobardet@users.noreply.github.com>
- Pablo Moncada <pablo.moncada@bq.com>
**@rw-access (Ross Wolf)** - Pablo Moncada <pmoncadaisla@gmail.com>
- Added support to mix exact and param routes - Panmax <967168@qq.com>
- Peperoncino <2wua4nlyi@gmail.com>
**@se77en (Damon Zhao)** - Philipp Meinen <philipp@bind.ch>
- Improve color logging - Pierre Massat <pierre@massat.io>
- Qt <golang.chen@gmail.com>
- Quentin ROYER <aydendevg@gmail.com>
**@silasb (Silas Baronda)** - README Bot <35302948+codetriage-readme-bot@users.noreply.github.com>
- Fixing quotes in README - Rafal Zajac <rzajac@gmail.com>
- Rahul Datta Roy <rahuldroy@users.noreply.github.com>
- Rajiv Kilaparti <rajivk085@gmail.com>
**@SkuliOskarsson (Skuli Oskarsson)** - Raphael Gavache <raphael.gavache@datadoghq.com>
- Fixes some texts in README II - Ray Rodriguez <rayrod2030@gmail.com>
- Regner Blok-Andersen <shadowdf@gmail.com>
- Remco <remco@dutchcoders.io>
**@slimmy (Jimmy Pettersson)** - Rex Lee(李俊) <duguying2008@gmail.com>
- Added messages for required bindings - Richard Lee <dlackty@gmail.com>
- Riverside <wangyb65@gmail.com>
- Robert Wilkinson <wilkinson.robert.a@gmail.com>
**@smira (Andrey Smirnov)** - Rogier Lommers <rogier@lommers.org>
- Add support for ignored/unexported fields in binding - Rohan Pai <me@rohanpai.com>
- Romain Beuque <rbeuque74@gmail.com>
- Roman Belyakovsky <ihryamzik@gmail.com>
**@superalsrk (SRK.Lyu)** - Roman Zaynetdinov <627197+zaynetro@users.noreply.github.com>
- Update httprouter godeps - Roman Zaynetdinov <roman.zaynetdinov@lekane.com>
- Ronald Petty <ronald.petty@rx-m.com>
- Ross Wolf <31489089+rw-access@users.noreply.github.com>
**@tebeka (Miki Tebeka)** - Roy Lou <roylou@gmail.com>
- Use net/http constants instead of numeric values - Rubi <14269809+codenoid@users.noreply.github.com>
- Ryan <46182144+ryanker@users.noreply.github.com>
- Ryan J. Yoder <me@ryanjyoder.com>
**@techjanitor** - SRK.Lyu <superalsrk@gmail.com>
- Update context.go reserved IPs - Sai <sairoutine@gmail.com>
- Samuel Abreu <sdepaula@gmail.com>
- Santhosh Kumar <santhoshkumarr1096@gmail.com>
**@yosssi (Keiji Yoshida)** - Sasha Melentyev <sasha@melentyev.io>
- Fix link in README - Sasha Myasoedov <msoedov@gmail.com>
- Segev Finer <segev208@gmail.com>
- Sergey Egorov <egorovhome@gmail.com>
**@yuyabee** - Sergey Fedchenko <seregayoga@bk.ru>
- Fixed README - Sergey Gonimar <sergey.gonimar@gmail.com>
- Sergey Ponomarev <me@sergey-ponomarev.ru>
- Serica <943914044@qq.com>
- Shamus Taylor <Shamus03@me.com>
- Shilin Wang <jarvisfironman@gmail.com>
- Shuo <openset.wang@gmail.com>
- Skuli Oskarsson <skuli@codeiak.io>
- Snawoot <vladislav-ex-github@vm-0.com>
- Sridhar Ratnakumar <srid@srid.ca>
- Steeve Chailloux <steeve@chaahk.com>
- Sudhir Mishra <sudhirxps@gmail.com>
- Suhas Karanth <sudo-suhas@users.noreply.github.com>
- TaeJun Park <miking38@gmail.com>
- Tatsuya Hoshino <tatsuya7.hoshino7@gmail.com>
- Tevic <tevic.tt@gmail.com>
- Tevin Jeffrey <tev.jeffrey@gmail.com>
- The Gitter Badger <badger@gitter.im>
- Thibault Jamet <tjamet@users.noreply.github.com>
- Thomas Boerger <thomas@webhippie.de>
- Thomas Schaffer <loopfz@gmail.com>
- Tommy Chu <tommychu2256@gmail.com>
- Tudor Roman <tudurom@gmail.com>
- Uwe Dauernheim <djui@users.noreply.github.com>
- Valentine Oragbakosi <valentine13400@gmail.com>
- Vas N <pnvasanth@users.noreply.github.com>
- Vasilyuk Vasiliy <By-Vasiliy@users.noreply.github.com>
- Victor Castell <victor@victorcastell.com>
- Vince Yuan <vince.yuan@gmail.com>
- Vyacheslav Dubinin <vyacheslav.dubinin@gmail.com>
- Waynerv <ampedee@gmail.com>
- Weilin Shi <934587911@qq.com>
- Xudong Cai <fifsky@gmail.com>
- Yasuhiro Matsumoto <mattn.jp@gmail.com>
- Yehezkiel Syamsuhadi <ybs@ybs.im>
- Yoshiki Nakagawa <yyoshiki41@gmail.com>
- Yoshiyuki Kinjo <yskkin+github@gmail.com>
- Yue Yang <g1enyy0ung@gmail.com>
- ZYunH <zyunhjob@163.com>
- Zach Newburgh <zach.newburgh@gmail.com>
- Zasda Yusuf Mikail <zasdaym@gmail.com>
- ZhangYunHao <zyunhjob@163.com>
- ZhiFeng Hu <hufeng1987@gmail.com>
- Zhu Xi <zhuxi910511@163.com>
- a2tt <usera2tt@gmail.com>
- ahuigo <1781999+ahuigo@users.noreply.github.com>
- ali <anio@users.noreply.github.com>
- aljun <salameryy@163.com>
- andrea <crypto.andrea@protonmail.ch>
- andriikushch <andrii.kushch@gmail.com>
- anoty <anjunyou@foxmail.com>
- awkj <hzzbiu@gmail.com>
- axiaoxin <254606826@qq.com>
- bbiao <bbbiao@gmail.com>
- bestgopher <84328409@qq.com>
- betahu <zhong.wenhuang@foxmail.com>
- bigwheel <k.bigwheel+eng@gmail.com>
- bn4t <17193640+bn4t@users.noreply.github.com>
- bullgare <bullgare@gmail.com>
- chainhelen <chainhelen@gmail.com>
- chenyang929 <chenyang929code@gmail.com>
- chriswhelix <chris.williams@helix.com>
- collinmsn <4130944@qq.com>
- cssivision <cssivision@gmail.com>
- danielalves <alves.lopes.dan@gmail.com>
- delphinus <delphinus@remora.cx>
- dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
- dickeyxxx <jeff@dickeyxxx.com>
- edebernis <emeric.debernis@gmail.com>
- error10 <error@ioerror.us>
- esplo <esplo@users.noreply.github.com>
- eudore <30709860+eudore@users.noreply.github.com>
- ffhelicopter <32922889+ffhelicopter@users.noreply.github.com>
- filikos <11477309+filikos@users.noreply.github.com>
- forging2012 <forging2012@users.noreply.github.com>
- goqihoo <goqihoo@gmail.com>
- grapeVine <treeui.old@gmail.com>
- guonaihong <guonaihong@qq.com>
- heige <daheige@users.noreply.github.com>
- heige <zhuwei313@hotmail.com>
- hellojukay <hellojukay@163.com>
- henrylee2cn <henrylee2cn@gmail.com>
- htobenothing <htobenothing@gmail.com>
- iamhesir <78344375+iamhesir@users.noreply.github.com>
- ijaa <kailiu2013@gmail.com>
- ishanray <ishan.iipm@gmail.com>
- ishanray <ishanray@users.noreply.github.com>
- itcloudy <272685110@qq.com>
- jarodsong6 <jarodsong6@gmail.com>
- jasonrhansen <jasonrodneyhansen@gmail.com>
- jincheng9 <perfume0607@gmail.com>
- joeADSP <75027008+joeADSP@users.noreply.github.com>
- junfengye <junfeng.yejf@gmail.com>
- kaiiak <aNxFi37X@outlook.com>
- kebo <kevinke2020@outlook.com>
- keke <19yamashita15@gmail.com>
- kishor kunal raj <68464660+kishorkunal-raj@users.noreply.github.com>
- kyledinh <kyledinh@gmail.com>
- lantw44 <lantw44@gmail.com>
- likakuli <1154584512@qq.com>
- linfangrong <linfangrong.liuxin@qq.com>
- linzi <873804682@qq.com>
- llgoer <yanghuxiao@vip.qq.com>
- long-road <13412081338@163.com>
- mbesancon <mathieu.besancon@gmail.com>
- mehdy <mehdy.khoshnoody@gmail.com>
- metal A-wing <freedom.awing.777@gmail.com>
- micanzhang <micanzhang@gmail.com>
- minarc <ragnhildmowinckel@gmail.com>
- mllu <mornlyn@gmail.com>
- mopemoepe <yutaka.matsubara@gmail.com>
- msoedov <msoedov@gmail.com>
- mstmdev <mstmdev@gmail.com>
- novaeye <fcoffee@gmail.com>
- olebedev <oolebedev@gmail.com>
- phithon <phith0n@users.noreply.github.com>
- pjgg <pablo.gonzalez.granados@gmail.com>
- qm012 <67568757+qm012@users.noreply.github.com>
- raymonder jin <rayjingithub@gmail.com>
- rns <ruslan.shvedov@gmail.com>
- root@andrea:~# <crypto.andrea@protonmail.ch>
- sekky0905 <20237968+sekky0905@users.noreply.github.com>
- senhtry <w169q169@gmail.com>
- shadrus <shadrus@gmail.com>
- silasb <silas.baronda@gmail.com>
- solos <lxl1217@gmail.com>
- songjiayang <songjiayang@users.noreply.github.com>
- sope <shenshouer@163.com>
- srt180 <30768686+srt180@users.noreply.github.com>
- stackerzzq <foo_stacker@yeah.net>
- sunshineplan <sunshineplan@users.noreply.github.com>
- syssam <s.y.s.sam.sys@gmail.com>
- techjanitor <puntme@gmail.com>
- techjanitor <techjanitor@users.noreply.github.com>
- thinkerou <thinkerou@gmail.com>
- thinkgo <49174849+thinkgos@users.noreply.github.com>
- tsirolnik <tsirolnik@users.noreply.github.com>
- tyltr <31768692+tylitianrui@users.noreply.github.com>
- vinhha96 <anhvinha1@gmail.com>
- voidman <retmain@foxmail.com>
- vz <vzvway@gmail.com>
- wei <wei840222@gmail.com>
- weibaohui <weibaohui@yeah.net>
- whirosan <whirosan@users.noreply.github.com>
- willnewrelic <will@newrelic.com>
- wssccc <wssccc@qq.com>
- wuhuizuo <wuhuizuo@126.com>
- xyb <xyb4638@gmail.com>
- y-yagi <yuuji.yaginuma@gmail.com>
- yiranzai <wuqingdzx@gmail.com>
- youzeliang <youzel@126.com>
- yugu <chenzilong_1227@foxmail.com>
- yuyabe <yuyabee@gmail.com>
- zebozhuang <zebozhuang@163.com>
- zero11-0203 <93071220+zero11-0203@users.noreply.github.com>
- zesani <7sin@outlook.co.th>
- zhanweidu <zhanweidu@163.com>
- zhing <zqwillseven@gmail.com>
- ziheng <zihenglv@gmail.com>
- zzjin <zzjin@users.noreply.github.com>
- 森 優太 <59682979+uta-mori@users.noreply.github.com>
- 杰哥 <858806258@qq.com>
- 涛叔 <hi@taoshu.in>
- 市民233 <mengrenxiong@gmail.com>
- 尹宝强 <wmdandme@gmail.com>
- 梦溪笔谈 <loongmxbt@gmail.com>
- 飞雪无情 <ls8707@gmail.com>
- 寻寻觅觅的Gopher <zoujh99@qq.com>

View File

@ -1,5 +1,53 @@
# Gin ChangeLog # Gin ChangeLog
## Gin v1.8.1
### ENHANCEMENTS
* feat(context): add ContextWithFallback feature flag [#3172](https://github.com/gin-gonic/gin/pull/3172)
## Gin v1.8.0
## Break Changes
* TrustedProxies: Add default IPv6 support and refactor [#2967](https://github.com/gin-gonic/gin/pull/2967). Please replace `RemoteIP() (net.IP, bool)` with `RemoteIP() net.IP`
* gin.Context with fallback value from gin.Context.Request.Context() [#2751](https://github.com/gin-gonic/gin/pull/2751)
### BUGFIXES
* Fixed SetOutput() panics on go 1.17 [#2861](https://github.com/gin-gonic/gin/pull/2861)
* Fix: wrong when wildcard follows named param [#2983](https://github.com/gin-gonic/gin/pull/2983)
* Fix: missing sameSite when do context.reset() [#3123](https://github.com/gin-gonic/gin/pull/3123)
### ENHANCEMENTS
* Use Header() instead of deprecated HeaderMap [#2694](https://github.com/gin-gonic/gin/pull/2694)
* RouterGroup.Handle regular match optimization of http method [#2685](https://github.com/gin-gonic/gin/pull/2685)
* Add support go-json, another drop-in json replacement [#2680](https://github.com/gin-gonic/gin/pull/2680)
* Use errors.New to replace fmt.Errorf will much better [#2707](https://github.com/gin-gonic/gin/pull/2707)
* Use Duration.Truncate for truncating precision [#2711](https://github.com/gin-gonic/gin/pull/2711)
* Get client IP when using Cloudflare [#2723](https://github.com/gin-gonic/gin/pull/2723)
* Optimize code adjust [#2700](https://github.com/gin-gonic/gin/pull/2700/files)
* Optimize code and reduce code cyclomatic complexity [#2737](https://github.com/gin-gonic/gin/pull/2737)
* Improve sliceValidateError.Error performance [#2765](https://github.com/gin-gonic/gin/pull/2765)
* Support custom struct tag [#2720](https://github.com/gin-gonic/gin/pull/2720)
* Improve router group tests [#2787](https://github.com/gin-gonic/gin/pull/2787)
* Fallback Context.Deadline() Context.Done() Context.Err() to Context.Request.Context() [#2769](https://github.com/gin-gonic/gin/pull/2769)
* Some codes optimize [#2830](https://github.com/gin-gonic/gin/pull/2830) [#2834](https://github.com/gin-gonic/gin/pull/2834) [#2838](https://github.com/gin-gonic/gin/pull/2838) [#2837](https://github.com/gin-gonic/gin/pull/2837) [#2788](https://github.com/gin-gonic/gin/pull/2788) [#2848](https://github.com/gin-gonic/gin/pull/2848) [#2851](https://github.com/gin-gonic/gin/pull/2851) [#2701](https://github.com/gin-gonic/gin/pull/2701)
* TrustedProxies: Add default IPv6 support and refactor [#2967](https://github.com/gin-gonic/gin/pull/2967)
* Test(route): expose performRequest func [#3012](https://github.com/gin-gonic/gin/pull/3012)
* Support h2c with prior knowledge [#1398](https://github.com/gin-gonic/gin/pull/1398)
* Feat attachment filename support utf8 [#3071](https://github.com/gin-gonic/gin/pull/3071)
* Feat: add StaticFileFS [#2749](https://github.com/gin-gonic/gin/pull/2749)
* Feat(context): return GIN Context from Value method [#2825](https://github.com/gin-gonic/gin/pull/2825)
* Feat: automatically SetMode to TestMode when run go test [#3139](https://github.com/gin-gonic/gin/pull/3139)
* Add TOML bining for gin [#3081](https://github.com/gin-gonic/gin/pull/3081)
* IPv6 add default trusted proxies [#3033](https://github.com/gin-gonic/gin/pull/3033)
### DOCS
* Add note about nomsgpack tag to the readme [#2703](https://github.com/gin-gonic/gin/pull/2703)
## Gin v1.7.7 ## Gin v1.7.7
### BUGFIXES ### BUGFIXES

View File

@ -86,7 +86,7 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi
To install Gin package, you need to install Go and set your Go workspace first. To install Gin package, you need to install Go and set your Go workspace first.
1. The first need [Go](https://golang.org/) installed (**version 1.14+ is required**), then you can use the below Go command to install Gin. 1. You first need [Go](https://golang.org/) installed (**version 1.15+ is required**), then you can use the below Go command to install Gin.
```sh ```sh
$ go get -u github.com/gin-gonic/gin $ go get -u github.com/gin-gonic/gin
@ -114,12 +114,16 @@ $ cat example.go
```go ```go
package main package main
import "github.com/gin-gonic/gin" import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() { func main() {
r := gin.Default() r := gin.Default()
r.GET("/ping", func(c *gin.Context) { r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{ c.JSON(http.StatusOK, gin.H{
"message": "pong", "message": "pong",
}) })
}) })
@ -300,7 +304,7 @@ func main() {
message := c.PostForm("message") message := c.PostForm("message")
nick := c.DefaultPostForm("nick", "anonymous") nick := c.DefaultPostForm("nick", "anonymous")
c.JSON(200, gin.H{ c.JSON(http.StatusOK, gin.H{
"status": "posted", "status": "posted",
"message": message, "message": message,
"nick": nick, "nick": nick,
@ -570,7 +574,7 @@ func main() {
router := gin.Default() router := gin.Default()
router.GET("/ping", func(c *gin.Context) { router.GET("/ping", func(c *gin.Context) {
c.String(200, "pong") c.String(http.StatusOK, "pong")
}) })
   router.Run(":8080")    router.Run(":8080")
@ -602,7 +606,7 @@ func main() {
router.Use(gin.Recovery()) router.Use(gin.Recovery())
router.GET("/ping", func(c *gin.Context) { router.GET("/ping", func(c *gin.Context) {
c.String(200, "pong") c.String(http.StatusOK, "pong")
}) })
router.Run(":8080") router.Run(":8080")
@ -630,7 +634,7 @@ func main() {
router := gin.Default() router := gin.Default()
router.GET("/ping", func(c *gin.Context) { router.GET("/ping", func(c *gin.Context) {
c.String(200, "pong") c.String(http.StatusOK, "pong")
}) })
router.Run(":8080") router.Run(":8080")
@ -649,7 +653,7 @@ func main() {
router := gin.Default() router := gin.Default()
router.GET("/ping", func(c *gin.Context) { router.GET("/ping", func(c *gin.Context) {
c.String(200, "pong") c.String(http.StatusOK, "pong")
}) })
router.Run(":8080") router.Run(":8080")
@ -658,7 +662,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, YAML, TOML and standard form values (foo=bar&boo=baz).
Gin uses [**go-playground/validator/v10**](https://github.com/go-playground/validator) for validation. Check the full docs on tags usage [here](https://godoc.org/github.com/go-playground/validator#hdr-Baked_In_Validators_and_Tags). Gin uses [**go-playground/validator/v10**](https://github.com/go-playground/validator) for validation. Check the full docs on tags usage [here](https://godoc.org/github.com/go-playground/validator#hdr-Baked_In_Validators_and_Tags).
@ -666,10 +670,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`, `BindHeader` - **Methods** - `Bind`, `BindJSON`, `BindXML`, `BindQuery`, `BindYAML`, `BindHeader`, `BindTOML`
- **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`, `ShouldBindHeader` - **Methods** - `ShouldBind`, `ShouldBindJSON`, `ShouldBindXML`, `ShouldBindQuery`, `ShouldBindYAML`, `ShouldBindHeader`, `ShouldBindTOML`,
- **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`.
@ -848,6 +852,7 @@ package main
import ( import (
"log" "log"
"net/http"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -870,7 +875,7 @@ func startPage(c *gin.Context) {
log.Println(person.Name) log.Println(person.Name)
log.Println(person.Address) log.Println(person.Address)
} }
c.String(200, "Success") c.String(http.StatusOK, "Success")
} }
``` ```
@ -884,6 +889,7 @@ package main
import ( import (
"log" "log"
"net/http"
"time" "time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -916,7 +922,7 @@ func startPage(c *gin.Context) {
log.Println(person.UnixTime) log.Println(person.UnixTime)
} }
c.String(200, "Success") c.String(http.StatusOK, "Success")
} }
``` ```
@ -932,7 +938,11 @@ See the [detail information](https://github.com/gin-gonic/gin/issues/846).
```go ```go
package main package main
import "github.com/gin-gonic/gin" import (
"net/http"
"github.com/gin-gonic/gin"
)
type Person struct { type Person struct {
ID string `uri:"id" binding:"required,uuid"` ID string `uri:"id" binding:"required,uuid"`
@ -944,10 +954,10 @@ func main() {
route.GET("/:name/:id", func(c *gin.Context) { route.GET("/:name/:id", func(c *gin.Context) {
var person Person var person Person
if err := c.ShouldBindUri(&person); err != nil { if err := c.ShouldBindUri(&person); err != nil {
c.JSON(400, gin.H{"msg": err.Error()}) c.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
return return
} }
c.JSON(200, gin.H{"name": person.Name, "uuid": person.ID}) c.JSON(http.StatusOK, gin.H{"name": person.Name, "uuid": person.ID})
}) })
route.Run(":8088") route.Run(":8088")
} }
@ -966,6 +976,8 @@ package main
import ( import (
"fmt" "fmt"
"net/http"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -980,11 +992,11 @@ func main() {
h := testHeader{} h := testHeader{}
if err := c.ShouldBindHeader(&h); err != nil { if err := c.ShouldBindHeader(&h); err != nil {
c.JSON(200, err) c.JSON(http.StatusOK, err)
} }
fmt.Printf("%#v\n", h) fmt.Printf("%#v\n", h)
c.JSON(200, gin.H{"Rate": h.Rate, "Domain": h.Domain}) c.JSON(http.StatusOK, gin.H{"Rate": h.Rate, "Domain": h.Domain})
}) })
r.Run() r.Run()
@ -1014,7 +1026,7 @@ type myForm struct {
func formHandler(c *gin.Context) { func formHandler(c *gin.Context) {
var fakeForm myForm var fakeForm myForm
c.ShouldBind(&fakeForm) c.ShouldBind(&fakeForm)
c.JSON(200, gin.H{"color": fakeForm.Colors}) c.JSON(http.StatusOK, gin.H{"color": fakeForm.Colors})
} }
... ...
@ -1219,14 +1231,14 @@ func main() {
// Serves unicode entities // Serves unicode entities
r.GET("/json", func(c *gin.Context) { r.GET("/json", func(c *gin.Context) {
c.JSON(200, gin.H{ c.JSON(http.StatusOK, gin.H{
"html": "<b>Hello, world!</b>", "html": "<b>Hello, world!</b>",
}) })
}) })
// Serves literal characters // Serves literal characters
r.GET("/purejson", func(c *gin.Context) { r.GET("/purejson", func(c *gin.Context) {
c.PureJSON(200, gin.H{ c.PureJSON(http.StatusOK, gin.H{
"html": "<b>Hello, world!</b>", "html": "<b>Hello, world!</b>",
}) })
}) })
@ -1473,7 +1485,7 @@ r.GET("/test", func(c *gin.Context) {
r.HandleContext(c) r.HandleContext(c)
}) })
r.GET("/test2", func(c *gin.Context) { r.GET("/test2", func(c *gin.Context) {
c.JSON(200, gin.H{"hello": "world"}) c.JSON(http.StatusOK, gin.H{"hello": "world"})
}) })
``` ```
@ -1626,6 +1638,7 @@ package main
import ( import (
"log" "log"
"net/http"
"github.com/gin-gonic/autotls" "github.com/gin-gonic/autotls"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -1636,7 +1649,7 @@ func main() {
// Ping handler // Ping handler
r.GET("/ping", func(c *gin.Context) { r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong") c.String(http.StatusOK, "pong")
}) })
log.Fatal(autotls.Run(r, "example1.com", "example2.com")) log.Fatal(autotls.Run(r, "example1.com", "example2.com"))
@ -1650,6 +1663,7 @@ package main
import ( import (
"log" "log"
"net/http"
"github.com/gin-gonic/autotls" "github.com/gin-gonic/autotls"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -1661,7 +1675,7 @@ func main() {
// Ping handler // Ping handler
r.GET("/ping", func(c *gin.Context) { r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong") c.String(http.StatusOK, "pong")
}) })
m := autocert.Manager{ m := autocert.Manager{
@ -1922,7 +1936,7 @@ type StructD struct {
func GetDataB(c *gin.Context) { func GetDataB(c *gin.Context) {
var b StructB var b StructB
c.Bind(&b) c.Bind(&b)
c.JSON(200, gin.H{ c.JSON(http.StatusOK, gin.H{
"a": b.NestedStruct, "a": b.NestedStruct,
"b": b.FieldB, "b": b.FieldB,
}) })
@ -1931,7 +1945,7 @@ func GetDataB(c *gin.Context) {
func GetDataC(c *gin.Context) { func GetDataC(c *gin.Context) {
var b StructC var b StructC
c.Bind(&b) c.Bind(&b)
c.JSON(200, gin.H{ c.JSON(http.StatusOK, gin.H{
"a": b.NestedStructPointer, "a": b.NestedStructPointer,
"c": b.FieldC, "c": b.FieldC,
}) })
@ -1940,7 +1954,7 @@ func GetDataC(c *gin.Context) {
func GetDataD(c *gin.Context) { func GetDataD(c *gin.Context) {
var b StructD var b StructD
c.Bind(&b) c.Bind(&b)
c.JSON(200, gin.H{ c.JSON(http.StatusOK, gin.H{
"x": b.NestedAnonyStruct, "x": b.NestedAnonyStruct,
"d": b.FieldD, "d": b.FieldD,
}) })
@ -2090,6 +2104,7 @@ package main
import ( import (
"html/template" "html/template"
"log" "log"
"net/http"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -2118,7 +2133,7 @@ func main() {
log.Printf("Failed to push: %v", err) log.Printf("Failed to push: %v", err)
} }
} }
c.HTML(200, "https", gin.H{ c.HTML(http.StatusOK, "https", gin.H{
"status": "success", "status": "success",
}) })
}) })
@ -2274,10 +2289,16 @@ The `net/http/httptest` package is preferable way for HTTP testing.
```go ```go
package main package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func setupRouter() *gin.Engine { func setupRouter() *gin.Engine {
r := gin.Default() r := gin.Default()
r.GET("/ping", func(c *gin.Context) { r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong") c.String(http.StatusOK, "pong")
}) })
return r return r
} }
@ -2305,10 +2326,10 @@ func TestPingRoute(t *testing.T) {
router := setupRouter() router := setupRouter()
w := httptest.NewRecorder() w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/ping", nil) req, _ := http.NewRequest(http.MethodGet, "/ping", nil)
router.ServeHTTP(w, req) router.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code) assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "pong", w.Body.String()) assert.Equal(t, "pong", w.Body.String())
} }
``` ```

2
any.go
View File

@ -1,4 +1,4 @@
// Copyright 2022 Gin Core Team. All rights reserved. // Copyright 2022 Gin Core Team. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -31,7 +31,7 @@ func (a authPairs) searchCredential(authValue string) (string, bool) {
return "", false return "", false
} }
for _, pair := range a { for _, pair := range a {
if subtle.ConstantTimeCompare([]byte(pair.value), []byte(authValue)) == 1 { if subtle.ConstantTimeCompare(bytesconv.StringToBytes(pair.value), bytesconv.StringToBytes(authValue)) == 1 {
return pair.user, true return pair.user, true
} }
} }

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2017 Manu Martinez-Almeida. All rights reserved. // Copyright 2017 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2022 Gin Core Team. All rights reserved. // Copyright 2022 Gin Core Team. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -22,6 +22,7 @@ const (
MIMEMSGPACK = "application/x-msgpack" MIMEMSGPACK = "application/x-msgpack"
MIMEMSGPACK2 = "application/msgpack" MIMEMSGPACK2 = "application/msgpack"
MIMEYAML = "application/x-yaml" MIMEYAML = "application/x-yaml"
MIMETOML = "application/toml"
) )
// Binding describes the interface which needs to be implemented for binding the // Binding describes the interface which needs to be implemented for binding the
@ -83,6 +84,7 @@ var (
YAML = yamlBinding{} YAML = yamlBinding{}
Uri = uriBinding{} Uri = uriBinding{}
Header = headerBinding{} Header = headerBinding{}
TOML = tomlBinding{}
) )
// Default returns the appropriate Binding instance based on the HTTP method // Default returns the appropriate Binding instance based on the HTTP method
@ -103,6 +105,8 @@ func Default(method, contentType string) Binding {
return MsgPack return MsgPack
case MIMEYAML: case MIMEYAML:
return YAML return YAML
case MIMETOML:
return TOML
case MIMEMultipartPOSTForm: case MIMEMultipartPOSTForm:
return FormMultipart return FormMultipart
default: // case MIMEPOSTForm: default: // case MIMEPOSTForm:

View File

@ -20,6 +20,7 @@ const (
MIMEMultipartPOSTForm = "multipart/form-data" MIMEMultipartPOSTForm = "multipart/form-data"
MIMEPROTOBUF = "application/x-protobuf" MIMEPROTOBUF = "application/x-protobuf"
MIMEYAML = "application/x-yaml" MIMEYAML = "application/x-yaml"
MIMETOML = "application/toml"
) )
// Binding describes the interface which needs to be implemented for binding the // Binding describes the interface which needs to be implemented for binding the
@ -79,6 +80,7 @@ var (
YAML = yamlBinding{} YAML = yamlBinding{}
Uri = uriBinding{} Uri = uriBinding{}
Header = headerBinding{} Header = headerBinding{}
TOML = tomlBinding{}
) )
// Default returns the appropriate Binding instance based on the HTTP method // Default returns the appropriate Binding instance based on the HTTP method
@ -99,6 +101,8 @@ func Default(method, contentType string) Binding {
return YAML return YAML
case MIMEMultipartPOSTForm: case MIMEMultipartPOSTForm:
return FormMultipart return FormMultipart
case MIMETOML:
return TOML
default: // case MIMEPOSTForm: default: // case MIMEPOSTForm:
return Form return Form
} }

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -165,6 +165,9 @@ func TestBindingDefault(t *testing.T) {
assert.Equal(t, YAML, Default("POST", MIMEYAML)) assert.Equal(t, YAML, Default("POST", MIMEYAML))
assert.Equal(t, YAML, Default("PUT", MIMEYAML)) assert.Equal(t, YAML, Default("PUT", MIMEYAML))
assert.Equal(t, TOML, Default("POST", MIMETOML))
assert.Equal(t, TOML, Default("PUT", MIMETOML))
} }
func TestBindingJSONNilBody(t *testing.T) { func TestBindingJSONNilBody(t *testing.T) {
@ -454,6 +457,20 @@ func TestBindingXMLFail(t *testing.T) {
"<map><foo>bar<foo></map>", "<map><bar>foo</bar></map>") "<map><foo>bar<foo></map>", "<map><bar>foo</bar></map>")
} }
func TestBindingTOML(t *testing.T) {
testBodyBinding(t,
TOML, "toml",
"/", "/",
`foo="bar"`, `bar="foo"`)
}
func TestBindingTOMLFail(t *testing.T) {
testBodyBindingFail(t,
TOML, "toml",
"/", "/",
`foo=\n"bar"`, `bar="foo"`)
}
func TestBindingYAML(t *testing.T) { func TestBindingYAML(t *testing.T) {
testBodyBinding(t, testBodyBinding(t,
YAML, "yaml", YAML, "yaml",
@ -1339,10 +1356,10 @@ func testProtoBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body
err := b.Bind(req, &obj) err := b.Bind(req, &obj)
assert.Error(t, err) assert.Error(t, err)
invalid_obj := FooStruct{} invalidobj := FooStruct{}
req.Body = ioutil.NopCloser(strings.NewReader(`{"msg":"hello"}`)) req.Body = ioutil.NopCloser(strings.NewReader(`{"msg":"hello"}`))
req.Header.Add("Content-Type", MIMEPROTOBUF) req.Header.Add("Content-Type", MIMEPROTOBUF)
err = b.Bind(req, &invalid_obj) err = b.Bind(req, &invalidobj)
assert.Error(t, err) assert.Error(t, err)
assert.Equal(t, err.Error(), "obj is not ProtoMessage") assert.Equal(t, err.Error(), "obj is not ProtoMessage")

View File

@ -1,4 +1,4 @@
// Copyright 2017 Manu Martinez-Almeida. All rights reserved. // Copyright 2017 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,3 +1,7 @@
// Copyright 2022 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 binding package binding
import ( import (

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2019 Gin Core Team. All rights reserved. // Copyright 2019 Gin Core Team. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,3 +1,7 @@
// Copyright 2022 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 binding package binding
import ( import (

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2017 Manu Martinez-Almeida. All rights reserved. // Copyright 2017 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2019 Gin Core Team. All rights reserved. // Copyright 2019 Gin Core Team. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2019 Gin Core Team. All rights reserved. // Copyright 2019 Gin Core Team. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2017 Manu Martinez-Almeida. All rights reserved. // Copyright 2017 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

35
binding/toml.go Normal file
View File

@ -0,0 +1,35 @@
// Copyright 2022 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 binding
import (
"bytes"
"io"
"net/http"
"github.com/pelletier/go-toml/v2"
)
type tomlBinding struct{}
func (tomlBinding) Name() string {
return "toml"
}
func decodeToml(r io.Reader, obj any) error {
decoder := toml.NewDecoder(r)
if err := decoder.Decode(obj); err != nil {
return err
}
return decoder.Decode(obj)
}
func (tomlBinding) Bind(req *http.Request, obj any) error {
return decodeToml(req.Body, obj)
}
func (tomlBinding) BindBody(body []byte, obj any) error {
return decodeToml(bytes.NewReader(body), obj)
}

22
binding/toml_test.go Normal file
View File

@ -0,0 +1,22 @@
// Copyright 2022 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 binding
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestTOMLBindingBindBody(t *testing.T) {
var s struct {
Foo string `toml:"foo"`
}
tomlBody := `foo="FOO"`
err := tomlBinding{}.BindBody([]byte(tomlBody), &s)
require.NoError(t, err)
assert.Equal(t, "FOO", s.Foo)
}

View File

@ -1,4 +1,4 @@
// Copyright 2018 Gin Core Team. All rights reserved. // Copyright 2018 Gin Core Team. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2018 Gin Core Team. All rights reserved. // Copyright 2018 Gin Core Team. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -34,11 +34,15 @@ const (
MIMEPOSTForm = binding.MIMEPOSTForm MIMEPOSTForm = binding.MIMEPOSTForm
MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm
MIMEYAML = binding.MIMEYAML MIMEYAML = binding.MIMEYAML
MIMETOML = binding.MIMETOML
) )
// BodyBytesKey indicates a default body bytes key. // BodyBytesKey indicates a default body bytes key.
const BodyBytesKey = "_gin-gonic/gin/bodybyteskey" const BodyBytesKey = "_gin-gonic/gin/bodybyteskey"
// ContextKey is the key that a Context returns itself for.
const ContextKey = "_gin-gonic/gin/contextkey"
// abortIndex represents a typical value used in abort functions. // abortIndex represents a typical value used in abort functions.
const abortIndex int8 = math.MaxInt8 >> 1 const abortIndex int8 = math.MaxInt8 >> 1
@ -98,6 +102,7 @@ func (c *Context) reset() {
c.Accepted = nil c.Accepted = nil
c.queryCache = nil c.queryCache = nil
c.formCache = nil c.formCache = nil
c.sameSite = 0
*c.params = (*c.params)[:0] *c.params = (*c.params)[:0]
*c.skippedNodes = (*c.skippedNodes)[:0] *c.skippedNodes = (*c.skippedNodes)[:0]
} }
@ -632,6 +637,11 @@ func (c *Context) BindYAML(obj any) error {
return c.MustBindWith(obj, binding.YAML) return c.MustBindWith(obj, binding.YAML)
} }
// BindTOML is a shortcut for c.MustBindWith(obj, binding.TOML).
func (c *Context) BindTOML(obj interface{}) error {
return c.MustBindWith(obj, binding.TOML)
}
// BindHeader is a shortcut for c.MustBindWith(obj, binding.Header). // BindHeader is a shortcut for c.MustBindWith(obj, binding.Header).
func (c *Context) BindHeader(obj any) error { func (c *Context) BindHeader(obj any) error {
return c.MustBindWith(obj, binding.Header) return c.MustBindWith(obj, binding.Header)
@ -690,6 +700,11 @@ func (c *Context) ShouldBindYAML(obj any) error {
return c.ShouldBindWith(obj, binding.YAML) return c.ShouldBindWith(obj, binding.YAML)
} }
// ShouldBindTOML is a shortcut for c.ShouldBindWith(obj, binding.TOML).
func (c *Context) ShouldBindTOML(obj interface{}) error {
return c.ShouldBindWith(obj, binding.TOML)
}
// ShouldBindHeader is a shortcut for c.ShouldBindWith(obj, binding.Header). // ShouldBindHeader is a shortcut for c.ShouldBindWith(obj, binding.Header).
func (c *Context) ShouldBindHeader(obj any) error { func (c *Context) ShouldBindHeader(obj any) error {
return c.ShouldBindWith(obj, binding.Header) return c.ShouldBindWith(obj, binding.Header)
@ -733,7 +748,7 @@ func (c *Context) ShouldBindBodyWith(obj any, bb binding.BindingBody) (err error
} }
// ClientIP implements one best effort algorithm to return the real client IP. // ClientIP implements one best effort algorithm to return the real client IP.
// It called c.RemoteIP() under the hood, to check if the remote IP is a trusted proxy or not. // It calls c.RemoteIP() under the hood, to check if the remote IP is a trusted proxy or not.
// If it is it will then try to parse the headers defined in Engine.RemoteIPHeaders (defaulting to [X-Forwarded-For, X-Real-Ip]). // If it is it will then try to parse the headers defined in Engine.RemoteIPHeaders (defaulting to [X-Forwarded-For, X-Real-Ip]).
// If the headers are not syntactically valid OR the remote IP does not correspond to a trusted proxy, // If the headers are not syntactically valid OR the remote IP does not correspond to a trusted proxy,
// the remote IP (coming from Request.RemoteAddr) is returned. // the remote IP (coming from Request.RemoteAddr) is returned.
@ -961,6 +976,11 @@ func (c *Context) YAML(code int, obj any) {
c.Render(code, render.YAML{Data: obj}) c.Render(code, render.YAML{Data: obj})
} }
// TOML serializes the given struct as TOML into the response body.
func (c *Context) TOML(code int, obj interface{}) {
c.Render(code, render.TOML{Data: obj})
}
// ProtoBuf serializes the given struct as ProtoBuf into the response body. // ProtoBuf serializes the given struct as ProtoBuf into the response body.
func (c *Context) ProtoBuf(code int, obj any) { func (c *Context) ProtoBuf(code int, obj any) {
c.Render(code, render.ProtoBuf{Data: obj}) c.Render(code, render.ProtoBuf{Data: obj})
@ -1065,6 +1085,7 @@ type Negotiate struct {
XMLData any XMLData any
YAMLData any YAMLData any
Data any Data any
TOMLData any
} }
// Negotiate calls different Render according to acceptable Accept format. // Negotiate calls different Render according to acceptable Accept format.
@ -1086,6 +1107,10 @@ func (c *Context) Negotiate(code int, config Negotiate) {
data := chooseData(config.YAMLData, config.Data) data := chooseData(config.YAMLData, config.Data)
c.YAML(code, data) c.YAML(code, data)
case binding.MIMETOML:
data := chooseData(config.TOMLData, config.Data)
c.TOML(code, data)
default: default:
c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server")) // nolint: errcheck c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server")) // nolint: errcheck
} }
@ -1133,7 +1158,7 @@ func (c *Context) SetAccepted(formats ...string) {
// Deadline returns that there is no deadline (ok==false) when c.Request has no Context. // Deadline returns that there is no deadline (ok==false) when c.Request has no Context.
func (c *Context) Deadline() (deadline time.Time, ok bool) { func (c *Context) Deadline() (deadline time.Time, ok bool) {
if c.Request == nil || c.Request.Context() == nil { if !c.engine.ContextWithFallback || c.Request == nil || c.Request.Context() == nil {
return return
} }
return c.Request.Context().Deadline() return c.Request.Context().Deadline()
@ -1141,7 +1166,7 @@ func (c *Context) Deadline() (deadline time.Time, ok bool) {
// Done returns nil (chan which will wait forever) when c.Request has no Context. // Done returns nil (chan which will wait forever) when c.Request has no Context.
func (c *Context) Done() <-chan struct{} { func (c *Context) Done() <-chan struct{} {
if c.Request == nil || c.Request.Context() == nil { if !c.engine.ContextWithFallback || c.Request == nil || c.Request.Context() == nil {
return nil return nil
} }
return c.Request.Context().Done() return c.Request.Context().Done()
@ -1149,7 +1174,7 @@ func (c *Context) Done() <-chan struct{} {
// Err returns nil when c.Request has no Context. // Err returns nil when c.Request has no Context.
func (c *Context) Err() error { func (c *Context) Err() error {
if c.Request == nil || c.Request.Context() == nil { if !c.engine.ContextWithFallback || c.Request == nil || c.Request.Context() == nil {
return nil return nil
} }
return c.Request.Context().Err() return c.Request.Context().Err()
@ -1162,12 +1187,15 @@ func (c *Context) Value(key any) any {
if key == 0 { if key == 0 {
return c.Request return c.Request
} }
if key == ContextKey {
return c
}
if keyAsString, ok := key.(string); ok { if keyAsString, ok := key.(string); ok {
if val, exists := c.Get(keyAsString); exists { if val, exists := c.Get(keyAsString); exists {
return val return val
} }
} }
if c.Request == nil || c.Request.Context() == nil { if !c.engine.ContextWithFallback || c.Request == nil || c.Request.Context() == nil {
return nil return nil
} }
return c.Request.Context().Value(key) return c.Request.Context().Value(key)

View File

@ -1,4 +1,4 @@
// Copyright 2021 Gin Core Team. All rights reserved. // Copyright 2021 Gin Core Team. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2021 Gin Core Team. All rights reserved. // Copyright 2021 Gin Core Team. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -17,6 +17,16 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
type interceptedWriter struct {
ResponseWriter
b *bytes.Buffer
}
func (i interceptedWriter) WriteHeader(code int) {
i.Header().Del("X-Test")
i.ResponseWriter.WriteHeader(code)
}
func TestContextFormFileFailed17(t *testing.T) { func TestContextFormFileFailed17(t *testing.T) {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
mw := multipart.NewWriter(buf) mw := multipart.NewWriter(buf)
@ -31,3 +41,32 @@ func TestContextFormFileFailed17(t *testing.T) {
assert.Nil(t, f) assert.Nil(t, f)
}) })
} }
func TestInterceptedHeader(t *testing.T) {
w := httptest.NewRecorder()
c, r := CreateTestContext(w)
r.Use(func(c *Context) {
i := interceptedWriter{
ResponseWriter: c.Writer,
b: bytes.NewBuffer(nil),
}
c.Writer = i
c.Next()
c.Header("X-Test", "overridden")
c.Writer = i.ResponseWriter
})
r.GET("/", func(c *Context) {
c.Header("X-Test", "original")
c.Header("X-Test-2", "present")
c.String(http.StatusOK, "hello world")
})
c.Request = httptest.NewRequest("GET", "/", nil)
r.HandleContext(c)
// Result() has headers frozen when WriteHeaderNow() has been called
// Compared to this time, this is when the response headers will be flushed
// As response is flushed on c.String, the Header cannot be set by the first
// middleware. Assert this
assert.Equal(t, "", w.Result().Header.Get("X-Test"))
assert.Equal(t, "present", w.Result().Header.Get("X-Test-2"))
}

View File

@ -1,4 +1,4 @@
// Copyright 2017 Manu Martinez-Almeida. All rights reserved. // Copyright 2017 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -1773,6 +1773,23 @@ func TestContextShouldBindWithYAML(t *testing.T) {
assert.Equal(t, 0, w.Body.Len()) assert.Equal(t, 0, w.Body.Len())
} }
func TestContextShouldBindWithTOML(t *testing.T) {
w := httptest.NewRecorder()
c, _ := CreateTestContext(w)
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("foo='bar'\nbar= 'foo'"))
c.Request.Header.Add("Content-Type", MIMETOML) // set fake content-type
var obj struct {
Foo string `toml:"foo"`
Bar string `toml:"bar"`
}
assert.NoError(t, c.ShouldBindTOML(&obj))
assert.Equal(t, "foo", obj.Bar)
assert.Equal(t, "bar", obj.Foo)
assert.Equal(t, 0, w.Body.Len())
}
func TestContextBadAutoShouldBind(t *testing.T) { func TestContextBadAutoShouldBind(t *testing.T) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
c, _ := CreateTestContext(w) c, _ := CreateTestContext(w)
@ -1880,6 +1897,7 @@ func TestContextGolangContext(t *testing.T) {
assert.Equal(t, ti, time.Time{}) assert.Equal(t, ti, time.Time{})
assert.False(t, ok) assert.False(t, ok)
assert.Equal(t, c.Value(0), c.Request) assert.Equal(t, c.Value(0), c.Request)
assert.Equal(t, c.Value(ContextKey), c)
assert.Nil(t, c.Value("foo")) assert.Nil(t, c.Value("foo"))
c.Set("foo", "bar") c.Set("foo", "bar")
@ -2079,12 +2097,18 @@ func TestRemoteIPFail(t *testing.T) {
} }
func TestContextWithFallbackDeadlineFromRequestContext(t *testing.T) { func TestContextWithFallbackDeadlineFromRequestContext(t *testing.T) {
c := &Context{} c, _ := CreateTestContext(httptest.NewRecorder())
// enable ContextWithFallback feature flag
c.engine.ContextWithFallback = true
deadline, ok := c.Deadline() deadline, ok := c.Deadline()
assert.Zero(t, deadline) assert.Zero(t, deadline)
assert.False(t, ok) assert.False(t, ok)
c2 := &Context{} c2, _ := CreateTestContext(httptest.NewRecorder())
// enable ContextWithFallback feature flag
c2.engine.ContextWithFallback = true
c2.Request, _ = http.NewRequest(http.MethodGet, "/", nil) c2.Request, _ = http.NewRequest(http.MethodGet, "/", nil)
d := time.Now().Add(time.Second) d := time.Now().Add(time.Second)
ctx, cancel := context.WithDeadline(context.Background(), d) ctx, cancel := context.WithDeadline(context.Background(), d)
@ -2096,10 +2120,16 @@ func TestContextWithFallbackDeadlineFromRequestContext(t *testing.T) {
} }
func TestContextWithFallbackDoneFromRequestContext(t *testing.T) { func TestContextWithFallbackDoneFromRequestContext(t *testing.T) {
c := &Context{} c, _ := CreateTestContext(httptest.NewRecorder())
// enable ContextWithFallback feature flag
c.engine.ContextWithFallback = true
assert.Nil(t, c.Done()) assert.Nil(t, c.Done())
c2 := &Context{} c2, _ := CreateTestContext(httptest.NewRecorder())
// enable ContextWithFallback feature flag
c2.engine.ContextWithFallback = true
c2.Request, _ = http.NewRequest(http.MethodGet, "/", nil) c2.Request, _ = http.NewRequest(http.MethodGet, "/", nil)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
c2.Request = c2.Request.WithContext(ctx) c2.Request = c2.Request.WithContext(ctx)
@ -2108,10 +2138,16 @@ func TestContextWithFallbackDoneFromRequestContext(t *testing.T) {
} }
func TestContextWithFallbackErrFromRequestContext(t *testing.T) { func TestContextWithFallbackErrFromRequestContext(t *testing.T) {
c := &Context{} c, _ := CreateTestContext(httptest.NewRecorder())
// enable ContextWithFallback feature flag
c.engine.ContextWithFallback = true
assert.Nil(t, c.Err()) assert.Nil(t, c.Err())
c2 := &Context{} c2, _ := CreateTestContext(httptest.NewRecorder())
// enable ContextWithFallback feature flag
c2.engine.ContextWithFallback = true
c2.Request, _ = http.NewRequest(http.MethodGet, "/", nil) c2.Request, _ = http.NewRequest(http.MethodGet, "/", nil)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
c2.Request = c2.Request.WithContext(ctx) c2.Request = c2.Request.WithContext(ctx)
@ -2120,9 +2156,9 @@ func TestContextWithFallbackErrFromRequestContext(t *testing.T) {
assert.EqualError(t, c2.Err(), context.Canceled.Error()) assert.EqualError(t, c2.Err(), context.Canceled.Error())
} }
type contextKey string
func TestContextWithFallbackValueFromRequestContext(t *testing.T) { func TestContextWithFallbackValueFromRequestContext(t *testing.T) {
type contextKey string
tests := []struct { tests := []struct {
name string name string
getContextAndKey func() (*Context, any) getContextAndKey func() (*Context, any)
@ -2132,7 +2168,9 @@ func TestContextWithFallbackValueFromRequestContext(t *testing.T) {
name: "c with struct context key", name: "c with struct context key",
getContextAndKey: func() (*Context, any) { getContextAndKey: func() (*Context, any) {
var key struct{} var key struct{}
c := &Context{} c, _ := CreateTestContext(httptest.NewRecorder())
// enable ContextWithFallback feature flag
c.engine.ContextWithFallback = true
c.Request, _ = http.NewRequest("POST", "/", nil) c.Request, _ = http.NewRequest("POST", "/", nil)
c.Request = c.Request.WithContext(context.WithValue(context.TODO(), key, "value")) c.Request = c.Request.WithContext(context.WithValue(context.TODO(), key, "value"))
return c, key return c, key
@ -2142,7 +2180,9 @@ func TestContextWithFallbackValueFromRequestContext(t *testing.T) {
{ {
name: "c with string context key", name: "c with string context key",
getContextAndKey: func() (*Context, any) { getContextAndKey: func() (*Context, any) {
c := &Context{} c, _ := CreateTestContext(httptest.NewRecorder())
// enable ContextWithFallback feature flag
c.engine.ContextWithFallback = true
c.Request, _ = http.NewRequest("POST", "/", nil) c.Request, _ = http.NewRequest("POST", "/", nil)
c.Request = c.Request.WithContext(context.WithValue(context.TODO(), contextKey("key"), "value")) c.Request = c.Request.WithContext(context.WithValue(context.TODO(), contextKey("key"), "value"))
return c, contextKey("key") return c, contextKey("key")
@ -2152,7 +2192,10 @@ func TestContextWithFallbackValueFromRequestContext(t *testing.T) {
{ {
name: "c with nil http.Request", name: "c with nil http.Request",
getContextAndKey: func() (*Context, any) { getContextAndKey: func() (*Context, any) {
c := &Context{} c, _ := CreateTestContext(httptest.NewRecorder())
// enable ContextWithFallback feature flag
c.engine.ContextWithFallback = true
c.Request = nil
return c, "key" return c, "key"
}, },
value: nil, value: nil,
@ -2160,7 +2203,9 @@ func TestContextWithFallbackValueFromRequestContext(t *testing.T) {
{ {
name: "c with nil http.Request.Context()", name: "c with nil http.Request.Context()",
getContextAndKey: func() (*Context, any) { getContextAndKey: func() (*Context, any) {
c := &Context{} c, _ := CreateTestContext(httptest.NewRecorder())
// enable ContextWithFallback feature flag
c.engine.ContextWithFallback = true
c.Request, _ = http.NewRequest("POST", "/", nil) c.Request, _ = http.NewRequest("POST", "/", nil)
return c, "key" return c, "key"
}, },
@ -2175,6 +2220,70 @@ func TestContextWithFallbackValueFromRequestContext(t *testing.T) {
} }
} }
func TestContextCopyShouldNotCancel(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
}))
defer srv.Close()
ensureRequestIsOver := make(chan struct{})
wg := &sync.WaitGroup{}
r := New()
r.GET("/", func(ginctx *Context) {
wg.Add(1)
ginctx = ginctx.Copy()
// start async goroutine for calling srv
go func() {
defer wg.Done()
<-ensureRequestIsOver // ensure request is done
req, err := http.NewRequestWithContext(ginctx, http.MethodGet, srv.URL, nil)
must(err)
res, err := http.DefaultClient.Do(req)
if err != nil {
t.Error(fmt.Errorf("request error: %w", err))
return
}
if res.StatusCode != http.StatusOK {
t.Error(fmt.Errorf("unexpected status code: %s", res.Status))
}
}()
})
l, err := net.Listen("tcp", ":0")
must(err)
go func() {
s := &http.Server{
Handler: r,
}
must(s.Serve(l))
}()
addr := strings.Split(l.Addr().String(), ":")
res, err := http.Get(fmt.Sprintf("http://127.0.0.1:%s/", addr[len(addr)-1]))
if err != nil {
t.Error(fmt.Errorf("request error: %w", err))
return
}
close(ensureRequestIsOver)
if res.StatusCode != http.StatusOK {
t.Error(fmt.Errorf("unexpected status code: %s", res.Status))
return
}
wg.Wait()
}
func TestContextAddParam(t *testing.T) { func TestContextAddParam(t *testing.T) {
c := &Context{} c := &Context{}
id := "id" id := "id"

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -67,7 +67,7 @@ func getMinVer(v string) (uint64, error) {
func debugPrintWARNINGDefault() { func debugPrintWARNINGDefault() {
if v, e := getMinVer(runtime.Version()); e == nil && v <= ginSupportMinGoVer { if v, e := getMinVer(runtime.Version()); e == nil && v <= ginSupportMinGoVer {
debugPrint(`[WARNING] Now Gin requires Go 1.14+. debugPrint(`[WARNING] Now Gin requires Go 1.15+.
`) `)
} }

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -104,7 +104,7 @@ func TestDebugPrintWARNINGDefault(t *testing.T) {
}) })
m, e := getMinVer(runtime.Version()) m, e := getMinVer(runtime.Version())
if e == nil && m <= ginSupportMinGoVer { if e == nil && m <= ginSupportMinGoVer {
assert.Equal(t, "[GIN-debug] [WARNING] Now Gin requires Go 1.14+.\n\n[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re) assert.Equal(t, "[GIN-debug] [WARNING] Now Gin requires Go 1.15+.\n\n[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re)
} else { } else {
assert.Equal(t, "[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re) assert.Equal(t, "[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re)
} }

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

2
fs.go
View File

@ -1,4 +1,4 @@
// Copyright 2017 Manu Martinez-Almeida. All rights reserved. // Copyright 2017 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

7
gin.go
View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -147,6 +147,9 @@ type Engine struct {
// UseH2C enable h2c support. // UseH2C enable h2c support.
UseH2C bool UseH2C bool
// ContextWithFallback enable fallback Context.Deadline(), Context.Done(), Context.Err() and Context.Value() when Context.Request.Context() is not nil.
ContextWithFallback bool
delims render.Delims delims render.Delims
secureJSONPrefix string secureJSONPrefix string
HTMLRender render.HTMLRender HTMLRender render.HTMLRender
@ -195,7 +198,7 @@ func New() *Engine {
trees: make(methodTrees, 0, 9), trees: make(methodTrees, 0, 9),
delims: render.Delims{Left: "{{", Right: "}}"}, delims: render.Delims{Left: "{{", Right: "}}"},
secureJSONPrefix: "while(1);", secureJSONPrefix: "while(1);",
trustedProxies: []string{"0.0.0.0/0"}, trustedProxies: []string{"0.0.0.0/0", "::/0"},
trustedCIDRs: defaultTrustedCIDRs, trustedCIDRs: defaultTrustedCIDRs,
} }
engine.RouterGroup.engine = engine engine.RouterGroup.engine = engine

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2017 Manu Martinez-Almeida. All rights reserved. // Copyright 2017 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -15,6 +15,7 @@ import (
"net/http/httptest" "net/http/httptest"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"sync" "sync"
"testing" "testing"
"time" "time"
@ -281,7 +282,16 @@ func TestFileDescriptor(t *testing.T) {
listener, err := net.ListenTCP("tcp", addr) listener, err := net.ListenTCP("tcp", addr)
assert.NoError(t, err) assert.NoError(t, err)
socketFile, err := listener.File() socketFile, err := listener.File()
assert.NoError(t, err) if isWindows() {
// not supported by windows, it is unimplemented now
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
if socketFile == nil {
return
}
go func() { go func() {
router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") }) router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
@ -547,3 +557,7 @@ func TestTreeRunDynamicRouting(t *testing.T) {
testRequest(t, ts.URL+"/addr/dd/aa", "404 Not Found") testRequest(t, ts.URL+"/addr/dd/aa", "404 Not Found")
testRequest(t, ts.URL+"/something/secondthing/121", "404 Not Found") testRequest(t, ts.URL+"/something/secondthing/121", "404 Not Found")
} }
func isWindows() bool {
return runtime.GOOS == "windows"
}

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -202,7 +202,7 @@ func TestLoadHTMLGlobFromFuncMap(t *testing.T) {
} }
resp, _ := ioutil.ReadAll(res.Body) resp, _ := ioutil.ReadAll(res.Body)
assert.Equal(t, "Date: 2017/07/01\n", string(resp)) assert.Equal(t, "Date: 2017/07/01", string(resp))
} }
func init() { func init() {
@ -320,7 +320,7 @@ func TestLoadHTMLFilesFuncMap(t *testing.T) {
} }
resp, _ := ioutil.ReadAll(res.Body) resp, _ := ioutil.ReadAll(res.Body)
assert.Equal(t, "Date: 2017/07/01\n", string(resp)) assert.Equal(t, "Date: 2017/07/01", string(resp))
} }
func TestAddRoute(t *testing.T) { func TestAddRoute(t *testing.T) {

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -296,8 +296,8 @@ func TestShouldBindUri(t *testing.T) {
router.Handle(http.MethodGet, "/rest/:name/:id", func(c *Context) { router.Handle(http.MethodGet, "/rest/:name/:id", func(c *Context) {
var person Person var person Person
assert.NoError(t, c.ShouldBindUri(&person)) assert.NoError(t, c.ShouldBindUri(&person))
assert.True(t, "" != person.Name) assert.True(t, person.Name != "")
assert.True(t, "" != person.ID) assert.True(t, person.ID != "")
c.String(http.StatusOK, "ShouldBindUri test OK") c.String(http.StatusOK, "ShouldBindUri test OK")
}) })
@ -318,8 +318,8 @@ func TestBindUri(t *testing.T) {
router.Handle(http.MethodGet, "/rest/:name/:id", func(c *Context) { router.Handle(http.MethodGet, "/rest/:name/:id", func(c *Context) {
var person Person var person Person
assert.NoError(t, c.BindUri(&person)) assert.NoError(t, c.BindUri(&person))
assert.True(t, "" != person.Name) assert.True(t, person.Name != "")
assert.True(t, "" != person.ID) assert.True(t, person.ID != "")
c.String(http.StatusOK, "BindUri test OK") c.String(http.StatusOK, "BindUri test OK")
}) })

9
go.mod
View File

@ -5,13 +5,14 @@ go 1.18
require ( require (
github.com/gin-contrib/sse v0.1.0 github.com/gin-contrib/sse v0.1.0
github.com/go-playground/validator/v10 v10.10.0 github.com/go-playground/validator/v10 v10.10.0
github.com/goccy/go-json v0.9.5 github.com/goccy/go-json v0.9.7
github.com/json-iterator/go v1.1.12 github.com/json-iterator/go v1.1.12
github.com/mattn/go-isatty v0.0.14 github.com/mattn/go-isatty v0.0.14
github.com/stretchr/testify v1.7.0 github.com/pelletier/go-toml/v2 v2.0.2
github.com/stretchr/testify v1.7.5
github.com/ugorji/go/codec v1.2.7 github.com/ugorji/go/codec v1.2.7
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
google.golang.org/protobuf v1.27.1 google.golang.org/protobuf v1.28.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
) )
@ -26,5 +27,5 @@ require (
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 // indirect golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 // indirect
golang.org/x/text v0.3.6 // indirect golang.org/x/text v0.3.6 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

19
go.sum
View File

@ -12,8 +12,8 @@ github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/j
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0= github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/goccy/go-json v0.9.5 h1:ooSMW526ZjK+EaL5elrSyN2EzIfi/3V0m4+HJEDYLik= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM=
github.com/goccy/go-json v0.9.5/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@ -36,6 +36,8 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OH
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.0.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS+49Gw=
github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@ -43,10 +45,14 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q=
github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
@ -67,8 +73,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
@ -77,5 +83,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,4 +1,4 @@
// Copyright 2017 Bo-Yi Wu. All rights reserved. // Copyright 2017 Bo-Yi Wu. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2017 Bo-Yi Wu. All rights reserved. // Copyright 2017 Bo-Yi Wu. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2017 Bo-Yi Wu. All rights reserved. // Copyright 2017 Bo-Yi Wu. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -208,6 +208,7 @@ func TestLoggerWithConfigFormatting(t *testing.T) {
// set dummy ClientIP // set dummy ClientIP
c.Request.Header.Set("X-Forwarded-For", "20.20.20.20") c.Request.Header.Set("X-Forwarded-For", "20.20.20.20")
gotKeys = c.Keys gotKeys = c.Keys
time.Sleep(time.Millisecond)
}) })
PerformRequest(router, "GET", "/example?a=100") PerformRequest(router, "GET", "/example?a=100")

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,10 +1,11 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package gin package gin
import ( import (
"flag"
"io" "io"
"os" "os"
@ -54,7 +55,11 @@ func init() {
// SetMode sets gin mode according to input string. // SetMode sets gin mode according to input string.
func SetMode(value string) { func SetMode(value string) {
if value == "" { if value == "" {
value = DebugMode if flag.Lookup("test.v") != nil {
value = TestMode
} else {
value = DebugMode
}
} }
switch value { switch value {

View File

@ -1,10 +1,11 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package gin package gin
import ( import (
"flag"
"os" "os"
"testing" "testing"
@ -21,9 +22,16 @@ func TestSetMode(t *testing.T) {
assert.Equal(t, TestMode, Mode()) assert.Equal(t, TestMode, Mode())
os.Unsetenv(EnvGinMode) os.Unsetenv(EnvGinMode)
SetMode("")
assert.Equal(t, testCode, ginMode)
assert.Equal(t, TestMode, Mode())
tmp := flag.CommandLine
flag.CommandLine = flag.NewFlagSet("", flag.ContinueOnError)
SetMode("") SetMode("")
assert.Equal(t, debugCode, ginMode) assert.Equal(t, debugCode, ginMode)
assert.Equal(t, DebugMode, Mode()) assert.Equal(t, DebugMode, Mode())
flag.CommandLine = tmp
SetMode(DebugMode) SetMode(DebugMode)
assert.Equal(t, debugCode, ginMode) assert.Equal(t, debugCode, ginMode)

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2021 Gin Core Team. All rights reserved. // Copyright 2021 Gin Core Team. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2017 Manu Martinez-Almeida. All rights reserved. // Copyright 2017 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2018 Gin Core Team. All rights reserved. // Copyright 2018 Gin Core Team. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2018 Gin Core Team. All rights reserved. // Copyright 2018 Gin Core Team. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2019 Gin Core Team. All rights reserved. // Copyright 2019 Gin Core Team. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -30,6 +30,7 @@ var (
_ Render = Reader{} _ Render = Reader{}
_ Render = AsciiJSON{} _ Render = AsciiJSON{}
_ Render = ProtoBuf{} _ Render = ProtoBuf{}
_ Render = TOML{}
) )
func writeContentType(w http.ResponseWriter, value []string) { func writeContentType(w http.ResponseWriter, value []string) {

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

36
render/toml.go Normal file
View File

@ -0,0 +1,36 @@
// Copyright 2022 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
import (
"net/http"
"github.com/pelletier/go-toml/v2"
)
// TOML contains the given interface object.
type TOML struct {
Data any
}
var TOMLContentType = []string{"application/toml; charset=utf-8"}
// Render (TOML) marshals the given interface object and writes data with custom ContentType.
func (r TOML) Render(w http.ResponseWriter) error {
r.WriteContentType(w)
bytes, err := toml.Marshal(r.Data)
if err != nil {
return err
}
_, err = w.Write(bytes)
return err
}
// WriteContentType (TOML) writes TOML ContentType for response.
func (r TOML) WriteContentType(w http.ResponseWriter) {
writeContentType(w, TOMLContentType)
}

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2017 Manu Martinez-Almeida. All rights reserved. // Copyright 2017 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2021 Gin Core Team. All rights reserved. // Copyright 2021 Gin Core Team. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1 +1 @@
Date: {[{.now | formatAsDate}]} Date: {[{.now | formatAsDate}]}

View File

@ -455,7 +455,7 @@ walk: // Outer loop for walking the tree
if !n.wildChild { if !n.wildChild {
// If the path at the end of the loop is not equal to '/' and the current node has no child nodes // If the path at the end of the loop is not equal to '/' and the current node has no child nodes
// the current node needs to roll back to last vaild skippedNode // the current node needs to roll back to last valid skippedNode
if path != "/" { if path != "/" {
for l := len(*skippedNodes); l > 0; { for l := len(*skippedNodes); l > 0; {
skippedNode := (*skippedNodes)[l-1] skippedNode := (*skippedNodes)[l-1]
@ -572,7 +572,7 @@ walk: // Outer loop for walking the tree
if path == prefix { if path == prefix {
// If the current path does not equal '/' and the node does not have a registered handle and the most recently matched node has a child node // If the current path does not equal '/' and the node does not have a registered handle and the most recently matched node has a child node
// the current node needs to roll back to last vaild skippedNode // the current node needs to roll back to last valid skippedNode
if n.handlers == nil && path != "/" { if n.handlers == nil && path != "/" {
for l := len(*skippedNodes); l > 0; { for l := len(*skippedNodes); l > 0; {
skippedNode := (*skippedNodes)[l-1] skippedNode := (*skippedNodes)[l-1]

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

View File

@ -1,8 +1,8 @@
// Copyright 2018 Gin Core Team. All rights reserved. // Copyright 2018 Gin Core Team. All rights reserved.
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package gin package gin
// Version is the current gin framework's version. // Version is the current gin framework's version.
const Version = "v1.7.7" const Version = "v1.8.1"